Commit 8f9689f
authored
For a metadata-driven platform the third-party API is WHAT AN AUTHOR MAY WRITE:
the keys inside each schema. Nothing guarded them.
Both existing witnesses watch the TypeScript surface instead. `api-surface.json`
records exported `name (kind)`, and a key inside a schema is not an export.
`api-surface-signatures.json` hashes each `defineX` factory's type — but via
`checker.typeToString()`, which prints a type REFERENCE (`z.input<typeof
ActionSchema>`) and never expands it, so member-level narrowing cannot reach the
hash. `spec-changes.json` inherits the blind spot: its added/removed arrays are a
diff of `api-surface.json`.
Verified concretely: #3883 narrowed `defineAction`'s input by three keys and the
signature snapshot did not move. And #3733 was the ACCIDENTAL version —
`dataQuality` / `cached` outlived their keys, stayed discoverable in the
reference docs, and were silently stripped on parse. ADR-0059 §5 deferred a
deeper gate "until a narrowing actually slips both". It has, twice.
`content/docs/protocol/backward-compatibility.mdx` had meanwhile been promising
third parties the exact rule nothing enforced: "removing or renaming properties
is a MAJOR change".
`authorable-surface.json` ratchets all 8588 authorable keys, derived from the
walk that already emits the JSON Schemas — one level deeper, no new
introspection. Three states, distinguishable for free because a tombstoned key
(`retiredKey()`, #3883) is `z.never()`, which Zod renders as `{ "not": {} }`:
live, [RETIRED], absent.
Three failure modes now fail the build, each verified non-vacuous by simulation
rather than assumed — the whole point being that a gate can look present and be
dead:
1. A key vanishes with no tombstone. These schemas are not `.strict()`, so Zod
silently strips an unknown key: clean parse, setting never takes effect. The
error spells out the retirement protocol.
2. A key is tombstoned with no registered migration. Audible to whoever hits
it, but the change documentation is still empty. Requires a D2 conversion /
D3 chain entry naming the surface — mechanizing what #3883 did by hand with
nothing to enforce it.
3. An addition is left uncommitted (`--check`). An unrecorded key is invisible
to the ratchet forever after, since it can only detect the disappearance of
something it once saw.
Failures exit before the snapshot write, so a red run never clobbers the
baseline.
Runs in `check:docs` (unconditional, required — the job whose own comment says
the gate cannot go dormant) and as an explicit step in Check Generated Artifacts,
with the paths filter widened in lockstep per that filter's own stated rule.
Value-level narrowing (an enum losing a member) stays ungated per ADR-0059 §5's
evidence gate; noise kills a ratchet faster than a gap does. What is fixed is the
over-promise: `build-api-surface.ts` advertised its signature snapshot as
answering "did the accepted authoring shape narrow?" — it does not, and believing
it did is what let this gap sit.
1 parent 9ea2bc5 commit 8f9689f
6 files changed
Lines changed: 8844 additions & 5 deletions
File tree
- .changeset
- .github/workflows
- packages/spec
- scripts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
65 | 71 | | |
66 | 72 | | |
67 | 73 | | |
| |||
558 | 564 | | |
559 | 565 | | |
560 | 566 | | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
0 commit comments