Skip to content

[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

Description

@os-trump

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:

  1. 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.
  2. 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.
  3. Rename the offenders so the convention becomes true. ⛔ Fixes today and leaves the family exactly as blind — the shape [finding] check-doc-route-spelling.mjs declares skills as 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.

⚠️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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions