Files
clean-architecture-frontend…/docs/reviews/adapters/01-network-and-state.md
T
DongHyeonkaandClaude Opus 5 4e87bacdf3 fix: enforce installed HTTP auth profiles
Install the REST auth profile registry once at composition and make it the
single transport authority for V3. Contract composition now rejects an
unregistered authProfileId, so the executor never resolves a profile at
runtime.

The credential collaborator contributes proof headers only: Fetch credentials
come from the resolved profile, transport-owned and forbidden headers are
rejected, headers outside the profile's allowed set are rejected, and a missing
required header fails closed as AUTH_INTEGRATION_FAILURE with zero fetch calls.
The final invariant re-proves credentials mode and the exact header sets.

Demo mode satisfies the strict bearer profile with a fixed non-secret marker
instead of weakening REFERENCE_EXTERNAL_BEARER. Credential owners now receive
the operation lifetime through AuthOperationContext.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 22:56:44 +09:00

60 KiB
Raw Blame History

Network and state adapters implementation review

  • Review date: 2026-08-13 (Asia/Seoul)
  • Reviewed revision: 4dc033cf33
  • Mode: code review only; no implementation source was changed
  • Primary scope: src/adapters/http, auth, query-cache, cross-context-invalidation, platform, diagnostics, telemetry
  • Traced boundaries: corresponding contracts, application ports, bootstrap composition, reference feature adapters, tests, architecture decisions, and operating documentation

1. Outcome and priority

No Critical issue was found. Five High findings are implementation blockers or near-term correctness/security work:

  1. N-01: the production V3 HTTP observation is always rejected by the diagnostics projector, and the V3 path never emits terminal-failure telemetry.
  2. N-02: V3 declares authProfileId but neither composes nor enforces a profile; a credential collaborator can change transport-owned Accept and credentials, while a declared bearer profile can send no Authorization header.
  3. N-03: after a command attempt has been dispatched, a retry-time final-invariant fence can downgrade MAYBE_APPLIED to NOT_STARTED.
  4. N-04: telemetry dispose only removes pagehide; queued callbacks, future emit calls, and in-flight delivery survive runtime teardown.
  5. N-05: the conditional-validator key codec is delimiter-ambiguous and lets two valid bindings overwrite each other. It is not composed into HTTP yet, so this is a rollout blocker rather than a current request-path incident.

The current reference feature uses V3. The older createHttpClient path remains exported and is still the documented rollback/compatibility seam, so its replay and cancellation defects cannot be dismissed as dead code.

2. Method, severity, and confidence

Severity:

Level Meaning
Critical immediate broad confidentiality/integrity loss, arbitrary execution, or unrecoverable state corruption
High security boundary bypass, wrong command-effect verdict, silent loss of required production evidence, or unsafe replay/rollout blocker
Medium bounded correctness, cancellation, cleanup, or cross-context isolation defect with a narrower activation condition
Low hardening or contract/documentation mismatch without a demonstrated material product failure

Confidence:

Level Meaning
Very high direct control/data-flow proof and a minimal failing reproduction
High direct code proof and aligned contract/documentation evidence
Medium implementation evidence exists but product requirement or browser/provider behavior must be selected
Low hypothesis requiring characterization before acceptance

Validation performed without retaining test changes:

  • A temporary five-case Vitest characterization was added, run, and removed. All five expected-correct assertions failed: V3 diagnostic projection, telemetry-after-dispose, conditional-validator collision, credential transport ownership, and retry-time effect preservation.
  • Related baseline: 21 test files, 144 tests passed.
  • Static producer check: corepack pnpm check:diagnostics passed with “8 diagnostics and 5 telemetry producers”.
  • The temporary test was deleted and the implementation worktree was clean before this report was written. Other agents later created unrelated docs/reviews entries; this review does not modify them.

This distinction matters: the green suite proves current intended behaviors, while the five failures identify missing assertions rather than contradicting existing passing tests.

3. Complete primary-scope inventory

All 24 files below were read in full.

