feat(auditlog): site script-side emitters stamp ExecutionId

Move the per-script-execution Guid on ScriptRuntimeContext from
_auditCorrelationId to _executionId, and stamp it into the dedicated
AuditEvent.ExecutionId column on every script-side audit row:

- Sync ApiCall / DbWrite: ExecutionId set; CorrelationId reverts to
  null (a sync one-shot call has no operation lifecycle).
- Cached-call script-side rows (CachedSubmit, immediate-completion
  ApiCallCached + CachedResolve) and NotifySend: ExecutionId set;
  CorrelationId unchanged (per-operation TrackedOperationId /
  NotificationId).

Renames the threaded ctor param/field across ExternalSystemHelper,
DatabaseHelper, AuditingDbConnection and AuditingDbCommand, and threads
the id through NotifyHelper/NotifyTarget. The S&F retry-loop cached rows
(CachedCallLifecycleBridge) are out of scope here.
This commit is contained in:
Joseph Doherty
2026-05-21 15:05:00 -04:00
parent 6b16a48886
commit 0149ce6180
10 changed files with 193 additions and 95 deletions

View File

@@ -41,6 +41,12 @@ public class ExternalSystemCachedCallEmissionTests
private const string InstanceName = "Plant.Pump42";
private const string SourceScript = "ScriptActor:CheckPressure";
/// <summary>
/// Audit Log #23: a fixed per-execution id so the cached-row tests can
/// assert <see cref="AuditEvent.ExecutionId"/> against a known value.
/// </summary>
private static readonly Guid TestExecutionId = Guid.NewGuid();
private static ScriptRuntimeContext.ExternalSystemHelper CreateHelper(
IExternalSystemClient client,
ICachedCallTelemetryForwarder? forwarder)
@@ -49,9 +55,10 @@ public class ExternalSystemCachedCallEmissionTests
client,
InstanceName,
NullLogger.Instance,
// Audit Log #23: execution-wide correlation id. Cached rows keep
// CorrelationId = TrackedOperationId, so any value works here.
Guid.NewGuid(),
// Audit Log #23: the per-execution id stamped into ExecutionId on
// every script-side row. Cached rows keep CorrelationId =
// TrackedOperationId (the per-operation lifecycle id).
TestExecutionId,
auditWriter: null,
siteId: SiteId,
sourceScript: SourceScript,
@@ -83,7 +90,10 @@ public class ExternalSystemCachedCallEmissionTests
Assert.Equal(AuditKind.CachedSubmit, packet.Audit.Kind);
Assert.Equal(AuditStatus.Submitted, packet.Audit.Status);
Assert.Equal("ERP.GetOrder", packet.Audit.Target);
// CorrelationId is the per-operation lifecycle id (TrackedOperationId);
// ExecutionId is the per-execution id from the runtime context.
Assert.Equal(trackedId.Value, packet.Audit.CorrelationId);
Assert.Equal(TestExecutionId, packet.Audit.ExecutionId);
Assert.Equal(AuditForwardState.Pending, packet.Audit.ForwardState);
// Operational mirror — same id, Submitted, RetryCount 0, not terminal.
@@ -298,6 +308,7 @@ public class ExternalSystemCachedCallEmissionTests
var submit = forwarder.Telemetry[0];
Assert.Equal(AuditKind.CachedSubmit, submit.Audit.Kind);
Assert.Equal(AuditStatus.Submitted, submit.Audit.Status);
Assert.Equal(TestExecutionId, submit.Audit.ExecutionId);
Assert.Equal(trackedId, submit.Operational.TrackedOperationId);
Assert.Null(submit.Operational.TerminalAtUtc);
@@ -305,7 +316,10 @@ public class ExternalSystemCachedCallEmissionTests
Assert.Equal(AuditChannel.ApiOutbound, attempted.Audit.Channel);
Assert.Equal(AuditKind.ApiCallCached, attempted.Audit.Kind);
Assert.Equal(AuditStatus.Attempted, attempted.Audit.Status);
// Cached rows: CorrelationId = TrackedOperationId; ExecutionId is the
// per-execution id from the runtime context.
Assert.Equal(trackedId.Value, attempted.Audit.CorrelationId);
Assert.Equal(TestExecutionId, attempted.Audit.ExecutionId);
Assert.Equal("ERP.GetOrder", attempted.Audit.Target);
Assert.Equal(trackedId, attempted.Operational.TrackedOperationId);
Assert.Equal("Attempted", attempted.Operational.Status);
@@ -316,6 +330,7 @@ public class ExternalSystemCachedCallEmissionTests
Assert.Equal(AuditKind.CachedResolve, resolve.Audit.Kind);
Assert.Equal(AuditStatus.Delivered, resolve.Audit.Status);
Assert.Equal(trackedId.Value, resolve.Audit.CorrelationId);
Assert.Equal(TestExecutionId, resolve.Audit.ExecutionId);
Assert.Equal(trackedId, resolve.Operational.TrackedOperationId);
Assert.Equal("Delivered", resolve.Operational.Status);
// Terminal row carries TerminalAtUtc.