Recording a gap surfaced while landing #9046 (PR #9669). Unassigned finding — not claiming, and not asserting a disposition.
Observed
When a field/object description or label is corrected in a .object.ts declaration, there is no mechanism that propagates the correction into a locale bundle that already holds a hand translation of the old text. The generated bundles keep the stale translation indefinitely, and every gate stays green.
The two halves, both measured on origin/main (d693ba158):
Extraction deliberately will not overwrite it.packages/cli/src/commands/i18n/extract.ts merges against the committed bundles (mergeExisting: !flags['no-merge']), and only the default locale is filled from schema labels. --fill=default fills gaps — a stale-but-present string is not a gap, so it is skipped. This is correct behaviour on its own terms: the alternative (--no-merge) wipes every hand translation in the bundle, which is the incident that config's own comment warns about.
check:i18n cannot see the drift. It proves the keys are in sync — that no authoring key is undeclared and no bundle carries an orphan. It never compares a translated value against the meaning of its source. So a locale asserting the opposite of what the English now says reports "all bundles in sync."
Why it is worth a card
This is the same shape as the class #9046 belongs to: a declared surface with no enforcement keeping it true. The locale bundle asserts a description to every non-English reader; nothing verifies that assertion still matches the source it was translated from. On compliance-adjacent text this is not cosmetic — #9046 existed precisely because two column descriptions promised a recertification review that does not happen, and three of the four locales would have kept promising it after the English was fixed, with check:i18n green throughout.
The correction in #9669 reached the three localized bundles only because a human edited the help leaves in place — the maintenance path the generated bundle header itself names ("Edit translations in place; re-run extract (with --merge) to fill new gaps. Do not hand-edit the structure — only the leaf string values."). That path works, but it is unenforced and invisible: nothing distinguishes "translator corrected it deliberately" from "nobody noticed."
What is genuinely open
⛔ I am not asserting this is a defect. It may be intended — translation staleness is normally a human/translator workflow concern, and a repo that regenerated translations automatically would be making a worse trade. The open question is whether it is intended and accepted, or an unnoticed hole:
- If accepted, the honest close is to say so where it is discoverable — the extract config comment and the bundle header describe the merge behaviour but not its consequence for changed sources.
- If a hole, the tractable shape is a staleness marker rather than a re-translation mechanism: record the source-text hash a translation was made from, and let
check:i18n report the leaves whose source has moved since. That names which strings need a translator without touching any of them, and it does not degrade a locale to English to fix a promise.
⛔ Scoped honestly: such a check would be a translation-staleness detector for schema-derived strings, not coverage of "documentation that lies." It would not read prose in content/docs/**, JSDoc, or READMEs.
Related
Recording a gap surfaced while landing #9046 (PR #9669). Unassigned finding — not claiming, and not asserting a disposition.
Observed
When a field/object
descriptionorlabelis corrected in a.object.tsdeclaration, there is no mechanism that propagates the correction into a locale bundle that already holds a hand translation of the old text. The generated bundles keep the stale translation indefinitely, and every gate stays green.The two halves, both measured on
origin/main(d693ba158):Extraction deliberately will not overwrite it.
packages/cli/src/commands/i18n/extract.tsmerges against the committed bundles (mergeExisting: !flags['no-merge']), and only the default locale is filled from schema labels.--fill=defaultfills gaps — a stale-but-present string is not a gap, so it is skipped. This is correct behaviour on its own terms: the alternative (--no-merge) wipes every hand translation in the bundle, which is the incident that config's own comment warns about.check:i18ncannot see the drift. It proves the keys are in sync — that no authoring key is undeclared and no bundle carries an orphan. It never compares a translated value against the meaning of its source. So a locale asserting the opposite of what the English now says reports "all bundles in sync."Why it is worth a card
This is the same shape as the class #9046 belongs to: a declared surface with no enforcement keeping it true. The locale bundle asserts a description to every non-English reader; nothing verifies that assertion still matches the source it was translated from. On compliance-adjacent text this is not cosmetic — #9046 existed precisely because two column descriptions promised a recertification review that does not happen, and three of the four locales would have kept promising it after the English was fixed, with
check:i18ngreen throughout.The correction in #9669 reached the three localized bundles only because a human edited the
helpleaves in place — the maintenance path the generated bundle header itself names ("Edit translations in place; re-run extract (with --merge) to fill new gaps. Do not hand-edit the structure — only the leaf string values."). That path works, but it is unenforced and invisible: nothing distinguishes "translator corrected it deliberately" from "nobody noticed."What is genuinely open
⛔ I am not asserting this is a defect. It may be intended — translation staleness is normally a human/translator workflow concern, and a repo that regenerated translations automatically would be making a worse trade. The open question is whether it is intended and accepted, or an unnoticed hole:
check:i18nreport the leaves whose source has moved since. That names which strings need a translator without touching any of them, and it does not degrade a locale to English to fix a promise.⛔ Scoped honestly: such a check would be a translation-staleness detector for schema-derived strings, not coverage of "documentation that lies." It would not read prose in
content/docs/**, JSDoc, or READMEs.Related
last_certified_at/certified_by) are declared on both grant tables and nothing writes or reads them #9046 / PR fix(security): withdraw the ADR-0091 D5 recertification claim from the attestation columns (#9046) #9669 — the card that surfaced it; the PM ruling on that PR carries the full reasoning for why no generator-only option was available.authorization.mdxlists the inert D5 pair alongside the enforcedreason/delegated_fromas one set of "lifecycle-audit columns" #9671 — a separate observation from the same PR (content/docs/permissions/authorization.mdxgrouping enforced and inert columns as one set).