File Responsibility Direct dependencies / consumers Review disposition
src/adapters/auth/external-session-adapter.ts Adapts the external session owner to AuthSessionPort; validates credential header names and values; supplies demo, anonymous, and unavailable variants application/ports/auth-session-port.ts; bootstrap/runtime-adapters.ts; HTTP V2/V3 Preserve token opacity and allowlist. Modify for cooperative cancellation and required-profile header enforcement.
src/adapters/cross-context-invalidation/browser-cross-context-host.ts Safely captures browser BroadcastChannel, localStorage, storage events, and secure random capabilities contracts/cache-invalidation.ts; browser-cross-context-invalidation.ts; runtime-adapters.ts Preserve fail-closed capability capture. Modify to capture one localStorage identity and validate native StorageEvent.storageArea.
src/adapters/cross-context-invalidation/browser-cross-context-invalidation.ts Versioned invalidate-only wire protocol, BroadcastChannel/storage fallback, TTL, dedupe, per-source sequence/gap detection, bounded tracking, subscription and close contracts/cache-invalidation.ts; host adapter; TanStack coordinator Preserve closed envelope, bounded maps, and idempotent close. Modify exact storage-area admission; dual-transport fan-out is a separate product choice.
src/adapters/cross-context-invalidation/index.ts Public barrel for host/runtime types and constructors bootstrap and query-cache coordinator Modify exports only if the storage event facade type changes.
src/adapters/diagnostics/bounded-diagnostics.ts Bounded in-memory diagnostics projection/sink and safe pre-mount boot evidence DiagnosticsPort; contracts/diagnostics.ts and telemetry.ts; bootstrap Preserve fail-isolated projection and cloning. Harden non-finite capacity. V3 producer fix belongs primarily in bootstrap.
src/adapters/http/bounded-body-reader.ts Declared-length and streamed byte ceilings, stream cancellation/release isolation, forbidden-body probing, strict UTF-8/JSON decode V3 executor; bounded-body-reader tests Keep as the single bounded response primitive. It already contains the cleanup behavior missing from bounded-json.ts.
src/adapters/http/bounded-json.ts Legacy response stream reader and JSON decoder legacy client.ts Replace internals with bounded-body-reader delegation, then remove with V2 retirement. Current cancel/release failures can reject.
src/adapters/http/client.ts Legacy/V2 operation lookup, profiles, auth recovery, retries, total deadline, response validation/mapping, diagnostics and telemetry legacy contracts and ports; runtime-adapters createRuntimeHttpClient Compatibility-only but exported. Fix empty keyed replay, cooperative auth cancellation, and common body-reader use before relying on it for rollback. Deprecate after callers are migrated.
src/adapters/http/http-contract-bridge.ts V3 request projection, URL/body bounds, credential patch type, final request invariant external-contract-runtime.ts; V3 executor Preserve descriptor-owned request projection. Change credential authority: patch cannot own credentials or transport headers; final invariant must compare exact resolved profile.
src/adapters/http/http-effect-certainty.ts Converts physical-attempt state and problem descriptors into mutation certainty/UI projection V3 executor; contracts Preserve explicit certainty vocabulary. Add a monotonic logical-execution certainty join used across retries.
src/adapters/http/http-execution-v3.ts Descriptor-driven V3 lifetime: validation, projection, credentials, deadline, retry, fetch, response admission, effect verdict and observation external contracts, scope, mutation intent, bridge, bounded reader, certainty, retry policy Main correction site for N-01, N-02, N-03 and cooperative cancellation. Keep one retry authority and closed result union.
src/adapters/http/request-builder.ts Legacy path/query construction and origin/base-prefix checks legacy client; ApiOperation Keep while V2 remains. Do not reuse it to weaken V3 descriptor projection.
src/adapters/http/resource-mapper.ts Thin legacy operation-payload mapper delegation boundary-mapper; legacy client No standalone defect. Remove only with V2, not as part of the correctness patch.
src/adapters/http/retry-policy.ts Legacy retry decision/backoff plus parseRetryAfter reused by V3 legacy client and V3 executor Keep deterministic parse/backoff seam. V2 must additionally prove a valid key before keyed replay.
src/adapters/http/schema-registry.ts Legacy Zod envelope/request/payload validation and clone legacy client/tests No standalone defect. Remains V2-only and should not be merged with installed external validators.
src/adapters/platform/browser-lifecycle.ts Single owner of visibility/network/focus/page/beforeunload listeners and lifecycle snapshots optional-runtime-host.ts Preserve centralized listener ownership and idempotent dispose. Clarify or redesign dirty-source attachment semantics; selection item O-02.
src/adapters/platform/browser-mutation-intent-factory.ts Secure intent/idempotency UUIDs plus monotonic creation time, normalized by defineMutationIntent MutationIntentFactory port; bootstrap Keep. Share one idempotency-key validator so external inputs and generated values have identical bounds.
src/adapters/platform/system-clock.ts Wall clock and abortable sleep with listener/timer cleanup ClockPort; legacy HTTP Keep. Existing unit test covers abort cleanup behavior.
src/adapters/query-cache/conditional-validator-store.ts In-memory ETag CAS sidecar keyed by scope, definition, identity, representation and cache revision bootstrap scope reset; future conditional HTTP/query join Fix tuple codec before composition. Preserve validator grammar, generation/revision checks and bounded capacity.
src/adapters/query-cache/cursor-pagination-runtime.ts Bounded cursor chain, page/snapshot/loop/item/byte validation cursor pagination contract; currently available but not composed Add post-await abort admission or an abort race. Current pre-await-only check can admit a late page.
src/adapters/query-cache/server-state-scope-runtime.ts Synchronous session-generation fence, ordered reset participants, cache reset, identity replacement and lifecycle notifications AuthSessionPort, query invalidation, scope contract; bootstrap Keep synchronous FENCED-before-await design. Consider async shutdown only as O-03; no current stale-generation admission was found.
src/adapters/query-cache/tanstack-cache-coordinator.ts Maps registry topics to query namespace invalidation, coalesces remote hints, defers under mutation leases, resets/disposes TanStack Query, invalidation contracts, cross-context runtime Keep invalidate-only remote authority, generation guard, reset serialization and bounded registry validation. Add teardown characterization if dispose becomes async.
src/adapters/query-cache/tanstack-query-cache.ts Creates QueryClient defaults and QueryCachePort read/write/invalidate adapter with diagnostics TanStack Query, QueryCachePort, errors/diagnostics Keep retry disabled and clone-on-write. Clone-on-read is an optional port-semantics decision, not a confirmed production defect.
src/adapters/telemetry/best-effort-telemetry.ts Allowlisted bounded oldest-drop telemetry queue, scheduled/pagehide flush, sink isolation and evidence TelemetryPort, telemetry/diagnostic contracts, bootstrap Add terminal lifecycle state, joined flush promise and in-flight abort; ensure runtime composition disposes it.

4. Traced boundary inventory

Application ports

File Relevant contract
src/application/ports/auth-session-port.ts Session state, credential patch, recovery; currently has no AbortSignal/deadline context.
src/application/ports/query-cache-port.ts Closed read/write/invalidate result; value is unknown and read mutability is unspecified.
src/application/ports/clock-port.ts Time and abortable sleep.
src/application/ports/diagnostics-port.ts Non-throwing logical diagnostics producer boundary.
src/application/ports/telemetry-port.ts Fire-and-forget semantic event emission.
src/application/ports/mutation-intent-factory.ts Intent identity and keyed-command creation.
src/application/result.ts Closed application result used by pagination and feature projection.

Contracts

Reviewed: server-state-scope.ts, cursor-pagination.ts, diagnostic-buckets.ts, mutation-intent.ts, boundary-mapper.ts, rest-profiles.ts, api-operations.ts, errors.ts, diagnostics.ts, telemetry.ts, query-invalidation.ts, query-keys.ts, cache-invalidation.ts, and external-contract-runtime.ts.

Key joins:

  • external-contract-runtime.ts:117-148 declares authProfileId but validates only non-empty text at 300-344.
  • rest-profiles.ts:11-37 already provides the profile/strategy shape and exact credentials mode used by V2.
  • diagnostics.ts:22-42 is a closed context allowlist and 83-99 rejects the whole record on an unknown key.
  • telemetry.ts defines api.request.failed required attributes: error_kind, http_status_group, attempt_count_bucket, and route_id.
  • server-state-scope.ts makes synchronous signal abortion/isCurrent the generation admission boundary.
  • cache-invalidation.ts supplies the closed wire grammar used by the cross-context runtime.

Bootstrap and feature path

Reviewed: runtime-adapters.ts, server-state-generation-store.ts, create-runtime-composition.ts, composition-root.ts, runtime-application.tsx, main.tsx, optional-runtime-host.ts, installed-contract-contributions.ts, installed-feature-adapters.ts, reference create-reference-feature-input.ts, reference-http-gateway.ts, reference feature contract contribution, reference feature API, application-query.ts, and server-state-generation-provider.tsx.

Production request flow:

reference-http-gateway (has routeId)
  -> createReferenceFeatureInstalledInput (drops routeId)
  -> runtime-adapters contractOperations
  -> createContractHttpExecutor (V3)
  -> runtime-adapters observe
  -> bounded diagnostics projector

The legacy createRuntimeHttpClient is still exported at runtime-adapters.ts:142-163 but is not the installed reference feature request path.

5. Confirmed defects

N-01 — V3 HTTP diagnostics are silently dropped and terminal telemetry is absent

  • Severity: High
  • Confidence: Very high
  • Activation: current production reference-feature V3 path

Evidence:

  • http-execution-v3.ts:150-155 defines an observation with diagnosticsOperation, outcome, attempts and certainty.
  • http-execution-v3.ts:354-365 emits that shape exactly once.
  • runtime-adapters.ts:331-343 maps attempts and certainty as literal context keys.
  • diagnostics.ts:22-42 allows attempt_count_bucket but not attempts or certainty.
  • diagnostics.ts:83-99 rejects the complete diagnostic on the first unknown context key.
  • reference-http-gateway.ts:14-42 and 69-103 constructs a low-cardinality routeId.
  • create-reference-feature-input.ts:41-54 forwards signal and intent but discards routeId.
  • runtime-adapters.ts:331-347 has no V3 telemetry emit at all.
  • VD-07 lines 36-39 requires exactly one logical HTTP diagnostic and exactly one terminal non-abort failure telemetry event.

Minimal reproduction:

Input was the exact runtime-adapters V3 record context:

