Measured by the os-dev patch round on #15811 (report 5715173579) and handed to the seat to file — devs do not POST /issues. ⛔ Not introduced by that PR (it arrived with the refine that round added, but the projection gap is general and pre-existing).
Measured
z.toJSONSchema in zod 4.4.3 returns byte-identical output for a plain record, the same record with a .refine(), and the same record with an aborting .refine(). ⇒ a refinement cannot reach the published JSON Schema at all.
Worked instance, packages/spec/json-schema/system/TraceSamplingConfig.json:
condition.anyOf[0] = {"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}
That accepts {dialect:'cel'} — which the runtime refuses. The string branch likewise carries no non-blank constraint, while the runtime requires non-empty-after-trim.
⭐ Why this is class (c) and not a generator nit
This is the metadata-authoring trap in its most exact form. packages/spec/json-schema/** is what an author — or an AI — validates against, and what the reference tables are generated from. Today it says yes to shapes the runtime says no to.
⇒ The failure is silent at the moment of authoring and loud only later, which is the inversion this project exists to prevent: 「声明即强制」 is violated in the direction where the published declaration is more permissive than what runs.
⚠️ And it is general: it applies to every refinement in packages/spec, not to the one slot that surfaced it. The tracing slot is the specimen, ⛔ not the population. Whoever takes this must census the refinements first.
What it is NOT
⛔ Not an argument to remove refinements — the runtime behaviour is correct and is what the ADR-0049 direction wants. The gap is that the projection drops it.
⛔ Not fixable by hand-editing the generated page: the #15811 round measured that regenerating alone can never move the type cell, and hand-edits are reverted by the next generation and red the generated-artifact gate. That round worked around it at the slot's .describe(), which documents the rule in prose — a mitigation, ⛔ not a fix, and it does not help a machine validator.
Direction for a fix
Either the projection learns to emit what a refinement constrains (where the refinement is expressible in JSON Schema — propertyNames, not, minLength and friends cover a lot of them), or the published artifact declares that it is a floor rather than the contract, loudly enough that a validator author cannot miss it. ⚠️ The second is weaker and should not be chosen just because it is cheaper — a schema that is documented to be wrong is still wrong to a machine.
Carrier: whoever owns packages/spec/scripts/build-schemas.ts's projection.
Dedupe words: json-schema projection refine dropped, toJSONSchema byte-identical refined, published schema wider than zod, TraceSamplingConfig condition anyOf record, authorable surface validator green runtime refuses.
os-decision-facets
⚠️ Added by the domain:spec seat when the half-state patrol row H62 measured this body as carrying no marker in either spelling. This seat filed the card, so this is its own filing duty discharged late — ⛔ nothing already on the face was removed or reworded. Item 1 has since LANDED (PR #18729, squash a49e8ae963); the facets below are about item 2 only, which is what remains in the box.
- ① 项目长远合理性 — the published
packages/spec/json-schema/** is measurably WIDER than the zod it is generated from wherever a .refine() carries the rule. Item 1 stopped the silence: every affected artefact now carries an x-dropped-refinements annotation and a ratchet-only ledger. ⭐ That annotation IS item 2’s worklist — every repaired site deletes a ledger row, so the migration is measurable from its first commit to its last. Item 2 decides whether the FILE stops lying or only keeps confessing.
- ② 实际业务拉动 — an author validating against the published JSON Schema gets a GREEN for metadata the runtime then refuses. Census on the tree, reproducible: 126 refinement sites (
refine 48 + superRefine 75 + check 3), 243 published schemas each dropping at least one, 737 dropped sites, and 0 sites actually projected into a published file. Mode-invariance proven (737/243 both with and without OS_EAGER_SCHEMAS=1), so the numbers are not an artefact of which vitest project ran the generator.
- ③ 防 AI 犯错 — the failure shape is a machine validator answering PASS on a document the runtime rejects: right at the door, wrong at run time, green throughout. ⚠️ The card’s own text warns against choosing the cheap option BECAUSE it is cheap.
- ④ 创业阶段不扩散 — A narrows the published shapes and is therefore breaking for already-passing documents ⇒ ADR-0087 disposition + a minor changeset under the launch-window convention; the implementing round recommended it, with a second census first classifying all 737 sites as expressible vs not. B is zero cost and changes no contract, but leaves the validator green on metadata the runtime refuses. C narrows only where the refinement is total and mechanically derivable, which is a smaller blast radius than A but ships two classes of rule on one published surface with nothing on the file distinguishing them.
Prior rulings read: ADR-0087 (semantic migration entries — what A or C would owe) · ADR-0049 (enforce-or-remove, the sibling discipline) · the launch-window convention that a breaking change ships minor + BREAKING banner, ⛔ never major (check-changeset-no-major.mjs enforces it). ⛔ No prior ruling decides whether the published projection may narrow; that is what this card asks.
The question, in one line: does the JSON Schema projection start emitting what a .refine() constrains wherever that is expressible (A — breaking for documents that validated yesterday), keep only item 1’s annotation and leave the shapes alone (B — the machine validator stays wrong on purpose), or narrow ONLY where the refinement is total and mechanically derivable (C)? ⛔ This seat states the options and does not grade them: it is a public-contract change.
Generated by Claude Code
Measured by the
os-devpatch round on #15811 (report5715173579) and handed to the seat to file — devs do notPOST /issues. ⛔ Not introduced by that PR (it arrived with the refine that round added, but the projection gap is general and pre-existing).Measured
z.toJSONSchemain zod 4.4.3 returns byte-identical output for a plain record, the same record with a.refine(), and the same record with an aborting.refine(). ⇒ a refinement cannot reach the published JSON Schema at all.Worked instance,
packages/spec/json-schema/system/TraceSamplingConfig.json:That accepts
{dialect:'cel'}— which the runtime refuses. The string branch likewise carries no non-blank constraint, while the runtime requires non-empty-after-trim.⭐ Why this is class (c) and not a generator nit
This is the metadata-authoring trap in its most exact form.
packages/spec/json-schema/**is what an author — or an AI — validates against, and what the reference tables are generated from. Today it says yes to shapes the runtime says no to.⇒ The failure is silent at the moment of authoring and loud only later, which is the inversion this project exists to prevent: 「声明即强制」 is violated in the direction where the published declaration is more permissive than what runs.
packages/spec, not to the one slot that surfaced it. The tracing slot is the specimen, ⛔ not the population. Whoever takes this must census the refinements first.What it is NOT
⛔ Not an argument to remove refinements — the runtime behaviour is correct and is what the ADR-0049 direction wants. The gap is that the projection drops it.
⛔ Not fixable by hand-editing the generated page: the
#15811round measured that regenerating alone can never move the type cell, and hand-edits are reverted by the next generation and red the generated-artifact gate. That round worked around it at the slot's.describe(), which documents the rule in prose — a mitigation, ⛔ not a fix, and it does not help a machine validator.Direction for a fix
Either the projection learns to emit what a refinement constrains (where the refinement is expressible in JSON Schema —⚠️ The second is weaker and should not be chosen just because it is cheaper — a schema that is documented to be wrong is still wrong to a machine.
propertyNames,not,minLengthand friends cover a lot of them), or the published artifact declares that it is a floor rather than the contract, loudly enough that a validator author cannot miss it.Carrier: whoever owns
packages/spec/scripts/build-schemas.ts's projection.Dedupe words:
json-schema projection refine dropped,toJSONSchema byte-identical refined,published schema wider than zod,TraceSamplingConfig condition anyOf record,authorable surface validator green runtime refuses.os-decision-facets
domain:specseat when the half-state patrol row H62 measured this body as carrying no marker in either spelling. This seat filed the card, so this is its own filing duty discharged late — ⛔ nothing already on the face was removed or reworded. Item 1 has since LANDED (PR #18729, squasha49e8ae963); the facets below are about item 2 only, which is what remains in the box.packages/spec/json-schema/**is measurably WIDER than the zod it is generated from wherever a.refine()carries the rule. Item 1 stopped the silence: every affected artefact now carries anx-dropped-refinementsannotation and a ratchet-only ledger. ⭐ That annotation IS item 2’s worklist — every repaired site deletes a ledger row, so the migration is measurable from its first commit to its last. Item 2 decides whether the FILE stops lying or only keeps confessing.refine48 +superRefine75 +check3), 243 published schemas each dropping at least one, 737 dropped sites, and 0 sites actually projected into a published file. Mode-invariance proven (737/243 both with and withoutOS_EAGER_SCHEMAS=1), so the numbers are not an artefact of which vitest project ran the generator.Prior rulings read: ADR-0087 (semantic migration entries — what A or C would owe) · ADR-0049 (enforce-or-remove, the sibling discipline) · the launch-window convention that a breaking change ships
minor+ BREAKING banner, ⛔ nevermajor(check-changeset-no-major.mjsenforces it). ⛔ No prior ruling decides whether the published projection may narrow; that is what this card asks.The question, in one line: does the JSON Schema projection start emitting what a
.refine()constrains wherever that is expressible (A — breaking for documents that validated yesterday), keep only item 1’s annotation and leave the shapes alone (B — the machine validator stays wrong on purpose), or narrow ONLY where the refinement is total and mechanically derivable (C)? ⛔ This seat states the options and does not grade them: it is a public-contract change.Generated by Claude Code