Filed by the domain:cli seat (#6024, session session_016yfqQh2dBgPAymYd7xipza) from the derivability reading the #14376 triage ruling asked its implementer to record. finding = awaiting first grading; domain:* and type left for triage. Recording only — not claimed.
The recurring shape
A translation key family lands in packages/spec with a resolver that reads it, and the CLI extractor that produces the coverage population is updated later or not at all. Between those two moments every gate is green while the ratchet measures a population it cannot see. Four instances now:
| resolver landed | extractor caught up in | gap |
|---|
| #11287 (flow screens) | #11485 | a family |
translatePage learning nested children | #13109 | per-component depth |
| #14253 (bulk actions, validation messages, datasets) | #14376 / PR #14651 | three families at once |
Each was found by a person noticing, not by an instrument. The measurement that closes the loop does not exist.
What the #14376 implementer measured (the reason this is a gate, not a refactor)
Full derivation of the extractor from the resolvers was investigated and is not the answer — the two enumerations answer different questions over different inputs: a resolver reads the served document shape, the walker reads the authored stack config; key identity is the walker's own problem (a view container's default list must resolve its registry name and emit no key of its own); the inline versus sourceValue split exists only walker-side and turns on renderer fallbacks that live in objectui, another repo; and the deliberate exclusions live in a third place again (a guidance note in the translation schema, and checkConditional in objectql).
What is already machine-readable is the half that keeps drifting: the key FACE. packages/spec/src/system/translation.zod.ts declares every group's leaf keys as a strictObject, with guidance naming each deliberately-excluded neighbour.
The proposal, as the implementer stated it
Walk TranslationDataSchema's declared leaf keys and assert each is produced by collectExpectedEntries for some fixture, or is listed in an explicit, shrink-only exemption ledger. It needs only two things that already exist and are already pure — the schema and the walker — so it lands as one new file (scripts/check-i18n-walk-parity.mjs) wired beside check:i18n and check:i18n-coverage.
The property that makes it worth its cost: it would have failed the day #14253 landed — which is exactly what the three previous instances of this shape all lacked.
Executable criterion
With the gate in place, deleting one group's emitter from packages/cli/src/utils/i18n-extract.ts (or adding a group to TranslationDataSchema with no walker change) makes pnpm check:i18n-walk-parity exit non-zero, naming the unwalked group. Today that scenario is green: the state on origin/main before PR #14651 was three declared groups with a reader each and zero keys produced, with every gate passing.
Sequencing
Independent of PR #14651, which lands the fourth manual walk. This card is the construct that would stop a fifth. A shrink-only exemption ledger is part of the ask, not an afterthought: some groups may legitimately have no extractor face, and the gate has to be able to say so out loud rather than by silence.
Refs: #14376 (the fourth walk, and the ruling that asked for this reading) · PR #14651 · #14253 (the resolvers) · #11485 · #13109 · #3786 (TRANSLATABLE_METADATA_TYPES made derived to avoid a second hand-maintained vocabulary) · #12911 (the class of recurrences whose remedy is a construct rather than a rule).
Filed by the
domain:cliseat (#6024, sessionsession_016yfqQh2dBgPAymYd7xipza) from the derivability reading the #14376 triage ruling asked its implementer to record.finding= awaiting first grading;domain:*andtypeleft for triage. Recording only — not claimed.The recurring shape
A translation key family lands in
packages/specwith a resolver that reads it, and the CLI extractor that produces the coverage population is updated later or not at all. Between those two moments every gate is green while the ratchet measures a population it cannot see. Four instances now:translatePagelearning nested childrenEach was found by a person noticing, not by an instrument. The measurement that closes the loop does not exist.
What the #14376 implementer measured (the reason this is a gate, not a refactor)
Full derivation of the extractor from the resolvers was investigated and is not the answer — the two enumerations answer different questions over different inputs: a resolver reads the served document shape, the walker reads the authored stack config; key identity is the walker's own problem (a view container's default list must resolve its registry name and emit no key of its own); the
inlineversussourceValuesplit exists only walker-side and turns on renderer fallbacks that live in objectui, another repo; and the deliberate exclusions live in a third place again (aguidancenote in the translation schema, andcheckConditionalin objectql).What is already machine-readable is the half that keeps drifting: the key FACE.
packages/spec/src/system/translation.zod.tsdeclares every group's leaf keys as astrictObject, withguidancenaming each deliberately-excluded neighbour.The proposal, as the implementer stated it
Walk
TranslationDataSchema's declared leaf keys and assert each is produced bycollectExpectedEntriesfor some fixture, or is listed in an explicit, shrink-only exemption ledger. It needs only two things that already exist and are already pure — the schema and the walker — so it lands as one new file (scripts/check-i18n-walk-parity.mjs) wired besidecheck:i18nandcheck:i18n-coverage.The property that makes it worth its cost: it would have failed the day #14253 landed — which is exactly what the three previous instances of this shape all lacked.
Executable criterion
With the gate in place, deleting one group's emitter from
packages/cli/src/utils/i18n-extract.ts(or adding a group toTranslationDataSchemawith no walker change) makespnpm check:i18n-walk-parityexit non-zero, naming the unwalked group. Today that scenario is green: the state onorigin/mainbefore PR #14651 was three declared groups with a reader each and zero keys produced, with every gate passing.Sequencing
Independent of PR #14651, which lands the fourth manual walk. This card is the construct that would stop a fifth. A shrink-only exemption ledger is part of the ask, not an afterthought: some groups may legitimately have no extractor face, and the gate has to be able to say so out loud rather than by silence.
Refs: #14376 (the fourth walk, and the ruling that asked for this reading) · PR #14651 · #14253 (the resolvers) · #11485 · #13109 · #3786 (
TRANSLATABLE_METADATA_TYPESmade derived to avoid a second hand-maintained vocabulary) · #12911 (the class of recurrences whose remedy is a construct rather than a rule).