3.8 KiB
Capability Spec Delta: api-router — PipelineRouter contract ownership
Package: @suaveplan/api-router
Status: PROPOSED
ADDED Requirements
Requirement: Owns the canonical PipelineRouter contract
@suaveplan/api-router SHALL export the canonical PipelineRouter interface and its companion types (PipelineRoute, PipelineRouteOptions, PipelineRouteRegistration) from the ./pipeline subpath. Every concrete pipeline-router adapter (api-router-in-memory, the HonoRouter pipeline facet in api-router-hono, future Stage-7 engines) targets this contract. @suaveplan/api-host MUST consume these types via @suaveplan/api-router/pipeline rather than define them locally.
Scenario: subpath exports the four contract types
- WHEN
import type { PipelineRoute, PipelineRouteOptions, PipelineRouteRegistration, PipelineRouter } from "@suaveplan/api-router/pipeline"is used - THEN all four symbols resolve AND match the prior shapes hosted in
@suaveplan/api-host/request-pipeline
Scenario: api-host re-exports preserve back-compat
- WHEN existing code uses
import { PipelineRouter } from "@suaveplan/api-host/request-pipeline" - THEN the symbol resolves to the same type identity as the new canonical location (verified by structural assignment in a type-level test)
Verified by: src/pipeline/pipeline.test.ts::"PipelineRouter contract exports the canonical surface" AND packages/api-stack/api/api-host/src/request-pipeline/request-pipeline.test.ts::"PipelineRouter re-export matches api-router source-of-truth"
Requirement: Ships the canonical runPipelineRouterConformance harness
@suaveplan/api-router SHALL export runPipelineRouterConformance({ label, build }) from ./testing/pipeline-router-conformance and re-export it through ./testing for ergonomic single-subpath consumption. The harness's invariants — route-match, plugin-ownership-preserved-across-reload, status-map propagation, missing-route returns null — MUST be preserved verbatim from the previous @suaveplan/api-host/testing location.
Scenario: harness invariants unchanged from the api-host source location
- WHEN an adapter that previously passed
runPipelineRouterConformancefrom@suaveplan/api-host/testingre-targets the harness at@suaveplan/api-router/testing/pipeline-router-conformance - THEN the same scenarios pass with no signature or behaviour change
Scenario: ergonomic ./testing re-export
- WHEN
import { runPipelineRouterConformance } from "@suaveplan/api-router/testing"is used - THEN the symbol resolves AND matches the dedicated-subpath export by identity
Verified by: src/testing/pipeline-router-conformance/pipeline-router-conformance.test.ts::"invariants match prior api-host location" AND src/testing/index.test.ts::"./testing re-exports runPipelineRouterConformance"
Requirement: Cycle-free build graph
After this change, the workspace build graph MUST NOT contain a cycle between @suaveplan/api-host and @suaveplan/api-router-in-memory. Turborepo's bunx turbo run build MUST complete without emitting Cyclic dependency detected.
Scenario: turbo schedules build with no cycle warning
- WHEN
bunx turbo run build --filter=@suaveplan/api-hostis run from a clean tree - THEN stderr contains no
Cyclic dependency detectedline AND the task graph builds successfully
Scenario: repo-wide test gate runs end-to-end
- WHEN
bunx turbo test --output-logs=errors-onlyis run - THEN the exit code is 0 AND no package reports a cycle warning
Verified by: CI assertion in bun scripts/lint/check-no-cycles.ts (new; greps bunx turbo run build --dry=json for any task whose dependencies form a cycle) AND the green-bar evidence captured in the change's archive tasks.md