diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Enums/NamespaceKind.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Enums/NamespaceKind.cs index 74718cdf..cc0f37b9 100644 --- a/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Enums/NamespaceKind.cs +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Enums/NamespaceKind.cs @@ -10,12 +10,6 @@ public enum NamespaceKind /// Equipment, - /// - /// System Platform namespace — Galaxy / MXAccess processed data (v1 LmxOpcUa folded in). - /// UNS rules do NOT apply; Galaxy hierarchy preserved as v1 expressed it. - /// - SystemPlatform, - /// /// Reserved for future replay driver per handoff §"Digital Twin Touchpoints" — not populated /// in v2.0 but enum value reserved so the schema does not need to change when the replay diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions/DriverTypeRegistry.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions/DriverTypeRegistry.cs index aa60242d..3b0e7313 100644 --- a/src/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions/DriverTypeRegistry.cs +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions/DriverTypeRegistry.cs @@ -110,9 +110,6 @@ public enum NamespaceKindCompatibility /// Driver may populate Equipment-kind namespaces (UNS path, Equipment rows). Equipment = 1, - /// Driver may populate SystemPlatform-kind namespaces (Galaxy hierarchy, FolderPath). - SystemPlatform = 2, - /// Driver may populate the future Simulated namespace (replay driver — not in v2.0). Simulated = 4, } diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NamespaceEdit.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NamespaceEdit.razor index 68499e88..2b09d13f 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NamespaceEdit.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NamespaceEdit.razor @@ -49,7 +49,6 @@ else - diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftValidatorTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftValidatorTests.cs index ef2eeed4..8ca8b1f2 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftValidatorTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests/DraftValidatorTests.cs @@ -136,7 +136,7 @@ public sealed class DraftValidatorTests DriverInstances = [new DriverInstance { DriverInstanceId = "d-1", ClusterId = "c", NamespaceId = "ns-1", Name = "drv", DriverType = "GalaxyMxGateway", DriverConfig = "{}" }], }; - DraftValidator.Validate(draft).ShouldNotContain(e => e.Code == "DriverNamespaceKindMismatch"); + DraftValidator.Validate(draft).ShouldBeEmpty(); } /// Verifies that all validation errors are reported simultaneously. @@ -165,32 +165,15 @@ public sealed class DraftValidatorTests // ------------------------------------------------------------------------------------ /// Probe for the deploy-path gate activation: a full, realistic config modelling - /// the REAL deployed shape (a SystemPlatform namespace + GalaxyMxGateway driver + SystemPlatform - /// Tags with EquipmentId=null from the OtOpcUa seed, PLUS an Equipment namespace + Modbus driver - /// + UNS area/line + canonical Equipment rows + VirtualTags from the company overlay) must + /// the REAL deployed shape. Galaxy is now a standard Equipment-kind driver (the SystemPlatform + /// namespace split is retired), so the GalaxyMxGateway driver + its Galaxy-hierarchy Tags + /// (EquipmentId=null from the seed) live in the Equipment namespace alongside a Modbus driver + /// + UNS area/line + canonical Equipment rows + VirtualTags from the company overlay. This must /// produce ZERO validation errors so the reject-on-any-error gate is safe to activate. [Fact] public void Full_realistic_config_passes_all_rules() { - // SystemPlatform side (OtOpcUa seed shape): Galaxy hierarchy, no Equipment, Tags carry EquipmentId=null. - var spNamespace = new Namespace - { - NamespaceId = "MAIN-OPCUA-systemplatform", - ClusterId = "MAIN", - Kind = NamespaceKind.SystemPlatform, - NamespaceUri = "urn:zb:main:systemplatform", - }; - var spDriver = new DriverInstance - { - DriverInstanceId = "main-galaxy", - ClusterId = "MAIN", - NamespaceId = spNamespace.NamespaceId, - Name = "Galaxy", - DriverType = "GalaxyMxGateway", - DriverConfig = "{}", - }; - - // Equipment side (company overlay): Modbus driver in an Equipment namespace + UNS + canonical equipment. + // Equipment side: Galaxy + Modbus drivers in a single Equipment namespace + UNS + canonical equipment. var eqNamespace = new Namespace { NamespaceId = "MAIN-OPCUA-equipment", @@ -198,6 +181,18 @@ public sealed class DraftValidatorTests Kind = NamespaceKind.Equipment, NamespaceUri = "urn:zb:main:equipment", }; + + // Galaxy hierarchy (OtOpcUa seed shape): GalaxyMxGateway driver, Tags carry EquipmentId=null. + var spDriver = new DriverInstance + { + DriverInstanceId = "main-galaxy", + ClusterId = "MAIN", + NamespaceId = eqNamespace.NamespaceId, + Name = "Galaxy", + DriverType = "GalaxyMxGateway", + DriverConfig = "{}", + }; + var eqDriver = new DriverInstance { DriverInstanceId = "main-modbus", @@ -242,14 +237,14 @@ public sealed class DraftValidatorTests GenerationId = 0, ClusterId = string.Empty, // global snapshot — matches DraftSnapshotFactory.FromConfigDbAsync // Enterprise/Site left null — matches the deploy path's conservative fallback - Namespaces = [spNamespace, eqNamespace], + Namespaces = [eqNamespace], DriverInstances = [spDriver, eqDriver], UnsAreas = [area], UnsLines = [line], Equipment = [rinser, filler], Tags = [ - // SystemPlatform tags from the seed: EquipmentId null, Galaxy folder hierarchy. + // Galaxy-hierarchy tags from the seed: EquipmentId null, Galaxy folder hierarchy. BuildTag(equipmentId: null, name: "PV", folderPath: "Area.Tank01"), BuildTag(equipmentId: null, name: "SP", folderPath: "Area.Tank01"), ], diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests/DriverTypeRegistryTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests/DriverTypeRegistryTests.cs index d9bbc8a4..bbd9990f 100644 --- a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests/DriverTypeRegistryTests.cs +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests/DriverTypeRegistryTests.cs @@ -118,7 +118,7 @@ public sealed class DriverTypeRegistryTests var registry = new DriverTypeRegistry(); registry.Register(SampleMetadata("Modbus")); registry.Register(SampleMetadata("S7")); - registry.Register(SampleMetadata("Galaxy", NamespaceKindCompatibility.SystemPlatform)); + registry.Register(SampleMetadata("Galaxy", NamespaceKindCompatibility.Equipment)); var all = registry.All(); @@ -132,12 +132,14 @@ public sealed class DriverTypeRegistryTests [Fact] public void NamespaceKindCompatibility_FlagsAreBitmask() { - // Per decision #111 — driver types like OpcUaClient may be valid for multiple namespace kinds. - var both = NamespaceKindCompatibility.Equipment | NamespaceKindCompatibility.SystemPlatform; + // Per decision #111 — driver types may be valid for multiple namespace kinds. + var both = NamespaceKindCompatibility.Equipment | NamespaceKindCompatibility.Simulated; both.HasFlag(NamespaceKindCompatibility.Equipment).ShouldBeTrue(); - both.HasFlag(NamespaceKindCompatibility.SystemPlatform).ShouldBeTrue(); - both.HasFlag(NamespaceKindCompatibility.Simulated).ShouldBeFalse(); + both.HasFlag(NamespaceKindCompatibility.Simulated).ShouldBeTrue(); + + // A single-flag value does not carry the other flag — proves these are real bitmask bits. + NamespaceKindCompatibility.Equipment.HasFlag(NamespaceKindCompatibility.Simulated).ShouldBeFalse(); } /// diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceTagTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceTagTests.cs index 68183c7e..99f9e9ee 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceTagTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceTagTests.cs @@ -29,14 +29,14 @@ public sealed class UnsTreeServiceTagTests /// /// Seeds an area→line→equipment path in . The equipment id is /// always EQ-1. Optionally seeds an Equipment-kind driver (DRV-EQ) in the equipment's - /// cluster, a SystemPlatform-kind driver (DRV-SP) in the equipment's cluster, and an - /// Equipment-kind driver (DRV-OTHER) in . + /// cluster, a non-Equipment-kind (Simulated) driver (DRV-SP) in the equipment's cluster, and + /// an Equipment-kind driver (DRV-OTHER) in . /// private static void SeedHierarchyAndDrivers( string dbName, string equipmentCluster, bool seedEquipmentDriver = false, - bool seedSystemPlatformDriver = false, + bool seedNonEquipmentDriver = false, string? otherCluster = null) { using var db = UnsTreeTestDb.CreateNamed(dbName); @@ -59,12 +59,12 @@ public sealed class UnsTreeServiceTagTests Kind = NamespaceKind.Equipment, NamespaceUri = "urn:zb:eq", }); - // SystemPlatform-kind namespace in the equipment's cluster. + // Non-Equipment-kind (Simulated) namespace in the equipment's cluster. db.Namespaces.Add(new Namespace { NamespaceId = "NS-SP", ClusterId = equipmentCluster, - Kind = NamespaceKind.SystemPlatform, + Kind = NamespaceKind.Simulated, NamespaceUri = "urn:zb:sp", }); @@ -81,15 +81,15 @@ public sealed class UnsTreeServiceTagTests }); } - if (seedSystemPlatformDriver) + if (seedNonEquipmentDriver) { db.DriverInstances.Add(new DriverInstance { DriverInstanceId = "DRV-SP", ClusterId = equipmentCluster, NamespaceId = "NS-SP", - Name = "galaxy driver", - DriverType = "Galaxy", + Name = "non-equipment driver", + DriverType = "ModbusTcp", DriverConfig = "{}", }); } @@ -187,12 +187,12 @@ public sealed class UnsTreeServiceTagTests db.Tags.Any(t => t.TagId == "TAG-1").ShouldBeFalse(); } - /// Binding a tree tag to a driver in a SystemPlatform-kind namespace is blocked. + /// Binding a tree tag to a driver in a non-Equipment-kind namespace is blocked. [Fact] - public async Task CreateTag_driver_systemplatform_namespace_blocked() + public async Task CreateTag_driver_non_equipment_namespace_blocked() { var (service, dbName) = Fresh(); - SeedHierarchyAndDrivers(dbName, equipmentCluster: "MAIN", seedSystemPlatformDriver: true); + SeedHierarchyAndDrivers(dbName, equipmentCluster: "MAIN", seedNonEquipmentDriver: true); var result = await service.CreateTagAsync("EQ-1", Input("TAG-1", "speed", "DRV-SP")); @@ -340,7 +340,7 @@ public sealed class UnsTreeServiceTagTests /// /// The driver loader returns only Equipment-kind drivers in the equipment's cluster — excluding - /// SystemPlatform-kind drivers in the same cluster and Equipment-kind drivers in other clusters. + /// non-Equipment-kind drivers in the same cluster and Equipment-kind drivers in other clusters. /// [Fact] public async Task LoadTagDriversForEquipment_returns_only_equipment_kind_drivers_in_cluster() @@ -350,7 +350,7 @@ public sealed class UnsTreeServiceTagTests dbName, equipmentCluster: "MAIN", seedEquipmentDriver: true, - seedSystemPlatformDriver: true, + seedNonEquipmentDriver: true, otherCluster: "SITE-A"); var drivers = await service.LoadTagDriversForEquipmentAsync("EQ-1"); 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 feb93c79..846cd3fa 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 @@ -15,8 +15,8 @@ namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Drivers; /// EquipmentId) bound to a GalaxyMxGateway driver in an Equipment-kind namespace — /// into the decoded EquipmentTags with byte-parity to the live-edit composer path: same FullName, /// EquipmentId, DriverInstanceId, Name, DataType. Both data-contract sites gate purely on the namespace -/// Kind being Equipment (no Galaxy/DriverType exception — the SystemPlatform-mirror contract is -/// retired), so they agree on which tags qualify. +/// Kind being Equipment (no Galaxy/DriverType exception — Galaxy is an ordinary Equipment-kind +/// driver), so they agree on which tags qualify. /// public sealed class DeploymentArtifactAliasParityTests { @@ -64,34 +64,34 @@ public sealed class DeploymentArtifactAliasParityTests tag.FullName.ShouldBe("TestMachine_020.TestChangingInt"); } - /// An equipment-scoped GalaxyMxGateway tag in a SystemPlatform-kind namespace must NOT surface - /// in EquipmentTags — byte-parity with the composer's pure ns.Kind == NamespaceKind.Equipment - /// predicate. The retired SystemPlatform-mirror contract no longer carried a DriverType exception, so a + /// An equipment-scoped tag in a non-Equipment (Simulated) namespace must NOT surface in + /// EquipmentTags — byte-parity with the composer's pure ns.Kind == NamespaceKind.Equipment + /// predicate. The gate keys off the namespace Kind alone, with no DriverType exception, so a /// non-Equipment namespace excludes the tag regardless of driver type. [Fact] - public void ParseComposition_excludes_galaxy_tag_in_non_equipment_namespace() + public void ParseComposition_excludes_tag_in_non_equipment_namespace() { var blob = JsonSerializer.SerializeToUtf8Bytes(new { Namespaces = new[] { - new { NamespaceId = "ns-sp", Kind = 1 }, // NamespaceKind.SystemPlatform + new { NamespaceId = "ns-sim", Kind = 1 }, // NamespaceKind.Simulated (non-Equipment) }, DriverInstances = new[] { - new { DriverInstanceId = "drv-galaxy", DriverType = "GalaxyMxGateway", DriverConfig = "{}", NamespaceId = "ns-sp" }, + new { DriverInstanceId = "drv-sim", DriverType = "Modbus", DriverConfig = "{}", NamespaceId = "ns-sim" }, }, Tags = new object[] { new { TagId = "tag-x", - DriverInstanceId = "drv-galaxy", + DriverInstanceId = "drv-sim", EquipmentId = "eq-1", Name = "Source", FolderPath = (string?)null, DataType = "Int32", - TagConfig = "{\"FullName\":\"TestMachine_020.Source\"}", + TagConfig = "{\"FullName\":\"40001\"}", }, }, }); 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 832af534..2ab2001c 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 @@ -193,10 +193,10 @@ public sealed class DeploymentArtifactTests /// /// Verifies ParseComposition surfaces Equipment-namespace tags (non-null EquipmentId in an /// Equipment-kind namespace) as EquipmentTags, with FullName extracted - /// from the tag's TagConfig blob. A tag in a non-Equipment (SystemPlatform) namespace with a + /// from the tag's TagConfig blob. A tag in a non-Equipment (Simulated) namespace with a /// null EquipmentId must NOT surface in EquipmentTags — byte-parity with the composer's pure - /// ns.Kind == NamespaceKind.Equipment predicate (the SystemPlatform-mirror contract is - /// retired, so such a tag routes nowhere). + /// ns.Kind == NamespaceKind.Equipment predicate (only Equipment-kind namespaces route + /// into EquipmentTags, so such a tag routes nowhere). /// [Fact] public void ParseComposition_reads_EquipmentTags_from_equipment_namespace() @@ -206,12 +206,12 @@ public sealed class DeploymentArtifactTests Namespaces = new[] { new { NamespaceId = "ns-eq", Kind = 0 }, // NamespaceKind.Equipment - new { NamespaceId = "ns-sp", Kind = 1 }, // NamespaceKind.SystemPlatform + new { NamespaceId = "ns-sim", Kind = 1 }, // NamespaceKind.Simulated (non-Equipment) }, DriverInstances = new[] { new { DriverInstanceId = "drv-modbus", DriverType = "Modbus", DriverConfig = "{}", NamespaceId = "ns-eq" }, - new { DriverInstanceId = "drv-galaxy", DriverType = "Galaxy", DriverConfig = "{}", NamespaceId = "ns-sp" }, + new { DriverInstanceId = "drv-sim", DriverType = "Modbus", DriverConfig = "{}", NamespaceId = "ns-sim" }, }, Tags = new object[] { @@ -227,8 +227,8 @@ public sealed class DeploymentArtifactTests }, new { - TagId = "tag-gx", - DriverInstanceId = "drv-galaxy", + TagId = "tag-sim", + DriverInstanceId = "drv-sim", EquipmentId = (string?)null, Name = "Temp", FolderPath = "area", @@ -248,9 +248,9 @@ public sealed class DeploymentArtifactTests tag.DataType.ShouldBe("Float"); tag.FullName.ShouldBe("40001"); // extracted from TagConfig, not the raw blob - // The SystemPlatform tag (null EquipmentId, non-Equipment namespace) does NOT leak into - // EquipmentTags — byte-parity with the composer's pure ns.Kind == Equipment predicate. - c.EquipmentTags.ShouldNotContain(t => t.TagId == "tag-gx"); + // The tag in the non-Equipment (Simulated) namespace, with null EquipmentId, does NOT leak + // into EquipmentTags — byte-parity with the composer's pure ns.Kind == Equipment predicate. + c.EquipmentTags.ShouldNotContain(t => t.TagId == "tag-sim"); } ///