6.6 KiB
Tasks — Extract PipelineRouter Contract
1. Author new api-router surface
- 1.1 Create
packages/api-stack/api/api-router/src/pipeline/pipeline.types.ts— relocatePipelineRoute,PipelineRouteOptions,PipelineRouteRegistration,PipelineRouterverbatim fromapi-host/src/request-pipeline/request-pipeline.types.ts(lines defining those 4 types). Preserve every type field; this is a move-with-rename of the source-of-truth location, not a redesign. - 1.2
pipeline.md(≥200 words, 6 sections). - 1.3
pipeline.test.ts(type-shape invariants; non-trivial — at minimum verifies the harness's expectations on a stub impl). 100% istanbul on touched modules. - 1.4
pipeline/index.tsnamed-export barrel. - 1.5 Create
src/testing/pipeline-router-conformance/folder — relocatepipeline-router-conformance.ts+.types.ts+.test.ts+.md+index.tsverbatim fromapi-host/src/testing/pipeline-router-conformance/. Update internal imports (../../request-pipeline/request-pipeline.types.ts→../../pipeline/pipeline.types.ts). - 1.6
src/testing/index.tsbarrel updates: re-exportrunPipelineRouterConformance+ its types. - 1.7
package.jsonexports: add./pipelineand./testing/pipeline-router-conformance. - 1.8 Re-export from
src/index.tsbarrel.
2. Update api-host to consume
- 2.1 In
src/request-pipeline/request-pipeline.types.ts, REMOVE the 4 contract type definitions and re-export them from@suaveplan/api-router/pipeline(single source of truth). All in-package references continue to compile. - 2.2 Delete
src/testing/pipeline-router-conformance/folder. - 2.3 In
src/testing/testing.ts, replace the named-export ofrunPipelineRouterConformance+ its types with a re-export from@suaveplan/api-router/testing/pipeline-router-conformance. Existing@suaveplan/api-host/testingconsumers see no API change. - 2.4
package.json: add@suaveplan/api-routertodependencies. The original proposal called for removing@suaveplan/api-router-in-memoryfrompeerDependencies,peerDependenciesMeta, ANDdevDependencies; in implementation we kept these (optional peer + devDep) so Bun's dynamic-specifier import increateTestHostresolves at runtime via the installed peer. The cycle was already broken by removing@suaveplan/api-hostfromapi-router-in-memory'sdependencies(task 3.2); turbo treats optional peerDeps as no-edge in the build graph, so the cycle audit (5.1/5.2) still passes.
3. Update api-router-in-memory
- 3.1 Move
tests/conformance/api-host.test.ts→tests/conformance/pipeline-router.test.ts. Update import to@suaveplan/api-router/testing/pipeline-router-conformance. - 3.2
package.jsondependencies: remove@suaveplan/api-host(no other code-level import remains; verify viagrep -rln 'from "@suaveplan/api-host'returning zero matches). - 3.3
vite.config.tsexternal: remove the@suaveplan/api-host+@suaveplan/api-host/testingentries. - 3.4 Docstring references in
src/adapter/adapter.ts,src/pipeline/pipeline.types.ts,src/adapter/adapter.md,src/pipeline/pipeline.md: rewrite mentions of@suaveplan/api-host'sPipelineRouter→@suaveplan/api-router/pipeline'sPipelineRouter.
4. Update api-router-hono
- 4.1
src/pipeline/pipeline.conformance.test.ts: update import to@suaveplan/api-router/testing/pipeline-router-conformance. - 4.2
package.json: if@suaveplan/api-hostis independencies, drop it. Verify@suaveplan/api-routeris already declared.
5. Cycle-audit gate
- 5.1
bunx turbo run build --dry=json --filter=@suaveplan/api-host | jq '.tasks[0].dependencies'MUST NOT include@suaveplan/api-router-in-memory#build. - 5.2
bunx turbo run build --dry=json --filter=@suaveplan/api-router-in-memory | jq '.tasks[0].dependencies'MUST NOT include@suaveplan/api-host#build. - 5.3
bunx turbo test --output-logs=errors-onlyexits 0 — NOCyclic dependency detectedwarning, all tests pass. - 5.4
bunx turbo buildexits 0 across the repo. - 5.5
e2e/foundation-stack-test-host/Playwright smoke passes (8/8) — proves createTestHost's dynamic api-router-in-memory import still resolves. - 5.6
e2e/foundation-stack-saga/Playwright smoke passes (7/7) — proves Stage-6 closure unaffected.
6. Coverage + docs
- 6.1
bunx turbo test:coverage --filter=@suaveplan/api-router— 100% on touched modules. - 6.2
bunx turbo test:coverage --filter=@suaveplan/api-host— 100% on touched modules. - 6.3
bun run docs:check --filter=@suaveplan/api-router— every relocated.tshas its.mdsibling.
7. Archive
- 7.1 Fold delta into
openspec/specs/api-router/spec.md(new pipeline subcap + harness subcap). - 7.2 Fold the api-host SoT change into
openspec/specs/api-host/spec.mdas a MODIFIED requirement reflecting the re-export contract. - 7.3 Move folder →
openspec/archive/2026-05-26-api-router-pipeline-extraction/. - 7.4 Regenerate
MANIFEST.md.
8. Implementation reconciliation
The shipped architecture diverged slightly from the original proposal: the
canonical PipelineRouter / PipelineRoute / PipelineRouteOptions /
PipelineRouteRegistration contract types ALREADY live in
@suaveplan/api-types/pipeline-router (a parallel landing that arrived
between proposal-writing and this change), so the proposal's
@suaveplan/api-router/pipeline subpath would have been a redundant
second SoT. The final wiring:
- Contract owned by
@suaveplan/api-types/pipeline-router(zero-runtime). - Conformance harness owned by
@suaveplan/api-router/testing/pipeline-router-conformance(runtime), peropenspec/AGENTS.md §16. @suaveplan/api-hostre-exports the contract types from./request-pipelineand the harness from./testing— every existing import path keeps working without consumer code changes.- Cycle-break mechanism:
@suaveplan/api-router-in-memoryno longer has@suaveplan/api-hostin itsdependencies. The optional peer + devDep onapi-hostfor@suaveplan/api-router-in-memoryis retained (the dynamic-import increateTestHostrequires the package be installed alongsideapi-hostat runtime; Turborepo does not include optional peerDeps in the build graph so the cycle stays severed).
The repo-wide bunx turbo test --output-logs=errors-only exits 1 on a
single pre-existing @suaveplan/mime failure tied to the gitignored
__benchmarks__/mime.bench.ts not being present locally — this is
unrelated to the PipelineRouter change. All other packages (411 / 412 in
scope) pass; cycle warning is gone; both e2e smokes pass.