# foundation-fix-gap-1-pipeline-router ## Summary Close foundation-coherence Gap #1: `@suaveplan/api-router-hono`'s `HonoRouter` did not satisfy `@suaveplan/api-host`'s `PipelineRouter` contract. The two `match()` shapes diverged (`RouteMatch` vs `PipelineRoute`), forcing every host-pipeline consumer to hand-roll a shim — the E2E `foundation-stack` server's `createFixtureRouter()` was the canonical example. This change adds a second, additive facet to `HonoRouter` (`registerPipelineRoute` / `matchPipeline` / `unregisterPipelinePlugin` / `listPipelineRoutes`) that produces values structurally assignable to the host's `PipelineRoute` interface, and ships a canonical `runPipelineRouterConformance(factory)` test harness in `@suaveplan/api-host/testing` so every concrete adapter has a single contract to pass. ## Motivation Empirically the gap caused two failure modes: 1. **Hand-rolled shims** in every consumer — the E2E `foundation-stack` server's `createFixtureRouter()` was 80 lines of router logic that should have lived inside `api-router-hono`. Every new host-pipeline consumer was on track to write the same shim. 2. **No conformance suite** — `api-router-hono` passes `runRouterConformance` against the abstract `Router`, but no harness existed for the host's `PipelineRouter` surface. Adapter drift would only surface during a real E2E run. The fix is additive — the existing abstract-`Router` surface is preserved verbatim; the pipeline facet lives next to it as a parallel metadata sidecar. No breaking changes to existing consumers. ## Scope - `@suaveplan/api-router-hono`: - new `src/pipeline/` feature module (`PipelineRouteTable`, `HonoPipelineRoute`, `HonoPipelineRegistration`, `HonoPipelineRouteOptions`, `HonoPipelineHandler`). - `HonoRouter` gains `registerPipelineRoute`, `unregisterPipelineRoute`, `unregisterPipelinePlugin`, `listPipelineRoutes`, `matchPipeline`. - new error code `ROUTER_HONO.PIPELINE_ROUTE_COLLISION`. - new subpath export `./pipeline`. - dev-dep on `@suaveplan/api-host` (testing-only). - vite config emits `index.js` per subpath (closes a pre-existing `./adapter` resolution bug). - `@suaveplan/api-host`: - `./testing` subpath populated with `runPipelineRouterConformance(factory)` + `PipelineRouterConformanceFactory` / `PipelineRouteRegistration` types. - vite config switched to multi-entry so the dist actually emits `testing/testing.js` (closes a pre-existing dead-export bug). - `e2e/foundation-stack`: - drop hand-rolled `createFixtureRouter` body; replace with the real `HonoRouter` pipeline facet. ## Verification - Unit + integration: `bunx turbo lint typecheck test build --filter=@suaveplan/api-router-hono --filter=@suaveplan/api-host` → green; 75 unit tests across `api-router-hono`, 252 across `api-host`. - Coverage: `api-router-hono` 100/100/100/100 on every touched module (`adapter`, `pipeline`, `error-codes`). - E2E: `cd e2e/foundation-stack && bunx playwright test` — all 10 test groups pass (`livez`/`readyz`, plugin routes, tenant resolver, domain error envelope, 404 envelope, secrets, admin plugins/details, admin capabilities, rate-limit, idempotency). ## Out of scope - Migrating `api-router-worker-bridge` to the pipeline facet — that adapter will adopt the same harness in a follow-up. - Wiring the `HonoRouter` pipeline facet into the host's `LifecycleDriver.mount-routes` op — currently consumers register manually; threading through the lifecycle is a follow-up change.