diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/CorrelationId.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/CorrelationId.cs
new file mode 100644
index 0000000..da7894e
--- /dev/null
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/CorrelationId.cs
@@ -0,0 +1,13 @@
+namespace ZB.MOM.WW.OtOpcUa.Commons.Types;
+
+public readonly record struct CorrelationId(Guid Value)
+{
+ public static CorrelationId NewId() => new(Guid.NewGuid());
+ public override string ToString() => Value.ToString("N");
+ public static CorrelationId Parse(string s) => new(Guid.ParseExact(s, "N"));
+ public static bool TryParse(string? s, out CorrelationId id)
+ {
+ if (Guid.TryParseExact(s, "N", out var g)) { id = new CorrelationId(g); return true; }
+ id = default; return false;
+ }
+}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/DeploymentId.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/DeploymentId.cs
new file mode 100644
index 0000000..8d74194
--- /dev/null
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/DeploymentId.cs
@@ -0,0 +1,13 @@
+namespace ZB.MOM.WW.OtOpcUa.Commons.Types;
+
+public readonly record struct DeploymentId(Guid Value)
+{
+ public static DeploymentId NewId() => new(Guid.NewGuid());
+ public override string ToString() => Value.ToString("N");
+ public static DeploymentId Parse(string s) => new(Guid.ParseExact(s, "N"));
+ public static bool TryParse(string? s, out DeploymentId id)
+ {
+ if (Guid.TryParseExact(s, "N", out var g)) { id = new DeploymentId(g); return true; }
+ id = default; return false;
+ }
+}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/ExecutionId.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/ExecutionId.cs
new file mode 100644
index 0000000..7920a66
--- /dev/null
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/ExecutionId.cs
@@ -0,0 +1,13 @@
+namespace ZB.MOM.WW.OtOpcUa.Commons.Types;
+
+public readonly record struct ExecutionId(Guid Value)
+{
+ public static ExecutionId NewId() => new(Guid.NewGuid());
+ public override string ToString() => Value.ToString("N");
+ public static ExecutionId Parse(string s) => new(Guid.ParseExact(s, "N"));
+ public static bool TryParse(string? s, out ExecutionId id)
+ {
+ if (Guid.TryParseExact(s, "N", out var g)) { id = new ExecutionId(g); return true; }
+ id = default; return false;
+ }
+}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/NodeId.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/NodeId.cs
new file mode 100644
index 0000000..273f7a3
--- /dev/null
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/NodeId.cs
@@ -0,0 +1,20 @@
+namespace ZB.MOM.WW.OtOpcUa.Commons.Types;
+
+///
+/// Logical cluster node identifier — typically the host name configured on a fused
+/// OtOpcUa.Host instance. NOT to be confused with OPC UA NodeId from the
+/// Opc.Ua.Core stack.
+///
+public readonly record struct NodeId(string Value)
+{
+ public override string ToString() => Value;
+ public static NodeId Parse(string s) =>
+ string.IsNullOrWhiteSpace(s)
+ ? throw new ArgumentException("NodeId value cannot be empty.", nameof(s))
+ : new NodeId(s);
+ public static bool TryParse(string? s, out NodeId id)
+ {
+ if (!string.IsNullOrWhiteSpace(s)) { id = new NodeId(s); return true; }
+ id = default; return false;
+ }
+}
diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/RevisionHash.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/RevisionHash.cs
new file mode 100644
index 0000000..30440eb
--- /dev/null
+++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/RevisionHash.cs
@@ -0,0 +1,19 @@
+namespace ZB.MOM.WW.OtOpcUa.Commons.Types;
+
+///
+/// SHA-256 hex digest identifying a config snapshot revision. Storage form is lowercase
+/// 64-char hex (no 0x prefix). Empty hash is invalid.
+///
+public readonly record struct RevisionHash(string Value)
+{
+ public override string ToString() => Value;
+ public static RevisionHash Parse(string s) =>
+ string.IsNullOrWhiteSpace(s)
+ ? throw new ArgumentException("RevisionHash value cannot be empty.", nameof(s))
+ : new RevisionHash(s);
+ public static bool TryParse(string? s, out RevisionHash hash)
+ {
+ if (!string.IsNullOrWhiteSpace(s)) { hash = new RevisionHash(s); return true; }
+ hash = default; return false;
+ }
+}