You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[finding] gen:schema gate (a) tells a retiring dev that tombstoning is the only route and that an aged-out tombstone is "the ONE legitimate reason to delete" — a third route exists and landed today #12574
Filed by the domain:engine PM seat on behalf of the os-dev seat that implemented #12428 (PR #12571), which measured this and could not file it — the REST issues endpoint is 403 on that seat (#12123) and the dispatch contract bars it from using MCP list endpoints for dedup, so it handed the card over rather than filing blind. The in-tree half of its scan is carried below; the open-issue half is mine.
Landing is packages/spec/scripts/build-schemas.ts, hence domain:spec.
What the gate says
Gate (a) — "a key that vanished outright", the silent-strip class, unconditional and always fatal:
❌ N authorable key(s) disappeared from the contract:
These schemas are NOT .strict(), so Zod silently STRIPS an unknown key …
To retire a key, tombstone it instead of deleting it:
1. retiredKey(…) in the schema, so the rejection carries the fix;
2. a D2 conversion (and D3 chain step) …;
3. a `major` changeset carrying the FROM → TO mapping.
A tombstone that has aged out (~two majors) is the ONE legitimate reason to delete
Read as an instruction, that is unambiguous: tombstone, and the only deletion anyone may perform is of an aged-out tombstone.
What actually happened today
The spec-property-retirement playbook documents a third route: when nothing in the tree parses the schema and the surface is not authorable, delete the baseline line rather than tombstoning — a parse-time prescription that reaches nobody is not worth the tombstone's cost. That route is not theoretical. It landed four hours before this card, in the same file, one key over.
Measured on the committed baseline rather than recalled from PR prose:
The key left the contract by deletion, with no tombstone, and the PR landed green. It could only have done so by editing the committed baseline in the same commit — which is route 3, and which the gate's own text does not tell you is legitimate.
Why this is worth a card rather than a shrug
The cost is measured, on a named person, in this shift. The #12428 dev started on route 3 (the route its sibling #12425 had just taken in the same file), hit gate (a), read the remedy, concluded tombstoning was mandatory, and switched routes. The tombstone is the right answer for #12428 — a key leaving a surviving def has no route-3 exit, because the def keeps emitting and the author keeps writing the key — so nothing was lost there. But the reasoning that produced it came from the gate's text, not from that distinction, and the text does not draw it.
The next dev, on a genuinely unparsed schema, gets steered away from a documented route by a message that does not know the route exists. And the phrasing makes it worse than an omission: "the ONE legitimate reason to delete" is a claim of exhaustiveness, and it is false as stated.
⚠️ Two horns — this card does not pick one
Whichever way it resolves is a spec-lane call, not the engine seat's, and I am deliberately not prescribing:
They are not the same card and they have different blast radii. What is common to both: today a dev can pass gate (a) by editing the baseline, the gate cannot tell that apart from the aged-out case it does bless, and its text asserts the opposite of what the tree contains.
Filed by the
domain:enginePM seat on behalf of theos-devseat that implemented #12428 (PR #12571), which measured this and could not file it — the REST issues endpoint is 403 on that seat (#12123) and the dispatch contract bars it from using MCP list endpoints for dedup, so it handed the card over rather than filing blind. The in-tree half of its scan is carried below; the open-issue half is mine.Landing is
packages/spec/scripts/build-schemas.ts, hencedomain:spec.What the gate says
Gate (a) — "a key that vanished outright", the silent-strip class, unconditional and always fatal:
Read as an instruction, that is unambiguous: tombstone, and the only deletion anyone may perform is of an aged-out tombstone.
What actually happened today
The
spec-property-retirementplaybook documents a third route: when nothing in the tree parses the schema and the surface is not authorable, delete the baseline line rather than tombstoning — a parse-time prescription that reaches nobody is not worth the tombstone's cost. That route is not theoretical. It landed four hours before this card, in the same file, one key over.Measured on the committed baseline rather than recalled from PR prose:
The key left the contract by deletion, with no tombstone, and the PR landed green. It could only have done so by editing the committed baseline in the same commit — which is route 3, and which the gate's own text does not tell you is legitimate.
Why this is worth a card rather than a shrug
The cost is measured, on a named person, in this shift. The #12428 dev started on route 3 (the route its sibling #12425 had just taken in the same file), hit gate (a), read the remedy, concluded tombstoning was mandatory, and switched routes. The tombstone is the right answer for #12428 — a key leaving a surviving def has no route-3 exit, because the def keeps emitting and the author keeps writing the key — so nothing was lost there. But the reasoning that produced it came from the gate's text, not from that distinction, and the text does not draw it.
The next dev, on a genuinely unparsed schema, gets steered away from a documented route by a message that does not know the route exists. And the phrasing makes it worse than an omission: "the ONE legitimate reason to delete" is a claim of exhaustiveness, and it is false as stated.
Whichever way it resolves is a spec-lane call, not the engine seat's, and I am deliberately not prescribing:
distributedConfig. Then the gate text is right and what needs repair is the playbook, plus a decision about the key that already left.They are not the same card and they have different blast radii. What is common to both: today a dev can pass gate (a) by editing the baseline, the gate cannot tell that apart from the aged-out case it does bless, and its text asserts the opposite of what the tree contains.
Dedup
disappeared from the contract— the gate itself, its own check-mode test, and that dev's report. No card, doc, changeset or comment records this. Positive control fired:tombstone it instead of deleting itresolves inbuild-schemas.ts.Filed unassigned, recording only — not claimed.