Repository navigation
test(plugin-dashboard): a dimension-less KPI tile re-reads on the data-invalidation bus once its answer names the base object (objectui#11095) - #11635
Merged
objectstack-fleet[bot] merged 4 commits intoOct 5, 2026
Conversation
…a-invalidation bus once its answer names the base object DatasetWidget subscribes useDataInvalidation on the base object the dataset query's answer names. The analytics service now names it on every dataset answer (objectstack-ai/objectstack#20644, AnalyticsResult.object in @objectstack/spec 17.6.0), so a metric widget with no dimensions subscribes. Pin that half: a write to the answer's object re-reads the tile once in place, another object does not, the unscoped '*' change the console's timer and Refresh All declare re-reads it, a zero-row first answer subscribes too, and an answer naming no object subscribes to nothing (no fallback key). Claude-Session: https://claude.ai/code/session_015W8GBu6sBiqus2L2xjMsAL Co-authored-by: Claude <noreply@anthropic.com>
…oducer pin Claude-Session: https://claude.ai/code/session_015W8GBu6sBiqus2L2xjMsAL Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
…tion Claude-Session: https://claude.ai/code/session_015W8GBu6sBiqus2L2xjMsAL Co-authored-by: Claude <noreply@anthropic.com>
…-bound KPI tile re-reads on the bus Every dataset answer names its base object since objectstack-ai/objectstack#20644 (AnalyticsResult.object), so the paragraph that described a dimension-less KPI tile as never re-reading on this handler or on a declared write is false. It now says what holds and points at the widget's pin (DatasetWidget.kpiInvalidation-11095.test.tsx) and the producer's upstream pin. Comment only; the changeset stays empty-frontmatter and says the comment ships in dist JS (objectui#11095, seat comment 5986840462). Claude-Session: https://claude.ai/code/session_015W8GBu6sBiqus2L2xjMsAL Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
objectstack-fleet
Bot
deleted the
claude/issue-11095-kpi-tile-invalidation
branch
October 5, 2026 02:52
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #11095
Clause-②: no
What this is
Triage's ruling on the card (
5890740102) set the unlock work: re-measure the four KPI tiles in a running console against a backend that carries objectstack-ai/objectstack#20644, add aDatasetWidgetpin, and close the card with the measurement if objectui then needs no code change. It needs none. This PR is the pin, an empty-frontmatter changeset and one doc comment, and no executable code changes.packages/plugin-dashboard/src/DatasetWidget.kpiInvalidation-11095.test.tsxhas four cases on the page path: the realSchemaRenderer, this package's own registration, and a bareuseDataInvalidationreader as the positive control. The fake answers the shape the producer returns fordimensions: []:rows,fieldsandobject, with nodimensionFieldsand nodrillRawRows.metrictile with no dimensions once, in place (the same value node). A write to another object does not re-read it.objectName: '*') re-reads it.'*'subscription and no read of the dataset's metadata..changeset/11095-kpi-tile-invalidation-pin.mdhas empty frontmatter: tests and one doc comment, no behaviour change. Its body says the comment ships indistJS. AGENTS.md §9 asks a change with no behaviour, export or type change for a declaration, not a release.packages/app-shell/src/views/DashboardView.tsx: therefreshDashboardDatadoc comment only, added in patch round 1 (seat comment5986840462). Its paragraph said the server names the base object only beside drill-through metadata, so a dataset-bound KPI tile never re-reads on this handler or on a declared write. Closing this card makes that false on the record, and the live re-measure below measured it false on objectstacke83c9f61. The paragraph now says every dataset answer names the object, and points at the pin and the upstream producer pin. The'*'scope paragraph and every other sentence are unchanged.@object-ui/app-shellbuilds withtsc, so the comment ships in the publisheddist/views/DashboardView.js: the published 17.7.0 tarball carries the old sentence once. No.d.tscarries it, because the function is not exported.The producer half is pinned upstream by
service-analytics'sdataset-answer-object.test.ts.Live re-measure
mainate83c9f61, in its own worktree, showcase closure built (turbo, 60/60 tasks), run withobjectstack dev --seed-admin --freshon a temporary database.apps/consoledev server, proxied to that backend./apps/showcase_app/dashboard/showcase_ops_dashboard, logging everyPOST /api/v1/analytics/dataset/querywith theobjectits answer named.The wire (curl,
datasetName: showcase_project_metricsunless noted):objectdimensions: [], filterhealth: redshowcase_projectdimensions: [], a filter matching nothing (an ungrouped COUNT answers one row of 0)showcase_projectdimensions: ['health'], a filter matching nothingshowcase_projectdimensions: []onshowcase_task_metricsshowcase_taskThe card's original reading answered no
objectfordimensions: [].The four KPI tiles (Active Projects, At-Risk (Red), Awaiting Review, Total Budget):
object(showcase_projectthree times,showcase_taskonce).showcase_task: 4 queries, the Awaiting Review tile and the three task charts. The three project KPI tiles did not re-read. Awaiting Review went from 2 to 3 after an out-of-band in-review task. The event was emitted through the app's ownnotifyDataChangedmodule as a stand-in for a declared write; this page has no real write path.refreshIntervalSeconds: 10was injected into the served dashboard metadata in the browser only (route interception; the backend was untouched). After an out-of-band red project and about 27 s with no interaction: 2 periods 10 s apart, 9 queries each, including all four KPI tiles. At-Risk went from 2 to 3 after the first period.Ablation: the pin can fail
The script carried its own
EXIT INT TERMtrap. Each mutation went throughablation-replace.mjs(anchor 1 to 0, blob moved), and each restore was proven by blob hash equal toHEADwithgit diff HEADempty. Both runs covered the new file and the objectui#10815 pin.DatasetWidget.tsxdimensionFields'*'fallback key when the answer names no objectThe first row is the gap: the objectui#10815 pin's answers always carry drill metadata, so it could not see a dimension-less tile.
Tests, patch round 1 (at
17d39ad)45f7b2cbrings inorigin/mainat1c2e2c4.main's copy ofDashboardView.tsxand this one, while the bytes differ.pnpm --filter @object-ui/app-shell lintexits 0 (0 errors).DashboardView.tsxalone: 0 errors and 9 warnings, the same 9 asmain's copy of the file (linted through stdin).pnpm --filter @object-ui/app-shell type-checkexits 0, after building its dependency closure (turbo run build --filter=@object-ui/app-shell^..., 28/28). Run through the shared verify lock.pnpm exec vitest runon the new pin and the objectui#10815 pin: 2 files, 9 passed.check:new-line-citations(0 new),check:control-bytes,check:changeset-claims,check:pending-changeset-literals,node scripts/check-changeset-presence.mjs(2 source files in 2 released packages, 1 empty-frontmatter changeset) andnode scripts/check-changeset-no-major.mjs.Tests, round 0 (at
a36c241)pnpm exec vitest run packages/plugin-dashboard/: 169 files passed, 1673 passed, 6 skipped. Run through the shared verify lock.pnpm --filter @object-ui/plugin-dashboard type-checkexits 0, after building the dependency closure (turbo run build --filter=@object-ui/plugin-dashboard^..., 12/12).tsc -p tsconfig.test.json --listFilesincludes the new file once.pnpm --filter @object-ui/plugin-dashboard lintexits 0 (0 errors). The new file itself: 0 errors, 0 warnings.check:new-line-citations(0 new),check:control-bytes,check:test-path-roots,check:vi-mock-specifiers,check:vi-mock-inherit,check:vi-mock-override-shape,check:changeset-claims,check:pending-changeset-literals,check:unreferenced-sources,check:shell-escape-residue, plusnode scripts/check-changeset-presence.mjsandnode scripts/check-changeset-no-major.mjs.origin/mainstill equalled the branch's base9dfaca6, so no merge commit was possible then. Patch round 1 merged1c2e2c4(above).Acceptance notes
ObjectStackAdapter.queryDatasetinpackages/data-objectstackdeclaresobject?: stringlocally, and its doc callsobjectdrill metadata "the REST route adds on top ofAnalyticsResult". Since@objectstack/spec17.6.0,objectis a declaredAnalyticsResultmember. The types agree, so nothing misbehaves; it is a restated contract that could drift. It is not touched here; carrier: none named. The other site, theDashboardView.tsxcomment, is fixed in this PR (patch round 1).Session:
https://claude.ai/code/session_015W8GBu6sBiqus2L2xjMsALGenerated by Claude Code