{
  operation_id: "reference.list",
  outcome: "TRANSPORT_FAILURE",
  attempts: 2,
  certainty: "TIMEOUT"
}

Expected projectDiagnosticRecord(...).success true; actual false.

Impact:

  • Success, retry recovery, failure and cancellation on the installed V3 feature leave no HTTP diagnostic record.
  • V3 terminal failures leave no api.request.failed event even when telemetry is enabled.
  • check:diagnostics remains green because it checks producer presence/source policy, not whether the concrete producer output passes the projector.

Required decision:

  • Observation is a safe typed internal record, not an arbitrary context map.
  • routeId is required at the installed operation-executor boundary.
  • Raw attempt count/duration/status stay internal; only buckets reach diagnostics/telemetry.
  • Cancellation and scope-fence outcomes produce diagnostics once but never api.request.failed.
  • Diagnostics/telemetry failures remain unable to affect the HTTP outcome.

Proposed signature:

export type HttpExecutionObservation = Readonly<{
  routeId: string;
  operationId: string;
  diagnosticsOperation: string;
  outcome: HttpExecutionOutcome<unknown, unknown>["kind"];
  errorKind: string;
  status?: number;
  attemptCount: number;
  durationMs: number;
  effect: HttpEffectCertainty;
  cancellationOwner?: CancellationOwner;
}>;

export interface HttpExecutionContext {
  readonly routeId: string;
  readonly signal?: AbortSignal;
  readonly scope: CacheScopeSnapshot;
  readonly intent?: MutationIntent;
}

Projection in runtime-adapters:

diagnostics.record({
  eventId: "http.request.completed",
  context: {
    route_id: observation.routeId,
    operation_id: observation.operationId,
    operation: observation.diagnosticsOperation,
    outcome: observation.outcome,
    error_kind: observation.errorKind,
    http_status_group: statusGroup(observation.status),
    attempt_count_bucket: attemptBucket(observation.attemptCount),
    duration_bucket: durationBucket(observation.durationMs)
  }
});

For terminal non-abort failures, emit api.request.failed using the same safe route/operation/status/attempt/duration fields. Do not add attempts or certainty as unregistered context. If product operators need effect certainty, add the explicit effect_certainty key and a closed value policy to both contracts and ADR; do not pass the current free string.

N-02 — V3 auth profile is declarative only; credential code can alter transport policy

  • Severity: High
  • Confidence: Very high for generic V3 authority violation; High for current missing-bearer behavior
  • Activation: current bootstrap permits a bearer-declared demo request with an empty patch; arbitrary Accept/credentials requires a custom/defective credential collaborator

Evidence:

  • external-contract-runtime.ts:117-125 contains authProfileId.
  • external-contract-runtime.ts:300-344 checks only non-empty identity, not registry existence or coherence.
  • runtime-adapters.ts:302-326 receives operation.authProfileId but ignores it, always returns credentials: omit, and accepts an authenticated empty patch.
  • http-contract-bridge.ts:14-22 lets the credential patch select any RequestCredentials.
  • http-execution-v3.ts:475-483 rejects only idempotency-key.
  • http-execution-v3.ts:486-489 spreads credential headers after transport-owned Accept, so patch Accept wins.
  • http-contract-bridge.ts:253-273 only checks that credentials is one of three valid Fetch values and generally allows Accept/Content-Type; it does not prove profile equality or header ownership.
  • reference contribution lines 133-141, 177-185, 224-236 declares REFERENCE_EXTERNAL_BEARER for all operations.
  • demo-session credentialPatch is empty at external-session-adapter.ts:109, yet authenticated demo requests are sent.
  • VD-23 lines 211-259 says transport owns Accept/Content-Type and an auth profile exact-fixes Fetch credentials.
  • The existing V2 profile registry at rest-profiles.ts:11-37 and 77-106 is a working local pattern.

Minimal reproduction:

A credential collaborator returned:

{
  kind: "READY",
  headers: { Accept: "text/plain" },
  credentials: "include"
}

The request completed successfully and fetch observed Accept text/plain and credentials include. Expected fetch count was zero or transport-owned application/json/omit.

Current mitigation and residual issue:

  • external-session-adapter.ts:18-46 currently restricts the real owner to authorization and x-csrf-token, so the Accept injection is blocked in this bootstrap path.
  • That does not restore generic executor authority, and required Authorization is not checked. Empty bearer remains possible in the current demo path.
  • Therefore do not characterize this as arbitrary external-owner header injection in the current bootstrap; characterize it as an executor contract violation plus a current profile-completeness failure.

Required decision:

  • Reuse the existing Profile/Strategy registry; do not introduce a general interceptor chain.
  • The resolved profile, not the credential patch, owns credentials.
  • Credential patch contains only a typed, runtime-validated subset of credential headers.
  • A bearer profile requires authorization; an anonymous profile permits none.
  • Unknown/incoherent profiles fail during composition. Missing required headers or extra headers return AUTH_INTEGRATION_FAILURE with effect NOT_STARTED and fetch count zero.
  • UNAUTHENTICATED remains a user/session state, not an integration/configuration error.

Proposed signatures:

export type CredentialHeaderName =
  | "authorization"
  | "x-csrf-token"
  | "x-tenant-context";

export type RestAuthProfile = Readonly<{
  authProfileId: string;
  transport: "ANONYMOUS" | "BEARER_HEADER" | "SAME_ORIGIN_COOKIE";
  credentials: "omit" | "same-origin" | "include";
  allowedCredentialHeaders: readonly CredentialHeaderName[];
  requiredCredentialHeaders: readonly CredentialHeaderName[];
}>;

export type CredentialPatchOutcome =
  | Readonly<{
      kind: "READY";
      headers: Readonly<Partial<Record<CredentialHeaderName, string>>>;
    }>
  | Readonly<{ kind: "UNAUTHENTICATED" }>
  | Readonly<{ kind: "UNAVAILABLE" }>
  | Readonly<{ kind: "SCOPE_FENCED" }>;

attachCredentials(
  operation: Readonly<{
    operationId: string;
    authProfileId: string;
    method: string;
  }>,
  context: Readonly<{ signal: AbortSignal }>
): Promise<CredentialPatchOutcome> | CredentialPatchOutcome;

The executor dependency receives a validated ReadonlyMap<string, RestAuthProfile>. Final invariant compares init.credentials to the selected profile and rejects missing/extra credential headers.

Demo migration must be explicit. Recommended repository choice: allow createDemoSessionAdapter to receive a demo credential patch from bootstrap and supply a fixed non-secret Authorization marker only in AUTH_MODE=demo; keep REFERENCE_EXTERNAL_BEARER strict. Do not silently weaken the bearer profile to make tests pass. If a product backend wants anonymous demo calls, it needs a distinct anonymous contract/profile selected at composition.

N-03 — retry-time scope fence downgrades a previously dispatched command to NOT_STARTED

  • Severity: High
  • Confidence: Very high
  • Activation: latent for a future IDEMPOTENT command with retryBudget greater than zero; the current reference create is KEYED with retryBudget zero

