Repository navigation
decision: should dashboard and report routes drop their 「仪表盘」/「报表」 type crumb, as page routes dropped 「页面」? #12273
Description
Filing gate ②: a decision only the maintainer can make. The maintainer's ruling on objectstack-ai/cloud#2768 (6118501670) named the 「页面」 crumb only. Whether it extends to two more crumbs of the same kind is the maintainer's to say.
- Who acts after the ruling: the
domain:uiseat that dispatches it (objectuiAppHeader.tsx,@object-ui/i18npacks). - Raised by:
domain:uiseat 2 (seat post objectui#9771),session_01G5TSaEwbEQsKMjhzTB4rEd, from objectui#12198's dev report (6124626764, out-of-scope finding 2) and contract review6125264132. - Dedupe: REST issue list of objectui, all states, updated since 2026-08-01 (710 issues), matched for
breadcrumb+dashboard(s)|report(s)+crumb: 11 hits. None asks this. The nearest is objectui#12198 (closed, the Pages crumb).
维护者速读
在应用里打开一个仪表盘,顶栏面包屑是「应用 › 仪表盘 › Ops Board」;打开报表是「应用 › 报表 › 某报表」。中间这一格是元数据类型名,点了只回到应用首页,和你已经裁掉的「页面」是同一种东西。选项:A 一并去掉(推荐);B 保持不动;C 改成指向真实的仪表盘/报表列表页。选哪个?
os-decision-facets
- ① 项目长远合理性:A 收窄——面包屑只写用户去过的地方,三类路由规则统一;C 扩大(新增列表路由)。
- ② 实际业务拉动:今天无人报告这两处;「页面」那次来自 cloud 首页走查。零拉动,但 A 是删除而非新增,成本低。
- ③ 防 AI 犯错:显示层文字,不涉及 AI 写元数据;A 少两个要翻译的 key,无反向风险。
- ④ 创业阶段不扩散:A 删两个已发布 key(删除优于维护);C 新增路由与页面,属扩散。
Prior rulings read: breadcrumb pages crumb metadata type → 1 hit (objectstack-ai/cloud#2768 6118501670, quoted on objectui#12198); ADR none; thread: objectui#12198.
One-line problem
On a dashboard or report route the top bar draws a crumb that names a metadata type ("Dashboards" / "Reports") and links back to the app's home, which the app pill already does. It is the crumb class the maintainer removed for pages.
Measured (objectui main 7af0ab37)
packages/app-shell/src/layout/AppHeader.tsx:397-398:routeType === 'dashboard'pushes{ label: t('console.breadcrumb.dashboards'), href: baseHref }. Then, at:424-425,routeType === 'report'pushesconsole.breadcrumb.reportsthe same way.- One reader each.
git grepfinds each key in exactly one non-pack file,AppHeader.tsx. Control:console.breadcrumb.marketplacehits 8 files. - No list page to point at. The app routes are
dashboard/:dashboardNameandreport/:reportName(AppContent.tsx:1150-1151); there is no in-app dashboards or reports list route. - objectui#12198's harness rendered
["console.breadcrumb.dashboards", "Ops Board"]on/apps/APP/dashboard/ops_board. The report trail was read from the code, not rendered.
Options
| what | customer-visible result | work | |
|---|---|---|---|
| A | drop both type crumbs; retire console.breadcrumb.dashboards and console.breadcrumb.reports from the ten packs |
trail reads app › dashboard (or report), like pages | domain:ui · 1 PR · precedent objectui#12247 (+322/−13; its crumb half was a few lines plus one pack line × 10, the rest pinned Studio handles) · @object-ui/i18n minor with a BREAKING note, Clause-②: no (narrowing), one contract-tier review |
| B | leave as is | two route types keep a crumb pages no longer have | none |
| C | keep the crumb but link it to a real list of the app's dashboards / reports | the crumb becomes a place | domain:ui · new list routes and pages · no precedent; not measured |
In business terms. A makes the three object-less route types read the same: app, then the thing you opened. B accepts one rule for pages and another for dashboards and reports. C builds a feature nobody asked for, to justify a crumb.
Recommendation
A. Same principle as the Pages ruling, one reader per key, no list page exists, and removal shrinks the published pack. Fallback: B (no work; the inconsistency stays). Confidence gap: the report trail was read, not rendered; whether any host outside this repo reads the two pack keys is not measurable from here (the same gap the Pages retirement accepted).
Self-check: judged on ① alone, A. Do ② ③ ④ flip it? No.
After the ruling
- A: this seat files one
domain:uicard with exactly objectui#12198's crumb half for the two branches: pins that the trail after the pill is the item alone, the keys retired from ten packs, aminorchangeset with a BREAKING note, and a contract-tier review before the queue. - B: this card closes
not_planned, citing the ruling. - C: the card goes back to triage to size the list pages.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 12, 2026
Triage: decision-box entry check. Not a product fork, so it executes the cloud#2768 ruling:
enhancement·priority:p3·domain:ui·area:records, intopm:queueTriage seat (seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-12T21:55Z. ⛔ Not a claim, ⛔ not a dispatch.6118501670): a metadata-type crumb that links back to the app's home. Dashboards and reports have the same crumb, the same single reader per key, and no list page to point at.minorchangeset carrying a BREAKING note;needs-user-decisionis removed. If the maintainer reads it differently, a word reopens it.objectstack-fleet commentedon Oct 12, 2026
Claim: PM loop round 3 (triage
6133338003: the card's A, the cloud#2768 ruling applied to the two remaining route types; the trail after the app pill is the item alone, and both keys are retired from the ten packs)Session:
session_01CsyMRsFJBKNEMa4oPY1b5zAccount:
zhuangjianguo(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12273-dashboard-report-crumbWorktree:
objectui-issue-12273Domain:
domain:uiSeat:
domain:ui#1File surface: the top bar's type crumbs for dashboard and report routes, read on objectui
main1fb1cedat 2026-10-12T22:57Z (stop on breach; explain in the report):packages/app-shell/src/layout/AppHeader.tsx, therouteType === 'dashboard'androuteType === 'report'branches ofextraSegments, which pushconsole.breadcrumb.dashboards/console.breadcrumb.reportslinking to the app's base.console.breadcrumb.dashboardsandconsole.breadcrumb.reportsin the tenpackages/i18n/src/locales/*.tspacks, each with one non-pack reader (AppHeader.tsx, read bygit grep; controlconsole.breadcrumb.marketplaceanswers 2 non-pack files)..changeset/12273-dashboard-report-crumb.md(@object-ui/i18nminorwith a BREAKING note, plus@object-ui/app-shell), following objectui#12198's crumb half (PR objectui#12247) as precedent.Container & model:
S,mode:subagent,model: default tier — dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate"Clause-②: no
Clause-② reason: narrowing. Retiring two published language-pack keys narrows
@object-ui/i18n's published key set (its packs are published), so an at-tier contract review is owed before the queue; nothing is widened.Responsibility:
objectui's console top bar (@object-ui/app-shell AppHeader), which draws a metadata-type crumb linking to the app's home on dashboard and report routes | the maintainer removed the same crumb class for pages (objectstack-ai/cloud#2768, 6118501670; objectui#12198) | every console user on a dashboard or report routeThread-read: 6133338003
Serial constraints cleared: read at 2026-10-12T22:57Z on objectui
main1fb1ced. No open PR touchesAppHeader.tsxor any language pack (open: objectui#12253, ci(spec-main-shape-gate): drop the merge_group trigger now the context is out of the required set (objectui#12252) #12262, ci(type-check): the affected speed builds the packages the repo-root setup program imports (objectui#12272) #12277). Dispatched in the same wave as objectui#12274, whose surface is disjoint.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
os-dev-report
{
"issue": 12273,
"status": "done",
"branch": "claude/issue-12273-dashboard-report-crumb",
"pr": "#12279",
"session": "session_01CsyMRsFJBKNEMa4oPY1b5z (subagent; the dispatching seat's harness-stamped id, which the relay derived from the container)",
"premise_still_valid": true,
"summary": "Executed triage 6133338003 (the card's option A, the cloud#2768 ruling applied to dashboards and reports), mirroring PR objectui#12247's crumb half. AppHeader's extraSegments no longer pushes the console.breadcrumb.dashboards / console.breadcrumb.reports type crumb (each linked only to the app's base), so on /apps/APP/dashboard/NAME and /apps/APP/report/NAME the trail after the app pill is the item alone; nothing else in AppHeader.tsx moved. Both keys are retired from all ten packs (zh's 报表 ruling comment sat on the reports key and leaves with it), with a changeset declaring @object-ui/i18n minor plus a BREAKING note naming both keys, and @object-ui/app-shell patch. New pin AppHeader.dashboardReportCrumb-12273.test.tsx renders the real AppHeader under a real I18nProvider (en, zh) on both routes, plus page/object/record routes and a system-route CONTROL. Draft PR objectui#12279 is open, assignee zhuangjianguo, labelled needs:contract-review (read back), body 8109 bytes stored identical.",
"zone2_measurements": [
"1 CONFIRMED on 1fb1ced: the dashboard branch pushed { label: t('console.breadcrumb.dashboards'), href: baseHref } and the report branch pushed console.breadcrumb.reports the same way.",
"2 CONFIRMED, re-measured over the whole tree with git grep -n -F on 1fb1ced: console.breadcrumb.dashboards 1 file (AppHeader.tsx); console.breadcrumb.reports AppHeader.tsx plus 2 lines of packages/i18n/CHANGELOG.md (release history of the 报表 ruling, not a reader; published CHANGELOG not edited); control console.breadcrumb.marketplace 8 files, 2 of them non-CHANGELOG (AppHeader.tsx, AppHeader.marketplaceBreadcrumb-10900.test.tsx). No dynamic console.breadcrumb head. Sibling objectstack checkout at df7a1379: 0 hits for both keys and also 0 for console.breadcrumb.marketplace/system, so that tree reads no console.breadcrumb key and the control cannot ring there; a host outside these repos stays unmeasured, as for the Pages retirement. No reader outside packages//src: plan unchanged.",
"3 DONE: both routes rendered in the pin (the report trail is rendered for the first time)."
],
"tests": "All at 12863df (the only commit; the tree was clean for every run). (1) Build closure: os-verify-lock -c 'pnpm exec turbo run build --filter=@object-ui/app-shell^... --concurrency=2' -- 'Tasks: 28 successful, 28 total', VERDICT command-exit 0. (2) New pin alone: 'Test Files 1 passed (1) / Tests 9 passed (9)'. (3) pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/layout/ packages/i18n/ -- 'Test Files 148 passed (148) / Tests 1790 passed | 13 skipped (1803)', VERDICT command-exit 0. (4) The 15 test files outside layout/ that name AppHeader (app-shell + apps/console) -- 'Test Files 15 passed (15) / Tests 118 passed (118)'. (5) pnpm --filter @object-ui/app-shell --filter @object-ui/i18n type-check -- 'packages/i18n type-check: Done', 'packages/app-shell type-check: Done', VERDICT command-exit 0; tsc -p tsconfig.test.json --listFilesOnly in app-shell lists the new test (1 hit; positive control the 12198 pin, 1 hit). ABLATION via objectstack scripts/ablation-replace.mjs wrap mode (relative import of ../AppHeader resolves src, no build needed): leg A planted the dashboards push back -- anchor 1 to 0, blob 2fc695ce6437 to f8be9f5247ea, 'Tests 2 failed | 7 passed (9)', both dashboard cases received ['console.breadcrumb.dashboards', 'Ops Board']; leg B planted the reports push -- 'Tests 2 failed | 7 passed (9)', received ['console.breadcrumb.reports', 'Sales Summary']; each restore: blob after restore == blob at HEAD 2fc695ce6437, git diff HEAD empty. The first leg-A attempt was a refused no-op (its replacement contained the anchor, count 1 to 1, the tool exited 1 and restored before any test ran); re-anchored and re-run as above.",
"gates": [
{
"gate": "build closure (turbo, app-shell^...)",
"exit": 0,
"verdict": "28 successful, 28 total"
},
{
"gate": "vitest packages/app-shell/src/layout/ packages/i18n/",
"exit": 0,
"verdict": "148 files passed, 1790 passed, 13 skipped"
},
{
"gate": "vitest AppHeader-naming tests outside layout/",
"exit": 0,
"verdict": "15 files passed, 118 tests"
},
{
"gate": "type-check @object-ui/app-shell + @object-ui/i18n",
"exit": 0,
"verdict": "both Done"
},
{
"gate": "eslint touched files (narrowed, proven)",
"exit": 0,
"verdict": "12 files, 0 errors, 0 ignored; 22 no-explicit-any warnings in AppHeader.tsx, 22 at base; new test 0. Population: each package lint script is eslint . under root eslint.config.js, and the 12 touched source files all came back as results. Invariance: no parserOptions.project/projectService in eslint.config.js, no eslint-rules/ rule reads another file, so untouched files cannot change verdict."
},
{
"gate": "pnpm check:i18n-keys",
"exit": 0
},
{
"gate": "pnpm check:i18n-drift",
"exit": 0,
"verdict": "0 en value(s) changed (0 key(s) added, 2 removed)"
},
{
"gate": "pnpm check:i18n-dead-keys",
"exit": 0,
"verdict": "report-only"
},
{
"gate": "pnpm check:i18n-designer-parity",
"exit": 0
},
{
"gate": "pnpm check:control-bytes",
"exit": 0,
"verdict": "OK (scanned 8559 tracked text files)"
},
{
"gate": "pnpm check:new-line-citations",
"exit": 0,
"verdict": "0 new citation(s)"
},
{
"gate": "node scripts/check-changeset-presence.mjs",
"exit": 0,
"verdict": "12 source files of 2 released packages, 1 changeset"
},
{
"gate": "node scripts/check-changeset-no-major.mjs",
"exit": 0
},
{
"gate": "node scripts/check-changeset-fixed.mjs",
"exit": 0
},
{
"gate": "pnpm check:changeset-claims",
"exit": 0
},
{
"gate": "node scripts/check-changeset-overwrite.mjs",
"exit": 0
},
{
"gate": "pnpm check:pending-changeset-literals",
"exit": 0
},
{
"gate": "pnpm check:vi-mock-specifiers",
"exit": 0
},
{
"gate": "pnpm check:vi-mock-override-shape",
"exit": 0
},
{
"gate": "pnpm check:vi-mock-inherit",
"exit": 0
},
{
"gate": "pnpm check:test-path-roots",
"exit": 0
},
{
"gate": "node scripts/check-type-check-coverage.mjs",
"exit": 0
},
{
"gate": "pnpm check:unreferenced-sources",
"exit": 0
},
{
"gate": "node scripts/check-eager-locale-catalogues.mjs",
"exit": 2,
"verdict": "NOT MEASURED: eager-locale-catalogues, reason: PREREQUISITE NOT MET (needs a built apps/console bundle); left to CI. The diff only shrinks the packs."
}
],
"gates_note": "Derived by hand from objectui package.json and .github/workflows at 1fb1ced (objectui has no dispatch-gates.mjs); exit codes captured before any pipe (cmd to LOG; EXIT=$?). origin/main moved to 48fb558 (objectui#12277, ci type-check) after the branch point; it touches none of these paths and was not merged in.",
"files_changed": [
".changeset/12273-dashboard-report-crumb.md",
"packages/app-shell/src/layout/AppHeader.tsx",
"packages/app-shell/src/layout/tests/AppHeader.dashboardReportCrumb-12273.test.tsx",
"packages/i18n/src/locales/ar.ts",
"packages/i18n/src/locales/de.ts",
"packages/i18n/src/locales/en.ts",
"packages/i18n/src/locales/es.ts",
"packages/i18n/src/locales/fr.ts",
"packages/i18n/src/locales/ja.ts",
"packages/i18n/src/locales/ko.ts",
"packages/i18n/src/locales/pt.ts",
"packages/i18n/src/locales/ru.ts",
"packages/i18n/src/locales/zh.ts"
],
"line_budget": "n/a: no skills/ and no line-budgeted ledger touched. Diff 13 files, +251/-34 (git diff --shortstat 1fb1ced 12863df).",
"deviations": [
"Zone 3 asked for 'a retired-key pin in the shape objectui#12247 used'. PR objectui#12247 added no pack-side retirement pin; its crumb pin is that shape (a re-planted crumb renders the retired key string), and this PR follows it. The harness is AppHeader.systemBreadcrumbs-10969's (real I18nProvider over the published packs, en and zh), not 12198's identity-t one. Both make a planted crumb read as its key string, as the ablation shows. No i18n pack-absence pin was added; the PR's Acceptance notes say so.",
"The first ablation attempt (leg A) was a no-op that ablation-replace refused before any test ran. It is reported in the tests field and the PR body, not silently re-run.",
"Commit trailers: AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude), over the harness reminder's model-named Co-Authored-By, per the harness's own precedence sentence."
],
"mcp_calls": "0",
"api_writes": "3 relay strokes, each one POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]: (1) pr_create = POST /repos/objectstack-ai/objectui/pulls (draft forced) + its assignees leg POST /repos//issues/12279/assignees; (2) label-write = POST /repos//issues/12279/labels (needs:contract-review, read back MATCHES); (3) this os-dev-report comment = POST /repos//issues/12273/comments. Plus 2 git pushes (empty branch probe, then 12863df), which are not REST writes.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted in PR Acceptance notes, not filed. Observation only: check:i18n-dead-keys is report-only and in no workflow, so a pack key re-added with no reader would go unflagged by CI. That holds equally for console.breadcrumb.pages (PR objectui#12247). A re-added reader goes red in the new pin, and in check:i18n-keys while the key is absent."
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Seat ACCEPT: objectui PR #12279 at
12863df·domain:uiseat 1 ·session_01CsyMRsFJBKNEMa4oPY1b5z· 2026-10-12T23:22ZVerdict: ACCEPT. Reviewed on GitHub against the claim
6134224892and triage6133338003, not against the report. It is gated on the at-tier contract review the narrowing owes, which runs once CI on this head has converged.PR form. Draft, base
main, assigneezhuangjianguo. Line 1 isFixes #12273and line 2 isClause-②: no (narrowing); a scan of the whole body found no other closing verb next to a card number.needs:contract-reviewis hung.Scope. 13 files, +251 / −34, all inside the claimed surface.
check-governed-merges --prreads NOT governed, 285 lines. Nothing is undercontent/docs/releases/.The diff, read.
AppHeader.tsxdrops exactly the twoextraSegments.pushcalls (console.breadcrumb.dashboards,console.breadcrumb.reports) and adds a comment citing the ruling. Nothing else in the file moves.zh.tsthe removal also takes the objectui#6166 terminology note (报表, not 报告) that sat on the retired key.navReport,navTypeReport, the command palette'sreports,typeReports,badgeReport, the nestedreport) all read 报表, so nothing is left inconsistent for the note to defend. Accepted as is.The changeset, sentence by sentence.
@object-ui/i18nminorwith a BREAKING note naming both retired keys, and@object-ui/app-shellpatch, with nomajor.packages/i18n/CHANGELOG.md, not readers, and the published CHANGELOG is rightly not edited.Evidence, as reported.
I18nProvider(en, zh); the report trail is rendered for the first time.Out of scope. That
check:i18n-dead-keysis report-only is an Acceptance note with no carrier, an observation and not a filing-gate class.Next (the seat's). CI on
12863dfis converging. Once it is green, an isolated at-tier contract review renders its record on this head. On PASS the seat stripsneeds:contract-reviewand runspr_ready+automerge_enable.Implemented-by:
claude/issue-12273-dashboard-report-crumb(mode:subagent dev of this seat)Reviewed-by:
session_01CsyMRsFJBKNEMa4oPY1b5zGenerated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Landed: objectui PR #12279 →
main9f282ef·domain:uiseat 1 ·session_01CsyMRsFJBKNEMa4oPY1b5z· 2026-10-12T23:55Zcompletedby the PR'sFixes #12273.main9f282efare blob-identical to the head the contract review judged,12863df(record6134710052, PASS).pm:dispatchedremoved (read back);domain:ui,area:records, type and priority stay.@object-ui/i18nminorwith a BREAKING note naming the two retired keys;@object-ui/app-shellpatch) rides the next objectui release.Generated by Claude Code