diff --git a/alog.md b/alog.md
index 8a265315..f7818094 100644
--- a/alog.md
+++ b/alog.md
@@ -135,7 +135,7 @@ Single wide table, polymorphic by `Channel` + `Kind` discriminators, JSON payloa
- `IX_AuditLog_Target_Occurred (Target, OccurredAtUtc)` — "what did we send to system X."
- Partitioning by month on `OccurredAtUtc` from day one (purge becomes a partition switch instead of a delete storm).
-**`Kind` values (flat — 17 discriminators across all channels; pinned by `AuditEnumTests`):**
+**`Kind` values (flat — 21 discriminators across all channels; pinned by `AuditEnumTests`):**
| Kind | Fires when |
|---|---|
@@ -156,6 +156,10 @@ Single wide table, polymorphic by `Channel` + `Kind` discriminators, JSON payloa
| `SecuredWriteExpire` | A `Pending` secured write aged past its server-side TTL and was transitioned to `Expired` without executing — emitted by the system (no verifier). |
| `ReconciliationAbandoned` | A reconciliation pull row failed to insert up to the permanent-abandon threshold and central advanced its cursor past it; one synthetic row so the loss is queryable in the Audit Log itself. |
| `ManualFailover` | An administrator triggered a manual failover of the central pair from the Health page; one row per invocation, written BEFORE the graceful `Cluster.Leave` is issued. `Target` = the leaving node's address. |
+| `RouteCall` | Central `Route.To(...).Call(...)` round-trip completed (success or failure). **Always-on** — one row per routed call regardless of tracing; `Extra.childExecutionId` = the site run's `ExecutionId`. Channel `ScriptTrace`. (Flow Debugger, 2026-09-05) |
+| `ScriptRun` | A traced site script run completed/failed/timed out; `Extra.trigger*` carries the trigger for value-change runs. Channel `ScriptTrace`, traced executions only. |
+| `AttributeWrite` | A traced script wrote an attribute (or a batch); `Extra.writes[]` lists each write's outcome. Channel `ScriptTrace`, traced executions only. |
+| `AttributeWait` | A traced script's `WaitAsync`/`WaitForAsync` resolved (satisfied / timeout / cancelled / error) with the observed value. Channel `ScriptTrace`, traced executions only. |
### Site: `AuditLog` (SQLite)
diff --git a/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AuditChannel.cs b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AuditChannel.cs
index 3e643b62..069d896d 100644
--- a/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AuditChannel.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AuditChannel.cs
@@ -21,5 +21,13 @@ public enum AuditChannel
/// restarted the active node, which is exactly the kind of act an audit log exists to
/// attribute. (decision 2026-07-22)
///
- Cluster
+ Cluster,
+
+ ///
+ /// Flow Debugger trace rows (design 2026-09-05): a script run, an attribute write, an
+ /// attribute wait or a central route call, emitted only for traced executions
+ /// (plus the always-on ). Appended last so stored
+ /// ordinals of existing channels never move.
+ ///
+ ScriptTrace
}
diff --git a/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AuditKind.cs b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AuditKind.cs
index e5ed83d0..4e86bacc 100644
--- a/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AuditKind.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AuditKind.cs
@@ -49,5 +49,17 @@ public enum AuditKind
/// is issued (the acting node is usually not the one that goes away, but the audit must
/// survive either outcome). (decision 2026-07-22)
///
- ManualFailover
+ ManualFailover,
+
+ /// Central Route.To().Call round-trip (always-on; channel).
+ RouteCall,
+
+ /// One site script run completed/failed/timed out (traced executions only; ).
+ ScriptRun,
+
+ /// One attribute write or batch write made by a traced script (traced executions only; ).
+ AttributeWrite,
+
+ /// One WaitAsync/WaitForAsync outcome in a traced script (traced executions only; ).
+ AttributeWait
}
diff --git a/tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/Audit/ScriptTraceEnumTests.cs b/tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/Audit/ScriptTraceEnumTests.cs
new file mode 100644
index 00000000..dcd159a7
--- /dev/null
+++ b/tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/Audit/ScriptTraceEnumTests.cs
@@ -0,0 +1,31 @@
+using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
+using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
+
+namespace ZB.MOM.WW.ScadaBridge.Commons.Tests.Audit;
+
+///
+/// Flow Debugger (design 2026-09-05): the ScriptTrace channel and its four kinds must
+/// fit the central AuditLog.Category/Kind columns and never move existing ordinals.
+///
+public class ScriptTraceEnumTests
+{
+ [Theory]
+ [InlineData(AuditKind.RouteCall)]
+ [InlineData(AuditKind.ScriptRun)]
+ [InlineData(AuditKind.AttributeWrite)]
+ [InlineData(AuditKind.AttributeWait)]
+ public void ScriptTraceKinds_FitTheCentralColumns(AuditKind kind)
+ {
+ // AuditLog.Category / Kind are nvarchar(32) (AuditLogEntityTypeConfiguration).
+ Assert.True(kind.ToString().Length <= 32);
+ Assert.True(AuditChannel.ScriptTrace.ToString().Length <= 32);
+ Assert.Equal($"ScriptTrace.{kind}", AuditFieldBuilders.BuildAction(AuditChannel.ScriptTrace, kind));
+ }
+
+ [Fact]
+ public void ScriptTrace_IsAppendedAfterCluster_SoExistingOrdinalsAreStable()
+ {
+ Assert.True((int)AuditChannel.ScriptTrace > (int)AuditChannel.Cluster);
+ Assert.True((int)AuditKind.RouteCall > (int)AuditKind.ManualFailover);
+ }
+}
diff --git a/tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/Types/Enums/AuditEnumTests.cs b/tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/Types/Enums/AuditEnumTests.cs
index b2176564..6e57625f 100644
--- a/tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/Types/Enums/AuditEnumTests.cs
+++ b/tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/Types/Enums/AuditEnumTests.cs
@@ -12,7 +12,7 @@ public class AuditEnumTests
[Fact]
public void AuditChannel_HasExactlyExpectedMembers()
{
- var expected = new[] { "ApiOutbound", "DbOutbound", "Notification", "ApiInbound", "SecuredWrite", "Cluster" };
+ var expected = new[] { "ApiOutbound", "DbOutbound", "Notification", "ApiInbound", "SecuredWrite", "Cluster", "ScriptTrace" };
var actual = Enum.GetValues(typeof(AuditChannel))
.Cast()
.Select(x => x.ToString())
@@ -23,7 +23,7 @@ public class AuditEnumTests
}
[Fact]
- public void AuditKind_HasExactlySeventeenExpectedMembers()
+ public void AuditKind_HasExactlyTwentyOneExpectedMembers()
{
var expected = new[]
{
@@ -34,13 +34,14 @@ public class AuditEnumTests
"SecuredWriteExpire",
"ReconciliationAbandoned",
"ManualFailover",
+ "RouteCall", "ScriptRun", "AttributeWrite", "AttributeWait",
};
var actual = Enum.GetValues(typeof(AuditKind))
.Cast()
.Select(x => x.ToString())
.ToArray();
- Assert.Equal(17, actual.Length);
+ Assert.Equal(21, actual.Length);
Assert.Equal(expected, actual);
}