Evidence:

  • After response admission, attemptState becomes SETTLED at http-execution-v3.ts:648-656.
  • A retry continues at 657-692.
  • The next iteration checks scope at 511-516 and uses current attemptState, which still yields MAYBE_APPLIED.
  • There is a second scope check inside final invariants at 554-563.
  • If the scope changes between those two checks, lines 568-575 call preDispatchEffect(isCommand), returning NOT_STARTED and forgetting the prior attempt.
  • Deep design lines 1683-1690 says dispatch followed by timeout/network/abort/body loss is MAYBE_APPLIED.

Minimal reproduction:

  • Contract: commandEffect non-null, retrySemantics IDEMPOTENT, retryBudget 1.
  • Attempt 1: fetch returns 429.
  • Sleep resolves.
  • Scope is current at retry-loop entry and false at final invariant.
  • Expected SCOPE_FENCED with MAYBE_APPLIED.
  • Actual SCOPE_FENCED with NOT_STARTED.

Root cause:

PhysicalAttemptState is being used as both current-attempt state and logical-execution history. Reset/final-invariant code reasons only about “this retry has not sent” and loses “a previous physical attempt was sent”.

Required decision:

Maintain a monotonic logical certainty accumulator for the whole execution. A new unsent retry cannot lower prior MAYBE_APPLIED. Final-invariant failures use the joined logical certainty; the first attempt can still return NOT_STARTED.

Proposed helper:

export function joinMutationEffectCertainty(
  current: MutationEffectCertainty,
  observed: MutationEffectCertainty
): MutationEffectCertainty;

Join rules:

  • MAYBE_APPLIED dominates NOT_STARTED and NOT_APPLIED.
  • APPLIED_CONFIRMED is terminal and cannot enter an automatic retry.
  • NOT_APPLIED dominates NOT_STARTED for internal history.
  • Query operations remain NOT_APPLICABLE and do not use the mutation lattice.

Also check caller/scope/deadline ownership after every awaited admission and before returning success. A separately named characterization should decide the response-completed-versus-caller-abort race; do not fold an unverified race rule into this patch without a test.

N-04 — telemetry continues work after dispose and composition never disposes it

  • Severity: High
  • Confidence: Very high
  • Activation: current when telemetry is enabled; no-op telemetry is unaffected

Evidence:

  • best-effort-telemetry.ts:95-101 schedules a callback that always calls flush.
  • emit at 104-125 has no disposed check.
  • flush at 127-147 has no disposed check or in-flight AbortController.
  • dispose at 154-156 removes only pagehide.
  • runtime-adapters.ts:412-416 clears validators/scope/generation but omits telemetry.dispose.
  • create-runtime-composition.ts:60-66 calls infrastructure.dispose after optional shutdown, so the omission reaches application teardown.
  • flush at 127-130 returns an already-resolved promise when another flush is active, so await adapter.flush does not mean “the active delivery has settled”.

Minimal reproduction:

  • Queue one valid api.request.failed with a captured scheduler callback.
  • Call dispose.
  • Run the captured callback and call emit again.
  • Expected no fetch and pendingCount zero.
  • Actual one fetch; later emit is also accepted.

Impact:

  • HMR/test/runtime teardown can send queued or future events after the owning composition is gone.
  • In-flight work has no cancellation owner.
  • This is a lifecycle/privacy contract defect even though delivery is best-effort.

Required decision:

Use a small terminal lifecycle state, not a durable queue:

type TelemetryLifecycle = "ACTIVE" | "DISPOSED";

flush(): Promise<void>;
dispose(): void;

Semantics:

  • emit after dispose is a no-op.
  • dispose removes pagehide, clears queued events, invalidates scheduled callbacks, and aborts the current sink request.
  • flush joins and returns the active flush promise.
  • completion of a sink that ignored abort cannot reschedule or update post-dispose delivery state.
  • disposal drops data silently; it must not recursively emit a drop event while shutting down.
  • runtime infrastructure.dispose calls telemetry.dispose before destroying diagnostics/state dependencies.

A separate async shutdown or persistent retry queue is unnecessary for current best-effort policy.

N-05 — conditional-validator composite key is collision-prone

  • Severity: High when composed; current effective risk Medium / activation blocker
  • Confidence: Very high
  • Activation: docs classify sidecar AVAILABLE_NOT_COMPOSED; bootstrap creates/clears it but HTTP does not use it

Evidence:

  • conditional-validator-store.ts:43-58 joins four unescaped components with colon.
  • identityToken permits colon at 47.
  • scope fingerprint permits colon in server-state-scope-runtime.ts:196-200.
  • definitionId is only checked for truthiness at line 46.
  • architecture status at api-contract-schema-mapper-and-server-state.md:108 explicitly says AVAILABLE_NOT_COMPOSED.

Collision using valid values and the same scope/version:

A: definitionId = "resource:detail"
   identityToken = "identity-token-00000001"

B: definitionId = "resource"
   identityToken = "detail:identity-token-00000001"

Both encode to the same string. Installing B overwrites A; prepare(A) returns Bs ETag.

Impact after composition:

A validator from one definition could be sent for another and a 304 could admit the wrong cached representation/revision relationship.

Required decision:

Use an injective deterministic tuple codec, not a repository abstraction. JSON.stringify of a validated fixed tuple is sufficient:

type ConditionalValidatorKeyTuple = readonly [
  scopeFingerprint: string,
  definitionId: string,
  identityToken: string,
  representationVersion: number
];

Validate and byte-bound definitionId and fingerprint at this trust boundary. No public store API change or persisted-data migration is needed because the store is in-memory and not composed into HTTP yet.

N-06 — legacy keyed commands can automatically retry with no Idempotency-Key

  • Severity: High on the compatibility/rollback path
  • Confidence: High
  • Activation: exported createRuntimeHttpClient/createHttpClient; not the current installed reference path

Evidence:

  • client.ts:241-246 uses nullish coalescing, so caller value "" is retained rather than replaced.
  • client.ts:534 sets Idempotency-Key only if the value is truthy.
  • retry-policy.ts:45-68 allows both safe and keyed retries.
  • Therefore a keyed command with explicit empty key can replay after a retryable response while sending no key.
  • The existing keyed integration test uses a non-empty logical-command value; there is no invalid-key case.
  • VD-23 lines 691-703 permits V1 fallback only if hardening remains.

Required decision:

Export one defineIdempotencyKey validator from mutation-intent.ts and use it in both V2 and V3. Reject empty, whitespace-only, control-character, and over-byte-budget keys before credentials, timers, or fetch. Do not trim or silently regenerate a caller-supplied invalid value. Return VALIDATION_REJECTED / IDEMPOTENCY_KEY_INVALID, attempt count zero.

N-07 — legacy total deadline does not bound or cancel credential attachment

  • Severity: High on the compatibility/rollback path
  • Confidence: High
  • Activation: auth-required V2 operation with a non-cooperative external owner

Evidence:

  • client.ts:517-526 creates the attempt controller/timer.
  • client.ts:570-586 awaits authSession.credentialPatch directly.
  • auth-session-port.ts:15-27 exposes no signal/deadline to credentialPatch.
  • If the owner never settles, aborting the attempt controller does not settle the await, so execute can exceed its total deadline indefinitely.
  • Recovery is raced at client.ts:297-324 and 666-697, but authSession.recover itself receives no signal; late owner work can continue.
  • V3 has the better local waiting pattern at http-execution-v3.ts:427-466, although its underlying credential work is not cooperatively signaled either.
  • VD-23 lines 339-349 explicitly includes credential/recovery in total deadline and requires auth waiter cleanup.

