From dc2c73b07d1664176f7bf41ff84dc03f61e2ced9 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 21 May 2026 17:26:49 -0400 Subject: [PATCH] refactor(inboundapi): fail-fast on missing inbound ExecutionId stash --- src/ScadaLink.InboundAPI/InboundScriptExecutor.cs | 3 +++ .../Middleware/AuditWriteMiddleware.cs | 11 ++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ScadaLink.InboundAPI/InboundScriptExecutor.cs b/src/ScadaLink.InboundAPI/InboundScriptExecutor.cs index 2a68abe..80aff65 100644 --- a/src/ScadaLink.InboundAPI/InboundScriptExecutor.cs +++ b/src/ScadaLink.InboundAPI/InboundScriptExecutor.cs @@ -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 diff --git a/src/ScadaLink.InboundAPI/Middleware/AuditWriteMiddleware.cs b/src/ScadaLink.InboundAPI/Middleware/AuditWriteMiddleware.cs index 71ce437..db83c85 100644 --- a/src/ScadaLink.InboundAPI/Middleware/AuditWriteMiddleware.cs +++ b/src/ScadaLink.InboundAPI/Middleware/AuditWriteMiddleware.cs @@ -249,8 +249,11 @@ public sealed class AuditWriteMiddleware /// Audit Log #23 (ParentExecutionId): reads the inbound request's per-request /// ExecutionId that minted and stashed on /// under . - /// Falls back to a fresh id only if the slot is somehow absent — the inbound - /// audit row must always carry an execution id. + /// Throws 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. 's + /// try/catch degrades the throw to a dropped best-effort audit row, never a + /// failed request. /// 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."); } ///