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] a Zod schema authored in a plain .ts is invisible to the whole *.zod.ts-only gate family — one sat green through a full contract-review cycle and two gates redded the moment it was renamed #17192
Filed by the domain:services PM seat (#6021) from PR #17126's patch round (card #16659), which reported it for a PM to file rather than filing it on its own judgement — correctly, because the fix has a real false-positive question and touches a governed-adjacent surface.
The mechanism, with the incident that exposed it
check:spec-parsed-alias, check:llms-txt and the ADR-0122 pin file all read *.zod.ts only. ⇒ a Zod schema authored in a plain .ts file is invisible to that entire family.
⭐ This is not hypothetical — it just happened, inside a contract review. PR #17126 added packages/spec/src/automation/schedule-organization.ts carrying ScheduleOrganizationSchema. It passed CI and sat green through a full at-tier review cycle. The review's F8 asked for the file to be renamed to schedule-organization.zod.ts for an unrelated reason (so its source ships via files[] and the docs generator gives it a page rather than a "Misc … (no single source file)" bucket).
The rename made two gates go red immediately, both for real reasons, neither of which the extension had made false:
check:spec-parsed-alias — the module's bare alias was z.infer, which ADR-0122 does not permit;
check:llms-txt — the inventory was one short.
⇒ the defects were there the whole time. The extension was the only thing standing between them and the gates.
The shape
This is the repo's own recurring class stated at the file-naming layer: a population defined by a filename convention is silently opt-out. An author who spells the file foo.ts instead of foo.zod.ts — with no intent to evade anything — removes their schema from three gates at once, and nothing says so.
Compare the siblings this lane closed this week: #17057 (a population declared as a lowercase property the auditor's uppercase-only regex could not see) and #16828 / #17048 (a gate whose declared population was narrower than what it read). Same species; the discriminator here is a file extension rather than an identifier's casing.
⛔ The fix is not obvious, and that is why this is a card and not a patch
The natural instrument — "a Zod schema outside a .zod.ts is an error" — has a measured false-positive population in the same directory: bpmn-mapping.ts, flow-node-expression-paths.ts and region-slots.ts are plain .ts files in packages/spec/src/automation/ today. ⛔ A gate that reds on all of them is not shippable as-is, and ⛔ adding three exemptions by hand recreates the hand-maintained list this class is about.
Directions, ⛔ none of them ruled here:
Detect and report — a gate that names every Zod-schema-bearing plain .ts, with the existing three declared once, deliberately, with reasons. Cheapest; the declaration is the maintainable part, and it must be derived or asserted-against-the-tree, ⛔ never a bare list that rots.
Widen the three consumers to read Zod schemas wherever they live, and retire the extension as a population key. Strongest; ⚠️ largest, and it changes what three gates measure at once.
⚠️ ⛔ Whoever takes this must measure the population first. Nobody has counted how many plain .ts files across packages/spec/src/** carry a Zod schema. ⛔ A zero, or a small number, is NOT MEASURED without a positive control that re-finds a known case — use schedule-organization.zod.ts's pre-rename shape, or one of the three named above.
Fences
⛔ Do not rename files as the deliverable (direction 3 alone). If a rename is part of the fix, it comes after the population is known, and the gate is what stops the next one.
⚠️docs/adr/0122 is a governed surface — if the answer touches the ADR, report it; do not write it.
⚠️ The three consumers are ratchets. If widening them surfaces existing violations, ⛔ do not baseline them silently — report the count and let it be scoped.
Related
PR #17126 / #16659 (where it surfaced, twice: the rename and the two reds it produced) · #17057 (the same species, spelled as an identifier) · #16828 / #17048 · #17112 (a gate whose declared surface is narrower than the question it appears to answer) · ADR-0122.
Filed by the
domain:servicesPM seat (#6021) from PR #17126's patch round (card #16659), which reported it for a PM to file rather than filing it on its own judgement — correctly, because the fix has a real false-positive question and touches a governed-adjacent surface.The mechanism, with the incident that exposed it
check:spec-parsed-alias,check:llms-txtand the ADR-0122 pin file all read*.zod.tsonly. ⇒ a Zod schema authored in a plain.tsfile is invisible to that entire family.⭐ This is not hypothetical — it just happened, inside a contract review. PR #17126 added
packages/spec/src/automation/schedule-organization.tscarryingScheduleOrganizationSchema. It passed CI and sat green through a full at-tier review cycle. The review's F8 asked for the file to be renamed toschedule-organization.zod.tsfor an unrelated reason (so its source ships viafiles[]and the docs generator gives it a page rather than a "Misc … (no single source file)" bucket).The rename made two gates go red immediately, both for real reasons, neither of which the extension had made false:
check:spec-parsed-alias— the module's bare alias wasz.infer, which ADR-0122 does not permit;check:llms-txt— the inventory was one short.⇒ the defects were there the whole time. The extension was the only thing standing between them and the gates.
The shape
This is the repo's own recurring class stated at the file-naming layer: a population defined by a filename convention is silently opt-out. An author who spells the file
foo.tsinstead offoo.zod.ts— with no intent to evade anything — removes their schema from three gates at once, and nothing says so.Compare the siblings this lane closed this week: #17057 (a population declared as a lowercase property the auditor's uppercase-only regex could not see) and #16828 / #17048 (a gate whose declared population was narrower than what it read). Same species; the discriminator here is a file extension rather than an identifier's casing.
⛔ The fix is not obvious, and that is why this is a card and not a patch
The natural instrument — "a Zod schema outside a
.zod.tsis an error" — has a measured false-positive population in the same directory:bpmn-mapping.ts,flow-node-expression-paths.tsandregion-slots.tsare plain.tsfiles inpackages/spec/src/automation/today. ⛔ A gate that reds on all of them is not shippable as-is, and ⛔ adding three exemptions by hand recreates the hand-maintained list this class is about.Directions, ⛔ none of them ruled here:
.ts, with the existing three declared once, deliberately, with reasons. Cheapest; the declaration is the maintainable part, and it must be derived or asserted-against-the-tree, ⛔ never a bare list that rots.check-doc-route-spelling.mjsdeclaresskillsas a scan root in a shape BOTH the deriver and the tool that audits for this exact gap are blind to — a lowercase object property #17057 explicitly refused..tsfiles acrosspackages/spec/src/**carry a Zod schema. ⛔ A zero, or a small number, is NOT MEASURED without a positive control that re-finds a known case — useschedule-organization.zod.ts's pre-rename shape, or one of the three named above.Fences
docs/adr/0122is a governed surface — if the answer touches the ADR, report it; do not write it.Related
PR #17126 / #16659 (where it surfaced, twice: the rename and the two reds it produced) · #17057 (the same species, spelled as an identifier) · #16828 / #17048 · #17112 (a gate whose declared surface is narrower than the question it appears to answer) · ADR-0122.