diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/DeferredAddressSpaceSink.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/DeferredAddressSpaceSink.cs index ab7d208c..8f714a31 100644 --- a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/DeferredAddressSpaceSink.cs +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/DeferredAddressSpaceSink.cs @@ -73,7 +73,7 @@ public sealed class DeferredAddressSpaceSink : IOpcUaAddressSpaceSink, ISurgical /// Forwards an in-place tag-attribute update (F10b) to the inner sink when it supports the /// surgical capability. Returns false otherwise — before the real SdkAddressSpaceSink is /// swapped in (inner is still the null sink), or any inner sink that isn't surgical — so the caller - /// (Phase7Applier) falls back to a full rebuild. Without this forward the surgical optimization is + /// (AddressSpaceApplier) falls back to a full rebuild. Without this forward the surgical optimization is /// inert on every driver-role host, because actors inject THIS wrapper, not the inner sink. /// The node ID of the variable to update in place. /// Whether the node should be read/write. diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/EquipmentNodeIds.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/EquipmentNodeIds.cs index f6e1c724..48942008 100644 --- a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/EquipmentNodeIds.cs +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/EquipmentNodeIds.cs @@ -4,7 +4,7 @@ namespace ZB.MOM.WW.OtOpcUa.Commons.OpcUa; /// Single source of truth for equipment-namespace OPC UA NodeId strings. The variable NodeId is /// FOLDER-SCOPED ({parent}/{Name}), NOT the driver-side FullName — a driver wire ref is not /// unique across identical machines, so FullName-as-NodeId would collide in the sink. Used by the -/// materialiser (Phase7Applier), the VirtualTag publish map, and the driver live-value router so all +/// materialiser (AddressSpaceApplier), the VirtualTag publish map, and the driver live-value router so all /// three agree on the exact NodeId a variable was placed at. /// public static class EquipmentNodeIds diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/IOpcUaAddressSpaceSink.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/IOpcUaAddressSpaceSink.cs index 237c5eeb..a7a1dd9a 100644 --- a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/IOpcUaAddressSpaceSink.cs +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/IOpcUaAddressSpaceSink.cs @@ -31,7 +31,7 @@ public interface IOpcUaAddressSpaceSink /// Materialise a real OPC UA Part 9 alarm-condition node under its equipment folder so clients /// can browse it as a proper condition (with basic Active/Ack state). The node id equals the /// alarm node id (the ScriptedAlarmId) so subsequent calls update - /// it. Used by Phase7Applier.MaterialiseScriptedAlarms. Idempotent. + /// it. Used by AddressSpaceApplier.MaterialiseScriptedAlarms. Idempotent. /// /// The alarm node ID (== ScriptedAlarmId); becomes the condition's NodeId. /// The equipment folder node ID the condition parents under. @@ -44,7 +44,7 @@ public interface IOpcUaAddressSpaceSink void MaterialiseAlarmCondition(string alarmNodeId, string equipmentNodeId, string displayName, string alarmType, int severity, bool isNative = false); /// - /// Ensure a folder node exists under the given parent. Used by Phase7Applier to + /// Ensure a folder node exists under the given parent. Used by AddressSpaceApplier to /// materialise the UNS Area/Line/Equipment hierarchy in the address space. When /// is null the folder is parented under the namespace /// root. Idempotent: calling twice with the same id is safe. @@ -58,7 +58,7 @@ public interface IOpcUaAddressSpaceSink /// Ensure a Variable node exists at , parented under /// (or the namespace root when null). Created with /// Bad quality + null value; subsequent calls update both. - /// Used by Phase7Applier to materialise equipment-namespace tags ahead of any + /// Used by AddressSpaceApplier to materialise equipment-namespace tags ahead of any /// driver-side subscribe so OPC UA clients can browse them. Idempotent. /// /// The OPC UA node ID for the variable. diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/ISurgicalAddressSpaceSink.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/ISurgicalAddressSpaceSink.cs index 98e11aa5..6a6f5592 100644 --- a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/ISurgicalAddressSpaceSink.cs +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/ISurgicalAddressSpaceSink.cs @@ -1,7 +1,7 @@ namespace ZB.MOM.WW.OtOpcUa.Commons.OpcUa; /// Optional capability on an address-space sink: surgical in-place attribute updates on an -/// EXISTING variable node, used by Phase7Applier to avoid a full RebuildAddressSpace for pure-property +/// EXISTING variable node, used by AddressSpaceApplier to avoid a full RebuildAddressSpace for pure-property /// tag changes (Writable / Historizing). A sink that does not implement it ⇒ caller falls back to a /// full rebuild (safe default). public interface ISurgicalAddressSpaceSink diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/EquipmentScriptPaths.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/EquipmentScriptPaths.cs index 4c9e95ce..e0cd6f2d 100644 --- a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/EquipmentScriptPaths.cs +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/EquipmentScriptPaths.cs @@ -88,7 +88,7 @@ public static class EquipmentScriptPaths /// /// Distinct ctx.GetTag("ref") string literals in first-seen order — the /// dependency refs the VirtualTagActor subscribes to. The single shared copy - /// formerly duplicated in Phase7Composer + DeploymentArtifact. GetTag + /// formerly duplicated in AddressSpaceComposer + DeploymentArtifact. GetTag /// only (writes are not dependencies). /// /// The (already substituted) script source. @@ -112,7 +112,7 @@ public static class EquipmentScriptPaths /// UNION the distinct {TagPath} token paths referenced in the message template (first-seen /// order, appended after the predicate reads, trimmed + non-empty). The reserved /// {{equip}} double-brace form is excluded by the token regex. Deterministic so the live - /// composer (Phase7Composer) and the artifact-decode mirror (DeploymentArtifact) + /// composer (AddressSpaceComposer) and the artifact-decode mirror (DeploymentArtifact) /// produce the exact same ordered list — the byte-parity contract EquipmentScriptedAlarmPlan /// equality depends on. Scripted alarms do NOT use {{equip}} substitution (only virtual /// tags do) — pass the predicate source as-is. diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Validation/DraftValidator.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Validation/DraftValidator.cs index 6d1432ad..76bdb3f3 100644 --- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Validation/DraftValidator.cs +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Validation/DraftValidator.cs @@ -54,7 +54,7 @@ public static class DraftValidator } // Minimal reader for the top-level "FullName" string in a tag's schemaless TagConfig JSON - // (mirrors Phase7Composer.ExtractTagFullName — a small local copy, consistent with this codebase + // (mirrors AddressSpaceComposer.ExtractTagFullName — a small local copy, consistent with this codebase // where the composer keeps its own). private static string? ExtractTagConfigFullName(string? tagConfig) { diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagModal.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagModal.razor index 0f11fb91..2cd5c3b9 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagModal.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagModal.razor @@ -139,7 +139,7 @@ @* Driver-agnostic server-side HistoryRead intent. Distinct from the native-alarm "Historize to AVEVA" toggle below: THIS gates TAG-VALUE history (root keys - `isHistorized` / `historianTagname`, read by Phase7Composer.ExtractTagHistorize), + `isHistorized` / `historianTagname`, read by AddressSpaceComposer.ExtractTagHistorize), merged onto the canonical TagConfig via the pure TagHistorizeConfig seam so it composes with the typed editor's driver-specific fields (both preserve unknown keys). Shown for EVERY driver once one is picked. *@ diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/ScriptAnalysis/IScriptTagCatalog.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/ScriptAnalysis/IScriptTagCatalog.cs index 2652fb9c..810febe3 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/ScriptAnalysis/IScriptTagCatalog.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/ScriptAnalysis/IScriptTagCatalog.cs @@ -41,15 +41,15 @@ public sealed record ScriptTagInfo(string Path, string Kind, string DataType, st /// /// Fidelity over breadth. Verified: the live runtime resolves a ctx.GetTag("X") /// literal against the driver FullName — the resolution chain is -/// Phase7Composer (via EquipmentScriptPaths.ExtractDependencyRefs) harvesting the ctx.GetTag("…") literals +/// AddressSpaceComposer (via EquipmentScriptPaths.ExtractDependencyRefs) harvesting the ctx.GetTag("…") literals /// into EquipmentVirtualTagPlan.DependencyRefs -/// (src/Server/…OpcUaServer/Phase7Composer.cs); those become +/// (src/Server/…OpcUaServer/AddressSpaceComposer.cs); those become /// VirtualTagActor._dependencyRefs, registered with the /// DependencyMuxActor, whose _byRef map is keyed by /// DriverInstanceActor.AttributeValuePublished.FullReference /// (src/Server/…Runtime/VirtualTags/DependencyMuxActor.cs:97) — and that /// FullReference is the FullName field extracted from Tag.TagConfig -/// (see Phase7Composer.ExtractTagFullName + EquipmentNodeWalker.ExtractFullName). +/// (see AddressSpaceComposer.ExtractTagFullName + EquipmentNodeWalker.ExtractFullName). /// The UNS-path engine (Core.VirtualTags.VirtualTagEngine, keyed by a slash-joined /// Enterprise/Site/Area/Line/Equipment/TagName) is dormant — it is NOT wired into the /// host — so UNS browse paths never resolve at runtime and are intentionally NOT suggested. @@ -175,7 +175,7 @@ public sealed class ScriptTagCatalog(IDbContextFactory d /// /// Extracts the driver-side full reference from a Tag.TagConfig JSON blob — the /// top-level FullName string every shipped driver stores. Mirrors - /// EquipmentNodeWalker.ExtractFullName / Phase7Composer.ExtractTagFullName + /// EquipmentNodeWalker.ExtractFullName / AddressSpaceComposer.ExtractTagFullName /// (AdminUI does not reference those assemblies). Falls back to the raw blob when it is not /// a JSON object carrying a string FullName. /// diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/ScriptAnalysis/ScriptAnalysisService.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/ScriptAnalysis/ScriptAnalysisService.cs index 32cf54aa..bff62966 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/ScriptAnalysis/ScriptAnalysisService.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/ScriptAnalysis/ScriptAnalysisService.cs @@ -223,7 +223,7 @@ public sealed class ScriptAnalysisService if (inv.Expression is not MemberAccessExpressionSyntax ma) return false; // Receiver guard: only ctx.GetTag(...) / ctx.SetVirtualTag(...) are real tag-path calls. Mirrors the // runtime harvest (EquipmentScriptPaths.GetTagRefRegex is syntactically `ctx`-anchored), so the editor - // offers tag completions/hover for exactly what Phase7Composer harvests — not an unrelated x.GetTag(...). + // offers tag completions/hover for exactly what AddressSpaceComposer harvests — not an unrelated x.GetTag(...). if (ma.Expression is not IdentifierNameSyntax { Identifier.ValueText: "ctx" }) return false; var method = ma.Name.Identifier.ValueText; if (method is not ("GetTag" or "SetVirtualTag")) return false; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/HistorianWonderwareTagConfigModel.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/HistorianWonderwareTagConfigModel.cs index 765061b6..f80065bb 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/HistorianWonderwareTagConfigModel.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/HistorianWonderwareTagConfigModel.cs @@ -7,7 +7,7 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors; /// the driver reads against). Preserves unrecognised JSON keys across a load→save. /// /// The FullName key is intentionally PascalCase: the deploy-time composer + node walker -/// (Phase7Composer.ExtractTagFullName, EquipmentNodeWalker) read it via a +/// (AddressSpaceComposer.ExtractTagFullName, EquipmentNodeWalker) read it via a /// case-sensitive TryGetProperty("FullName", …), so the editor MUST persist that exact /// casing. The driver-agnostic server-side HistoryRead intent keys (isHistorized / /// historianTagname) are NOT modelled here — they are owned by the TagModal-merge seam diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/NativeAlarmModel.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/NativeAlarmModel.cs index 0ab3a68e..864581c5 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/NativeAlarmModel.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/NativeAlarmModel.cs @@ -6,7 +6,7 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors; /// Typed working model for the optional native-alarm alarm sub-object inside a tag's /// TagConfig JSON. A tag whose TagConfig carries an alarm object is materialised /// as an OPC UA Part 9 condition (rather than a value variable); the fields here mirror what the -/// server's Phase7Composer.ExtractTagAlarm / DeploymentArtifact.ExtractTagAlarm parse. +/// server's AddressSpaceComposer.ExtractTagAlarm / DeploymentArtifact.ExtractTagAlarm parse. /// /// /// is the per-condition opt-out of the DURABLE AVEVA historian write diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/OpcUaClientTagConfigModel.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/OpcUaClientTagConfigModel.cs index c072d731..7066e7ad 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/OpcUaClientTagConfigModel.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/OpcUaClientTagConfigModel.cs @@ -8,7 +8,7 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors; /// Preserves unrecognised JSON keys across a load→save. /// /// The FullName key is intentionally PascalCase: the deploy-time composer + node walker -/// (Phase7Composer.ExtractTagFullName, EquipmentNodeWalker) read it via a +/// (AddressSpaceComposer.ExtractTagFullName, EquipmentNodeWalker) read it via a /// case-sensitive TryGetProperty("FullName", …), so the editor MUST persist that exact /// casing. The driver-agnostic server-side HistoryRead intent keys (isHistorized / /// historianTagname) are NOT modelled here — they are owned by the TagModal-merge seam diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/TagHistorizeConfig.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/TagHistorizeConfig.cs index 586a44fd..9935e679 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/TagHistorizeConfig.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/TagEditors/TagHistorizeConfig.cs @@ -4,7 +4,7 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors; /// Pure, driver-agnostic merge helper for the two server-side HistoryRead intent keys at the ROOT of a /// tag's TagConfig JSON: isHistorized (camelCase bool — omit/false default) and /// historianTagname (camelCase string override — omit when blank). These map to what the server's -/// Phase7Composer.ExtractTagHistorize reads (see docs/Historian.md). +/// AddressSpaceComposer.ExtractTagHistorize reads (see docs/Historian.md). /// /// /// This is the TagModal-merge seam: the TagModal owns the canonical TagConfig JSON; the driver's typed diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Phase7Applier.cs b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpaceApplier.cs similarity index 89% rename from src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Phase7Applier.cs rename to src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpaceApplier.cs index 4d405233..17afaedf 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Phase7Applier.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpaceApplier.cs @@ -4,9 +4,9 @@ using ZB.MOM.WW.OtOpcUa.Commons.OpcUa; namespace ZB.MOM.WW.OtOpcUa.OpcUaServer; /// -/// Side-effecting orchestrator over . Drives an +/// Side-effecting orchestrator over . Drives an /// to materialise the diff between two -/// snapshots: +/// snapshots: /// /// /// RemovedEquipment / RemovedAlarms — write Bad-quality on every removed @@ -23,15 +23,15 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer; /// production binds a real SDK sink, dev/Mac binds , /// and tests can capture every call. /// -public sealed class Phase7Applier +public sealed class AddressSpaceApplier { private readonly IOpcUaAddressSpaceSink _sink; - private readonly ILogger _logger; + private readonly ILogger _logger; - /// Initializes a new instance of the Phase7Applier class. + /// Initializes a new instance of the AddressSpaceApplier class. /// The OPC UA address space sink to apply changes to. /// The logger instance. - public Phase7Applier(IOpcUaAddressSpaceSink sink, ILogger logger) + public AddressSpaceApplier(IOpcUaAddressSpaceSink sink, ILogger logger) { ArgumentNullException.ThrowIfNull(sink); ArgumentNullException.ThrowIfNull(logger); @@ -44,15 +44,15 @@ public sealed class Phase7Applier /// callers (OpcUaPublishActor) can correlate the work back to the originating deployment. /// /// The plan to apply. - /// A Phase7ApplyOutcome summarizing the applied changes. - public Phase7ApplyOutcome Apply(Phase7Plan plan) + /// A AddressSpaceApplyOutcome summarizing the applied changes. + public AddressSpaceApplyOutcome Apply(AddressSpacePlan plan) { ArgumentNullException.ThrowIfNull(plan); if (plan.IsEmpty) { - _logger.LogDebug("Phase7Applier: plan is empty; skipping sink writes"); - return new Phase7ApplyOutcome(RemovedNodes: 0, AddedNodes: 0, ChangedNodes: 0, RebuildCalled: false); + _logger.LogDebug("AddressSpaceApplier: plan is empty; skipping sink writes"); + return new AddressSpaceApplyOutcome(RemovedNodes: 0, AddedNodes: 0, ChangedNodes: 0, RebuildCalled: false); } var ts = DateTime.UtcNow; @@ -68,7 +68,7 @@ public sealed class Phase7Applier removedCount++; } // Removed equipment tags / VirtualTags are plain variable nodes (no Part 9 condition to write - // before tear-down), but they ARE real removals — count them so Phase7ApplyOutcome.RemovedNodes + // before tear-down), but they ARE real removals — count them so AddressSpaceApplyOutcome.RemovedNodes // is accurate on a removed-tag-only deploy, which now reaches the rebuild path below. removedCount += plan.RemovedEquipmentTags.Count + plan.RemovedEquipmentVirtualTags.Count; @@ -136,7 +136,7 @@ public sealed class Phase7Applier try { ok = surgical.UpdateTagAttributes(nodeId, writable, historian); } catch (Exception ex) { - _logger.LogError(ex, "Phase7Applier: surgical UpdateTagAttributes threw for {Node}", nodeId); + _logger.LogError(ex, "AddressSpaceApplier: surgical UpdateTagAttributes threw for {Node}", nodeId); ok = false; } if (!ok) { allApplied = false; break; } @@ -152,10 +152,10 @@ public sealed class Phase7Applier } _logger.LogInformation( - "Phase7Applier: applied plan (added={Added}, removed={Removed}, changed={Changed}, surgicalTags={Surgical}, rebuild={Rebuild})", + "AddressSpaceApplier: applied plan (added={Added}, removed={Removed}, changed={Changed}, surgicalTags={Surgical}, rebuild={Rebuild})", addedCount, removedCount, changedCount, rebuilt ? 0 : surgicalTagDeltas.Count, rebuilt); - return new Phase7ApplyOutcome(removedCount, addedCount, changedCount, rebuilt); + return new AddressSpaceApplyOutcome(removedCount, addedCount, changedCount, rebuilt); } private void SafeRebuild() @@ -166,7 +166,7 @@ public sealed class Phase7Applier } catch (Exception ex) { - _logger.LogError(ex, "Phase7Applier: sink.RebuildAddressSpace threw"); + _logger.LogError(ex, "AddressSpaceApplier: sink.RebuildAddressSpace threw"); } } @@ -178,7 +178,7 @@ public sealed class Phase7Applier /// present, so re-applies are cheap. /// /// The composition result containing the hierarchy to materialise. - public void MaterialiseHierarchy(Phase7CompositionResult composition) + public void MaterialiseHierarchy(AddressSpaceComposition composition) { ArgumentNullException.ThrowIfNull(composition); @@ -198,7 +198,7 @@ public sealed class Phase7Applier } _logger.LogInformation( - "Phase7Applier: hierarchy materialised (areas={Areas}, lines={Lines}, equipment={Equipment})", + "AddressSpaceApplier: hierarchy materialised (areas={Areas}, lines={Lines}, equipment={Equipment})", composition.UnsAreas.Count, composition.UnsLines.Count, composition.EquipmentNodes.Count); } @@ -223,7 +223,7 @@ public sealed class Phase7Applier /// /// /// The composition result containing the equipment tags to materialise. - public void MaterialiseEquipmentTags(Phase7CompositionResult composition) + public void MaterialiseEquipmentTags(AddressSpaceComposition composition) { ArgumentNullException.ThrowIfNull(composition); if (composition.EquipmentTags.Count == 0) return; @@ -276,7 +276,7 @@ public sealed class Phase7Applier } _logger.LogInformation( - "Phase7Applier: equipment tags materialised (tags={Tags}, equipment={Equipment})", + "AddressSpaceApplier: equipment tags materialised (tags={Tags}, equipment={Equipment})", composition.EquipmentTags.Count, composition.EquipmentTags.Select(t => t.EquipmentId).Distinct(StringComparer.Ordinal).Count()); } @@ -294,7 +294,7 @@ public sealed class Phase7Applier /// Idempotent (per-variable idempotency relies on the sink's own EnsureVariable). /// /// The composition result containing the equipment VirtualTags to materialise. - public void MaterialiseEquipmentVirtualTags(Phase7CompositionResult composition) + public void MaterialiseEquipmentVirtualTags(AddressSpaceComposition composition) { ArgumentNullException.ThrowIfNull(composition); if (composition.EquipmentVirtualTags.Count == 0) return; @@ -328,7 +328,7 @@ public sealed class Phase7Applier } _logger.LogInformation( - "Phase7Applier: equipment virtualtags materialised (vtags={Vtags}, equipment={Equipment})", + "AddressSpaceApplier: equipment virtualtags materialised (vtags={Vtags}, equipment={Equipment})", composition.EquipmentVirtualTags.Count, composition.EquipmentVirtualTags.Select(v => v.EquipmentId).Distinct(StringComparer.Ordinal).Count()); } @@ -343,7 +343,7 @@ public sealed class Phase7Applier /// MaterialiseAlarmCondition re-creates cleanly on re-apply). /// /// The composition result containing the scripted alarms to materialise. - public void MaterialiseScriptedAlarms(Phase7CompositionResult composition) + public void MaterialiseScriptedAlarms(AddressSpaceComposition composition) { ArgumentNullException.ThrowIfNull(composition); if (composition.EquipmentScriptedAlarms.Count == 0) return; @@ -357,7 +357,7 @@ public sealed class Phase7Applier } _logger.LogInformation( - "Phase7Applier: scripted alarms materialised (alarms={Alarms}, equipment={Equipment})", + "AddressSpaceApplier: scripted alarms materialised (alarms={Alarms}, equipment={Equipment})", materialised, composition.EquipmentScriptedAlarms.Where(a => a.Enabled) .Select(a => a.EquipmentId).Distinct(StringComparer.Ordinal).Count()); @@ -366,13 +366,13 @@ public sealed class Phase7Applier private void SafeEnsureFolder(string nodeId, string? parentNodeId, string displayName) { try { _sink.EnsureFolder(nodeId, parentNodeId, displayName); } - catch (Exception ex) { _logger.LogWarning(ex, "Phase7Applier: EnsureFolder threw for {Node}", nodeId); } + catch (Exception ex) { _logger.LogWarning(ex, "AddressSpaceApplier: EnsureFolder threw for {Node}", nodeId); } } private void SafeEnsureVariable(string nodeId, string? parentNodeId, string displayName, string dataType, bool writable, string? historianTagname = null, bool isArray = false, uint? arrayLength = null) { try { _sink.EnsureVariable(nodeId, parentNodeId, displayName, dataType, writable, historianTagname, isArray, arrayLength); } - catch (Exception ex) { _logger.LogWarning(ex, "Phase7Applier: EnsureVariable threw for {Node}", nodeId); } + catch (Exception ex) { _logger.LogWarning(ex, "AddressSpaceApplier: EnsureVariable threw for {Node}", nodeId); } } // A VirtualTag's materialised OPC UA node (MaterialiseEquipmentVirtualTags) is derived ONLY from @@ -381,7 +381,7 @@ public sealed class Phase7Applier // so a delta changing ONLY those three leaves a byte-identical node and needs no address-space rebuild. // Whitelist-of-may-differ via `with` + the record's custom Equals: any OTHER field difference (current // or future) makes the override unequal → falls back to a full rebuild (safe default). - private static bool VtagDeltaIsNodeIrrelevant(Phase7Plan.EquipmentVirtualTagDelta d) => + private static bool VtagDeltaIsNodeIrrelevant(AddressSpacePlan.EquipmentVirtualTagDelta d) => (d.Previous with { Expression = d.Current.Expression, @@ -394,7 +394,7 @@ public sealed class Phase7Applier // ISurgicalAddressSpaceSink.UpdateTagAttributes, avoiding a full rebuild (preserving subscriptions). // DataType / IsArray / ArrayLength / FullName / DriverInstanceId / identity / alarm differences fall // through to a rebuild — the override-unequal default also covers any future field. - private static bool TagDeltaIsSurgicalEligible(Phase7Plan.EquipmentTagDelta d) => + private static bool TagDeltaIsSurgicalEligible(AddressSpacePlan.EquipmentTagDelta d) => d.Previous.Alarm is null && d.Current.Alarm is null && (d.Previous with { @@ -418,18 +418,18 @@ public sealed class Phase7Applier private void SafeWriteAlarmCondition(string nodeId, AlarmConditionSnapshot state, DateTime ts) { try { _sink.WriteAlarmCondition(nodeId, state, ts); } - catch (Exception ex) { _logger.LogWarning(ex, "Phase7Applier: WriteAlarmCondition threw for {Node}", nodeId); } + catch (Exception ex) { _logger.LogWarning(ex, "AddressSpaceApplier: WriteAlarmCondition threw for {Node}", nodeId); } } private void SafeMaterialiseAlarmCondition(string alarmNodeId, string equipmentNodeId, string displayName, string alarmType, int severity, bool isNative) { try { _sink.MaterialiseAlarmCondition(alarmNodeId, equipmentNodeId, displayName, alarmType, severity, isNative); } - catch (Exception ex) { _logger.LogWarning(ex, "Phase7Applier: MaterialiseAlarmCondition threw for {Node}", alarmNodeId); } + catch (Exception ex) { _logger.LogWarning(ex, "AddressSpaceApplier: MaterialiseAlarmCondition threw for {Node}", alarmNodeId); } } } /// Summary of one apply pass. Useful for tests + audit-log entries on the deploy path. -public sealed record Phase7ApplyOutcome( +public sealed record AddressSpaceApplyOutcome( int RemovedNodes, int AddedNodes, int ChangedNodes, diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Phase7Composer.cs b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpaceComposer.cs similarity index 97% rename from src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Phase7Composer.cs rename to src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpaceComposer.cs index 535d0ae4..27cfbfff 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Phase7Composer.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpaceComposer.cs @@ -6,11 +6,11 @@ using ZB.MOM.WW.OtOpcUa.Configuration.Enums; namespace ZB.MOM.WW.OtOpcUa.OpcUaServer; -/// Outcome of — pure value tuple, no side effects. +/// Outcome of — pure value tuple, no side effects. /// + carry the UNS topology so the applier can /// materialise the Area/Line/Equipment folder hierarchy in the address space; equipment carries /// its parent line id so the applier knows where to hang each equipment folder. -public sealed record Phase7CompositionResult( +public sealed record AddressSpaceComposition( IReadOnlyList UnsAreas, IReadOnlyList UnsLines, IReadOnlyList EquipmentNodes, @@ -21,7 +21,7 @@ public sealed record Phase7CompositionResult( /// The equipment nodes. /// The driver instance plans. /// The scripted alarm plans. - public Phase7CompositionResult( + public AddressSpaceComposition( IReadOnlyList equipmentNodes, IReadOnlyList driverInstancePlans, IReadOnlyList scriptedAlarmPlans) @@ -32,7 +32,7 @@ public sealed record Phase7CompositionResult( /// /// Equipment-namespace tags — a with non-null - /// in an Equipment-kind namespace. Phase7Applier.MaterialiseEquipmentTags + /// in an Equipment-kind namespace. AddressSpaceApplier.MaterialiseEquipmentTags /// materialises each as a Variable under its existing equipment folder. Declared as an /// init-only member defaulting to empty (rather than a positional parameter) so every existing /// convenience constructor + call site keeps compiling unchanged; new producers set it via @@ -66,7 +66,7 @@ public sealed record ScriptedAlarmPlan(string ScriptedAlarmId, string EquipmentI /// One Equipment-namespace tag from a row whose /// is non-null and whose owning driver's namespace is Equipment-kind. Carries the stable /// (diff identity), the parent folder (already -/// materialised by Phase7Applier.MaterialiseHierarchy) the variable hangs under, the +/// materialised by AddressSpaceApplier.MaterialiseHierarchy) the variable hangs under, the /// optional sub-folder, the leaf display, the OPC UA /// , and the driver-side reference (extracted from /// Tag.TagConfig) the later values milestone routes reads/writes by. The variable's NodeId @@ -117,7 +117,7 @@ public sealed record EquipmentTagAlarmInfo(string AlarmType, int Severity, bool? /// /// One Equipment-namespace VirtualTag from a row (joined to its /// for the expression). The VirtualTag value analogue of -/// : Phase7Applier.MaterialiseEquipmentVirtualTags +/// : AddressSpaceApplier.MaterialiseEquipmentVirtualTags /// materialises each as a Variable under its equipment folder with a folder-scoped NodeId /// (EquipmentId/Name, or EquipmentId/FolderPath/Name when a sub-folder is set), /// and VirtualTagHostActor spawns a VirtualTagActor per plan that evaluates @@ -252,19 +252,19 @@ public sealed record EquipmentScriptedAlarmPlan( /// startup (Task 53) consumes the result and hands it to the node-manager factory. /// /// #85 — the composer now carries UNS topology ( + -/// ) so Phase7Applier can build the +/// ) so AddressSpaceApplier can build the /// Area/Line/Equipment folder hierarchy in the SDK's address space. The legacy /// EquipmentNodeWalker integration that did this server-side is fully replaced by the /// (composer → applier → sink → node manager) chain. /// -public static class Phase7Composer +public static class AddressSpaceComposer { /// Convenience overload for legacy callers + tests that don't supply UNS topology or tags. /// The equipment. /// The driver instances. /// The scripted alarms. /// The composition result. - public static Phase7CompositionResult Compose( + public static AddressSpaceComposition Compose( IReadOnlyList equipment, IReadOnlyList driverInstances, IReadOnlyList scriptedAlarms) => @@ -278,7 +278,7 @@ public static class Phase7Composer /// The driver instances. /// The scripted alarms. /// The composition result. - public static Phase7CompositionResult Compose( + public static AddressSpaceComposition Compose( IReadOnlyList unsAreas, IReadOnlyList unsLines, IReadOnlyList equipment, @@ -300,7 +300,7 @@ public static class Phase7Composer /// The Equipment-namespace virtual (calculated) tags. null = none. /// The scripts joined to by ScriptId for the expression. null = none. /// The composition result. - public static Phase7CompositionResult Compose( + public static AddressSpaceComposition Compose( IReadOnlyList unsAreas, IReadOnlyList unsLines, IReadOnlyList equipment, @@ -434,7 +434,7 @@ public static class Phase7Composer if (!scriptsById.TryGetValue(a.PredicateScriptId, out var s)) { Trace.TraceWarning( - "Phase7Composer: scripted alarm '{0}' (equipment '{1}') references predicate " + + "AddressSpaceComposer: scripted alarm '{0}' (equipment '{1}') references predicate " + "script '{2}' which is not in the supplied scripts — skipping.", a.ScriptedAlarmId, a.EquipmentId, a.PredicateScriptId); continue; @@ -458,7 +458,7 @@ public static class Phase7Composer Enabled: a.Enabled)); } - return new Phase7CompositionResult(areas, lines, nodes, plans, alarms) + return new AddressSpaceComposition(areas, lines, nodes, plans, alarms) { EquipmentTags = equipmentTags, EquipmentVirtualTags = equipmentVirtualTags, diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Phase7Plan.cs b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpacePlan.cs similarity index 88% rename from src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Phase7Plan.cs rename to src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpacePlan.cs index 0641f75d..e5ecdade 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Phase7Plan.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpacePlan.cs @@ -1,7 +1,7 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer; /// -/// Pure diff between two snapshots — the +/// Pure diff between two snapshots — the /// previous currently-applied composition and the next from a freshly-applied /// deployment. Three lists per entity class (Equipment / DriverInstance / ScriptedAlarm) /// captured by stable identity: added items are new, removed items have to be torn down, @@ -12,22 +12,22 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer; /// nodes that actually changed — full tear-down + rebuild is reserved for first-boot or /// drastic schema flips. /// -public sealed record Phase7Plan( +public sealed record AddressSpacePlan( IReadOnlyList AddedEquipment, IReadOnlyList RemovedEquipment, - IReadOnlyList ChangedEquipment, + IReadOnlyList ChangedEquipment, IReadOnlyList AddedDrivers, IReadOnlyList RemovedDrivers, - IReadOnlyList ChangedDrivers, + IReadOnlyList ChangedDrivers, IReadOnlyList AddedAlarms, IReadOnlyList RemovedAlarms, - IReadOnlyList ChangedAlarms) + IReadOnlyList ChangedAlarms) { /// /// Equipment-namespace tag diff sets, keyed by . Added as /// init-only members (defaulting empty) rather than positional parameters so existing - /// Phase7Plan construction sites compile unchanged — consistent with how - /// was added. Without these, an + /// AddressSpacePlan construction sites compile unchanged — consistent with how + /// was added. Without these, an /// incremental deploy that changes ONLY equipment tags produced an empty plan and /// OpcUaPublishActor.HandleRebuild short-circuited before materialising them. /// @@ -67,7 +67,7 @@ public sealed record Phase7Plan( public sealed record EquipmentVirtualTagDelta(EquipmentVirtualTagPlan Previous, EquipmentVirtualTagPlan Current); } -public static class Phase7Planner +public static class AddressSpacePlanner { /// /// Diff two compositions, emitting Added/Removed/Changed sets per entity class. @@ -77,7 +77,7 @@ public static class Phase7Planner /// /// The previous composition result. /// The new composition result. - public static Phase7Plan Compute(Phase7CompositionResult previous, Phase7CompositionResult next) + public static AddressSpacePlan Compute(AddressSpaceComposition previous, AddressSpaceComposition next) { ArgumentNullException.ThrowIfNull(previous); ArgumentNullException.ThrowIfNull(next); @@ -85,22 +85,22 @@ public static class Phase7Planner var (addedEq, removedEq, changedEq) = DiffById( previous.EquipmentNodes, next.EquipmentNodes, n => n.EquipmentId, - (a, b) => new Phase7Plan.EquipmentDelta(a, b)); + (a, b) => new AddressSpacePlan.EquipmentDelta(a, b)); var (addedDrv, removedDrv, changedDrv) = DiffById( previous.DriverInstancePlans, next.DriverInstancePlans, d => d.DriverInstanceId, - (a, b) => new Phase7Plan.DriverDelta(a, b)); + (a, b) => new AddressSpacePlan.DriverDelta(a, b)); var (addedAlarm, removedAlarm, changedAlarm) = DiffById( previous.ScriptedAlarmPlans, next.ScriptedAlarmPlans, a => a.ScriptedAlarmId, - (a, b) => new Phase7Plan.AlarmDelta(a, b)); + (a, b) => new AddressSpacePlan.AlarmDelta(a, b)); var (addedEqTags, removedEqTags, changedEqTags) = DiffById( previous.EquipmentTags, next.EquipmentTags, t => t.TagId, - (a, b) => new Phase7Plan.EquipmentTagDelta(a, b)); + (a, b) => new AddressSpacePlan.EquipmentTagDelta(a, b)); // VirtualTags diff by VirtualTagId, mirroring the EquipmentTags pass. EquipmentVirtualTagPlan // overrides record equality to compare ALL fields by value — scalars (Expression/DataType/ @@ -110,9 +110,9 @@ public static class Phase7Planner var (addedVTags, removedVTags, changedVTags) = DiffById( previous.EquipmentVirtualTags, next.EquipmentVirtualTags, t => t.VirtualTagId, - (a, b) => new Phase7Plan.EquipmentVirtualTagDelta(a, b)); + (a, b) => new AddressSpacePlan.EquipmentVirtualTagDelta(a, b)); - return new Phase7Plan( + return new AddressSpacePlan( addedEq, removedEq, changedEq, addedDrv, removedDrv, changedDrv, addedAlarm, removedAlarm, changedAlarm) diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OtOpcUaNodeManager.cs b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OtOpcUaNodeManager.cs index ee503ef5..0acb5bea 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OtOpcUaNodeManager.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OtOpcUaNodeManager.cs @@ -25,7 +25,7 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer; /// /// Node-id encoding uses the manager's default namespace + the caller-supplied string id /// as the identifier portion (e.g. "ns=2;s=eq-1/temp"). Equipment-folder hierarchy -/// and OPC UA type metadata still come from the Phase7Applier / EquipmentNodeWalker +/// and OPC UA type metadata still come from the AddressSpaceApplier / EquipmentNodeWalker /// integration (F14b, tracked under #85) — this manager treats every id as a flat /// under the namespace root. /// @@ -1252,7 +1252,7 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2 /// /// Ensure a folder node exists at with the given display /// name, parented under (or the namespace root when null). - /// #85 — used by to materialise the UNS Area/Line/Equipment + /// #85 — used by to materialise the UNS Area/Line/Equipment /// folder hierarchy. Idempotent: the second call with the same id returns the cached /// folder so adding child variables under it still works. /// @@ -1424,7 +1424,7 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2 _ => DataTypeIds.BaseDataType, }; - /// Clear every registered variable + folder from the address space. Phase7Applier + /// Clear every registered variable + folder from the address space. AddressSpaceApplier /// calls this when Equipment/Alarm topology changes; the populator then re-adds via /// EnsureFolder + WriteValue on the next pass. public void RebuildAddressSpace() diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Drivers/DeploymentArtifact.cs b/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Drivers/DeploymentArtifact.cs index d0dc203c..6116dce7 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Drivers/DeploymentArtifact.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Drivers/DeploymentArtifact.cs @@ -169,8 +169,8 @@ public static class DeploymentArtifact } /// - /// Parse the artifact into the projected used by - /// Phase7Planner + Phase7Applier. Returns an empty composition for empty/ + /// Parse the artifact into the projected used by + /// AddressSpacePlanner + AddressSpaceApplier. Returns an empty composition for empty/ /// malformed blobs so callers can treat parse failure as a no-op deploy. /// /// The artifact JSON is produced by ConfigComposer.SnapshotAndFlattenAsync in the @@ -179,7 +179,7 @@ public static class DeploymentArtifact /// nodes. /// /// The deployment artifact blob to parse. - public static Phase7CompositionResult ParseComposition(ReadOnlySpan blob) + public static AddressSpaceComposition ParseComposition(ReadOnlySpan blob) { if (blob.IsEmpty) return Empty(); @@ -197,7 +197,7 @@ public static class DeploymentArtifact var equipmentVirtualTags = BuildEquipmentVirtualTagPlans(root, equipmentTags); var equipmentScriptedAlarms = BuildEquipmentScriptedAlarmPlans(root); - return new Phase7CompositionResult(areas, lines, equipment, drivers, alarms) + return new AddressSpaceComposition(areas, lines, equipment, drivers, alarms) { EquipmentTags = equipmentTags, EquipmentVirtualTags = equipmentVirtualTags, @@ -224,7 +224,7 @@ public static class DeploymentArtifact /// This node's identity in "host:port" form. /// Optional diagnostic callback for cross-cluster orphan bindings; null disables the check. /// The filtered composition per the node's scoping decision. - public static Phase7CompositionResult ParseComposition( + public static AddressSpaceComposition ParseComposition( ReadOnlySpan blob, string nodeId, Action? onInconsistency = null) { var scope = ResolveClusterScope(blob, nodeId); @@ -253,7 +253,7 @@ public static class DeploymentArtifact } } - return new Phase7CompositionResult( + return new AddressSpaceComposition( full.UnsAreas.Where(a => sets.AreaIds.Contains(a.UnsAreaId)).ToArray(), keptLines, keptEquipment, @@ -348,7 +348,7 @@ public static class DeploymentArtifact } } - private static Phase7CompositionResult Empty() => new( + private static AddressSpaceComposition Empty() => new( Array.Empty(), Array.Empty(), Array.Empty(), @@ -359,7 +359,7 @@ public static class DeploymentArtifact /// Cross-reference the artifact's Tags + Namespaces + DriverInstances arrays to find /// Equipment-namespace tags (non-null EquipmentId, owning namespace Kind == Equipment), then /// emit one per qualifying tag. The artifact-decode mirror of - /// Phase7Composer.Compose's equipment filter — so the compose-side + artifact-decode + /// AddressSpaceComposer.Compose's equipment filter — so the compose-side + artifact-decode /// plans agree on the same set of tags. FullName is read from each tag's TagConfig blob /// (top-level "FullName" field). /// @@ -421,7 +421,7 @@ public static class DeploymentArtifact // AccessLevel → Writable. ConfigComposer serialises the TagAccessLevel enum WITHOUT a // string converter, so it lands as a number (Read = 0, ReadWrite = 1); tolerate the string // form ("ReadWrite") too — same defensive both-forms parse as the Kind gate above. MUST match - // Phase7Composer's `AccessLevel == TagAccessLevel.ReadWrite` exactly (byte-parity). A missing + // AddressSpaceComposer's `AccessLevel == TagAccessLevel.ReadWrite` exactly (byte-parity). A missing // field defaults to non-writable (read-only). var writable = el.TryGetProperty("AccessLevel", out var alEl) && alEl.ValueKind switch { @@ -469,7 +469,7 @@ public static class DeploymentArtifact /// /// Join the artifact's VirtualTags array to its Scripts array (by ScriptId) to emit one /// per VirtualTag. The artifact-decode mirror of - /// Phase7Composer.Compose's VirtualTag producer — so the compose-side + artifact-decode + /// AddressSpaceComposer.Compose's VirtualTag producer — so the compose-side + artifact-decode /// plans agree. The reserved {{equip}} token in the joined Script's SourceCode is /// substituted with the owning equipment's tag base (derived from ' /// FullNames) BEFORE refs are extracted, byte-parity with the composer. Expression = the @@ -529,14 +529,14 @@ public static class DeploymentArtifact // Historize: the artifact carries a Pascal-case "Historize" bool (ConfigComposer serialises // the whole VirtualTag entity with DefaultIgnoreCondition.Never). Robust parse — default // false; only honoured when the JSON value is an actual boolean — so absent/non-bool ⇒ false, - // byte-parity with Phase7Composer's entity-default-false behaviour. + // byte-parity with AddressSpaceComposer's entity-default-false behaviour. var historize = el.TryGetProperty("Historize", out var hEl) && (hEl.ValueKind == JsonValueKind.True || hEl.ValueKind == JsonValueKind.False) && hEl.GetBoolean(); // Substitute the {{equip}} token with the owning equipment's tag base BEFORE extracting // refs, so both Expression and DependencyRefs are machine-specific — byte-parity with - // Phase7Composer.Compose. + // AddressSpaceComposer.Compose. var expanded = EquipmentScriptPaths.SubstituteEquipmentToken( source, baseByEquip.GetValueOrDefault(equipmentId!)); @@ -562,7 +562,7 @@ public static class DeploymentArtifact /// /// Join the artifact's ScriptedAlarms array to its Scripts array (by PredicateScriptId) to emit /// one per alarm. The artifact-decode mirror of - /// Phase7Composer.Compose's scripted-alarm producer — so the compose-side + artifact-decode + /// AddressSpaceComposer.Compose's scripted-alarm producer — so the compose-side + artifact-decode /// plans agree byte-for-byte. An alarm whose PredicateScriptId has no matching Script row is /// SKIPPED (matching the composer's skip behaviour) to preserve parity. PredicateSource = the /// joined script source ("" when missing — but such alarms are skipped above); DependencyRefs @@ -616,7 +616,7 @@ public static class DeploymentArtifact if (string.IsNullOrWhiteSpace(scriptedAlarmId)) continue; - // Skip alarms whose predicate script is missing — matching Phase7Composer's skip behaviour + // Skip alarms whose predicate script is missing — matching AddressSpaceComposer's skip behaviour // so both sides emit the same set (byte-parity). if (predicateScriptId is null || !scriptSourceById.TryGetValue(predicateScriptId, out var source)) continue; @@ -646,7 +646,7 @@ public static class DeploymentArtifact /// /// Extract the driver-side full reference from a tag's TagConfig JSON (top-level "FullName" - /// field). The artifact-decode mirror of Phase7Composer.ExtractTagFullName / + /// field). The artifact-decode mirror of AddressSpaceComposer.ExtractTagFullName / /// EquipmentNodeWalker.ExtractFullName — replicated because Runtime does not reference /// the Core driver assembly. Falls back to the raw blob when absent or non-JSON. /// @@ -669,7 +669,7 @@ public static class DeploymentArtifact /// Parses the optional alarm object from a tag's TagConfig JSON. Returns null /// when absent, non-object, or non-JSON (the tag is then a plain variable). Never throws. The - /// live-edit side (Phase7Composer.ExtractTagAlarm) MUST parse identically (byte-parity). + /// live-edit side (AddressSpaceComposer.ExtractTagAlarm) MUST parse identically (byte-parity). private static EquipmentTagAlarmInfo? ExtractTagAlarm(string? tagConfig) { if (string.IsNullOrWhiteSpace(tagConfig)) return null; @@ -683,7 +683,7 @@ public static class DeploymentArtifact var sev = a.TryGetProperty("severity", out var sEl) && sEl.ValueKind == JsonValueKind.Number && sEl.TryGetInt32(out var sv) ? sv : 500; // historizeToAveva (bool?, absent ⇒ null ⇒ historize): byte-parity with - // Phase7Composer.ExtractTagAlarm — only an explicit false suppresses the durable AVEVA write. + // AddressSpaceComposer.ExtractTagAlarm — only an explicit false suppresses the durable AVEVA write. bool? historize = a.TryGetProperty("historizeToAveva", out var hEl) && hEl.ValueKind is JsonValueKind.True or JsonValueKind.False ? hEl.GetBoolean() @@ -699,7 +699,7 @@ public static class DeploymentArtifact /// whitespace-or-empty ⇒ null, meaning the historian tagname defaults to the tag's FullName, /// resolved later). The raw string value is used — not trimmed — matching ExtractTagFullName / /// ExtractTagAlarm. Never throws. The live-edit composer side - /// (Phase7Composer.ExtractTagHistorize) MUST parse identically (byte-parity). + /// (AddressSpaceComposer.ExtractTagHistorize) MUST parse identically (byte-parity). private static (bool IsHistorized, string? HistorianTagname) ExtractTagHistorize(string? tagConfig) { if (string.IsNullOrWhiteSpace(tagConfig)) return (false, null); @@ -727,7 +727,7 @@ public static class DeploymentArtifact /// arrayLength uint (honoured ONLY when isArray is true AND the prop is a JSON number /// that fits uint; else null). Mirrors in structure + /// null/blank/non-object/malformed-JSON tolerance. Never throws. The live-edit composer side - /// (Phase7Composer.ExtractTagArray) MUST parse identically (byte-parity). + /// (AddressSpaceComposer.ExtractTagArray) MUST parse identically (byte-parity). private static (bool IsArray, uint? ArrayLength) ExtractTagArray(string? tagConfig) { if (string.IsNullOrWhiteSpace(tagConfig)) return (false, null); @@ -764,7 +764,7 @@ public static class DeploymentArtifact var item = reader(el); if (item is not null) result.Add(item); } - // Match Phase7Composer's natural-key sort so plan diffs are deterministic across + // Match AddressSpaceComposer's natural-key sort so plan diffs are deterministic across // artifact-decode + composer-compose passes. return result.OrderBy(IdentityOf, StringComparer.Ordinal).ToList(); } diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Drivers/DriverHostActor.cs b/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Drivers/DriverHostActor.cs index 9a4d8701..b708339e 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Drivers/DriverHostActor.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Drivers/DriverHostActor.cs @@ -939,7 +939,7 @@ public sealed class DriverHostActor : ReceiveActor, IWithTimers return; } - Phase7CompositionResult composition; + AddressSpaceComposition composition; try { composition = DeploymentArtifact.ParseComposition(blob, _localNode.Value); diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/OpcUa/OpcUaPublishActor.cs b/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/OpcUa/OpcUaPublishActor.cs index cf18c778..40259377 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/OpcUa/OpcUaPublishActor.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/OpcUa/OpcUaPublishActor.cs @@ -63,7 +63,7 @@ public sealed class OpcUaPublishActor : ReceiveActor, IWithTimers private readonly bool _subscribeRedundancyTopic; private readonly NodeId? _localNode; private readonly IDbContextFactory? _dbFactory; - private readonly Phase7Applier? _applier; + private readonly AddressSpaceApplier? _applier; private readonly IActorRef? _dbHealthProbe; private readonly TimeSpan _staleWindow; private readonly TimeSpan _probeFreshnessWindow; @@ -77,7 +77,7 @@ public sealed class OpcUaPublishActor : ReceiveActor, IWithTimers private DbHealthProbeActor.DbHealthStatus? _lastDbHealth; private RedundancyStateChanged? _lastSnapshot; private (bool Ok, DateTime At)? _probeAboutMe; - private Phase7CompositionResult _lastApplied = new( + private AddressSpaceComposition _lastApplied = new( Array.Empty(), Array.Empty(), Array.Empty(), @@ -116,7 +116,7 @@ public sealed class OpcUaPublishActor : ReceiveActor, IWithTimers IServiceLevelPublisher? serviceLevel = null, NodeId? localNode = null, IDbContextFactory? dbFactory = null, - Phase7Applier? applier = null, + AddressSpaceApplier? applier = null, IActorRef? dbHealthProbe = null, TimeSpan? staleWindow = null, TimeSpan? probeFreshnessWindow = null, @@ -157,7 +157,7 @@ public sealed class OpcUaPublishActor : ReceiveActor, IWithTimers bool subscribeRedundancyTopic = false, NodeId? localNode = null, IDbContextFactory? dbFactory = null, - Phase7Applier? applier = null, + AddressSpaceApplier? applier = null, IActorRef? dbHealthProbe = null, TimeSpan? staleWindow = null, TimeSpan? probeFreshnessWindow = null, @@ -197,7 +197,7 @@ public sealed class OpcUaPublishActor : ReceiveActor, IWithTimers bool subscribeRedundancyTopic, NodeId? localNode, IDbContextFactory? dbFactory = null, - Phase7Applier? applier = null, + AddressSpaceApplier? applier = null, IActorRef? dbHealthProbe = null, TimeSpan? staleWindow = null, TimeSpan? probeFreshnessWindow = null, @@ -308,7 +308,7 @@ public sealed class OpcUaPublishActor : ReceiveActor, IWithTimers ? DeploymentArtifact.ParseComposition(artifact, ln.Value, inconsistency => _log.Warning("OpcUaPublish {Node}: cross-cluster binding — {Message}", ln, inconsistency)) : DeploymentArtifact.ParseComposition(artifact); - var plan = Phase7Planner.Compute(_lastApplied, composition); + var plan = AddressSpacePlanner.Compute(_lastApplied, composition); if (plan.IsEmpty) { @@ -321,7 +321,7 @@ public sealed class OpcUaPublishActor : ReceiveActor, IWithTimers _lastApplied = composition; // #85 — after the plan diff lands, rebuild the UNS folder hierarchy so OPC UA - // clients see Area/Line/Equipment as proper folders. Idempotent; Phase7Applier + // clients see Area/Line/Equipment as proper folders. Idempotent; AddressSpaceApplier // skips folders that already exist with the same node id. _applier.MaterialiseHierarchy(composition); // T14 — scripted alarms get their own pass right after the hierarchy so the equipment diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/ServiceCollectionExtensions.cs b/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/ServiceCollectionExtensions.cs index c0604569..8c873d7a 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/ServiceCollectionExtensions.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/ServiceCollectionExtensions.cs @@ -206,9 +206,9 @@ public static class ServiceCollectionExtensions registry.Register(mux); // OPC UA publish actor — pinned dispatcher, owns the address-space side of the - // pipeline. Phase7Applier is constructed here so the actor + applier share the + // pipeline. AddressSpaceApplier is constructed here so the actor + applier share the // same sink reference (when DeferredAddressSpaceSink swaps later, both see it). - var applier = new Phase7Applier(addressSpaceSink, loggerFactory.CreateLogger()); + var applier = new AddressSpaceApplier(addressSpaceSink, loggerFactory.CreateLogger()); var publishActor = system.ActorOf( OpcUaPublishActor.Props( sink: addressSpaceSink, diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/VirtualTags/VirtualTagHostActor.cs b/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/VirtualTags/VirtualTagHostActor.cs index 61571288..00beb670 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/VirtualTags/VirtualTagHostActor.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.Runtime/VirtualTags/VirtualTagHostActor.cs @@ -20,7 +20,7 @@ namespace ZB.MOM.WW.OtOpcUa.Runtime.VirtualTags; /// /// /// The published NodeId is computed by the shared — -/// the single source of truth Phase7Applier.MaterialiseEquipmentVirtualTags also +/// the single source of truth AddressSpaceApplier.MaterialiseEquipmentVirtualTags also /// materialises against — so the value always lands on a NodeId that exists. /// /// @@ -198,7 +198,7 @@ public sealed class VirtualTagHostActor : ReceiveActor } /// Folder-scoped NodeId for a VirtualTag plan. The formula now lives in the shared - /// (the single source of truth that Phase7Applier also + /// (the single source of truth that AddressSpaceApplier also /// materialises against), so the published value always lands on the NodeId that was materialised. private static string NodeIdFor(EquipmentVirtualTagPlan p) => EquipmentNodeIds.Variable(p.EquipmentId, p.FolderPath, p.Name); diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/Phase7ScriptingEntitiesTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/ScriptingEntitiesTests.cs similarity index 99% rename from tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/Phase7ScriptingEntitiesTests.cs rename to tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/ScriptingEntitiesTests.cs index 5a9df6be..e0b65a4b 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/Phase7ScriptingEntitiesTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/ScriptingEntitiesTests.cs @@ -15,7 +15,7 @@ namespace ZB.MOM.WW.OtOpcUa.Configuration.Tests; /// the plan decisions call for. Introspection only — no SQL Server required. /// [Trait("Category", "Unit")] -public sealed class Phase7ScriptingEntitiesTests +public sealed class ScriptingEntitiesTests { private static OtOpcUaConfigDbContext BuildCtx() { diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/EquipmentNamespaceMaterializationTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/EquipmentNamespaceMaterializationTests.cs index 37ca48fa..e2167ca2 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/EquipmentNamespaceMaterializationTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/EquipmentNamespaceMaterializationTests.cs @@ -20,7 +20,7 @@ namespace ZB.MOM.WW.OtOpcUa.Host.IntegrationTests; /// seam that the OpcUaServer unit tests only approximate with hand-built JSON. /// /// The OPC UA address-space browse is exercised separately against a real SDK node manager in -/// Phase7ApplierHierarchyTests.Equipment_namespace_structure_materialises_end_to_end_against_real_SDK, +/// AddressSpaceApplierHierarchyTests.Equipment_namespace_structure_materialises_end_to_end_against_real_SDK, /// because the in-process binds the no-op address-space sink. /// /// diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierHierarchyTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceApplierHierarchyTests.cs similarity index 93% rename from tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierHierarchyTests.cs rename to tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceApplierHierarchyTests.cs index 0dbaf7db..c533e184 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierHierarchyTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceApplierHierarchyTests.cs @@ -10,13 +10,13 @@ using ZB.MOM.WW.OtOpcUa.Configuration.Enums; namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests; /// -/// #85 — verifies builds the UNS +/// #85 — verifies builds the UNS /// Area/Line/Equipment folder tree through . /// One pure unit test (recording sink) confirms ordering + parenting; one boot-verify test /// drives a real and inspects the resulting predefined-node /// count to prove the folders land in the SDK address space. /// -public sealed class Phase7ApplierHierarchyTests : IDisposable +public sealed class AddressSpaceApplierHierarchyTests : IDisposable { private static CancellationToken Ct => TestContext.Current.CancellationToken; @@ -29,9 +29,9 @@ public sealed class Phase7ApplierHierarchyTests : IDisposable public void MaterialiseHierarchy_creates_areas_then_lines_then_equipment_with_correct_parents() { var sink = new RecordingFolderSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( UnsAreas: new[] { new UnsAreaProjection("area-1", "Plant North") }, UnsLines: new[] { new UnsLineProjection("line-1", "area-1", "Cell A") }, EquipmentNodes: new[] { new EquipmentNode("eq-1", "Pump-1", "line-1") }, @@ -52,9 +52,9 @@ public sealed class Phase7ApplierHierarchyTests : IDisposable public void MaterialiseHierarchy_orphan_equipment_hangs_under_root() { var sink = new RecordingFolderSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( UnsAreas: Array.Empty(), UnsLines: Array.Empty(), EquipmentNodes: new[] { new EquipmentNode("eq-orphan", "Orphan", UnsLineId: "") }, @@ -86,9 +86,9 @@ public sealed class Phase7ApplierHierarchyTests : IDisposable sdkServer.NodeManager.ShouldNotBeNull(); var sink = new SdkAddressSpaceSink(sdkServer.NodeManager!); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - applier.MaterialiseHierarchy(new Phase7CompositionResult( + applier.MaterialiseHierarchy(new AddressSpaceComposition( UnsAreas: new[] { new UnsAreaProjection("area-A", "Area A"), new UnsAreaProjection("area-B", "Area B") }, UnsLines: new[] { new UnsLineProjection("line-1", "area-A", "Line 1") }, EquipmentNodes: new[] { new EquipmentNode("eq-1", "Eq 1", "line-1"), new EquipmentNode("eq-2", "Eq 2", "line-1") }, @@ -98,7 +98,7 @@ public sealed class Phase7ApplierHierarchyTests : IDisposable sdkServer.NodeManager!.FolderCount.ShouldBe(5); // 2 areas + 1 line + 2 equipment // Idempotent: re-applying with the same composition doesn't create duplicates. - applier.MaterialiseHierarchy(new Phase7CompositionResult( + applier.MaterialiseHierarchy(new AddressSpaceComposition( UnsAreas: new[] { new UnsAreaProjection("area-A", "Area A"), new UnsAreaProjection("area-B", "Area B") }, UnsLines: new[] { new UnsLineProjection("line-1", "area-A", "Line 1") }, EquipmentNodes: new[] { new EquipmentNode("eq-1", "Eq 1", "line-1"), new EquipmentNode("eq-2", "Eq 2", "line-1") }, @@ -132,9 +132,9 @@ public sealed class Phase7ApplierHierarchyTests : IDisposable sdkServer.NodeManager.ShouldNotBeNull(); var sink = new SdkAddressSpaceSink(sdkServer.NodeManager!); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( UnsAreas: Array.Empty(), UnsLines: Array.Empty(), EquipmentNodes: new[] { new EquipmentNode("eq-1", "filling-eq", UnsLineId: "") }, @@ -157,7 +157,7 @@ public sealed class Phase7ApplierHierarchyTests : IDisposable /// /// Full structure-materialisation pipeline against a real SDK node manager: real Config - /// entities (Area / Line / Equipment + an Equipment-namespace Tag) → + /// entities (Area / Line / Equipment + an Equipment-namespace Tag) → /// → MaterialiseHierarchy + MaterialiseEquipmentTags → . Proves /// an Equipment namespace lands its Area/Line/Equipment folder tree + the equipment-signal /// Variable in a live OPC UA address space (structure-only; live values are a later milestone). @@ -192,7 +192,7 @@ public sealed class Phase7ApplierHierarchyTests : IDisposable var equipment = new Equipment { EquipmentId = "eq-1", DriverInstanceId = "drv-modbus", UnsLineId = "nw-line-1", Name = "station-1", MachineCode = "STATION_001" }; var tag = new Tag { TagId = "tag-speed", DriverInstanceId = "drv-modbus", EquipmentId = "eq-1", Name = "Speed", DataType = "Float", AccessLevel = TagAccessLevel.Read, TagConfig = "{\"FullName\":\"40001\"}" }; - var composition = Phase7Composer.Compose( + var composition = AddressSpaceComposer.Compose( new[] { area }, new[] { line }, new[] { equipment }, new[] { driver }, Array.Empty(), new[] { tag }, new[] { ns }); @@ -202,7 +202,7 @@ public sealed class Phase7ApplierHierarchyTests : IDisposable planned.FullName.ShouldBe("40001"); var sink = new SdkAddressSpaceSink(sdkServer.NodeManager!); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); applier.MaterialiseHierarchy(composition); applier.MaterialiseEquipmentTags(composition); diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceApplierTests.cs similarity index 89% rename from tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierTests.cs rename to tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceApplierTests.cs index 8d12249f..b11d80a8 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceApplierTests.cs @@ -6,14 +6,14 @@ using ZB.MOM.WW.OtOpcUa.Commons.OpcUa; namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests; -public sealed class Phase7ApplierTests +public sealed class AddressSpaceApplierTests { /// Verifies that an empty plan does not call the sink or trigger a rebuild. [Fact] public void Empty_plan_does_not_call_sink_and_does_not_trigger_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var outcome = applier.Apply(EmptyPlan); @@ -30,7 +30,7 @@ public sealed class Phase7ApplierTests public void Removed_equipment_writes_inactive_alarm_state_per_id_and_triggers_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var plan = WithEquipmentRemoval("eq-1", "eq-2"); var outcome = applier.Apply(plan); @@ -48,18 +48,18 @@ public sealed class Phase7ApplierTests public void Added_equipment_triggers_rebuild_without_alarm_writes() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var plan = new Phase7Plan( + var plan = new AddressSpacePlan( AddedEquipment: new[] { new EquipmentNode("new", "New", "line-1") }, RemovedEquipment: Array.Empty(), - ChangedEquipment: Array.Empty(), + ChangedEquipment: Array.Empty(), AddedDrivers: Array.Empty(), RemovedDrivers: Array.Empty(), - ChangedDrivers: Array.Empty(), + ChangedDrivers: Array.Empty(), AddedAlarms: Array.Empty(), RemovedAlarms: Array.Empty(), - ChangedAlarms: Array.Empty()); + ChangedAlarms: Array.Empty()); var outcome = applier.Apply(plan); @@ -74,23 +74,23 @@ public sealed class Phase7ApplierTests public void Driver_only_changes_do_not_trigger_address_space_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var plan = new Phase7Plan( + var plan = new AddressSpacePlan( AddedEquipment: Array.Empty(), RemovedEquipment: Array.Empty(), - ChangedEquipment: Array.Empty(), + ChangedEquipment: Array.Empty(), AddedDrivers: new[] { new DriverInstancePlan("d-new", "Modbus", "{}") }, RemovedDrivers: Array.Empty(), ChangedDrivers: new[] { - new Phase7Plan.DriverDelta( + new AddressSpacePlan.DriverDelta( new DriverInstancePlan("d-1", "Modbus", "{\"v\":1}"), new DriverInstancePlan("d-1", "Modbus", "{\"v\":2}")), }, AddedAlarms: Array.Empty(), RemovedAlarms: Array.Empty(), - ChangedAlarms: Array.Empty()); + ChangedAlarms: Array.Empty()); var outcome = applier.Apply(plan); @@ -103,7 +103,7 @@ public sealed class Phase7ApplierTests public void Sink_exception_in_WriteAlarmCondition_does_not_propagate_and_rebuild_still_fires() { var sink = new ThrowingSink(throwOnAlarmWrite: true); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var plan = WithEquipmentRemoval("eq-1"); @@ -120,9 +120,9 @@ public sealed class Phase7ApplierTests public void MaterialiseEquipmentTags_creates_variable_under_equipment_folder() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( UnsAreas: Array.Empty(), UnsLines: Array.Empty(), EquipmentNodes: Array.Empty(), @@ -151,9 +151,9 @@ public sealed class Phase7ApplierTests public void MaterialiseEquipmentTags_nests_FolderPath_subfolder_under_equipment() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -178,9 +178,9 @@ public sealed class Phase7ApplierTests public void MaterialiseEquipmentTags_identical_FullName_across_two_equipments_does_not_collide() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -206,9 +206,9 @@ public sealed class Phase7ApplierTests public void MaterialiseEquipmentTags_alarm_bearing_tag_becomes_condition_plain_tag_stays_variable() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -241,9 +241,9 @@ public sealed class Phase7ApplierTests public void MaterialiseEquipmentTags_alarm_bearing_tag_with_FolderPath_conditions_under_subfolder() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -271,9 +271,9 @@ public sealed class Phase7ApplierTests public void MaterialiseEquipmentTags_resolves_historian_tagname_default_override_and_null() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -304,9 +304,9 @@ public sealed class Phase7ApplierTests public void MaterialiseEquipmentTags_blank_override_falls_back_to_full_name() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -324,16 +324,16 @@ public sealed class Phase7ApplierTests } /// Array-support Task 2 — an with IsArray: true, - /// ArrayLength: 16 flowing through must + /// ArrayLength: 16 flowing through must /// forward BOTH flags verbatim to the sink's EnsureVariable. Guards against arg-order swaps or /// accidental drops in the wire-through. [Fact] public void MaterialiseEquipmentTags_array_plan_forwards_isArray_and_arrayLength_to_sink() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -358,9 +358,9 @@ public sealed class Phase7ApplierTests public void MaterialiseEquipmentTags_scalar_plan_forwards_isArray_false_to_sink() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -387,9 +387,9 @@ public sealed class Phase7ApplierTests public void MaterialiseEquipmentTags_array_writable_true_is_forced_read_only() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -417,9 +417,9 @@ public sealed class Phase7ApplierTests public void MaterialiseEquipmentTags_scalar_writable_true_stays_writable() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -446,9 +446,9 @@ public sealed class Phase7ApplierTests public void MaterialiseEquipmentVirtualTags_creates_variable_under_equipment_folder() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentVirtualTags = new[] @@ -469,7 +469,7 @@ public sealed class Phase7ApplierTests /// Golden/parity guard: the materialiser's Variable NodeId for BOTH the equipment-tag and /// the equipment-VirtualTag pass is byte-identical to — the - /// single source of truth Phase7Applier + VirtualTagHostActor both point at. Covers null/empty + /// single source of truth AddressSpaceApplier + VirtualTagHostActor both point at. Covers null/empty /// FolderPath (directly under equipment) and a non-empty FolderPath (sub-folder scoped). This test /// LOCKS the formula against drift: any change to the materialiser NodeId that diverges from the /// shared helper fails here. @@ -477,9 +477,9 @@ public sealed class Phase7ApplierTests public void Materialised_variable_node_ids_match_shared_EquipmentNodeIds_formula() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -512,9 +512,9 @@ public sealed class Phase7ApplierTests public void MaterialiseEquipmentVirtualTags_two_under_same_equipment_do_not_collide() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentVirtualTags = new[] @@ -541,9 +541,9 @@ public sealed class Phase7ApplierTests public void MaterialiseScriptedAlarms_materialises_enabled_and_skips_disabled() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var composition = new Phase7CompositionResult( + var composition = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentScriptedAlarms = new[] @@ -574,7 +574,7 @@ public sealed class Phase7ApplierTests public void Added_equipment_tags_trigger_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var plan = EmptyPlan with { @@ -598,7 +598,7 @@ public sealed class Phase7ApplierTests public void Added_equipment_virtual_tags_trigger_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var plan = EmptyPlan with { @@ -624,7 +624,7 @@ public sealed class Phase7ApplierTests public void Changed_equipment_tags_only_trigger_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "40001", Writable: false, Alarm: null)); @@ -632,7 +632,7 @@ public sealed class Phase7ApplierTests var next = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Int32", FullName: "40001", Writable: true, Alarm: null)); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); // Guard the arrange: ONLY ChangedEquipmentTags is populated. plan.ChangedEquipmentTags.Count.ShouldBe(1); @@ -659,7 +659,7 @@ public sealed class Phase7ApplierTests public void Changed_virtual_tag_expression_only_skips_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithVirtualTags( new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float64", @@ -669,7 +669,7 @@ public sealed class Phase7ApplierTests new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float64", Expression: "ctx.GetTag(\"a\") * 120", DependencyRefs: new[] { "a" })); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); // Guard the arrange: ONLY ChangedEquipmentVirtualTags is populated. plan.ChangedEquipmentVirtualTags.Count.ShouldBe(1); @@ -690,7 +690,7 @@ public sealed class Phase7ApplierTests public void Changed_virtual_tag_dependency_refs_only_skips_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithVirtualTags( new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float64", @@ -703,7 +703,7 @@ public sealed class Phase7ApplierTests new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float64", Expression: "ctx.GetTag(\"a\")", DependencyRefs: new[] { "a", "b" })); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentVirtualTags.Count.ShouldBe(1); var outcome = applier.Apply(plan); @@ -719,7 +719,7 @@ public sealed class Phase7ApplierTests public void Changed_virtual_tag_historize_only_skips_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithVirtualTags( new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float64", @@ -729,7 +729,7 @@ public sealed class Phase7ApplierTests new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float64", Expression: "ctx.GetTag(\"a\")", DependencyRefs: new[] { "a" }, Historize: true)); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentVirtualTags.Count.ShouldBe(1); var outcome = applier.Apply(plan); @@ -747,7 +747,7 @@ public sealed class Phase7ApplierTests public void Changed_virtual_tag_data_type_change_still_rebuilds() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithVirtualTags( new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float64", @@ -757,7 +757,7 @@ public sealed class Phase7ApplierTests new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Int32", Expression: "ctx.GetTag(\"a\") * 60", DependencyRefs: new[] { "a" })); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentVirtualTags.Count.ShouldBe(1); var outcome = applier.Apply(plan); @@ -772,7 +772,7 @@ public sealed class Phase7ApplierTests public void Changed_virtual_tag_name_change_still_rebuilds() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithVirtualTags( new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float64", @@ -781,7 +781,7 @@ public sealed class Phase7ApplierTests new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "EfficiencyPct", DataType: "Float64", Expression: "ctx.GetTag(\"a\")", DependencyRefs: new[] { "a" })); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentVirtualTags.Count.ShouldBe(1); var outcome = applier.Apply(plan); @@ -796,7 +796,7 @@ public sealed class Phase7ApplierTests public void Changed_virtual_tag_folder_path_change_still_rebuilds() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithVirtualTags( new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float64", @@ -805,7 +805,7 @@ public sealed class Phase7ApplierTests new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "Calc", Name: "Efficiency", DataType: "Float64", Expression: "ctx.GetTag(\"a\")", DependencyRefs: new[] { "a" })); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentVirtualTags.Count.ShouldBe(1); var outcome = applier.Apply(plan); @@ -822,9 +822,9 @@ public sealed class Phase7ApplierTests public void Node_irrelevant_vtag_edit_mixed_with_another_change_still_rebuilds() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var previous = new Phase7CompositionResult( + var previous = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -838,7 +838,7 @@ public sealed class Phase7ApplierTests }, }; // Expression-only vtag edit (node-irrelevant) AND a node-affecting tag DataType flip. - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -852,7 +852,7 @@ public sealed class Phase7ApplierTests }, }; - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); // Both a node-irrelevant vtag change AND a node-affecting tag change are present. plan.ChangedEquipmentVirtualTags.Count.ShouldBe(1); @@ -873,7 +873,7 @@ public sealed class Phase7ApplierTests public void Changed_virtual_tag_equipment_id_triggers_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithVirtualTags( new EquipmentVirtualTagPlan("vt-1", "eq-1", FolderPath: "", Name: "Efficiency", DataType: "Float64", @@ -884,7 +884,7 @@ public sealed class Phase7ApplierTests new EquipmentVirtualTagPlan("vt-1", "eq-2", FolderPath: "", Name: "Efficiency", DataType: "Float64", Expression: "ctx.GetTag(\"a\")", DependencyRefs: new[] { "a" })); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); // Guard the arrange: the planner sees this as a changed vtag (same id, different EquipmentId). plan.ChangedEquipmentVirtualTags.Count.ShouldBe(1); @@ -907,9 +907,9 @@ public sealed class Phase7ApplierTests public void Changed_virtual_tags_one_irrelevant_one_structural_triggers_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var previous = new Phase7CompositionResult( + var previous = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentVirtualTags = new[] @@ -922,7 +922,7 @@ public sealed class Phase7ApplierTests Expression: "ctx.GetTag(\"load\")", DependencyRefs: new[] { "load" }), }, }; - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentVirtualTags = new[] @@ -936,7 +936,7 @@ public sealed class Phase7ApplierTests }, }; - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); // Guard the arrange: both vtags are diffed as changed, nothing else. plan.ChangedEquipmentVirtualTags.Count.ShouldBe(2); @@ -961,13 +961,13 @@ public sealed class Phase7ApplierTests public void Changed_alarms_only_trigger_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithAlarms(new ScriptedAlarmPlan("alm-1", "eq-1", "scr-1", "Temp high")); // Same alarm id, edited message template — the planner classifies this as a change. var next = CompositionWithAlarms(new ScriptedAlarmPlan("alm-1", "eq-1", "scr-1", "Temp critically high")); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); // Guard the arrange: ONLY ChangedAlarms is populated. plan.ChangedAlarms.Count.ShouldBe(1); @@ -991,12 +991,12 @@ public sealed class Phase7ApplierTests public void Changed_drivers_only_do_not_trigger_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithDrivers(new DriverInstancePlan("d-1", "Modbus", "{\"v\":1}")); var next = CompositionWithDrivers(new DriverInstancePlan("d-1", "Modbus", "{\"v\":2}")); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); // Guard the arrange: ONLY ChangedDrivers is populated. plan.ChangedDrivers.Count.ShouldBe(1); @@ -1017,15 +1017,15 @@ public sealed class Phase7ApplierTests /// H1a (review follow-up) — a deploy that ONLY removes existing equipment tag / VirtualTag /// nodes must rebuild AND tally the removals. Removed tags/VirtualTags are plain variable nodes (no /// Part 9 condition to write), so before the fix they reached the rebuild path but were never added - /// to removedCountPhase7ApplyOutcome.RemovedNodes reported 0, a misleading audit + /// to removedCountAddressSpaceApplyOutcome.RemovedNodes reported 0, a misleading audit /// entry. This pins both the rebuild and the accurate count. [Fact] public void Removed_equipment_tags_and_virtual_tags_only_rebuild_and_are_counted() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var previous = new Phase7CompositionResult( + var previous = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -1038,10 +1038,10 @@ public sealed class Phase7ApplierTests Expression: "ctx.GetTag(\"a\")", DependencyRefs: new[] { "a" }), }, }; - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); // Guard the arrange: ONLY the two Removed sets are populated. plan.RemovedEquipmentTags.Count.ShouldBe(1); @@ -1069,7 +1069,7 @@ public sealed class Phase7ApplierTests public void Changed_tag_writable_only_skips_rebuild_and_updates_in_place() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "40001", Writable: false, Alarm: null)); @@ -1077,7 +1077,7 @@ public sealed class Phase7ApplierTests var next = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "40001", Writable: true, Alarm: null)); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentTags.Count.ShouldBe(1); plan.AddedEquipmentTags.ShouldBeEmpty(); plan.RemovedEquipmentTags.ShouldBeEmpty(); @@ -1101,8 +1101,8 @@ public sealed class Phase7ApplierTests { // false → true (no override) ⇒ historian defaults to FullName. var sinkOn = new RecordingSink(); - var applierOn = new Phase7Applier(sinkOn, NullLogger.Instance); - var planOn = Phase7Planner.Compute( + var applierOn = new AddressSpaceApplier(sinkOn, NullLogger.Instance); + var planOn = AddressSpacePlanner.Compute( CompositionWithTags(new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "T.A", Writable: false, Alarm: null, IsHistorized: false, HistorianTagname: null)), CompositionWithTags(new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", @@ -1117,8 +1117,8 @@ public sealed class Phase7ApplierTests // true → false ⇒ historian null. var sinkOff = new RecordingSink(); - var applierOff = new Phase7Applier(sinkOff, NullLogger.Instance); - var planOff = Phase7Planner.Compute( + var applierOff = new AddressSpaceApplier(sinkOff, NullLogger.Instance); + var planOff = AddressSpacePlanner.Compute( CompositionWithTags(new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "T.A", Writable: false, Alarm: null, IsHistorized: true, HistorianTagname: null)), CompositionWithTags(new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", @@ -1138,7 +1138,7 @@ public sealed class Phase7ApplierTests public void Changed_tag_historian_tagname_only_skips_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", @@ -1147,7 +1147,7 @@ public sealed class Phase7ApplierTests new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "T.A", Writable: false, Alarm: null, IsHistorized: true, HistorianTagname: "WW.New")); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentTags.Count.ShouldBe(1); var outcome = applier.Apply(plan); @@ -1163,7 +1163,7 @@ public sealed class Phase7ApplierTests public void Changed_tag_data_type_change_rebuilds_and_no_surgical_call() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "40001", Writable: false, Alarm: null)); @@ -1171,7 +1171,7 @@ public sealed class Phase7ApplierTests var next = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Int32", FullName: "40001", Writable: true, Alarm: null)); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentTags.Count.ShouldBe(1); var outcome = applier.Apply(plan); @@ -1187,7 +1187,7 @@ public sealed class Phase7ApplierTests public void Changed_tag_is_array_change_rebuilds() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Buffer", DataType: "Int16", @@ -1196,7 +1196,7 @@ public sealed class Phase7ApplierTests new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Buffer", DataType: "Int16", FullName: "40001", Writable: false, Alarm: null, IsArray: true, ArrayLength: 16u)); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentTags.Count.ShouldBe(1); var outcome = applier.Apply(plan); @@ -1212,14 +1212,14 @@ public sealed class Phase7ApplierTests public void Changed_tag_full_name_change_rebuilds() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "40001", Writable: false, Alarm: null)); var next = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "40002", Writable: false, Alarm: null)); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentTags.Count.ShouldBe(1); var outcome = applier.Apply(plan); @@ -1235,14 +1235,14 @@ public sealed class Phase7ApplierTests public void Changed_tag_name_change_rebuilds() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "40001", Writable: false, Alarm: null)); var next = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "SpeedRpm", DataType: "Float", FullName: "40001", Writable: false, Alarm: null)); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentTags.Count.ShouldBe(1); var outcome = applier.Apply(plan); @@ -1259,7 +1259,7 @@ public sealed class Phase7ApplierTests public void Changed_tag_alarm_presence_change_rebuilds() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "OverTemp", DataType: "Boolean", FullName: "00001", Writable: false, Alarm: null)); @@ -1267,7 +1267,7 @@ public sealed class Phase7ApplierTests new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "OverTemp", DataType: "Boolean", FullName: "00001", Writable: false, Alarm: new EquipmentTagAlarmInfo("OffNormalAlarm", 700))); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentTags.Count.ShouldBe(1); var outcome = applier.Apply(plan); @@ -1288,7 +1288,7 @@ public sealed class Phase7ApplierTests public void Changed_alarm_bearing_tag_writable_only_still_rebuilds() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); // Both previous and current carry an identical, non-null alarm — the tag is an alarm-bearing node. var alarm = new EquipmentTagAlarmInfo("OffNormalAlarm", 700); @@ -1300,7 +1300,7 @@ public sealed class Phase7ApplierTests new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "OverTemp", DataType: "Boolean", FullName: "00001", Writable: true, Alarm: alarm)); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); // Guard the arrange: the planner sees a changed tag (Writable differs) and nothing else. plan.ChangedEquipmentTags.Count.ShouldBe(1); @@ -1323,10 +1323,10 @@ public sealed class Phase7ApplierTests public void Two_surgical_eligible_tag_deltas_both_apply_in_place_no_rebuild() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); // Two distinct plain (no-alarm) tags, both will flip Writable — both are surgical-eligible. - var previous = new Phase7CompositionResult( + var previous = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -1336,7 +1336,7 @@ public sealed class Phase7ApplierTests }, }; // Only Writable flips on both tags; everything else is identical. - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -1346,7 +1346,7 @@ public sealed class Phase7ApplierTests }, }; - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); // Guard the arrange: exactly two changed tags, nothing else. plan.ChangedEquipmentTags.Count.ShouldBe(2); @@ -1380,9 +1380,9 @@ public sealed class Phase7ApplierTests public void Surgical_eligible_tag_delta_mixed_with_added_equipment_rebuilds() { var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); - var previous = new Phase7CompositionResult( + var previous = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -1391,7 +1391,7 @@ public sealed class Phase7ApplierTests }, }; // Surgical-eligible Writable flip on the tag AND a brand-new equipment node. - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( new[] { new EquipmentNode("eq-new", "New", "line-1") }, Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -1400,7 +1400,7 @@ public sealed class Phase7ApplierTests }, }; - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentTags.Count.ShouldBe(1); plan.AddedEquipment.Count.ShouldBe(1); @@ -1418,14 +1418,14 @@ public sealed class Phase7ApplierTests public void Surgical_eligible_delta_on_non_surgical_sink_rebuilds() { var sink = new PlainRecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "40001", Writable: false, Alarm: null)); var next = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "40001", Writable: true, Alarm: null)); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentTags.Count.ShouldBe(1); var outcome = applier.Apply(plan); @@ -1441,14 +1441,14 @@ public sealed class Phase7ApplierTests public void Surgical_sink_returning_false_node_missing_falls_back_to_rebuild() { var sink = new RecordingSink { SurgicalReturns = false }; - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); var previous = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "40001", Writable: false, Alarm: null)); var next = CompositionWithTags( new EquipmentTagPlan("tag-1", "eq-1", "drv", FolderPath: "", Name: "Speed", DataType: "Float", FullName: "40001", Writable: true, Alarm: null)); - var plan = Phase7Planner.Compute(previous, next); + var plan = AddressSpacePlanner.Compute(previous, next); plan.ChangedEquipmentTags.Count.ShouldBe(1); var outcome = applier.Apply(plan); @@ -1458,44 +1458,44 @@ public sealed class Phase7ApplierTests sink.SurgicalCalls.ShouldHaveSingleItem(); // the surgical update was attempted first } - private static Phase7CompositionResult CompositionWithTags(params EquipmentTagPlan[] tags) => + private static AddressSpaceComposition CompositionWithTags(params EquipmentTagPlan[] tags) => new( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = tags, }; - private static Phase7CompositionResult CompositionWithVirtualTags(params EquipmentVirtualTagPlan[] vtags) => + private static AddressSpaceComposition CompositionWithVirtualTags(params EquipmentVirtualTagPlan[] vtags) => new( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentVirtualTags = vtags, }; - private static Phase7CompositionResult CompositionWithAlarms(params ScriptedAlarmPlan[] alarms) => + private static AddressSpaceComposition CompositionWithAlarms(params ScriptedAlarmPlan[] alarms) => // ScriptedAlarmPlans is the set the planner diffs into Added/Removed/ChangedAlarms. new( Array.Empty(), Array.Empty(), alarms); - private static Phase7CompositionResult CompositionWithDrivers(params DriverInstancePlan[] drivers) => + private static AddressSpaceComposition CompositionWithDrivers(params DriverInstancePlan[] drivers) => new( Array.Empty(), drivers, Array.Empty()); - private static Phase7Plan EmptyPlan => new( - Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), Array.Empty(), Array.Empty()); + private static AddressSpacePlan EmptyPlan => new( + Array.Empty(), Array.Empty(), Array.Empty(), + Array.Empty(), Array.Empty(), Array.Empty(), + Array.Empty(), Array.Empty(), Array.Empty()); - private static Phase7Plan WithEquipmentRemoval(params string[] ids) => new( + private static AddressSpacePlan WithEquipmentRemoval(params string[] ids) => new( AddedEquipment: Array.Empty(), RemovedEquipment: ids.Select(id => new EquipmentNode(id, id, "line-1")).ToArray(), - ChangedEquipment: Array.Empty(), + ChangedEquipment: Array.Empty(), AddedDrivers: Array.Empty(), RemovedDrivers: Array.Empty(), - ChangedDrivers: Array.Empty(), + ChangedDrivers: Array.Empty(), AddedAlarms: Array.Empty(), RemovedAlarms: Array.Empty(), - ChangedAlarms: Array.Empty()); + ChangedAlarms: Array.Empty()); private sealed class RecordingSink : IOpcUaAddressSpaceSink, ISurgicalAddressSpaceSink { diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerAliasTagTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerAliasTagTests.cs similarity index 92% rename from tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerAliasTagTests.cs rename to tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerAliasTagTests.cs index f508dbf7..c01d71c6 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerAliasTagTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerAliasTagTests.cs @@ -6,13 +6,13 @@ using ZB.MOM.WW.OtOpcUa.Configuration.Enums; namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests; /// -/// Verifies the live-edit compose seam () treats a Galaxy +/// Verifies the live-edit compose seam () treats a Galaxy /// point as an ordinary equipment tag: GalaxyMxGateway is a standard Equipment-kind driver. /// An equipment-scoped (non-null ) bound to a /// GalaxyMxGateway driver living in an Equipment-kind namespace must surface under -/// (carrying its driver-side FullName). +/// (carrying its driver-side FullName). /// -public sealed class Phase7ComposerAliasTagTests +public sealed class AddressSpaceComposerAliasTagTests { /// A GalaxyMxGateway driver in an Equipment-kind namespace carries an /// equipment-scoped Galaxy tag (EquipmentId set, FolderPath null, TagConfig FullName = the Galaxy @@ -61,7 +61,7 @@ public sealed class Phase7ComposerAliasTagTests TagConfig = "{\"FullName\":\"TestMachine_020.TestChangingInt\"}", }; - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( new[] { area }, new[] { line }, new[] { equip }, new[] { driver }, Array.Empty(), new[] { galaxyTag }, new[] { ns }); diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerEquipTokenTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerEquipTokenTests.cs similarity index 95% rename from tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerEquipTokenTests.cs rename to tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerEquipTokenTests.cs index 215d4ebe..3f216ab3 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerEquipTokenTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerEquipTokenTests.cs @@ -6,12 +6,12 @@ using ZB.MOM.WW.OtOpcUa.Configuration.Enums; namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests; /// -/// Verifies the live-edit compose seam () substitutes the +/// Verifies the live-edit compose seam () substitutes the /// reserved {{equip}} token in a shared VirtualTag script with each owning equipment's /// derived tag base (from its child-tag FullNames) — so one script reused across N /// identical machines resolves to N machine-specific dependency graphs. /// -public sealed class Phase7ComposerEquipTokenTests +public sealed class AddressSpaceComposerEquipTokenTests { /// One shared using ctx.GetTag("{{equip}}.Source"), bound /// to two equipments (TestMachine_001 / _002) each with one equipment Tag whose FullName carries @@ -79,7 +79,7 @@ public sealed class Phase7ComposerEquipTokenTests var vt1 = new VirtualTag { VirtualTagId = "vt-1", EquipmentId = "eq-1", Name = "over50", DataType = "Boolean", ScriptId = "s-equip" }; var vt2 = new VirtualTag { VirtualTagId = "vt-2", EquipmentId = "eq-2", Name = "over50", DataType = "Boolean", ScriptId = "s-equip" }; - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( new[] { area }, new[] { line }, new[] { equip1, equip2 }, new[] { driver1, driver2 }, Array.Empty(), new[] { tag1, tag2 }, new[] { ns }, diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerPurityTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerPurityTests.cs similarity index 91% rename from tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerPurityTests.cs rename to tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerPurityTests.cs index 3fd7388c..075cd5f9 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerPurityTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerPurityTests.cs @@ -4,13 +4,13 @@ using ZB.MOM.WW.OtOpcUa.Configuration.Entities; namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests; -public sealed class Phase7ComposerPurityTests +public sealed class AddressSpaceComposerPurityTests { /// Verifies empty inputs produce empty result. [Fact] public void Empty_inputs_produce_empty_result() { - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( equipment: Array.Empty(), driverInstances: Array.Empty(), scriptedAlarms: Array.Empty()); @@ -31,12 +31,12 @@ public sealed class Phase7ComposerPurityTests var a1 = NewAlarm("a-1", "eq-1"); var a2 = NewAlarm("a-2", "eq-2"); - var r1 = Phase7Composer.Compose( + var r1 = AddressSpaceComposer.Compose( equipment: new[] { e1, e2 }, driverInstances: new[] { d1, d2 }, scriptedAlarms: new[] { a1, a2 }); - var r2 = Phase7Composer.Compose( + var r2 = AddressSpaceComposer.Compose( equipment: new[] { e2, e1 }, driverInstances: new[] { d2, d1 }, scriptedAlarms: new[] { a2, a1 }); @@ -54,8 +54,8 @@ public sealed class Phase7ComposerPurityTests var drivers = new[] { NewDriver("drv-x") }; var alarms = new[] { NewAlarm("alarm-1", "eq-a") }; - var r1 = Phase7Composer.Compose(equipment, drivers, alarms); - var r2 = Phase7Composer.Compose(equipment, drivers, alarms); + var r1 = AddressSpaceComposer.Compose(equipment, drivers, alarms); + var r2 = AddressSpaceComposer.Compose(equipment, drivers, alarms); // Record equality won't help here — IReadOnlyList uses reference equality. Compare // element-wise to verify the pure-function contract. @@ -69,7 +69,7 @@ public sealed class Phase7ComposerPurityTests public void Output_is_sorted_by_natural_key() { var equipment = new[] { NewEquipment("z"), NewEquipment("a"), NewEquipment("m") }; - var result = Phase7Composer.Compose(equipment, Array.Empty(), Array.Empty()); + var result = AddressSpaceComposer.Compose(equipment, Array.Empty(), Array.Empty()); result.EquipmentNodes.Select(e => e.EquipmentId) .ShouldBe(new[] { "a", "m", "z" }); @@ -83,7 +83,7 @@ public sealed class Phase7ComposerPurityTests { var equipment = new[] { NewEquipment("filling-eq") }; // Name="filling-eq", MachineCode="FILLING-EQ" - var node = Phase7Composer.Compose(equipment, Array.Empty(), Array.Empty()) + var node = AddressSpaceComposer.Compose(equipment, Array.Empty(), Array.Empty()) .EquipmentNodes.ShouldHaveSingleItem(); node.EquipmentId.ShouldBe("filling-eq"); // NodeId stays the logical Id @@ -94,7 +94,7 @@ public sealed class Phase7ComposerPurityTests [Fact] public void Composition_carries_empty_equipment_virtualtags_by_default() { - var r = new Phase7CompositionResult( + var r = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()); r.EquipmentVirtualTags.ShouldBeEmpty(); } @@ -133,7 +133,7 @@ public sealed class Phase7ComposerPurityTests SourceHash = "hash-1", }; - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), @@ -171,7 +171,7 @@ public sealed class Phase7ComposerPurityTests SourceHash = "hash-1", }; - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), @@ -197,7 +197,7 @@ public sealed class Phase7ComposerPurityTests ScriptId = "s-does-not-exist", }; - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerScriptedAlarmTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerScriptedAlarmTests.cs similarity index 95% rename from tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerScriptedAlarmTests.cs rename to tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerScriptedAlarmTests.cs index 0be9a0b2..c75dc3c3 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerScriptedAlarmTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerScriptedAlarmTests.cs @@ -5,7 +5,7 @@ using ZB.MOM.WW.OtOpcUa.Configuration.Entities; namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests; /// -/// Verifies the live-edit compose seam () builds the richer +/// Verifies the live-edit compose seam () builds the richer /// per-equipment scripted-alarm projection (): each alarm /// is joined to its predicate for the source, carries the parsed /// ctx.GetTag("…") read refs UNION the {TagPath} tokens referenced in its @@ -13,7 +13,7 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests; /// (including disabled alarms). The projection is deterministic so the upcoming /// artifact-byte-parity test (sibling task) is reliable. /// -public sealed class Phase7ComposerScriptedAlarmTests +public sealed class AddressSpaceComposerScriptedAlarmTests { /// Two equipments, each with a scripted alarm whose predicate script reads one tag via /// ctx.GetTag("X.Y"). Each plan must carry the resolved PredicateSource, DependencyRefs @@ -62,7 +62,7 @@ public sealed class Phase7ComposerScriptedAlarmTests Enabled = true, }; - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), new[] { alarm1, alarm2 }, Array.Empty(), Array.Empty(), @@ -118,7 +118,7 @@ public sealed class Phase7ComposerScriptedAlarmTests PredicateScriptId = "s-1", }; - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), new[] { alarm }, Array.Empty(), Array.Empty(), @@ -155,7 +155,7 @@ public sealed class Phase7ComposerScriptedAlarmTests PredicateScriptId = "s-1", }; - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), new[] { alarm }, Array.Empty(), Array.Empty(), @@ -199,7 +199,7 @@ public sealed class Phase7ComposerScriptedAlarmTests PredicateScriptId = "s-does-not-exist", }; - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), new[] { goodAlarm, orphanAlarm }, Array.Empty(), Array.Empty(), @@ -234,7 +234,7 @@ public sealed class Phase7ComposerScriptedAlarmTests Enabled = false, }; - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), new[] { alarm }, Array.Empty(), Array.Empty(), @@ -261,12 +261,12 @@ public sealed class Phase7ComposerScriptedAlarmTests var a3 = NewAlarm("al-3", "eq-1", "s-3"); var scripts = new[] { script1, script2, script3 }; - var r1 = Phase7Composer.Compose( + var r1 = AddressSpaceComposer.Compose( Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), new[] { a1, a2, a3 }, Array.Empty(), Array.Empty(), scripts: scripts); - var r2 = Phase7Composer.Compose( + var r2 = AddressSpaceComposer.Compose( Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), new[] { a3, a1, a2 }, Array.Empty(), Array.Empty(), scripts: scripts); @@ -282,7 +282,7 @@ public sealed class Phase7ComposerScriptedAlarmTests [Fact] public void Composition_carries_empty_scripted_alarms_by_default() { - var r = new Phase7CompositionResult( + var r = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()); r.EquipmentScriptedAlarms.ShouldBeEmpty(); } diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerVirtualTagHistorizeTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerVirtualTagHistorizeTests.cs similarity index 93% rename from tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerVirtualTagHistorizeTests.cs rename to tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerVirtualTagHistorizeTests.cs index a48499d4..92dc6c4a 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ComposerVirtualTagHistorizeTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpaceComposerVirtualTagHistorizeTests.cs @@ -6,13 +6,13 @@ using ZB.MOM.WW.OtOpcUa.Configuration.Enums; namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests; /// -/// Verifies the live-edit compose seam () carries the +/// Verifies the live-edit compose seam () carries the /// entity column onto the resulting /// (H5a). The flag was authored in the UI but /// never threaded onto the plan, leaving equipment-namespace runtime historization dead. Both a /// true and a false case are asserted so the default (false) and the explicit set both prove out. /// -public sealed class Phase7ComposerVirtualTagHistorizeTests +public sealed class AddressSpaceComposerVirtualTagHistorizeTests { [Fact] public void Compose_carries_virtual_tag_historize_flag_onto_plan() @@ -57,7 +57,7 @@ public sealed class Phase7ComposerVirtualTagHistorizeTests var vtHist = new VirtualTag { VirtualTagId = "vt-hist", EquipmentId = "eq-1", Name = "Historized", DataType = "Int32", ScriptId = "s-1", Historize = true }; var vtPlain = new VirtualTag { VirtualTagId = "vt-plain", EquipmentId = "eq-1", Name = "Plain", DataType = "Int32", ScriptId = "s-1", Historize = false }; - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( new[] { area }, new[] { line }, new[] { equip }, new[] { driver }, Array.Empty(), new[] { tag }, new[] { ns }, diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7PlannerTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpacePlannerTests.cs similarity index 85% rename from tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7PlannerTests.cs rename to tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpacePlannerTests.cs index 2f8c68fe..645056cd 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7PlannerTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/AddressSpacePlannerTests.cs @@ -3,16 +3,16 @@ using Xunit; namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests; -public sealed class Phase7PlannerTests +public sealed class AddressSpacePlannerTests { /// Verifies that empty inputs produce an empty plan. [Fact] public void Empty_inputs_produce_empty_plan() { - var prev = new Phase7CompositionResult(Array.Empty(), Array.Empty(), Array.Empty()); + var prev = new AddressSpaceComposition(Array.Empty(), Array.Empty(), Array.Empty()); var next = prev; - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.IsEmpty.ShouldBeTrue(); } @@ -22,10 +22,10 @@ public sealed class Phase7PlannerTests public void Identical_compositions_produce_empty_plan() { var eq = new EquipmentNode("eq-1", "Eq 1", "line-1"); - var prev = new Phase7CompositionResult(new[] { eq }, Array.Empty(), Array.Empty()); - var next = new Phase7CompositionResult(new[] { eq }, Array.Empty(), Array.Empty()); + var prev = new AddressSpaceComposition(new[] { eq }, Array.Empty(), Array.Empty()); + var next = new AddressSpaceComposition(new[] { eq }, Array.Empty(), Array.Empty()); - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.IsEmpty.ShouldBeTrue(); } @@ -36,9 +36,9 @@ public sealed class Phase7PlannerTests [Fact] public void Equipment_tag_only_change_yields_non_empty_plan_with_added_tag() { - var prev = new Phase7CompositionResult( + var prev = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()); - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -47,7 +47,7 @@ public sealed class Phase7PlannerTests }, }; - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.IsEmpty.ShouldBeFalse(); plan.AddedEquipmentTags.Single().TagId.ShouldBe("tag-1"); @@ -61,9 +61,9 @@ public sealed class Phase7PlannerTests [Fact] public void Equipment_virtual_tag_only_change_yields_non_empty_plan_with_added_tag() { - var prev = new Phase7CompositionResult( + var prev = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()); - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentVirtualTags = new[] @@ -73,7 +73,7 @@ public sealed class Phase7PlannerTests }, }; - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.IsEmpty.ShouldBeFalse(); plan.AddedEquipmentVirtualTags.Single().VirtualTagId.ShouldBe("vt-1"); @@ -85,7 +85,7 @@ public sealed class Phase7PlannerTests [Fact] public void Disappeared_virtual_tag_goes_to_RemovedEquipmentVirtualTags() { - var prev = new Phase7CompositionResult( + var prev = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentVirtualTags = new[] @@ -94,10 +94,10 @@ public sealed class Phase7PlannerTests Expression: "a + b", DependencyRefs: new[] { "a", "b" }), }, }; - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()); - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.IsEmpty.ShouldBeFalse(); plan.RemovedEquipmentVirtualTags.Single().VirtualTagId.ShouldBe("vt-1"); @@ -111,7 +111,7 @@ public sealed class Phase7PlannerTests [Fact] public void Same_id_with_different_expression_routes_to_ChangedEquipmentVirtualTags() { - var prev = new Phase7CompositionResult( + var prev = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentVirtualTags = new[] @@ -120,7 +120,7 @@ public sealed class Phase7PlannerTests Expression: "a + b", DependencyRefs: new[] { "a", "b" }), }, }; - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentVirtualTags = new[] @@ -130,7 +130,7 @@ public sealed class Phase7PlannerTests }, }; - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.IsEmpty.ShouldBeFalse(); plan.ChangedEquipmentVirtualTags.Single().Previous.Expression.ShouldBe("a + b"); @@ -146,7 +146,7 @@ public sealed class Phase7PlannerTests [Fact] public void Same_id_with_toggled_historize_routes_to_ChangedEquipmentVirtualTags() { - var prev = new Phase7CompositionResult( + var prev = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentVirtualTags = new[] @@ -155,7 +155,7 @@ public sealed class Phase7PlannerTests Expression: "a + b", DependencyRefs: new[] { "a", "b" }, Historize: false), }, }; - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentVirtualTags = new[] @@ -165,7 +165,7 @@ public sealed class Phase7PlannerTests }, }; - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.IsEmpty.ShouldBeFalse(); plan.ChangedEquipmentVirtualTags.Single().Previous.Historize.ShouldBeFalse(); @@ -181,7 +181,7 @@ public sealed class Phase7PlannerTests [Fact] public void Same_id_with_toggled_isarray_routes_to_ChangedEquipmentTags() { - var prev = new Phase7CompositionResult( + var prev = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -190,7 +190,7 @@ public sealed class Phase7PlannerTests FullName: "40001", Writable: false, Alarm: null, IsArray: false, ArrayLength: null), }, }; - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentTags = new[] @@ -200,7 +200,7 @@ public sealed class Phase7PlannerTests }, }; - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.IsEmpty.ShouldBeFalse(); plan.ChangedEquipmentTags.Single().Previous.IsArray.ShouldBeFalse(); @@ -221,7 +221,7 @@ public sealed class Phase7PlannerTests var refsA = new[] { "EQ1.Speed", "EQ1.Torque" }; var refsB = new[] { "EQ1.Speed", "EQ1.Torque" }; - var prev = new Phase7CompositionResult( + var prev = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentVirtualTags = new[] @@ -230,7 +230,7 @@ public sealed class Phase7PlannerTests Expression: "ctx.GetTag(\"EQ1.Speed\") / ctx.GetTag(\"EQ1.Torque\")", DependencyRefs: refsA), }, }; - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( Array.Empty(), Array.Empty(), Array.Empty()) { EquipmentVirtualTags = new[] @@ -240,7 +240,7 @@ public sealed class Phase7PlannerTests }, }; - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.IsEmpty.ShouldBeTrue(); plan.ChangedEquipmentVirtualTags.ShouldBeEmpty(); @@ -252,13 +252,13 @@ public sealed class Phase7PlannerTests [Fact] public void New_equipment_goes_to_AddedEquipment() { - var prev = new Phase7CompositionResult(Array.Empty(), Array.Empty(), Array.Empty()); - var next = new Phase7CompositionResult( + var prev = new AddressSpaceComposition(Array.Empty(), Array.Empty(), Array.Empty()); + var next = new AddressSpaceComposition( new[] { new EquipmentNode("eq-1", "A", "line-1") }, Array.Empty(), Array.Empty()); - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.AddedEquipment.Single().EquipmentId.ShouldBe("eq-1"); plan.RemovedEquipment.ShouldBeEmpty(); @@ -269,13 +269,13 @@ public sealed class Phase7PlannerTests [Fact] public void Disappeared_equipment_goes_to_RemovedEquipment() { - var prev = new Phase7CompositionResult( + var prev = new AddressSpaceComposition( new[] { new EquipmentNode("eq-1", "A", "line-1") }, Array.Empty(), Array.Empty()); - var next = new Phase7CompositionResult(Array.Empty(), Array.Empty(), Array.Empty()); + var next = new AddressSpaceComposition(Array.Empty(), Array.Empty(), Array.Empty()); - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.RemovedEquipment.Single().EquipmentId.ShouldBe("eq-1"); plan.AddedEquipment.ShouldBeEmpty(); @@ -285,16 +285,16 @@ public sealed class Phase7PlannerTests [Fact] public void Same_id_with_different_display_name_routes_to_ChangedEquipment() { - var prev = new Phase7CompositionResult( + var prev = new AddressSpaceComposition( new[] { new EquipmentNode("eq-1", "Old", "line-1") }, Array.Empty(), Array.Empty()); - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( new[] { new EquipmentNode("eq-1", "New", "line-1") }, Array.Empty(), Array.Empty()); - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.ChangedEquipment.Single().Previous.DisplayName.ShouldBe("Old"); plan.ChangedEquipment.Single().Current.DisplayName.ShouldBe("New"); @@ -306,16 +306,16 @@ public sealed class Phase7PlannerTests [Fact] public void Driver_config_change_routes_to_ChangedDrivers() { - var prev = new Phase7CompositionResult( + var prev = new AddressSpaceComposition( Array.Empty(), new[] { new DriverInstancePlan("drv-1", "Modbus", "{\"host\":\"old\"}") }, Array.Empty()); - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( Array.Empty(), new[] { new DriverInstancePlan("drv-1", "Modbus", "{\"host\":\"new\"}") }, Array.Empty()); - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.ChangedDrivers.Single().Current.ConfigJson.ShouldContain("new"); } @@ -324,16 +324,16 @@ public sealed class Phase7PlannerTests [Fact] public void Alarm_message_template_change_routes_to_ChangedAlarms() { - var prev = new Phase7CompositionResult( + var prev = new AddressSpaceComposition( Array.Empty(), Array.Empty(), new[] { new ScriptedAlarmPlan("a-1", "eq-1", "script-1", "old") }); - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( Array.Empty(), Array.Empty(), new[] { new ScriptedAlarmPlan("a-1", "eq-1", "script-1", "new") }); - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.ChangedAlarms.Single().Current.MessageTemplate.ShouldBe("new"); } @@ -342,13 +342,13 @@ public sealed class Phase7PlannerTests [Fact] public void Added_and_removed_lists_are_sorted_by_id_for_deterministic_ordering() { - var prev = new Phase7CompositionResult( + var prev = new AddressSpaceComposition( new[] { new EquipmentNode("z", "Z", "line-1"), new EquipmentNode("a", "A", "line-1") }, Array.Empty(), Array.Empty()); - var next = new Phase7CompositionResult(Array.Empty(), Array.Empty(), Array.Empty()); + var next = new AddressSpaceComposition(Array.Empty(), Array.Empty(), Array.Empty()); - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.RemovedEquipment.Select(e => e.EquipmentId).ShouldBe(new[] { "a", "z" }); } @@ -357,16 +357,16 @@ public sealed class Phase7PlannerTests [Fact] public void Mixed_changes_across_all_three_classes_are_captured_in_one_pass() { - var prev = new Phase7CompositionResult( + var prev = new AddressSpaceComposition( new[] { new EquipmentNode("eq-keep", "Keep", "line-1"), new EquipmentNode("eq-drop", "Drop", "line-1") }, new[] { new DriverInstancePlan("drv-keep", "Modbus", "{}"), new DriverInstancePlan("drv-change", "Modbus", "{\"v\":1}") }, new[] { new ScriptedAlarmPlan("a-keep", "eq-keep", "s1", "t1") }); - var next = new Phase7CompositionResult( + var next = new AddressSpaceComposition( new[] { new EquipmentNode("eq-keep", "Keep", "line-1"), new EquipmentNode("eq-new", "New", "line-1") }, new[] { new DriverInstancePlan("drv-keep", "Modbus", "{}"), new DriverInstancePlan("drv-change", "Modbus", "{\"v\":2}") }, new[] { new ScriptedAlarmPlan("a-keep", "eq-keep", "s1", "t1"), new ScriptedAlarmPlan("a-new", "eq-new", "s2", "t2") }); - var plan = Phase7Planner.Compute(prev, next); + var plan = AddressSpacePlanner.Compute(prev, next); plan.AddedEquipment.Single().EquipmentId.ShouldBe("eq-new"); plan.RemovedEquipment.Single().EquipmentId.ShouldBe("eq-drop"); diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/DeferredAddressSpaceSinkTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/DeferredAddressSpaceSinkTests.cs index 2fdae40e..ecd9a2ef 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/DeferredAddressSpaceSinkTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/DeferredAddressSpaceSinkTests.cs @@ -84,7 +84,7 @@ public sealed class DeferredAddressSpaceSinkTests } /// F10b regression: the deferred wrapper MUST forward the surgical capability to a - /// surgical inner sink — otherwise Phase7Applier (which injects THIS wrapper on every + /// surgical inner sink — otherwise AddressSpaceApplier (which injects THIS wrapper on every /// driver-role host, not the inner SdkAddressSpaceSink) never sees the capability and the /// in-place tag-attribute optimization is inert in production (it silently falls back to rebuild). [Fact] diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ExtractTagAlarmTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ExtractTagAlarmTests.cs index 47a96926..49dfd56a 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ExtractTagAlarmTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ExtractTagAlarmTests.cs @@ -14,7 +14,7 @@ public class ExtractTagAlarmTests [InlineData("{\"FullName\":\"X.Y\",\"alarm\":\"oops\"}", false, null, 0)] public void ExtractTagAlarm_parses_or_returns_null(string cfg, bool present, string? type, int sev) { - var info = Phase7Composer.ExtractTagAlarm(cfg); + var info = AddressSpaceComposer.ExtractTagAlarm(cfg); if (!present) { info.ShouldBeNull(); return; } info!.AlarmType.ShouldBe(type); info.Severity.ShouldBe(sev); @@ -30,7 +30,7 @@ public class ExtractTagAlarmTests [InlineData("{\"alarm\":{\"alarmType\":\"LimitAlarm\",\"severity\":500,\"historizeToAveva\":\"oops\"}}", null)] public void ExtractTagAlarm_parses_historizeToAveva(string cfg, bool? expected) { - var info = Phase7Composer.ExtractTagAlarm(cfg); + var info = AddressSpaceComposer.ExtractTagAlarm(cfg); info.ShouldNotBeNull(); info!.HistorizeToAveva.ShouldBe(expected); } diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ExtractTagArrayTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ExtractTagArrayTests.cs index 2a96ad1d..2855eb34 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ExtractTagArrayTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ExtractTagArrayTests.cs @@ -7,12 +7,12 @@ using ZB.MOM.WW.OtOpcUa.OpcUaServer; namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests; /// -/// Verifies parses the optional array intent from a -/// tag's TagConfig JSON exactly as parses +/// Verifies parses the optional array intent from a +/// tag's TagConfig JSON exactly as parses /// the historize intent: the isArray bool (absent / not a bool / non-object root / blank / /// malformed ⇒ false) and the optional arrayLength uint (only honoured when /// isArray is true AND the prop is a JSON number that fits uint; else null). Never -/// throws. Also pins the end-to-end thread-through onto +/// throws. Also pins the end-to-end thread-through onto /// / . /// public class ExtractTagArrayTests @@ -45,13 +45,13 @@ public class ExtractTagArrayTests [InlineData("{\"isArray\":true,\"arrayLength\":4294967296}", true, null)] public void ExtractTagArray_parses_or_returns_defaults(string? cfg, bool expectedIsArray, uint? expectedLength) { - var (isArray, arrayLength) = Phase7Composer.ExtractTagArray(cfg); + var (isArray, arrayLength) = AddressSpaceComposer.ExtractTagArray(cfg); isArray.ShouldBe(expectedIsArray); arrayLength.ShouldBe(expectedLength); } /// End-to-end: an equipment tag whose TagConfig carries isArray/arrayLength - /// surfaces those on its through , + /// surfaces those on its through , /// exactly as the historize keys thread through. [Fact] public void Compose_threads_array_keys_onto_equipment_tag_plan() @@ -94,7 +94,7 @@ public class ExtractTagArrayTests TagConfig = "{\"FullName\":\"40001\",\"isArray\":true,\"arrayLength\":16}", }; - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( new[] { area }, new[] { line }, new[] { equip }, new[] { driver }, Array.Empty(), new[] { arrayTag }, new[] { ns }); @@ -147,7 +147,7 @@ public class ExtractTagArrayTests TagConfig = "{\"FullName\":\"40005\"}", }; - var result = Phase7Composer.Compose( + var result = AddressSpaceComposer.Compose( new[] { area }, new[] { line }, new[] { equip }, new[] { driver }, Array.Empty(), new[] { scalarTag }, new[] { ns }); diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ExtractTagHistorizeTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ExtractTagHistorizeTests.cs index 6404c6d1..a48ce961 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ExtractTagHistorizeTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ExtractTagHistorizeTests.cs @@ -28,7 +28,7 @@ public class ExtractTagHistorizeTests [InlineData("{\"isHistorized\":true,\"historianTagname\":123}", true, null)] public void ExtractTagHistorize_parses_or_returns_defaults(string? cfg, bool expectedHistorized, string? expectedTagname) { - var (isHistorized, historianTagname) = Phase7Composer.ExtractTagHistorize(cfg); + var (isHistorized, historianTagname) = AddressSpaceComposer.ExtractTagHistorize(cfg); isHistorized.ShouldBe(expectedHistorized); historianTagname.ShouldBe(expectedTagname); } diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactAliasParityTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactAliasParityTests.cs index e288aec3..b0362164 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactAliasParityTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactAliasParityTests.cs @@ -178,7 +178,7 @@ public sealed class DeploymentArtifactAliasParityTests /// /// The load-bearing direct byte-parity proof for the two equipment-tag producers: for the SAME - /// input draft, the live-edit composer () and the + /// input draft, the live-edit composer () and the /// artifact decoder () /// must emit IDENTICAL EquipmentTags — element-wise equal on every field /// (TagId, EquipmentId, DriverInstanceId, FolderPath, Name, DataType, FullName) AND in the same @@ -275,7 +275,7 @@ public sealed class DeploymentArtifactAliasParityTests var namespaces = new[] { ns }; // ---- Side 1: the live-edit composer ---- - var composed = Phase7Composer.Compose( + var composed = AddressSpaceComposer.Compose( areas, lines, equipment, drivers, Array.Empty(), tags, namespaces); // ---- Side 2: serialise the SAME draft to the artifact blob shape ConfigComposer emits @@ -349,7 +349,7 @@ public sealed class DeploymentArtifactAliasParityTests /// The native-alarm historizeToAveva opt-out (bool?, the per-condition durable-AVEVA-write /// gate) is parsed by BOTH equipment-tag producers' ExtractTagAlarm and MUST stay byte-parity: /// for the SAME tag TagConfig carrying alarm.historizeToAveva: true (and : false), the - /// live-edit composer () and the artifact decoder + /// live-edit composer () and the artifact decoder /// () must derive the /// identical EquipmentTagAlarmInfo.HistorizeToAveva. The galaxy-tag parity test above already /// covers the absent ⇒ null case; this pins the explicit-bool branch on both sides. @@ -399,7 +399,7 @@ public sealed class DeploymentArtifactAliasParityTests }; // ---- Side 1: the live-edit composer ---- - var composed = Phase7Composer.Compose( + var composed = AddressSpaceComposer.Compose( new[] { area }, new[] { line }, new[] { equip }, new[] { driver }, Array.Empty(), new[] { alarmTag }, new[] { ns }); diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactArrayParityTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactArrayParityTests.cs index 52335e13..5ff6975b 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactArrayParityTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactArrayParityTests.cs @@ -12,7 +12,7 @@ namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Drivers; /// /// Proves the Phase 4c array intent (isArray + optional arrayLength), which rides /// inside the raw TagConfig JSON blob, round-trips with byte-parity through both -/// equipment-tag producers: the live-edit composer () and the +/// equipment-tag producers: the live-edit composer () and the /// artifact decoder (). /// A secondary/follower node decoding a serialized deployment artifact MUST materialise array tags /// identically to the primary, so the artifact side must derive IsArray / ArrayLength @@ -153,7 +153,7 @@ public sealed class DeploymentArtifactArrayParityTests var namespaces = new[] { ns }; // ---- Side 1: the live-edit composer ---- - var composed = Phase7Composer.Compose( + var composed = AddressSpaceComposer.Compose( areas, lines, equipment, drivers, Array.Empty(), tags, namespaces); // ---- Side 2: serialise the SAME draft to the artifact blob shape, then decode it ---- diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactEquipTokenTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactEquipTokenTests.cs index 3ea4c8c4..98ce4523 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactEquipTokenTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactEquipTokenTests.cs @@ -9,7 +9,7 @@ namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Drivers; /// Verifies the artifact-decode mirror substitutes the reserved {{equip}} token in a /// VirtualTag script's ctx.GetTag("…") literals with the owning equipment's tag base /// (derived from its child Equipment-namespace tag's FullName) — byte-parity with -/// Phase7Composer.Compose's live-edit path, using the same shared +/// AddressSpaceComposer.Compose's live-edit path, using the same shared /// EquipmentScriptPaths helper and the same equipmentTags-derived base. /// public sealed class DeploymentArtifactEquipTokenTests diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactHistorizeParityTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactHistorizeParityTests.cs index dec9b8f8..3783aa63 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactHistorizeParityTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactHistorizeParityTests.cs @@ -12,7 +12,7 @@ namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Drivers; /// /// Proves the Phase C HistoryRead intent (isHistorized + optional historianTagname), /// which rides inside the raw TagConfig JSON blob, round-trips with byte-parity through both -/// equipment-tag producers: the live-edit composer () and the +/// equipment-tag producers: the live-edit composer () and the /// artifact decoder (). /// The artifact serializer re-parses the SAME TagConfig string both sides emit, so no /// ConfigComposer change is needed — the flags are already carried in the blob. @@ -120,7 +120,7 @@ public sealed class DeploymentArtifactHistorizeParityTests var namespaces = new[] { ns }; // ---- Side 1: the live-edit composer ---- - var composed = Phase7Composer.Compose( + var composed = AddressSpaceComposer.Compose( areas, lines, equipment, drivers, Array.Empty(), tags, namespaces); // ---- Side 2: serialise the SAME draft to the artifact blob shape, then decode it ---- diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactScriptedAlarmParityTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactScriptedAlarmParityTests.cs index f81080e7..721d5269 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactScriptedAlarmParityTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactScriptedAlarmParityTests.cs @@ -11,7 +11,7 @@ namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Drivers; /// /// Byte-parity tests for the scripted-alarm deployment-artifact decode path /// (DeploymentArtifact.BuildEquipmentScriptedAlarmPlans) against the live compose seam -/// (Phase7Composer.Compose). Both sides derive EquipmentScriptedAlarmPlan from the +/// (AddressSpaceComposer.Compose). Both sides derive EquipmentScriptedAlarmPlan from the /// same ScriptedAlarm + Script data via the shared EquipmentScriptPaths.ExtractAlarmDependencyRefs /// helper, so the decoded plans must equal the composer's element-wise (the record has value /// equality including DependencyRefs order). Mirrors the existing EquipmentVirtualTags parity @@ -70,7 +70,7 @@ public sealed class DeploymentArtifactScriptedAlarmParityTests Enabled = false, }; - var composed = Phase7Composer.Compose( + var composed = AddressSpaceComposer.Compose( Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), new[] { alarm1, alarm2 }, Array.Empty(), Array.Empty(), @@ -189,7 +189,7 @@ public sealed class DeploymentArtifactScriptedAlarmParityTests Enabled = true, }; - var composed = Phase7Composer.Compose( + var composed = AddressSpaceComposer.Compose( Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), new[] { goodAlarm, orphanAlarm }, Array.Empty(), Array.Empty(), diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactTests.cs index 2ab2001c..402175ea 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactTests.cs @@ -257,7 +257,7 @@ public sealed class DeploymentArtifactTests /// Verifies ParseComposition surfaces Equipment-namespace VirtualTags (joined to their Script /// by ScriptId for the expression source) as EquipmentVirtualTags, with the /// DependencyRefs extracted from the script's ctx.GetTag("…") literals — the - /// artifact-decode mirror of Phase7Composer.Compose's VirtualTag producer. + /// artifact-decode mirror of AddressSpaceComposer.Compose's VirtualTag producer. /// [Fact] public void ParseComposition_reads_EquipmentVirtualTags_from_virtualtags_and_scripts() diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactVirtualTagHistorizeParityTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactVirtualTagHistorizeParityTests.cs index 6410bd64..b1d34622 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactVirtualTagHistorizeParityTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DeploymentArtifactVirtualTagHistorizeParityTests.cs @@ -12,7 +12,7 @@ namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Drivers; /// /// Byte-parity tests for the VirtualTag Historize flag across the artifact-decode path /// (DeploymentArtifact.BuildEquipmentVirtualTagPlans) and the live compose seam -/// (Phase7Composer.Compose) — H5b. The artifact JSON already carries a Pascal-case +/// (AddressSpaceComposer.Compose) — H5b. The artifact JSON already carries a Pascal-case /// "Historize" bool (ConfigComposer serialises the whole VirtualTag entity with /// DefaultIgnoreCondition.Never); the decode just had to read it. Both sides default to /// false when the flag is unset/absent/non-bool, so the decoded plans must equal the @@ -65,7 +65,7 @@ public sealed class DeploymentArtifactVirtualTagHistorizeParityTests var vtHist = new VirtualTag { VirtualTagId = "vt-hist", EquipmentId = "eq-1", Name = "Historized", DataType = "Int32", ScriptId = "s-1", Historize = true }; var vtPlain = new VirtualTag { VirtualTagId = "vt-plain", EquipmentId = "eq-1", Name = "Plain", DataType = "Int32", ScriptId = "s-1", Historize = false }; - var composed = Phase7Composer.Compose( + var composed = AddressSpaceComposer.Compose( new[] { area }, new[] { line }, new[] { equip }, new[] { driver }, Array.Empty(), new[] { tag }, new[] { ns }, diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorRebuildTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorRebuildTests.cs index 74341fd9..0a414439 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorRebuildTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorRebuildTests.cs @@ -24,7 +24,7 @@ public sealed class OpcUaPublishActorRebuildTests : RuntimeActorTestBase { var db = NewInMemoryDbFactory(); var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); SeedDeployment(db, equipmentIds: new[] { "eq-1", "eq-2" }, driverIds: new[] { "drv-1" }); @@ -49,7 +49,7 @@ public sealed class OpcUaPublishActorRebuildTests : RuntimeActorTestBase { var db = NewInMemoryDbFactory(); var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); // No deployment seeded — LoadLatestArtifact returns empty blob. var actor = Sys.ActorOf(OpcUaPublishActor.PropsForTests( @@ -69,7 +69,7 @@ public sealed class OpcUaPublishActorRebuildTests : RuntimeActorTestBase { var db = NewInMemoryDbFactory(); var sink = new RecordingSink(); - var applier = new Phase7Applier(sink, NullLogger.Instance); + var applier = new AddressSpaceApplier(sink, NullLogger.Instance); SeedDeployment(db, equipmentIds: new[] { "eq-1" }, driverIds: Array.Empty()); var actor = Sys.ActorOf(OpcUaPublishActor.PropsForTests( @@ -114,7 +114,7 @@ public sealed class OpcUaPublishActorRebuildTests : RuntimeActorTestBase // --- SITE-A node: only the SITE-A tag's variable, never MAIN's. --- var dbA = NewInMemoryDbFactory(); var sinkA = new RecordingSink(); - var applierA = new Phase7Applier(sinkA, NullLogger.Instance); + var applierA = new AddressSpaceApplier(sinkA, NullLogger.Instance); SeedMultiClusterDeployment(dbA); var siteActor = Sys.ActorOf(OpcUaPublishActor.PropsForTests( @@ -134,7 +134,7 @@ public sealed class OpcUaPublishActorRebuildTests : RuntimeActorTestBase // --- MAIN node: the mirror — only MAIN's tag's variable, never SITE-A's. --- var dbM = NewInMemoryDbFactory(); var sinkM = new RecordingSink(); - var applierM = new Phase7Applier(sinkM, NullLogger.Instance); + var applierM = new AddressSpaceApplier(sinkM, NullLogger.Instance); SeedMultiClusterDeployment(dbM); var mainActor = Sys.ActorOf(OpcUaPublishActor.PropsForTests(