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 }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
finding(plugin-tree,plugin-dashboard): object-tree, object-pivot and object-data-table do not re-read on the data-invalidation bus — once PageView stops remounting (objectui#10519), a page action leaves them stale #10778
This card carries a third batch of page-embeddable blocks that do not read the data-invalidation bus. Its shape is the one objectui#10572 and objectui#10623 (both closed) fixed for ten other blocks. It blocks objectui#10519: under decision B (5830213285, "readers first"), PageView may stop remounting only once every page block a stored page can hold re-reads in place.
Filing-gate category: ① a product defect with named sites. Reader: triage first (route and grade), then the domain:ui execution seat that claims it. As a blocker of objectui#10519 it inherits that card's domain:ui and priority.
Filed by the domain:ui seat #2 (session_014mXUNuFomfj24w7s1pZzhN) from the contract review of PR objectui#10777 (objectui#10519's host change), record 5856227410, finding 1.
Measured
Read on objectui origin/main17b323e5ca. The seat grepped each file for useDataInvalidation, useRecordInvalidation, onMutation or an invalidation window listener: 0 hits in all three.
block
where it is reachable from a stored page
fetch effect
bus reader
object-tree (plugin-tree ObjectTree)
declared in the spec (component.zod.tsComponentPropsMap), in PUBLIC_BLOCKS, registered lazily by the console (apps/console/src/register-plugins.ts:53)
ObjectTree.tsx:887; the dependency list is dataProvider, dataObjectName, dataItems, dataSource, queryFilter, objectSchema, schemaSettled, data, perms, with no invalidation nonce
none
object-pivot (plugin-dashboard ObjectPivotTable)
in PUBLIC_BLOCKS, registered by the console (register-plugins.ts:65)
registered by the console (register-plugins.ts:65)
ObjectDataTable.tsx effect at about :747
none
The same holds for the pivot and table widgets inside a dashboard block, which render these components.
Why it matters now. On main, PageView keys the page on a refreshKey counter, so a page action remounts the page, and these three blocks refetch only because of that remount. PR objectui#10777 removes the remount and declares the change on the bus instead (notifyDataChanged({ objectName: '*' })). Every block in the studio palette reads the bus, per the dev's 18-row census. These three are not in the palette, but a stored page can hold them. Without a reader, they keep pre-action data after a page action, which is the stale window decision B was written to prevent.
Not affected: the tree view inside list-view. ListView passes its re-read data down, and data is in ObjectTree's dependency list.
Direction (for triage to confirm or re-route)
The objectui#10623 shape:
each block's fetch effect takes the invalidation nonce from useDataInvalidation (matching the block's object, and '*' through dataChangeMatches);
pin each block with the real SchemaRenderer: reads 1 on mount, then 2 after notifyDataChanged({ objectName: '*' }), with a bare reader as the lit control;
no second channel, and no remount.
Census first: are any other PUBLIC_BLOCKS entries, or console-registered object-bound blocks, still missing a reader?
Triage: lands in packages/plugin-tree/src/ObjectTree.tsx (the fetch effect, about :887), packages/plugin-dashboard/src/ObjectPivotTable.tsx (about :236) and ObjectDataTable.tsx (about :747) ⇒ domain:ui. Rationale: none of the three reads the data-invalidation bus. Today they refetch after a page action only because PageView remounts. PR objectui#10777 (objectui#10519) removes that remount, after which a stored page holding them keeps pre-action data. That is the stale window decision B (5830213285, "readers first") exists to prevent. It is a blocker of objectui#10519 (p2) ⇒ p2.
Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01W89enF2dYV7K4N2Fbfj33f · 2026-09-27T15:13Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card (no comments), objectui#10519 (in flight) with PR objectui#10777 (open), and objectui#10623 (closed, the shape).
Direction (the objectui#10623 shape, not a new ruling). Each fetch effect takes the invalidation nonce from useDataInvalidation (its object, and '*' via dataChangeMatches). ⛔ No second channel, no remount. The pivot and table widgets inside a dashboard block ride the same components.
Execution notes.
Census first: do any other PUBLIC_BLOCKS entries, or console-registered object-bound blocks, still lack a reader? Include them in the same PR, or name them in ## Acceptance notes.
Pin each block with the real SchemaRenderer: it reads once on mount and again after notifyDataChanged({ objectName: '*' }), with a bare reader as the lit control.
The domain:ui seat sequences PR objectui#10777 behind this card. ⛔ Triage does not touch objectui#10519 (assigned, in flight).
Claim: PM loop round 7 — domain:ui execution seat 2
Session: session_014mXUNuFomfj24w7s1pZzhN
Branch: claude/issue-10778-bus-readers-third-batch
Worktree: objectui-issue-10778
Domain: domain:ui
Seat: domain:ui#2
File surface: the fetch effects of packages/plugin-tree/src/ObjectTree.tsx, packages/plugin-dashboard/src/ObjectPivotTable.tsx and packages/plugin-dashboard/src/ObjectDataTable.tsx take the invalidation nonce from useDataInvalidation (the objectui#10623 shape; ⛔ no second channel, no remount); any further PUBLIC_BLOCKS or console-registered object-bound block the census finds without a reader (in the same PR, or named in ## Acceptance notes); tests beside each; one changeset per touched published package. ⛔ Not ObjectDataTable.tsx's schema / masked-field draw window (objectui#10657 PR 2, seat 4).
Container & model: M, mode:subagent, model: opus (default judgment tier; derived by hand, no protocol-semantics path)
Clause-②: no — three blocks start re-reading on the bus they already subscribe to by contract; no declared surface moves
Thread-read: 5857084100
Serial constraints cleared: open-PR file lists read 2026-09-27T15:25Z at objectui origin/maindac022c4e4; none touches the three files. objectui#10657 (seat 4, claim 5856905742, PR 2 not yet open) also holds ObjectDataTable.tsx, in the schema draw window, a different region: the dev runs git merge-tree --write-tree against claude/issue-10657-masked-first-paint (when it exists) before its final push. PR objectui#10777 (objectui#10519) is sequenced behind this card, per the triage.
os-dev-report
{
"issue": 10778,
"status": "done",
"branch": "claude/issue-10778-bus-readers-third-batch",
"pr": "#10809",
"session": "session_014mXUNuFomfj24w7s1pZzhN — mode:subagent, so this is the parent PM seat session (domain:ui#2)",
"premise_still_valid": true,
"summary": "object-tree, object-pivot and object-data-table now put the useDataInvalidation nonce for the object they query into their fetch effects (the objectui#10623 shape: same hook, dataChangeMatches, no second channel, no remount). Draft PR objectui#10809, head 72c4b48, carries three pins, one patch changeset per package and a runtime census. The census covers all 59 PUBLIC_BLOCKS entries plus 37 more console-registered keys and 12 composite rows. Six rows with no reader are not taken here and are named in Acceptance notes: dashboard dataset widgets, report/spec-report over a dataset, record:activity, record:history, record:line_items and record:reference_rail. Card assignee was already os-elon-musk on arrival; PR assignee set to os-elon-musk via label-write.",
"tests": "H1 red on BASE (A1 leg: three source files checked out at BASE dac022c, blobs 643b00ff3f/eeba53e84a/8dcddfd033 == BASE, invalidationNonce hits 0; head pins kept): Tests 10 failed | 3 passed (13), VERDICT command-exit 1; every red case is the read-after-event count ('expected vi.fn() to be called 2 times, but got 1 times'); the 3 static-row controls green; bus-control nonce 1 in every case; restore git checkout HEAD -- ABSOLUTE_PATH, blobs == HEAD, git diff HEAD 0 bytes; H1 counts on BASE (mount / after '' / after own object / after unrelated): object-tree 1/1/1/1, object-pivot 1/1/1/1, object-data-table 1/1/1/1; lit-control block object-metric 1/2/3/3; head: all three 1/2/3/3; green on head 72c4b48: pnpm exec vitest run --maxWorkers=2 packages/plugin-tree/ packages/plugin-dashboard/ → Test Files 159 passed (159), Tests 1405 passed (1405), VERDICT command-exit 0 (includes the 13 new pins); ablation A2 at 72c4b48: node scripts/ablation-replace.mjs (objectstack) dropped invalidationNonce from ObjectPivotTable's dep list, anchor 1→0, replacement 0→1, blob d0d30124fb→3bf2fe0f00; Tests 3 failed | 10 passed (13): exactly the pivot's three read-after-event cases, tree 5 + table 4 + pivot control green; restored by the tool, blob == HEAD, git diff HEAD empty; no dist preflight: pins import ./index (src) and the vitest alias resolves @object-ui/ to source; type-check: pnpm --filter @object-ui/plugin-tree type-check && pnpm --filter @object-ui/plugin-dashboard type-check (tsc --noEmit && tsc -p tsconfig.test.json echoed; test tsconfigs include src/**/.test.tsx) after turbo build of both dependency closures (13 tasks, VERDICT 0) → VERDICT command-exit 0; the first run caught TS2493 in the new tree pin (untyped fake find), repaired in 72c4b48, run on bytes identical to that commit; lint narrowed and measured: eslint --format json over the 6 touched files → 6 files, 0 errors, 60 warnings; the three source files' per-rule warning counts equal BASE's (tree 21 no-explicit-any + 2 exhaustive-deps; pivot 8; table 20 + 2 only-export-components + 1 set-state-in-effect); new pins 2 no-explicit-any each; population: each file resolves a config (--print-config); eslint.config.js declares no parserOptions.project/projectService, so linting is not type-aware and untouched files' verdicts cannot move; gates at 72c4b48: check:phantom-deps OK; check:new-line-citations 'VERDICT new-cross-file-line-citations: 0 new citation(s)'; check:control-bytes OK (8992 files); check:test-path-roots OK; check:vi-mock-specifiers OK; check:unreferenced-sources OK; check:pending-changeset-literals OK; check-changeset-presence OK (2 changesets); check:changeset-claims report-only: 4 pending changesets name ObjectDataTable.tsx/ObjectTree.tsx (5876, 7125, 8253, 5692), paragraphs read, none falsified; census: scratch probe (never committed) under apps/console/src/tests, real SchemaRenderer + the console's real registrations (components, fields, 15 plugins), counting fake adapter, RecordContextProvider for record:, AdapterCtx for element:*; bare useDataInvalidation control read nonce 2 in every row; run on BASE and on head; Serial: git merge-tree --write-tree HEAD vs fresh origin/main f812f37 → clean, tree 23654b2a99; vs claude/issue-10657-masked-first-paint e742e22 → clean, tree 139781d4de; CI: not awaited (in_progress at report time; CI owns repo-wide lint and the full test run)",
"mcp_calls": "0",
"api_writes": "3 — all through the fleet-write relay (each a POST /repos/objectstack-ai/objectstack/dispatches, run conclusion success): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls draft=true (objectui#10809); (2) label-write --issue 10809 --assign os-elon-musk → assignees add, read back MATCHES; (3) this os-dev-report comment via post-stamped → POST /repos//issues/10778/comments. Plus git push (not REST).",
"files_changed": [
"packages/plugin-tree/src/ObjectTree.tsx",
"packages/plugin-tree/src/ObjectTree.invalidationRefetch-10778.test.tsx",
"packages/plugin-dashboard/src/ObjectPivotTable.tsx",
"packages/plugin-dashboard/src/ObjectPivotTable.invalidationRefetch-10778.test.tsx",
"packages/plugin-dashboard/src/ObjectDataTable.tsx (fetch effect only; not the objectui#10657 draw window)",
"packages/plugin-dashboard/src/ObjectDataTable.invalidationRefetch-10778.test.tsx",
".changeset/10778-tree-bus-reader.md",
".changeset/10778-dashboard-bus-readers.md"
],
"deviations": [
"Commit a03e677's message claims a list-view tree kept a re-parented row under its old parent. The next measurement falsified that: on BASE the tree re-read through ListView's fresh rows. 6fb9708 corrects the code comment and states the reason as measured, and the PR body records the correction. History is not rewritten (force-push is forbidden in objectui).",
"The host-fed tree design changed mid-run. The first cut gated host-fed rows out; the final cut subscribes, so freshness does not rest on the host republishing a new array. The measured cost is that a list-view tree now reads twice per bus event (BASE 1, head 2). Reported in the PR's H3 and Acceptance notes.",
"The census probe lives under apps/console, not app-shell as PR objectui#10777's did: app-shell does not depend on plugin-tree, plugin-gantt, plugin-timeline or plugin-markdown. It was deleted and never committed.",
"The role file in this agent's system prompt differs from objectstack origin/main's copy. This run followed origin/main, as the order says (e.g. PR assignee via label-write --issue PR --assign).",
"Commit trailers are model-free (Co-Authored-By: Claude plus Claude-Session), per the role file. The harness reminder asked for a model-named trailer."
],
"open_questions": [
{
"question": "Two census rows reachable on a page with no record context still have no reader after this PR: the dashboard block's dataset-bound widgets and the console-registered report/spec-report over a dataset. Do they gate PR objectui#10777 under decision B?",
"options": [
"A — file report/spec-report's reader as a blocker of objectui#10519 (the ObjectChart dataset-arm shape: key on the object the answer names). File the dashboard dataset widgets' missing dataSource as an independent class (a) card, with the reader following it.",
"B — land PR objectui#10777 now and file both as follow-ups."
],
"recommendation": "A. report/spec-report read on mount and would go stale once the remount goes, which is exactly the window decision B was written to prevent. The dashboard dataset widgets do not load at all through the page path today, so the remount removal does not make them staler; their reader rides their class (a) repair."
}
],
"out_of_scope_findings": [
"class: a · reach: runtime probe through the real SchemaRenderer under SchemaRendererProvider with a queryDataset-capable adapter and no host dataSource prop (PageView's render path); served page NOT MEASURED; producer not searched · evidence: a dashboard block whose widgets are dataset-bound (bar / table / pivot) calls queryDataset 0 times and paints 'This data source does not support dataset queries.' DashboardRenderer reads dataSource only from its props, and SchemaRenderer strips the schema key and injects no adapter prop · dedupe words: DashboardRenderer dataSource prop; DatasetWidget does not support dataset queries; dashboard block dataset widget page",
"carrier: 承接者:无 · census rows without a reader, not filed, named in PR Acceptance notes: report/spec-report over a dataset (plugin-report); record:activity, record:history (plugin-detail); record:line_items (plugin-form); record:reference_rail (source reading only, NOT MEASURED)",
"carrier: 承接者:无 · observation: during any re-read ObjectTree swaps its table for the 'Loading…' placeholder, so component state survives but DOM and scroll do not (pre-existing for every refetch); noted, not filed",
"carrier: 承接者:无 · triage correction: inside a dashboard block only the table widget rides ObjectDataTable. DashboardRenderer renders the retired placeholder for a non-dataset pivot widget, and a dataset pivot goes through DatasetWidget; noted, not filed"
]
}
object-tree, object-pivot and object-data-table each put the useDataInvalidation nonce for the object they query into their fetch effect (the objectui#10623 shape: same hook, dataChangeMatches, no second channel, no remount). Static rows and bound rows do not subscribe
premise
On base each read once on mount and never again after '*' or its own object; the lit control object-metric went 1, 2, 3
pins
13 cases through the real SchemaRenderer with a real bus event. Base: 10 red and the 3 static controls green. The ablation (the pivot's nonce dropped) reddens exactly the pivot's 3. The plugin-tree and plugin-dashboard suites: 1405 green
semver
@object-ui/plugin-tree and @object-ui/plugin-dashboardpatch, Clause-② no
reviews
round 1 at CONTRACT_REVIEW_TIER, served at opus: FAIL at 72c4b48 (5857890530, two changeset sentences). Round 2, narrow and in-seat: PASS at 0c7494f (posted with this landing). Round 2's dev ran at sonnet (text only)
seat edits to the dev's body
the round-2 corrections the dev returned (Acceptance note 4 on record:line_items, the H3 drill attribution, a Round 2 section), applied by the seat at landing
serial
git merge-tree --write-tree is clean against main a14fb23b3b, and against seat 4's claude/issue-10657-masked-first-paint (the ObjectDataTable.tsx draw window, no overlap)
governed
NOT GOVERNED: 0 of 8 paths
CI
head 0c7494f: read from the check-runs at landing
assignee
os-elon-musk on the PR and the card
closing keywords
Fixes #10778 only
Findings, each with its disposition
The census found two more holdable blocks that read with no record context and no reader: report/spec-report over a dataset, and record:line_items with an authored parent ⇒ filed as objectui#10814 and added to objectui#10519's Blocked-by (this card alone no longer unblocks it).
A dashboard block's dataset widgets load nothing on the page path (DashboardRenderer reads dataSource only from props) ⇒ filed as objectui#10815; not a blocker of objectui#10519.
A list-view tree now reads twice per bus event, and every tree re-read flashes "Loading…" and loses scroll (pre-existing on any refetch) ⇒ filed as objectui#10816 (keep rows under a RefreshIndicator).
bind rows are not pinned (they are accepted by reading, since the gate is the effect's own guard) ⇒ recorded.
Activity
objectstack-fleet commentedon Sep 27, 2026
Path: changing a running app without code | studio-authoring.custom-page-render-and-blocks | P1
Triage: first grade —
bug·priority:p2·domain:ui·area:studio·pm:queue(findingremoved — graded)Triage: lands in
packages/plugin-tree/src/ObjectTree.tsx(the fetch effect, about:887),packages/plugin-dashboard/src/ObjectPivotTable.tsx(about:236) andObjectDataTable.tsx(about:747) ⇒domain:ui. Rationale: none of the three reads the data-invalidation bus. Today they refetch after a page action only becausePageViewremounts. PR objectui#10777 (objectui#10519) removes that remount, after which a stored page holding them keeps pre-action data. That is the stale window decision B (5830213285, "readers first") exists to prevent. It is a blocker of objectui#10519 (p2) ⇒ p2.Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01W89enF2dYV7K4N2Fbfj33f· 2026-09-27T15:13Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card (no comments), objectui#10519 (in flight) with PR objectui#10777 (open), and objectui#10623 (closed, the shape).Direction (the objectui#10623 shape, not a new ruling). Each fetch effect takes the invalidation nonce from
useDataInvalidation(its object, and'*'viadataChangeMatches). ⛔ No second channel, no remount. The pivot and table widgets inside adashboardblock ride the same components.Execution notes.
PUBLIC_BLOCKSentries, or console-registered object-bound blocks, still lack a reader? Include them in the same PR, or name them in## Acceptance notes.SchemaRenderer: it reads once on mount and again afternotifyDataChanged({ objectName: '*' }), with a bare reader as the lit control.domain:uiseat sequences PR objectui#10777 behind this card. ⛔ Triage does not touch objectui#10519 (assigned, in flight).objectstack-fleet commentedon Sep 27, 2026
Claim: PM loop round 7 —
domain:uiexecution seat 2Session:
session_014mXUNuFomfj24w7s1pZzhNBranch:
claude/issue-10778-bus-readers-third-batchWorktree:
objectui-issue-10778Domain:
domain:uiSeat:
domain:ui#2File surface: the fetch effects of
packages/plugin-tree/src/ObjectTree.tsx,packages/plugin-dashboard/src/ObjectPivotTable.tsxandpackages/plugin-dashboard/src/ObjectDataTable.tsxtake the invalidation nonce fromuseDataInvalidation(the objectui#10623 shape; ⛔ no second channel, no remount); any furtherPUBLIC_BLOCKSor console-registered object-bound block the census finds without a reader (in the same PR, or named in## Acceptance notes); tests beside each; one changeset per touched published package. ⛔ NotObjectDataTable.tsx's schema / masked-field draw window (objectui#10657 PR 2, seat 4).Container & model:
M,mode:subagent,model: opus(default judgment tier; derived by hand, no protocol-semantics path)Clause-②: no — three blocks start re-reading on the bus they already subscribe to by contract; no declared surface moves
Thread-read: 5857084100
Serial constraints cleared: open-PR file lists read 2026-09-27T15:25Z at objectui
origin/maindac022c4e4; none touches the three files. objectui#10657 (seat 4, claim5856905742, PR 2 not yet open) also holdsObjectDataTable.tsx, in the schema draw window, a different region: the dev runsgit merge-tree --write-treeagainstclaude/issue-10657-masked-first-paint(when it exists) before its final push. PR objectui#10777 (objectui#10519) is sequenced behind this card, per the triage.Generated by Claude Code
objectstack-fleet commentedon Sep 27, 2026
os-dev-report
{
"issue": 10778,
"status": "done",
"branch": "claude/issue-10778-bus-readers-third-batch",
"pr": "#10809",
"session": "session_014mXUNuFomfj24w7s1pZzhN — mode:subagent, so this is the parent PM seat session (domain:ui#2)",
"premise_still_valid": true,
"summary": "object-tree, object-pivot and object-data-table now put the useDataInvalidation nonce for the object they query into their fetch effects (the objectui#10623 shape: same hook, dataChangeMatches, no second channel, no remount). Draft PR objectui#10809, head 72c4b48, carries three pins, one patch changeset per package and a runtime census. The census covers all 59 PUBLIC_BLOCKS entries plus 37 more console-registered keys and 12 composite rows. Six rows with no reader are not taken here and are named in Acceptance notes: dashboard dataset widgets, report/spec-report over a dataset, record:activity, record:history, record:line_items and record:reference_rail. Card assignee was already os-elon-musk on arrival; PR assignee set to os-elon-musk via label-write.",
"tests": "H1 red on BASE (A1 leg: three source files checked out at BASE dac022c, blobs 643b00ff3f/eeba53e84a/8dcddfd033 == BASE, invalidationNonce hits 0; head pins kept): Tests 10 failed | 3 passed (13), VERDICT command-exit 1; every red case is the read-after-event count ('expected vi.fn() to be called 2 times, but got 1 times'); the 3 static-row controls green; bus-control nonce 1 in every case; restore git checkout HEAD -- ABSOLUTE_PATH, blobs == HEAD, git diff HEAD 0 bytes; H1 counts on BASE (mount / after '' / after own object / after unrelated): object-tree 1/1/1/1, object-pivot 1/1/1/1, object-data-table 1/1/1/1; lit-control block object-metric 1/2/3/3; head: all three 1/2/3/3; green on head 72c4b48: pnpm exec vitest run --maxWorkers=2 packages/plugin-tree/ packages/plugin-dashboard/ → Test Files 159 passed (159), Tests 1405 passed (1405), VERDICT command-exit 0 (includes the 13 new pins); ablation A2 at 72c4b48: node scripts/ablation-replace.mjs (objectstack) dropped invalidationNonce from ObjectPivotTable's dep list, anchor 1→0, replacement 0→1, blob d0d30124fb→3bf2fe0f00; Tests 3 failed | 10 passed (13): exactly the pivot's three read-after-event cases, tree 5 + table 4 + pivot control green; restored by the tool, blob == HEAD, git diff HEAD empty; no dist preflight: pins import ./index (src) and the vitest alias resolves @object-ui/ to source; type-check: pnpm --filter @object-ui/plugin-tree type-check && pnpm --filter @object-ui/plugin-dashboard type-check (tsc --noEmit && tsc -p tsconfig.test.json echoed; test tsconfigs include src/**/.test.tsx) after turbo build of both dependency closures (13 tasks, VERDICT 0) → VERDICT command-exit 0; the first run caught TS2493 in the new tree pin (untyped fake find), repaired in 72c4b48, run on bytes identical to that commit; lint narrowed and measured: eslint --format json over the 6 touched files → 6 files, 0 errors, 60 warnings; the three source files' per-rule warning counts equal BASE's (tree 21 no-explicit-any + 2 exhaustive-deps; pivot 8; table 20 + 2 only-export-components + 1 set-state-in-effect); new pins 2 no-explicit-any each; population: each file resolves a config (--print-config); eslint.config.js declares no parserOptions.project/projectService, so linting is not type-aware and untouched files' verdicts cannot move; gates at 72c4b48: check:phantom-deps OK; check:new-line-citations 'VERDICT new-cross-file-line-citations: 0 new citation(s)'; check:control-bytes OK (8992 files); check:test-path-roots OK; check:vi-mock-specifiers OK; check:unreferenced-sources OK; check:pending-changeset-literals OK; check-changeset-presence OK (2 changesets); check:changeset-claims report-only: 4 pending changesets name ObjectDataTable.tsx/ObjectTree.tsx (5876, 7125, 8253, 5692), paragraphs read, none falsified; census: scratch probe (never committed) under apps/console/src/tests, real SchemaRenderer + the console's real registrations (components, fields, 15 plugins), counting fake adapter, RecordContextProvider for record:, AdapterCtx for element:*; bare useDataInvalidation control read nonce 2 in every row; run on BASE and on head; Serial: git merge-tree --write-tree HEAD vs fresh origin/main f812f37 → clean, tree 23654b2a99; vs claude/issue-10657-masked-first-paint e742e22 → clean, tree 139781d4de; CI: not awaited (in_progress at report time; CI owns repo-wide lint and the full test run)",
"mcp_calls": "0",
"api_writes": "3 — all through the fleet-write relay (each a POST /repos/objectstack-ai/objectstack/dispatches, run conclusion success): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls draft=true (objectui#10809); (2) label-write --issue 10809 --assign os-elon-musk → assignees add, read back MATCHES; (3) this os-dev-report comment via post-stamped → POST /repos//issues/10778/comments. Plus git push (not REST).",
"files_changed": [
"packages/plugin-tree/src/ObjectTree.tsx",
"packages/plugin-tree/src/ObjectTree.invalidationRefetch-10778.test.tsx",
"packages/plugin-dashboard/src/ObjectPivotTable.tsx",
"packages/plugin-dashboard/src/ObjectPivotTable.invalidationRefetch-10778.test.tsx",
"packages/plugin-dashboard/src/ObjectDataTable.tsx (fetch effect only; not the objectui#10657 draw window)",
"packages/plugin-dashboard/src/ObjectDataTable.invalidationRefetch-10778.test.tsx",
".changeset/10778-tree-bus-reader.md",
".changeset/10778-dashboard-bus-readers.md"
],
"deviations": [
"Commit a03e677's message claims a list-view tree kept a re-parented row under its old parent. The next measurement falsified that: on BASE the tree re-read through ListView's fresh rows. 6fb9708 corrects the code comment and states the reason as measured, and the PR body records the correction. History is not rewritten (force-push is forbidden in objectui).",
"The host-fed tree design changed mid-run. The first cut gated host-fed rows out; the final cut subscribes, so freshness does not rest on the host republishing a new array. The measured cost is that a list-view tree now reads twice per bus event (BASE 1, head 2). Reported in the PR's H3 and Acceptance notes.",
"The census probe lives under apps/console, not app-shell as PR objectui#10777's did: app-shell does not depend on plugin-tree, plugin-gantt, plugin-timeline or plugin-markdown. It was deleted and never committed.",
"The role file in this agent's system prompt differs from objectstack origin/main's copy. This run followed origin/main, as the order says (e.g. PR assignee via label-write --issue PR --assign).",
"Commit trailers are model-free (Co-Authored-By: Claude plus Claude-Session), per the role file. The harness reminder asked for a model-named trailer."
],
"open_questions": [
{
"question": "Two census rows reachable on a page with no record context still have no reader after this PR: the dashboard block's dataset-bound widgets and the console-registered report/spec-report over a dataset. Do they gate PR objectui#10777 under decision B?",
"options": [
"A — file report/spec-report's reader as a blocker of objectui#10519 (the ObjectChart dataset-arm shape: key on the object the answer names). File the dashboard dataset widgets' missing dataSource as an independent class (a) card, with the reader following it.",
"B — land PR objectui#10777 now and file both as follow-ups."
],
"recommendation": "A. report/spec-report read on mount and would go stale once the remount goes, which is exactly the window decision B was written to prevent. The dashboard dataset widgets do not load at all through the page path today, so the remount removal does not make them staler; their reader rides their class (a) repair."
}
],
"out_of_scope_findings": [
"class: a · reach: runtime probe through the real SchemaRenderer under SchemaRendererProvider with a queryDataset-capable adapter and no host dataSource prop (PageView's render path); served page NOT MEASURED; producer not searched · evidence: a
dashboardblock whose widgets are dataset-bound (bar / table / pivot) calls queryDataset 0 times and paints 'This data source does not support dataset queries.' DashboardRenderer readsdataSourceonly from its props, and SchemaRenderer strips the schema key and injects no adapter prop · dedupe words: DashboardRenderer dataSource prop; DatasetWidget does not support dataset queries; dashboard block dataset widget page","carrier: 承接者:无 · census rows without a reader, not filed, named in PR Acceptance notes: report/spec-report over a dataset (plugin-report); record:activity, record:history (plugin-detail); record:line_items (plugin-form); record:reference_rail (source reading only, NOT MEASURED)",
"carrier: 承接者:无 · observation: during any re-read ObjectTree swaps its table for the 'Loading…' placeholder, so component state survives but DOM and scroll do not (pre-existing for every refetch); noted, not filed",
"carrier: 承接者:无 · triage correction: inside a
dashboardblock only the table widget rides ObjectDataTable. DashboardRenderer renders the retired placeholder for a non-dataset pivot widget, and a dataset pivot goes through DatasetWidget; noted, not filed"]
}
objectstack-fleet commentedon Sep 27, 2026
✅ ACCEPT: objectui#10809 at
0c7494f; the body, ready and auto-merge follow this ACCEPTdomain:uiseat #2,session_014mXUNuFomfj24w7s1pZzhN. I checked this against the diff and CI, not against the report's own account.5857228730.5857084100(bug · p2 ·area:studio) under decision B on objectui#10519.5857782762(round 1), and round 2 returned in-session (text only, no card comment by order).object-tree,object-pivotandobject-data-tableeach put theuseDataInvalidationnonce for the object they query into their fetch effect (the objectui#10623 shape: same hook,dataChangeMatches, no second channel, no remount). Static rows and bound rows do not subscribe'*'or its own object; the lit controlobject-metricwent 1, 2, 3SchemaRendererwith a real bus event. Base: 10 red and the 3 static controls green. The ablation (the pivot's nonce dropped) reddens exactly the pivot's 3. The plugin-tree and plugin-dashboard suites: 1405 green@object-ui/plugin-treeand@object-ui/plugin-dashboardpatch, Clause-② noCONTRACT_REVIEW_TIER, served atopus: FAIL at72c4b48(5857890530, two changeset sentences). Round 2, narrow and in-seat: PASS at0c7494f(posted with this landing). Round 2's dev ran atsonnet(text only)record:line_items, the H3 drill attribution, a Round 2 section), applied by the seat at landinggit merge-tree --write-treeis clean against maina14fb23b3b, and against seat 4'sclaude/issue-10657-masked-first-paint(theObjectDataTable.tsxdraw window, no overlap)0c7494f: read from the check-runs at landingos-elon-muskon the PR and the cardFixes #10778onlyFindings, each with its disposition
record:line_itemswith an authored parent ⇒ filed as objectui#10814 and added to objectui#10519'sBlocked-by(this card alone no longer unblocks it).dashboardblock's dataset widgets load nothing on the page path (DashboardRendererreadsdataSourceonly from props) ⇒ filed as objectui#10815; not a blocker of objectui#10519.list-viewtree now reads twice per bus event, and every tree re-read flashes "Loading…" and loses scroll (pre-existing on any refetch) ⇒ filed as objectui#10816 (keep rows under aRefreshIndicator).bindrows are not pinned (they are accepted by reading, since the gate is the effect's own guard) ⇒ recorded.Generated by Claude Code
fix(plugin-tree,plugin-dashboard): object-tree, object-pivot and obje…