@@ -322,21 +322,12 @@ export async function preprocessExecution(
322322 }
323323 }
324324
325- // ========== STEPS 3.5–6: Parallel Read-Only Preflight Gates ==========
326- // All remaining gates before the STEP 7 write are read-only with no side
327- // effects, so they run concurrently to cut sequential latency. The ban check
328- // (STEP 3.5) and the subscription fetch (STEP 4) are mutually independent and
329- // start together. Once the subscription resolves, the usage gates (STEP 5a/5b)
330- // and the rate-limit gate (STEP 6) — all of which depend only on the
331- // subscription, actor, and workspace — start together.
332- //
333- // Each gate resolves to either `null` (passed/skipped) or a deferred outcome:
334- // the `PreprocessExecutionResult` to return plus the optional error-log write
335- // to perform. Because every gate completes regardless of which fails first,
336- // outcomes are evaluated IN A FIXED PRECEDENCE ORDER — ban (403) → usage (402)
337- // → rate limit (429) — to reproduce the sequential version's behavior exactly.
338- // Wasted work on a request that ends up rejected is acceptable here: the gates
339- // are read-only and the sole write (STEP 7) stays after every gate passes.
325+ // ========== STEPS 3.5–6: Preflight Gates ==========
326+ // The read-only gates run concurrently to cut latency: ban + subscription
327+ // together, then usage (which needs the subscription). The rate-limit gate is
328+ // stateful — it debits a token — so it runs sequentially only after ban and
329+ // usage pass. Failures apply in fixed precedence (ban 403 → usage 402 → rate
330+ // 429), and the sole write (the STEP 7 reservation) stays last.
340331
341332 /**
342333 * A failing gate's deferred outcome: the response to return, plus an optional
@@ -654,9 +645,7 @@ export async function preprocessExecution(
654645 const usageResult = await usageCheckTask
655646 const usageSnapshot = usageResult . snapshot
656647
657- // The read-only gates (ban, subscription, usage) ran concurrently; evaluate
658- // them in fixed precedence order — ban (403) → usage (402) — so the response
659- // matches the sequential version regardless of which settled first.
648+ // Precedence: ban (403) wins over usage (402).
660649 const readGateFailure = banFailure ?? usageResult . failure
661650 if ( readGateFailure ) {
662651 if ( readGateFailure . recordError ) {
@@ -665,9 +654,6 @@ export async function preprocessExecution(
665654 return readGateFailure . response
666655 }
667656
668- // Rate limiting (429) runs only after ban and usage pass, because it debits a
669- // token — matching the original sequential order so rejected requests never
670- // consume quota.
671657 const rateLimitFailure = await runRateLimitGate ( )
672658 if ( rateLimitFailure ) {
673659 if ( rateLimitFailure . recordError ) {
0 commit comments