Repository navigation
Commit df4c06e
fix(plugin-detail): the activity feed names the record as the reader reads it when the object is named by a formula (#30438)
<!-- claude-projects-attribution: {"github_login":"os-sales"} -->
_Requested by **Sales** · [project
thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4UuMF4rV72CDoWfEYjfxmXjCu)_
domain:ui#6 · os-sales · session_01L6bhgVKbmZ6tBvw9qv8rir
Fixes #29962
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:记录页的动态(活动面板、动态
tab、动态小面板)里,活动摘要引号中的记录名,现在按读者的语言显示,与记录页标题一致。只对「名称字段是公式」的对象生效(例如
`label(record.status) + ' · ' + record.name`)。
- **为什么改**:服务端在写入时把记录名按写入者语言存进 `sys_activity.record_label` 和
`summary`;读取时虽按读者语言重组整句,但记录名仍是写入者那份。中文用户创建的记录,英文读者看到 `Created Project
"计划中 · Atlas Rollout"`,而标题是 `Active · Atlas Rollout`。
-
**风险与回滚**:纯前端读时替换,不动数据、不动服务端、不动元数据。名称字段是普通文本的对象完全不变(改名不改写旧记录)。代价:公式名对象的旧动态显示的是记录「现在」的名字(例如创建时是「计划中」,现在显示「Active」),与标题同源。回滚即
revert 本 PR。
- **先看**:`ui/packages/plugin-detail/src/renderers/recordActivityFeed.ts`
的 `readerRecordNameOf` /
`withReaderRecordName`(规则本身);`RecordActivityTimeline.tsx` 顶部那段
`useMemo`(唯一接入点);新测试文件。
- **两分钟验证**:`pnpm --dir ui exec vitest run
packages/plugin-detail/src/__tests__/RecordActivityTimeline.readerRecordName-29962.test.tsx`,预期
14 条全绿;或看下方前后截图。
- **需要你做的**:无,席位落地。
## What changes
The record page's activity feed names the page record as the reader
reads it, for an object whose name field is a formula. **This is the
read-time ui half; no server read is changed** (triage 6612785923 asked
the PR to say which side resolves the name).
Measured first, how a row's text is composed: plugin-audit stores
`summary` and `record_label` at write time; on read,
`installActivitySummaryLocale` re-composes `summary` in the reader's
language from the code stored in `metadata` (`activityCreated` /
`activityUpdated` / `activityUpdatedFields` / `activityDeleted`), but
the code's `label` parameter is the stored writer-language text, and the
code is stripped from what a non-system reader is served. So the ui
receives a reader-language sentence that quotes the writer's name, plus
`record_label` (the same text) and `record_id`.
- `activityRowToFeedItem` (`renderers/recordActivityFeed.ts`) carries
the row's `record_id` and `record_label` onto the item as a
package-local hand-off (`ActivityRecordFacts`, the same pattern as
`recordTimelineStream.ts`'s `AuditFeedFacts`), so both readers of
`sys_activity` (the record page's own feed read and the
`record:activity` block's self-fetch) carry it. No `@object-ui/types`
member is added.
- `readerRecordNameOf(objectSchema, record, recordId)`: the value of the
object's name field (`resolveNameField`, the ADR-0079 ladder
plugin-audit titles the row by) on the record the page read, which is
the H1's name, answered only when that field is a `formula`.
- `withReaderRecordName(items, reader)`: for each item of the page
record whose stored name the summary quotes (`"…"`, or `「…」` for ja-JP),
replaces the first quoted occurrence with the reader's name. Returns the
input array when nothing changes.
- `RecordActivityTimeline` applies it once, at the top, from the
`RecordContextProvider` it already reads for field labels, so the panel,
the stream (动态 tab) and the peek (动态 panel) all draw the reader's name.
## Why
hotclm names four child objects with a formula `display_name` over
`label(record.FIELD)` (#26608), so toasts, related lists and the H1
follow the reader's locale; the activity panel did not.
## Tests
`ui/packages/plugin-detail/src/__tests__/RecordActivityTimeline.readerRecordName-29962.test.tsx`,
14 tests, real subjects `activityRowToFeedItem` +
`RecordActivityTimeline` under `RecordContextProvider`:
- en-US reader of a zh-CN writer's row reads the H1's name, in the
`panel`, `stream` and `peek` variants; a system update in zh-CN; a ja-JP
`「…」` summary.
- Kept as stored: an object named by a text field (a rename does not
rewrite older rows), a row of another record, no record context, a
record with an empty name.
- Pure half: `readerRecordNameOf` answers formula name fields only;
`readerRecordSummary` touches only the first quoted name (an unquoted
field-change value equal to the name is left); `withReaderRecordName`
returns the same array when nothing changes.
**Positive control on main** (src files at `fdd06415`, test file kept):
9 failed / 5 passed; the 5 DOM tests that assert the reader's name are
among the 9 (the other 4 are the pure tests, whose exports do not exist
on main).
**Ablation** (`scripts/ablation-replace.mjs`, anchor `readerRecordId !==
undefined && readerRecordName !== undefined` → `false` in
`RecordActivityTimeline.tsx`, anchor 1 → 0, restored to the HEAD blob,
`git diff HEAD` empty): 5 failed / 9 passed, exactly the five
reader-name DOM tests. The test file imports the timeline by relative
path and the ui vitest config aliases `@object-ui/*` to source, so no
`dist/` is involved.
## Acceptance notes
- **Current name, not name-at-the-time, for formula names.** The
replacement is the record's name now, as the H1 shows it (the issue's
"resolve the name at read time when the object's name field is a
formula"). A formula whose inputs changed since the row was written
shows the current composition: in the evidence below, the `created` row
reads `"Active · Atlas Rollout"` although the project was created
`planned`. A stored (non-formula) name field is not touched, so a
renamed record's older rows keep their old name, as before.
- **Scope is the record page's feed.** Other surfaces that draw
`sys_activity.summary` (a user's home/My Work feed in `app-shell`, Setup
dashboards) still show the stored name; they have no page record to name
it by. A fully per-reader name everywhere is the server half (store the
record reference and render the label on read), `domain:server`'s,
outside this card.
- A fired milestone's author template is not quoted by the platform
templates; if it quotes the stored name the same way, it is replaced
too; otherwise left.
- Branch name is the harness-assigned `claude/project-thread-d97x01`,
not `claude/issue-29962-…` (Duplicate Fix Guard). The two
`chore(evidence)` commits add and then remove the screenshots below; the
squash merge carries neither.
## Verification
Head `8f4210c8` (the fix is `736d4ace`; the two later commits add and
remove evidence only, net diff identical).
Screenshots, real stack (`examples/app-showcase` with a formula name
patched in, `os dev --seed-admin`, the Console dev server proxied to it;
zh-CN writer through REST, en-US browser reader; how it was rendered:
`evidence/29962/README.md` at the evidence commit):
| before (main behaviour, timeline wiring ablated) | after (this branch)
|
| --- | --- |
|

|

|
Served on that stack to an en-US reader: `summary` `Created Project "计划中
· Atlas Rollout"` with `record_label` `计划中 · Atlas Rollout`, and the
record's `display_name` `Active · Atlas Rollout`.
<details><summary>Local runs</summary>
- `pnpm --dir ui exec vitest run
packages/plugin-detail/src/__tests__/RecordActivityTimeline.readerRecordName-29962.test.tsx`:
Test Files 1 passed, Tests 14 passed.
- `pnpm --dir ui exec vitest run packages/plugin-detail/ --maxWorkers=2`
(under the verify lock): Test Files 371 passed, 1 skipped; Tests 3311
passed, 18 skipped. VERDICT command-exit 0.
- `pnpm --filter @object-ui/plugin-detail run type-check` (`tsc --noEmit
&& tsc -p tsconfig.test.json`): VERDICT command-exit 0.
- `node scripts/pm/dispatch-gates.mjs --commands`: 35 derived families,
every one run, each exit 0 (including `pnpm --dir ui exec vitest run
scripts/`: 170 files passed, 2 skipped). `--ran` reconciliation: 35
derived, 35 run, 0 NOT-MEASURED, 0 UNRUN.
- Type-check CI lanes (`Type Check UI` and the workspace lanes) are
CI's; not run locally beyond the package type-check above.
</details>
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(not touched)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` is CI's.
- [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: 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 维护者速读 section is
the maintainer's Chinese summary).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01L6bhgVKbmZ6tBvw9qv8rir
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L6bhgVKbmZ6tBvw9qv8rir)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 3abe011 commit df4c06e
4 files changed
Lines changed: 357 additions & 6 deletions
File tree
- .changeset
- ui/packages/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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | | - | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
45 | 50 | | |
46 | 51 | | |
47 | 52 | | |
| |||
318 | 323 | | |
319 | 324 | | |
320 | 325 | | |
321 | | - | |
| 326 | + | |
322 | 327 | | |
323 | 328 | | |
324 | 329 | | |
| |||
368 | 373 | | |
369 | 374 | | |
370 | 375 | | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
371 | 398 | | |
372 | 399 | | |
373 | 400 | | |
| |||
503 | 530 | | |
504 | 531 | | |
505 | 532 | | |
506 | | - | |
507 | 533 | | |
508 | 534 | | |
509 | 535 | | |
| |||
| 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 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
0 commit comments