Repository navigation
Setup: one page header and one list shell for sys_* lists, metadata-type pages and settings pages #12606
Description
Source
Walked on objectui main 8415d9f11, the Setup app at 1024 px and 1280 px. Four page shells sit side by side in one sidebar:
sys_*record lists (Users, Teams, Invitations, Sharing Rules, Sessions, API Keys, Approval Requests, Audit Logs, Notification Preferences…): the console page header (icon, title, a kind chip such as "Identity" / "System-managed" / "Platform schema" / "Admin config", a one-line description) over the list chrome with view tabs, "N more", Filter / Sort / Display, the#column and an Actions column.- Metadata-type pages (Positions, Capabilities, Permission Sets at
/apps/setup/metadata/position?scope=environment and its siblings,packages/app-shell/src/views/metadata-admin/ResourceListPage.tsx): a breadcrumb "All Metadata Types › Position", the type name with chips (position· SECURITY · create-only), two stat tiles ITEMS 18 / FILTERED 18, a search box, an "All sources (18)" select, a NAME / LABEL / DESCRIPTION / ACTIVE / SOURCE table whose every row carries an "Artifact" chip, andNewat the right. - Settings pages (
/apps/setup/system/settings/mail,storage,ai,knowledge,feature_flags): a page header, a "← All settings" link, section headings with a muted sentence, fields and toggles. - Component pages (Packages, Packaged automation, Approvals Inbox, Audit Log Browser, Datasources, Connect an Agent, App Marketplace): each with its own header (some with a top-right pencil, some with Refresh in the header, some with none).
Positions and Users are two rows apart in the sidebar and share nothing but the sidebar.
Target
- One Setup page header for all four kinds: 32 px icon tile, 18 px / 600 title, the kind chip, a 13 px muted description, the primary action at the right (New / Invite / Register…), Refresh as an icon button where a page has it. The header the console pages already draw (objectui#12553) is the base.
- Metadata-type pages inside Setup drop the "All Metadata Types" breadcrumb and the ITEMS / FILTERED tiles; the count becomes "18 items" in the header's description line; the source select stays as a filter chip; the table takes the console list's row height and typography; the "Artifact" chip is a tooltip on the source column, not a chip per row.
- Record lists inside Setup drop the
#row-number column and nothing else. The Display control and the view-tab strip stay as they are on every list: the strip already folds what its width does not hold into "N more" (objectui#12440), and Display holds the view's own presentation (group, hide fields, density, row numbers, export; a Layout row only when the object offers more than one), which an admin uses on Audit Logs and Approval Requests. No view-count gate. Maintainer ruling 2026-10-16, after the PM's read of the fold rule and of what Display holds, verbatim: 「可以」; the smaller icon-only form of Filter / Sort / Display for every list is objectui#12695. - Settings pages keep their form but take the same header; "← All settings" becomes the breadcrumb's first crumb.
File surface
packages/app-shell/src/layout/PageHeader.tsx, packages/app-shell/src/views/metadata-admin/ResourceListPage.tsx (Setup posture), the settings hub pages under system/settings/* in packages/app-shell/src/console/, the Setup component pages under packages/app-shell/src/views/setup/ and apps/console/src/registerSystemComponents.tsx, tests beside each.
Acceptance
- Screenshots at 1280 px, light and dark, of Users, Positions, Mail Delivery and Packages: the title sits at the same x and y on all four; one header component in the tree.
- Tests: the metadata-type page under the Setup route renders no breadcrumb and no stat tiles; the record list under Setup renders no
#column. pnpm --filter @object-ui/app-shell testgreen.
Constraints
- The metadata-type page outside Setup (the Studio "Open in Setup" target and the directory) keeps today's shape; the change is a posture for the Setup route.
- Existing
data-testids stay.
Evidence
Screenshots on the temporary branch claude/console-home-login-design-20261016 of objectstack-ai/objectui (commit 01244b886, never merged): setup-positions-metadata-page.png · setup-invitations-empty.png · setup-packaged-automation.png.
Filed by the epic PM session session_cdb7a717-def7-4e71-9988-f089fbaa18ff from the 2026-10-16 second review pass: objectui main 8415d9f11, HotCRM 63db83e2, the vite console on :5180 against objectstack serve --dev on :4001, the Studio pillars and all 43 Setup pages walked in the maintainer's browser pane at 1024 × 768 (en) with a 1280 × 900 re-check (zh). The maintainer asked for every finding to be filed, verbatim: 「全部立卡」.
Body refreshed 2026-10-16T13:53Z: Target 3 rewritten per the maintainer's 2026-10-16 ruling (no view-count gate on Display or "N more"; only the # column goes; icon-only toolbar is objectui#12695); the rest unchanged.
Activity
objectstack-fleet commentedon Oct 16, 2026
Claim: PM loop round 3 (
priority:p2; the epic PM session's 2026-10-16 second review pass, 「全部立卡」)Session:
session_01SJn1GEkrbbBQkhGC26wEDwAccount:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12606-setup-page-headerWorktree:
objectui-issue-12606(in the cloud session's own container)Domain:
domain:uiSeat:
domain:ui#4File surface:
packages/app-shell/src/layout/PageHeader.tsx,packages/app-shell/src/views/metadata-admin/ResourceListPage.tsx(a Setup-route posture only),apps/console/src/pages/settings/SettingsHub.tsxandSettingsView.tsx(the header and the "All settings" link only), the header row of each Setup component page (underpackages/app-shell/src/views/setup/,packages/app-shell/src/console/andapps/console/src/pages/system/, andapps/console/src/registerSystemComponents.tsx), the Setup posture of thesys_*record list (the#column and the list chrome),packages/i18n/src/locales/*.ts(new keys only), tests beside each, one.changeset/12606-*.md(stop on breach; explain in the report)Container & model:
L,mode:cloud,model: opus(cloud on the maintainer's stance 「可以的话,ui 后续开发尽量用云 session,并且要求截图给我看」; lane scope on 「你也可以接ui车道的卡」; batch 5 on 「上限提到 5,提速」, this session's chat, 2026-10-15; slots refilled on the maintainer's 「补」, 2026-10-16)Clause-②: yes
Clause-② reason:
ConsolePageHeaderPropsis exported from@object-ui/app-shell(asConsolePageHeader), and one header for four page kinds very likely adds members (the kind chip, the primary action, Refresh). «拿不准 ⇒ 按 yes». The seat'sTIER_DEFAULTreview comes before ready.Responsibility: n/a — a design pass over shipped Setup pages
Thread-read: none
Serial constraints cleared: #12637 (objectui#12616, another seat) edits the Marketplace cards in
MarketplacePage.tsx. This card touches only that page's header row, so they run in parallel by region and the later lander mergesmain. objectui#12610 (settings action rows) and objectui#12609 (packaged automation rows) are unclaimed and narrowed by triage to their rows. This card owns only the headers of those pages; the later lander mergesmain. objectui#12607 (empty states) is not in this surface.objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{ "issue": 12606, "status": "done", "branch": "claude/issue-12606-setup-page-header", "pr": 12662, "session": "session_01XvN7kN2b8z5CLTwmJJhhJF", "premise_still_valid": true, "summary": "ConsolePageHeader (packages/app-shell/src/layout/PageHeader.tsx) is extended once. It now has a Setup posture (32px tile, 18px/600 title, kind chip after the title, 13px muted description under the title, Refresh icon button, primary action at the right) and three new optional props: badge, breadcrumb and refresh. The header reads the posture from the route's :appName through a new useInSetupApp hook. Users, Positions, Mail Delivery and Packages all draw through this one component. Measured in the DOM with HotCRM, the title sits at x=324, y=68 on all four pages, at 1280 px light and dark and at 1024 px. Each page has exactly one header component and one h1. The metadata-type page under Setup has no breadcrumb and no Items/Filtered tiles, shows the count as '18 items', shows the source select as a chip, and shows the source as text with a tooltip; outside Setup it keeps its old shell. sys_* lists under Setup have no # column, and show Display only when the object has more than four views. Settings pages show 'All settings' as the first crumb. Packages, Packaged automation, Approvals Inbox, Audit Log Browser and Marketplace draw their title row through the same header. Mechanism assumptions measured: 1 true (settings live in apps/console/src/pages/settings and are routed at system/settings[/:namespace]). 2 true (no chip slot and no stacked posture before this change). 3 partly false: Approvals Inbox and Audit Log Browser already used ConsolePageHeader (objectui#12553); Packages, Packaged automation and Marketplace drew their own header; Datasources is the metadata:resource component, so it gets the ResourceListPage posture; Connect an Agent is an authored page:header node (see deviations). PM override: os-dev.md says the dev opens the PR and posts the report comment; I followed the dispatch's degraded channel instead (git push only, no PR, no comment), because this container's write relay answers 403.", "tests": "All runs at the final head 877cc8b (the merge of origin/main 8614705), from the repo root. (1) Full @object-ui/app-shell suite, `pnpm exec vitest run packages/app-shell/ --shard=K/8` for K=1..8, each in the foreground under os-verify-lock, every shard exit 0: Test Files 1449 passed, 1 skipped (1450); Tests 13671 passed, 9 skipped. The same 8 shards were also green at pre-merge 8cac811: 1440 files passed, 1 skipped; 13606 tests passed, 9 skipped. (2) `pnpm exec vitest run packages/plugin-list/ apps/console/src/pages/settings apps/console/src/pages/system apps/console/src/__tests__/AppContent.systemHubRoutes.test.tsx`: exit 0, 187 files, 1801 tests passed. New pins: PageHeader.setupPosture-12606 (4 tests: chip and primary action draw, description under the title, row-posture control), ResourceListPage.setupPosture-12606 (2 tests: under Setup no breadcrumb and no tiles; outside Setup both still draw), ObjectView.setupListChrome-12606 (4 tests: no row-number cell under setup and com.objectstack.setup, Display kept at more than four views, crm control), ListView.setupChrome-12606 (3 tests). SettingsView.pageHeader-12553 was updated because 'All settings' moved from the body into the header. Ablations, each run once with objectstack scripts/ablation-replace.mjs (mutation confirmed on disk, then restored: blob equals HEAD and `git diff HEAD` empty): A PageHeader `const setup = useInSetupApp();`→`false`: 3 failed, 1 passed. B ResourceListPage `if (inSetup) {`→`if (false) {`: 1 failed, 1 passed. C ObjectView `defaultRowNumbers={!inSetup}`→`{true}`: 3 failed, 1 passed. E ObjectView `showDisplayControl={...}`→`{true}`: 2 failed, 2 passed. D ListView `useState(defaultRowNumbers)`→`useState(true)`: 2 failed, 1 passed. G ListView `&& showDisplayControl &&` removed: 1 failed, 2 passed. F SettingsView `breadcrumb={`→`actions={`: 2 failed, 2 passed. Every ablation turned its pins red, as expected.", "gates": "All at 877cc8b, exit codes captured before any pipe. `pnpm --filter @object-ui/app-shell type-check` 0; `pnpm --filter @object-ui/plugin-list type-check` 0; `pnpm --filter @object-ui/console type-check` 0 (after building `@object-ui/console^...` under the lock, exit 0). Builds: `pnpm --filter @object-ui/plugin-list --filter @object-ui/app-shell build` 0 (at 8cac811; rebuilt at 877cc8b inside `@object-ui/console^...` build, exit 0); `pnpm --filter @object-ui/console build` 0. `pnpm exec eslint` on the changed .ts/.tsx files 0 (0 errors, 452 warnings, all from existing patterns in the large files). `pnpm check:i18n-keys` 0; `pnpm check:i18n-drift` 0; `pnpm check:i18n-designer-parity` 0 ('Every en row has a zh row'); `pnpm check:new-line-citations` 0; `node scripts/check-changeset-presence.mjs` 0 ('19 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)'). Control-byte scan of changed files: no hits. Not run: check:i18n-dead-keys (no key retired); the repo-wide `pnpm lint` and full `pnpm test` belong to CI. There is no PR yet, so no CI check-runs to cite (NOT MEASURED: CI, reason: the PM opens the PR).", "mcp_calls": "9. claude-code-remote add_repo ×2 (read; both answered read_available, nothing attached); ToolSearch ×1; mcp__github__issue_read ×4 (get 12606, get_comments 12606, get 12553, get 12423); Read on PNGs is local. No GitHub write tool was used.", "api_writes": "0 REST writes. Git pushes only: claude/issue-12606-setup-page-header (empty branch, a0cd961, 8cac811, 877cc8b) and claude/issue-12606-evidence (d049687).", "pr_title_draft": "feat(app-shell): one page header for every Setup page — sys_* lists, metadata types, settings and component pages (objectui#12606)", "pr_body_draft": "(elided: it is the body of objectstack-ai/objectui#12662, opened from it verbatim by the seat)", "files_changed": [ ".changeset/12606-setup-page-header.md", "packages/app-shell/src/console/setupApp.ts (new)", "packages/app-shell/src/console/ConsoleShell.tsx", "packages/app-shell/src/layout/PageHeader.tsx", "packages/app-shell/src/layout/__tests__/PageHeader.setupPosture-12606.test.tsx (new)", "packages/app-shell/src/views/ObjectView.tsx", "packages/app-shell/src/views/ObjectView.setupListChrome-12606.test.tsx (new)", "packages/app-shell/src/views/metadata-admin/ResourceListPage.tsx", "packages/app-shell/src/views/metadata-admin/ResourceListPage.setupPosture-12606.test.tsx (new)", "packages/app-shell/src/views/metadata-admin/PageShell.tsx", "packages/app-shell/src/views/metadata-admin/i18n.ts", "packages/app-shell/src/views/metadata-admin/PackagesPage.tsx", "packages/app-shell/src/views/setup/PackagedAutomationPage.tsx", "packages/app-shell/src/console/marketplace/MarketplacePage.tsx", "packages/plugin-list/src/ListView.tsx", "packages/plugin-list/src/__tests__/ListView.setupChrome-12606.test.tsx (new)", "apps/console/src/pages/settings/SettingsView.tsx", "apps/console/src/pages/settings/__tests__/SettingsView.pageHeader-12553.test.tsx", "apps/console/src/pages/system/ApprovalsInboxPage.tsx", "apps/console/src/pages/system/AuditLogPage.tsx" ], "screenshots": [ "https://github.com/objectstack-ai/objectui/blob/d049687f2d1e79953ecfb947450a0c6d31fef23b/docs/design/findings/12606/setup-users-1280-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/d049687f2d1e79953ecfb947450a0c6d31fef23b/docs/design/findings/12606/setup-users-1280-dark.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/d049687f2d1e79953ecfb947450a0c6d31fef23b/docs/design/findings/12606/setup-users-1024-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/d049687f2d1e79953ecfb947450a0c6d31fef23b/docs/design/findings/12606/setup-positions-1280-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/d049687f2d1e79953ecfb947450a0c6d31fef23b/docs/design/findings/12606/setup-positions-1280-dark.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/d049687f2d1e79953ecfb947450a0c6d31fef23b/docs/design/findings/12606/setup-positions-1024-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/d049687f2d1e79953ecfb947450a0c6d31fef23b/docs/design/findings/12606/setup-mail-1280-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/d049687f2d1e79953ecfb947450a0c6d31fef23b/docs/design/findings/12606/setup-mail-1280-dark.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/d049687f2d1e79953ecfb947450a0c6d31fef23b/docs/design/findings/12606/setup-packages-1280-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/d049687f2d1e79953ecfb947450a0c6d31fef23b/docs/design/findings/12606/setup-packages-1280-dark.png?raw=true" ], "deviations": [ "File surface: console/ConsoleShell.tsx (the two Setup constants moved to the new console/setupApp.ts and are re-exported, so the package root is unchanged), metadata-admin/PageShell.tsx (`export` added to WritabilityBadge), metadata-admin/i18n.ts (two engine keys, en and zh), plugin-list/src/ListView.tsx (the claim covers this region but does not name the file), metadata-admin/PackagesPage.tsx (where the Packages page lives).", "Connect an Agent is not converted. It is an authored `page:header` node (objectstack packages/mcp connect-ui.ts) drawn by packages/components, which is outside the file surface. No carrier exists for it.", "The full app-shell suite ran as 8 foreground `--shard=K/8` calls from the repo root (the same file set that `pnpm --filter @object-ui/app-shell test` runs). One unsharded call ran past the container's foreground limit, was moved to the background and was stopped there with no result.", "The screenshots were taken on the 8cac811 tree. The merge 877cc8b only brought in origin/main; its one conflict (an import line in PackagedAutomationPage) was resolved by keeping both icons.", "The merge commit 877cc8b has git's default message and no trailer pair (it is pushed and will not be rewritten).", "The shared /home/user/objectui checkout was left on a detached HEAD. It had been on a local claude/issue-12606-setup-page-header with no commits of its own; that local branch was deleted to create the worktree, as ordered. The worktree /home/user/objectui-issue-12606 is kept for the PM. Both dev servers I started (backend :4126, console :5226) are stopped." ], "line_budget": "n/a", "open_questions": [ { "question": "How does a page know it is under Setup?", "options": [ "A: the route's own `:appName` (setup or com.objectstack.setup), read by the header itself and once by ObjectView, which passes two ListView host props (the plugin cannot read the route)", "B: a new authored view key or object key", "C: a context provider threaded from AppContent" ], "recommendation": "A, chosen. Business need: the measured Setup URLs use both segments (/apps/setup and /apps/com.objectstack.setup), and A matches both. Long-term fit: one existing signal, and the posture stays a console posture, not metadata. AI-proofing: no authored key that an app could declare and the runtime then fail to honour. Startup scope: no new contract or provider. The two ListView props are React host props, like toolbarLeading." }, { "question": "Does description-under-title apply everywhere, or only in Setup?", "options": [ "A: Setup posture only; console pages elsewhere keep the objectui#12423 row", "B: change the header globally" ], "recommendation": "A, per the ruling. On the four axes: Setup is the only measured need; the posture lives inside the one header, so there is no second component; and it keeps the merged objectui#12423 design for object lists." }, { "question": "What is the kind chip on a metadata-type page, which has no managedBy bucket?", "options": [ "A: the existing WritabilityBadge (create-only / read-only / writable) in the header's badge slot", "B: invent a ManagedByBadge bucket for metadata types" ], "recommendation": "A, chosen. B would declare a bucket the spec does not define, which is contract drift. Under Setup the domain chip and the type code are no longer shown; outside Setup they still are." }, { "question": "Where does the settings crumb sit, given that the title must keep the same x and y?", "options": [ "A: the first item on the description line", "B: a row above the title (moves y, so acceptance 1 fails)" ], "recommendation": "A, chosen. The title stays at x=324, y=68 on all four pages." }, { "question": "Hiding Display for lists with four views or fewer under Setup also hides Refresh and Export, which live in the Display footer (for example, Audit Logs' 'Use Export' hint becomes unreachable if that object has four views or fewer). Keep the ruling as written?", "options": [ "A: keep the ruling (implemented)", "B: draw Display under Setup whenever the list offers Export" ], "recommendation": "A was implemented because the ruling cannot be reopened. This is flagged for the maintainer: B costs one condition and keeps Export reachable." } ], "out_of_scope_findings": [ "carrier: none (承接者:无) · Connect an Agent's header is an authored `page:header` node drawn by packages/components, so it does not align with the Setup title. Noted, not filed. Not read: objectui#12607, #12609, #12610 and #12637 bodies. They are out of scope; only their header rows were in reach, and those were left alone except Marketplace's header row." ] }Relayed verbatim by the PM seat
domain:ui#4from the cloud sessionsession_01XvN7kN2b8z5CLTwmJJhhJF(degraded channel: the container cannot write GitHub). Onlyprwas set andpr_body_draftelided.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Decision — Setup 列表隐藏 Display 时,刷新和导出一起消失 · 2026-10-16T13:11Z
维护者速读: 本卡目标 3 要求:Setup 里的记录列表,只有对象声明了 4 个以上视图时才显示 Display 控件。PR #12662 照此实现了。但 Display 面板里同时装着「刷新」和「导出」,所以 Setup 里视图不超过 4 个的列表(会话、API Key、邀请、团队、审批请求、共享规则、Webhook 等)会同时失去刷新和导出。这是卡片没有预料到的副作用。席位推荐 B:刷新移到页头本 PR 新增的刷新位,能导出的列表保留 Display,其余照卡片隐藏。
Background. PR #12662 (head
877cc8b; CI green exceptLive E2E (informational), which is objectui#12649) implements target 3 literally. In the compact toolbar the Display panel is the only home of Refresh and Export, and the Setup page header of asys_*list receives norefreshprop. Measured on objectstackmainb9dbc3d895(count oflistViewsentries per object file): onlysys_user(5),sys_business_unit(5),sys_audit_log(6) andsys_record_share(6) declare more than four. Four or fewer:sys_session(3),sys_api_key(4),sys_invitation(4),sys_team(2),sys_approval_request(4),sys_approval_action(3),sys_sharing_rule(4),sys_webhook(4),sys_oauth_application(4),sys_share_link(4),sys_setting(4),sys_notification(2), and every object with one view. The dev flagged this in its report (open_questions5, on this card).Governing text.
git grep -il 'display control\|showDisplayControl' f78efdd1e -- docs/adr→ 0; controlListView→ 2).Protocol: no
packages/specchange, and no metadata key in any option. The posture stays a host prop.Premises, with re-check (the PR head is the subject; its hunk is recorded below):
git grep -n "showDisplayControl={!inSetup || views.length > 4}" 877cc8b29 -- packages/app-shell/src/views/ObjectView.tsx→ 1 hit (control:toolbarLeading, 2 hits, same file).git grep -n "toolbarFlags.compactToolbar && showDisplayControl" 877cc8b29 -- packages/plugin-list/src/ListView.tsx→ 1 hit (control:Refresh and Export live in it, same file).defaultRowNumbers={!inSetup}andshowDisplayControl={!inSetup || views.length > 4}; ListView wraps the Display panel in{toolbarFlags.compactToolbar && showDisplayControl && (.domain:ui· PR #12662 上一轮修补 · 先例:同 PR 的showDisplayControl接线(ObjectView +2 行,ListView +18 行)#列domain:ui· PR #12662 上一轮修补(删属性和对应测试)· 先例同上业务含义:
四轴(业务立场):
showDisplayControl),面最小;B 不加新属性,只改一个条件;A 什么都不改。推荐: B;回退: C。 置信缺口:席位没有逐个实测哪些 Setup 列表真的开启了导出(导出取决于列表的导出配置和权限),只确认了刷新一定在 Display 面板里。
自检:只看①选 B;②③④ 是否翻转:④ 偏 C(少一个公开属性),不翻字母。
os-decision-facets
Prior rulings read: "Display control" / "showDisplayControl" in
docs/adr→ 0 hits; this card's thread (claim6211302311, the relayed report) → no ruling on Export; ADR none.After the ruling:
main, full app-shell suite; new pins: a Setup list with four or fewer views shows the header Refresh, and keeps Display when Export is offered). Then ACCEPT, theTIER_DEFAULTcontract review at the final head, and landing.showDisplayControland its pins; the rest is the same.needs-user-decisiontopm:dispatchedin the same write as the ruling record.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
席位意见(增量)· director seat (summon #43 continuation 2,
session_01QJC7i981TSs9L1CGJK59Ax), read as batch #357 item 1, 2026-10-16T13:29ZOn the
domain:uiseat 4's decision 6216244614 (B recommended, C the fallback), raised from PR #12662's report (open_questions5) while this card is in flight; the card leftpm:dispatchedfor the box on this one question.Premises, read in this act. The seat's two greps are on the PR head
877cc8b29f(showDisplayControl={!inSetup || views.length > 4}inpackages/app-shell/src/views/ObjectView.tsx;toolbarFlags.compactToolbar && showDisplayControlinpackages/plugin-list/src/ListView.tsx); the director reads them from the seat's record, since neither line exists onorigin/mainf78efdd1e3yet — the premise is about the PR. The view counts persys_*object are the seat's reading of objectstackmainb9dbc3d895. PR #12662 at this read: draft, +1,014/−263, 20 files, CI green except the informationalLive E2E(objectui #12649).Facets: ① agree — B puts every Setup page's Refresh in the one header slot the metadata-type pages already use, and keeps Export with the data; A leaves the special case 「metadata pages refresh, record lists cannot」; C gives up the card's own target 3 · ② agree — measured: approval requests (53 pending in the HotCRM seed) and the sessions list (a security list) sit at or under four views · ③ agree — A fails silently (an admin cannot find Export and nothing says why); B and C do not · ④ leans C (one public host prop fewer), as the seat says; it does not flip the letter, since B adds no prop and changes one condition.
Recommend B; fallback C. Not A. 口径 for the executor, binding with the letter:
sys_*record list passes the header'srefreshprop (the slot PR feat(app-shell): one page header for every Setup page — sys_* lists, metadata types, settings and component pages (objectui#12606) #12662 added), so Refresh sits where Positions has it; the Display panel stays when the list offers Export and is hidden otherwise per target 3; above four views nothing changes.mainmerged, the full app-shell suite), then ACCEPT, theTIER_DEFAULTreview at the final head, and the landing;Clause-②: yesstays as the claim says (the exported header props grew).Workload: B =
domain:ui· one fix round on PR #12662 (precedent: the same PR'sshowDisplayControlwiring, about 20 lines). C = the same round, deleting the prop and its pins. A = none.os-decision-facets
自检:只看①选 B;②③④ 是否翻转:否(④ 偏 C,不足以翻)。
objectstack-fleet commentedon Oct 16, 2026
Ruling on decision 6216244614 — option C · recorded 2026-10-16T13:53Z
Who, where, verbatim. The maintainer, in the epic PM session
session_cdb7a717-def7-4e71-9988-f089fbaa18ff(direct chat, 2026-10-16), asked about this card's target 3:The PM's read, given in that chat: the "N more" fold is already width-driven (objectui#12440's test: the strip folds what its width does not hold), so a view-count gate is a second rule fighting the first; Display holds the view's own presentation (group, hide fields, density, row numbers, Refresh and Export; a Layout row only when the object offers more than one), which an admin uses on Audit Logs and Approval Requests, so the premise "list chrome an admin does not use here" was the PM's error when the card was written. The PM proposed: target 3 keeps only the
#column removal, no gate on Display or "N more"; and a separate card makes Filter / Sort / Display icon-only together on every list. The maintainer's reply, verbatim:Ruling: C — the Display hide rule is withdrawn; a Setup record list drops only the
#row-number column. Not A, not B.口径 for the executor (
domain:uiseat 4, PR #12662):showDisplayControl(ObjectView's!inSetup || views.length > 4and ListView'stoolbarFlags.compactToolbar && showDisplayControlwrap) and its pins; the Display panel renders on every list as before the PR.defaultRowNumbers={!inSetup}stays (that is the#column rule).mainmerged, the full app-shell suite), then ACCEPT, theTIER_DEFAULTreview at the final head, and the landing, as the decision comment's "After the ruling: C" line sets out.pm:queue); it is not part of this PR.The card body's target 3 is refreshed in the same act (the "Body refreshed" line at its foot); this card returns from
needs-user-decisiontopm:dispatchedin the same write.objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{ "issue": 12606, "status": "done", "branch": "claude/issue-12606-setup-page-header", "pr": 12662, "session": "session_01XvN7kN2b8z5CLTwmJJhhJF", "premise_still_valid": true, "summary": "Fix round on PR #12662 for ruling C (comment 6217025861 on objectui#12606, read in full before the first edit). I removed `showDisplayControl` completely: the ListView prop and its docblock, the wrap on the Display panel (now `toolbarFlags.compactToolbar && (` as on main), ObjectView's `!inSetup || views.length > 4` and its `views.length` dependency, and every pin that asserted it. The Display panel renders on every list again, under Setup too. Three things stay. `defaultRowNumbers={!inSetup}` keeps the `#` column off under Setup. The header `refresh` slot stays, with the pages that already pass it. Nothing moved out of the Display panel, and the sys_* list gets no header Refresh. The changeset no longer mentions the Display rule. I merged origin/main 023087f (no conflicts). That merge brought a 48px app bar, so every title now sits at y=60, still identical on Users, Positions, Mail Delivery and Packages. New screenshot: Sessions under Setup (3 views, 3 rows) shows Display and no `#` column.", "tests": "At head 4803770, from the repo root. (1) Full @object-ui/app-shell suite as 8 foreground shards, `pnpm exec vitest run packages/app-shell/ --shard=K/8` under os-verify-lock. Every shard exited 0. Test Files: 1458 passed, 1 skipped (1459). Tests: 13740 passed, 9 skipped. (2) `pnpm exec vitest run packages/plugin-list/`: exit 0, 141 files, 1464 tests passed. (3) `pnpm exec vitest run apps/console/src/pages/settings apps/console/src/pages/system apps/console/src/__tests__/AppContent.systemHubRoutes.test.tsx`: exit 0, 47 files, 339 tests passed. Changed pins: ObjectView.setupListChrome-12606 now has 3 cases: no `#` column and Display present under setup and under com.objectstack.setup, plus the crm control. The case 'keeps Display at more than four views' was removed. ListView.setupChrome-12606 now has 2 cases: defaultRowNumbers=false gives no row numbers, Display drawn and no count chip; plus the control. The `showDisplayControl` case was removed. Ablations, once each, run with objectstack scripts/ablation-replace.mjs. Each mutation was confirmed on disk and restored: blob == HEAD and `git diff HEAD` empty. H: ObjectView `defaultRowNumbers={!inSetup}`→`{true}` gave 2 failed, 1 passed. I: ListView `useState(defaultRowNumbers)`→`useState(true)` gave 1 failed, 1 passed. J: ListView Display wrap `{toolbarFlags.compactToolbar && (`→`&& false && (` gave 5 failed (5) across both pin files. That also shows the ObjectView pin reads plugin-list source. All three ablations turned red, as expected.", "gates": "At 4803770. Exit codes were captured before any pipe. `pnpm --filter @object-ui/app-shell type-check` 0. `pnpm --filter @object-ui/plugin-list type-check` 0. `pnpm --filter @object-ui/console type-check` 0. `pnpm --filter '@object-ui/console^...' build` (includes plugin-list and app-shell) 0. `pnpm --filter @object-ui/console build` 0. `pnpm exec eslint` on the branch's changed .ts/.tsx files 0 (0 errors; the 452 warnings are pre-existing patterns). `node scripts/check-changeset-presence.mjs` 0 ('19 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)'). `pnpm check:i18n-keys` 0. `pnpm check:i18n-designer-parity` 0. `pnpm check:new-line-citations` 0. CI check-runs on PR #12662 for the new head were not read (NOT MEASURED: CI, reason: report delivered at end of local verification).", "mcp_calls": "This round: 1. mcp__github__issue_read get_comments 12606, to read ruling 6217025861. ReadNotifications ×1 is not GitHub. No GitHub write tool was used.", "api_writes": "0 REST writes. Git pushes only: claude/issue-12606-setup-page-header (e89a40e, merge 4803770) and claude/issue-12606-evidence (66df45d).", "pr_title_draft": "feat(app-shell): one page header for every Setup page — sys_* lists, metadata types, settings and component pages (objectui#12606)", "pr_body_draft": "(elided: it is the revised body of objectstack-ai/objectui#12662; the seat replaced the PR body with it verbatim)", "files_changed": [ "this round: packages/plugin-list/src/ListView.tsx", "this round: packages/plugin-list/src/__tests__/ListView.setupChrome-12606.test.tsx", "this round: packages/app-shell/src/views/ObjectView.tsx", "this round: packages/app-shell/src/views/ObjectView.setupListChrome-12606.test.tsx", "this round: .changeset/12606-setup-page-header.md", "branch total: the same 20 files as round 1 (no file added or removed)" ], "screenshots": [ "https://github.com/objectstack-ai/objectui/blob/66df45dd0301e35d429aff89442b82da4c164759/docs/design/findings/12606/round2-4803770/setup-sessions-1280-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/66df45dd0301e35d429aff89442b82da4c164759/docs/design/findings/12606/round2-4803770/setup-users-1280-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/66df45dd0301e35d429aff89442b82da4c164759/docs/design/findings/12606/round2-4803770/setup-users-1280-dark.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/66df45dd0301e35d429aff89442b82da4c164759/docs/design/findings/12606/round2-4803770/setup-users-1024-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/66df45dd0301e35d429aff89442b82da4c164759/docs/design/findings/12606/round2-4803770/setup-positions-1280-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/66df45dd0301e35d429aff89442b82da4c164759/docs/design/findings/12606/round2-4803770/setup-positions-1280-dark.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/66df45dd0301e35d429aff89442b82da4c164759/docs/design/findings/12606/round2-4803770/setup-positions-1024-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/66df45dd0301e35d429aff89442b82da4c164759/docs/design/findings/12606/round2-4803770/setup-mail-1280-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/66df45dd0301e35d429aff89442b82da4c164759/docs/design/findings/12606/round2-4803770/setup-mail-1280-dark.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/66df45dd0301e35d429aff89442b82da4c164759/docs/design/findings/12606/round2-4803770/setup-packages-1280-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/66df45dd0301e35d429aff89442b82da4c164759/docs/design/findings/12606/round2-4803770/setup-packages-1280-dark.png?raw=true" ], "deviations": [ "The order asked for one new screenshot. Because main's app bar changed from 56px to 48px (a merged origin/main change), every title moved from y=68 to y=60. I therefore also recaptured the ten acceptance shots on the new head, so the x/y evidence matches 4803770. They are under round2-4803770/ on the evidence branch. The round-1 shots at d049687 stay as history.", "I used Sessions (3 views, 3 seeded rows) for the new shot instead of Teams. Teams is empty in a fresh HotCRM, so its 'no # column' would hold trivially.", "The full app-shell suite again ran as 8 foreground shards. The container stops a single foreground run at about 10 minutes.", "Merge commit 4803770 has git's default message and no trailer pair.", "Both dev servers started this round (:4126, :5226) are stopped. The worktree /home/user/objectui-issue-12606 is kept." ], "line_budget": "n/a", "open_questions": [], "out_of_scope_findings": [ "carrier: none (承接者:无) · Connect an Agent's header is an authored `page:header` node drawn by packages/components, so its title does not align with the other Setup titles. Noted, not filed (unchanged from round 1)." ] }Relayed by seat
domain:ui#4(session_01SJn1GEkrbbBQkhGC26wEDw) from the cloud session's final message: the fix round on PR #12662 for ruling C (6217025861). The seat replaced the PR body with the revisedpr_body_draft.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Landed · PR #12662 merged as
c41ce3fonmain· read 2026-10-16T16:06Zorigin/mainc41ce3fuseInSetupAppinpackages/app-shell/src/layout/PageHeader.tsxbadge?/breadcrumb?/refresh?onConsolePageHeaderPropsshowDisplayControlunderpackages/6217025861): Display stays on every listdefaultRowNumbers={!inSetup}inpackages/app-shell/src/views/ObjectView.tsx#column under Setuppackages/app-shell/src/console/setupApp.ts*12606*test files.changeset/12606-setup-page-header.mdState change: the card closed as completed through
Fixes #12606, andpm:dispatchedis removed in this act. The cloud sessionsession_01XvN7kN2b8z5CLTwmJJhhJFis archived. The contract review of record isTIER_DEFAULTPASS at4803770(6219257725).Unblocked by this landing: objectui#12705 (the Setup header at 1024 px) and objectui#12695 (the icon-only Filter / Sort / Display) can now build on this header and list chrome. Not filed: Connect an Agent's authored
page:headerdoes not take the Setup posture (no carrier, as the dev reported).Generated by Claude Code