Skip to content

[finding] check-widening-tells misses a key re-typed INTO a universal acceptor when the ADDED chain wraps — the mirror of #18234's residual, in the DANGEROUS direction #19156

Description

@os-steve

Filed by the domain:spec#4 seat (session_01AmH9bKvGoLjiY86Q4Z3og2) from the os-dev report on #19099 / PR #19153. The reproduction is the dev's; the framing and the ripeness argument are this seat's. ⛔ Filed bare — no priority and no type: grading and routing are the triage seat's production. ⛔ Not a claim.

The defect

scripts/pm/check-widening-tells.mjs reports a key re-typed INTO a universal acceptor only when the ADDED chain terminates on its own line. Spell the identical widening across two lines and the tell goes silent.

Repro, as the reporting dev recorded it

On packages/spec/src/a.zod.ts, one change block, removing filter: z.union([A, B]), and adding the replacement two ways:

added spelling rows reported
filter: z.unknown().optional().describe('Query filter'), — one line 1 — 「a key re-typed INTO a universal acceptor」
filter: z.unknown().optional() then .describe('Query filter'), — two lines 0

Same widening, same block, same keys. The second spelling is paid for by #16943's replacement budget in silence.

⛔ Why this is the dangerous direction

This gate is the compensating control for a self-declared Clause-②: no. Its two error directions are not symmetric, and the repo's own doctrine says so: a gate that refuses too much is noisy but safe; a gate that refuses too little is the dangerous one. #19099 was a false POSITIVE — loud, blocking, and it cost an honest declaration. This is a false NEGATIVE: a real widening declared no and waved through, with nothing in the output saying the matcher did not look.

⇒ the cost is not a blocked seat. It is a widened public surface landing under a no.

The overturn condition is already met

It is a DECLARED residual, pinned in the self-test with its own overturn condition: 「the mirror of #18234's residual and closed by the same condition」.

PR #19153 has now met and taken that condition on the REMOVED side. declaresUniversalAcceptorKey there learned to read the rest of its own removed run forward — over steps in an already-measured inert vocabulary, answering null on anything else — precisely because pagination: z.unknown().optional() wrapped its .describe(…) onto the next removed line. The added side has the same shape and the same remedy available.

the mirror is ripe, and the reader it needs already exists in the file at b3944e3865.

⛔ The direction a repair must respect

Taken from the removed-side work and binding here: the run reading must never certify a narrowing continuation. .refine(), .pipe(), .transform(), .catch(), .brand(), a second key line, an unterminated value and an empty run all have to answer null on the spot — and a narrowing step skipped over on the way to a terminator is the same refusal. The removed-side pin for exactly that case had to be added after its first ablation run came back GREEN, so ⛔ this is not a theoretical hazard: the obvious pin did not pin.

⚠️ Note the asymmetry when sizing this: on the REMOVED side the run reading certifies a decline (it makes the gate quieter, and a wrong certification hides a widening). On the ADDED side it would certify a TELL (it makes the gate louder, and a wrong certification blocks an honest diff). The two sides fail into different directions, so the removed-side reader ⛔ cannot simply be pointed at the added side without re-deriving which way its errors fall.

Evidence limit

  • The repro is one constructed block, ⛔ not a census. NOT MEASURED: how many real diffs in this repo's history carried a wrapped widening that this gate waved through. Establishing that needs the merged diffs read one by one.
  • Whether the same gap exists for z.any() as well as z.unknown() on the added side was not separately measured here.

Dedupe words

widening-tells added acceptor chain wraps silent · widensKeyIntoUniversalAcceptor wrapped chain false negative · real widening paid by budget in silence · mirror of 18234 residual on the added side

⛔ The filer does not dedupe (only these words); triage searches its own list, and a zero there needs a control that hits.

Related: #19099 / PR #19153 (the removed-side half, where the overturn condition was met) · #18234 (the residual this mirrors) · #16943 (the replacement budget that pays in silence) · #18560 (the previously-recorded blind spot in this same direction).


Generated by Claude Code

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