fix(site-runtime): trace sink is guarded — a throwing observer can neither fail a call nor skip the audit write
Review of Task 3: the sink invoke sat before WriteAsync/ForwardAsync inside the best-effort try, so a throwing sink would have silently dropped the durable row. GuardTraceSink wraps the delegate in every helper ctor (and Collect guards EmitTrace); pinned by a throwing-sink test. ScriptRunLauncher no longer allocates a collector for a traced run with no reply target (Nobody) — the list would never be read. FlowTraceCollector.Complete pinned at unit level; Snapshot documented as a non-closing peek. Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
This commit is contained in:
+16
@@ -507,4 +507,20 @@ public class ScriptRuntimeContextTraceEmissionTests : TestKit
|
||||
writer.Events.Select(e => Row(e).Kind));
|
||||
Assert.Equal(AuditKind.CachedSubmit, Row(Assert.Single(forwarder.Telemetry).Audit).Kind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ThrowingTraceSink_NeverFailsTheCall_AndTheWriterStillGetsTheRow()
|
||||
{
|
||||
var writer = new CapturingAuditWriter();
|
||||
var helper = new ScriptRuntimeContext.ExternalSystemHelper(
|
||||
SyncClient(new ExternalCallResult(true, "{}", null)).Object, InstanceName, NullLogger.Instance, Guid.NewGuid(),
|
||||
auditWriter: writer, siteId: "site-a", sourceScript: "S",
|
||||
traceSink: _ => throw new InvalidOperationException("observer broke"));
|
||||
|
||||
var result = await helper.Call("ERP", "GetOrder");
|
||||
|
||||
Assert.True(result.Success);
|
||||
var written = Assert.Single(writer.Events);
|
||||
Assert.Equal(AuditKind.ApiCall, Row(written).Kind);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user