Repository navigation
finding(app-shell): the console mounts dashboards with no refresh handler, so an authored refreshIntervalSeconds never starts a timer #11062
Description
Activity
objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsPath: business reporting — a dashboard refreshes as its author set | 缺项 (the console passes no refresh handler, so
refreshIntervalSecondsdoes nothing) | P3Triage: first grade —
bug·priority:p3·domain:ui·area:reports·pm:queue. Direction: enforce. The console passes the refresh handlerTriage: lands in
packages/app-shell/src/views/DashboardView.tsx(rendersDashboardRendererwith noonRefresh) ⇒domain:ui.Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-09-29T09:14Z. ⛔ Not a claim, ⛔ not a dispatch.Why p3. Studio offers 自动刷新 (
refreshIntervalSeconds), and the console never starts a timer. It is a declared, authorable key with no effect, and read at source only.Direction: enforce, by the #18900 criterion. Mainstream dashboards auto-refresh on an authored period, so
DashboardViewpasses a refresh handler that re-fetches the dashboard's widgets, anduseDashboardAutoRefresharms as designed. ⛔ No second timer in the view. Pins: an authored 60 s period re-fetches once per period (fake timers),0means none, and unmounting clears the timer. Measure once in a browser before closing, since the card is source-read.- addedarea:reportsBusiness reporting — dashboards, reports, the numbers a manager readsBusiness reporting — dashboards, reports, the numbers a manager readsbugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatand removed
on Sep 29, 2026 objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsClaim: PM loop round 22 · an opus-only card while the review tier is unavailable
Session:session_01DuWo5bdP9SdVebamn99GGk
Account:os-steve(the seat's linked user asGET /useranswers it; the card's assignee)
Branch:claude/issue-11062-dashboard-auto-refresh
Worktree:objectui-issue-11062
Domain:domain:ui
Seat:domain:ui#1
File surface (triage grade5887250442: enforce, the console passes the refresh handler):packages/app-shell/src/views/DashboardView.tsx: it passesDashboardRendereranonRefreshthat re-reads the dashboard's widget data in place, souseDashboardAutoRefresharms as designed. ⛔ No second timer in the view.- Pins with fake timers: an authored 60 s period refreshes once per period,
0means none, and unmounting clears the timer. - A changeset.
⛔
useDashboardAutoRefreshandDashboardRendererkeep their contract (objectui#8820, objectui#11004). Other hosts ofDashboardRenderer(the Studio preview, the componentspagerenderer) are measured and reported, not changed here.
Stop on breach; explain in the report.
Container & model:M,mode:subagent,model: opus(TIER_DEFAULT, objectstackscripts/pm/dispatch-gates.mjs:12692at81137630)
Clause-②: no
Why no: a console host wires a handler the renderer already accepts; no published type, schema key, spec row or documented contract moves.
Thread-read: 5887250442
Dispatch note: under the maintainer's 「当前没有fable,你可以派 opus 卡」 (this seat's chat, 2026-09-29T01:00Z), this card needs no review atCONTRACT_REVIEW_TIER. The seat verifies the changeset prose itself at the ACCEPT.
Serial constraints cleared: read 2026-09-29T10:39Z at objectuiorigin/main. PR objectui#11077 (objectui#11056, this seat) merged 2026-09-29T10:35Z. None of the four open code PRs (objectui#11084, #11078, #11069, #10278) touchesDashboardView.tsxorpackages/plugin-dashboard.domain:uiseat #1 · claim · 2026-09-29T10:39Z
Generated by Claude Code
objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 11062,
"status": "done",
"branch": "claude/issue-11062-dashboard-auto-refresh",
"pr": "#11093",
"session": "session_01DuWo5bdP9SdVebamn99GGk (mode:subagent, so this is the parent seat's id from the Claude-Session line)",
"premise_still_valid": true,
"summary": "DashboardView now passes DashboardRenderer onRefresh={refreshDashboardData}, a module-level function that calls notifyDataChanged({ objectName: '' }), the bus's unknown-scope value and the one PageView already uses. There is no second timer and no useCallback: useDashboardAutoRefresh arms on the authored period as designed, and widgets that hold a bus subscription re-read in place with no remount. The pin is DashboardView.autoRefresh-11062.test.tsx, 5 cases through the real view, renderer, DatasetWidget and bus. The docs and the changeset (app-shell patch) say what the user sees: a 'Refresh All' button in its own grid row, the 600 ms 'Refreshing…' state, and English-only labels. Zone 2 item 1 is partly falsified in a running console: the 4 dataset-bound KPI tiles (no dimensions) of 9 widgets never re-read, because DatasetWidget subscribes on the answer'sobject, which the analytics service attaches only as drill-through metadata. That is out_of_scope_findings item 1. The draft PR has CI all complete (43 check-runs: 40 success, 3 skipped, Spec Main Shape Gate and Bundle Analysis success). The PR assignee os-steve was set and read back. I followed three conflicts toward the dispatch text and the role file: model-free commit trailers instead of the harness reminder's model-named Co-Authored-By; the role file's session-URL PR footer instead of the harness form; and the brief's per-card CI polling instead of the role file's no-wait default.",
"tests": "All heavy runs went through os-verify-lock. Head a353dcd unless noted. PIN: 'Tests 5 passed (5)'. RED LEG at ae53475 (DashboardView.tsx checked out at base 8732846, on-disk blob 2e95d2a61 equal to the base blob, handler count 0): 'Tests 3 failed | 2 passed (5)'. The period case failed at 'the widget was not re-read when the authored period ended' (1 call, expected 2), the unmount case at 'the timer never ran', and the manual button case because the button is absent. The 0 and absent-period cases pass on base because they assert absence. Restore used git checkout HEAD on the absolute path inside a trap: blob cee18a6e7 equal to HEAD, git diff HEAD empty, status clean. MUTATION LEG at ae53475 via ablation-replace.mjs (scope '' changed to 'unrelated_object', anchor 1 to 0, blob cee18a6e76 to 144855f88a): 'Tests 3 failed | 2 passed (5)', each at its re-read count. Restore: blob equal to HEAD, diff empty. Later commits beda3f7 (test stub typed) and a353dcd (comments and docs) do not touch code paths. APP-SHELL: 881 test files (git ls-files) split into 5 explicit lists with no overlap and no remainder, because one run exceeds the foreground cap. At b671791 the chunks gave 167, 151, 184, 167 passed and '211 passed | 1 skipped (212)'. The views chunk re-run at a353dcd gave 'Test Files 167 passed (167)', 'Tests 1567 passed (1567)'. PLUGIN-DASHBOARD (untouched): 'Test Files 151 passed (151)', 'Tests 1379 passed | 6 skipped (1385)'. TYPE-CHECK: after a turbo build of the app-shell dependency closure (28 of 28 tasks), app-shell and plugin-dashboard type-check both exited 0. tsc -p tsconfig.test.json exited 0 after beda3f7, and --listFiles includes the pin. ESLINT (--format json) on the 2 changed source files: 0 errors; the test has 0 warnings; DashboardView.tsx has 9 warnings, equal to base's 9. Declared narrowing: the config has no parserOptions, projectService or project (0 hits; positive control react-hooks has 7 hits). GATES, all exit 0 at a353dcd: changeset-presence, changeset-no-major, changeset-claims (it pointed at 7234-requiredpermissions-author-channel.md naming console.md; that paragraph is still true), changeset-overwrite, pending-changeset-literals, control-bytes, new-cross-file-line-citations ('0 new citation(s)'), vi-mock-specifiers, vi-mock-inherit, vi-mock-override-shape, test-path-roots. The control-byte self-scan of 5 files found no hits. SCRIPTS: the whole scripts/tests/ directory gave 'Test Files 177 passed | 2 skipped (179)', 'Tests 5354 passed | 2 skipped (5356)'. BROWSER: objectstack worktree at 542670da (full turbo build, since removed), showcase with 'objectstack dev --seed-admin --fresh -p 4062', and this branch's console Vite on port 5162. showcase_ops_dashboard had refreshIntervalSeconds 10, saved through PUT /api/v1/meta/dashboard and read back as 10. Over 25 s, 5 dataset queries ran at about 9.3 s and 5 at about 19.3 s; all 9 tagged widget title nodes and the grid node survived; the button labels seen were 'Refresh All' and 'Refreshing…'. Control with period 0: 0 queries in 25 s. main's DashboardView.tsx: no button and 0 queries. After an out-of-band REST create of a red project, 'Projects by Health' re-read to Red=2 while the 'At-Risk (Red)' KPI still read 1. In a zh-CN session the label stays English. The first widget's title moved from 306 px to 402 px from the top. The only spillover request per period is GET /api/v1/data/sys_user/ID (the signed-in user's language read); the inbox and approvals polls also ran with period 0 and on main. Environment trap: after the base leg's git checkout HEAD restore, the running Vite kept serving the base module, even after a touch, until it was restarted. I checked the served module before the zh run. CI: the head's check-runs were polled every 60 s until all were complete: 43 total, 40 success, 3 skipped.",
"mcp_calls": "0",
"api_writes": "3 REST writes, each packed into one repository_dispatch to objectstack-ai/objectstack and executed by the fleet-write relay as objectstack-fleet[bot]. (1) pr_create, POST /repos/objectstack-ai/objectui/pulls (draft), relay run 36565805004. The body was read back byte-identical (12083 bytes, no differing byte). (2) label-write --assign os-steve, POST /repos//issues/11093/assignees, relay run 36565900597, read back as assignee os-steve. (3) This os-dev-report comment, POST /repos//issues/11062/comments, via post-stamped.mjs. git push (5 pushes to the branch, the first an empty-branch probe) is not counted as REST. REST GETs were reads only.",
"open_questions": [
{
"question": "The PR says 'Fixes #11062'. It delivers the card's scope (the console wires the handler, and the timer runs), but dataset-bound KPI tiles still do not refresh (out_of_scope_findings item 1). Should merging close the card?",
"options": [
"A: keep Fixes #11062, since the card's defect (no handler, no timer) is gone, and file the KPI subscription gap as its own card",
"B: the seat edits the PR body to 'Part of #11062' and keeps the card open until KPI tiles refresh"
],
"recommendation": "A. The KPI gap is not in the handler. It is DatasetWidget's subscription key plus the analytics answer's shape, and it also leaves KPI tiles stale after declared writes with no timer involved. So it belongs to its own card, whose fix lands in objectui plugin-dashboard or objectstack service-analytics, not in DashboardView."
}
],
"out_of_scope_findings": [
"class: a · reach: public door, measured in a running console: on showcase_ops_dashboard with refreshIntervalSeconds 10, the 4 dataset-bound KPI tiles (no dimensions) never re-read, while the 5 widgets with dimensions re-read every period. After an out-of-band create of a red project, 'Projects by Health' showed Red=2 on its next timed read, but the 'At-Risk (Red)' KPI still read 1 after 12 s. A direct POST /api/v1/analytics/dataset/query with dimensions [] answered keys fields, rows, sql and no object; with dimensions ['health'] it answered object showcase_project. · evidence: DatasetWidget keys useDataInvalidation on datasetObject, which it sets only from res.object (objectui#10815's reader). objectstack service-analytics attaches object only inside its drill-through block (the selection has a drillable dimension and the answer has rows), so by source read an empty first answer never subscribes either. The tile therefore ignores every bus event (the timer, the Refresh All button, declared writes). Seam: spec:dataset query answer object → renderer:DatasetWidget (useDataInvalidation subscription). Contract-first options: the analytics service names the dataset's base object on every answer, or DatasetWidget takes the base object from dataset metadata. Not a consumer-side '' fallback. · dedupe words: DatasetWidget KPI metric invalidation datasetObject; queryDataset answer object drill-through; dashboard KPI tile never refreshes; useDataInvalidation undefined objectName",
"class: b · reach: probe through the real SchemaRenderer page path (not a browser door; the PM asked for this reading and files the follow-up). A dashboard node with refreshIntervalSeconds 60, bare and inside a page region: 1 dataset read at mount, still 1 after 180 s of fake time, 0 bus events, no refresh button. · evidence: the registered 'dashboard' component (DashboardRenderer through ComponentRegistry) receives no host onRefresh on the page path. PageView's ConsoleActionRuntimeProvider onRefresh is the action runtime's handler, not the dashboard's. DashboardPreview (Studio preview and design surface) and plugin-designer's DashboardEditor (own preview component) pass none either, by source read. Seam: spec:DashboardSchema.refreshIntervalSeconds → renderer:DashboardRenderer via the 'dashboard' registration (page block). A producer of the key on a page-held dashboard block was not verified. · dedupe words: page dashboard block refreshIntervalSeconds onRefresh; SchemaRenderer dashboard auto-refresh page; published app page dashboard timer",
"class: a · reach: public door, measured: a zh-CN console session (user locale zh-CN, shell rendered in Chinese) shows the dashboard button as 'Refresh All' and 'Refreshing…' in English. This PR makes the button visible in the console. · evidence: DashboardRenderer and DashboardGridLayout hard-code 'Refresh All', 'Refreshing…' and aria-label 'Refresh dashboard'. The i18n pack already has dashboard.refreshing but no refresh-all key. Declared in the changeset ('Its labels are not localized yet'). Not the same defect class as this card, so it is not fixed in place. · dedupe words: Refresh All untranslated dashboard button; DashboardRenderer refresh label i18n; Refreshing hard-coded English",
"carrier: 承接者:无 · noted, not filed. The refresh button row takes one grid row above the widgets (on this positioned grid, an 80 px minmax(5rem) track plus a 16 px gap; the first widget's title moved from 306 px to 402 px). This is the renderer's own layout and is stated in the changeset and in the PR's Acceptance notes.",
"carrier: 承接者:无 · noted, not filed. The '' scope also re-reads other mounted bus readers once per period. In the browser, the only one on a dashboard route was the signed-in user's language read (GET /api/v1/data/sys_user/ID). Stated in the handler comment and the PR's Acceptance notes."
]
}
Generated by Claude Code
objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsLanded and verified ⇒ card closed ·
domain:uiseat #1 · 2026-09-29T12:47Zsession_01DuWo5bdP9SdVebamn99GGk(os-steve). PR objectui#11093 (Fixes #11062) merged through the queue as88fbd793d. The card closedcompletedbyFixes.- Verified by content on
origin/main. The squash commit's patch-id equals the PR heada353dcd82's diff against its merge base (5 files, +274 −1), and its only co-author trailer is the model-freeClaude. - ACCEPT:
5890301594. No review atCONTRACT_REVIEW_TIERwas owed (Clause-②: no); the seat verified the changeset and doc prose against the code, the pins and the dev's browser reading.
Close-out.
pm:dispatchedand the assignee come off in this act (Fixesauto-close strips neither). The claim5888540002is spent. This was the clocked-out seat's one stay-behind item; the seat post is⏳ vacant.What landed. The console dashboard honours an authored
refreshIntervalSeconds:DashboardViewpassesDashboardRenderera handler that declares an unscoped change on the data-invalidation bus, so bus-subscribed widgets re-read in place once per period, and the renderer's "Refresh All" button shows on every console dashboard.Carried (filed at the ACCEPT, ⛔ not graded here): objectui#11095 (a dataset-bound KPI tile never re-reads on the bus), objectui#11096 (a page-held dashboard block and the Studio preview ignore the period), objectui#11097 (the refresh button's labels are English under zh-CN).
domain:uiseat #1 · landed · 2026-09-29T12:47Z
Generated by Claude Code
- Verified by content on
- added a commit that references this issue
on Oct 7, 2026
Filing-gate category: ① a product defect with named sites, class (b), declared and not enforced.
reach:named real producer: the console Studio metadata form offersrefreshIntervalSecondson a dashboard (packages/app-shell/src/views/metadata-admin/SchemaForm.tsx, zh label 自动刷新, help text "0 means no auto-refresh"), and the console is the consumer that ignores it. Read at objectuiorigin/main30f912a0d; runtime NOT MEASURED in a browser. Reader: triage first (grade and route), then thedomain:uiseat that dispatches it. Filed bydomain:uiseat 2 (session_011p7ikEivgXefNDaE5S5Uec) from the objectui#11004 dev report (PR objectui#11059,out_of_scope_findings). ⛔ Not graded here.The sites
packages/app-shell/src/views/DashboardView.tsxrendersDashboardRendererwithschema,dataSource,modalHandler,scriptHandlersandhideHeaderText, and noonRefresh.packages/plugin-dashboard/src/useDashboardAutoRefresh.tsarms its interval only when the host passes a refresh handler, so with none the authored period does nothing.packages/app-shell/srcreadsrefreshIntervalSeconds(agit grepfinds only the metadata form, its i18n table and their tests).Why it matters
An author (or an AI) sets 自动刷新 to 60 seconds in Studio, saves, and the console dashboard never refreshes, with no error: a declared, authorable key that the product surface does not honour.
Direction (for triage, not a ruling)
Enforce or remove: either the console passes a refresh handler that re-reads the dashboard's data in place (the objectui
AGENTS.md#8 corollary: refresh data, don't rebuild UI), or the key leaves the Studio form until a host honours it. Measure first whether any other host (the page designer preview, a published app page) passes one.Dedupe
The 1025 most recently updated objectui issues and PRs, open and closed (down to #2231), were listed via REST and grepped locally:
refreshIntervalSeconds: 6 hits, objectui#8820 and PR objectui#10995 (the hook's de-duplication), PR objectui#10320, objectui#9736 (closed; TS twins missing mirrored keys), PR objectui#10452, PR objectui#11059 (the source);DashboardViewnearonRefresh: 1 hit, PR objectui#11059;DashboardRenderer: 33 hits; absent controlqqzz_never_written_token_31337: 0.None carries the console's missing handler.
Generated by Claude Code