Import: GetIdByNameAsync derived-template ambiguity; intra-record exact-name lookups; reuse the PSK pub-sub invalidation for D1/D3 #100

Closed
opened 2026-11-09 14:38:53 -05:00 by dohertj2 · 3 comments
Owner

Residuals after #93/#95 (transport import name matching vs case-insensitive SQL):

  • BundleImporter's TemplateLibrary.GetIdByNameAsync matches exactly and includes derived templates (first match wins) when resolving parent, composition and instance template names on apply. Composition targets may legitimately be derived templates, so decide the rule (base-first? reject ambiguity?) before changing it.
  • Name lookups inside a record — template attributes, alarms, scripts, native alarm sources, external-system methods — still match exactly while their DB unique indexes are case-insensitive.
  • The new site-psk-invalidation pub-sub topic (#96) is the first cross-node invalidation broadcast; the #85 audit's D1 (role-mapping cache) and D3/#83 (external definition cache) could reuse the same mechanism.
Residuals after #93/#95 (transport import name matching vs case-insensitive SQL): - `BundleImporter`'s `TemplateLibrary.GetIdByNameAsync` matches exactly and includes derived templates (first match wins) when resolving parent, composition and instance template names on apply. Composition targets may legitimately be derived templates, so decide the rule (base-first? reject ambiguity?) before changing it. - Name lookups *inside* a record — template attributes, alarms, scripts, native alarm sources, external-system methods — still match exactly while their DB unique indexes are case-insensitive. - The new `site-psk-invalidation` pub-sub topic (#96) is the first cross-node invalidation broadcast; the #85 audit's D1 (role-mapping cache) and D3/#83 (external definition cache) could reuse the same mechanism.
dohertj2 added the type:followuppriority:p3 labels 2026-11-09 14:38:53 -05:00
Author
Owner

Item 2 fixed on main 6ff5efd3: overwrite sync matches template attributes, alarms, scripts, native alarm sources and external-system methods case-insensitively (#93/#95 helper); alarm→script link pass, alarm equality and the preview diff likewise (notification recipients stay exact — no unique index, replaced wholesale). Also fixes a #93 regression: the relink passes looked up an Overwrite target by exact name, so a case-variant target was skipped and its alarm on-trigger links stayed null — now a case-insensitive fallback (composed/base references stay exact, not pre-empting item 1). Members_inside_a_record_match_case_insensitively fails three ways without the fixes. Open: item 1 (GetIdByNameAsync derived ambiguity — needs a rule) and item 3 (reuse the PSK pub-sub for D1/D3). Evidence (after rebase): slnx 0 warnings/0 errors; ManagementService, InboundAPI, Transport, CentralUI, Transport.IntegrationTests (144) passed.

Item 2 fixed on main 6ff5efd3: overwrite sync matches template attributes, alarms, scripts, native alarm sources and external-system methods case-insensitively (#93/#95 helper); alarm→script link pass, alarm equality and the preview diff likewise (notification recipients stay exact — no unique index, replaced wholesale). Also fixes a #93 regression: the relink passes looked up an Overwrite target by exact name, so a case-variant target was skipped and its alarm on-trigger links stayed null — now a case-insensitive fallback (composed/base references stay exact, not pre-empting item 1). Members_inside_a_record_match_case_insensitively fails three ways without the fixes. **Open:** item 1 (GetIdByNameAsync derived ambiguity — needs a rule) and item 3 (reuse the PSK pub-sub for D1/D3). Evidence (after rebase): slnx 0 warnings/0 errors; ManagementService, InboundAPI, Transport, CentralUI, Transport.IntegrationTests (144) passed.
Author
Owner

Item 3 done on main 153609ef: one central central-cache-invalidation DistributedPubSub topic with typed messages + sender-node id (own broadcasts ignored); PSK rotation migrated onto it and still also published/listened on the legacy site-psk-invalidation topic for one release (mixed-version pair); D1 role-mapping/scope-rule changes and D3 external definitions now reach the peer immediately; every cache keeps its TTL as fallback. Item 2 landed earlier. Item 1 (GetIdByNameAsync derived-template rule) still open — needs a decision. Evidence (after rebase): slnx 0 warnings/0 errors; ManagementService 752, CLI 571, CentralUI 1533, InboundAPI 373, Security 199, ExternalSystemGateway 146, TemplateEngine 617, Transport.IntegrationTests 145, Host 623, Commons 915 passed; key projects re-run green on the pushed tip.

Item 3 done on main 153609ef: one central `central-cache-invalidation` DistributedPubSub topic with typed messages + sender-node id (own broadcasts ignored); PSK rotation migrated onto it and **still also published/listened on the legacy `site-psk-invalidation` topic for one release** (mixed-version pair); D1 role-mapping/scope-rule changes and D3 external definitions now reach the peer immediately; every cache keeps its TTL as fallback. Item 2 landed earlier. **Item 1 (GetIdByNameAsync derived-template rule) still open — needs a decision.** Evidence (after rebase): slnx 0 warnings/0 errors; ManagementService 752, CLI 571, CentralUI 1533, InboundAPI 373, Security 199, ExternalSystemGateway 146, TemplateEngine 617, Transport.IntegrationTests 145, Host 623, Commons 915 passed; key projects re-run green on the pushed tip.
Author
Owner

Item 1 fixed on main @ a13aabc7. Items 2 (6ff5efd3) and 3 (153609ef) were already done, so all three are complete.

Rule chosen. It follows the precedent ToTemplateLookup already applies to Overwrite targets. Owner can revisit; the rule is documented in Component-Transport.md "Template second-pass rewires".

  • Matching is by exact name.
  • A base template wins. Base names are unique through the filtered index, and a base is what a by-name parent or instance reference means.
  • A name held only by derived composition-slot templates resolves only when exactly one holds it. Composition targets can legitimately be derived.
  • Several derived templates and no base is ambiguous: the reference stays unresolved, and the BundleImportCompositionUnresolved audit reason says so, instead of binding to a slot owned by another composition.

Before, it was first-row-wins over the projection order, so a lower-id derived template shadowed a same-named base. The tracked-template exact index and the instance-pass Local overlay are base-first too.

Tests: TemplateReferenceResolutionTests (base beats a lower-id derived; a unique derived-only name resolves; ambiguous derived names stay unresolved; exact match). Mutation-proved: restoring first-wins fails 2 of 4.

Found on the way and filed as #118: Transport does not carry IsDerived/OwnerCompositionId at all, so derived slot templates in a bundle are re-created as base templates named after the slot. That needs an owner design decision. My recommendation is to carry them additively and recreate the slot through the compose flow.

Evidence: dotnet build ZB.MOM.WW.ScadaBridge.slnx 0 warnings / 0 errors; DataConnectionLayer.Tests 483 passed (4 skipped), SiteRuntime.Tests 1016, Transport.Tests 232, Transport.IntegrationTests 151, ScriptAnalysis.Tests 103 — all green. Not deployed anywhere.

Item 1 fixed on main @ a13aabc7. Items 2 (6ff5efd3) and 3 (153609ef) were already done, so all three are complete. **Rule chosen.** It follows the precedent `ToTemplateLookup` already applies to Overwrite targets. Owner can revisit; the rule is documented in Component-Transport.md "Template second-pass rewires". - Matching is by exact name. - A **base** template wins. Base names are unique through the filtered index, and a base is what a by-name parent or instance reference means. - A name held only by derived composition-slot templates resolves only when **exactly one** holds it. Composition targets can legitimately be derived. - Several derived templates and no base is **ambiguous**: the reference stays unresolved, and the `BundleImportCompositionUnresolved` audit reason says so, instead of binding to a slot owned by another composition. Before, it was first-row-wins over the projection order, so a lower-id derived template shadowed a same-named base. The tracked-template exact index and the instance-pass Local overlay are base-first too. Tests: `TemplateReferenceResolutionTests` (base beats a lower-id derived; a unique derived-only name resolves; ambiguous derived names stay unresolved; exact match). **Mutation-proved:** restoring first-wins fails 2 of 4. Found on the way and filed as **#118**: Transport does not carry `IsDerived`/`OwnerCompositionId` at all, so derived slot templates in a bundle are re-created as *base* templates named after the slot. That needs an owner design decision. My recommendation is to carry them additively and recreate the slot through the compose flow. Evidence: `dotnet build ZB.MOM.WW.ScadaBridge.slnx` 0 warnings / 0 errors; DataConnectionLayer.Tests 483 passed (4 skipped), SiteRuntime.Tests 1016, Transport.Tests 232, Transport.IntegrationTests 151, ScriptAnalysis.Tests 103 — all green. Not deployed anywhere.
Sign in to join this conversation.