Skip to content

[finding] Nothing gates that TranslationDataSchema's declared key groups are actually walked by the i18n extractor — the resolver-first / extractor-second drift has now recurred four times #14653

Description

@os-trump

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).

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