import { HTTP_EXECUTION_CEILINGS, invokeValidator, type InstalledHttpContract, } from "../../contracts/external-contract-runtime.ts"; import type { CacheScopeSnapshot } from "../../contracts/server-state-scope.ts"; import { defineMutationIntent, MUTATION_INTENT_BOUNDS, type MutationIntent, } from "../../contracts/mutation-intent.ts"; import { decodeJsonBytes, isEffectivelyEmpty, isJsonMediaType, probeForbiddenBody, readBoundedBytes, } from "./bounded-body-reader.ts"; import { checkFinalInvariants, projectRequest, type CredentialPatchOutcome, } from "./http-contract-bridge.ts"; import { certaintyForAbandonedAttempt, classifyProblemEffect, type PhysicalAttemptState, } from "./http-effect-certainty.ts"; import { parseRetryAfter } from "./retry-policy.ts"; /** * §7–§8. Descriptor-driven HTTP execution. * * This is not a general purpose HTTP client. A caller passes an installed * contract and typed input; the runtime owns bounds, the total deadline, the * single retry authority and the effect-certainty verdict. */ export type SafeResponseMetadata = Readonly<{ status: number; correlationReference?: string; retryAfterMs?: number; validatorToken?: string; }>; export type HttpContractViolationKind = | "MISSING_IDEMPOTENCY_KEY" | "UNEXPECTED_IDEMPOTENCY_KEY" | "UNEXPECTED_STATUS" | "UNEXPECTED_EMPTY_BODY" | "UNEXPECTED_BODY" | "CONTENT_TYPE_MISMATCH" | "RESPONSE_TOO_LARGE" | "UTF8_INVALID" | "JSON_INVALID" | "SUCCESS_SCHEMA_INVALID" | "PROBLEM_SCHEMA_INVALID" | "VALIDATOR_RUNTIME_FAILURE" | "MAPPING_CONTRACT_VIOLATION" | "FINAL_REQUEST_INVARIANT_FAILED" | "SCOPE_FENCED"; export type HttpContractViolation = Readonly<{ kind: HttpContractViolationKind; operation: "REQUEST" | "RESPONSE" | "VALIDATION" | "MAPPING"; }>; export type HttpEffectCertainty = | "NOT_APPLICABLE" | "NOT_STARTED" | "NOT_APPLIED" | "APPLIED_CONFIRMED" | "MAYBE_APPLIED"; export type HttpTransportFailure = Readonly<{ kind: | "DNS_OR_CONNECT_FAILURE" | "TLS_OR_NETWORK_FAILURE" | "NETWORK_FAILURE" | "TIMEOUT" | "RESPONSE_STREAM_FAILURE" | "ABORTED_BY_SCOPE" | "ABORTED_BY_CALLER" | "OVERLOADED_BEFORE_SEND"; retryable: boolean; }>; export type HttpExecutionOutcome = | Readonly<{ kind: "SUCCESS"; value: Value; metadata: SafeResponseMetadata; effect: "NOT_APPLICABLE" | "APPLIED_CONFIRMED"; }> | Readonly<{ kind: "PROBLEM"; problem: Problem; metadata: SafeResponseMetadata; effect: "NOT_APPLIED" | "APPLIED_CONFIRMED" | "MAYBE_APPLIED"; }> | Readonly<{ kind: "UNAUTHENTICATED"; effect: "NOT_APPLICABLE" | "NOT_APPLIED" | "MAYBE_APPLIED"; }> | Readonly<{ kind: "FORBIDDEN"; effect: "NOT_APPLICABLE" | "NOT_APPLIED" | "MAYBE_APPLIED"; }> | Readonly<{ kind: "RATE_LIMITED"; retryAfterMs?: number; effect: "NOT_APPLICABLE" | "NOT_APPLIED" | "MAYBE_APPLIED"; }> | Readonly<{ kind: "CONTRACT_VIOLATION"; violation: HttpContractViolation; effect: HttpEffectCertainty; }> | Readonly<{ kind: "TRANSPORT_FAILURE"; failure: HttpTransportFailure; effect: "NOT_STARTED" | "MAYBE_APPLIED"; }> | Readonly<{ kind: "CANCELLED"; effect: "NOT_STARTED" | "MAYBE_APPLIED"; }>; export type CancellationOwner = | "CALLER" | "ROUTE_TRANSITION" | "SCOPE_FENCE" | "APPLICATION_SHUTDOWN" | "DEADLINE"; export interface HttpExecutionContext { readonly signal?: AbortSignal; readonly scope: CacheScopeSnapshot; readonly intent?: MutationIntent; } export interface ContractHttpExecutor { execute( operation: InstalledHttpContract, input: Input, context: HttpExecutionContext, ): Promise>; } export type HttpExecutionObservation = Readonly<{ diagnosticsOperation: string; outcome: string; attempts: number; certainty: string; }>; export type ContractHttpExecutorDependencies = Readonly<{ baseUrl: string; /** §8.2. `MAX_RETRY_ATTEMPTS` from Runtime Config; the ceiling is still 2. */ maxRetryAttempts: number; attachCredentials( operation: Readonly<{ operationId: string; authProfileId: string; method: string; }>, ): Promise | CredentialPatchOutcome; fetcher?: typeof fetch; /** Adapter seam for the common bounded response reader. */ readBoundedResponseBytes?: typeof readBoundedBytes; monotonicNow?: () => number; sleep?: (ms: number, signal: AbortSignal) => Promise; random?: () => number; observe?: (observation: HttpExecutionObservation) => void; }>; const RETRYABLE_STATUSES: ReadonlySet = new Set([ 408, 425, 429, 502, 503, 504, ]); const RETRY_BASE_DELAY_MS = 250; const RETRY_MAX_LOCAL_DELAY_MS = 2_000; const RETRY_AFTER_CEILING_MS = 5_000; type MutationIntentValidation = | Readonly<{ ok: true; intent?: MutationIntent }> | Readonly<{ ok: false; violation: "MISSING_IDEMPOTENCY_KEY" | "UNEXPECTED_IDEMPOTENCY_KEY"; }>; function validateMutationIntent( contract: Readonly<{ operationId: string; retrySemantics: "SAFE" | "IDEMPOTENT" | "KEYED" | "NEVER"; commandEffect: unknown | null; }>, intent: MutationIntent | undefined, ): MutationIntentValidation { const isCommand = contract.commandEffect !== null; const requiresKey = contract.retrySemantics === "KEYED"; if (!isCommand) { return intent === undefined ? Object.freeze({ ok: true }) : Object.freeze({ ok: false, violation: "UNEXPECTED_IDEMPOTENCY_KEY", }); } if (intent === undefined) { return requiresKey ? Object.freeze({ ok: false, violation: "MISSING_IDEMPOTENCY_KEY" }) : Object.freeze({ ok: true }); } let validated: MutationIntent; try { validated = defineMutationIntent(intent); } catch { return Object.freeze({ ok: false, violation: requiresKey ? "MISSING_IDEMPOTENCY_KEY" : "UNEXPECTED_IDEMPOTENCY_KEY", }); } if (validated.operationId !== contract.operationId) { return Object.freeze({ ok: false, violation: requiresKey ? "MISSING_IDEMPOTENCY_KEY" : "UNEXPECTED_IDEMPOTENCY_KEY", }); } const key = validated.idempotencyKey; if (requiresKey && !validIdempotencyKey(key)) { return Object.freeze({ ok: false, violation: "MISSING_IDEMPOTENCY_KEY", }); } if (!requiresKey && key !== undefined) { return Object.freeze({ ok: false, violation: "UNEXPECTED_IDEMPOTENCY_KEY", }); } return Object.freeze({ ok: true, intent: validated }); } const UTF8 = new TextEncoder(); function validIdempotencyKey(value: unknown): value is string { return ( typeof value === "string" && value.trim().length > 0 && UTF8.encode(value).byteLength <= MUTATION_INTENT_BOUNDS.idempotencyKeyMaxBytes && !hasControlCharacter(value) ); } function hasControlCharacter(value: string): boolean { for (const character of value) { const codePoint = character.codePointAt(0) ?? 0; if ( codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f) ) { return true; } } return false; } export function createContractHttpExecutor( dependencies: ContractHttpExecutorDependencies, ): ContractHttpExecutor { const fetcher = dependencies.fetcher ?? fetch; const readResponseBytes = dependencies.readBoundedResponseBytes ?? readBoundedBytes; const now = dependencies.monotonicNow ?? (() => performance.now()); const random = dependencies.random ?? Math.random; const sleep = dependencies.sleep ?? ((ms: number, signal: AbortSignal) => new Promise((resolve) => { const timer = setTimeout(resolve, ms); signal.addEventListener( "abort", () => { clearTimeout(timer); resolve(); }, { once: true }, ); })); async function execute( operation: InstalledHttpContract, input: Input, context: HttpExecutionContext, ): Promise> { const contract = operation.contract; const policy = operation.frontend; const isCommand = contract.commandEffect !== null; // §8.5. One monotonic deadline covers credential resolution, encoding, // backoff, every physical attempt, body read and validation. const deadlineAt = now() + policy.totalDeadlineMs; const remaining = () => deadlineAt - now(); let attemptState: PhysicalAttemptState = "PREPARING"; let attempts = 0; let terminalCancellation: CancellationOwner | null = null; const lifetimeController = new AbortController(); const forwardCallerToLifetime = () => { terminalCancellation ??= "CALLER"; lifetimeController.abort(); }; const forwardScopeToLifetime = () => { terminalCancellation ??= "SCOPE_FENCE"; lifetimeController.abort(); }; const callerSignal = context.signal === context.scope.signal ? undefined : context.signal; if (callerSignal?.aborted) forwardCallerToLifetime(); else { callerSignal?.addEventListener("abort", forwardCallerToLifetime, { once: true, }); } if (context.scope.signal.aborted) forwardScopeToLifetime(); else { context.scope.signal.addEventListener("abort", forwardScopeToLifetime, { once: true, }); } const lifetimeDeadlineTimer = setTimeout(() => { terminalCancellation ??= "DEADLINE"; lifetimeController.abort(); }, policy.totalDeadlineMs); let lifetimeDisposed = false; const disposeLifetime = () => { if (lifetimeDisposed) return; lifetimeDisposed = true; clearTimeout(lifetimeDeadlineTimer); callerSignal?.removeEventListener("abort", forwardCallerToLifetime); context.scope.signal.removeEventListener("abort", forwardScopeToLifetime); lifetimeController.abort(); }; const finish = ( outcome: HttpExecutionOutcome, certainty: string, ): HttpExecutionOutcome => { disposeLifetime(); try { dependencies.observe?.({ diagnosticsOperation: policy.diagnosticsOperation, outcome: outcome.kind, attempts, certainty, }); } catch { // Observation is outside the execution authority. } return outcome; }; try { // §7.4 step 1-2: capture the scope and verify it is still current. if (!context.scope.isCurrent()) { return finish(scopeFenced(preDispatchEffect(isCommand)), "NOT_STARTED"); } const intentValidation = validateMutationIntent(contract, context.intent); if (!intentValidation.ok) { return finish( violation(intentValidation.violation, "REQUEST", "NOT_STARTED"), "NOT_STARTED", ); } const validated = invokeValidator(contract.inputValidator, input); if (validated.outcome === "THROWN") { return finish( violation( "VALIDATOR_RUNTIME_FAILURE", "VALIDATION", preDispatchEffect(isCommand), ), "NOT_STARTED", ); } if (validated.outcome === "INVALID") { return finish( violation( "FINAL_REQUEST_INVARIANT_FAILED", "REQUEST", preDispatchEffect(isCommand), ), "NOT_STARTED", ); } const projected = projectRequest( operation, validated.value, dependencies.baseUrl, ); if (!projected.ok) { return finish( violation( "FINAL_REQUEST_INVARIANT_FAILED", "REQUEST", preDispatchEffect(isCommand), ), "NOT_STARTED", ); } // §7.7 / §8.4. Credentials are resolved before send. A response 401 is // terminal; there is no hidden refresh-and-replay. let patchOperation: Promise; try { patchOperation = Promise.resolve( dependencies.attachCredentials({ operationId: contract.operationId, authProfileId: policy.authProfileId, method: contract.method, }), ); } catch { return finish(unauthenticated("NOT_STARTED", isCommand), "NOT_STARTED"); } const patchResult = await awaitWithAbort( patchOperation, lifetimeController.signal, ); if (patchResult === ABORTED) { if (terminalCancellation === "SCOPE_FENCE") { return finish( transportFailure( "ABORTED_BY_SCOPE", false, attemptState, isCommand, ), "SCOPE_FENCED", ); } return terminalCancellation === "CALLER" ? finish(cancelled("NOT_STARTED"), "CANCELLED") : finish( transportFailure( "TIMEOUT", false, attemptState, isCommand, ), "TIMEOUT", ); } const patch = patchResult; if (patch.kind === "SCOPE_FENCED") { return finish(scopeFenced(preDispatchEffect(isCommand)), "NOT_STARTED"); } if (patch.kind !== "READY") { // A missing credential never downgrades into an anonymous request. return finish(unauthenticated("NOT_STARTED", isCommand), "NOT_STARTED"); } if ( Object.keys(patch.headers).some( (name) => name.toLowerCase() === "idempotency-key", ) ) { return finish( violation("UNEXPECTED_IDEMPOTENCY_KEY", "REQUEST", "NOT_STARTED"), "NOT_STARTED", ); } const headers: Record = { Accept: "application/json", ...patch.headers, }; if (contract.requestBody === "JSON") { headers["Content-Type"] = "application/json"; } if (intentValidation.intent?.idempotencyKey !== undefined) { headers["Idempotency-Key"] = intentValidation.intent.idempotencyKey; } const retryCeiling = Math.min( policy.retryBudget, dependencies.maxRetryAttempts, HTTP_EXECUTION_CEILINGS.hardRetryCount, ); for (let retryIndex = 0; ; retryIndex += 1) { if (callerSignal?.aborted) { terminalCancellation ??= "CALLER"; return finish( cancelled(certaintyForAbandonedAttempt(attemptState, isCommand)), "CANCELLED", ); } if (!context.scope.isCurrent()) { terminalCancellation ??= "SCOPE_FENCE"; return finish( scopeFenced(contractViolationEffect(attemptState, isCommand)), "SCOPE_FENCED", ); } const controller = new AbortController(); const budget = remaining(); if (budget <= 0) { return finish( transportFailure("TIMEOUT", false, attemptState, isCommand), "TIMEOUT", ); } const deadlineTimer = setTimeout(() => { terminalCancellation ??= "DEADLINE"; controller.abort(); }, budget); const forwardLifetime = () => { controller.abort(); }; if (lifetimeController.signal.aborted) forwardLifetime(); else { lifetimeController.signal.addEventListener("abort", forwardLifetime, { once: true, }); } const init: RequestInit = { method: contract.method, headers, redirect: "error", referrerPolicy: "no-referrer", credentials: patch.credentials, cache: "no-store", signal: controller.signal, ...(projected.request.bodyBytes ? { body: projected.request.bodyBytes.slice() } : {}), }; const invariantFailure = checkFinalInvariants({ request: projected.request, expectedMethod: contract.method, baseUrl: dependencies.baseUrl, init, headers, requestByteLimit: policy.requestByteLimit, deadlineRemainingMs: remaining(), scopeIsCurrent: context.scope.isCurrent(), }); if (invariantFailure) { clearTimeout(deadlineTimer); lifetimeController.signal.removeEventListener("abort", forwardLifetime); return finish( invariantFailure === "SCOPE_FENCED" ? scopeFenced(preDispatchEffect(isCommand)) : violation( "FINAL_REQUEST_INVARIANT_FAILED", "REQUEST", preDispatchEffect(isCommand), ), "NOT_STARTED", ); } let response: Response; attemptState = "READY_TO_SEND"; try { attempts += 1; const pending = fetcher(projected.request.url, init); attemptState = "DISPATCHED"; response = await pending; attemptState = "RESPONSE_HEADERS"; } catch { clearTimeout(deadlineTimer); lifetimeController.signal.removeEventListener("abort", forwardLifetime); const owner = terminalCancellation; if (owner === "CALLER") { return finish( cancelled(certaintyForAbandonedAttempt(attemptState, isCommand)), "CANCELLED", ); } if (owner === "SCOPE_FENCE") { return finish( transportFailure( "ABORTED_BY_SCOPE", false, attemptState, isCommand, ), "SCOPE_FENCED", ); } const kind = owner === "DEADLINE" ? "TIMEOUT" : "NETWORK_FAILURE"; if ( owner === null && canRetryTransport(contract.retrySemantics, attemptState) && retryIndex < retryCeiling && remaining() > 0 ) { const delay = jitteredDelay(retryIndex, random); if (delay < remaining()) { const slept = await awaitWithAbort( sleep(delay, lifetimeController.signal), lifetimeController.signal, ); if (slept === ABORTED) { return terminalCancellation === "CALLER" ? finish( cancelled( certaintyForAbandonedAttempt(attemptState, isCommand), ), "CANCELLED", ) : finish( transportFailure( "TIMEOUT", false, attemptState, isCommand, ), "TIMEOUT", ); } continue; } } return finish( transportFailure(kind, false, attemptState, isCommand), kind, ); } try { const outcome = await admitResponse( operation, response, context, attemptState, readResponseBytes, ); attemptState = "SETTLED"; if ( outcome.retryHint && retryIndex < retryCeiling && isRetryableSemantics(contract.retrySemantics) ) { const delay = retryDelayFor(outcome.retryAfterMs, retryIndex, random); if (delay !== null && delay < remaining()) { clearTimeout(deadlineTimer); lifetimeController.signal.removeEventListener( "abort", forwardLifetime, ); const slept = await awaitWithAbort( sleep(delay, lifetimeController.signal), lifetimeController.signal, ); if (slept === ABORTED) { return terminalCancellation === "CALLER" ? finish( cancelled( certaintyForAbandonedAttempt(attemptState, isCommand), ), "CANCELLED", ) : finish( transportFailure( "TIMEOUT", false, attemptState, isCommand, ), "TIMEOUT", ); } continue; } } return finish(outcome.result, outcome.certainty); } finally { clearTimeout(deadlineTimer); lifetimeController.signal.removeEventListener("abort", forwardLifetime); } } } catch { return finish( transportFailure("NETWORK_FAILURE", false, attemptState, isCommand), "RUNTIME_FAILURE", ); } finally { disposeLifetime(); } } return Object.freeze({ execute }); } type AdmissionOutcome = Readonly<{ result: HttpExecutionOutcome; certainty: string; retryHint: boolean; retryAfterMs: number | null; }>; /** * §7.9. Admission order is fixed: redirect, status allowlist, media type, * declared length, bounded stream, body policy, decode, validate, scope fence. * `response.ok` is never used on its own. */ async function admitResponse( operation: InstalledHttpContract, response: Response, context: HttpExecutionContext, attemptState: PhysicalAttemptState, readResponseBytes: typeof readBoundedBytes, ): Promise> { const contract = operation.contract; const policy = operation.frontend; const isCommand = contract.commandEffect !== null; const status = response.status; const retryAfterMs = parseRetryAfter(response.headers.get("retry-after")); if (response.redirected || response.type === "opaqueredirect") { await response.body?.cancel().catch(() => {}); return settled( violation( "UNEXPECTED_STATUS", "RESPONSE", postDispatchEffect(isCommand), ), "CONTRACT_VIOLATION", ); } const metadata = safeMetadata(response, retryAfterMs); if (!contract.acceptedStatuses.includes(status)) { if (status === 401) { await response.body?.cancel().catch(() => {}); return settled( unauthenticated( certaintyForAbandonedAttempt(attemptState, isCommand), isCommand, ), "UNAUTHENTICATED", ); } if (status === 403) { await response.body?.cancel().catch(() => {}); return settled( forbidden(certaintyForAbandonedAttempt(attemptState, isCommand), isCommand), "FORBIDDEN", ); } if (status === 429) { await response.body?.cancel().catch(() => {}); return Object.freeze({ result: Object.freeze({ kind: "RATE_LIMITED" as const, ...(retryAfterMs === null ? {} : { retryAfterMs }), effect: normalizeOptionalEffect( certaintyForAbandonedAttempt(attemptState, isCommand), isCommand, ), }), certainty: "RATE_LIMITED", retryHint: true, retryAfterMs, }); } return admitProblem( operation, response, status, metadata, attemptState, readResponseBytes, ); } // Success status: body policy first. if (contract.responseBody === "NONE") { const probe = await probeForbiddenBody(response); if (!probe.ok) { return settled( transportFailure( "RESPONSE_STREAM_FAILURE", false, attemptState, isCommand, ), probe.code, ); } if (probe.present) { return settled( violation("UNEXPECTED_BODY", "RESPONSE", postDispatchEffect(isCommand)), "CONTRACT_VIOLATION", ); } if (!context.scope.isCurrent()) { return settled( scopeFenced(postDispatchEffect(isCommand)), "SCOPE_FENCED", ); } return settled( Object.freeze({ kind: "SUCCESS" as const, value: undefined as WireOutput, metadata, effect: (isCommand ? "APPLIED_CONFIRMED" : "NOT_APPLICABLE") as "NOT_APPLICABLE" | "APPLIED_CONFIRMED", }), isCommand ? "APPLIED_CONFIRMED" : "NOT_APPLICABLE", ); } const emptyAllowed = contract.emptyBodyStatuses.includes(status); const mediaOk = isJsonMediaType(response.headers.get("content-type")); const bytes = await readResponseBytes(response, policy.responseByteLimit); if (!bytes.ok) { return settled( bytes.code === "RESPONSE_TOO_LARGE" ? violation( "RESPONSE_TOO_LARGE", "RESPONSE", postDispatchEffect(isCommand), ) : transportFailure( "RESPONSE_STREAM_FAILURE", false, attemptState, isCommand, ), bytes.code, ); } const empty = isEffectivelyEmpty(bytes.bytes); if (empty) { if (contract.responseBody === "REQUIRED_JSON" || !emptyAllowed) { return settled( violation( "UNEXPECTED_EMPTY_BODY", "RESPONSE", postDispatchEffect(isCommand), ), "CONTRACT_VIOLATION", ); } if (!context.scope.isCurrent()) { return settled( scopeFenced(postDispatchEffect(isCommand)), "SCOPE_FENCED", ); } return settled( Object.freeze({ kind: "SUCCESS" as const, value: undefined as WireOutput, metadata, effect: (isCommand ? "APPLIED_CONFIRMED" : "NOT_APPLICABLE") as "NOT_APPLICABLE" | "APPLIED_CONFIRMED", }), isCommand ? "APPLIED_CONFIRMED" : "NOT_APPLICABLE", ); } if (!mediaOk) { return settled( violation( "CONTENT_TYPE_MISMATCH", "RESPONSE", postDispatchEffect(isCommand), ), "CONTRACT_VIOLATION", ); } const decoded = decodeJsonBytes(bytes.bytes); if (!decoded.ok) { return settled( violation(decoded.code, "RESPONSE", postDispatchEffect(isCommand)), "CONTRACT_VIOLATION", ); } const validated = invokeValidator(contract.outputValidator, decoded.value); if (validated.outcome === "THROWN") { return settled( violation( "VALIDATOR_RUNTIME_FAILURE", "VALIDATION", postDispatchEffect(isCommand), ), "CONTRACT_VIOLATION", ); } if (validated.outcome === "INVALID") { return settled( violation( "SUCCESS_SCHEMA_INVALID", "VALIDATION", postDispatchEffect(isCommand), ), "CONTRACT_VIOLATION", ); } // §10.8. A successful response for a stale scope is discarded, not committed. if (!context.scope.isCurrent()) { return settled( scopeFenced(postDispatchEffect(isCommand)), "SCOPE_FENCED", ); } return settled( Object.freeze({ kind: "SUCCESS" as const, value: validated.value, metadata, effect: (isCommand ? "APPLIED_CONFIRMED" : "NOT_APPLICABLE") as "NOT_APPLICABLE" | "APPLIED_CONFIRMED", }), isCommand ? "APPLIED_CONFIRMED" : "NOT_APPLICABLE", ); } const ABORTED = Symbol("http-operation-aborted"); async function awaitWithAbort( operation: Promise, signal: AbortSignal, ): Promise { if (signal.aborted) return ABORTED; let onAbort: (() => void) | undefined; const aborted = new Promise((resolve) => { onAbort = () => resolve(ABORTED); signal.addEventListener("abort", onAbort, { once: true }); }); try { return await Promise.race([operation, aborted]); } finally { if (onAbort) signal.removeEventListener("abort", onAbort); } } async function admitProblem( operation: InstalledHttpContract, response: Response, status: number, metadata: SafeResponseMetadata, attemptState: PhysicalAttemptState, readResponseBytes: typeof readBoundedBytes, ): Promise> { const contract = operation.contract; const isCommand = contract.commandEffect !== null; const retryable = RETRYABLE_STATUSES.has(status); const bytes = await readResponseBytes( response, HTTP_EXECUTION_CEILINGS.problemResponseBytes, ); if (!bytes.ok || isEffectivelyEmpty(bytes.bytes)) { // An unclassifiable failure stays uncertain for a command. return Object.freeze({ result: violation( "PROBLEM_SCHEMA_INVALID", "VALIDATION", postDispatchEffect(isCommand), ), certainty: isCommand ? "MAYBE_APPLIED" : "NOT_STARTED", retryHint: retryable, retryAfterMs: metadata.retryAfterMs ?? null, }); } if (!isJsonMediaType(response.headers.get("content-type"))) { return Object.freeze({ result: violation( "CONTENT_TYPE_MISMATCH", "RESPONSE", postDispatchEffect(isCommand), ), certainty: isCommand ? "MAYBE_APPLIED" : "NOT_STARTED", retryHint: retryable, retryAfterMs: metadata.retryAfterMs ?? null, }); } const decoded = decodeJsonBytes(bytes.bytes); if (!decoded.ok) { return Object.freeze({ result: violation( decoded.code, "RESPONSE", postDispatchEffect(isCommand), ), certainty: isCommand ? "MAYBE_APPLIED" : "NOT_STARTED", retryHint: retryable, retryAfterMs: metadata.retryAfterMs ?? null, }); } const validated = invokeValidator(contract.problemValidator, decoded.value); if (validated.outcome !== "VALID") { return Object.freeze({ result: violation( validated.outcome === "THROWN" ? "VALIDATOR_RUNTIME_FAILURE" : "PROBLEM_SCHEMA_INVALID", "VALIDATION", postDispatchEffect(isCommand), ), certainty: isCommand ? "MAYBE_APPLIED" : "NOT_STARTED", retryHint: retryable, retryAfterMs: metadata.retryAfterMs ?? null, }); } const classification = classifyProblemEffect({ status, problem: validated.value, descriptor: contract.commandEffect, }); const effect = isCommand ? classification.effect : certaintyForAbandonedAttempt(attemptState, false); return Object.freeze({ result: Object.freeze({ kind: "PROBLEM" as const, problem: validated.value, metadata, effect: (effect === "NOT_STARTED" ? "NOT_APPLIED" : effect) as "NOT_APPLIED" | "APPLIED_CONFIRMED" | "MAYBE_APPLIED", }), certainty: effect, retryHint: retryable && effect !== "MAYBE_APPLIED", retryAfterMs: metadata.retryAfterMs ?? null, }); } /** * §8.3. `SAFE` and `IDEMPOTENT` may replay the same frozen request. `KEYED` * must not automatically retry once an attempt was dispatched and its response * was lost; that path goes to inspect/reconciliation instead. `NEVER` is zero. */ function canRetryTransport( semantics: InstalledHttpContract< unknown, unknown, unknown >["contract"]["retrySemantics"], attemptState: PhysicalAttemptState, ): boolean { if (semantics === "NEVER") return false; if (semantics === "KEYED") { return attemptState === "PREPARING" || attemptState === "READY_TO_SEND"; } return true; } function isRetryableSemantics( semantics: InstalledHttpContract< unknown, unknown, unknown >["contract"]["retrySemantics"], ): boolean { return semantics === "SAFE" || semantics === "IDEMPOTENT"; } /** §8.2. Full jitter over `min(2000, 250 * 2^index)`. */ function jitteredDelay(retryIndex: number, random: () => number): number { const ceiling = Math.min( RETRY_MAX_LOCAL_DELAY_MS, RETRY_BASE_DELAY_MS * 2 ** retryIndex, ); return Math.floor(random() * ceiling); } function retryDelayFor( retryAfterMs: number | null, retryIndex: number, random: () => number, ): number | null { const local = jitteredDelay(retryIndex, random); if (retryAfterMs === null) return local; if (retryAfterMs > RETRY_AFTER_CEILING_MS) return null; return Math.max(local, retryAfterMs); } /** §7.12. No raw header map, URL, cookie, traceparent or ETag value escapes. */ function safeMetadata( response: Response, retryAfterMs: number | null, ): SafeResponseMetadata { const correlation = response.headers.get("x-correlation-id"); return Object.freeze({ status: response.status, ...(correlation && /^[A-Za-z0-9._:-]{1,128}$/.test(correlation) ? { correlationReference: correlation } : {}), ...(retryAfterMs === null ? {} : { retryAfterMs }), }); } function settled( result: HttpExecutionOutcome, certainty: string, ): AdmissionOutcome { return Object.freeze({ result, certainty, retryHint: false, retryAfterMs: null, }); } function violation( kind: HttpContractViolationKind, operation: HttpContractViolation["operation"], effect: HttpEffectCertainty, ): HttpExecutionOutcome { return Object.freeze({ kind: "CONTRACT_VIOLATION" as const, violation: Object.freeze({ kind, operation }), effect, }); } function scopeFenced( effect: HttpEffectCertainty, ): HttpExecutionOutcome { return violation("SCOPE_FENCED", "RESPONSE", effect); } function preDispatchEffect(isCommand: boolean): HttpEffectCertainty { return isCommand ? "NOT_STARTED" : "NOT_APPLICABLE"; } function postDispatchEffect(isCommand: boolean): HttpEffectCertainty { return isCommand ? "MAYBE_APPLIED" : "NOT_APPLICABLE"; } function contractViolationEffect( attemptState: PhysicalAttemptState, isCommand: boolean, ): HttpEffectCertainty { if (!isCommand) return "NOT_APPLICABLE"; return attemptState === "PREPARING" || attemptState === "READY_TO_SEND" ? "NOT_STARTED" : "MAYBE_APPLIED"; } function unauthenticated( effect: string, isCommand: boolean, ): HttpExecutionOutcome { return Object.freeze({ kind: "UNAUTHENTICATED" as const, effect: normalizeOptionalEffect(effect, isCommand), }); } function forbidden( effect: string, isCommand: boolean, ): HttpExecutionOutcome { return Object.freeze({ kind: "FORBIDDEN" as const, effect: normalizeOptionalEffect(effect, isCommand), }); } function cancelled( effect: "NOT_STARTED" | "NOT_APPLIED" | "MAYBE_APPLIED" | "APPLIED_CONFIRMED", ): HttpExecutionOutcome { return Object.freeze({ kind: "CANCELLED" as const, effect: effect === "MAYBE_APPLIED" ? "MAYBE_APPLIED" : "NOT_STARTED", }); } function transportFailure( kind: HttpTransportFailure["kind"], retryable: boolean, attemptState: PhysicalAttemptState, isCommand: boolean, ): HttpExecutionOutcome { const effect = certaintyForAbandonedAttempt(attemptState, isCommand); return Object.freeze({ kind: "TRANSPORT_FAILURE" as const, failure: Object.freeze({ kind, retryable }), effect: effect === "MAYBE_APPLIED" ? "MAYBE_APPLIED" : "NOT_STARTED", }); } function normalizeOptionalEffect( effect: string, isCommand: boolean, ): "NOT_APPLICABLE" | "NOT_APPLIED" | "MAYBE_APPLIED" { if (!isCommand) return "NOT_APPLICABLE"; return effect === "MAYBE_APPLIED" ? "MAYBE_APPLIED" : "NOT_APPLIED"; }