159 lines
11 KiB
Markdown
159 lines
11 KiB
Markdown
# HTTP Worker and Adapter Remediation Implementation Plan
|
||
|
||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||
|
||
**Goal:** Remove duplicate HTTP authorities, harden Service Worker activation bounds and identity, and decompose large browser adapters only after shared golden behavior is locked.
|
||
|
||
**Architecture:** Installed contract contributions are the HTTP source of truth and expose provider-neutral typed outcomes. Worker protocol V2 exchanges a canonical full-identity digest. Browser adapter facades remain stable while shared persisted schemas and cohesive internal modules are extracted.
|
||
|
||
**Tech Stack:** TypeScript 7, Fetch API, Service Worker API, IndexedDB, OPFS, React 19, Vitest 4, Playwright.
|
||
|
||
## Global Constraints
|
||
|
||
- Contract and application layers never import concrete adapter outcome types.
|
||
- Production exports accept only `BoundQuery` and `BoundMutation` after migration.
|
||
- Runtime timeout is a global ceiling applied over descriptor deadlines.
|
||
- Worker marker reads are bounded even without `Content-Length` and cancel oversized/non-terminating streams.
|
||
- Public adapter facades and product-default optional capability selection remain unchanged.
|
||
- Extraction follows characterization tests; file length alone does not justify a split.
|
||
|
||
---
|
||
|
||
### Task 1: Installed HTTP contract as single source of truth
|
||
|
||
**Files:**
|
||
- Modify: `src/features/reference-feature/contracts/reference-feature-contract.ts`
|
||
- Modify: `src/features/reference-feature/contracts/reference-schemas.ts`
|
||
- Modify: `src/contracts/external-contract-runtime.ts`
|
||
- Modify: `src/contracts/api-operations.ts`
|
||
- Modify: `src/contracts/rest-profiles.ts`
|
||
- Modify: `src/contracts/schema-registry.ts`
|
||
- Modify: `src/features/installed-feature-contracts.ts`
|
||
- Modify: `src/bootstrap/runtime-adapters.ts`
|
||
- Modify: `tests/features/reference-feature/reference-contract.test.ts`
|
||
- Modify: `tests/runtime-schema/http-schema.test.ts`
|
||
- Modify: `tests/integration/http-execution-contract.test.ts`
|
||
- Modify: `tests/unit/http-execution-v3.test.ts`
|
||
|
||
- [ ] Add parity tests showing method/path/validators/retry/effect/deadline/byte bounds come from one contribution; `createdAt` accepts omitted or RFC3339 datetime and rejects arbitrary strings.
|
||
- [ ] Run focused tests and confirm RED on duplicated descriptors and permissive date schema.
|
||
- [ ] Make the installed contribution authoritative; generate temporary legacy views from it and migrate all production callers before deleting the legacy registries/codecs.
|
||
- [ ] Apply `REQUEST_TIMEOUT_MS` as `min(runtimeCeiling, descriptorDeadline)` without replacing shorter descriptor deadlines.
|
||
- [ ] Keep the deadline authoritative through response admission and body reads: a deadline-owned abort after headers must still return `TRANSPORT_FAILURE / TIMEOUT`, perform one attempt, and never enter retry sleep instead of being masked as `RESPONSE_STREAM_FAILURE`.
|
||
- [ ] Treat credential resolution as a credential-only patch boundary: reject attempts to inject or overwrite `Idempotency-Key` (including case variants) or transport/query authority, and cover hostile patches in the executor regression table.
|
||
- [ ] Prove diagnostic privacy against the full runtime seam with non-empty identity references; assertions over an empty diagnostic projection do not count as evidence that intent/key/query identity is absent.
|
||
- [ ] Re-run focused tests, prove `rg` has zero production callers of removed registries, and commit with `git commit -m "refactor: consolidate installed HTTP contracts"`.
|
||
|
||
### Task 2: Provider-neutral typed operation outcomes
|
||
|
||
**Files:**
|
||
- Create: `src/contracts/operation-outcome.ts`
|
||
- Create: `src/application/ports/contract-operation-executor.ts`
|
||
- Modify: `src/features/reference-feature/adapters/reference-http-gateway.ts`
|
||
- Modify: `src/bootstrap/runtime-adapters.ts`
|
||
- Modify: `src/adapters/http/http-execution-v3.ts`
|
||
- Modify: `tests/features/reference-feature/reference-contract.test.ts`
|
||
- Modify: `tests/unit/runtime-adapters.test.ts`
|
||
|
||
- [ ] Add compile/runtime tests that unknown operation IDs and mismatched input/output types fail, and that the feature gateway has no import from `src/adapters/http`.
|
||
- [ ] Run focused tests/typecheck and confirm RED because the port is `operationId: string`, `input: unknown`, and concrete `HttpExecutionOutcome` leaks inward.
|
||
- [ ] Derive `InstalledOperationMap` from installed contracts, expose generic `execute<K extends keyof Map>(operationId: K, input: Map[K]["input"], context)` and map HTTP outcomes to provider-neutral contract outcomes at the adapter boundary.
|
||
- [ ] Re-run tests, typecheck, and architecture; commit with `git commit -m "refactor: type installed contract operations"`.
|
||
|
||
### Task 3: Bound-only server-state exports
|
||
|
||
**Files:**
|
||
- Modify: `src/presentation/adapters/query/application-query.ts`
|
||
- Modify: `src/presentation/adapters/query/index.ts`
|
||
- Modify: `src/features/reference-feature/presentation/use-reference-feature.ts`
|
||
- Create: `tests/helpers/legacy-application-query-harness.tsx`
|
||
- Modify: `tests/component/application-query.test.tsx`
|
||
|
||
- [ ] Add type tests that production hooks reject raw query keys and raw mutation executors while bound definitions still compile.
|
||
- [ ] Run typecheck and confirm current overloads accept raw forms.
|
||
- [ ] Move legacy raw harness behavior under `tests/helpers`; remove `LegacyMutationOptions` and the raw query union from production exports; migrate feature callers to `bindQuery`/bound mutations.
|
||
- [ ] Run focused component tests and typecheck; commit with `git commit -m "refactor: expose bound server-state hooks only"`.
|
||
|
||
### Task 4: Bounded Service Worker marker reader
|
||
|
||
**Files:**
|
||
- Create: `src/adapters/service-worker/bounded-worker-response.ts`
|
||
- Modify: `src/adapters/service-worker/service-worker-lifecycle.ts`
|
||
- Modify: `tests/unit/service-worker-runtime.test.ts`
|
||
|
||
- [ ] Add tests for oversized declared length, headerless oversized chunks, invalid UTF-8, malformed JSON, and a non-terminating stream. Assert reader cancellation and bounded completion.
|
||
- [ ] Run `corepack pnpm exec vitest run tests/unit/service-worker-runtime.test.ts` and confirm RED because lifecycle calls `response.text()`.
|
||
- [ ] Implement realm-safe stream reads up to `maxBytes + 1`, fatal `TextDecoder`, explicit cancellation, and strict marker parsing. Never call `Response.text()` for protocol data.
|
||
- [ ] Re-run tests and commit with `git commit -m "fix: bound Service Worker activation markers"`.
|
||
|
||
### Task 5: Service Worker protocol V2 full identity
|
||
|
||
**Files:**
|
||
- Modify: `src/contracts/service-worker.ts`
|
||
- Modify: `src/adapters/service-worker/service-worker-protocol.ts`
|
||
- Modify: `src/adapters/service-worker/service-worker-entry.ts`
|
||
- Modify: `src/adapters/service-worker/service-worker-lifecycle.ts`
|
||
- Modify: `src/adapters/service-worker/service-worker-page-controller.ts`
|
||
- Modify: `src/bootstrap/register-service-worker.ts`
|
||
- Modify: `scripts/generate-build-manifest.ts`
|
||
- Modify: `tests/unit/service-worker-runtime.test.ts`
|
||
- Modify: `tests/unit/service-worker-build-input.test.ts`
|
||
|
||
- [ ] Add a tuple-mutation table for protocol/cache schema/build/release/contract/static set; each mutation must change the digest and reject activation. Add a valid ACTIVE fixture build that recomputes static set digest from asset entries.
|
||
- [ ] Run focused tests and confirm RED because protocol V1 compares partial fields.
|
||
- [ ] Set `SERVICE_WORKER_PROTOCOL_VERSION = 2`, define canonical sorted identity serialization, compute SHA-256 over every identity field, and exchange/validate the digest on every page-worker message.
|
||
- [ ] Keep default capability selection `null`; use ACTIVE only in the explicit fixture build.
|
||
- [ ] Re-run focused tests and the supported fixture build; commit with `git commit -m "fix: bind Service Worker activation to full identity"`.
|
||
|
||
### Task 6: Shared IndexedDB persisted-row schema
|
||
|
||
**Files:**
|
||
- Create: `src/adapters/storage/indexeddb/indexeddb-persisted-schema.ts`
|
||
- Modify: `src/adapters/storage/indexeddb/indexeddb-types.ts`
|
||
- Modify: `src/adapters/storage/indexeddb/indexeddb-runtime.ts`
|
||
- Modify: `src/adapters/storage/indexeddb/indexeddb-maintenance.ts`
|
||
- Create: `tests/fixtures/indexeddb/persisted-rows.ts`
|
||
- Modify: `tests/unit/indexeddb-runtime.test.ts`
|
||
- Modify: `tests/unit/indexeddb-maintenance.test.ts`
|
||
|
||
- [ ] Before extraction, run the same accepted/rejected record, receipt, retention, and budget golden rows through runtime and maintenance and assert identical verdicts.
|
||
- [ ] Confirm RED on at least one drift fixture using the duplicate current guards.
|
||
- [ ] Move persisted types/guards into the shared module; runtime and maintenance import it without behavior changes.
|
||
- [ ] Re-run both large suites and commit with `git commit -m "refactor: share IndexedDB persisted schemas"`.
|
||
|
||
### Task 7: Cohesive browser adapter decomposition
|
||
|
||
**Files:**
|
||
- Modify: `src/adapters/storage/opfs/opfs-worker-runtime.ts`
|
||
- Create: `src/adapters/storage/opfs/opfs-worker-bootstrap.ts`
|
||
- Create: `src/adapters/storage/opfs/opfs-worker-message-host.ts`
|
||
- Create: `src/adapters/storage/opfs/opfs-worker-core.ts`
|
||
- Create: `src/adapters/storage/opfs/opfs-worker-lock.ts`
|
||
- Create: `src/adapters/storage/opfs/opfs-physical-io.ts`
|
||
- Modify: `src/adapters/cache-storage/public-response-cache-adapter.ts`
|
||
- Create: `src/adapters/cache-storage/public-cache-manifest.ts`
|
||
- Create: `src/adapters/cache-storage/cache-lock.ts`
|
||
- Modify: `src/adapters/browser-files/download-delivery-adapter.ts`
|
||
- Create: `src/adapters/browser-files/download-browser-managed.ts`
|
||
- Create: `src/adapters/browser-files/download-picker-stream.ts`
|
||
- Create: `src/adapters/browser-files/download-object-url.ts`
|
||
- Modify: `tests/unit/opfs-worker-runtime.test.ts`
|
||
- Modify: `tests/unit/public-response-cache.test.ts`
|
||
- Modify: `tests/unit/browser-file-download.test.ts`
|
||
|
||
- [ ] Add golden facade tests for all success/failure/cancellation/lock-loss branches before moving code; snapshot externally observable operation order and error kinds.
|
||
- [ ] Run the three focused suites and capture GREEN characterization evidence.
|
||
- [ ] Extract OPFS bootstrap, host, core state machine, Web Lock, and physical I/O without changing public exports. Do not split the core state machine further.
|
||
- [ ] Extract public-cache manifest codec/digest and generic lock logic behind the same facade.
|
||
- [ ] Extract browser-managed, picker streaming, and object-URL download strategies behind the same delivery facade.
|
||
- [ ] Re-run the same golden suites after each extraction. Any failure is a refactor regression, not a fixture update.
|
||
- [ ] Commit each adapter independently with `refactor: decompose OPFS worker adapter`, `refactor: extract public cache internals`, and `refactor: extract download delivery strategies`.
|
||
|
||
### Task 8: HTTP/worker/adapter verification
|
||
|
||
- [ ] Run all focused tests named in Tasks 1–7.
|
||
- [ ] Run `corepack pnpm check:architecture`, `corepack pnpm check:types`, and `corepack pnpm lint`.
|
||
- [ ] Run `corepack pnpm test:all`.
|
||
- [ ] Run supported Service Worker, IndexedDB, OPFS, public-cache, and download Playwright capability specs.
|
||
- [ ] Run `git diff --check` and report unsupported browser gates without claiming success.
|