fix: harden the legacy HTTP rollback path

N-06: export one idempotency-key authority from mutation-intent.ts and use it
in the V2 client. A caller-supplied key is validated before credentials, timers
and fetch, and an invalid value is rejected as VALIDATION_REJECTED /
IDEMPOTENCY_KEY_INVALID rather than trimmed, regenerated or dropped, so a keyed
command can no longer replay while sending no key.

N-07: bound the legacy credential wait by the existing attempt controller,
which already carries the total deadline and the caller signal, so a
non-cooperative owner cannot hold the request open and no extra timer is
introduced. The owner receives the operation context, and the failure follows
ownership: deadline to REQUEST_TIMEOUT, caller to REQUEST_ABORTED, and only a
genuine rejection to AUTH_INTEGRATION_FAILURE. None of these paths fetch.

N-08: readBoundedJson delegates to the common bounded reader, so cancel and
releaseLock throws stay isolated inside the closed result, and the V2
content-type mismatch now cancels the response body.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
DongHyeonka
2026-08-13 23:46:03 +09:00
co-authored by Claude Opus 5
parent 4fe924ee0f
commit c9e820aed5
7 changed files with 356 additions and 63 deletions
@@ -77,9 +77,9 @@ Rollout state starts at `NOT_STARTED`; documented-unimplemented items start at
| N-03 | Live V3 path | `corepack pnpm exec vitest run tests/unit/http-execution-v3.test.ts -t "retry-time fence"` | `fix: preserve command effect certainty across retries` | `FIXED_NOT_RELEASED` | command effect verdict regression | Red reproduced `SCOPE_FENCED` with `NOT_STARTED` after one dispatched attempt → green `MAYBE_APPLIED`; lattice table 9/9; `check:types` PASS; `lint` PASS |
| N-04 | Live composition teardown | `corepack pnpm exec vitest run tests/unit/telemetry.test.ts tests/unit/runtime-adapters.test.ts` | `fix: terminate telemetry work on disposal` | `FIXED_NOT_RELEASED` | telemetry delivery loss after teardown change | Red 10 failed (5 lifecycle + 5 capacity) → green 34/34; `check:diagnostics` PASS; `check:types` PASS; `check:architecture` PASS; `lint` PASS |
| N-05 | Rollout blocker (sidecar not composed) | `corepack pnpm exec vitest run tests/unit/conditional-validator-store.test.ts` | `fix: harden bounded state sidecars` | `FIXED_NOT_RELEASED` | persisted validator key incompatibility | Red collision case (two valid bindings sharing one delimiter-joined key) → green; key is now a bounded validated tuple encoded with `JSON.stringify` |
| N-06 | Legacy V2 rollback seam | `corepack pnpm exec vitest run tests/integration/http-client.test.ts` | — | `NOT_STARTED` | legacy keyed command rejection spike | — |
| N-07 | Legacy V2 rollback seam | `corepack pnpm exec vitest run tests/integration/auth-recovery.test.ts` | — | `NOT_STARTED` | legacy credential timeout regression | — |
| N-08 | Legacy V2 rollback seam | `corepack pnpm exec vitest run tests/unit/bounded-json-compatibility.test.ts` | — | `NOT_STARTED` | legacy JSON failure-code drift | — |
| N-06 | Legacy V2 rollback seam | `corepack pnpm exec vitest run tests/integration/http-client.test.ts` | `fix: harden the legacy HTTP rollback path` | `FIXED_NOT_RELEASED` | legacy keyed command rejection spike | Red 4 invalid-key cases → green; rejection happens before credentials and fetch (0 credential calls, 0 fetches) |
| N-07 | Legacy V2 rollback seam | `corepack pnpm exec vitest run tests/integration/http-client.test.ts tests/integration/auth-recovery.test.ts` | `fix: harden the legacy HTTP rollback path` | `FIXED_NOT_RELEASED` | legacy credential timeout regression | Red never-settling owner → green; credential wait races the existing attempt controller so no extra timer is added; ownership maps to REQUEST_TIMEOUT / REQUEST_ABORTED / AUTH_INTEGRATION_FAILURE with zero fetches |
| N-08 | Legacy V2 rollback seam | `corepack pnpm exec vitest run tests/unit/bounded-json-compatibility.test.ts` | `fix: harden the legacy HTTP rollback path` | `FIXED_NOT_RELEASED` | legacy JSON failure-code drift | Green 7/7 including throwing cancel/releaseLock; `readBoundedJson` now delegates to `bounded-body-reader` with the legacy codes preserved |
| N-09 | Live cross-context host | `corepack pnpm exec vitest run tests/unit/cross-tab-invalidation.test.ts` | `fix: harden bounded state sidecars` | `FIXED_NOT_RELEASED` | cross-tab invalidation drop | Red foreign-area pulse accepted → green 13/13; localStorage captured once and `StorageEvent.storageArea` compared by object identity; pulse key registered as `CACHE_INVALIDATION_PULSE`; `check:registries` PASS |
| N-10 | Cursor runtime `AVAILABLE_NOT_COMPOSED` | `corepack pnpm exec vitest run tests/unit/cursor-pagination-runtime.test.ts` | `fix: harden bounded state sidecars` | `FIXED_NOT_RELEASED` | pagination abort semantics change | Red never-settling loader → green `PAGINATION_ABORTED` with the late page ignored |
| N-11 | Live composition | `corepack pnpm exec vitest run tests/unit/telemetry.test.ts -t capacity` | `fix: terminate telemetry work on disposal` | `FIXED_NOT_RELEASED` | capacity rejection on valid composition | Red 5/5 capacity cases → green; ceilings documented in VD-07 §7-4 |