Proposed compatible port extension:

export type AuthOperationContext = Readonly<{
  signal: AbortSignal;
  deadlineAtMonotonicMs: number;
}>;

credentialPatch(
  binding: CredentialRequestBinding,
  context?: AuthOperationContext
): Promise<CredentialPatch>;

recover(context?: AuthOperationContext):
  Promise<"restored" | "no-session">;

Make context optional for one release to preserve existing owner implementations, but both clients must race owner promises against the lifetime signal immediately. Extend ExternalSessionOwner attachCredential/recoverSession the same way, pass the context through, and ignore all late completions. In the following breaking release, require the context from external owners.

Error semantics:

  • deadline owner: REQUEST_TIMEOUT / TIMEOUT.
  • caller owner: REQUEST_ABORTED / CANCELLED.
  • scope owner in V3: ABORTED_BY_SCOPE or SCOPE_FENCED, preserving logical effect.
  • ordinary owner rejection: AUTH_INTEGRATION_FAILURE.
  • none of these paths may fetch.

N-08 — legacy bounded JSON can reject and leave response cleanup inconsistent

  • Severity: Medium
  • Confidence: High
  • Activation: V2 response path

Evidence:

  • bounded-json.ts:9-12 awaits response.body.cancel outside a catch.
  • lines 24-26 awaits reader.cancel; a rejection escapes the closed result.
  • lines 30-33 does not cancel after reader failure and releaseLock can throw.
  • client.ts:714-723 returns immediately on content-type mismatch without cancelling the response body.
  • bounded-body-reader.ts:31-76 and 148-153 already isolates cancellation/release errors and is well tested.

Required decision:

Make bounded-body-reader the common primitive. Keep readBoundedJsons public return codes temporarily by delegating and mapping:

  • RESPONSE_TOO_LARGE -> RESPONSE_BODY_LIMIT.
  • UTF8_INVALID / JSON_INVALID / RESPONSE_STREAM_FAILURE -> MALFORMED_JSON for legacy compatibility.

Cancel on V2 content-type mismatch. Do not maintain two stream-reader strategies.

N-09 — localStorage fallback cannot prove the event came from localStorage

  • Severity: Medium
  • Confidence: Very high
  • Activation: storage fallback; invalidation is hint-only, so effect is stale/refetch pressure rather than data/authorization corruption

Evidence:

  • StoragePulseEvent at browser-cross-context-invalidation.ts:98-101 contains only key and newValue.
  • receiveStorage at 179-193 checks exact key/value but cannot check area.
  • browser-cross-context-host.ts:206-248 discards native storageArea.
  • client-cache-and-storage.md:82-83, 939-948 and checklist 1638 explicitly documents this missing check.
  • Existing native browser tests cover homogeneous BroadcastChannel and homogeneous storage fallback, not a foreign storage area.

Required decision:

Capture localStorage once and derive both the write facade and event validator from the same object identity. Do not call a hostile getter twice.

Proposed facade:

export type StoragePulseEvent = Readonly<{
  key: string | null;
  newValue: string | null;
  storageArea: "EXPECTED_LOCAL_STORAGE" | "OTHER_OR_UNKNOWN";
}>;

Core receiveStorage admits only EXPECTED_LOCAL_STORAGE. Register the pulse key in storage-keys.ts at the same time:

CACHE_INVALIDATION_PULSE:
  backend localStorage
  classification opaque-cache
  valueCodec opaque-string-v1
  ttl null
  migration discard
  quotaFallback no-persist

The storage adapter need not own pulse I/O; the registry owns its physical-key policy.

N-10 — cursor pagination can admit a page after cancellation

  • Severity: Medium
  • Confidence: High
  • Activation: AVAILABLE_NOT_COMPOSED pagination runtime

Evidence:

  • cursor-pagination-runtime.ts:29-33 checks signal only before await loadPage.
  • There is no post-await signal check before page validation/accumulation and success at lines 34-59.
  • A non-cooperative loadPage that resolves after abort can make the last page return success.
  • The architecture status claims an abort test, but cursor-pagination-runtime.test.ts currently covers finite chain, invalid invariants, loop and snapshot drift only.

Required decision:

Race loadPage with the signal or check immediately after await and before observing the page. Prefer an awaitWithAbort helper so a never-settling loader cannot hold loadAll forever. Late page completion is ignored. Return REQUEST_ABORTED / PAGINATION_ABORTED without partial items.

N-11 — non-finite queue capacities bypass boundedness

  • Severity: Low
  • Confidence: High
  • Activation: custom adapter construction only; bootstrap uses defaults

Evidence:

  • bounded-diagnostics.ts:21 uses Math.max(1, maxEntries). NaN remains NaN and Infinity remains Infinity.
  • best-effort-telemetry.ts:49 has the same issue.
  • Comparisons against NaN/Infinity can disable intended eviction.

Fix: require Number.isSafeInteger and a documented upper ceiling, throwing TypeError at construction. This is configuration validation, not a runtime drop.

6. Selection-dependent improvements and explicitly separated hypotheses

These are not confirmed defects at the same level as N-01 through N-11.

O-01 — mixed BroadcastChannel/storage-only tabs

  • Confidence: Medium
  • Evidence: browser-cross-context-invalidation.ts:318-342 returns immediately after a successful BroadcastChannel post and does not pulse storage. A second tab whose BroadcastChannel constructor failed but whose storage works listens only to storage.
  • Existing tests at cross-tab-invalidation.test.ts:447-488 cover a sender whose BroadcastChannel post fails, then storage fallback. Browser capability tests cover BroadcastChannel/BroadcastChannel and storage/storage, not BroadcastChannel sender/storage-only receiver.
  • Product decision: if per-tab capability asymmetry must be supported, mirror every accepted BroadcastChannel event to storage and rely on existing eventId dedupe. If “priority fallback” assumes partition-homogeneous capability, document that assumption and keep single-write behavior.
  • Trade-off: mirroring increases synchronous localStorage writes and storage-event fan-out. This protocol is a best-effort hint with focus/stale revalidation, so do not build a durable/exactly-once bus.

O-02 — beforeunload attachment comment does not match implementation

  • Confidence: High for mismatch; Low material impact
  • browser-lifecycle.ts:39-43 says the listener exists only while a source reports dirty.
  • syncBeforeUnload at 135-143 attaches whenever any source is registered; it cannot observe a callback changing from false to true.
  • onBeforeUnload rechecks actual dirtiness, so users are not incorrectly prompted.
  • Preferred minimal action: document “while at least one dirty reporter is registered”. Add an observable update handle only if listener-count optimization is a real requirement.

O-03 — async scope/coordinator teardown

  • Confidence: Medium
  • ServerStateScopeRuntime.dispose and QueryInvalidationCoordinator.dispose are void while reset/flush promises may exist.
  • Current generation checks and disposed flags prevent reactivation; no stale cache admission was demonstrated.
  • If runtime shutdown needs a “all background state work settled” guarantee, introduce async close and await it in composition. Otherwise characterize late work and retain the simpler void API.

