Repository navigation
test(i18n): fail on an orphaned apps.*.navigation locale key - #1726
Merged
Merged
Conversation
Every i18n assertion in this repo asks whether an authored surface has a translation. That direction cannot see a key whose target is gone: deleting a navigation entry leaves its `apps.*.navigation` rows behind in all four bundles, and a forward walk has nothing left to iterate that would reach them. PR #1261 removed five such keys from three locales by hand; had it not, `pnpm verify` would have stayed green with 15 dead keys. Measured before choosing the shape. The platform rule `translation-target-unknown` DOES report a navigation orphan, once per locale, with the remedy printed — orphans are not invisible, which the card assumed. What nothing does is fail: the finding is a `warning`, `objectstack lint` exits 0 on warnings, and `scripts/check-lint-i18n-gate.mjs` gates the `i18n/missing-*` family, the forward direction. The platform rule id carries no `i18n/` namespace, so it sits outside that gate rather than unlisted in it. Adds the orphan assertion plus the anti-vacuity half that pins the nav walk and the per-locale tables really were non-empty. Scope stops at `apps.*.navigation`; the forward direction already gates as `i18n/missing-navigation`. Co-authored-by: Claude
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
A single orphaned
apps.*.navigationlocale key now turnspnpm verifyred.Every i18n assertion in this repo is one-directional: it asks whether an authored
surface has a translation, never whether a translation still has a surface. That
direction structurally cannot see a key whose target is gone — deleting a
navigation entry leaves its
apps.*.navigationrows behind in all four bundles,and a forward walk has nothing left to iterate that would ever reach them.
The near miss this is written from: #1259 cut four navigation entries, and PR
#1261 removed their
nav_pipeline/nav_all_tasks/nav_event_calendar/nav_event_historykeys — plusgroup_approvals— fromzh-CN,es-ESandja-JPby hand. Had that author not remembered,pnpm verifywould havestayed fully green carrying 15 dead keys.
What I measured, and why I chose this route
The card says orphans are invisible to every i18n check. Half of that is
false, and the half that is true is what this PR fixes. Everything below was
measured on this branch, not inherited.
1. Baseline (
objectstack lint --json, this tree) — reproduced independently:true_sectionsorphan planted in all 4 bundlestruetrueZero
translation-target-unknownfindings at baseline confirms the repo carriesno orphans today in any keyspace that rule covers.
2. The decisive probe — does the platform rule cover
apps.*.navigation?objects.*evidence proves nothing aboutapps.*, so a nav orphan was planteddirectly. It is reported, once per locale:
with the remedy printed: "Match the key to the navigation item's
id, or dropit. Declared navigation ids: … (33 total)."
3. So what is actually broken is that nothing gates it. The finding is a
warning;objectstack lintexits 0 on warnings (passed: truein every rowabove); and
scripts/check-lint-i18n-gate.mjsgates thei18n/missing-*family, which is the forward direction.
Route: the repo-side assertion, not a wider gate
Both routes were live. The gating route was rejected on measurement:
translation-target-unknown— noi18n/namespace atall. The CLI passes registry rule ids straight through (
rule: f.rulein@objectstack/cli'slint.js); only its own rubric carriesfamily/ids. Sothe rule sits outside the gate's world rather than merely unlisted in it,
which is the condition on which the 2026-08-25 ruling stands unchanged.
a family that spans every keyspace at once — objects, fields, views, sections,
tabs, validations, actions, dashboards, flows. Adopting all of that is a much
wider decision than this card.
assertions were retired (
.changeset/retire-assertions-the-platform-already-reds-on.md),the criterion was that
objectstack lintexits 1 on the defect. Theconverse is the rule for keeping one: this rule does not error, so the local
assertion is exactly the kind this repo keeps.
test/i18n-references.test.ts's own header states the principle directly:every guard there walks the metadata and asks what it declares, and "none of
them asks a linter what it noticed."
On the gate script's header text (which the 2026-08-25 grading cited): read in
full, it does not forbid widening — it says "Widening this script to cover
other rule families is a separate, deliberate change, not a side effect of this
one." That sentence scopes #1018, not the script's future. The reason not to
widen it here is the namespace measurement above, not that header.
Changes Made
test/i18n-references.test.ts: addsno locale carries an apps.*.navigation entry the app does not declare, mirroring the existing_viewsorphanassertion, plus its anti-vacuity half (
sees a real navigation tree and an apps.*.navigation table in every locale) pinning thatstack.apps, the navwalk and each locale's table were all non-empty.
childrento any depth andareas[],matching what the console can render —
group_approvalswas one of the fiveorphans feat(nav): one entry per destination, one exemplar per nav-item kind (#1259) #1261 removed by hand.
(always green in the orphan direction) this card records.
.changeset/orphan-nav-locale-keys-turn-verify-red.md, empty frontmatter.Scope stops at
apps.*.navigationper the 2026-08-25 ruling — flat keyspace,nav tree right beside it.
objects.*/actions.*generalise from this shapeonce agreed. The forward direction for navigation already gates as
i18n/missing-navigationand is deliberately not restated.Acceptance, in both directions
RED — plant the real historical orphan
nav_pipelineinzh-CNonly, onekey, and run the full chain:
Note the gate line: with the orphan present the existing i18n gate stayed green
and merely counted one more unrelated issue. That is the card, in one line.
GREEN — at
d4c203b6, the final commit:Every mutation used the disk-proof procedure: hash the file, mutate, prove the
marker landed and the hash moved, measure under an EXIT/INT/TERM trap, restore
with
git checkout HEAD -- ABSOLUTE_PATH, then re-hash to provebyte-identity. Both ablations restored byte-identical; no exit code was
trusted on its own, and no
git stashwas used.Type of Change
src/metadata changed, nothing user-visible)Related Issues
Closes #1262
Testing
pnpm test— viapnpm verify, 3410 passed)pnpm lint,pnpm lint:i18n-gate)pnpm build)Additional Notes
Upstream, reshaped. The card anticipated asking the platform to build an
orphan rule family. It already has one. The remaining upstream ask is narrower:
translation-target-unknownis unfailable by design — warning severity, noi18n/namespace, no severity knob — so every app on the platform, not justthis one, ships dead locale keys through a green pipeline. Filing that is
optional and was deliberately left to the maintainer rather than guessed at,
since it is a severity/gateability request and not the "build it" card the
original wording describes.
Generated by Claude Code