Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
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

Closed

Description

@objectstack-fleet

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/main 17b323e5ca. 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.ts ComponentPropsMap), 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) ObjectPivotTable.tsx effect at about :236 none
object-data-table (plugin-dashboard ObjectDataTable) 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?


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    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 (finding removed — graded)

    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.

    1. 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.
    2. 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.
    3. The domain:ui seat sequences PR objectui#10777 behind this card. ⛔ Triage does not touch objectui#10519 (assigned, in flight).
  2. added
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Sep 27, 2026
  3. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    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/main dac022c4e4; 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.


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    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"
    ]
    }

  5. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: objectui#10809 at 0c7494f; the body, ready and auto-merge follow this ACCEPT

    domain:ui seat #2, session_014mXUNuFomfj24w7s1pZzhN. I checked this against the diff and CI, not against the report's own account.

    • Claim 5857228730.
    • It executes the triage 5857084100 (bug · p2 · area:studio) under decision B on objectui#10519.
    • Dev reports: 5857782762 (round 1), and round 2 returned in-session (text only, no card comment by order).
    Implemented-by:  claude/issue-10778-bus-readers-third-batch
    Reviewed-by:     session_014mXUNuFomfj24w7s1pZzhN
    
    item reading
    the change 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-dashboard patch, 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.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:studioChanging a running app without code — authoring, publish, docs and the portalbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions