build: run doc-sync gates in the local pre-push hook too
The doc-sync gates were CI-only, so the AGENTS.md doc-sync promise could be missed locally until after push. Add a shared `doc-sync` package.json script (doc-typecheck + verify-event-taxonomy) wired into the lefthook pre-push job, and point the CI step at the same script — one source of truth per ADR 0007. Addresses PR review finding.
This commit is contained in:
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
@@ -46,9 +46,10 @@ jobs:
|
|||||||
# Doc-sync gates (RFC 006). doc-typecheck compiles the fenced ts blocks in
|
# Doc-sync gates (RFC 006). doc-typecheck compiles the fenced ts blocks in
|
||||||
# the docs and resolves vendor packages via their built declarations, which
|
# the docs and resolves vendor packages via their built declarations, which
|
||||||
# the typecheck step above emits — so it runs after typecheck. The event
|
# the typecheck step above emits — so it runs after typecheck. The event
|
||||||
# taxonomy check only reads source.
|
# taxonomy check only reads source. Same `doc-sync` script the pre-push
|
||||||
|
# hook runs (ADR 0007: one source of truth).
|
||||||
- name: Doc-sync gates (doc code blocks + event taxonomy)
|
- name: Doc-sync gates (doc code blocks + event taxonomy)
|
||||||
run: yarn doc-typecheck && yarn verify-event-taxonomy
|
run: yarn doc-sync
|
||||||
|
|
||||||
- name: Tests with coverage gate (per-file 100%)
|
- name: Tests with coverage gate (per-file 100%)
|
||||||
run: yarn test:coverage
|
run: yarn test:coverage
|
||||||
|
|||||||
@@ -8,16 +8,16 @@ AGENTS.md promises that docs and code stay strictly in sync, but the promise was
|
|||||||
|
|
||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
Two CI gates, mirroring the existing `scripts/` style (tsx ESM, one job each):
|
Two gates, mirroring the existing `scripts/` style (tsx ESM, one job each):
|
||||||
|
|
||||||
1. **`doc-typecheck`** extracts every fenced ` ```ts ` block from `README.md`, `docs/**`, and `packages/*/README.md`, writes them to a temp project, and compiles with `tsc --noEmit`. The temp tsconfig copies only resolution-relevant options and the workspace `paths` map from `tsconfig.typecheck.json` (vendor → built `lib`, harness → `src`) — resolving vendor to `lib` is essential, or tsc type-checks raw vendor source and floods the run. A block that is a deliberate sketch opts out with an explicit ` ```ts ignore-check ` info string; the script reports the opt-out ratio and fails if it exceeds half, so the escape hatch can't quietly become the norm.
|
1. **`doc-typecheck`** extracts every fenced ` ```ts ` block from `README.md`, `docs/**`, and `packages/*/README.md`, writes them to a temp project, and compiles with `tsc --noEmit`. The temp tsconfig copies only resolution-relevant options and the workspace `paths` map from `tsconfig.typecheck.json` (vendor → built `lib`, harness → `src`) — resolving vendor to `lib` is essential, or tsc type-checks raw vendor source and floods the run. A block that is a deliberate sketch opts out with an explicit ` ```ts ignore-check ` info string; the script reports the opt-out ratio and fails if it exceeds half, so the escape hatch can't quietly become the norm.
|
||||||
2. **`verify-event-taxonomy`** extracts the event names from the `interface Events` blocks across `packages/*/src` and from the taxonomy table in `docs/architecture.md`, and asserts the two sets match exactly. Verify, don't generate: the table keeps its hand-written Mode/Purpose columns; only the set of names is checked. (Landing this surfaced three events the table had been missing — `tools/change`, `llm/adapter-change`, `system-prompt/change`.)
|
2. **`verify-event-taxonomy`** extracts the event names from the `interface Events` blocks across `packages/*/src` and from the taxonomy table in `docs/architecture.md`, and asserts the two sets match exactly. Verify, don't generate: the table keeps its hand-written Mode/Purpose columns; only the set of names is checked. (Landing this surfaced three events the table had been missing — `tools/change`, `llm/adapter-change`, `system-prompt/change`.)
|
||||||
|
|
||||||
Both run in CI after `yarn typecheck` (which emits the vendor `lib/` that doc-typecheck resolves against). API-extractor golden reports (RFC 006 part 3) were deliberately **deferred** — low value for an internal monorepo where reviewers already see the source diff, and a heavy, finicky dependency.
|
Both run via a shared `doc-sync` package.json script that the lefthook pre-push hook and CI both invoke (ADR 0007: hooks and CI call the same scripts, so the gate fires locally before a push — not only after it). They run after `yarn typecheck` (which emits the vendor `lib/` that doc-typecheck resolves against). API-extractor golden reports (RFC 006 part 3) were deliberately **deferred** — low value for an internal monorepo where reviewers already see the source diff, and a heavy, finicky dependency.
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
- Doc drift in the two checkable classes now fails CI instead of waiting for a reviewer to notice. This is an instance of ADR 0007's "mechanical gates over prose."
|
- Doc drift in the two checkable classes now fails the pre-push hook and CI instead of waiting for a reviewer to notice. This is an instance of ADR 0007's "mechanical gates over prose."
|
||||||
- Making doc snippets compile costs a few stub imports/`declare`s; the `ignore-check` ratio must stay low or the gate is theater (the ratio guard enforces this).
|
- Making doc snippets compile costs a few stub imports/`declare`s; the `ignore-check` ratio must stay low or the gate is theater (the ratio guard enforces this).
|
||||||
- The taxonomy check is name-only — a wrong Mode or Purpose column still needs human review. Generating the table from source was considered and rejected as more machinery than the problem warrants.
|
- The taxonomy check is name-only — a wrong Mode or Purpose column still needs human review. Generating the table from source was considered and rejected as more machinery than the problem warrants.
|
||||||
- API reports remain available to revisit if the packages are ever published externally.
|
- API reports remain available to revisit if the packages are ever published externally.
|
||||||
|
|||||||
@@ -27,3 +27,6 @@ pre-push:
|
|||||||
|
|
||||||
- name: hygiene
|
- name: hygiene
|
||||||
run: yarn hygiene
|
run: yarn hygiene
|
||||||
|
|
||||||
|
- name: doc-sync
|
||||||
|
run: yarn doc-sync
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"publint": "tsx scripts/publint-all.ts",
|
"publint": "tsx scripts/publint-all.ts",
|
||||||
"doc-typecheck": "tsx scripts/doc-typecheck.ts",
|
"doc-typecheck": "tsx scripts/doc-typecheck.ts",
|
||||||
"verify-event-taxonomy": "tsx scripts/verify-event-taxonomy.ts",
|
"verify-event-taxonomy": "tsx scripts/verify-event-taxonomy.ts",
|
||||||
|
"doc-sync": "yarn doc-typecheck && yarn verify-event-taxonomy",
|
||||||
"hygiene": "yarn knip && yarn publint && yarn constraints",
|
"hygiene": "yarn knip && yarn publint && yarn constraints",
|
||||||
"demo:echo": "node --expose-internals --import tsx examples/echo-agent/start.ts",
|
"demo:echo": "node --expose-internals --import tsx examples/echo-agent/start.ts",
|
||||||
"demo:coding": "node --expose-internals --import tsx examples/coding-agent/start.ts",
|
"demo:coding": "node --expose-internals --import tsx examples/coding-agent/start.ts",
|
||||||
|
|||||||
Reference in New Issue
Block a user