refactor(inboundapi): fail-fast on missing inbound ExecutionId stash

This commit is contained in:
Joseph Doherty
2026-05-21 17:26:49 -04:00
parent d8453bfba2
commit dc2c73b07d
2 changed files with 11 additions and 3 deletions

View File

@@ -172,6 +172,9 @@ public class InboundScriptExecutor
RouteHelper route,
TimeSpan timeout,
CancellationToken cancellationToken = default,
// Deliberate ordering: this optional parameter trails the CancellationToken
// because it was appended additively for non-breaking contract evolution.
// Every call site passes it by named argument (parentExecutionId:).
Guid? parentExecutionId = null)
{
// InboundAPI-004: keep the timeout source and the request-abort source

View File

@@ -249,8 +249,11 @@ public sealed class AuditWriteMiddleware
/// Audit Log #23 (ParentExecutionId): reads the inbound request's per-request
/// <c>ExecutionId</c> that <see cref="InvokeAsync"/> minted and stashed on
/// <see cref="HttpContext.Items"/> under <see cref="InboundExecutionIdItemKey"/>.
/// Falls back to a fresh id only if the slot is somehow absent — the inbound
/// audit row must always carry an execution id.
/// Throws <see cref="InvalidOperationException"/> if the slot is absent — for a
/// correlation feature a silently-divergent id is the worst failure mode, so we
/// fail fast rather than mint a fresh one. <see cref="EmitInboundAudit"/>'s
/// try/catch degrades the throw to a dropped best-effort audit row, never a
/// failed request.
/// </summary>
private static Guid ResolveInboundExecutionId(HttpContext ctx)
{
@@ -260,7 +263,9 @@ public sealed class AuditWriteMiddleware
return id;
}
return Guid.NewGuid();
throw new InvalidOperationException(
"Inbound ExecutionId invariant violated: the inbound ExecutionId must be "
+ "stashed by AuditWriteMiddleware.InvokeAsync before the audit row is emitted.");
}
/// <summary>