diff --git a/archreview/plans/R2-11-tagconfig-consolidation-plan.md.tasks.json b/archreview/plans/R2-11-tagconfig-consolidation-plan.md.tasks.json
index 85846869..92f4e5b6 100644
--- a/archreview/plans/R2-11-tagconfig-consolidation-plan.md.tasks.json
+++ b/archreview/plans/R2-11-tagconfig-consolidation-plan.md.tasks.json
@@ -10,7 +10,7 @@
{ "id": "T6", "subject": "Device-host re-home: composer TryExtractDeviceHost/NormalizeDeviceHost → DeviceConfigIntent; update DriverHostActor + DeploymentArtifact callers", "status": "completed", "blockedBy": ["T4", "T5"] },
{ "id": "T7", "subject": "DeploymentArtifact swap: delete 4 private mirrors, parse once per tag element via TagConfigIntent", "status": "completed", "blockedBy": ["T5"] },
{ "id": "T8", "subject": "DraftValidator swap: Configuration→Commons ProjectReference; ExtractTagConfigFullName → TagConfigIntent.ExplicitFullName (null-on-absent preserved)", "status": "completed", "blockedBy": ["T2", "T3"] },
- { "id": "T9", "subject": "EquipmentNodeWalker.ExtractFullName delegates to TagConfigIntent; repoint tree-wide canonical-parser doc cites", "status": "pending", "blockedBy": ["T2", "T3"] },
+ { "id": "T9", "subject": "EquipmentNodeWalker.ExtractFullName delegates to TagConfigIntent; repoint tree-wide canonical-parser doc cites", "status": "completed", "blockedBy": ["T2", "T3"] },
{ "id": "T10", "subject": "Retire OpcUaServer.Tests ExtractTag*Tests (authority moved to Commons.Tests); verify zero 'MUST parse identically' hits", "status": "pending", "blockedBy": ["T3", "T5"] },
{ "id": "T11", "subject": "TagConfigJson strict-capable readers in Core.Abstractions (TryReadEnum Absent/Valid/Invalid, ReadEnumOrDefault, ReadWritable, DescribeInvalidEnum) (TDD)", "status": "pending", "blockedBy": [] },
{ "id": "T12", "subject": "Modbus equipment-tag parser: freeze test, shared readers, honour writable key, Inspect warnings", "status": "pending", "blockedBy": ["T11"] },
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Core/OpcUa/EquipmentNodeWalker.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Core/OpcUa/EquipmentNodeWalker.cs
index 217cca88..96eacf2b 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Core/OpcUa/EquipmentNodeWalker.cs
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Core/OpcUa/EquipmentNodeWalker.cs
@@ -1,4 +1,4 @@
-using System.Text.Json;
+using ZB.MOM.WW.OtOpcUa.Commons.Types;
using ZB.MOM.WW.OtOpcUa.Configuration.Entities;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
@@ -190,22 +190,8 @@ public static class EquipmentNodeWalker
///
/// The tag configuration JSON or string.
/// The extracted FullName value, or the raw if it can't be extracted.
- internal static string ExtractFullName(string tagConfig)
- {
- if (string.IsNullOrWhiteSpace(tagConfig)) return tagConfig;
- try
- {
- using var doc = JsonDocument.Parse(tagConfig);
- if (doc.RootElement.ValueKind == JsonValueKind.Object
- && doc.RootElement.TryGetProperty("FullName", out var fullName)
- && fullName.ValueKind == JsonValueKind.String)
- {
- return fullName.GetString() ?? tagConfig;
- }
- }
- catch (JsonException) { /* fall through */ }
- return tagConfig;
- }
+ internal static string ExtractFullName(string tagConfig) =>
+ TagConfigIntent.Parse(tagConfig).FullName;
///
/// Parse (stored as the enum
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Core/ZB.MOM.WW.OtOpcUa.Core.csproj b/src/Core/ZB.MOM.WW.OtOpcUa.Core/ZB.MOM.WW.OtOpcUa.Core.csproj
index 44c4f648..6cd66876 100644
--- a/src/Core/ZB.MOM.WW.OtOpcUa.Core/ZB.MOM.WW.OtOpcUa.Core.csproj
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Core/ZB.MOM.WW.OtOpcUa.Core.csproj
@@ -14,6 +14,8 @@
+
+
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 fe607acc..8e8eea22 100644
--- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/ScriptAnalysis/IScriptTagCatalog.cs
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/ScriptAnalysis/IScriptTagCatalog.cs
@@ -53,7 +53,7 @@ public sealed record ScriptTagInfo(string Path, string Kind, string DataType, st
/// DriverInstanceActor.AttributeValuePublished.FullReference
/// (src/Server/…Runtime/VirtualTags/DependencyMuxActor.cs:97) — and that
/// FullReference is the FullName field extracted from Tag.TagConfig
-/// (see AddressSpaceComposer.ExtractTagFullName + EquipmentNodeWalker.ExtractFullName).
+/// (see Commons.Types.TagConfigIntent.Parse, the shared byte-parity FullName authority).
/// 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.
@@ -179,8 +179,8 @@ 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 / AddressSpaceComposer.ExtractTagFullName
- /// (AdminUI does not reference those assemblies). Falls back to the raw blob when it is not
+ /// Commons.Types.TagConfigIntent.Parse(...).FullName (the shared byte-parity authority;
+ /// AdminUI does not reference that assembly here). Falls back to the raw blob when it is not
/// a JSON object carrying a string FullName.
///
private static string ExtractFullNameFromTagConfig(string tagConfig)
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 82a6348b..86deb8ee 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
@@ -7,9 +7,9 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors;
/// stable nsu=…;s=… or plain ns=2;s=… NodeId the driver reads/writes/subscribes against).
/// Preserves unrecognised JSON keys across a load→save.
///
-/// The FullName key is intentionally PascalCase: the deploy-time composer + node walker
-/// (AddressSpaceComposer.ExtractTagFullName, EquipmentNodeWalker) read it via a
-/// case-sensitive TryGetProperty("FullName", …), so the editor MUST persist that exact
+/// The FullName key is intentionally PascalCase: the shared deploy-time parser
+/// (Commons.Types.TagConfigIntent.Parse, consumed by the composer, artifact decoder, draft
+/// gate, and node walker) reads 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
/// () and survive a load→save of this model as preserved unknown keys.
diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpaceApplier.cs b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpaceApplier.cs
index 3fba3d99..b3980942 100644
--- a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpaceApplier.cs
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpaceApplier.cs
@@ -647,7 +647,7 @@ public sealed class AddressSpaceApplier
// REACH (live-verified): the shape path only fires for drivers whose TagConfig carries a stable
// top-level "FullName" (Galaxy = tag_name.AttributeName; OpcUaClient = the node id) — there a DataType/array
// edit leaves FullName untouched ⇒ surgical. For structured-TagConfig protocol drivers (Modbus/S7/AbCip/…)
- // AddressSpaceComposer.ExtractTagFullName falls back to the RAW TagConfig blob as FullName, so a DataType/
+ // TagConfigIntent.Parse falls back to the RAW TagConfig blob as FullName, so a DataType/
// array edit also mutates that blob ⇒ FullName differs ⇒ this returns false ⇒ full rebuild. That is the
// correct safe default (a protocol driver's subscription needs re-spawning for a new shape anyway).
private static bool TagDeltaIsSurgicalEligible(AddressSpacePlan.EquipmentTagDelta d) =>