This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
Commit 29c19cc
fix(app-shell): a record page reads its timeline, comments, user list and foot attachments when shown (objectui#13010 part 2) (#13021)
Part of #13010
Clause-②: no
Part 2 of the card: Wanted item 4. Items 1 and 2 landed as part 1
(`46dbf32`). Items 3 and 5 are not in this PR, so the card stays open.
## What changes
`RecordDetailView` used to send four reads beside the record read on
every open: `sys_activity` (`top=200`, expand `actor_id`), the record's
`sys_comment` thread, `sys_user` (`top=50`, the comment mention list),
and, for an `enable.files` object on a page that places no
`record:attachments` node, the host's foot-of-page Attachments panel's
`sys_attachment` (`top=100`). On HotCRM's opportunity page none of the
four is drawn at open. The timeline is a `record:activity` block in the
Activity tab, there is no discussion block, and the Attachments panel is
the host's fallback below the Details tab.
### P1: each read, its caller, and what the first paint draws from it
| Read | Caller | What draws it | On first paint? |
|---|---|---|---|
| `sys_activity` `top=200` | `RecordDetailView` feed effect |
DiscussionContext rows, read by `record:discussion` / `record:chatter` /
`record:activity` | Only when one of those blocks is mounted at open |
| `sys_comment` | the same effect | the same | the same |
| `sys_user` `top=50` | `RecordDetailView` mention effect | the
composer's mention suggestions in those same blocks; also read when a
comment is posted, which needs a composer on screen | the same |
| `sys_attachment` `top=100` | `RecordAttachmentsPanel` refresh | that
panel | Inside a tab: only when its tab is active (Radix unmounts
inactive tab content, so this was already the case). The host's
foot-of-page fallback: mounted on every open, but below the record's
content |
Nothing in the header draws any of them. The header reads the record's
own expanded fields. The `page:tabs` badge probes, including the
Attachments tab's `sys_attachment` count probe, are separate reads in
`containers.tsx`, untouched by this PR.
### The change, per read (the smaller correct change for each)
- **`sys_activity` + `sys_comment` + `sys_user`: read when their block
is shown.** This is "on show", not "after first paint".
`useAfterFirstPaint` (objectui#12980 part 3) can be reached from the
record page, but it marks the console's boot paint. On an in-app open
(list to record), the measured case, it has already fired, so it would
defer nothing. The view now judges whether a feed block is on screen
from the tree it renders (with `enable.feeds: false` stripping the
discussion nodes, as it already did for rendering) and from `?tab=`. A
`page:tabs` strip mounts only its active item. The active item is chosen
the way `PageTabsRenderer` chooses it: `?tab=` when it names an item,
else the first item. Every case the view cannot read keeps the old eager
read: a strip the URL does not drive (a strip nested in a tab item), a
strip with a `visibleWhen` item, a strip with its own `defaultTab` and
no `?tab=`, and blocks outside any strip (the synthesized page's
discussion footer). Once a block has been on screen, the reads stay
wanted for the view's life. A drawer swaps records without remounting,
and the strip keeps its own selection while `?tab=` may not follow it.
Until the reads go out, the feed reports the loading state it already
had (`feedLoading`), which is what a block shows when it mounts.
- **The foot-of-page Attachments panel: read once it scrolls into
view.** It is always mounted but drawn below the record's content. So it
gets an `IntersectionObserver` (`rootMargin: 200px`), the same gate the
reference rail's reads use. Until then the panel is handed no data
source. It then issues no read and stays in its own `loading` state,
never the empty state. With no observer (SSR, a test environment), it
reads at once as before.
- `RecordAttachmentsPanel.tsx`, `record-activity.tsx` and
`record-history.tsx` are unchanged. The first already reads on mount
only. The other two own none of the four reads: their self-fetch runs
only without a host DiscussionContext, or only in their own tab.
No export, prop or type member is added. No cache layer.
### Wave table: harness
`RecordDetailView.recordOpenWaves-13010.test.tsx`, HotCRM-shaped page
(Details, Related, Activity with `record:activity`) over an
`enable.files` object
Before (base `4016370af3`): 14 requests, all in wave 1:
```
w1 GET approvals/requests
w1 POST security/explain (update)
w1 POST security/explain (delete)
w1 GET data/os_13010_deal/rec-13010
w1 GET data/sys_user top=50
w1 GET data/sys_comment
w1 GET data/sys_activity top=200
w1 GET data/sys_attachment top=100
w1 GET data/os_13010_{quote,line,task} top=1 (x3, badge probes)
w1 GET data/os_13010_{quote,line,task} top=3 (x3, rail cards)
```
After (`9bb86845d2`): 10 requests, all in wave 1, and none of the four.
Opening the Activity tab then reads `sys_activity`, `sys_comment` and
`sys_user` once each. Scrolling the foot panel into view reads
`sys_attachment` once. On part 1's page, which has no feed block and no
`enable.files`, the open goes from 13 requests to 10.
## Pins (in the part-1 harness)
- (a) A record whose default tab draws none of them issues none of the
four reads at open. The foot panel is mounted and does not show rows.
- (b) Opening the Activity tab issues `sys_activity` (`top=200`),
`sys_comment` and `sys_user top=50` once each, after the open's
requests, and draws the activity and comment rows. Scrolling the foot
panel in issues `sys_attachment top=100` once and draws its row.
- (c) CONTROLS. `?tab=activity` reads all three in wave 1 and draws the
same rows. `?tab=attachments` reads the list in wave 1. The Attachments
tab's `top=1` badge probe goes out in wave 1 whether that tab is active
or not. The synthesized page (discussion footer) still reads the feed
and the user list in wave 1. Part 1's three harness tests are unchanged
and green.
- `RecordDetailView.recordOpenRequests-12701.test.tsx` pinned "the
activity read unchanged: 1" on a page with no feed block. That page now
reads none, so the pin says 0 and points to the harness for the
read-once half.
### Ablations: one per moved read, each through `ablation-replace.mjs`
(anchor hit counted, blob changed, restore proven by blob hash equal to
HEAD and an empty `git diff HEAD`). Pin (a) went red on all three
- Feed gate removed (`if (!feedWanted) return;` deleted): (a) red with
`w1 GET data/sys_comment` and `w1 GET data/sys_activity top=200`. The
`sys_activity` and `sys_comment` reads share one effect, so one gate
covers both. Blob `ae4c165df435` to `2ba42a0b1e2a`, then restored to
`ae4c165df435`.
- Mention gate removed: (a) red with `w1 GET data/sys_user top=50`. Blob
to `05c7bf455fe1`, then restored.
- Foot panel handed its data source eagerly: (a) red with `w1 GET
data/sys_attachment top=100`. Blob to `df8241ecdebc`, then restored.
The "before" table above was measured by putting the base blob
`8e061749eb57` in place under an EXIT/INT/TERM trap. It was restored by
`git checkout HEAD --` and proven by hash: `ae4c165df435`, the HEAD
blob, with an empty diff.
## Gates (all on `9bb86845d2` unless named)
- Closure build `pnpm --workspace-concurrency=2 --filter
'@object-ui/app-shell^...' build`: exit 0.
- `pnpm --filter @object-ui/app-shell type-check` (`tsc --noEmit && tsc
-p tsconfig.test.json`; `--listFilesOnly` shows the test project reads
the harness): exit 0. It ran on `453eb0720b`. The later commit touched
one test assertion only.
- vitest, `--maxWorkers=1`, one package at a time, under the shared
lock:
- The harness plus the 12701 file: 12/12.
- Family files naming `RecordDetailView`, `RecordAttachmentsPanel`,
`record-activity`, `record-history`, `recordOpenWaves-13010`,
`authoredActivityThreading`, `comment`, `mention`: app-shell 70 files /
460 tests (1 failure, the 12701 pin above, since updated and green);
plugin-detail 10 files / 135 tests; collaboration 4 files / 56 tests.
- A further 126 app-shell / console test files that name `sys_comment`,
`sys_activity`, `sys_attachment`, `mentionSuggestions` or
`RecordDetailView`: 1120/1120.
- **Declared to CI:** the full `packages/app-shell/` directory, too
large to run locally inside the time cap. Also `packages/plugin-detail/`
and `packages/collaboration/`, of which only the family files above ran.
- `pnpm lint`, narrowed to the 3 changed source and test files: exit 0,
0 errors. `RecordDetailView.tsx` carries 102 warnings, against 104 on
the base blob. Both test files have 0 warnings. Population: the root
`eslint.config.js`, which every package's `eslint .` reads. File count:
3, from `--format json`. Invariance: the config enables no type-aware
linting (no `parserOptions.project`), so this diff cannot move a verdict
on any untouched file.
- Pre-tsc battery, each exit 0: `check:phantom-deps`,
`check:self-import`, `check:unreferenced-sources`,
`check:doc-example-readers`, `check:handler-key-reads`,
`check:side-effects-array`, `check:element-data-source-declaration`,
`check:spec-symbols`, `check:action-forward-parity`,
`check:designer-field-key-parity`, `check:icon-record-names`,
`check:i18n-keys`, `check:i18n-drift`, `check:i18n-designer-parity`,
`check:control-bytes`, `scripts/check-hand-rolled-comment-mask.mjs`.
- `scripts/check-changeset-fixed.mjs`: exit 0.
`scripts/check-changeset-presence.mjs`: exit 0 (1 changeset,
`@object-ui/app-shell` patch). `check:new-line-citations`: 0 new.
## Acceptance notes
- `sys_audit_log` (`top=50`, plus a `sys_user` `$in` name lookup) is
still read at open when the object tracks history, before the History
tab is opened. It is the same family as item 4 but not one of the four
reads this part names. It was not in the measured HotCRM wave. Noted,
not filed. Carrier: none.
- "Shown" means mounted. A feed block inside a collapsed
`page:accordion` panel, or on a strip this view cannot read, keeps the
eager read. That is the conservative side: such a block can never sit in
a loading state the view never ends.
- Not browser-verified against a running stack. The harness drives the
real page over the real adapter with a held transport.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 4016370 commit 29c19cc
4 files changed
Lines changed: 406 additions & 17 deletions
File tree
- .changeset
- packages/app-shell/src/views
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
269 | 269 | | |
270 | 270 | | |
271 | 271 | | |
272 | | - | |
| 272 | + | |
273 | 273 | | |
274 | 274 | | |
275 | 275 | | |
| |||
282 | 282 | | |
283 | 283 | | |
284 | 284 | | |
285 | | - | |
286 | | - | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
287 | 290 | | |
288 | 291 | | |
289 | 292 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
| 54 | + | |
53 | 55 | | |
54 | 56 | | |
55 | 57 | | |
| |||
82 | 84 | | |
83 | 85 | | |
84 | 86 | | |
85 | | - | |
86 | 87 | | |
87 | 88 | | |
88 | 89 | | |
| |||
169 | 170 | | |
170 | 171 | | |
171 | 172 | | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
172 | 187 | | |
173 | 188 | | |
174 | 189 | | |
| |||
189 | 204 | | |
190 | 205 | | |
191 | 206 | | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
192 | 211 | | |
193 | 212 | | |
194 | 213 | | |
| |||
268 | 287 | | |
269 | 288 | | |
270 | 289 | | |
271 | | - | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
272 | 302 | | |
273 | 303 | | |
274 | | - | |
| 304 | + | |
275 | 305 | | |
276 | 306 | | |
| 307 | + | |
277 | 308 | | |
278 | | - | |
| 309 | + | |
279 | 310 | | |
280 | | - | |
281 | | - | |
| 311 | + | |
| 312 | + | |
282 | 313 | | |
283 | 314 | | |
284 | 315 | | |
| |||
287 | 318 | | |
288 | 319 | | |
289 | 320 | | |
290 | | - | |
| 321 | + | |
291 | 322 | | |
292 | 323 | | |
293 | 324 | | |
| |||
301 | 332 | | |
302 | 333 | | |
303 | 334 | | |
304 | | - | |
| 335 | + | |
305 | 336 | | |
306 | 337 | | |
307 | 338 | | |
| |||
358 | 389 | | |
359 | 390 | | |
360 | 391 | | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
0 commit comments