Blocked-by: #11566 (the enforcement PR must land first).
What
The #11566 tightening (maxLength → z.number().int().min(1) + refused outside BOUNDED_STRING_FIELD_TYPES) shipped without its ADR-0087 ledger entry: packages/spec/src/migrations/registry.ts was held by the #10724/#11169 family dispatch in the same wave, and the dispatch constraint was explicit — do not touch it. The changeset declares the narrowing (minor, launch-window convention) and names what newly gets rejected; the ledger entry is the missing half.
What the entry owes (the #8321 template, verbatim precedent in step18's rationale)
#8321 (scale/precision int refusal — the same defect class, same file) registered both halves at the next-major step:
Per step18's own text, enforcement ships on the 17.x line (accept-set narrowings ride minors) and the ledger tells migrate meta users at the major boundary — so this deferral is temporally sound, but the entry must exist before that boundary; this card is what keeps it from being the #6048 silence.
Generated by Claude Code
Blocked-by: #11566 (the enforcement PR must land first).
What
The #11566 tightening (maxLength →
z.number().int().min(1)+ refused outsideBOUNDED_STRING_FIELD_TYPES) shipped without its ADR-0087 ledger entry:packages/spec/src/migrations/registry.tswas held by the #10724/#11169 family dispatch in the same wave, and the dispatch constraint was explicit — do not touch it. The changeset declares the narrowing (minor, launch-window convention) and names what newly gets rejected; the ledger entry is the missing half.What the entry owes (the #8321 template, verbatim precedent in step18's rationale)
#8321 (
scale/precisionint refusal — the same defect class, same file) registered both halves at the next-major step:maxLength(0 / negative / non-integer) from old sources and stored rows — behaviour-preserving (A number field's declaredscaleis never enforced — values with more decimals are accepted and stored verbatim (min/max on the same field are enforced) #7501-style: nothing ever enforced the malformed value; the SQL drift planner mis-consuming it is exactly what driver-sql: the string family ignoresmaxLengthtoo — a declared 1024 becomes varchar(255) and refuses legitimate writes #11431 closed). Also mechanical: stripmaxLengthfrom field types outsideBOUNDED_STRING_FIELD_TYPES(the value was inert by construction — the write-time validator never read it there).Per step18's own text, enforcement ships on the 17.x line (accept-set narrowings ride minors) and the ledger tells
migrate metausers at the major boundary — so this deferral is temporally sound, but the entry must exist before that boundary; this card is what keeps it from being the #6048 silence.Generated by Claude Code