O-04 — QueryCachePort clone-on-read

  • Confidence: Medium
  • tanstack-query-cache.ts clones writes but returns TanStacks object reference on read.
  • Docs say cached mapped values are immutable, but QueryCachePort returns unknown rather than a readonly type.
  • Decide whether the port guarantees immutable values or isolation. If isolation is required, clone on read and return QUERY_CACHE_FAILURE on clone failure. Do not add cost to production TanStack hooks based only on this legacy port.

O-05 — caller-abort versus already-buffered successful response

  • Confidence: Medium; not included in confirmed findings
  • V3 aborts the fetch signal, but admitResponse does not directly inspect terminalCancellation after a custom/buffered reader resolves.
  • Before changing semantics, add a deterministic test where readBoundedResponseBytes aborts the caller and then returns valid bytes. Product must choose first-terminal-owner-wins versus completed-response-wins. The designs CancellationOwner wording suggests first-owner-wins, but this report does not claim it without characterization.

7. Patterns to apply, and patterns to reject

Apply:

  1. Profile/Strategy registry for auth. The operation selects an immutable profile; the credential owner supplies only proof material.
  2. Stable tuple codec for validator keys. It directly solves injectivity and keeps storage private.
  3. Monotonic certainty lattice for logical command execution. Physical attempts cannot downgrade already-observed uncertainty.
  4. Structured cancellation context. One lifetime signal/deadline is passed through credential, recovery, retry sleep, fetch and response admission.
  5. Small terminal lifecycle state for telemetry. ACTIVE/DISPOSED plus one joined flush promise is sufficient.
  6. Adapter-boundary predicate for StorageEvent.storageArea. Browser identity checks belong at native capability capture.
  7. Characterization-first consolidation for legacy body reading. Delegate to the proven bounded reader while preserving old error codes.

Reject:

  • A generic HTTP interceptor/middleware pipeline: it obscures authority/order and recreates the transport-header bug.
  • A generic repository abstraction for query cache, ETag store and storage pulse: their consistency and lifecycle semantics differ.
  • Durable/exactly-once cross-tab messaging: invalidation is a bounded hint; server revalidation remains authoritative.
  • Persistent telemetry retry/offline queue: current contract is best-effort and has no consent/retention decision.
  • A new retry library or circuit breaker: current retry bounds are explicit and adequate once replay proof/certainty is corrected.
  • Event sourcing for scope/reset: synchronous generation fencing plus ordered participants is simpler and already correct.

8. Exact implementation manifest

Implement as small reviewable changes. “Delete: none” and “Move: none” applies to the immediate remediation; legacy removals occur only after the compatibility window.

Change set A — V3 observability and monotonic effect

Modify:

  • src/adapters/http/http-execution-v3.ts
  • src/adapters/http/http-effect-certainty.ts
  • src/bootstrap/runtime-adapters.ts
  • src/features/reference-feature/adapters/create-reference-feature-input.ts
  • src/contracts/diagnostics.ts only if effect_certainty is approved; otherwise do not modify its allowlist
  • tests/unit/http-execution-v3.test.ts
  • tests/unit/runtime-adapters.test.ts
  • tests/features/reference-feature/reference-runtime-composition.test.ts
  • docs/architecture/decisions/VD-07-diagnostics-and-telemetry-exporter.md
  • docs/architecture/2026-07-30-frontend-runtime-capability-repository-aligned-implementation-closed-deep-design.md

Create:

  • tests/integration/http-execution-v3-observability.test.ts

Delete: none. Move: none.

Change set B — profile-authoritative credentials and auth cancellation

Modify:

  • src/contracts/rest-profiles.ts
  • src/contracts/external-contract-runtime.ts for strict authProfileId grammar only
  • src/adapters/http/http-contract-bridge.ts
  • src/adapters/http/http-execution-v3.ts
  • src/application/ports/auth-session-port.ts
  • src/adapters/auth/external-session-adapter.ts
  • src/bootstrap/runtime-adapters.ts
  • src/features/reference-feature/adapters/create-reference-feature-input.ts to map AUTH_INTEGRATION_FAILURE
  • tests/unit/rest-profile-contract.test.ts
  • tests/unit/auth-session-adapter.test.ts
  • tests/unit/http-execution-v3.test.ts
  • tests/unit/runtime-adapters.test.ts
  • tests/features/reference-feature/reference-runtime-composition.test.ts
  • docs/architecture/decisions/VD-23-api-transport-selection-and-rest-execution.md

Create:

  • tests/integration/http-execution-v3-auth-profile.test.ts

Delete: none. Move: none.

Change set C — telemetry lifecycle

Modify:

  • src/adapters/telemetry/best-effort-telemetry.ts
  • src/bootstrap/runtime-adapters.ts
  • tests/unit/telemetry.test.ts
  • tests/unit/runtime-adapters.test.ts
  • docs/architecture/decisions/VD-07-diagnostics-and-telemetry-exporter.md

Create: none. Delete: none. Move: none.

Change set D — state sidecars and cancellation

Modify:

  • src/adapters/query-cache/conditional-validator-store.ts
  • src/adapters/query-cache/cursor-pagination-runtime.ts
  • tests/unit/conditional-validator-store.test.ts
  • tests/unit/cursor-pagination-runtime.test.ts
  • docs/architecture/api-contract-schema-mapper-and-server-state.md

Create: none. Delete: none. Move: none.

Change set E — legacy rollback hardening and reader consolidation

Modify:

  • src/contracts/mutation-intent.ts
  • src/application/ports/auth-session-port.ts
  • src/adapters/auth/external-session-adapter.ts
  • src/adapters/http/client.ts
  • src/adapters/http/http-execution-v3.ts to reuse the common key validator/context
  • src/adapters/http/bounded-json.ts to delegate to bounded-body-reader
  • tests/integration/http-client.test.ts
  • tests/integration/auth-recovery.test.ts
  • tests/integration/http-execution-contract.test.ts
  • tests/unit/bounded-body-reader.test.ts
  • docs/architecture/decisions/VD-23-api-transport-selection-and-rest-execution.md

Create:

  • tests/unit/bounded-json-compatibility.test.ts

Delete immediately: none. Move: none.

Later removal after zero runtime callers and an expired rollback window:

  • Delete src/adapters/http/client.ts
  • Delete src/adapters/http/bounded-json.ts
  • Delete src/adapters/http/request-builder.ts
  • Delete src/adapters/http/resource-mapper.ts
  • Delete src/adapters/http/schema-registry.ts
  • Remove createRuntimeHttpClient from src/bootstrap/runtime-adapters.ts
  • Remove V2-only tests/fixtures after V3 equivalents exist

Do not delete retry-policy.ts while V3 imports parseRetryAfter.

Change set F — exact storage fallback admission

Modify:

  • src/contracts/storage-keys.ts
  • src/adapters/cross-context-invalidation/browser-cross-context-host.ts
  • src/adapters/cross-context-invalidation/browser-cross-context-invalidation.ts
  • src/adapters/cross-context-invalidation/index.ts
  • tests/unit/cross-tab-invalidation.test.ts
  • tests/browser-capabilities/cross-context-invalidation.spec.ts
  • docs/architecture/client-cache-and-storage.md
  • docs/architecture/decisions/VD-13-client-cache-scope-and-persistence.md

Create:

  • tests/unit/browser-cross-context-host.test.ts

