You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
spec: a navigation item of type 'report' without reportName targets the app's report index; the console stops injecting the "All reports" row; ⌘K finds reports from the report registry #27525
Seam: spec:NavigationItemSchema (packages/spec/src/ui/app.zod.ts, the type: 'report' variant) → consumer ui/packages/app-shell/src/layout/UnifiedSidebar.tsx (the injected 「全部报表」 row, objectui#13020) and the ⌘K command palette's report matching. Clause-②: yes — the variant's accept set widens (a report item may omit reportName), so the spec seat owes the contract review; the consumer end is claimed with it.
Source (main 273137d227; HotCRM 47a0666543)
NavigationItemSchema variants: object / page / url / dashboard / report (one report, reportName required). No item can target the app's report index at <app>/reports.
The console therefore injects a static 「全部报表」 row at the bottom of EVERY non-Studio app's sidebar (UnifiedSidebar.tsx ~line 598, objectui#13020), apps without reports included (the index then says there are none).
⌘K finds a report only through a navigation entry (HotCRM crm.app.tsgroup_reports comment), so HotCRM declares one nav entry per report (ten) in a collapsed group — and gets the injected row as a second entry to the same reports.
Target (maintainer, 2026-10-29, verbatim: 「报表按这版立两张卡:spec(索引型导航项 + 停止注入 + ⌘K 走注册表)」; on the model: 「报表是否建议配置成一个自定义菜单,加上才有」 — the entry exists only when the author adds it, as Salesforce / Dynamics / Zoho do)
type: 'report' with reportName absent = the app's report index (<app>/reports); with reportName = that report, as today. The describe says so; validate-* refuses nothing new (an absent name is now legal). ADR-0087: a widening, not a retirement; the authorable-surface baseline follows.
The console stops injecting the 「全部报表」 row for every app; it draws the index entry only where the app's navigation declares one. Studio unchanged.
⌘K matches reports from the report registry the app ships (the member's readable set), not from navigation entries, so an app no longer needs one nav entry per report to make them searchable.
HotCRM follow-up (filed in hotcrm after this lands): replace the ten per-report entries with one index entry.
Acceptance
Spec pin: a report item with no reportName parses and the Studio navigation inspector offers 「报表索引」 as that item's face; the describe and the generated reference say what it does.
Console pins: no injected row on an app whose navigation has no report-index item; the index entry drawn where declared; ⌘K finds a report that has no nav entry.
Migration note in the changeset for apps relying on the injected row (one line to add to their navigation).
Filed by the epic PM session session_cdb7a717-def7-4e71-9988-f089fbaa18ff on 2026-10-29 on the maintainer's instruction; design board SidebarReports.dc.html on evidence branch claude/record-page-v2-evidence-20261027b @ 72cd481c4a (the 「加上才有」 model supersedes the board's 「并入组尾」 variant).
Claim: PM loop round 3 · 2026-10-29T11:18Z
Session: session_01WGufzgbJhFoXYsLSe5WSPP
Account: os-support-ai
Branch: claude/project-thread-1iqx7w (card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead of claude/issue-27525-<slug>)
Worktree: objectstack-27525
Domain: domain:spec
Seat: domain:spec#3
Ruling-ref: none (the maintainer's target is quoted verbatim in the card body: 「报表按这版立两张卡:spec(索引型导航项 + 停止注入 + ⌘K 走注册表)」 and 「加上才有」)
File surface: the type: 'report' variant of NavigationItemSchema (packages/spec/src/ui/app.zod.ts) and its describe; the console readers of a nav item's reportName (UnifiedSidebar.tsx and the injected row, route resolution, Studio's navigation inspector); the ⌘K report matching; shipped example / dogfood apps that relied on the injected row; their tests; regenerated schema / references / baseline / form translations; one root changeset per touched published package (stop on breach; explain in the report)
Container & model: M, mode:thread, model: TIER_DEFAULT — --tier: no path-derived mandate (a widening; the contract review is triage's), effort: high
Clause-②: yes (widening)
Metadata-protocol: none
Responsibility: the one unclaimed p1 domain:spec card; seat 1 told through the coordinator
Thread-read: none
Premise: to be measured first by the dev on origin/main57c51aab: a report nav item without reportName is refused, every non-Studio app's sidebar carries an injected 「全部报表」 row, and ⌘K finds a report only through a nav entry
Serial constraints cleared: no open PR on these files that the seat knows of; the dev re-checks before editing
{
"issue": 27525,
"status": "done",
"branch": "claude/project-thread-1iqx7w",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27566",
"head": "dd0bd483ff19e86361f5546ea86318bc76731327",
"session": "session_01WGufzhEW5k2a4Vd5KSupfu",
"premise_still_valid": true,
"summary": "Measured on origin/main 57c51aab: NavigationItemSchema refuses { type: 'report' } with no reportName (invalid_type at reportName), and UnifiedSidebar injects a static All reports row (sidebar-report-index) under !isStudioApp for every app. Target 3's premise does not hold: CommandPalette already lists the app's shipped, member-readable reports through useAppReportEntries (objectui#13020/#13273/#26892), pinned by AppReportIndex-13020.test.tsx, so it is reused and pinned under an index-only navigation, not rebuilt. Now reportName is optional (absent = the app's report index, describe + TSDoc say so, reference regenerated); resolveHref answers BASE/reports and the active-row election follows; a label-less index entry asks the host's new { kind: 'reportIndex' } label target, which the console answers with sidebar.allReports; the sidebar injects nothing; Studio's nav inspector shows the report picker's empty face as 报表索引 / Report index with a hint, the entry is no longer unbound, and navPayloadOf keeps it on save (NAV_TARGET_OPTIONAL); the metadata-admin inspector and preview treat it as the index. examples/app-showcase and examples/app-todo (the shipped apps that ship reports) declare the entry; app-crm and app-multi-package ship no report. Five root changesets, all minor, the app-shell one carrying the one-line migration. Merged origin/main (no file overlap) before opening.",
"tests": "spec at 0b6a152e: test 751/751 files, 22330 tests; test:repo 86/86 files, 1432 tests; typecheck VERDICT command-exit 0. After the main merge (dd0bd483): spec build + check:generated all 14 up to date; spec test 752/752 files, 22341 tests. ui, 138 files importing or pinning the edited modules: first run 4 red, all pinning the old behaviour (bare report unbound / left out of save / not taken bare), updated; final on dd0bd483 Test Files 138 passed (138), Tests 1755 passed. ui type-check types/layout/i18n/app-shell all Done, VERDICT 0; full turbo build 115/115. Ablation: resolveHref index answer put back to '#' via ablation-replace.mjs (anchor 1->0, blob 9f866973->f4b35fdd): sidebar pins (b)x2 and (c) red, 3 failed | 13 passed; restored blob == HEAD, git diff HEAD empty. The ⌘K index-entry pin stays green under it (it asserts presence, not href).",
"gates": "dispatch-gates --commands: 108 at 01ed76af, same 108 at 0b6a152e. Serial pass: 103 exit 0; pnpm --dir ui exec vitest run scripts/ exit 1 (two 15 s sweep timeouts beside a locked run; those two files rerun alone 2/2 passed, 91 tests); check:skill-examples, check:dual-build-cjs-loads, check:i18n-coverage exit 3 (no dist) then exit 0 after the full build. dispatch-gates --ran: 108 derived, 108 run, 0 NOT-MEASURED, 0 UNRUN. After changeset regrade + merge: the five changeset gates exit 0; check-changeset-no-major --event (the PR body) exit 0, LEVEL AXIS added with no moved package graded patch. gen:authorable-surface-base refuses on the shallow clone; check:authorable-surface green (the base lists keys; ui/ReportNavItem:reportName stays). CI check-runs: in_progress at report time.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "0 — no GitHub MCP calls; GitHub reads were unauthenticated GETs through the proxy",
"api_writes": "2 relay writes as objectstack-fleet[bot]: pr_create (#27566, 16590 bytes read back identical), comment (this report on #27525). Plus 3 git pushes of the thread branch. No assignee, reviewer or label written.",
"writes": "git push x3; relay pr_create x1; relay comment x1",
"deviations": [
"Metadata-protocol: the claim says none; measured and declared added (a newly accepted shape), as the order's 'as measured' asks. Changesets carry added and grade every moved package minor.",
"Kept edits inside the claim's file surface: the teaching text in packages/cli/src/commands/explain.ts:226 and content/docs/ui/apps.mdx / reports.mdx was edited, then backed out; the ready patch is /mnt/project-files/seat3-orders/27525-teaching-text.patch.",
"The worktree ../objectstack-issue-27525 is kept for a patch round instead of removed after the PR opened.",
"The 13020 sidebar test file is moved and rewritten (UnifiedSidebar.reportIndexEntry-27525.test.tsx): its first assertion is now the opposite behaviour, so it was replaced, not duplicated."
],
"open_questions": [],
"out_of_scope_findings": [
"carrier: seat 3 · noted, not filed · os explain app (packages/cli/src/commands/explain.ts:226) and content/docs/ui/apps.mdx, reports.mdx do not teach the index form; none teaches a refused shape; patch at seat3-orders/27525-teaching-text.patch",
"carrier: none · noted in Acceptance notes · the Studio '+' sends a new report entry into the create-a-report flow, so an index entry is made by choosing type report and leaving the report unpicked",
"carrier: HotCRM follow-up (card Target 4) · replace HotCRM's ten per-report entries with one { type: 'report' } entry once this lands"
]
}
Claim amendment: two declarations and one surface addition · domain:spec seat 3 · session session_01WGufzgbJhFoXYsLSe5WSPP · 2026-10-29T13:14Z · same claim 6495221889, same branch claude/project-thread-1iqx7w
Metadata-protocol: added replaces none: a newly accepted shape (a report navigation item without reportName) is added, measured by the dev; the changesets are minor.
File surface adds the teaching text that names the report navigation item: os explain app in packages/cli, content/docs/ui/apps.mdx and content/docs/ui/reports.mdx, so they teach the index form in this PR.
Target 3's premise did not hold: ⌘K already reads the app's shipped, readable reports. The PR reuses that reader and pins it under an index-only navigation instead of rebuilding it.
Claim amendment: one surface addition · domain:spec seat 3 · session session_01WGufzgbJhFoXYsLSe5WSPP · 2026-10-29T15:39Z · same claim 6495221889, same branch claude/project-thread-1iqx7w
File surface adds docs/qa/platform-checklist/areas/platform-core.json (the nav-surfaces-render and builtin-apps-nav-render rows). Both rows expected the injected "All reports" entry this PR removes, so the PR would make them false; they now expect the report index only where the app's navigation declares it. QA checklist text, not a governed path.
seat ACCEPT (6501729633) on triage's PASS (6498961917, the spec face), merged through the merge queue at 2026-10-29T16:23Z, head 19f4cf83a, merge commit bf658d1b8f
origin/main
contains the merge commit (git merge-base --is-ancestor)
Delivered:
A report navigation item without reportName is accepted and opens the app's report index. The console draws the index only where an app's navigation declares it; the injected "All reports" row is gone. The showcase and todo examples declare it.
Both nav inspectors (Studio and metadata-admin) show a report item with no report as "Report index", and choosing it removes reportName rather than storing ''.
os explain app, content/docs/ui/apps.mdx, content/docs/ui/reports.mdx and the platform-core QA rows teach the index form.
Owed elsewhere: #27609 (the governed skills rows that teach only the named form). pm:dispatched is removed here; the card is closed by the merge.
Activity
objectstack-fleet commentedon Oct 29, 2026
domain:spec#3 · os-support-ai · session_01WGufzgbJhFoXYsLSe5WSPP
Claim: PM loop round 3 · 2026-10-29T11:18Z
Session:
session_01WGufzgbJhFoXYsLSe5WSPPAccount:
os-support-aiBranch:
claude/project-thread-1iqx7w(card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead ofclaude/issue-27525-<slug>)Worktree:
objectstack-27525Domain:
domain:specSeat:
domain:spec#3Ruling-ref: none (the maintainer's target is quoted verbatim in the card body: 「报表按这版立两张卡:spec(索引型导航项 + 停止注入 + ⌘K 走注册表)」 and 「加上才有」)
File surface: the
type: 'report'variant ofNavigationItemSchema(packages/spec/src/ui/app.zod.ts) and its describe; the console readers of a nav item'sreportName(UnifiedSidebar.tsxand the injected row, route resolution, Studio's navigation inspector); the ⌘K report matching; shipped example / dogfood apps that relied on the injected row; their tests; regenerated schema / references / baseline / form translations; one root changeset per touched published package (stop on breach; explain in the report)Container & model:
M,mode:thread,model: TIER_DEFAULT — --tier: no path-derived mandate (a widening; the contract review is triage's),effort: highClause-②: yes (widening)
Metadata-protocol: none
Responsibility: the one unclaimed p1
domain:speccard; seat 1 told through the coordinatorThread-read: none
Premise: to be measured first by the dev on
origin/main57c51aab: areportnav item withoutreportNameis refused, every non-Studio app's sidebar carries an injected 「全部报表」 row, and ⌘K finds a report only through a nav entrySerial constraints cleared: no open PR on these files that the seat knows of; the dev re-checks before editing
objectstack-fleet commentedon Oct 29, 2026
domain:spec#3 · os-support-ai · session_01WGufzhEW5k2a4Vd5KSupfu
os-dev-report
{ "issue": 27525, "status": "done", "branch": "claude/project-thread-1iqx7w", "pr": "https://github.com/objectstack-ai/objectstack/pull/27566", "head": "dd0bd483ff19e86361f5546ea86318bc76731327", "session": "session_01WGufzhEW5k2a4Vd5KSupfu", "premise_still_valid": true, "summary": "Measured on origin/main 57c51aab: NavigationItemSchema refuses { type: 'report' } with no reportName (invalid_type at reportName), and UnifiedSidebar injects a static All reports row (sidebar-report-index) under !isStudioApp for every app. Target 3's premise does not hold: CommandPalette already lists the app's shipped, member-readable reports through useAppReportEntries (objectui#13020/#13273/#26892), pinned by AppReportIndex-13020.test.tsx, so it is reused and pinned under an index-only navigation, not rebuilt. Now reportName is optional (absent = the app's report index, describe + TSDoc say so, reference regenerated); resolveHref answers BASE/reports and the active-row election follows; a label-less index entry asks the host's new { kind: 'reportIndex' } label target, which the console answers with sidebar.allReports; the sidebar injects nothing; Studio's nav inspector shows the report picker's empty face as 报表索引 / Report index with a hint, the entry is no longer unbound, and navPayloadOf keeps it on save (NAV_TARGET_OPTIONAL); the metadata-admin inspector and preview treat it as the index. examples/app-showcase and examples/app-todo (the shipped apps that ship reports) declare the entry; app-crm and app-multi-package ship no report. Five root changesets, all minor, the app-shell one carrying the one-line migration. Merged origin/main (no file overlap) before opening.", "tests": "spec at 0b6a152e: test 751/751 files, 22330 tests; test:repo 86/86 files, 1432 tests; typecheck VERDICT command-exit 0. After the main merge (dd0bd483): spec build + check:generated all 14 up to date; spec test 752/752 files, 22341 tests. ui, 138 files importing or pinning the edited modules: first run 4 red, all pinning the old behaviour (bare report unbound / left out of save / not taken bare), updated; final on dd0bd483 Test Files 138 passed (138), Tests 1755 passed. ui type-check types/layout/i18n/app-shell all Done, VERDICT 0; full turbo build 115/115. Ablation: resolveHref index answer put back to '#' via ablation-replace.mjs (anchor 1->0, blob 9f866973->f4b35fdd): sidebar pins (b)x2 and (c) red, 3 failed | 13 passed; restored blob == HEAD, git diff HEAD empty. The ⌘K index-entry pin stays green under it (it asserts presence, not href).", "gates": "dispatch-gates --commands: 108 at 01ed76af, same 108 at 0b6a152e. Serial pass: 103 exit 0; pnpm --dir ui exec vitest run scripts/ exit 1 (two 15 s sweep timeouts beside a locked run; those two files rerun alone 2/2 passed, 91 tests); check:skill-examples, check:dual-build-cjs-loads, check:i18n-coverage exit 3 (no dist) then exit 0 after the full build. dispatch-gates --ran: 108 derived, 108 run, 0 NOT-MEASURED, 0 UNRUN. After changeset regrade + merge: the five changeset gates exit 0; check-changeset-no-major --event (the PR body) exit 0, LEVEL AXIS added with no moved package graded patch. gen:authorable-surface-base refuses on the shallow clone; check:authorable-surface green (the base lists keys; ui/ReportNavItem:reportName stays). CI check-runs: in_progress at report time.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0 — no GitHub MCP calls; GitHub reads were unauthenticated GETs through the proxy", "api_writes": "2 relay writes as objectstack-fleet[bot]: pr_create (#27566, 16590 bytes read back identical), comment (this report on #27525). Plus 3 git pushes of the thread branch. No assignee, reviewer or label written.", "writes": "git push x3; relay pr_create x1; relay comment x1", "deviations": [ "Metadata-protocol: the claim says none; measured and declared added (a newly accepted shape), as the order's 'as measured' asks. Changesets carry added and grade every moved package minor.", "Kept edits inside the claim's file surface: the teaching text in packages/cli/src/commands/explain.ts:226 and content/docs/ui/apps.mdx / reports.mdx was edited, then backed out; the ready patch is /mnt/project-files/seat3-orders/27525-teaching-text.patch.", "The worktree ../objectstack-issue-27525 is kept for a patch round instead of removed after the PR opened.", "The 13020 sidebar test file is moved and rewritten (UnifiedSidebar.reportIndexEntry-27525.test.tsx): its first assertion is now the opposite behaviour, so it was replaced, not duplicated." ], "open_questions": [], "out_of_scope_findings": [ "carrier: seat 3 · noted, not filed · os explain app (packages/cli/src/commands/explain.ts:226) and content/docs/ui/apps.mdx, reports.mdx do not teach the index form; none teaches a refused shape; patch at seat3-orders/27525-teaching-text.patch", "carrier: none · noted in Acceptance notes · the Studio '+' sends a new report entry into the create-a-report flow, so an index entry is made by choosing type report and leaving the report unpicked", "carrier: HotCRM follow-up (card Target 4) · replace HotCRM's ten per-report entries with one { type: 'report' } entry once this lands" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:spec#3 · os-support-ai · session_01WGufzgbJhFoXYsLSe5WSPP
Claim amendment: two declarations and one surface addition ·
domain:specseat 3 · sessionsession_01WGufzgbJhFoXYsLSe5WSPP· 2026-10-29T13:14Z · same claim 6495221889, same branchclaude/project-thread-1iqx7wMetadata-protocol: addedreplacesnone: a newly accepted shape (areportnavigation item withoutreportName) isadded, measured by the dev; the changesets are minor.os explain appinpackages/cli,content/docs/ui/apps.mdxandcontent/docs/ui/reports.mdx, so they teach the index form in this PR.docs(cli, docs, qa): teach the report index nav entry; drop the injec…
fix(app-shell): metadata-admin's report picker reaches the report ind…
objectstack-fleet commentedon Oct 29, 2026
domain:spec#3 · os-support-ai · session_01WGufzgbJhFoXYsLSe5WSPP
Claim amendment: one surface addition ·
domain:specseat 3 · sessionsession_01WGufzgbJhFoXYsLSe5WSPP· 2026-10-29T15:39Z · same claim 6495221889, same branchclaude/project-thread-1iqx7wdocs/qa/platform-checklist/areas/platform-core.json(thenav-surfaces-renderandbuiltin-apps-nav-renderrows). Both rows expected the injected "All reports" entry this PR removes, so the PR would make them false; they now expect the report index only where the app's navigation declares it. QA checklist text, not a governed path.objectstack-fleet commentedon Oct 29, 2026
domain:spec#3 · os-support-ai · session_01WGufzgbJhFoXYsLSe5WSPP
ACCEPT → PR #27566 comment 6501729633
objectstack-fleet commentedon Oct 29, 2026
domain:spec#3 · os-support-ai · session_01WGufzgbJhFoXYsLSe5WSPP
Landed ·
domain:specseat 3 ·os-support-ai· 2026-10-29T16:24Z19f4cf83a, merge commitbf658d1b8forigin/maingit merge-base --is-ancestor)Delivered:
reportnavigation item withoutreportNameis accepted and opens the app's report index. The console draws the index only where an app's navigation declares it; the injected "All reports" row is gone. The showcase and todo examples declare it.reportNamerather than storing''.os explain app,content/docs/ui/apps.mdx,content/docs/ui/reports.mdxand the platform-core QA rows teach the index form.Owed elsewhere: #27609 (the governed skills rows that teach only the named form).
pm:dispatchedis removed here; the card is closed by the merge.