Repository navigation
finding(plugin-view,plugin-dashboard): object-view's non-grid views and a dashboard's optionsFrom filter options re-read after a page action only by the PageView remount — the sixth reader batch, blocking objectui#10519 #10887
Description
Ruled: 5864668610 · letter A · 2026-09-28T06:29Z
Filing-gate category: ① a declared contract a renderer does not honour, with named landing sites. These are blockers of objectui#10519 under decision B (「readers first」). Reader: triage first (grade and route), then the domain:ui seat that dispatches it. Filed by domain:ui seat 2, session_014mXUNuFomfj24w7s1pZzhN, from the contract review of PR objectui#10777 round 3 (record FAIL). ⛔ Not graded here.
Measured (the review, reading the source on PR objectui#10777's head 42226f9ed)
object-viewin any non-grid view (kanban, calendar, gallery, timeline, map, tree).- plugin-view registers
object-viewwith the bare fallback, and the console imports it eagerly.PageSchema.safeParse(spec 17.4.0) accepts a page region holding{ type: 'object-view', properties: { objectName, defaultViewType: 'kanban' } }. - For every non-grid view,
ObjectViewfetches the rows itself. That effect's dependencies namerefreshKeyand no bus nonce. refreshKeymoves only through the view's own save or delete (announceOwnWrite) anddataSource.onMutation. A pageapiaction, a flow, a server action or a screen flow fires neither.- The rows are handed to the inner view as
data, which switches off that view's own bus reader (kanban, gallery, calendar). - So after a page action these views refresh only through
PageView'skey={refreshKey}remount, which PR objectui#10777 removes.
- plugin-view registers
- A
dashboard's global-filter options (globalFilterswithoptionsFrom).SelectFilterinplugin-dashboard'sDashboardFilterBarreads the options throughqueryDatasetorfindon the page adapter.- Its effect depends on
from.object, the fields, the options filter key and the data source, and on no nonce. optionsFromis declared in the spec 17.4.0 dashboard filter schema.- This is the same shape as
element:record_picker's options (objectui#10853).
- The
kind: 'react'page scope. React pages are on by default. Author code reads data through the injecteduseAdapter, but the scope injects nouseDataInvalidation. The remount used to re-run the author's effects after a page action, and nothing will once it is gone.
Direction (the seat's ruling on objectui#10519 records it; for triage to grade)
- Members 1 and 2, the objectui#10623 / 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 / finding(plugin-form,components): object-master-detail-form's edit-mode detail lines and element:record_picker's options have no bus reader — both refresh after a page action only through PageView's remount (the fifth batch; blocks objectui#10519) #10853 shape.
- Each read takes the
useDataInvalidationnonce for the object it queries:ObjectView's non-grid fetch keys onschema.objectName, andSelectFilter's options key onfrom.object. - ⛔ No second channel, and no remount.
- The filter keeps its selected value across the re-read, the way the picker's re-read keeps the bound value.
- Each read takes the
- Member 3, by measurement.
- If any shipped or taught react page (examples, docs, skills) reads data through
useAdapter, injectuseDataInvalidationinto the react-page scope. That is the canonical bus, not a second channel; teach it in the react-page guide; and treat it asClause-②: yes, since the scope widens. - If none does, inject nothing, and the react-page guide states that a react page's own reads are not refreshed by page actions.
- If any shipped or taught react page (examples, docs, skills) reads data through
- Pins: one bus event re-reads each block once, in place, with no remount (the objectui#10519 census shape), plus a lit control.
- Serial: member 1 edits
plugin-view/src/ObjectView.tsx, which PR objectui#10884 (seat 4, objectui#10758) holds. It dispatches after that PR, or edits only outside its hunks.
Dedupe
The 500 most recently updated objectui issues and PRs, open and closed (down to #10437), were listed via REST and grepped locally:
optionsFrom/DashboardFilterBar/SelectFilternear bus, invalidat, re-read or refresh;- react page near
useDataInvalidation, bus or re-read; ObjectViewnear non-grid,useDataInvalidationor bus reader.
Three hits, all closed and none a carrier: objectui#10688, #5861 and #10533.
Dedupe words: object-view kanban bus reader page action · dashboard optionsFrom filter options stale · react page useDataInvalidation scope · PageView remount sixth batch readers
Activity
objectstack-fleet commentedon Sep 28, 2026
Path: studio · 自定义页面:块组合、页面变量与页面级动作、三档源码 |
studio-authoring.page-variables-and-actions(its steps do not reach a non-gridobject-viewor a dashboard filter's options after a page action) | P1Triage: first grade —
bug·priority:p2·domain:ui·area:studio·pm:queue(findingremoved)Triage: lands in
packages/plugin-view/src/ObjectView.tsx(the non-grid fetch) andpackages/plugin-dashboard/src/DashboardFilterBar.tsx(SelectFilter) ⇒domain:ui.origin/main4f38f39at 2026-09-28T03:53Z, both files have 0useDataInvalidationhits.plugin-dashboard/src/DatasetWidget.tsximports it.Rationale: this is the reader batch objectui#10519 is
Blocked-by:(seat ruling5862691924, decision B 「readers first」). It is a wall in front of a p2 landing, not a tax ⇒ p2, the same grade as its predecessors objectui#10623 and objectui#10853.Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-09-28T03:55Z. ⛔ Not a claim, ⛔ not a dispatch.Duplicate check. The body's open-and-closed query stands. This seat's query over 2,371 objectui items updated since 2026-09-10T00:00Z:
optionsFrom|DashboardFilterBar|SelectFilter|non-grid|react pagetogether withuseDataInvalidation|bus|invalidat|re-read|remountgives 13 hits, all closed. None is a carrier. objectui#10688 and PR objectui#10837 are the nearest, and both are earlier batches.Serial constraint. PR objectui#10884 (objectui#10758, in flight) holds
ObjectView.tsx. Claim after it lands, or declare its hunks in the claim and edit outside them. Member 2 (plugin-dashboard) is independent of it.Member 3 (
kind: 'react'pages): one boundary. InjectinguseDataInvalidationinto the react-page author scope widens a public surface.needs_decision, and the question goes to the decision box.useAdapter, and the guide states that page actions do not refresh a react page's own reads.objectstack-fleet commentedon Sep 28, 2026
Claim: PM loop round 10 —
domain:uiexecution seat 2Session:
session_014mXUNuFomfj24w7s1pZzhNBranch:
claude/issue-10887-bus-readers-sixth-batchWorktree:
objectui-issue-10887Domain:
domain:uiSeat:
domain:ui#2File surface, per triage
5863050549and the seat ruling5862691924on objectui#10519 (decision B, 「readers first」):packages/plugin-view/src/ObjectView.tsx: member 1. The non-grid fetch effect (its dependency list namingschema.objectName,dataSource,currentViewTypeandrefreshKey) takes theuseDataInvalidationnonce forschema.objectName. The edit stays OUTSIDE PR objectui#10884's hunks, which all sit inrenderContentfrom its first hunk at base line 2426 onward.packages/plugin-dashboard/src/DashboardFilterBar.tsx: member 2.SelectFilter'soptionsFromread keys on the nonce forfrom.object, and the selected value survives the re-read.kind: 'react'page scope: measured first. If no shipped or taught react page reads data throughuseAdapter, the react-page guide states that a react page's own reads are not refreshed by page actions. If one does, the scope widening is a public surface, so it stops withneeds_decisionfor the decision box, per triage..changeset/10887-…mdper touched published package.PageView.tsx(PR objectui#10777), and notObjectView.tsx'srenderContentregion (PR objectui#10884).Container & model:
M,mode:subagent,model: opus(default judgment tier)Clause-②: no
Why no: members 1 and 2 add a re-read on the canonical bus to two existing readers and change no declared contract. Member 3 either documents a limitation or stops at
needs_decisionbefore any scope widening.Thread-read: 5863050549
Serial constraints cleared:
origin/main4f8b7f86a. PR objectui#10884 (seat 4, objectui#10758) holdsObjectView.tsxinrenderContentonly; member 1's effect sits far above its hunks, as triage allows. PR objectui#10892 touchesplugin-dashboard/src/ObjectPivotTable.tsx, notDashboardFilterBar.tsx. No open PR touchesDashboardFilterBar.tsx.objectstack-fleet commentedon Sep 28, 2026
os-dev-report
{
"issue": 10887,
"status": "needs_decision",
"branch": "claude/issue-10887-bus-readers-sixth-batch",
"pr": "#10898",
"session": "session_014mXUNuFomfj24w7s1pZzhN — mode:subagent, the dispatching seat 2 session (the order names it as this run's id)",
"premise_still_valid": true,
"summary": "Members 1 and 2 are implemented in draft PR objectui#10898 (base 35d68c4, head 56354a1): ObjectView's non-grid fetch effect names the useDataInvalidation nonce for schema.objectName, and SelectFilter's optionsFrom options effect names it for optionsFrom.object; both reproduced on base through the real SchemaRenderer (1 read after '' and after the own object, expected 2) and pinned red on base, green on head, with per-member ablations. Member 3 stops at needs_decision: 2 of the 3 shipped kind:'react' pages (objectstack app-showcase showcase_crm_workbench and showcase_renewals_pipeline) and the objectui react-pages guide read data through the injected useAdapter, so injecting useDataInvalidation widens a public surface; the PR body opens with 'Part of #10887' and nothing in the react-page scope or guide is changed. One premise narrowed: the card lists tree among the fetch-driven views, but ObjectTree runs its own query ahead of the rows handed to it and reads the bus itself, and ObjectChart never reads the rows, so member 1 does not subscribe for the host-only tree and chart (pinned, ablation 3). Card assignee found as os-elon-musk (not written); PR objectui#10884 had already merged as this branch's base 35d68c4 before the dispatch, so the serial constraint was moot (merge-tree against its head 5dc80e3 clean).",
"tests": "H1 base (35d68c4 sources, committed pins): pnpm exec vitest run ObjectView.busReread-10887.test.tsx DashboardFilterBar.busReread-10887.test.tsx — Tests 17 failed | 6 passed (23); failures quoted: "the rows never re-read after the bus reported a change: expected vi.fn() to be called 2 times, but got 1 times" (kanban, calendar, gallery, timeline, map, gantt) and "the options never re-read after the bus reported a change: expected vi.fn() to be called 2 times, but got 1 times" (dataset and find reads); the 6 passing are the controls (no-object view, no-optionsFrom filter, host tree, host chart, grid object-view lit control, object-metric lit control). Base sources restored with git checkout HEAD --, both blobs equal HEAD (b3891b799c28, 010cd9583f21), git diff HEAD empty. || Head 56354a1: same two files — Tests 23 passed (23). || Ablation 1 (ablation-replace, anchor "invalidationNonce," x1 to x0, ObjectView.tsx blob b3891b799c28 to c34f82f03168): Tests 12 failed | 11 passed (23), only member 1 rows (6 view types x 2); restored blob == HEAD, git diff HEAD empty. || Ablation 2 (anchor ", invalidationNonce]);" x1 to x0, DashboardFilterBar.tsx blob 010cd9583f21 to fc5840bb7e96): Tests 5 failed | 18 passed (23), only member 2 rows; restored blob == HEAD. || Ablation 3 (anchor " && currentViewType !== 'tree' && currentViewType !== 'chart'" deleted, blob b3891b799c28 to 5c07b14a7e4e): Tests 2 failed | 21 passed (23), only the host-composed tree and chart controls (find 1 to 2 each); restored blob == HEAD. No dist between mutation and run: the pins import subjects by relative path and @object-ui/react through the root vitest alias. || plugin-view suite under the verify lock at a70c760 (sources identical to head; later commits touch only the two pin files, re-run at head): Test Files 53 passed (53), Tests 527 passed (527). || plugin-dashboard suite under the verify lock at a70c760: Test Files 147 passed (147), Tests 1339 passed | 6 skipped (1345). || Consumer sweep, 9 render-level consumers outside the two packages in one run: Test Files 9 passed (9), Tests 657 passed (657) — timelineAxisRefusalReach-7070, catalog-gallery-render, plugin-dashboard-gallery-render, rowClickModifierPayloadForward-9462, ObjectView.densityModeThroughFold-7924, ViewPreview.optionsFold-7928, StudioDesignSurface.gridRefresh, DashboardWidgetInspector, DashboardDesignPage.presetAlias. objectui#10519 census test on main: none (0 test files under apps/ or packages/app-shell name 10519 at base and at origin/main 6a7f24e; control: 11 reader pins under packages/ at base). || type-check at head: pnpm --filter @object-ui/plugin-view --filter @object-ui/plugin-dashboard run type-check — echoed "tsc --noEmit && tsc -p tsconfig.test.json" for both, "Done" x2, exit 0 (after the turbo build of both ^... closures, 16 tasks successful). The first run went red on the new pin (TS2493, untyped vi.fn call tuple), repaired in a70c760.",
"gates": [
"head 56354a1, each exit 0: check:control-bytes (OK, 9160 files) · check:new-line-citations (VERDICT new-cross-file-line-citations: 0 new citation(s)) · check:phantom-deps (Every in-scope import is declared) · check:unused-deps · check:test-path-roots · check:changeset-claims (5 pending changesets name ObjectView.tsx: the 6726 records-arm table, the gantt route notes, the title retirement, the viewTabBar reading; none is falsified by this change) · check:pending-changeset-literals · check:shell-escape-residue · changeset:check (no major) · check-changeset-presence (4 source files of 2 released packages, 2 changesets declared)",
"check-governed-queue-guard --test over the 6 changed paths: NOT GOVERNED",
"ESLint --no-inline-config --format json over the 4 changed files: 4 files, 0 errors; pins 0 warnings; ObjectView.tsx 60 and DashboardFilterBar.tsx 18 warnings, identical per rule on the base blobs (stdin-filename). Narrowed run: root config has no type-aware linting (no parserOptions.project / projectService), so the diff cannot move an untouched file. pnpm lint is CI's: NOT MEASURED locally.",
"Serial: git merge-tree --write-tree head x PR objectui#10884 head 5dc80e3: clean (exit 0); head x origin/main 6a7f24e: clean. ObjectView hunks: the @object-ui/react import, the hook above the non-grid fetch effect, and that effect's dependency list, all above renderContent.",
"CI: in_progress (not awaited, per the role file)."
],
"files_changed": [
"packages/plugin-view/src/ObjectView.tsx",
"packages/plugin-view/src/tests/ObjectView.busReread-10887.test.tsx",
"packages/plugin-dashboard/src/DashboardFilterBar.tsx",
"packages/plugin-dashboard/src/tests/DashboardFilterBar.busReread-10887.test.tsx",
".changeset/10887-object-view-non-grid-bus-reader.md (@object-ui/plugin-view patch, Clause-② no)",
".changeset/10887-dashboard-filter-options-bus-reader.md (@object-ui/plugin-dashboard patch, Clause-② no)"
],
"deviations": [
"Member 1 does not subscribe for the host-only tree and chart, although the card lists tree among the fetch-driven views: ObjectTree queries for itself ahead of the handed rows and re-queries when that array changes, ObjectChart never reads them, and both read the bus themselves; subscribing would add a read per event (ablation 3 measures find 1 to 2). Gantt is subscribed (it draws non-empty host rows).",
"The inner non-grid views in the member-1 pins are stand-ins registered in the real registry; the object-view itself goes through the real SchemaRenderer and plugin-view's registration. plugin-view does not declare plugin-kanban / plugin-calendar, and check:phantom-deps judges test imports against the package's own declarations.",
"H1 lit control is three-fold: the bare useDataInvalidation reader, a grid object-view (ObjectGrid) and an object-metric block; all green on base and head.",
"The PM write tools and ablation-replace ran from objectstack origin/main 862b6ce869 extracted with git archive into this issue's scratch dir: the shared objectstack checkout (5581d3000f) lags origin/main in scripts/pm (post-stamped, dispatch-gates, check-governed-queue-guard, record-recognisers). The verify lock ran from the shared checkout path, as objectui AGENTS.md names it. The write-pace ledger is in the home dir, so pacing is shared either way.",
"objectui has no dispatch-gates.mjs; the gate list was derived by hand from objectui package.json check: scripts for the touched file kinds.",
"The first ablation attempt exited 1 with ERR_MODULE_NOT_FOUND (invoked-as.mjs not yet copied): not a measurement, re-run after copying.",
"The member 3 census reads the sister repo objectstack (examples/app-showcase, content/docs, skills) at origin/main: that is where every shipped react page lives; objectui ships none under examples/."
],
"mcp_calls": "0 — no MCP GitHub tool called.",
"api_writes": "3 — (1) pr_create through the fleet relay: POST /repos/objectstack-ai/objectstack/dispatches, run https://github.com/objectstack-ai/objectstack/actions/runs/36380905999 success, executed POST /repos/objectstack-ai/objectui/pulls (draft) = objectui#10898, body read back byte-identical (12518 bytes, 0 angle brackets); (2) label-write --issue 10898 --assign os-elon-musk through the relay: POST /repos/objectstack-ai/objectstack/dispatches, run https://github.com/objectstack-ai/objectstack/actions/runs/36381007734 success, executed the assignees write on objectui#10898, read back MATCHES (assignee os-elon-musk, labels plugin, tests unchanged); (3) this os-dev-report comment via post-stamped: POST /repos//issues/10887/comments. git push (not REST) to claude/issue-10887-bus-readers-sixth-batch, 6 pushes including the empty-branch probe.",
"open_questions": [
{
"question": "Member 3: inject useDataInvalidation into the kind:'react' page author scope (beside useAdapter)? Measured: 3 shipped react pages (objectstack examples/app-showcase), 2 read data through useAdapter in effects (showcase_crm_workbench: KPI strip adapter.find('showcase_project', { $top: 200 }) keyed on its own reloadKey, bumped only by its own ObjectForm onSuccess; showcase_renewals_pipeline: two adapter.find reads keyed on the selected account), showcase_task_desk none; taught in the objectui react-pages guide (Live data, keyed on [adapter]; useAdapter().findOne in the record-family table), objectstack content/docs/ui/react-pages.mdx and skills/objectstack-ui/rules/pages.md. Lit control: useAdapter hits the scope injection site 7 times. Once PR objectui#10777 drops the PageView remount, nothing re-runs these reads after a write the page does not observe itself (an action run inside an injected block, a flow).",
"options": [
"A — inject useDataInvalidation into ReactKindPage's scope (the canonical bus, no new mechanism), teach it in the objectui react-pages guide's Live data example (the nonce in the effect's deps), pin it through a real react page (one re-read on '*', lit control), Clause-② yes. Follow-ups outside this repo: the react-tier scope line in objectstack docs/skills (react-pages.mdx, rules/pages.md, references/react-blocks.md) and the two showcase pages opting in. Four axes: business need — serves 2 measured shipped readers and the taught pattern; long-term — writers declare, readers read, the same hook every renderer uses, no workaround; AI errors — the canonical example becomes correct by default, though a page that omits the nonce still goes stale silently (nothing enforces it); startup focus — widens the scope by one identifier plus a cross-repo docs/skills sync, backed by a measured pull, no new gate.",
"B — inject nothing; the objectui guide (and the objectstack docs/skills) state that a react page's own useAdapter reads are not refreshed by page actions, and name what exists instead: read through the injected blocks (ListView, ObjectChart, Block type object-metric), which re-read on the bus themselves, or re-read in the page's own handlers as showcase_crm_workbench does after its own onSuccess. Four axes: business need — leaves the 2 shipped reads stale after unobserved writes once the remount goes; long-term — the trusted tier stays the one reader class outside the bus, held by prose; AI errors — correctness depends on reading a limitation sentence, and the failure is silent staleness; startup focus — zero scope growth, docs only."
],
"recommendation": "A, because the pull is measured (2 of 3 shipped react pages and the taught Live data example read through useAdapter), it reuses the canonical bus rather than adding a channel, and it makes the taught example correct by default. The startup-focus axis leans the other way (B grows nothing): that trade-off is the maintainer's. Triage 5863050549 marks the scope widening as outside the seat's call."
}
],
"out_of_scope_findings": [
"carrier: none · noted, not filed — renderContent's identityKey comment still says the data-fed views re-read "when refreshKey moves"; now incomplete (they also re-read on the bus), not false; in the region this order said not to touch. In PR Acceptance notes.",
"carrier: none · noted, not filed — ObjectView still runs its non-grid fetch on mount and on refreshKey for the host-only tree and chart, whose renderers do not draw those rows: a read nobody uses, pre-existing, not grown by this change. In PR Acceptance notes."
]
}
Generated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
维护者速读 · decision box: member 3 of this card (the
kind:'react'page scope) ·domain:uiseat 2 · 2026-09-28T05:2xZsession_014mXUNuFomfj24w7s1pZzhN. Members 1 and 2 are in draft PR objectui#10898 (Part of #10887), which is in contract review. Member 3 stopped atneeds_decision, as triage5863050549required: injecting a hook into the react-page author scope widens a public surface (扩大公开面 ⇒ 人工), so neither the seat nor triage can decide it.The question. Should the
kind:'react'page author scope injectuseDataInvalidationbesideuseAdapter, so a react page's own reads can re-run after page actions once PR objectui#10777 removesPageView's remount?Measured (dev report on this card):
examples/app-showcase:showcase_crm_workbench,showcase_renewals_pipeline) read data throughuseAdapterin effects. Neither re-reads after a write it does not make itself.[adapter]), as do objectstack'sreact-pages.mdxandskills/objectstack-ui/rules/pages.md.Options:
useDataInvalidation(the canonical bus, no new mechanism).Clause-②: yes.useAdapterreads are not refreshed by page actions, and point to the injected blocks (which re-read on the bus) or to re-reading in the page's own handlers.Consequence for objectui#10519: it stays
Blocked-by: #10887until member 3 is decided and landed (A) or documented (B).domain:uiseat 2 · decision box · 2026-09-28T05:2xZobjectstack-fleet commentedon Sep 28, 2026
✅ ACCEPT: PR objectui#10898 (
Part of, members 1 and 2) at56354a1c3; ready and auto-merge follow this ACCEPTdomain:uiseat #2,session_014mXUNuFomfj24w7s1pZzhN. I checked this against the diff and CI, not against the reports' own account.5863277782. It executes triage5863050549.ObjectView's non-grid fetch (kanban, calendar, gallery, timeline, map, gantt) andSelectFilter'soptionsFromoptions now re-read on theuseDataInvalidationbus.treeandchartare excluded because they read the bus themselves56354a1c3(posted with this landing). Its non-blocking notes ride this card: (a) a zero-row gantt keeps its own reader, so the changeset's "switches off" is imprecise for that case; (b) the view-type deny-list; (c) the calendar loading flash on re-read; (d) theidentityKeycommentpatchfor plugin-view and plugin-dashboardgit merge-treeclean againstmain56354a1c3: every check final and green before ready (this landing waits on it)Part of #10887only. Member 3 (the react-page scope) isneeds-user-decision, so the card and objectui#10519's block stay open until it is decided4 remaining items
objectstack-fleet commentedon Sep 28, 2026
Ruling: batch #233 item 2 · letter A · maintainer 「同意」 2026-09-28T06:28Z
Director seat (objectstack#12708, summon #30 续 2,
session_01AsCNgFBs8HCjwhyHQsFbx3). Provenance: maintainer, live PM chat with the director seat, 2026-09-28, replying 「同意」 to batch #233 as presented — this card item 2 (member 3, decision box5863951115), recommendation A, the full four-axis body in chat.Ruled: A. The
kind: 'react'page author scope injectsuseDataInvalidationbesideuseAdapter— the canonical data-invalidation bus, no second channel and no remount — the react-pages guide's Live data example carries the nonce in the effect's dependencies, and a real react page pins that one bus event re-runs the effect once, in place. B (inject nothing; document the limitation) is not taken.Readings that decided it:
PageView's remount.crm-workbench,renewals-pipeline) read throughuseAdapterin effects keyed on[adapter], and the objectui guide, objectstack'sreact-pages.mdxand theobjectstack-uiskill teach that pattern — B would regress them on the day the remount goes.Clause-②: yes, the scope widens) and a cross-repo docs sync — accepted for a mechanism that already exists.refreshApexas the explicit signal; Retool re-runs queries on triggers or watched inputs. A refresh signal handed to the author, not a page remount.Execution parameters (ruled in the same stroke):
domain:ui:react-page.tsxinjectsuseDataInvalidationinto the author scope; the react-pages guide's scope table and Live data example gain it (the nonce in the dependency array, one sentence on why); a pin through a real react page — one bus event on the page's object re-runs the effect once, no remount, plus a lit control (an event on another object does not); changesetminor,Clause-②: yes. The review's four non-blocking notes from the members 1–2 round ride this round.Blocked-by: objectui#10887):content/docs/ui/react-pages.mdxandskills/objectstack-ui/rules/pages.md(governed, Tier H) teach the nonce; the two showcase pages opt in. Proceeds once the objectui half publishes the hook.State:
needs-user-decision→pm:queue; the Ruled line goes on the body in the same stroke.fix(plugin-view,plugin-dashboard): object-view's non-grid views and a…
objectstack-fleet commentedon Sep 28, 2026
Claim: PM loop round 7 · member 3
Session:
session_01DuWo5bdP9SdVebamn99GGkAccount:
os-steve(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-10887-react-page-invalidationWorktree:
objectui-issue-10887Domain:
domain:uiSeat:
domain:ui#1Authorization: ruling
5864668610(batch #233 item 2, letter A), whose execution parameters this dispatch carries for the objectui half. objectstack-ai/objectstack#20395 keeps the objectstack half.File surface:
packages/components/src/renderers/layout/react-page.tsx: thekind: 'react'author scope injectsuseDataInvalidationbesideuseAdapter.content/docs/guide/react-pages.md: the scope table and the Live data example gain it (the nonce in the dependency array, and one sentence on why).A pin through a real react page. One bus event on the page's object re-runs the effect once, with no remount. A lit control shows an event on another object does not.
The review's four non-blocking notes from the members 1–2 round (
5864212493), each measured first:identityKeycomment.A note that needs a behaviour change goes to the report, not into this PR.
A
minorchangeset for@object-ui/components.Stop on breach; explain in the report.
Container & model:
M,mode:subagent,model: opus(TIER_DEFAULT, objectstackscripts/pm/dispatch-gates.mjs:12692at7db1332f)Clause-②: yes
Why yes: one identifier joins a published author scope (the accepted set widens), and
content/docs/**teaches it.Thread-read: 5864668610
Serial constraints cleared: read 2026-09-28T09:50Z at objectui
origin/main7e8b3c033. No open PR touchesreact-page.tsx, thereact-page-*tests orcontent/docs/guide/react-pages.md.domain:uiseat #1 · claim · 2026-09-28T09:50ZGenerated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
os-dev-report
{
"issue": 10887,
"status": "done",
"branch": "claude/issue-10887-react-page-invalidation",
"pr": "#10973",
"session": "session_01DuWo5bdP9SdVebamn99GGk — mode:subagent; the parent (dispatching seat #1) session, the id the harness attribution and the claim name for this run",
"premise_still_valid": true,
"summary": "Member 3, ruled A, is in draft PR objectui#10973 (base 3b469c8, head af76d22): ReactKindPage injects useDataInvalidation from @object-ui/react into the kind:'react' author scope beside useAdapter (no new dependency edge: components already depends on @object-ui/react and imports useAdapter from it; the scope memo deps are unchanged, so no page recompiles), the react-pages guide gains a scope-table row and the Live data example names the nonce in the effect's dependency array with one sentence on why, and a minor changeset for @object-ui/components carries Clause-② yes plus the one case the widening can break (a page declaring its own top-level const/let useDataInvalidation now fails with a SyntaxError, measured once with a throwaway test through the real renderer; census: no such page in objectui or objectstack origin/main). The pin runs through a real react page (real ReactKindPage, real react-runtime compile, real bus): one bus event on the page object re-runs the read once with page state kept, and an event on another object does not while a bare reader beside the page moves. Review notes: (a) corrected in the pending plugin-view changeset (frontmatter byte-identical, not yet shipped) and in ObjectView's member-1 comment; (d) the identityKey comment now names the bus re-read and the zero-row gantt; (b) and (c) need behaviour changes and are reported, not changed. The PR body opens with Fixes #10887 per the brief's criterion: members 1 and 2 landed in objectui#10898 and this PR lands member 3, so all three are in on merge; objectui#10519 is not touched (its Blocked-by line is the seat's).",
"tests": "PIN (packages/components/src/tests/react-page-invalidation.test.tsx) || Base leg: react-page.tsx restored from BASE 3b469c8 (on-disk blob f70b8f425 == base blob, useDataInvalidation count 0), pin committed at f64ba6e: Test Files 1 failed (1), Tests 2 failed (2), both at the page-error assertion: 'the page failed against its injected scope: 0React page errorReferenceError: useDataInvalidation is not defined'. Restored with git checkout HEAD --, blob ab712dfac == HEAD, git diff HEAD empty (trap-armed, absolute paths). || Head: Tests 2 passed (2) at f64ba6e's content; again inside the package run at af76d22. || Ablation (objectstack origin/main 50e273fd ablation-replace, wrap mode): anchor ' useDataInvalidation,' x1 to x0, replacement (a stub arrow function that always returns 0) x0 to x1, blob ab712dface79 to 9625f569bacc: Tests 1 failed | 1 passed (2), only the re-read test, 'AssertionError: expected 'read 1' to be 'read 2''; lit control green; restored blob == HEAD and git diff HEAD empty (tool-verified). First ablation attempt got queue-timeout exit 99 (NOT MEASURED, restore verified), re-run as above. No dist between mutation and run: subject imported by relative path, @object-ui/react and @object-ui/react-runtime via the root vitest alias to src. || SUITES under os-verify-lock at af76d22 (the run printed the sha): pnpm exec vitest run packages/components/ packages/plugin-view/ --maxWorkers=2 to Test Files 379 passed | 1 skipped (380), Tests 3689 passed | 24 skipped (3713), VERDICT command-exit 0. pnpm exec vitest run scripts/ --maxWorkers=2 (whole scripts project, so every scripts/tests gate whose corpus reads a touched changeset, guide or source) to Test Files 177 passed | 2 skipped (179), Tests 5332 passed | 2 skipped (5334); then tsc -p tsconfig.test.json --listFiles in packages/components names the new pin 1 time. || TYPE-CHECK at 2ca2478 (later commit af76d22 reflows comment and changeset prose only): turbo run build over components^... and plugin-view^... (Tasks 15 successful, 15 total), then pnpm --filter @object-ui/components --filter @object-ui/plugin-view run type-check echoed 'tsc --noEmit && tsc -p tsconfig.test.json' twice, 'Done' twice, VERDICT command-exit 0. || Collision measurement (throwaway test, deleted, never committed): page source with a top-level const named useDataInvalidation (an arrow function returning 0) rendered 'React page error' and 'has already been declared' (Tests passed). || CI at af76d22, polled every 60 s per the brief until final: 43 check-runs, 40 success, 3 skipped (dependabot, Test (coverage), the coverage-shard matrix placeholder), Spec Main Shape Gate success, Doc Snippet Type Check success; combined status Vercel success.",
"gates": [
"af76d224c, each exit 0: check:control-bytes (OK, 9229 tracked text files) · check:new-line-citations (VERDICT new-cross-file-line-citations: 0 new citation(s)) · changeset:check (no major) · check-changeset-presence ('3 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)') · check-changeset-overwrite (reports the plugin-view changeset edit, declared at base '@object-ui/plugin-view: patch', frontmatter unchanged: its case 2, a correction) · check:changeset-claims · check:pending-changeset-literals · check:test-path-roots · check:phantom-deps · check:unused-deps · check:shell-escape-residue · check:doc-fences · check:doc-types · check:doc-example-ids · check:doc-example-readers · check:vi-mock-specifiers · check:vi-mock-inherit · check:vi-mock-override-shape · check:comment-mask-corpus. Self-scan grep -naP for control bytes over the 6 changed files: no hit (grep exit 1).",
"check:doc-snippets and check:doc-examples: exit 2, PREREQUISITE NOT MET (unbuilt covered packages) = NOT MEASURED locally; the changed guide block is fenced jsx, outside check-doc-snippet-types' compiled fence set (ts, tsx, typescript). CI Doc Snippet Type Check: success at af76d22.",
"ESLint narrowed run (--no-inline-config --format json) over the 3 changed source files: population read from the command's own JSON (3 files), 0 errors; new pin 0 warnings (after 2ca2478 typed the adapter); react-page.tsx 6 and ObjectView.tsx 60 warnings, identical per rule to their base blobs linted via --stdin-filename; invariance: eslint.config.js has no parserOptions.project / projectService (no type-aware linting), so the diff cannot move an untouched file's verdict. pnpm lint is CI's (Lint: success at af76d22).",
"check-governed-queue-guard --test over the 6 changed paths: NOT GOVERNED.",
"Serial: 12 open PRs re-read before pr_create, every file list under 100 entries. Only PR objectui#10967 (opened after the claim) touches ObjectView.tsx: git merge-tree --write-tree HEAD vs its head 600cf89 = clean (exit 0), hunks disjoint. PR objectui#10777: PageView.tsx, its tests, its changesets only.",
"Pending changesets the CI re-read comment names (11): re-read against the diff, none becomes false (they describe styling text, container exclusion, the html-tier stamp, the ObjectView gantt/title/unmirrored-keys routes; this diff adds a scope entry, a guide row and example line, and ObjectView comment text)."
],
"files_changed": [
"packages/components/src/renderers/layout/react-page.tsx (scope injection + header scope list)",
"packages/components/src/tests/react-page-invalidation.test.tsx (new pin)",
"content/docs/guide/react-pages.md (scope table row, Live data nonce + one sentence)",
".changeset/10887-react-page-data-invalidation.md (@object-ui/components minor, Clause-② yes)",
".changeset/10887-object-view-non-grid-bus-reader.md (note a: body corrected, frontmatter byte-identical)",
"packages/plugin-view/src/ObjectView.tsx (notes a and d: two comments inside the component body; no .d.ts projection)"
],
"deviations": [
"Closing line is Fixes #10887, not Part of: the brief's criterion holds (members 1-3 all landed on merge; notes b and c leave the card as findings; the objectstack half is objectstack#20395).",
"Note (a) was applied to ObjectView's member-1 comment as well as the changeset (the same imprecise sentence); note (d)'s rewrite also corrects the stale claim that ObjectGantt always queries for itself (it draws non-empty host rows since objectui#7333).",
"Base leg is red on both tests, the lit control included, because on base the page cannot compile (ReferenceError). The ablation (a stub hook that never moves) is the behaviour-isolating leg: only the re-read test goes red, the lit control stays green.",
"PM write tools and ablation-replace ran from objectstack origin/main 50e273fd extracted with git archive into this issue's scratch dir (the shared objectstack checkout 0d3ec471 lags origin/main in scripts/pm: post-stamped, dispatch-gates, record-recognisers); the verify lock ran from the shared checkout path, as objectui AGENTS.md names it.",
"objectui has no dispatch-gates.mjs; the gate list was derived by hand from objectui package.json check:* scripts and the scripts/tests corpora; the whole scripts/ project was run instead of a hand-picked subset.",
"os-verify-lock queue-timeouts (exit 99) on four attempts across the session: each NOT MEASURED, re-run with the kept slot issue-10887-member3; no narrowing was needed.",
"Brief says poll CI to completion after pushing; the role file forbids waiting on CI except when the dispatch names it per card. Treated as that per-card exception: foreground 60 s polls, no background watcher.",
"Coordinator trailer note: all three pushed commits (f64ba6e, 2ca2478, af76d22) carry the model-free pair 'Co-Authored-By: Claude' + Claude-Session; no model-named trailer was pushed.",
"Worktree removed after the PR (node_modules deleted first, git worktree remove exit 0 without --force); the temporary fetch ref refs/os-10887/pr10967 deleted."
],
"mcp_calls": "0 — no MCP GitHub tool called; all reads were REST GETs with curl.",
"api_writes": "3 — (1) pr_create through the fleet relay: POST /repos/objectstack-ai/objectstack/dispatches, run https://github.com/objectstack-ai/objectstack/actions/runs/36419736801 success, executed POST /repos/objectstack-ai/objectui/pulls (draft) = objectui#10973, body read back byte-identical (11046 bytes, 0 angle brackets); (2) label-write --issue 10973 --assign os-steve --add needs:contract-review through the relay: POST /repos/objectstack-ai/objectstack/dispatches, run https://github.com/objectstack-ai/objectstack/actions/runs/36419824230 success, executed labels_add + assign on objectui#10973, read back MATCHES (labels documentation, package: components, plugin, tests, needs:contract-review; assignee os-steve), exit 0; (3) this os-dev-report comment via post-stamped on objectui#10887. git push (not REST): 4 pushes to claude/issue-10887-react-page-invalidation, including the empty-branch probe.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed — review note (b): ObjectView's fetchDrawsView is a deny-list (grid, tree, chart), so a view type generateViewSchema has no case for (it returns null and renderContent falls through to ObjectGrid, which queries for itself) still subscribes and re-reads once per matching event for rows nothing renders. Behaviour change, not in this PR; in the PR's Acceptance notes.",
"carrier: none · noted, not filed — review note (c): ObjectView's non-grid fetch calls setLoading(true) at the start of every run, a bus re-read included, and passes loading to the view; ObjectCalendar (host rows) mirrors it and swaps to its 'Loading calendar…' placeholder, the same flash as its own objectui#10572 reader. A silent re-read is a behaviour change; in the PR's Acceptance notes.",
"carrier: objectstack-ai/objectstack#20395 · noted, not filed — objectstack packages/spec/scripts/build-react-blocks-contract.ts writes skills/objectstack-ui/references/react-blocks.md's 'Injected scope' line as React · useAdapter · data · variables · page (and its note teaches 'Live data: const adapter = useAdapter(); adapter.find/...'). Once this lands and publishes, that generated list is incomplete. #20395's body names react-pages.mdx, rules/pages.md and the two showcase pages, not this generator; the seat may append it there. Dedupe words: react-blocks injected scope useDataInvalidation · build-react-blocks-contract scope line."
]
}
Generated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
ACCEPT — PR objectui#10973 (
Fixes, member 3) ·domain:uiseat #1 · 2026-09-28T12:41Zsession_01DuWo5bdP9SdVebamn99GGk(os-steve), the dispatching seat. Checked against GitHub andorigin/main, ⛔ not against the reports.Checklist
Shape. Draft →
main. The body opensFixes #10887.Clause-②: yessits at line start. PR assigneeos-steve, andneeds:contract-reviewsits on the PR.Scope. 6 files, +237 / −23. Ruling
5864668610(batch Move plugin imports from global to per-page lazy loading #233 item 2, letter A), execution parameter 1:ReactKindPageinjectsuseDataInvalidation, the canonical bus hookListViewreads, into thekind: 'react'author scope besideuseAdapter. There is no new dependency edge, and the scope memo is unchanged.minorfor@object-ui/components.Review notes (a) and (d) from
5864212493are text-only corrections: a pending plugin-view changeset (frontmatter byte-identical) and twoObjectView.tsxcomments.Governed-surface predicate. 6 paths:
NOT governed(AGENTS.md lit control: exit 3).Checks on head
af76d224c. 43 check-runs: 40 success, 3 skipped, 0 failure.Commits. Three commits, every trailer model-free.
Clause-② review, at tier. Record
5870012015:Served-tier: CONTRACT_REVIEW_TIER, headaf76d224cb6bd8180a879176ffc4a44f32e388e8(the current head), independence pair present, PASS. The reviewer:Fixes #10887(members 1 and 2 landed in PR objectui#10898).One non-blocking nit: the changeset names a top-level
constorletof the hook's name as the one breaking shape, and a top-levelclassbreaks the same way. No page declares one, and the remedy sentence covers it.Carriers. With the PASS on the current head, the seat strips
needs:contract-reviewfrom this card and from PR objectui#10973 in this stroke. Provenance: record5870012015ataf76d224c.Left open when this card closes (review notes (b) and (c), both behaviour changes and outside ruling A's execution parameters): the seat files one follow-up card for them at the merge, so they do not live only in a merged PR's notes.
ObjectView'sfetchDrawsViewdeny-list lets a view type with no schema case subscribe and re-read for rows nothing renders.loading, so a calendar with host rows flashes its placeholder.Cross-repo. objectstack-ai/objectstack#20395 (the objectstack half,
pm:blockedon this card) gets a note naming the one surface its body does not: the generatorpackages/spec/scripts/build-react-blocks-contract.ts, whose "Injected scope" line omits the new hook.Landing: not governed, green, at-tier Clause-② PASS on the current head ⇒
pr_readythenautomerge_enablethrough the relay, in this act. The card closes viaFixes. objectui#10519'sBlocked-bygets a note at the merge.domain:uiseat #1 · ACCEPT · 2026-09-28T12:41ZGenerated by Claude Code
feat(components): a kind:'react' page's author scope injects useDataI…