Repository navigation
Commit 55a1feb
feat(app-shell): one top bar above the record header on every face, the enlarged related list draws a toolbar, and Activity counts on a deep link (#28458)
domain:ui#5 · os-sales · session_01L6bhgVP3twvBvDTwoLPU6J
<!-- claude-projects-attribution: {"github_login":"os-sales"} -->
_Requested by **Sales** · [project
thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4UuP5SeDdTXdueuof1bJtgkLy)_
Fixes #27524
Clause-②: yes (widening: `@object-ui/components` gains `RecordTopBar`,
`RecordTopBarButton`, `useRecordStepKeys` and the types
`RecordTopBarProps` / `RecordTopBarStepper`; `NavigationOverlay` gains
an optional `toggles` prop and its `stepper` an optional `position` and
`scope`; `@object-ui/i18n` gains eight `detail.*` keys in all ten
locales; no entry export retires and no accept set moves. The claim's
provisional `no` is corrected here, measured on the diff.)
Metadata-protocol: none
## 维护者速读
- **改了什么**:记录在每一种呈现方式里(整页、分屏面板、覆盖抽屉、最大化、手机)都在记录头上方画一条 40 px 顶栏。左边是面包屑「对象
› 记录名」(点对象回列表;面板下一层仍是「← 路径」);右边按固定顺序只画适用的控件:计数「3 / 21」和 ↓ ↑、⊟、⤢ /
⤡、✕。原来记录头上方的面包屑行(‹ 来源、收为抽屉)删掉,⊟ 从记录头操作行移进顶栏。另带两项(③
预览闸门裁定):放大的相关列表画看板工具栏(筛选、全部 / 我的 / 逾期、新建、导出)而不是卡片头尾;深链到别的标签时「动态」标签也显示条数。
- **为什么改**:#27524 Target 7 和 Target 4 的 ⊟ 部分(画布 60 定稿),四个串行 PR 的最后一个,带
`Fixes #27524`。
- **风险与回滚**:只动 ui 包(components、app-shell、plugin-detail、十个语言包),不碰
spec、不碰服务端。没有退役任何入口导出(`PanelToggles`、`PageHeaderTrailingContext`
都保留,宿主自己的普通覆盖层仍把 ⊟ 放在记录头末尾),所以是 widening。整页上的计数和 ↓ ↑ 只在从列表打开时出现(行的
↗,或行本身就开整页的列表,比如 HotCRM 线索),用 `replace` 换页,不增历史;⤡ 只给 ↗ 打开的整页。回滚即 revert
本 PR。
- **先看**:`ui/packages/components/src/custom/record-top-bar.tsx`(顶栏和 j /
k 归属);`ui/packages/app-shell/src/views/RecordDetailView.tsx` 的
`pageLeading` / `pageBar`;`recordDrawerStack.tsx` 的
`useRecordPageReturn` 和
`RecordPaneBarToggles`;`ui/packages/plugin-detail/src/RelatedList.tsx` 的
`enlargedFace`。
- **两分钟验证**:`pnpm --dir ui exec vitest run
packages/components/src/__tests__/record-top-bar-27524.test.tsx
packages/app-shell/src/views/RecordDetailView.topBar-27524.test.tsx
packages/plugin-detail/src/__tests__/RelatedList.enlargedToolbar-27524.test.tsx
packages/plugin-detail/src/__tests__/RecordPageColumns.tabRow-27524.test.tsx
packages/app-shell/src/views/objectViewRecordNavigation.listRows-27524.test.tsx`,预期
5 个文件 34 个测试全绿。
- **需要你做的**:无,席位做预览闸门(HotCRM 截图对照 v4 画板)后落地。
## What changes
Record page v4, Target 7 and the ⊟ half of Target 4, plus the two
ride-alongs ruled at ③'s preview gate. PR ④ of the four serial PRs for
#27524, cut from `main` after ③ (#28394, `bf74607954`).
### The top bar (Target 7)
`RecordTopBar` (`@object-ui/components`, new
`custom/record-top-bar.tsx`) is one 40 px row above the record header.
The page, the split pane, the overlay drawer, the maximized pane and a
phone all draw this one component.
- **Left: the breadcrumb.**
- At the pane's root it reads 「对象 › 记录名」 (for example 「线索 › Mira
Costa」). The object name closes the pane, which returns to the list.
- One level down in the pane, the bar keeps 「← 路径」 as #26679 drew it.
- On the page, the object goes to the list the page was opened from (the
`?from=` origin, without the record the list had open) or else to the
object's list.
- A page opened under a `?from=` trail draws ← and the path, and each
ancestor links to its own page.
- The record's name in the pane bar comes from the record itself,
through `RecordPaneBarContext.reportTitle`.
- **Right, in a fixed order.** First the counter 「n / N」 and ↓ ↑, then a
hairline, then ⊟, then ⤢ / ⤡, then ✕. Each one is drawn only where it
applies:
- **The pane.** The counter and ↓ ↑ show whenever the list reported its
rows (#26679's sibling set). The tooltip names the list: 「全部线索 中第 3 条,共
21 条」. ✕ closes the whole path.
- **The page.** The counter and ↓ ↑ show only for a page a list opened.
That is the row's ↗, or a row click or record link on a list whose rows
open as pages, as HotCRM's lead list does. Every navigation the list
makes to a record's page (`handleNavOverlayNavigate`) now hands the
shown rows in the page's `from` state when the record is one of them,
and the ↗ also hands them in its way back to the pane. ↓ ↑ and `j` / `k`
replace the page with the sibling's page, keep the list's state, and
drop `?related=`. On the page the arrow keys still scroll.
- **⤡ 「收为抽屉」** shows only for a page the row's ↗ opened. It returns to
the list with the record you stepped to open in the pane. A list whose
rows open as pages opens no pane, so there is nothing to collapse to.
- **A page opened directly** shows only ⊟. It has no counter, no ⤡ and
no ✕.
- **The step keys** belong to the latest host. While a pane is open over
a page, the pane owns `j` / `k` until it closes (`useRecordStepKeys`
keeps an owner stack).
- **What goes.** The crumb row above the record header goes: the 「‹
origin」 and 「收为抽屉」 row, together with its small ‹ line. The header's
action row keeps the business actions only.
### ⊟ in the top bar (Target 4)
The right-column switch (「右栏」, ⌘⇧,) leaves the header's action row.
- On the page it is drawn in the page's top bar.
- In the pane, the record portals it into the pane's own bar
(`RecordPaneBarToggles` into the bar's `data-record-pane-toggles` slot).
- It is drawn only where the face's tier has a right column, the rule ②
already applied to `PanelToggles`.
- A host's plain overlay without the console's pane
(`InterfaceListPage`, `ObjectDataPage`) has no bar slot. It keeps ⊟ at
the end of the header's action row through `PageHeaderTrailingContext`,
so that export stays.
### Ride-along (a): the enlarged related list draws the board toolbar
When a related list is the active tab, `RecordPageColumns` provides
`RelatedListEnlargedContext`. `RelatedList` then draws:
- **A toolbar** (`role="toolbar"`) over the table, in place of the card
header and the card foot. The toolbar holds:
- the filter input;
- the chips 全部 N / 我的 / 逾期;
- the child object's toolbar actions;
- 新建;
- 导出.
- **A status line** 「N 条 · 第 x / y 页」 between the toolbar and the table.
- **The table at the face's full height.**
Each chip is drawn only where the child object declares what it says:
- **我的** where the object has an `owner_id` column. It filters with `{
owner_id: '{current_user_id}' }`.
- **逾期** where a `date` / `datetime` field declares `dueLike: true` with
no `settledWhen`. It filters with `{ field: { $lt: '{today}' } }`. A
`settledWhen` is CEL that no query can ask, so such a field gets no
chip.
- **全部** alone is no choice, so then no chip group is drawn.
A chip narrows the list's own read: it is merged beside the parent scope
with `mergeFilterNodes`.
**导出** downloads a CSV through `dataSource.exportDownload`. It sends the
same parent, chip and list filter, the filter text as `search`, the
shown columns and the order.
### Ride-along (b): 动态's count on a deep link
`RecordTimelineCountProbe` (in `record-activity.tsx`) reads the feed the
page already holds and reports its size to the tab row. The feed is the
discussion context, the field-change context, and the node's types and
`showCompleted`. The probe starts no read of its own. It is mounted only
when the 动态 tab is not active and the stream is not drawn elsewhere: a
deep link to another tab, or ⊟ off. Before ④, 动态 had no count there
until the stream was drawn once (③'s noted gap).
### i18n
Eight keys arrive in all ten packs, with each pack's plural forms:
`detail.recordOfScope`, `detail.relatedFilter`, `detail.relatedChips`,
`detail.relatedChipAll`, `detail.relatedChipMine`,
`detail.relatedChipOverdue`, `detail.relatedExport` and
`detail.relatedRows`.
### File surface beyond the claim
- `app-shell`:
- `ObjectView.tsx`, `objectViewRecordNavigation.ts` and
`objectViewRecordOverlay.tsx`: the view's label as the counter's scope,
and the shown rows handed to every page the list opens.
- `recordDrawerContext.ts`: the pane bar context.
- `urlParams.ts`: one state-key constant.
- `components`: `custom/record-top-bar.tsx` and its line in
`custom/index.ts`, in place of `renderers/layout/containers.tsx`. The
bar is a frame component, not a page-layout slot, so `containers.tsx` is
untouched. `panel-toggles.tsx` is untouched too: ⊟ is still
`PanelToggles`, drawn in a new place.
- `plugin-detail`: `RelatedList.tsx`, `relatedListCompact.ts`,
`renderers/record-activity.tsx` and `useDetailTranslation.ts`, for the
two ride-alongs.
#27545's split / overlay / maximize mechanics are not changed.
`NavigationOverlay` only draws its existing ⤢ / ⤡ / ✕ into the shared
bar.
## Tests
New:
- `components/src/__tests__/record-top-bar-27524.test.tsx` (6):
- the right end's fixed order;
- the counter's text and its tooltip naming the list;
- only what is handed is drawn;
- the pair without a counter;
- the step-key owner stack: a page steps with `j` / `k` but not the
arrows, a pane over it takes the keys until it closes, and a pane with
no set holds them without stepping the page;
- `NavigationOverlay` drawing the shared bar.
- `app-shell/src/views/RecordDetailView.topBar-27524.test.tsx` (7), a
real `RecordDetailView`:
- a direct page: the crumb, only ⊟, no crumb row;
- a page from ↗: the counter 「2 / 3」 with its scope, ↓ to the sibling by
`replace`, `k` back, ArrowUp ignored, ⤡ back to `?recordId=` with the
restore state;
- a page a list opened as a page: 「1 / 3」 with its scope, no ⤡, `j` and
↑ step, and the next page keeps the same `from` state;
- control: an origin without its rows draws no counter;
- the object crumb back to the origin list;
- a `?from=` trail with ← and the ancestors;
- the pane: ⊟ portalled into the pane's bar, the record's title reported
to the crumb, one bar only, the scope tooltip.
-
`app-shell/src/views/objectViewRecordNavigation.listRows-27524.test.tsx`
(3), the list's navigation hook:
- a row that opens as a page hands the origin, the view's name and the
shown rows;
- control: a record the list does not show gets the origin alone;
- the row's ↗ hands the rows both in the way back to the pane and in the
origin.
-
`plugin-detail/src/__tests__/RelatedList.enlargedToolbar-27524.test.tsx`
(5):
- the toolbar with no card;
- 我的 and 逾期 narrowing the read beside the parent;
- a chip drawn only where the object declares it;
- 导出 with the parent and the chip;
- control: outside the active tab the card face stays.
- `plugin-detail/src/__tests__/RecordPageColumns.tabRow-27524.test.tsx`
(+3):
- 动态's count on a deep link to another tab;
- control: no count while the feed is loading or absent;
- the count with ⊟ off.
Pins updated to the new anatomy, not deleted:
- `RecordDetailView.panelToggles-27052` (#27052): ⊟ in the top bar,
nothing in the header's trailing slot, no crumb row, the bar before the
header.
- `recordDrawerStack-26679` and `recordDrawerStack.rootStepper-26679`
(#26679): the root crumb 「对象 › 记录名」 and the counter.
- `RelatedCardStack-27055` (#27055): the enlarged face's stub sees the
enlarged context.
- `RecordDetailView.pageHeaderTitleFls-10499`: the record's gated name
now appears twice, in the H1 and in the top bar's crumb. The pin checks
that the crumb names the same gated title and never the denied email,
and that the body still shows the name once.
- `residue-namespaces-3546`: RelatedList's `detail.add` sites number
four with the toolbar's Add.
- The #26678 pins (`RecordDetailView.recordPageTiers-26678`,
`RelatedList.compactColumn-26678`) needed no change and ran green in the
broad suite below. No test file is named for #27473. The plugin-detail
package and the record-view tests, where its pins would sit, ran in full
in that suite.
<details><summary>Eleven ablations (each through <code>node
scripts/ablation-replace.mjs</code>, restore proven blob ==
HEAD)</summary>
- The page's bar not drawn: `RecordDetailView.topBar-27524`, 4 failed.
- The pane toggles not portalled: 1 failed.
- The page stepper withheld: 1 failed.
- The page's `from` rows not read (`readFromSiblings`):
`RecordDetailView.topBar-27524`, 1 failed | 6 passed.
- The list's navigation not handing its rows in `from`:
`objectViewRecordNavigation.listRows-27524`, 2 failed | 1 passed.
- The root crumb reverted to the bare path: 1 failed.
- The step-key owner stack disabled (every host steps):
`record-top-bar-27524`, 2 failed.
- The count probe not mounted: `RecordPageColumns.tabRow-27524`, 2
failed.
- The enlarged face off: `RelatedList.enlargedToolbar-27524`, 4 failed |
1 passed.
- The chip left out of the read: `RelatedList.enlargedToolbar-27524`, 2
failed | 3 passed.
- The enlarged context not provided by `RecordPageColumns`:
`RelatedCardStack-27055`, 1 failed | 12 passed.
</details>
## Acceptance notes
**Screenshots on HotCRM** against the v4 boards at `a7825499aa`, zh-CN.
They are committed on this branch in `b0a817c91d` and removed again in
the next commit, so they never reach `main`. The folder's
[README](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/README.md)
says how they were made, and
[`facts.json`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/facts.json)
records each shot's top bar as read from the DOM.
HotCRM runs on this branch's own server. The published 18.2.0 server has
no `POST /data/:object/:id/page`, which the console's record page now
reads, so it shows 「未找到记录」. Three of HotCRM's lead form views declare
the form `type`s that spec 18.3.0 retired; in the rig's clone only, they
were set to `simple`.
| Shot | What the top bar shows | Board |
|:--|:--|:--|
|
[`01-lead-1440-from-list.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/01-lead-1440-from-list.png?raw=true)
| Lead at 1440, opened from the lead list. HotCRM's lead list opens its
rows as pages, so there is no ↗ there. The bar reads 「线索 › Mira Costa」
with `1 / 21`, the tooltip 「全部线索 中第 1 条,共 21 条」, and ↓ ↑. There is no ⊟:
the lead declares its own page layout, which has no right column. |
RecordPageV4Panels |
|
[`02-lead-1440-after-step-down.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/02-lead-1440-after-step-down.png?raw=true)
| After ↓: `2 / 21`, Kai Watanabe, the page replaced. |
RecordPageV4Panels |
|
[`03-lead-1200-direct.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/03-lead-1200-direct.png?raw=true)
| Lead at 1200, opened directly: the crumb only. | RecordPageV4TwoCol |
|
[`04-contact-split-720.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/04-contact-split-720.png?raw=true)
| Contact in the split pane at 720: 「联系人 › John Smith」, ⤢, ✕. There is
no counter because the contact list is grouped by account (see the first
note below). There is no ⊟ because the 720 tier has no right column. |
RecordDrawerV4Peek |
|
[`05-contact-maximized.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/05-contact-maximized.png?raw=true)
| The pane maximized: ⊟, ⤡, ✕. | RecordDrawerV4Max |
|
[`06-contact-split-task-tab.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/06-contact-split-task-tab.png?raw=true)
| The pane with 任务 active, chosen from 「+5 ▾」. The toolbar holds the
filter, 全部 1 / 我的, 新建 and 导出, with 「1 条」 under it. |
RecordDrawerV4Enlarged |
|
[`07-contact-page-task-tab-deep-link.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/07-contact-page-task-tab-deep-link.png?raw=true),
[`07b-contact-page-task-tab-mine.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/07b-contact-page-task-tab-mine.png?raw=true)
| The contact page deep-linked to 任务: the same toolbar, and 动态 counts
`2` although its stream is not drawn. | RecordPageV4Enlarged |
|
[`08-product-1440.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/08-product-1440.png?raw=true)
| Product at 1440, opened directly: the crumb and ⊟. |
RecordPageV4Product |
|
[`09-lead-phone-390.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/09-lead-phone-390.png?raw=true),
[`09b-contact-phone-390.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/09b-contact-phone-390.png?raw=true)
| A 390 phone: the crumb only. | RecordMobile |
|
[`10-crm_account-split-pane-counter.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/10-crm_account-split-pane-counter.png?raw=true),
[`11-crm_account-split-pane-after-step.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/11-crm_account-split-pane-after-step.png?raw=true)
| An account in the pane over the ungrouped account list: `3 / 9`, then
`4 / 9` after ↓, with ⤢ and ✕. | RecordDrawerV4Peek |
|
[`12-crm_account-page-from-arrow.png`](https://github.com/objectstack-ai/objectstack/blob/b0a817c91dcac099c993f1a9246198079159f5a6/evidence/record-page-v4-top-bar/12-crm_account-page-from-arrow.png?raw=true)
| An account page opened by the row's ↗: `1 / 9`, ↓ ↑, ⊟, ⤡ 「收为抽屉」. |
RecordPageV4Panels |
No shot has the crumb row (`crumbRow: false` in every `facts.json`
entry). Every top bar measures 40 px.
Not built here, reported:
- **The counter's group scope.** Target 7 says the tooltip names the
group when the list was grouped or is a kanban column. `ListView`
reports its row sequence only for the paged, ungrouped grid (#26679,
`rowSequenceShown`). On a grouped list or a kanban board the pane
therefore has no sibling set and draws no counter at all; the HotCRM
contact list, grouped by account, is one. Naming the group needs
`ListView` (plugin-list, outside this claim) to report grouped and lane
rows with their group. That is a follow-up.
- **逾期 on HotCRM.** `crm_task.due_date` does not declare `dueLike`, so
HotCRM's 任务 tab shows 全部 / 我的 only. The chip appears where an object
declares the deadline.
- **The object crumb.** It returns to the list without a pane, so the
board's "the record you last saw stays selected" is not drawn: the list
has no selection without a pane. ⤡ is the path that returns with the
record open.
- **导出.** It sends the filter text to the server as `search`, while the
table's own text filter is a client-side contains sweep over the fetched
page. The CSV can differ where the server's search matches other fields.
- **The phone.** It draws the same bar. The board's phone header (‹
title ↑ ↓ ⋯) and bottom action bar are a separate face and are not in ④.
- **The app header's crumb** is unchanged (#27950 holds the list title,
per the release).
## Human Minimum
Each item is one rule from
[CONTRIBUTING.md › Human
Minimum](https://github.com/objectstack-ai/objectstack/blob/main/CONTRIBUTING.md#human-minimum),
which links the AGENTS.md text that states it.
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(`packages/spec` is not touched.)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; eslint on the changed files: 0 errors.
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset.
- [x] 6. `packages/spec` touched: its generated artifacts are
regenerated and committed. (Not touched.)
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English (the 维护者速读 block is the
project's Chinese summary).
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
## Verification
All local readings are at head `d94e010b0a`, which includes the merge of
`origin/main` `5517005d3a`. Against that merge base the change is 37
paths, +2,125 / −303. The evidence folder is added and removed inside
the range, so it is not among them.
<details><summary>Tests, type-check, lint</summary>
- **Broad suite.** Under the verify lock: `pnpm exec vitest run
--maxWorkers=3 packages/plugin-detail packages/components packages/i18n`
plus the 619 other test files under `ui/` that name a module, test id or
key this PR changes, derived by `git grep`.
- The run was on `6c535caa83`: `Test Files 4 failed | 1529 passed | 2
skipped (1535)`, `Tests 10 failed | 17140 passed | 67 skipped (17217)`.
- All ten reds came from this change, in four files:
- `all-locales-key-parity` and `plural-categories-11432`: fr / es / pt
lacked `detail.relatedRows_many`, and ar's `_one` / `_two` lacked
`{{count}}`;
- `residue-namespaces-3546`: RelatedList's `detail.add` count, now 4
with the toolbar's Add;
- `RecordDetailView.pageHeaderTitleFls-10499`: the record's name now
also appears in the top bar's crumb. The pin now checks that the crumb
names the same gated title and never the denied email.
- All four were fixed in `d94e010b0a`, and the four files rerun green:
`Tests 107 passed (107)`.
- **Type-check.** `type-check` (`tsc --noEmit` + `tsc -p
tsconfig.test.json`) of `@object-ui/app-shell`, `@object-ui/components`
and `@object-ui/plugin-detail` under the lock, and `@object-ui/i18n` at
`d94e010b0a`: each exit 0.
- **eslint** on the 36 added or modified `ts` / `tsx` files under `ui/`
at `d94e010b0a`: 0 errors. The warnings left on added lines are
`react-refresh/only-export-components` on the hook exports beside
components, a pattern these files already follow.
- **`pnpm --dir ui run check:i18n-drift`**: exit 0.
</details>
<details><summary>Derived gate families: 34 derived, 34 run, 0
NOT-MEASURED</summary>
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derives the same 34 commands at `857d25f771`
and at `d94e010b0a`. Each was run at `d94e010b0a` with stdin from
`/dev/null`, and its exit code was captured before any pipe.
An earlier pass at `857d25f771` had one red: `pnpm --dir ui exec vitest
run scripts/`, in `check-doc-snippet-types`' root-bound case on
`plugin-grid` / `plugin-report` READMEs that this branch does not touch.
It came while a `turbo` build was rewriting `@objectstack/spec`'s `dist`
(the HotCRM rig), and it is green on every run since: `169 passed | 2
skipped`, `4901 passed`.
`--ran` on this record: "34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN … a
DERIVED zero — all 34 recorded an exit code and none of them is 3".
```
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-sdui-manifest.mjs :: exit 0
node scripts/check-sdui-manifest.mjs --self-test :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --dir ui exec vitest run scripts/ :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-changeset-deadline-census :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
```
</details>
<details><summary>Merge-tree and what was not run</summary>
- `main` has moved 7 commits past the merge base. Two of them are
#28438, which touches `ObjectView.tsx`, and #28436. `git merge-tree
--write-tree HEAD origin/main` (`776c1d875b`) is clean, and so is the
open #28440. No second merge was pushed.
- Not run locally, left to CI: the whole `ui/` suite, the other
type-check lanes and the repo-wide scans.
</details>
CI check-runs: not started at the time of writing.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L6bhgVP3twvBvDTwoLPU6J)_
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01L6bhgVP3twvBvDTwoLPU6J
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 7e1089e commit 55a1feb
37 files changed
Lines changed: 2125 additions & 303 deletions
File tree
- .changeset
- ui/packages
- app-shell/src
- views
- __tests__
- components/src
- __tests__
- custom
- i18n/src
- __tests__
- locales
- plugin-detail/src
- __tests__
- renderers
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
107 | 114 | | |
108 | 115 | | |
109 | 116 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
745 | 745 | | |
746 | 746 | | |
747 | 747 | | |
748 | | - | |
| 748 | + | |
749 | 749 | | |
750 | 750 | | |
751 | 751 | | |
| |||
1168 | 1168 | | |
1169 | 1169 | | |
1170 | 1170 | | |
| 1171 | + | |
1171 | 1172 | | |
1172 | 1173 | | |
1173 | 1174 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
204 | 204 | | |
205 | 205 | | |
206 | 206 | | |
207 | | - | |
208 | | - | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
209 | 211 | | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
210 | 215 | | |
211 | | - | |
| 216 | + | |
212 | 217 | | |
213 | 218 | | |
214 | 219 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
27 | | - | |
28 | | - | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
29 | 31 | | |
30 | 32 | | |
31 | 33 | | |
| |||
218 | 220 | | |
219 | 221 | | |
220 | 222 | | |
221 | | - | |
222 | | - | |
223 | | - | |
224 | | - | |
225 | | - | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
231 | 236 | | |
232 | 237 | | |
233 | 238 | | |
| |||
315 | 320 | | |
316 | 321 | | |
317 | 322 | | |
318 | | - | |
| 323 | + | |
319 | 324 | | |
320 | 325 | | |
321 | 326 | | |
| |||
0 commit comments