Repository navigation
feat(plugin-detail)!: one record page laid out by its own width; 动态 is the right column's first panel - #28116
objectstack-fleet[bot] wants to merge 8 commits into
Conversation
… the right column's first panel Two tiers by the container's width: at 760 px and up, details beside a right column (320 px; 380 px with a 3-column details grid at 1120 px and up); below 760 px, one column. The three-column, tabbed and rail tiers, the resident timeline column and its ⊞ switch retire. 动态 is the first panel of the right column: a one-line composer, the newest 3 entries (5 when wide) and 「查看全部 N 条 →」 to the full stream. ⊟ shows or hides the right column. Claude-Session: https://claude.ai/code/session_01Utp6CaA9ZdTcj97mzGtHYt Co-authored-by: Claude <noreply@anthropic.com>
…e by width, the 动态 panel and tab, the ⊟ switch The pins that opened the tabbed tier now read the anatomy that replaced it: the stack in jsdom, the right column's panels, `?related=timeline` for the whole 动态 stream and `?related=<object>.<field>` for a related list's whole face. Changesets for plugin-detail, components, app-shell and i18n. Claude-Session: https://claude.ai/code/session_01Utp6CaA9ZdTcj97mzGtHYt Co-authored-by: Claude <noreply@anthropic.com>
…hored Timeline tab stays a timeline `detail.timeline` names the record page's 动态 stream now, so the tab strip no longer maps the bare word `Timeline` to it: that word is an author's too (the served approval page's history tab). The synthesizer writes `Activity stream` for its stream tab, read as `detail.timeline`; an authored `Timeline` reads the pack's own word for a timeline. The slotted approval request page is laid out, so its actions list opens by `?related=`. Claude-Session: https://claude.ai/code/session_01Utp6CaA9ZdTcj97mzGtHYt Co-authored-by: Claude <noreply@anthropic.com>
…动态 first, laid out by one rule The pages guide and the three QA checklist items that located the stream by the retired timeline column, its switch and the tabbed tier now point at the 动态 panel and its tab (`?related=timeline`). Claude-Session: https://claude.ai/code/session_01Utp6CaA9ZdTcj97mzGtHYt Co-authored-by: Claude <noreply@anthropic.com>
…e, and pin its two-column cap The section-columns helper took a second argument (the cap beside a 320 px right column), so passing it straight to Array.map handed it the index as a cap: a type error in the test project, and a cap nobody meant at runtime. Claude-Session: https://claude.ai/code/session_01Utp6CaA9ZdTcj97mzGtHYt Co-authored-by: Claude <noreply@anthropic.com>
…tack tier The tabbed tier this case pinned is retired: below the 760 px view floor the record page is one column, the details then the right column's panels. The case asserts the stack and the absent tab strip, Invoices and Projects as body tables in the details, 动态 as the right column's first panel, and the Contacts panel reading its rows once scrolled into view. Claude-Session: https://claude.ai/code/session_01Utp6CaA9ZdTcj97mzGtHYt Co-authored-by: Claude <noreply@anthropic.com>
|
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC Contract-review-claim: session_01Utp6CY2n1JmZZKrHgtp9jC · head a38376b · 2026-10-30T13:13Z Full at-tier review ( Generated by Claude Code |
|
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC Contract reviewServed-tier: Read: card #27524 (body, all ten comments incl. the split plan 6513066595, the ruling-B status 6520776586, the ① landing 6521929290 and the ② dev report 6523663352), PR #28116 body and file list (70 files, +1795/−1511), the net diff against Check-runs on ① Derived judgmentsPublic surface of
Stored shapes (app-shell
ADR-0087 markers against Accept-set changes inside the tree, each judged:
② Semver level
No finding in ②. ③ Boundary flagsPR Dev report 6523663352 —
Source re-measured by the dev (the card's Out-of-scope finding (dogfood red ④ Design judgmentScope files, each against the code they cite and Target items 4, 5 and 6 (1, 2, 10–12 landed in ①; 7–9 are ③ and ④; the interim faces — ⊟ at the end of the header's action row, the 动态 tab as
Tests updated, not deleted (Acceptance 4). Findings: must-fix 1 (④-1); should-fix 1 (④-2). Implemented-by: VERDICT: FAIL Generated by Claude Code |
…returns to the record; ⌘⇧, is the topmost record view's Inside the record pane the 动态 tab and a related list's whole face never closed on Esc: the face's guard found the pane's own dialog, and the pane's Esc (the drawer's dialog layer, the split pane's document listener) closed or stepped the pane instead. The face now listens on the window in the capture phase and takes the key unless a text field, an open menu or alert, or a dialog the face is not inside owns it. A drawer wide enough for its own right column draws its own ⊟, and the page under it keeps its tree mounted, so one ⌘⇧, ran both views' listeners and the page's ran first: it flipped the hidden page's stored switch, not the drawer's. Only the topmost record root, the last in document order, answers the chord now. Claude-Session: https://claude.ai/code/session_01Utp6CaA9ZdTcj97mzGtHYt Co-authored-by: Claude <noreply@anthropic.com>
|
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC Preview review (proxy for epic:#26676#1) · a38376b · PASS A context-free review agent ran this per the #26676 ruling B (6520722066). It worked on this head's live console (Vite dev server from source) on Target 4, ⊟ 「右栏」.
Target 5, 动态 as a panel and a tab.
Target 6, one rule by the container's width (the view root is measured, 48 px wider than the tier element):
In Regression, Target 1, 2 and 10.
Notes, none blocking.
Not verifiable live:
Screenshots, in project files (not a repository branch):
Generated by Claude Code |
…he record pane stays open around it The face let an Esc pressed in a text field go on to the field, unmarked, so inside the record pane the drawer's dialog layer took it next and closed the whole pane: Esc in the 动态 tab's composer dropped the reader on the list with `?related=timeline` still in the URL. A field in the face still gets the key (it closes its mention list, cancels an inline edit), and the face marks it handled, so the drawer does not dismiss on it and the face stays open. A field outside the face, and an open floating layer (a select, a popover), keep the key unmarked as before. Claude-Session: https://claude.ai/code/session_01Utp6CaA9ZdTcj97mzGtHYt Co-authored-by: Claude <noreply@anthropic.com>
|
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC Preview review (proxy for epic:#26676#1) · 90828f1 · PASS Delta re-check of the two pane keys from the contract review 6523984004, ④-1 and ④-2. The same context-free review agent as 6524207275 ran it on this head's live console (Vite dev server from source), on An intermediate head, Key 1 (④-2),
Key 2 (④-1),
Nothing was skipped. The maximized pane is still not reachable in this console (no ⤢ yet, #27545), as in 6524207275. Screenshots are in project files, not a repository branch:
|
|
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC Contract-review-claim: session_01Utp6CY2n1JmZZKrHgtp9jC · head 90828f1 · 2026-10-30T14:24Z Delta review of the findings commits ( Generated by Claude Code |
|
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC Contract reviewServed-tier: Delta review after record 6523984004 (FAIL on Check-runs on ① Derived judgmentsEach finding of record 6523984004, checked in the tree (not the body):
No accept-set or public-surface change: the delta touches no export, prop type, stored shape or i18n pack. ② Semver levelUnchanged from record 6523984004: ③ Boundary flagsNo new dev flag arrived with the delta. Carried from record 6523984004 and still standing, not decided here: the human-merge path for a diff over 3,000 lines (an authorized APPROVED review or the maintainer's merge; this record alone lands nothing). The dev's out-of-scope finding is real, and pre-existing. PR ④ Design judgment
Tests. The chord pin renders a second real Findings: must-fix 0; should-fix 0. Implemented-by: VERDICT: PASS Generated by Claude Code |
|
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC 席位核对ACCEPT · head
Generated by Claude Code |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 41080050426 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
|
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC The merge-queue red (run 41080050426, The red test. Why This PR's part. It touches neither the ledger nor that test ( The fix |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 41083191968 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC
Requested by Bill · project thread
Part of #27524
Clause-②: yes (narrowing)
Metadata-protocol: none
Skills-docs: content —
content/docs/ui/pages.mdxdescribed the synthesized record page's tab strip, its column tiers, the related rail and the timeline column; it now describes the details and the right column, 动态 first, laid out by one rule. No file underskills/**teaches the record page's layout (agit grepfor the tiers, the switch and the stream names nothing there).维护者速读
?related=timeline,完整流:筛选、回复、加载更多)。右栏开关 ⊟(「右栏」,⌘⇧,)只剩一个图标。detail.timeline的值改成 动态 / Activity,所以手写页面的Timeline页签不再映射到它,仍读「时间线」。回滚即 revert 本 PR。ui/packages/plugin-detail/src/RecordPageColumns.tsx(档位与右栏);RecordTimelinePanel.tsx+RecordActivityTimeline.tsx的 peek 面;synth/recordPageColumns.ts(宽度规则);app-shellRecordDetailView.tsx(⊟ 与开页读)。pnpm --dir ui exec vitest run packages/plugin-detail/src/__tests__/RecordTimelinePanel-27524.test.tsx packages/app-shell/src/views/RecordDetailView.recordPageTiers-26678.test.tsx packages/app-shell/src/views/RecordDetailView.panelToggles-27052.test.tsx,预期 3 个文件、23 个测试全绿。a38376b7be上判 FAIL。④-1:⌘⇧,会串到抽屉下面的页面。④-2:在抽屉里按 Esc 会关掉整个抽屉,而不是先退出放大面。两个修复提交之后,复审 6525247890 判 PASS。预览审查两次 PASS(6524207275、6525118794)。遗留 Record pane: Esc that a field already handled still steps the pane back a level (or restores it from maximized) #28156:抽屉最大化或在下层时,字段内的 Esc 会被抽屉接走;那段代码属 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。What changes
The synthesized record page is laid out by one rule, the width of the container it occupies, and 动态 becomes the right column's first panel (record page v4, canvas 60). This is PR ② of four serial PRs for #27524, approved by the seat as a split. It restarts from
mainafter PR ① merged and leavesmaincoherent on its own.?related=timelineface; PR ③ makes it a tab of the tab row)6. One rule (
synth/recordPageColumns.ts,useRecordPageTier.ts,RecordPageColumns.tsx).recordPageTierFor(width)answerswidefrom 1120 px (RECORD_PAGE_WIDE_MIN_WIDTH),two-columnfrom 760 px,stackbelow it and for an unknown width. The embedded record (split pane, overlay drawer, maximized) and the phone take the same answer:useRecordPageTierlostembedded. Both column tiers draw details | the right column, 320 px (grid-cols-[minmax(0,1fr)_20rem]) or 380 px when wide (_23.75rem). The stack is one column: the details, then the right column's panels in their order. A details section takes up to three field columns when wide and two beside a 320 px column (DetailsColumnCapContext, read byframelessSectionColumns). The three-column tier, the tabbed tier, the 「相关 N」 rail (relatedRail,record-related-rail-toggle), the resident timeline column, its ⊞ promotion andrecordTimelineDefaultReason/recordPageColumnDefaults/recordPageArrangementForretire. The right column is an<aside aria-label="右栏">in every tier.5. 动态 is a panel and a tab (
RecordTimelinePanel.tsx,renderers/record-activity.tsx,RecordActivityTimeline.tsx). The panel leads the right column and has a related panel's header: 「动态」, the stream's count (data-record-timeline-count, absent while the feed loads), and the header row as one stretched button that opens the 动态 tab (the census rule from PR ①). Its body is the page's ownrecord:activityblock in a peek face, chosen byRecordTimelinePanelContext:detail.timelineComposer). Pressed, it becomes the full composer, focused; a sent note folds it back;The 动态 tab is
?related=timeline, the existing enlarged face: the whole stream with the 全部 · 活动 · 讨论 · 变更 chips, threaded replies and "Load more" (data-stream-load-more, one page per press; it replaces the stream's own 「查看全部」). The synthesized tab strip, where a page keeps one, orders details / 动态 / related for every object; the worked-object promotion is gone.4. ⊟ (app-shell
RecordDetailView.tsx, componentspanel-toggles.tsx). One toggle, 「右栏」, drawn at the end of the record header's action row only where the tier has a right column and the page has a panel for it.⌘⇧,flips it;⌘⇧.(the timeline column's) is gone. Off, the details take the row. The stored preference keeps its name,record.columns.related, so a reader's earlier related-column choice holds;record.columns.timelineis no longer read.PanelTogglesdraws icon-only toggles named by their label (no border group,h-8 w-8).Naming.
detail.timelineis 「动态」 / "Activity" in all ten packs (the valuesdetail.timelineFoldedhad).detail.relatedColumnis 「右栏」 / "Right column";console.shortcuts.toggleRelatedfollows.detail.timelineFoldedandconsole.shortcuts.toggleTimelineleave every pack;detail.timelineComposerarrives in all ten.Tab labels (components
containers.tsx). Withdetail.timelinenow naming the stream, the strip's well-known-token map could no longer send the bare wordTimelineto it: the served approval page's history tab is labelledTimeline, and in en it read "Activity" (approvalRequestsDataSource.servedPagewent red on exactly that). The synthesizer writes its own token,Activity stream, for its stream tab (read asdetail.timeline), and an authoredTimelinereadsconsole.objectView.viewTypeTimeline, the pack's word for a timeline (zh-TW keeps its dict form). Pinned inpage-tabs-builtin-label-i18n-4645.Open waves. The 动态 panel is on screen at open in every tier, so a synthesized page reads its feed, the mention list and the audit log at open at every width (before, the narrow tier waited for the Timeline tab). Opening the 动态 tab reads none of them again. An authored page with tabs still waits for the tab that holds them (
recordOpenWaves-13010keeps those cases unchanged).Review fixes. The contract review 6523984004 on
a38376b7bewas FAIL, with must-fix ④-1 and should-fix ④-2. The delta review 6525247890 on90828f16cbis PASS.d98543cb28). A record page keeps its tree mounted under the drawer it opens. A drawer wide enough for its own right column draws its own ⊟, so one⌘⇧,ran both views' listeners. The page's listener ran first and flipped the hidden page's stored switch. Now only the topmost record root (the last[data-record-page-root]in the document) answers the chord.d98543cb28,90828f16cb). Inside the record pane,Escon an open face (the 动态 tab, or a related list's whole face) closed or stepped the pane, because the face's guard found the pane's own dialog. The face now listens on the window in the capture phase and ignores the dialog that holds it. It takes the key ahead of the drawer's dialog layer and the split pane's listener.Escpressed in a text field inside the face still reaches the field, which closes its mention list or cancels an inline edit. The face marks it handled, so the drawer does not dismiss on it. The preview re-check ond98543cb28found this case, and90828f16cbfixes it.onEscapeKeyDownacts without readingdefaultPrevented. SoEscin a field inside a face restores or steps the pane there. That handler is innavigation-overlay.tsx, 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's surface, and the behaviour is onmaintoday at level 2 and deeper.Declared.
Clause-②: yes (narrowing). Two changesets:27524-record-page-tiers-activity-panel.md(plugin-detail, components, app-shell): eight exports and three members leave the plugin-detail entry, undernot-required (runtime-export-retired …)with one FROM → TO line each. The gate verifies all eleven.RecordPageTierbecomes'stack' | 'two-column' | 'wide', andrecordPageTierFortakes one argument. Both are said in prose.27524-record-page-activity-i18n.md(i18n):TranslationKeysloses the two keys, undernot-required (runtime-interface-only …#TranslationKeys), as PR ① did.Size: over the human-merge threshold. This PR changes 3,571 lines (+2,052 / −1,519 over 71 files,
additions + deletions), over the 3,000 of AGENTS.md §7(c), so it lands the way a Tier H surface does: an authorized APPROVED review (GOVERNED_APPROVERS) and then the owning seat, or the maintainer's merge. It is not split further. More than a third of it is retired code and pins rewritten to the new anatomy (acceptance item 4), and Target 5 and 6 share one retirement, the timeline column: a split would have to build an interim layout that exists only to be deleted by the next PR.Source re-measured. The card names
record.timeline.*keys. No such namespace exists: the record page's labels aredetail.timeline(value changed),detail.timelineFoldedandconsole.shortcuts.toggleTimeline(both retired). The 1200 px board draws the details grid at three columns; this follows the card's rule, two columns beside the right column below 1120 px.File surface. Outside the card's list:
components/src/custom/panel-toggles.tsx(⊟ is icon-only),components/src/renderers/layout/containers.tsx(theTimelinetoken above),app-shell/src/utils/workspacePreference.ts(the timeline switch's preference retires),RichTextCommentInput.tsx(autoFocusfor the expanded composer),DetailSection.tsx/defaultRecordPage.ts(the details column cap), the plugin-detail README,content/docs/ui/pages.mdx, three items ofdocs/qa/platform-checklist/areas/records-forms.jsonthat located the stream by the retired column, andui/e2e/live/record-history-display.spec.ts(opens?related=timeline; onmain#28009 had re-pointed it at the folded Activity card that this PR retires).Seat-approved addition (the dispatch keeps
examples/**off limits):examples/app-showcase/e2e/detail-shapes.spec.ts, the Contoso case only. #28009 pinned it to the tabbed tier at a 780 px window, and Target 6 retires that tier, so the nightly showcase smoke would go red on this PR's merge. The case now reads the one-column stack tier instead (seat 2 widened the surface to this one file; the rest ofexamples/**is untouched).Tests
New:
plugin-detail/src/__tests__/RecordTimelinePanel-27524.test.tsx(7): the realrecord:activityblock in the panel. Header 「Activity」 and the whole stream's count, the header opens the tab; the newest three roots (a reply is not a line), no chips, no load-more, 「查看全部 8」 opens the tab; five when wide; no 「查看全部」 when the stream holds no more; no count while the feed loads; the one-line composer expands focused and folds after a sent note; CONTROL: outside the panel the same block is the full stream.plugin-detail/src/__tests__/RecordPageColumns.enlargedEscapeInPane-27524.test.tsx(6). It runs through the realNavigationOverlay(its Radix sheet and its split listener), with the page's blocks stubbed:Escon the 动态 tab returns to the record's page, and the nextEscdismisses the drawer;Esc;Escwhile the face and the pane stay, in the drawer and in the split pane.Rewritten to the new anatomy, not deleted (acceptance item 4):
RecordDetailView.recordPageTiers-26678(6): 1440 and 1200 wide (380 px, details grid at three), 1100 two-column (320 px, two), 720 and 390 one column with 动态 after the details, embedded at 1440 and 720 by the same rule,?tab=addresses no strip and?related=timelineis the full stream.RecordDetailView.panelToggles-27052(10): one icon 「Right column」 at the end of the action row; off and on; survives a remount, per object; non-worked and container objects open with the right column;⌘⇧,by key and by character, inert in a text field;⌘⇧.is not the page's; not drawn in the one column; drawn for the embedded record at 1440; with a 1000 px drawer over a 1440 px page,⌘⇧,flips the drawer's switch alone, and the page's once the drawer is gone.recordPageV3Face-27055(the details column cap: two beside a 320 px right column),RecordPageColumns.test,RecordPageColumns.switches-27052,synth/recordPageColumns.test,synth/recordPageColumns.switches-27052,RelatedCardStack-27055,recordTimelineStream-27055,buildDefaultPageSchema.*(order details / 动态 / related for every object),panel-toggles.test,workspacePreference.*.examples/app-showcase/e2e/detail-shapes.spec.ts, the Contoso case (nightly showcase smoke): at 780 px (732 px of view) the page isstack,data-record-columns-shown="details", no Details / Related tab; Invoices and Projects are body tables in the details with their rows read at open; the right column's first panel is 动态, Invoices and Projects are not panels; the Contacts panel reads 「Carl Fox」 once scrolled into view. The flat-details, money-strip and footer assertions are unchanged.approvalLock-12220,approvalLock-25934,approvalRecallGate: the first of the page's probes), the feed and audit pins (?related=timeline), the related-list wire pins (relatedBadgeArity-8882andrelatedListFilter-4664read the panel's count and rows;relatedListInheritedSort-5795andchildWriteRefreshesParent-12244open the list's whole face),relatedCountsFirst-27056,relatedListsOrder-27241,bodyTablePredicate-27478(the right column),accessibleNames-12625(the right column and its panels are named),recordOpenWaves-13010(the synthesized cases read at open), and consoleapprovalRequestsDataSource.decisionPage(the slotted request page is laid out; its actions list opens by?related=).Runs
Head
90828f16cb(the two review-fix commits ona38376b7be), under the verify lock:pnpm --dir ui exec vitest runover 105 test files (bygit ls-files:RecordDetailView.*, the drawer tests,navigation-overlay*and consoleapprovalRequestsDataSource.*) pluspackages/plugin-detail→Test Files 452 passed | 1 skipped (453),Tests 3820 passed | 18 skipped (3838), VERDICT command-exit 0.type-checkof@object-ui/plugin-detailand@object-ui/app-shell: each exit 0. eslint on the four changed files: 0 errors.Escpin was red ond98543cb28: the drawer'ssetIsOpen(false)was called for anEscin a field inside the face. It is green on90828f16cb.90828f16cb: all 61 check-runs concluded success, or skipped by path filter or opt-in.Test UI(16/16),Type Check UI,Lint UIandLive E2E UIare among them.Head
a38376b7be, onmainf0857d29c1(PR ① merged asad030d805b; #27953 is in), under the verify lock unless said:pnpm build→Tasks: 115 successful, 115 total, VERDICT command-exit 0.pnpm --dir ui exec vitest run packages/plugin-detail packages/i18nplus 322 test files acrossui/: the 311 that name a module or id this PR changes (RecordDetailView,RecordPageColumns,useRecordPageTier,record:activity,page:tabs,PanelToggles,workspacePreference,detail.timelineand the rest; derived bygit grepon this head) and the 11 test files feat(ui): record pane v4 mechanics — split beside the list, non-modal drawer over a list, maximize in place, narrowed list faces #27953 added or changed for the pane →Test Files 760 passed | 1 skipped (761),Tests 9018 passed | 31 skipped (9049), VERDICT command-exit 0. The wholeui/suite is left to CI Test UI: a full local run outlives this container's background ceiling.type-check(tsc --noEmit+tsc -p tsconfig.test.json) of@object-ui/i18n,@object-ui/components,@object-ui/plugin-detail,@object-ui/app-shell, and@objectstack/example-showcase typecheck(itstsconfigincludese2e/): each exit 0. eslint on the 64 touchedts/tsxfiles underui/: 0 errors (unlocked).pnpm console:build:cd examples/app-showcase && OS_TEST_TIERS=nightly pnpm exec vitest run test/showcase-smoke.live.test.ts test/console-live-specs.live.test.ts→Test Files 2 passed (2). The showcase smoke's Playwright run:53 passed, the three detail-shapes cases among them (Contoso on the stack tier). The console live specs:19 passed,record-history-displayamong them (the Changes chip on the 动态 tab).Before the restart, on
c888a82d32(PR ①'s8b20d10d4c): the same derivation gave 742 files green. That run found one type-check error, in plugin-detail's test project:recordPageV3Face-27055passedframelessSectionColumnsstraight toArray.map, which now hands it the index as the new cap.c888a82d32(now81683b80b7) calls it with the count and pins the cap. Three console approval page pins (decisionPage,servedPage,servedPageMemberPermissions-13324) were red on the first run, before the Tab labels fix above and thedecisionPagerewrite.Acceptance notes
Screenshots: on
examples/app-crm, not HotCRM (deviation, as the order says); eleven shotspr2-*.pngin/mnt/project-files/ui-seat2/card-27524/shots/(project files, not a repository branch), zh, through the console's dev server onc888a82d32(before the restart ontomain; the record page code is unchanged by it). Measured in the page (container width → tier, right column width, 动态 lines):pr2-01-account-1440(container 1184 →wide, right column 380, 动态 shows 5 of 6 and 「查看全部 6 条 →」),pr2-02-account-1200(944 →two-column, 320, 3 lines),pr2-03-account-1000(952 →two-column, 320).pr2-04-account-720andpr2-09-account-390(phone, full page): one column, the details, then 动态, then the related panels; no ⊟.pr2-05-activity-panel,pr2-06-composer-open(the one-line composer pressed: the full composer, focused),pr2-07-activity-tab(「查看全部」 →?related=timeline: chips 全部 · 活动 · 讨论 · 变更, threaded entries),pr2-08-right-column-off(⊟ off at 1440: the details take the row).pr2-10-lead-1440(details grid at three columns beside 380) andpr2-11-lead-1000(two beside 320). app-crm's account shows no details body at all: every field it holds a value for is a highlight, the same onmain.The tier follows the container, not the window: with the sidebar open, a 1200 px window gives a 944 px page, which is
two-column.Preview review (proxy for 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#1, per ruling B 6520722066):
a38376b7be(6524207275). It covered Target 4, 5 and 6, plus a regression pass on ①, at 1440, 1200, 1000, 720 and 390 and in the pane opened from a list.90828f16cb(6525118794). This was a delta re-check of the two pane keys,Escand⌘⇧,, at 1440 and 720.Verification
Gates and the dogfood run
Head
90828f16cb, change set vs the merge basef0857d29c1: 71 paths, 3,571 changed lines (OVER the 3,000 line).node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon90828f16cb→ 84 commands, the same list as ona38376b7be. Each was run and its exit code captured before any pipe. All 84 are:: exit 0,node scripts/check-sdui-manifest.mjsamong them. One more was run beyond the derivation,pnpm --dir ui run check:i18n-drift :: exit 0.pnpm check:type-check-debtfirst answered exit 3, NOT MEASURED: its closure build queued behind the dogfood run for the verify lock. Rerun under the lock, it exits 0 (0 raw tsc error(s) total, none above its recorded number). That rerun is the code recorded below.--ranreconcile:84 derived, 84 run, 0 NOT-MEASURED, 0 UNRUN.90828f16cb(the title has!), under the verify lock:pnpm --filter @objectstack/dogfood test→ VERDICT command-exit 1,Test Files 1 failed | 359 passed | 1 skipped (361),Tests 1 failed | 2891 passed | 9 skipped (2901). This is the same single red as ona38376b7be:api-action-door-forward.dogfood.test.ts, "the switch holds: ban_user OFF answers 409 ACTION_DISABLED…".sys_metadata_activationin the disabled-action sentence that3e0fd7a8f7(feat(spec,metadata-protocol,rest,objectql,runtime): GET /meta/object serves switched-off packaged actions beside the item, and the disabled-action refusal reads as a plain sentence #27964) rewrote. That red ismain's own, already carded as main red (Dogfood Regression Gate 3/3) since 3e0fd7a8 (#27964): the api-action door dogfood pin still expectssys_metadata_activationin the disabled-action sentence that #27842 rewrote #28082. This PR touches neither the action door nor that sentence.Dogfood Regression Gateis success on this head.type-checkruns above stand in for the lanes of the four packages this PR changes.mainhas moved 33 commits pastf0857d29c1since the restart, andgit merge-treewith it is clean. The shared paths are the ten locale packs,RecordDetailView.tsxandcontainers.tsx, in different hunks. CI's merge ref covers it, and no merge was pushed (seat, 13:12Z).Body refreshed 2026-10-30T14:49Z for head
90828f16cb: the two review fixes, their runs, the preview re-check and the gates and dogfood run on this head.Generated by Claude Code