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
console list Display menu: 「打开记录」 (drawer | split) as a per-user preference; an object or view declaring page shows the declaration instead; the name cell's hover ↗ opens the record as a full page #26681
Part of the record-page-v2 epic #26676 (child 4 of 4). Runs after #26677 (the preference util it writes) and after #26637 (claimed by the domain:ui seat 4, no PR yet; it edits the same popover's Layout row and width).
Source (origin/main 416a76030e)
ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx has a Layout row (:322-329), the Sections Group (:332), Row Color (:358) and Hide Fields (:385), a Density row (:416-419) and the Row numbers / Edit inline toggles (:443, :452), and nothing about how a row opens (grep for navigation, drawer, split: empty); the split pane used to be authored (navigation.mode: 'split'), which #26677 retires in favour of a per-user preference read (recordOpenPreference, app-shell). A row's name cell opens the record one way only (the resolved mode); there is no affordance to open it as a full page from the list.
Target
Display menu, a new section 「打开记录」 with two segments 抽屉 | 分屏 writing recordOpenPreference; the choice is the user's, per browser, across objects; the section's note reads 「个人偏好,不进对象声明;两种都能展开为整页」.
For an object or view whose resolved mode is page, the section is a read-only line 「此对象声明为整页打开」 (the declaration wins; no segments).
The name cell shows a hover-only ↗ (tooltip 「整页打开」) that navigates to the record route without changing the preference; keyboard-reachable.
No new metadata; no change to navigation reading.
File surface
ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx and its host wiring in app-shell (ObjectView.tsx passes the resolved mode and the preference setter), the name-cell renderer in ui/packages/plugin-grid (the link column of objectui#4490), i18n keys in ui/packages/i18n, tests beside; changesets for the touched published packages.
Acceptance
Tests: the section renders the segments for a drawer object and the read-only line for a page object; choosing 分屏 then clicking a row draws the split face; the hover ↗ navigates to the record route.
Screenshot of the Display menu on HotCRM leads and on opportunities (HotCRM lead declares page).
Rulings (maintainer, 2026-10-27, chat in the filing session — verbatim, not re-decidable here)
The model, quoted back by the maintainer and ordered built: 「1. 一个对象一个默认打开方式:默认抽屉(带展开整页),page 只给显式声明的对象,modal 退役,split / popover 变成用户个人偏好;抽屉和整页是同一张页在两个宽度。」
On the drawer's top bar: 「左上角的 任务 · 2 / 2 · 分屏 几个字有必要嘛」 — no object name, no mode label on the bar.
On the position counter: 「我觉得记录详情页显示第几条记录 好像也没必要」 — no "n / N" anywhere on a record; the ↑ ↓ previous / next controls stay.
On the right pane: 「右侧应该可以拖动吗?展开为整页那个是不是用图标就可以」 — the pane is drag-resizable and "open as full page" is an icon-only control with a tooltip.
On related records, the maintainer confirmed the in-place model: 「所以关联记录是一层一层的往下点,然后可以一层一层的反悔吗」 — one level down per click, one level back per ← / Esc, never a second drawer.
Filed by the epic PM session session_cdb7a717-def7-4e71-9988-f089fbaa18ff on 2026-10-27, from the record-page / list-page assessment and the clickable prototype the maintainer walked and ruled on in that session (objectstack main 416a76030e, HotCRM 1f3f8880 on platform 18.2.0). The maintainer's instruction to build it, verbatim: 「你直接立卡派发处理这个开发,然后审核。」 Design evidence (never merged): branch claude/record-page-v2-evidence-20261027b at commit 345ec777220843ce1fd7f95b6cc0b2b6dcc81bf8, folder docs/design/record-page-v2-2026-10-27/ (prototype.html, artboards/, assessment.md).
Target unchanged; three Source statements are corrected and the landing path is wider than the card says:
ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx (586 lines, after fix(plugin-list): fold the Display popover's layout segments to icons when they would not fit #26696): Layout row :390-396 (LayoutSlot, folds to icons), Group :400, Row Color :426, Hide Fields :453, Density :484-506, Row numbers :510, Edit inline :519, footer :529; props ViewSettingsPopoverProps:64; nothing about row opening. Its only host is plugin-list/src/ListView.tsx:5967 — not ObjectView: the new section's props travel ObjectView → plugin-view PluginObjectView → ListView → the popover.
The name cell's anchor is plugin-grid/src/objectGridLinkCell.tsxLinkCell (:83-175, host.recordHref + onActivate), wired in objectGridGenerateColumns.tsx (:397, :415, :635, :647) — not ObjectGrid.tsx. No hover-only control exists in the cell; the hover-reveal pattern to copy is plugin-grid/src/components/RowActionMenu.tsx:650.
i18n: flat list.* keys in ui/packages/i18n/src/locales/en.ts (list::990) and zh.ts (:756) plus the eight other locales, and plugin-list/src/ListView.tsx:1089-1090 keeps a defaults map byte-pinned to the en pack by app-shell/src/__tests__/defaults-maps-mirror-en-pack.test.tsx.
Claim: PM loop round 2 (epic #26676, child 4 of 4)
Session: session_cdb7a717-def7-4e71-9988-f089fbaa18ff
Account: zhuangjianguo
Branch: claude/issue-26681-display-record-open-preference
Worktree: objectstack-issue-26681
Domain: domain:ui
Seat: epic #26676 (the epic PM session, not a domain seat)
File surface: ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx (the new 「打开记录」 section) and its host wiring in app-shell (ObjectView.tsx passes the resolved mode and the preference setter; ListView.tsx relay if the popover is reached through it), ui/packages/app-shell/src/utils/recordOpenPreference.ts (the WRITE side beside the read side #26804 shipped), the name-cell renderer in ui/packages/plugin-grid/src/ObjectGrid.tsx (hover ↗), i18n keys in ui/packages/i18n, tests beside, changesets for the touched published packages; ⛔ packages/spec/**, ⛔ navigation-overlay.tsx / objectViewRecordNavigation.ts (#26679) (stop on breach; explain in the report)
Container & model: M, mode:subagent (desktop session on the maintainer's macOS; verify lock in declared-unlocked mode; one of two parallel subagents, the other on components / app-shell record navigation), model: TIER_DEFAULT (dispatch-gates --tier 2026-10-27T23:59Z: no path-derived mandate), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: none
Premise: corrected 6456666557 (line numbers and landing path re-read on origin/main 7bb8084; target unchanged)
Serial constraints cleared: #26637 CLOSED via PR #26696 (the layout row folds to icons) — the popover constraint is gone, work on the merged popover; #26804 (this epic) MERGED at 23:43Z shipped recordOpenPreference.ts (read side) and the ObjectView split face driven by it; #26679 (this epic, in parallel) edits components navigation-overlay.tsx, app-shell record navigation / overlay / bridge / RecordDetailView.tsx, disjoint; no open PR touches ViewSettingsPopover.tsx or ObjectGrid.tsx (scan 2026-10-27T23:59Z)
Dispatched at 2026-10-27T23:59Z as an os-dev subagent of this session; the dispatch order lives in the subagent's opening prompt.
{
"issue": 26681,
"status": "done",
"branch": "claude/issue-26681-display-record-open-preference",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27031",
"session": "session_cdb7a717-def7-4e71-9988-f089fbaa18ff — the dispatching PM session (mode:subagent)",
"premise_still_valid": true,
"summary": "Display menu (ViewSettingsPopover) gains the Open records section after Layout: drawer-mode rows get 抽屉 | 分屏 segments writing the reader's preference plus the ruling's note; page-mode rows get the read-only line 此对象声明为整页打开; new_window / none and hosts without the prop draw nothing. recordOpenPreference.ts gains the write side and useRecordOpenPreference (useSyncExternalStore, same-page writes plus cross-tab storage events), which replaces ObjectView's read-once useState, so a choice takes effect on the next row click. The name cell's hover ↗ (整页打开, anchor at the host recordHref, plain click via host openRecord, stops before the row) is drawn for drawer rows only, through a new ObjectGrid/ListView host channel recordLinkAdornment beside the first authored link (else the auto-linked primary field). Two dispatch hypotheses corrected: the props travel ObjectView → renderListView → ListView → popover (plugin-view PluginObjectView is not on the path); and the grid's existing rowAdornment was tried first and dropped after a HotCRM measurement put the ↗ in the contacts avatar column (contact nameField full_name is not a column).",
"tests": "On head 3d7fb4c462 from ui/: vitest run --maxWorkers=3 packages/app-shell/ packages/plugin-grid/ packages/plugin-list/ packages/i18n/ → Test Files 2307 passed | 1 skipped (2308), Tests 21776 passed | 22 skipped (21798), exit 0. New suites: ViewSettingsPopover.recordOpen-26681 (7+ cases), ObjectGrid.recordLinkAdornment-26681 (4), ObjectView.recordOpenDisplay-26681 (4: Split then row click draws the split face; no choice opens the drawer; page view read-only line and no ↗; ↗ href /apps/demo/duly_task/record/r1 beside the link, click lands on the record route, no drawer, nothing stored), recordOpenPreference.test write side (2). type-check (i18n, plugin-grid, plugin-list, app-shell, after building the three libs) exit 0, each script echoed. Reverse verification via scripts/ablation-replace.mjs with trap restore on committed state: resolvedMode 'split' as const → app-shell tsc TS2322 (Type '\"split\"' is not assignable to '\"none\" | \"drawer\" | \"page\" | \"new_window\"'), exit 2; restored blob 43072da53b2a, git diff HEAD empty. A first leg adding an extra key stayed green (exit 0, no excess-property check on a contextually typed arrow return) and is declared a no-op, not counted. No ablation: the behaviour is new, not changed. Screenshots of HotCRM 1f3f8880 (fresh DB, console from this branch's ui src) on evidence branch commit 964025cf3f3f7a2ecfd4a743d250699f2ec552ec, linked in the PR body.",
"gates": "Local, derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 3d7fb4c462 (35 commands; it warned origin/main had moved 7 commits, only .github/workflows/ci.yml differing in the family source), each exit captured before any pipe: 0 | node scripts/check-adr-0087-registration.mjs --base origin/main; 0 | node scripts/check-adr-0087-registration.mjs --self-test; 0 | node scripts/check-changeset-no-major.mjs --base origin/main; 0 | node scripts/check-closing-keyword-parity.mjs; 0 | node scripts/check-closing-keyword-parity.mjs --self-test; 0 | node scripts/check-comment-mask-corpus.mjs; 0 | node scripts/check-empty-changeset.mjs --base origin/main; 0 | node scripts/check-empty-changeset.mjs --self-test; 0 | node scripts/check-sdui-manifest.mjs; 0 | node scripts/check-sdui-manifest.mjs --self-test; 0 | node scripts/pm/release-rehearsal-clone.mjs --self-test; 0 | node scripts/release-pending-publish.mjs --self-test; 1 | pnpm --dir ui exec vitest run scripts/; 0 | pnpm --filter @objectstack/spec run check:duration-unit-keys; 0 | pnpm check:changeset-gate-self-tests; 0 | pnpm check:closed-ceremony-text; 0 | pnpm check:cross-package-test-inputs; 0 | pnpm check:dispatcher-error-vocabulary; 0 | pnpm check:driver-memory-census; 0 | pnpm check:engine-double-contract; 0 | pnpm check:error-status-conformance; 0 | pnpm check:gitlink-declared; 0 | pnpm check:nul-bytes; 0 | pnpm check:pm-changeset-deadline-census; 0 | pnpm check:published-files; 0 | pnpm check:query-options-erasure; 0 | pnpm check:refd-timer-probe; 0 | pnpm check:skill-identifier-liveness; 0 | pnpm check:test-source-alias; 0 | pnpm check:tier-file-adoption; 0 | pnpm check:type-check-coverage; 0 | pnpm check:type-check-debt; 0 | pnpm check:undeclared-dep-imports; 0 | pnpm check:watch-hint-literal; 0 | pnpm check:where-matcher. The one red, pnpm --dir ui exec vitest run scripts/ (14 files / 22 tests under load average 14), rerun in isolation: 12 of 14 files green, 2 red — select-affected-tests-wiring (mapfile: command not found, exit 127, macOS bash 3; host artifact) and check-i18n-dead-keys one case timing out at 15000 ms; the gates themselves run directly: node ui/scripts/check-i18n-dead-keys.mjs exit 0 (no new key reported), node ui/scripts/check-i18n-call-site-keys.mjs exit 0. --ran reconciliation not run as a separate invocation (every derived command ran, list = the derived list). CI check-runs at 3d7fb4c462: 53 total, 43 success, 10 skipped, 0 failed — Lint & Repo Gates success, TypeScript Type Check success, Test Core success, Build Core skipped, Governed Surface Queue Guard success, Lint UI success, Type Check UI success, Test UI success (16/16 shards success), Build & E2E UI success, Check Changeset success. Every verification ran in DECLARED UNLOCKED MODE (no flock); disclosed in the PR body.",
"mcp_calls": "0",
"api_writes": "3 — POST /repos/objectstack-ai/objectstack/pulls (draft, #27031); POST /repos/objectstack-ai/objectstack/issues/27031/assignees (zhuangjianguo); POST /repos/objectstack-ai/objectstack/issues/26681/comments (this report, via post-stamped). Label writes: 0 (dispatch named none; a changeset exists, so no skip-changeset). git pushes (not REST): the branch (6 pushes) and one evidence branch claude/issue-26681-evidence-20261028 (orphan commit, screenshots only, never merged).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted, not filed — the ↗ tooltip zh 整页打开 (console.objectView.openAsPage, per the dispatch ruling text) and the drawer's expand control console.objectView.expandToPage 以完整页面打开 are two zh spellings of one English sentence on one page; recorded in the PR Acceptance notes, the drawer's controls are #26679's.",
"carrier: 承接者:无 · noted, not filed — ui/scripts/__tests__/select-affected-tests-wiring.test.ts cannot pass on macOS (shard.sh uses bash mapfile); host-local, CI runs Linux and is green."
],
"line_budget": "24 files, +999 / -18 (tests 497 of the additions); no governed surface, no skills/**.",
"deviations": [
"PR opened by direct REST (scripts/pm/with-fleet.sh -- gh api -X POST /pulls, then POST /issues/27031/assignees) because fleet-write/dispatch.mjs refused the local session id (exit 3, PREREQUISITE NOT MET), as the dispatch anticipated.",
"One extra git push: the evidence branch for the screenshots (acceptance 2 asks for them; the bot cannot attach files).",
"Mechanism hypotheses corrected: props do not pass through plugin-view PluginObjectView; the ↗ lives in app-shell objectViewOpenAsPage.tsx and reaches LinkCell through a new recordLinkAdornment host prop rather than being built inside LinkCell, so plugin-grid stays router-free and only the console decides drawer-only.",
"new_window / none draw no Open records section (the ruling names no copy for them); the wide toolbar has no twin of the section.",
"First reverse-verification leg was a no-op (extra key not rejected) and was replaced by a rejected-value leg."
],
"files_changed": [
".changeset/26681-display-record-open-preference.md",
"ui/packages/app-shell/src/utils/recordOpenPreference.ts",
"ui/packages/app-shell/src/utils/recordOpenPreference.test.ts",
"ui/packages/app-shell/src/views/ObjectView.tsx",
"ui/packages/app-shell/src/views/objectViewListRenderer.tsx",
"ui/packages/app-shell/src/views/objectViewOpenAsPage.tsx",
"ui/packages/app-shell/src/views/ObjectView.recordOpenDisplay-26681.test.tsx",
"ui/packages/plugin-list/src/ListView.tsx",
"ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx",
"ui/packages/plugin-list/src/__tests__/ViewSettingsPopover.recordOpen-26681.test.tsx",
"ui/packages/plugin-grid/src/ObjectGrid.tsx",
"ui/packages/plugin-grid/src/objectGridGenerateColumns.tsx",
"ui/packages/plugin-grid/src/objectGridLinkCell.tsx",
"ui/packages/plugin-grid/src/__tests__/ObjectGrid.recordLinkAdornment-26681.test.tsx",
"ui/packages/i18n/src/locales/{en,zh,ar,de,es,fr,ja,ko,pt,ru}.ts"
]
}
Review recorded on the PR: #27031## 席位核对 — ACCEPT at head 3d7fb4c462; ready + auto-merge handed to the queue on the maintainer's standing authorization for this epic (verbatim, 2026-10-28: 「授权你用车队身份给 #26758 翻 ready 并挂 auto-merge(squash),后续本 epic 的 PR 复核 ACCEPT 后同样处理」). pm:dispatched stays until MERGED; the card closes by the PR's Fixes line. — epic PM session_cdb7a717-def7-4e71-9988-f089fbaa18ff, 2026-10-28T02:36Z
Activity
objectstack-fleet commentedon Oct 27, 2026
Premise reading before dispatch · epic PM
session_cdb7a717-def7-4e71-9988-f089fbaa18ff· origin/main7bb8084590· 2026-10-27T23:58ZTarget unchanged; three Source statements are corrected and the landing path is wider than the card says:
ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx(586 lines, after fix(plugin-list): fold the Display popover's layout segments to icons when they would not fit #26696): Layout row:390-396(LayoutSlot, folds to icons), Group:400, Row Color:426, Hide Fields:453, Density:484-506, Row numbers:510, Edit inline:519, footer:529; propsViewSettingsPopoverProps:64; nothing about row opening. Its only host isplugin-list/src/ListView.tsx:5967— notObjectView: the new section's props travel ObjectView → plugin-viewPluginObjectView→ListView→ the popover.ui/packages/app-shell/src/utils/recordOpenPreference.ts(feat(spec,ui)!: a record opens one way per object — navigation.mode keeps drawer (the default), page, new_window and none; modal, split and popover are retired; the split pane becomes a reader preference #26804) is READ-only (readRecordOpenPreference, storage typePick<Storage, 'getItem'>); the write function and asetItemstorage type are this card's.ObjectView.tsx:717-721reads it once per mount (useState(readRecordOpenPreference), no setter) and decidesopensBesideListat:740— the choice must take effect live, so the read becomes reactive state the Display control updates.plugin-grid/src/objectGridLinkCell.tsxLinkCell(:83-175,host.recordHref+onActivate), wired inobjectGridGenerateColumns.tsx(:397,:415,:635,:647) — notObjectGrid.tsx. No hover-only control exists in the cell; the hover-reveal pattern to copy isplugin-grid/src/components/RowActionMenu.tsx:650.list.*keys inui/packages/i18n/src/locales/en.ts(list::990) andzh.ts(:756) plus the eight other locales, andplugin-list/src/ListView.tsx:1089-1090keeps a defaults map byte-pinned to the en pack byapp-shell/src/__tests__/defaults-maps-mirror-en-pack.test.tsx.ObjectGrid.tsx/objectGridGenerateColumns.tsxwere split byf79ec28949on 2026-10-27;ViewSettingsPopover.tsxlast changed by fix(plugin-list): fold the Display popover's layout segments to icons when they would not fit #26696 (5cc31c7885).Generated by Claude Code
objectstack-fleet commentedon Oct 28, 2026
Claim: PM loop round 2 (epic #26676, child 4 of 4)
Session:
session_cdb7a717-def7-4e71-9988-f089fbaa18ffAccount:
zhuangjianguoBranch:
claude/issue-26681-display-record-open-preferenceWorktree:
objectstack-issue-26681Domain:
domain:uiSeat: epic #26676 (the epic PM session, not a domain seat)
File surface:
ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx(the new 「打开记录」 section) and its host wiring in app-shell (ObjectView.tsxpasses the resolved mode and the preference setter;ListView.tsxrelay if the popover is reached through it),ui/packages/app-shell/src/utils/recordOpenPreference.ts(the WRITE side beside the read side #26804 shipped), the name-cell renderer inui/packages/plugin-grid/src/ObjectGrid.tsx(hover ↗), i18n keys inui/packages/i18n, tests beside, changesets for the touched published packages; ⛔packages/spec/**, ⛔navigation-overlay.tsx/objectViewRecordNavigation.ts(#26679) (stop on breach; explain in the report)Container & model:
M,mode:subagent(desktop session on the maintainer's macOS; verify lock in declared-unlocked mode; one of two parallel subagents, the other on components / app-shell record navigation),model: TIER_DEFAULT(dispatch-gates --tier 2026-10-27T23:59Z: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: none
Premise: corrected 6456666557 (line numbers and landing path re-read on origin/main 7bb8084; target unchanged)
Serial constraints cleared: #26637 CLOSED via PR #26696 (the layout row folds to icons) — the popover constraint is gone, work on the merged popover; #26804 (this epic) MERGED at 23:43Z shipped
recordOpenPreference.ts(read side) and theObjectViewsplit face driven by it; #26679 (this epic, in parallel) edits componentsnavigation-overlay.tsx, app-shell record navigation / overlay / bridge /RecordDetailView.tsx, disjoint; no open PR touchesViewSettingsPopover.tsxorObjectGrid.tsx(scan 2026-10-27T23:59Z)Dispatched at 2026-10-27T23:59Z as an
os-devsubagent of this session; the dispatch order lives in the subagent's opening prompt.Generated by Claude Code
objectstack-fleet commentedon Oct 28, 2026
os-dev-report
{ "issue": 26681, "status": "done", "branch": "claude/issue-26681-display-record-open-preference", "pr": "https://github.com/objectstack-ai/objectstack/pull/27031", "session": "session_cdb7a717-def7-4e71-9988-f089fbaa18ff — the dispatching PM session (mode:subagent)", "premise_still_valid": true, "summary": "Display menu (ViewSettingsPopover) gains the Open records section after Layout: drawer-mode rows get 抽屉 | 分屏 segments writing the reader's preference plus the ruling's note; page-mode rows get the read-only line 此对象声明为整页打开; new_window / none and hosts without the prop draw nothing. recordOpenPreference.ts gains the write side and useRecordOpenPreference (useSyncExternalStore, same-page writes plus cross-tab storage events), which replaces ObjectView's read-once useState, so a choice takes effect on the next row click. The name cell's hover ↗ (整页打开, anchor at the host recordHref, plain click via host openRecord, stops before the row) is drawn for drawer rows only, through a new ObjectGrid/ListView host channel recordLinkAdornment beside the first authored link (else the auto-linked primary field). Two dispatch hypotheses corrected: the props travel ObjectView → renderListView → ListView → popover (plugin-view PluginObjectView is not on the path); and the grid's existing rowAdornment was tried first and dropped after a HotCRM measurement put the ↗ in the contacts avatar column (contact nameField full_name is not a column).", "tests": "On head 3d7fb4c462 from ui/: vitest run --maxWorkers=3 packages/app-shell/ packages/plugin-grid/ packages/plugin-list/ packages/i18n/ → Test Files 2307 passed | 1 skipped (2308), Tests 21776 passed | 22 skipped (21798), exit 0. New suites: ViewSettingsPopover.recordOpen-26681 (7+ cases), ObjectGrid.recordLinkAdornment-26681 (4), ObjectView.recordOpenDisplay-26681 (4: Split then row click draws the split face; no choice opens the drawer; page view read-only line and no ↗; ↗ href /apps/demo/duly_task/record/r1 beside the link, click lands on the record route, no drawer, nothing stored), recordOpenPreference.test write side (2). type-check (i18n, plugin-grid, plugin-list, app-shell, after building the three libs) exit 0, each script echoed. Reverse verification via scripts/ablation-replace.mjs with trap restore on committed state: resolvedMode 'split' as const → app-shell tsc TS2322 (Type '\"split\"' is not assignable to '\"none\" | \"drawer\" | \"page\" | \"new_window\"'), exit 2; restored blob 43072da53b2a, git diff HEAD empty. A first leg adding an extra key stayed green (exit 0, no excess-property check on a contextually typed arrow return) and is declared a no-op, not counted. No ablation: the behaviour is new, not changed. Screenshots of HotCRM 1f3f8880 (fresh DB, console from this branch's ui src) on evidence branch commit 964025cf3f3f7a2ecfd4a743d250699f2ec552ec, linked in the PR body.", "gates": "Local, derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 3d7fb4c462 (35 commands; it warned origin/main had moved 7 commits, only .github/workflows/ci.yml differing in the family source), each exit captured before any pipe: 0 | node scripts/check-adr-0087-registration.mjs --base origin/main; 0 | node scripts/check-adr-0087-registration.mjs --self-test; 0 | node scripts/check-changeset-no-major.mjs --base origin/main; 0 | node scripts/check-closing-keyword-parity.mjs; 0 | node scripts/check-closing-keyword-parity.mjs --self-test; 0 | node scripts/check-comment-mask-corpus.mjs; 0 | node scripts/check-empty-changeset.mjs --base origin/main; 0 | node scripts/check-empty-changeset.mjs --self-test; 0 | node scripts/check-sdui-manifest.mjs; 0 | node scripts/check-sdui-manifest.mjs --self-test; 0 | node scripts/pm/release-rehearsal-clone.mjs --self-test; 0 | node scripts/release-pending-publish.mjs --self-test; 1 | pnpm --dir ui exec vitest run scripts/; 0 | pnpm --filter @objectstack/spec run check:duration-unit-keys; 0 | pnpm check:changeset-gate-self-tests; 0 | pnpm check:closed-ceremony-text; 0 | pnpm check:cross-package-test-inputs; 0 | pnpm check:dispatcher-error-vocabulary; 0 | pnpm check:driver-memory-census; 0 | pnpm check:engine-double-contract; 0 | pnpm check:error-status-conformance; 0 | pnpm check:gitlink-declared; 0 | pnpm check:nul-bytes; 0 | pnpm check:pm-changeset-deadline-census; 0 | pnpm check:published-files; 0 | pnpm check:query-options-erasure; 0 | pnpm check:refd-timer-probe; 0 | pnpm check:skill-identifier-liveness; 0 | pnpm check:test-source-alias; 0 | pnpm check:tier-file-adoption; 0 | pnpm check:type-check-coverage; 0 | pnpm check:type-check-debt; 0 | pnpm check:undeclared-dep-imports; 0 | pnpm check:watch-hint-literal; 0 | pnpm check:where-matcher. The one red, pnpm --dir ui exec vitest run scripts/ (14 files / 22 tests under load average 14), rerun in isolation: 12 of 14 files green, 2 red — select-affected-tests-wiring (mapfile: command not found, exit 127, macOS bash 3; host artifact) and check-i18n-dead-keys one case timing out at 15000 ms; the gates themselves run directly: node ui/scripts/check-i18n-dead-keys.mjs exit 0 (no new key reported), node ui/scripts/check-i18n-call-site-keys.mjs exit 0. --ran reconciliation not run as a separate invocation (every derived command ran, list = the derived list). CI check-runs at 3d7fb4c462: 53 total, 43 success, 10 skipped, 0 failed — Lint & Repo Gates success, TypeScript Type Check success, Test Core success, Build Core skipped, Governed Surface Queue Guard success, Lint UI success, Type Check UI success, Test UI success (16/16 shards success), Build & E2E UI success, Check Changeset success. Every verification ran in DECLARED UNLOCKED MODE (no flock); disclosed in the PR body.", "mcp_calls": "0", "api_writes": "3 — POST /repos/objectstack-ai/objectstack/pulls (draft, #27031); POST /repos/objectstack-ai/objectstack/issues/27031/assignees (zhuangjianguo); POST /repos/objectstack-ai/objectstack/issues/26681/comments (this report, via post-stamped). Label writes: 0 (dispatch named none; a changeset exists, so no skip-changeset). git pushes (not REST): the branch (6 pushes) and one evidence branch claude/issue-26681-evidence-20261028 (orphan commit, screenshots only, never merged).", "open_questions": [], "out_of_scope_findings": [ "carrier: 承接者:无 · noted, not filed — the ↗ tooltip zh 整页打开 (console.objectView.openAsPage, per the dispatch ruling text) and the drawer's expand control console.objectView.expandToPage 以完整页面打开 are two zh spellings of one English sentence on one page; recorded in the PR Acceptance notes, the drawer's controls are #26679's.", "carrier: 承接者:无 · noted, not filed — ui/scripts/__tests__/select-affected-tests-wiring.test.ts cannot pass on macOS (shard.sh uses bash mapfile); host-local, CI runs Linux and is green." ], "line_budget": "24 files, +999 / -18 (tests 497 of the additions); no governed surface, no skills/**.", "deviations": [ "PR opened by direct REST (scripts/pm/with-fleet.sh -- gh api -X POST /pulls, then POST /issues/27031/assignees) because fleet-write/dispatch.mjs refused the local session id (exit 3, PREREQUISITE NOT MET), as the dispatch anticipated.", "One extra git push: the evidence branch for the screenshots (acceptance 2 asks for them; the bot cannot attach files).", "Mechanism hypotheses corrected: props do not pass through plugin-view PluginObjectView; the ↗ lives in app-shell objectViewOpenAsPage.tsx and reaches LinkCell through a new recordLinkAdornment host prop rather than being built inside LinkCell, so plugin-grid stays router-free and only the console decides drawer-only.", "new_window / none draw no Open records section (the ruling names no copy for them); the wide toolbar has no twin of the section.", "First reverse-verification leg was a no-op (extra key not rejected) and was replaced by a rejected-value leg." ], "files_changed": [ ".changeset/26681-display-record-open-preference.md", "ui/packages/app-shell/src/utils/recordOpenPreference.ts", "ui/packages/app-shell/src/utils/recordOpenPreference.test.ts", "ui/packages/app-shell/src/views/ObjectView.tsx", "ui/packages/app-shell/src/views/objectViewListRenderer.tsx", "ui/packages/app-shell/src/views/objectViewOpenAsPage.tsx", "ui/packages/app-shell/src/views/ObjectView.recordOpenDisplay-26681.test.tsx", "ui/packages/plugin-list/src/ListView.tsx", "ui/packages/plugin-list/src/components/ViewSettingsPopover.tsx", "ui/packages/plugin-list/src/__tests__/ViewSettingsPopover.recordOpen-26681.test.tsx", "ui/packages/plugin-grid/src/ObjectGrid.tsx", "ui/packages/plugin-grid/src/objectGridGenerateColumns.tsx", "ui/packages/plugin-grid/src/objectGridLinkCell.tsx", "ui/packages/plugin-grid/src/__tests__/ObjectGrid.recordLinkAdornment-26681.test.tsx", "ui/packages/i18n/src/locales/{en,zh,ar,de,es,fr,ja,ko,pt,ru}.ts" ] }Posted 2026-10-28T02:33Z.
Generated by Claude Code
objectstack-fleet commentedon Oct 28, 2026
Review recorded on the PR: #27031
## 席位核对— ACCEPT at head3d7fb4c462; ready + auto-merge handed to the queue on the maintainer's standing authorization for this epic (verbatim, 2026-10-28: 「授权你用车队身份给 #26758 翻 ready 并挂 auto-merge(squash),后续本 epic 的 PR 复核 ACCEPT 后同样处理」).pm:dispatchedstays until MERGED; the card closes by the PR'sFixesline. — epic PMsession_cdb7a717-def7-4e71-9988-f089fbaa18ff, 2026-10-28T02:36ZGenerated by Claude Code