Repository navigation
feat(nav): one entry per destination, one exemplar per nav-item kind (#1259) - #1261
Merged
Merged
Conversation
…1259) The sidebar had grown to 7 groups / 31 items against a docs promise of a slimmed nav. Almost all the excess was one pattern: the same object surfaced repeatedly through its own saved views while the list page already carried a tab for each — crm_event held four rows, crm_opportunity three. Removes Pipeline, Calendar, Interaction History and All Tasks; every one of those destinations stays one click away as a tab on its object's list page. Moves Products into Sales (revenue master data, not campaigns) and the approvals Inbox into My Work, dissolving the one-item Approvals group. Marketing stays a single-item domain group on purpose. All six nav-item kinds keep an exemplar. test/app-navigation-shape.test.ts pins that floor plus the no-duplicate-destination ceiling, so neither the growth this fixes nor the over-slimming it invites can land silently. Locale bundles drop the orphaned nav keys; the docs that enumerate the sidebar are re-cut in all three doc locales, re-pointing each retired name rather than deleting it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
os-zhuang
marked this pull request as ready for review
August 23, 2026 12:41
8 of 9 tasks
os-steve
pushed a commit
that referenced
this pull request
Sep 6, 2026
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
5 tasks done
github-merge-queue Bot
pushed a commit
that referenced
this pull request
Sep 6, 2026
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 Co-authored-by: Claude <noreply@anthropic.com>
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.
Fixes #1259
Slims the authored nav from 7 groups / 31 items to 6 groups / 27 items, to the shape the maintainer accepted verbatim in the card (「接受你的建议」).
What moved, and what was removed
The excess was almost entirely one pattern: the same object surfaced repeatedly through its own saved views while the list page already carried a tab for each.
crm_eventheld four rows,crm_opportunitythree.Reachability — measured per view, not assumed
Every removed destination is still one click away on its object's tab strip. Read from the built artifact the runtime serves (
dist/objectstack.json), not from source:list.tabslistViewspipeline_kanban(crm_opportunity)event_calendar(crm_event)held_events(crm_event)all_tasks(crm_task)listblock (isDefault+pinned) — the landing tab of the page My Tasks opensThis partly falsifies the mechanism assumption in the dispatch, which read the strip as "declared
listViewsin declaration order".all_tasksis not inlistViewsat all — it is thelistblock itself — so alistViews-only check would have wrongly reported All Tasks as lost. Both surfaces matter; the repo's own guard (view-references.test.ts→ every named list view is reachable) treatstabsas the curator, and it stays green. No view needed adding to a tab strip.The card's other premise holds: all five My Work entries are
viewName-type, so the view-entry exemplar duty really does pass to them whennav_pipelinegoes.The six-exemplar constraint, now guarded
test/app-navigation-shape.test.tsis new and pins the constraint in both directions:object/ view /page/dashboard/report/component) keeps ≥1 entry.pageandcomponentare down to one each, so the next slimming pass was one deletion away from removing a demonstration silently.Reverse-verified, both legs, mutation confirmed on disk before reading the result and restore confirmed after (via an
EXIT-trapped script):componententry →× still ships at least one \component` entry` (1 failed / 10 passed)crm_opportunityentry →× no two entries open the same destinationand× no object holds more than one plain list entry(2 failed / 9 passed)Docs and i18n
Removing nav entries falsified prose in ten doc pages across all three doc locales, three of them enforced by docs↔nav parity tests that went red immediately. Each retired name is re-pointed, not deleted — the convention
docs-quick-tour-navigation.test.tsalready enforces — and the four retired item names joined itsPHANTOMSlist so they must stay named in italics and can never be bolded again while they are not nav labels.The three non-English locale bundles drop the orphaned
apps.crm_enterprise.navigationkeys and keep the labels of the two items that moved.en.tscarries only group entries and needed no change.Verification
All on
a8b3514:pnpm typecheck→ exit 0pnpm validate→✓ Validation passed (823ms)pnpm lint:i18n-gate→✓ i18n lint gate: 0 \i18n/missing-*` issues`pnpm build→ exit 0,UI: 1 Apps 14 Views 8 Pages 5 Dashboards 10 Reports 30 Actionspnpm exec vitest run→ 121 files, 2851 passed | 2 skipped, 0 failedTwo verification caveats, declared:
os-verify-lock: VERDICT lock-unusable (exit 99) · never acquired · nothing was built or tested, because macOS ships noflock. Commands were run directly with--maxWorkers=2andNODE_OPTIONS=--max-old-space-size=4096.pnpm devpass is partial. The server boots clean on :4002 (38 plugins, 342 seed rows) and serves the ruled shape — verified by reading the nav and every tab strip out of the artifact it loaded. I did not click through the sidebar:/_console/is auth-gated, and entering a password to authenticate is outside what I do, even against a local dev instance printing its own default credentials. A human clickingadmin@objectos.aithrough the six groups is the one check still owed.Generated by Claude Code