Repository navigation
Description
epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff
Filed by the record-page epic seat under epic #26676, on the maintainer's ruling. Code readings below are on main 9a9823d921. No domain:* label is set: triage routes this card.
Ruling
The maintainer, 2026-11-02: 「默认应该是普通列表,右侧弹出。drawer」 and 「默认改抽屉,分屏彻底退役,只留抽屉和整页,立卡。」
This supersedes #27545 Target item 1 ("Split is the default") and the split half of item 2, written on the 2026-10-29 final design. The other #27545 items stand: the non-modal drawer, ⤢ maximizing in place, and the full page from ↗ and ⋯.
Why
- Observed. Opening a record narrows the list. At 1440 px a lead list keeps three columns. In a narrower window it turns into card rows.
- No metadata pull.
splitalready leftNavigationModeSchema, so no author can declare it.ui/packages/app-shell/src/views/ObjectView.tsx:780still turns a declared or defaultdrawerintosplitunless the reader chose the drawer. HotCRM's task, opportunity and case views declaremode: 'drawer'and get a split pane. - The scenario is already covered. The drawer draws no dimming overlay and is non-modal, so the list stays visible, a click on another row swaps the record, and the 「1 / 13」 stepper works.
Reading: the split surface
ui/packages/app-shell/src/utils/recordOpenPreference.ts: the type at line 55, the default at line 61, and the decode at line 78.ui/packages/app-shell/src/views/ObjectView.tsx:780: the mapping fromdrawertosplit.ui/packages/components/src/custom/navigation-overlay.tsx: the'split'mode,RECORD_SPLIT_MIN_CONTENT_PX,useSplitEscapeandpaneBeside.ui/packages/components/src/custom/record-list-face.tsx, with its readers inplugin-grid/src/ObjectGrid.tsxandplugin-list/src/ListView.tsx: the narrowed list face.ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx(lines 74, 84, 343–355) and thelist.recordOpenSplitkey in the i18n packs.content/docs/frontend/plugins/plugin-view.mdx, around line 520.
Target
- A record opened from a list opens in the drawer by default. The list keeps its full width underneath.
RecordOpenPreferenceis'drawer' | 'page'. A storedsplitis an unknown value and reads as the default, with no compatibility read (startup posture).- The split mode and its code go: the mapping at
ObjectView.tsx:780, the overlay's split face and width floor, the narrowed list face if nothing else reads it, and the i18n key in every pack. - The Display menu's 「打开记录」 offers 抽屉 and 整页.
- These stay: the non-modal drawer, a row click swapping the record, the stepper, drag-to-resize, ⤢ maximizing in place, and the modal sheet for a drawer with no list.
- No metadata change:
navigation.modekeeps its values.
Premise to verify first
ui/packages/app-shell/src/layout/consoleSidebarRail.ts:50 derives the sidebar's auto-fold width from split content (1160 + 256 = 1416, #27593). Read whether anything other than the split pane needs that fold. Do not change it on assumption: name the reading in the PR. If the fold has no remaining reason, report it as a follow-up finding for the maintainer, because #27593 was a separate ruling.
Acceptance
- At 1440 px and with the sidebar open, a row click opens the drawer, and the list behind it keeps its columns and width.
- A click on another row swaps the record. ↑ ↓ step through the list. ⤢ maximizes in place.
- With
splitstored inos:record-open-mode, a row click opens the drawer. - The Display menu shows 抽屉 and 整页 only. Choosing 整页 opens the record page.
- A view that declares
navigation.mode: 'page'still opens the page. A phone still opens the page. - A
grepforrecordOpenSplitandRECORD_SPLIT_MIN_CONTENT_PXfinds nothing. - The Record drawer v4: a bounded peek over the list — md cap instead of the field-count bucket, no dim overlay, the list stays readable and clickable, ⤢ maximizes in place at the same URL; the full page is reached only from the row ↗ and the header ⋯ #27545 tests are converted to the drawer, not deleted, wherever the behaviour stays (
ObjectView.recordPaneV4-27545,navigation-overlay-split-27545,ListView.recordPaneCount-27545,recordPaneGroupScope-28461,ObjectView.recordOpenPreference-26677,ObjectView.recordOpenDisplay-26681). - Screenshots at 1440 and 1000 px are linked from the PR.
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: priority:p2 · domain:ui · pm:queue · 2026-11-02T05:08Z
⛔ Not a claim.
recordOpenPreference.ts,ObjectView.tsx:780,navigation-overlay.tsx,record-list-face.tsx,ViewSettingsPopover.tsx, the i18n key), so it is a user-visible feature at p2 indomain:ui. The direction is ruled, so it goes topm:queue, and theconsoleSidebarRail.tsfold is reported as a follow-up, not changed. It was filed under epic epic: record page v2 — one default open mode per object (drawer by default, page by declaration; modal / split / popover retired as metadata); the drawer and the page are one page at two widths; related records open in place #26676 but is not a sub-issue, and the body hands routing to triage.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Claim: PM loop round 10 · 2026-11-02T05:21Z
Session:
session_01QsR2jRrZ9h4h6RnBzGnhgi(card thread, os-dev); dispatched by seat sessionsession_01QsR2jR7ZFkpqmm4U8S1f9yAccount:
zhuangjianguoBranch:
claude/project-thread-o2b23t(platform-assigned to the card thread; it can push only this branch)Worktree:
objectstack-issue-28915Domain:
domain:uiSeat:
domain:ui#4File surface:
recordOpenPreference.ts,ObjectView.tsx(the drawer→split mapping),componentsnavigation-overlay.tsx,record-list-face.tsxandcustom/index.ts, their readers inObjectGrid.tsxandListView.tsx,ViewSettingsPopover.tsx, thelist.recordOpenSpliti18n key in every pack,content/docs/frontend/plugins/plugin-view.mdx, the tests of all of these, and a changeset;consoleSidebarRail.tsread-only (stop on breach; explain in the report)Container & model: M,
mode:thread,model: default tier (dispatch-gates --tier: no path-derived mandate),effort: defaultClause-②: yes (narrowing)
Metadata-protocol: none
Responsibility:
opening a record narrows the list to a split pane, so a lead list keeps three columns at 1440 px and turns into card rows in a narrower window | the drawer is non-modal and already keeps the list, the row swap and the stepper | every user who opens a record from a listThread-read: 6569566361
Premise: holds (at
origin/main8bb2417a,ObjectView.tsx:779mapsdrawertosplitunless the reader chose the drawer, andnavigation-overlay.tsx:589draws the split face)Serial constraints cleared: none in flight on these files (every open PR checked);
domain:ui#1holds #28950 (ViewSettingsPopover.tsx) until this PR is upGenerated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jRrZ9h4h6RnBzGnhgi
os-dev-report
{ "issue": 28915, "status": "done", "branch": "claude/project-thread-o2b23t", "pr": "https://github.com/objectstack-ai/objectstack/pull/29108", "head": "2255b429", "session": "session_01QsR2jRrZ9h4h6RnBzGnhgi", "premise_still_valid": true, "summary": "A record opened from a list now opens in the non-modal drawer over the full-width list by default; the split pane, its narrowed list face (three columns or compact cards) and the Split choice in the Display menu's Open records control are retired. RecordOpenPreference is drawer | page and a stored split reads as the default with no compatibility read. Seven @object-ui/components exports leave (RECORD_SPLIT_MIN_CONTENT_PX, RecordListFaceProvider, useRecordListFace, recordListFaceFor, RECORD_LIST_CARD_FACE_BELOW_PX, RECORD_LIST_NARROW_COLUMN_COUNT, RecordListFace) under a BREAKING changeset with FROM-TO lines and an ADR-0087 runtime-export-retired disposition; list.recordOpenSplit leaves all ten packs. The #27545 tests are converted to the drawer (4 renamed), not deleted.", "claim_lines": [ "Clause-②: yes (narrowing)", "Metadata-protocol: none", "Skills-docs: follow-up owed — skills/objectstack-ui/rules/record-page.md, skills/objectstack-ui/evals/record-page.json" ], "tests": "At 407e38cf, ui vitest --maxWorkers=2 under os-verify-lock: plugin-list whole suite 179/179 files 1725 tests; plugin-grid ObjectGrid set + components/plugin-detail/plugin-view set 207/207 files 1692 tests; app-shell ObjectView set 141/141 files 1314 tests (527 files, all VERDICT command-exit 0). At 4b3e19eb: the 54 test files touched against the base, 377 tests green. At 2255b429 after the second main merge: 29 files 228 tests green (touched tests, plugin-list Display-menu and record-count tests, main's new ListView.restoreViewDefaults-28948 and data-table row-action tests). turbo type-check components, i18n, plugin-grid, plugin-list, plugin-detail, plugin-view, app-shell, console 78/78 exit 0 at 407e38cf; plugin-list + components 51/51 at 2255b429. ui eslint (Lint UI config) on the 41 touched ts/tsx files: 0 errors. Ablation: decode mutated to map a stored split to page via ablation-replace.mjs, recordOpenPreference.test.ts went red (1 failed); restored, git diff HEAD empty.", "gates": "dispatch-gates --commands derived 67; all 67 run, exit 0 each, --ran reconciliation 67 run 0 NOT-MEASURED (at 407e38cf). check:skill-examples first exit 3 (client-react not built), exit 0 after the full build. check:type-check-debt under the verify lock exit 0. node scripts/check-sdui-manifest.mjs exit 0. PR-body gates with GITHUB_EVENT_PATH on the sent body: check-changeset-no-major 0, check-adr-0087-registration 0, check-closing-keyword-parity 0, check-partof-closing-keyword 0. CI check-runs on #29108: not yet concluded at report time (in_progress).", "dogfood_battery": "4b3e19eb · VERDICT command-exit 0 on each of four locked legs (pnpm --filter @objectstack/dogfood exec vitest run --shard=K/4) · Test Files 384 passed + 3 skipped of 387 · Tests 3166 passed + 28 skipped · no failures. Ran as shards because one foreground call is capped at 600 s (see deviations).", "screenshots": "/mnt/project-files/issue-28915/shots/ — 12 PNGs, before and after, 1440 and 1000 px, sidebar open (pinned at 1000 px), examples/app-crm Accounts: list, Display menu Open records, record open. Before at 1440: split pane with the list narrowed to three columns; before at 1000: drawer (split fell back for want of width); after: drawer over the full-width list at both widths; Display menu Split/Drawer/Full page before, Drawer/Full page after. The console rendered in English, so the 打开记录 control reads Open records.", "mcp_calls": "0", "api_writes": "2 — fleet-write relay pr_create (run 41407687829, read-back byte-identical, no assignees) and this os-dev-report comment via post-stamped; plus git pushes to the branch", "open_questions": [], "out_of_scope_findings": [ "class: b · reach: named producer ui/packages/app-shell/src/layout/consoleSidebarRail.ts · evidence: CONSOLE_SIDEBAR_RAIL_BELOW_WIDTH = RECORD_SPLIT_MIN_CONTENT_WIDTH (440 + 720) + 256 = 1416 px is derived only from split content; with split retired the threshold has no remaining reason, while the fold itself keeps one (#27593 maintainer quote 窄屏幕左侧菜单自动折叠,点击弹出, original target near 1100 px) · dedupe words: sidebar rail fold threshold 1416 split-derived", "class: c · reach: named producer · stale split-pane comments outside the declared surface: record-top-bar.tsx:11, data-table.tsx:3735, plugin-detail RecordPageColumns.tsx:135/237, useRecordPageTier.ts:31, synth/recordPageColumns.ts:16/93/110, react useNavigationOverlay.ts:278, plugin-view ObjectView.tsx:590/1193, RecordDetailView.tsx:943/1003, objectViewOpenAsPage.tsx:15, appObjectScope.ts:45, ObjectGrid.tsx:3202 · dedupe words: stale split pane comments", "class: c · reach: named producer @object-ui/i18n · the console.objectView.recordCount key family is now read by no source file, and common.closePanel is no longer read by the overlay · dedupe words: unread i18n keys recordCount closePanel", "class: c · reach: named producer skills/objectstack-ui · rules/record-page.md:48 and evals/record-page.json:24 still describe split as the default Open records choice · dedupe words: skills record-page split default", "carrier: seat · noted, not filed" ], "deviations": [ "content/docs/ui/views.mdx (one paragraph on Open records) edited outside the declared file surface: a bounded in-place fix of the same claim; the seat amends the claim surface", "test files outside the listed surface touched because they drove the split mode: plugin-detail RecordPageColumns.enlargedEscapeInPane-27524, app-shell RecordDetailView.topBar-27524, ObjectView.recordCountFooter-10636, objectListTitle-27950, titleViewSwitcher-27594, viewRefusal-12112, phoneRecordPage-27058; four test files renamed from split to drawer names", "dogfood battery ran as four vitest --shard legs under the lock, not one pnpm --filter @objectstack/dogfood test call, because a foreground call is capped at 600 s and the brief requires foreground posture; the four legs cover all 387 files", "the derived gate sweep ran at 407e38cf, before two clean main merges; the touched tests and type-check were re-run at the final head", "screenshots: a temporary console Vite dev server against examples/app-crm (objectstack dev --seed-admin --fresh); the before state came from git restore of the 21 ui src files to the base in the worktree, then restored to HEAD; both servers stopped and git status clean afterwards" ], "line_budget": "48 files, +1169 / -1488 = 2657 changed lines without rename detection (46 files, +854 / -1173 = 2027 with renames); under the 3000-line size check", "files_changed": [ ".changeset/28915-record-open-drawer-default.md", "content/docs/frontend/plugins/plugin-view.mdx", "content/docs/ui/views.mdx", "ui/packages/app-shell/src/utils/recordOpenPreference.test.ts", "ui/packages/app-shell/src/utils/recordOpenPreference.ts", "ui/packages/app-shell/src/views/ObjectView.objectListTitle-27950.test.tsx", "ui/packages/app-shell/src/views/ObjectView.phoneRecordPage-27058.test.tsx", "ui/packages/app-shell/src/views/ObjectView.recordCountFooter-10636.test.tsx", "ui/packages/app-shell/src/views/ObjectView.recordDrawer-27545.test.tsx", "ui/packages/app-shell/src/views/ObjectView.recordOpenDisplay-26681.test.tsx", "ui/packages/app-shell/src/views/ObjectView.recordOpenPreference-26677.test.tsx", "ui/packages/app-shell/src/views/ObjectView.titleViewSwitcher-27594.test.tsx", "ui/packages/app-shell/src/views/ObjectView.tsx", "ui/packages/app-shell/src/views/ObjectView.viewRefusal-12112.test.tsx", "ui/packages/app-shell/src/views/RecordDetailView.topBar-27524.test.tsx", "ui/packages/app-shell/src/views/objectViewRecordNavigation.ts", "ui/packages/app-shell/src/views/objectViewRecordOverlay.tsx", "ui/packages/app-shell/src/views/recordDrawerStack.tsx", "ui/packages/components/src/__tests__/chrome-i18n-no-provider-fallback.test.tsx", "ui/packages/components/src/__tests__/navigation-overlay-close-i18n.test.tsx", "ui/packages/components/src/__tests__/navigation-overlay-drawer-27545.test.tsx", "ui/packages/components/src/__tests__/navigation-overlay-field-escape-28156.test.tsx", "ui/packages/components/src/__tests__/navigation-overlay-split-27545.test.tsx", "ui/packages/components/src/__tests__/record-list-face-27545.test.tsx", "ui/packages/components/src/__tests__/record-top-bar-27524.test.tsx", "ui/packages/components/src/custom/index.ts", "ui/packages/components/src/custom/navigation-overlay.tsx", "ui/packages/components/src/custom/record-list-face.tsx", "ui/packages/i18n/src/locales/ar.ts", "ui/packages/i18n/src/locales/de.ts", "ui/packages/i18n/src/locales/en.ts", "ui/packages/i18n/src/locales/es.ts", "ui/packages/i18n/src/locales/fr.ts", "ui/packages/i18n/src/locales/ja.ts", "ui/packages/i18n/src/locales/ko.ts", "ui/packages/i18n/src/locales/pt.ts", "ui/packages/i18n/src/locales/ru.ts", "ui/packages/i18n/src/locales/zh.ts", "ui/packages/plugin-detail/src/__tests__/RecordPageColumns.enlargedEscapeInPane-27524.test.tsx", "ui/packages/plugin-grid/src/ObjectGrid.tsx", "ui/packages/plugin-grid/src/__tests__/ObjectGrid.recordDrawerList-27545.test.tsx", "ui/packages/plugin-grid/src/__tests__/ObjectGrid.recordPaneFace-27545.test.tsx", "ui/packages/plugin-list/src/ListView.tsx", "ui/packages/plugin-list/src/__tests__/ListView.recordDrawerCount-27545.test.tsx", "ui/packages/plugin-list/src/__tests__/ViewSettingsPopover.recordOpen-26681.test.tsx", "ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx" ] }Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Seat review · 2026-11-02T08:06Z · PR #29108 at
aaa5cdb7: contract review (TIER_DEFAULT) PASS 6572157203 and ACCEPT 6572168862. It goes to the merge queue now. Findings filed: #29109 and #29110.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Landed · 2026-11-02T09:20Z · PR #29108 merged through the merge queue as
ea150b7f. Records: contract review (TIER_DEFAULT) PASS 6572157203 and ACCEPT 6572168862, both ataaa5cdb7.ea150b7f~1)origin/main)DEFAULT_RECORD_OPEN_PREFERENCE: RecordOpenPreference = 'drawer'inapp-shell/src/utils/recordOpenPreference.tsRecordOpenPreference = 'split' | 'drawer' | 'page'in the same fileRecordListFaceProviderincomponents/src/custom/index.ts(one of the seven retired exports)recordOpenSplitini18n/src/locales/en.tsThe card closed through
Fixes.pm:dispatchedcomes off with this note. Follow-ups are now orderable: #29109 (domain:ui#1, sidebar fold threshold) and #29110 (domain:ui#3, skills record-page).domain:ui#1's #28950 and #29074, anddomain:ui#4's #29175, mergemainnow.Generated by Claude Code