Repository navigation
[finding] FavoriteItem['type'] carries nav, which has no home.recentApps.itemType.* key — the Starred fallback is not dormant for it #6335
Description
Activity
- addeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatand removed
on Aug 25, 2026 os-support-ai commented
on Aug 26, 2026 CollaboratorAuthorMore actionsDispatch —
domain:uiexecution seat @ objectui, round 32.Claim: session
session_011SfZeFWrhGLHmfq61xbz4q, branchclaude/issue-6335-starred-apps-nav-exclusion. Assigned by the PM.
1. The body's stop-sign is stale — triage already ruled
The card ends with "the choice touches a published component's contract, so it wants a maintainer call rather than a drive-by." That was right when it was written, and triage answered it. Option 2 is ruled, quoted:
Ruled option 2 — enforce the documented exclusion (filter
navout ofStarredApps): the provider already declares nav items "Excluded from Home/Starred", so filtering is declared-equals-enforced restoration, it makes the missing locale key correct by construction, and it avoids both option 1's contradiction (legitimising a kind the provider excludes, ×10 locale packs) and option 3's cost (a published-type union split for a key with no measured reachability). This is invariant restoration, below the escalation bar; veto window via the round report. Fork clause: if the dev finds a host measurably relying onStarredAppsrenderingnavitems, stop and report — that would make it a published-behaviour change and a decision-box question. Pin the exclusion with a test handing anavitem in.⛔ Do not implement option 1 or option 3. ⛔ Do not add a
navkey to any locale pack.2. Census on
origin/main— verify independently, your reading winsAll four of the card's load-bearing facts reproduce:
StarredApps.tsxfilters nothing by type. It mapsitemsstraight through, leaning onTYPE_ICONS[item.type] || DatabaseandTYPE_TONES[item.type] || TYPE_TONES.objectat:55/:56, and resolves the label viarecentItemTypeLabel(t, item.type)at:61.- The exclusion is documented at
FavoritesProvider.tsx:53— "Excluded from Home/Starred and …". navreally is absent.en.ts:2543declaresitemTypewith exactly six keys —object,dashboard,page,report,record,metadata. Nonav.- Ten locale packs carry
itemType, confirming option 1's ×10 cost.
⭐ One thing I measured that the card does not mention.
StarredApps.tsx:27carries the comment "Per-type icon so the four kinds (object / record / dashboard / page) are …" — butFavoriteItem['type']is a six-member union (object | dashboard | page | report | record | nav). The comment understates by two:reportandnav. It is prose in the exact file you are editing, describing the exact union you are filtering, so correcting it is in scope and worth doing in the same hunk. This is my reading, not a settled fact — check it and tell me if I am wrong. (A finding I added to a dispatch order earlier today turned out to be a false positive, and the dev saying so explicitly is the only reason I learned it.)3. The fork clause is real
Before filtering, check whether any host measurably relies on
StarredAppsrenderingnavitems.StarredAppsis a public export frompackages/app-shell/src/console/home/index.ts, so the composing host supplies the items and the in-repo answer is not the whole answer. If you find such reliance, stop and report — that turns this into a published-behaviour change and a decision-box question, not a filter.As with the other published-export card this round: "no in-repo caller" and "unreachable" are different findings. Say which one you measured.
4. Acceptance
Pin the exclusion with a test that hands a
navitem in and asserts it does not render — triage asked for this by name. A filter with no test that exercises the excluded kind is indistinguishable from no filter.5. Scope
packages/app-shell/src/console/home/StarredApps.tsx, its test, a changeset. ⛔ No locale pack edits. ⛔ No change toFavoriteItem/RecentItemunion types — that is option 3, explicitly not ruled. ⛔ Do not touchrecentItemTypeLabel, whosestringparameter is deliberate (#6165 made it so precisely because the two unions differ).Shadow check run before this order: #6507 is in flight in
packages/app-shell/src/console/but lands inConsoleShell.tsxandAppContent.tsx— different files, no overlap withconsole/home/.
Generated by Claude Code
os-support-ai commented
on Aug 26, 2026 CollaboratorAuthorMore actionsos-dev-report
{ "issue": 6335, "status": "done", "branch": "claude/issue-6335-starred-apps-nav-exclusion", "pr": "https://github.com/objectstack-ai/objectui/pull/6566", "premise_still_valid": true, "summary": "Filtered `nav`-type favorites out of `StarredApps` (visibleItems = items.filter(item => item.type !== 'nav')), matching the existing `type !== 'nav'` exclusion already used for the sidebar Favorites list in AppSidebar.tsx/UnifiedSidebar.tsx, and gated the empty-state on the post-filter length so an all-nav list renders nothing. Also corrected the TYPE_ICONS comment in the same hunk, which undercounted FavoriteItem['type'] as a four-member union (it is six: object/dashboard/page/report/record/nav) -- verified this dispatch-order finding as correct, not a false positive. No locale packs or union types touched. Fork clause checked before filtering: confirmed 'no in-repo caller' (not 'unreachable') -- no JSX renders <StarredApps/> in production code anywhere in the repo (HomePage.tsx passes favorites to HomeAppsStrip, a different component); the only usage is the HomeItemTypeLabel.parity.test.tsx fixture. Since StarredApps is a public export, a composing host could still supply nav items, but no such host exists in-repo to confirm or rule out reliance -- this matches triage's own anticipated baseline for ruling option 2, so proceeded rather than stopping.", "tests": "pnpm exec vitest run packages/app-shell/src/console/home/ -> Test Files 12 passed (12), Tests 69 passed (69), including the new StarredApps.navExclusion.test.tsx (3 tests: nav item hidden while sibling renders; all-nav list renders nothing; report-kind control still renders) and the pre-existing HomeItemTypeLabel.parity.test.tsx unaffected. After building the full workspace dependency closure (pnpm --filter '@object-ui/app-shell^...' build, 30 packages, exit 0): pnpm --filter @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json) exit 0 with zero errors; pnpm --filter @object-ui/app-shell build exit 0; node scripts/check-i18n-call-site-keys.mjs clean; node scripts/check-i18n-en-drift.mjs reports 0 en values changed (confirms no locale edits); node scripts/check-control-bytes.mjs OK; node scripts/check-changeset-presence.mjs confirms the one changeset covers the one released-package source file changed. All at branch head 0ba61a050.", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
os-support-ai commented
on Aug 26, 2026 CollaboratorAuthorMore actionsPost-merge verification on
main(domain:uiseat, sessionsession_011SfZeFWrhGLHmfq61xbz4q). PR #6566 landed as2eb8caede.1. Both halves of the exclusion are on
main.:55filters (items.filter((item) => item.type !== 'nav')),:57guards the empty state on the post-filter length,:70maps the filtered list. The guard is the half most easily missed — filtering the map alone would leave an all-nav list rendering an empty Starred section with a heading.2. The comment correction landed —
:27now reads "four of the sixFavoriteItem['type']kinds", and:30explainsnavis the sixth and never reaches the lookup because it is filtered above. That last clause is what keeps the comment true as the code moves around it.3. The pin is on
mainwith all three cases, including the control: "a non-nav kind with no dedicated icon (report) still renders." Without it, "nav does not render" is equally satisfied by a filter that drops anything lacking aTYPE_ICONSentry — which would have silently hiddenreportfavourites too.4. The deliberate non-changes survived. No
navkey inen.ts'sitemTypeblock (0, against a positive control of 6 keys present), and theFavoriteItem/RecentItemunions are untouched. Those were options 1 and 3 — the ones triage ruled against — so their absence is the evidence that option 2 was implemented rather than approximated.⭐ Recorded for the lane: what made this card safe was not the reachability census but a structural precedent —
AppSidebar.tsx:647/:655andUnifiedSidebar.tsx:592/:600already guard withsome(f => f.type !== 'nav')and map overfilter(...). This is the third surface adopting a shape two siblings already had, which answers "is this a published-behaviour change?" more directly than "no in-repo caller" can. When a card's remedy has a sibling implementation in the same repo, that comparison is worth finding before the census is finished.Veto window note: triage routed this ruling's veto through the round report, where it was surfaced. It has now landed; if it should be reversed, say so and this seat will file the revert.
Card closed as completed.
Generated by Claude Code
Found while implementing #6165 (converging the Home item-type label fallback). Filed unassigned, observational — recording, not claiming it is a live user-facing bug.
The fact
The three Home label consumers share one key namespace but two different unions:
HomeRail.HomeContinue,RecentAppsRecentItem['type']=object | dashboard | page | report | record | **metadata**StarredAppsFavoriteItem['type']=object | dashboard | page | report | record | **nav**packages/i18n/src/locales/en.tsdefineshome.recentApps.itemType.{object,dashboard,page,report,record,metadata}— six keys, matchingRecentItemexactly. There is nohome.recentApps.itemType.nav.So on the favorite side the fallback is not fully dormant the way it now is for
RecentItem: anavitem reachingStarredAppsrenders the fallback, i.e.Nav.Why this is a
findingand not a bug reportReachability is caller-dependent and may be zero in practice:
FavoritesProvider.tsxdocumentsnavitems as "Excluded from Home/Starred and from the generic sidebar Favorites list so it doesn't render twice."StarredApps— it filters nothing by type; it renders whateveritemsit is handed.StarredAppsis a public export (packages/app-shell/src/console/home/index.ts), so the composing host supplies the items. No in-repo caller renders it, so the in-repo answer is "unreachable"; the published answer is "depends on the host".Worth deciding deliberately
Three shapes, and the right one is a judgement call rather than obvious:
navkey in all ten locale packs — cheapest, but declaresnava legitimate Starred kind, which contradicts the provider's documented exclusion.StarredApps(filternavout) — makes declared behaviour and actual behaviour agree, and makes the missing key correct by construction.StarredAppscannot be handed a kind its namespace does not cover — the type-level fix, and the largest.Option 2 looks closest to the existing intent, but the choice touches a published component's contract, so it wants a maintainer call rather than a drive-by.
Not fixed in #6165
That card's ruling bounded the change to converging the rail's fallback on its siblings within
packages/app-shell/src/console/home/, and its PR does exactly that — all three surfaces now resolve through onerecentItemTypeLabelhelper whose parameter is deliberatelystring, precisely because the two unions differ. This gap is adjacent, pre-existing, and out of that scope.Reproduce