diff --git a/docs/work/conformance-system-v1/04-ci-drift-gate/_story.md b/docs/work/conformance-system-v1/04-ci-drift-gate/_story.md new file mode 100644 index 0000000..03ba9c8 --- /dev/null +++ b/docs/work/conformance-system-v1/04-ci-drift-gate/_story.md @@ -0,0 +1,47 @@ +--- +id: 04-ci-drift-gate +epic: conformance-system-v1 +title: CI drift gate — pnpm conformance with cross-feature event closure +type: technical-story +status: in-progress +feature: scripts +depends-on: [03-b-ast-eslint-rules] +blocks: [05-generator-updates] +--- + +## Goal +`pnpm conformance` aggregates cross-feature checks that no single-file +ESLint rule can perform — most importantly, event closure: every event +declared in any manifest's `consumes` must have at least one matching +`publishes` somewhere in the repo. + +## Why +Per-file lint can't see cross-feature contracts. Without this gate, a +feature can declare it consumes `X` while no feature publishes `X` — +silent until the broken handler is exercised in prod. + +## Done when +- `pnpm conformance` exits 0 when manifests are consistent; non-zero + with a clear error message on orphan consumers +- Wired into `turbo.json` as the `conformance` task +- Wired into `.github/workflows/ci.yml` after `pnpm lint` + +## In scope +- `scripts/conformance.mjs` — orphan-consumer check +- Tests via vitest +- turbo.json + CI wiring + +## Out of scope +- Scaffold drift check (regenerate via `turbo gen feature`, diff against + on-disk state) — depends on generator updates landing +- Repository write outside use-cases check — separate concern +- Reverse check (orphan publishers — events nothing consumes) — many + events are intentionally "fire and forget"; not a closure violation + +## Tasks +- [ ] Story scaffold +- [ ] `scripts/conformance.mjs` implementation +- [ ] Tests for the script +- [ ] Wire into root package.json + turbo.json +- [ ] Wire into ci.yml +- [ ] Final verification + closeout