Skip to content

test(cli): extend check:app-nav-i18n with pages.* default-locale content parity - #8826

Merged
qq9340100 merged 1 commit into
mainfrom
claude/issue-8764-pages-default-locale-parity
Aug 15, 2026
Merged

test(cli): extend check:app-nav-i18n with pages.* default-locale content parity#8826
qq9340100 merged 1 commit into
mainfrom
claude/issue-8764-pages-default-locale-parity

Conversation

@qq9340100

Copy link
Copy Markdown
Collaborator

Fixes#8764

Route 1 of the two candidate shapes the card named: extend the existing check:app-nav-i18n gate rather than move the entries into the packages that author them.

The mechanism assumption, measured before anything was written

The card and triage both flagged one unmeasured thing — whether the page metadata carrying marketplace_installed / cloud_connection_settings / connect_agent actually flows through the composition this gate boots, given that the gate walks the merged nav tree today and pages are a different surface.

It does, and the path is short:

  • CONTRIBUTORS already loads @objectstack/mcp's CONNECT_AGENT_UI_BUNDLE and @objectstack/cloud-connection's three bundles, for their nav contributions.
  • Those same manifests carry pages:, and engine.registerApp registers that collection through METADATA_ARRAY_KEYS in packages/objectql/src/engine.ts'pages' is on the list.
  • So the pages are already in the registry this gate builds. Probed on the real composition: registry.listItems('page') returns all three, with label and the page:headertitle / subtitle intact.

Route 1 is therefore available and costs one extra read of the registry — no second boot, no new dependency, no ownership change. Route 2 is not addressed here and remains a separate, larger question.

What the assertion compares

Not invented here — it is the mapping translatePage implements and TranslationDataSchema.pages documents:

bundle keysource in the page metadata
pages.NAME.labelthe page document's own label
pages.NAME.descriptionthe page document's own description
pages.NAME.titleevery page:header's properties.title
pages.NAME.subtitleevery page:header's properties.subtitle

Default locale only.en is a copy of the source literals, not a translation — the extractor rewrites it from the source on every run — so comparing it to its source is meaningful, while comparing zh-CN to the source would be backwards. Per-locale key coverage stays the first assertion's job, one section over.

The title fallback is implemented, and it is not a detail.pages.NAME.title falls back to pages.NAME.label. All three pages declare label only, so that one key is what serves the header title; a header title edited to differ from the page label would be silently overwritten by the label in every locale, en included, with nothing else in the repo comparing the two.

Three finding kinds, kept apart because their remedies differ: drift, orphan (a bundle entry naming a page the composition does not contain), and no-source (a key with no field to overlay).

The anti-vacuity half

A parity assertion that cannot fail is the exact defect class this card is about, so the orphan finding is load-bearing: without it, renaming a page silently reduces this assertion to comparing nothing while staying green. This is the key-level counterpart of the gate's existing contributor-level guard.

It is deliberately not the reverse direction the gate declines for nav. That refusal is about conditionally-contributed entries being indistinguishable from dead keys. These three pages come from bundles this gate registers unconditionally as static manifest exports, so within this composition an absence means renamed or removed — never gated off. Stated in the script.

Verified — both ablations run against the real composition

The gate imports built packages, so each ablation is mutate → pnpm --filter @objectstack/mcp build → prove the marker reached dist → run. A green ablation on a stale dist would certify an assertion that can never fail.

  1. Drift — prefixed the connect-ui.ts header subtitle. Marker confirmed present in 2 built files, then: RED, one finding, naming the key path, the authoring package and both strings.
  2. Orphan — renamed the page to connect_agent_ABLATION8764. Marker confirmed in dist, then: RED with the orphan finding, proving a renamed page cannot reduce this to a vacuous pass.

Restored after each: source proven byte-identical to the commit via git hash-object (64ede463… both sides), dist re-verified marker-absent with --absent so no mutated artifact survives in the worktree, gate green again.

Test evidence — all at HEAD 58ef91535

node scripts/check-app-nav-i18n.mjs --self-test EXIT=0
node scripts/check-app-nav-i18n.mjs EXIT=0
OK (10 contributors, 53 merged setup nav ids, 4 locales, every id labelled
in every locale; 3 pages.* entries in verbatim parity with their source
metadata in en)
pnpm --filter @objectstack/cli test 122 files / 1329 tests passed
pnpm --filter @objectstack/cli typecheck EXIT=0
npx eslint (changed file) EXIT=0
node scripts/check-nul-bytes.mjs OK (5838 files)

Gate families re-derived against the actual changed path with scripts/pm/dispatch-gates.mjs: no family names this path in its own source; check:nul-bytes (any edit) run green.

Notes

  • All three entries measured in verbatim parity at the time of writing, so the new assertion goes green on landing — consistent with the card: an unexercised hole, not a live defect. Nothing drifted between filing and now.
  • No changeset: packages/cli publishes dist only, so a file under scripts/ ships nothing to consumers. skip-changeset applied.

Generated by Claude Code

The platform bundle's `pages.*` section was compared by nothing, in any
locale including `en`, because its three sources are authored in other
packages (@objectstack/cloud-connection, @objectstack/mcp) that
platform-objects does not and must not depend on. The #8721 static walk
says so and defers here.
This gate already boots the composition and already registers both
carrying manifests for their nav contributions; those same manifests
carry `pages:`, which engine.registerApp registers through
METADATA_ARRAY_KEYS. So the pages are already in the registry this gate
builds — the assertion costs one extra read, no second boot.
Compares the default locale only (`en` is a copy of the source literals,
not a translation) against the mapping translatePage implements,
including its `title` -> `label` fallback. Three finding kinds with
distinct remedies: drift, orphan (the anti-vacuity guard, so a renamed
page cannot silently reduce the assertion to comparing nothing), and a
key with no source field to overlay.
All three entries measured in verbatim parity at the time of writing.
Part of #8764
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NaS1PAHJcPfAA2acnV53Tn
@vercel

vercelBot commented Aug 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 15, 2026 5:20am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

No hand-written docs reference the 0 changed package(s). ✅

@qq9340100qq9340100 added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 15, 2026 — with Claude
@qq9340100
qq9340100 marked this pull request as ready for review August 15, 2026 05:33
@qq9340100
qq9340100 added this pull request to the merge queueAug 15, 2026
Merged via the queue into main with commit 03a8da0Aug 15, 2026
30 checks passed
@qq9340100
qq9340100 deleted the claude/issue-8764-pages-default-locale-parity branch August 15, 2026 05:47
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 17, 2026
…ctstack-ai#8861)
app-nav-translation-parity.test.ts's block comment above the default-locale
describe still said pages.* had "no source comparison in ANY locale" and
tracked the gap as objectstack-ai#8764. PR objectstack-ai#8826 closed that: check:app-nav-i18n
(packages/cli/scripts/check-app-nav-i18n.mjs) now asserts the `en` copy of
pages.* against the composed page metadata verbatim.
Keep the structural explanation (the sources live in packages
platform-objects must not depend on), replace the stale sentence with a
pointer to the gate that now covers it, retire the closed-issue forward
reference, and state plainly what still isn't covered: per-locale
(zh-CN / ja-JP / es-ES) coverage of those pages.* keys remains unasserted
anywhere in the repo.
Comment-only change; no behaviour, gate, or test-count change.
Fixesobjectstack-ai#8828
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@qq9340100@claude