Delete: none. Move: none.

Optional O-01 mirroring must be a separate change set and must not be bundled with the exact storageArea security check.

Change set G — capacity and lifecycle documentation hardening

Modify:

  • src/adapters/diagnostics/bounded-diagnostics.ts
  • src/adapters/telemetry/best-effort-telemetry.ts
  • tests/unit/diagnostics.test.ts
  • tests/unit/telemetry.test.ts
  • src/adapters/platform/browser-lifecycle.ts comment only, unless observable dirty state is selected

Create a browser-lifecycle unit test only if behavior changes. Delete: none. Move: none.

9. TDD matrix

Write each test red first.

Test name Input/setup Expected result
records_v3_terminal_outcome_with_allowlisted_context_once V3 success and terminal 503; concrete diagnostics adapter one record per logical execution; route/operation/status/attempt/duration are safe bucket keys; dropped map empty
emits_v3_terminal_non_abort_failure_once V3 retry exhaustion one api.request.failed after final attempt, none per attempt
does_not_emit_v3_failure_telemetry_for_caller_or_scope_abort caller abort and scope fence diagnostic once, telemetry zero
forwards_reference_route_id_to_v3_observation list/detail/create gateway requests exact registry route IDs reach observation; no raw URL/intent
rejects_unknown_auth_profile_during_runtime_composition installed contract refers to missing profile composition throws before any feature can execute
rejects_bearer_ready_patch_without_authorization authenticated session, empty READY patch AUTH_INTEGRATION_FAILURE, NOT_STARTED, fetch zero
rejects_credential_patch_that_owns_accept_content_type_or_credentials hostile credential adapter integration/contract failure, fetch zero
sends_exact_profile_credentials_and_required_headers valid bearer and cookie profiles exact init.credentials and header subset
forwards_lifetime_abort_to_external_credential_owner hanging owner, deadline/caller abort owner signal aborts; execution settles with correct closed error
preserves_prior_maybe_applied_when_retry_is_fenced_before_dispatch IDEMPOTENT command, first 429, scope false only at retry final invariant SCOPE_FENCED and MAYBE_APPLIED; fetch called once
never_decreases_logical_command_certainty_across_attempts table of NOT_STARTED/NOT_APPLIED/MAYBE combinations join follows lattice
dispose_prevents_queued_and_future_telemetry_delivery captured schedule, emit, dispose, callback, emit fetch zero, queue zero
dispose_aborts_active_telemetry_delivery_without_reschedule fetch waits on signal, dispose signal aborted, no reschedule
concurrent_flush_joins_active_delivery call flush twice while sink pending both promises settle only after same fetch settles; fetch once
runtime_dispose_disposes_telemetry_before_state_dependencies spied telemetry/lifecycle pagehide removed and sink aborted during composition dispose
keeps_delimiter_ambiguous_validator_bindings_distinct the A/B binding pair from N-05 prepare(A)=etag A, prepare(B)=etag B
rejects_unbounded_or_invalid_validator_definition_identity empty/oversize/invalid fingerprint install false, no row
rejects_empty_control_and_oversize_legacy_idempotency_keys_before_send "", whitespace, control, 257-byte key VALIDATION_REJECTED/IDEMPOTENCY_KEY_INVALID; auth/fetch/timer zero
reuses_one_valid_legacy_key_on_every_retry keyed 503 then success identical non-empty header on each physical attempt
settles_legacy_hanging_credential_at_total_deadline owner never resolves REQUEST_TIMEOUT; fetch zero; listeners/timer removed
ignores_late_legacy_recovery_completion recovery resolves after abort/scope transition terminal result unchanged; no replay/notification from late completion
bounded_json_never_rejects_when_cancel_or_release_fails hostile stream methods closed legacy error, no rejection
content_type_mismatch_cancels_legacy_response_body_once non-JSON response with cancellable stream CONTENT_TYPE_MISMATCH and cancel called once
ignores_storage_event_from_non_local_storage_area exact pulse key/value but OTHER_OR_UNKNOWN area delivery zero
accepts_storage_event_only_from_captured_local_storage native-like event with captured identity delivery once
captures_local_storage_getter_once getter returns different objects per access getter called once; event/write identity coherent
ignores_late_cursor_page_after_abort loader aborts signal then resolves final page REQUEST_ABORTED/PAGINATION_ABORTED
settles_never_resolving_cursor_loader_on_abort loader never settles loadAll settles promptly with abort
rejects_non_finite_adapter_capacities NaN, Infinity, fractional, excessive values TypeError at construction

Targeted commands:

corepack pnpm exec vitest run \
  tests/unit/http-execution-v3.test.ts \
  tests/integration/http-execution-v3-observability.test.ts \
  tests/integration/http-execution-v3-auth-profile.test.ts \
  tests/features/reference-feature/reference-runtime-composition.test.ts

corepack pnpm exec vitest run \
  tests/unit/telemetry.test.ts \
  tests/unit/runtime-adapters.test.ts \
  tests/unit/diagnostics.test.ts

corepack pnpm exec vitest run \
  tests/unit/conditional-validator-store.test.ts \
  tests/unit/cursor-pagination-runtime.test.ts \
  tests/unit/cross-tab-invalidation.test.ts \
  tests/unit/browser-cross-context-host.test.ts

corepack pnpm exec vitest run \
  tests/integration/http-client.test.ts \
  tests/integration/auth-recovery.test.ts \
  tests/integration/http-execution-contract.test.ts \
  tests/unit/bounded-json-compatibility.test.ts

Browser evidence:

corepack pnpm test:browser-capabilities

Required final gates:

corepack pnpm check:types
corepack pnpm lint
corepack pnpm check:architecture
corepack pnpm check:diagnostics
corepack pnpm test:unit
corepack pnpm test:integration
corepack pnpm test:reference-feature

If storage registry changes, also run:

corepack pnpm check:registries
corepack pnpm verify:compatibility

10. Compatibility and migration order

  1. Land characterization tests only. They must fail for N-01 through N-05 and remain isolated from implementation.
  2. Add routeId to InstalledContractOperationExecutor and HttpExecutionContext. Update every compile-time call site in reference gateway/tests in one commit. This is source-breaking but has no wire change.
  3. Add typed V3 observation fields and runtime projection. Keep diagnostic/telemetry registries closed; use existing buckets. Deploy read operations first and verify non-empty, non-dropped V3 records.
  4. Add logical certainty accumulation. No wire/API change outside the exported outcome values; downstream code must already handle MAYBE_APPLIED.
  5. Extend RestAuthProfile with requiredCredentialHeaders and build the profile index at composition. Deploy fail-closed validation before changing credential owners.
  6. Extend auth cancellation context as optional. Update internal/demo/external adapters and both clients. After one compatibility release, make it required for external owners.
  7. Make demo authentication explicit. Do not relax REFERENCE_EXTERNAL_BEARER. Validate the selected demo behavior only against loopback/test provider evidence before enabling.
  8. Fix telemetry lifecycle and call dispose from infrastructure teardown. This changes only post-dispose behavior and flush-await semantics.
  9. Replace validator key codec before the first conditional HTTP composition. It is memory-only, so no data migration is required.
  10. Harden V2 idempotency/cancellation/body reading before documenting it as a rollback target. Add deprecation notices and audit createRuntimeHttpClient callers.
  11. Add storage registry entry and exact storageArea check without changing the invalidation wire envelope/version.
  12. Run native browser capability evidence. Decide mixed-transport mirroring separately.
  13. Only after zero V2 callers, V3/provider evidence, and expiration of the rollback window, delete legacy files.

