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