feat(server): equipment-tag node writability from Tag.AccessLevel (parity-safe, no migration)

This commit is contained in:
Joseph Doherty
2026-06-13 11:46:00 -04:00
parent f8f1027287
commit a23fb2b82e
15 changed files with 170 additions and 43 deletions
@@ -71,7 +71,11 @@ public sealed record ScriptedAlarmPlan(string ScriptedAlarmId, string EquipmentI
/// <see cref="DataType"/>, and the driver-side <see cref="FullName"/> reference (extracted from
/// <c>Tag.TagConfig</c>) the later values milestone routes reads/writes by. The variable's NodeId
/// is folder-scoped (<c>parent/Name</c>), NOT <see cref="FullName"/>, because a raw driver ref
/// (e.g. a Modbus register) is not unique across identical machines.
/// (e.g. a Modbus register) is not unique across identical machines. <see cref="Writable"/>
/// mirrors the authored <c>Tag.AccessLevel == ReadWrite</c> so the materialised node is created
/// <c>CurrentReadWrite</c> (the prerequisite for the inbound-write pipeline); a <c>Read</c> tag
/// stays read-only. This flag is derived identically on the artifact-decode side
/// (<c>DeploymentArtifact.BuildEquipmentTagPlans</c>) for byte-parity.
/// </summary>
public sealed record EquipmentTagPlan(
string TagId,
@@ -80,7 +84,8 @@ public sealed record EquipmentTagPlan(
string FolderPath,
string Name,
string DataType,
string FullName);
string FullName,
bool Writable);
/// <summary>
/// One Equipment-namespace VirtualTag from a <see cref="VirtualTag"/> row (joined to its
@@ -322,7 +327,8 @@ public static class Phase7Composer
FolderPath: t.FolderPath ?? string.Empty,
Name: t.Name,
DataType: t.DataType,
FullName: ExtractTagFullName(t.TagConfig)))
FullName: ExtractTagFullName(t.TagConfig),
Writable: t.AccessLevel == TagAccessLevel.ReadWrite))
.ToList();
// Per-equipment tag base = the shared substring-before-first-dot across each equipment's