Compatibility notes:

Change Compatibility
Required routeId TypeScript source break; no network wire break. Update all executor callers atomically.
Observation shape Internal dependency seam but exported type; tests/custom composition must update.
AUTH_INTEGRATION_FAILURE outcome Exhaustive switch source break; add mapping to existing ApiFailure AUTH_INTEGRATION_FAILURE.
RestAuthProfile required headers Source break for custom profiles; provide migration error naming profile ID only.
Optional AuthOperationContext phase Backward compatible for owner implementation types; behavior improves immediately for updated owners.
Telemetry dispose Intentional behavioral change only after ownership ends.
Validator key codec No persisted state and no HTTP composition; safe replacement.
StoragePulseEvent area enum Test/host facade source break; wire envelope unchanged.
Invalid legacy idempotency key Intentional fail-fast behavior; callers relying on empty keys must be fixed, not grandfathered.

11. Rollback sequence

Rollback must preserve security/correctness invariants.

  1. Disable affected command operations first; do not route a command to legacy V2 unless V2 idempotency, auth deadline, final invariant and provider evidence are already fixed.
  2. If observability sink causes incidents, set telemetry config off or wire noOpTelemetry. Keep V3 diagnostic projection, redaction registries and producer tests.
  3. If strict auth composition rejects a bad deployment, fail the operation/provider as unavailable and repair the profile/owner. Do not restore broad credential headers or patch-owned credentials.
  4. Read-only V3 operations may fall back only to a hardened V2 path with unexpired provider/security evidence, matching VD-23 lines 700-703.
  5. The logical-effect accumulator must not be rolled back independently; downstream reconciliation depends on conservative MAYBE_APPLIED.
  6. Conditional-validator codec rollback is simply disabling conditional request composition and clearing the in-memory store.
  7. Storage-area hardening rollback should degrade to BroadcastChannel/local-only revalidation, not accept unverified storage events.
  8. Cross-context wire version remains unchanged, so no coordinated tab upgrade is needed.
  9. Roll back contract artifact, frontend and backend as one coherent set where operation/profile semantics changed.
  10. Keep new regression tests during rollback; change only routing/configuration.

12. Existing tests/docs cross-check and false-positive controls

What the passing tests genuinely prove

  • http-execution-v3.test.ts proves descriptor projection, keyed intent validation, one-key reuse, no query key, schema containment, post-dispatch command uncertainty, scope fencing after a response, credential-wait deadline, deadline retry suppression, retry-sleep cancellation and forbidden-body stream failure.
  • bounded-body-reader.test.ts has strong hostile stream/cancellation/release coverage; this is why consolidation is preferred.
  • server-state-scope-runtime.test.ts proves synchronous fencing, participant order, fail-closed reset/activation and identity close.
  • tanstack-cache-coordinator.test.ts proves topic mapping, lease deferral, reset ordering and disposal behavior under current contract.
  • cross-tab-invalidation.test.ts proves invalid/stale/self/duplicate/gap handling, bounded fallback and cleanup.
  • browser capability spec proves actual BroadcastChannel/BroadcastChannel and storage/storage delivery in supported browsers.
  • diagnostics.test.ts and telemetry.test.ts prove projector allowlists, bounded queues, hostile context containment and pagehide listener removal.
  • integration/http-diagnostics.test.ts proves exactly-once diagnostics/telemetry for legacy createHttpClient.
  • reference runtime composition proves V3 URLs/headers and that private intent values do not appear in collected evidence.
  • 21 selected files / 144 tests pass, so findings do not rely on a generally broken baseline.

Why those tests do not invalidate the findings

  • Legacy HTTP diagnostics tests import createHttpClient, not createContractHttpExecutor. They cannot validate V3 runtime-adapters projection.
  • reference runtime composition only asserts private values are absent; an empty diagnostics array also satisfies it.
  • check:diagnostics counts/inspects source producers but does not execute their concrete context through projectDiagnosticRecord.
  • auth-session tests validate the external owners current header allowlist, but V3s exported CredentialPatchOutcome and final invariant still grant broader authority; they also do not require Authorization for the declared bearer profile.
  • current V3 command is KEYED with retryBudget zero. It does not exercise an IDEMPOTENT retry followed by a final-invariant fence.
  • telemetrys disposal test calls dispose after pagehide has already flushed and checks only listener removal.
  • conditional-validator tests use delimiter-unambiguous values and docs explicitly mark the sidecar not composed.
  • storage tests check exact key and envelope but the facade has no storageArea field to assert.
  • browser docs explicitly list pulse registration and storageArea as unfinished, confirming N-09 rather than contradicting it.
  • mixed-transport asymmetry is left as O-01 because the documented priority fallback can reasonably be read as a deliberate single-transport policy.
  • beforeunload does not prompt falsely because the event callback rechecks dirty state; only the attachment comment is mismatched.
  • no claim is made that conditional validators or cursor pagination currently corrupt the installed reference HTTP path; both are activation blockers for future composition.

13. Design worth preserving

  • V3 keeps operation semantics in installed descriptors and re-verifies a bounded final request rather than accepting arbitrary URLs/headers from features.
  • Bounded response admission avoids Response.json, enforces byte ceilings, uses strict UTF-8, and isolates stream cleanup failures.
  • Mutation intent and command effect are explicit public concepts; post-dispatch uncertainty is represented instead of guessed from HTTP status.
  • Server-state scope fences synchronously before any reset await, aborts the old signal, closes identity registries and creates a new QueryClient generation.
  • Query invalidation sends only registry topic/version/epoch, never query keys, cached data, account IDs or mutation payloads. Remote authority is invalidate-only.
  • Cross-context event parsing is closed and bounded with TTL, event dedupe, source epoch/sequence and gap escalation.
  • TanStack retry is disabled so the HTTP layer remains the single retry authority.
  • Diagnostics/telemetry have closed registries, low-cardinality value policies, redaction and failure isolation.
  • External auth owner never returns raw tokens to application code; it returns a constrained header patch.
  • Composition tears down optional capabilities before base state, which is the right dependency order.
  • No unnecessary persistence/offline mutation queue/exactly-once protocol is claimed.

P0:

  1. N-01 V3 observability.
  2. N-02 profile-authoritative auth.
  3. N-03 monotonic command certainty.
  4. N-04 telemetry terminal lifecycle.

P1 before enabling currently available capabilities or trusting rollback:

  1. N-05 conditional-validator key codec.
  2. N-06/N-07 V2 replay and auth deadline.
  3. N-09 exact storageArea and registered pulse.
  4. N-10 pagination cancellation.

P2 cleanup:

  1. N-08 body-reader consolidation.
  2. N-11 capacity validation.
  3. O-02 documentation alignment.
  4. Decide O-01/O-03/O-04/O-05 with explicit product requirements and characterization tests.

This ordering closes silent current-path failures and security/effect authority first, then makes latent capabilities safe to compose, and only then removes duplication.