Skip to content

fix(platform-objects): make two System Overview tiles count what their labels say - #7614

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-7531-system-overview-tile-labels
Aug 11, 2026
Merged

fix(platform-objects): make two System Overview tiles count what their labels say#7614
os-zhuang merged 1 commit into
mainfrom
claude/issue-7531-system-overview-tile-labels

Conversation

@claude

@claude claude Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Fixes #7531

Two tiles on the shipped System Overview board reported a different quantity from the one on the card. Both premises the dispatch hung its rulings on were checked against origin/main before implementing, and both hold — so both rulings are implemented as ruled, and neither tile was relabelled.

Tile 1 — "Total Users" was a 7-day count

The board declares one dashboard-level filter, created_at defaulting to last_7_days, and a dashboard-level filter is broadcast into every widget's analytics query (#2501). sys_user.created_at exists, so the broadcast landed on it and the tile reported "users created in the last 7 days" under a label that says "Total".

Premise checked — is the date bar reaching this tile fan-out, or intent? Fan-out. The board is mixed, and the source says so in three places: the header comment splits it into "Platform KPIs" (row 1) and audit rows (2-4); every row-1 tile is labelled as a stock, not a flow ("Total Users", "Total organizations on the platform", "Number of currently active user sessions"); and the row-3 comment introduces globalFilters specifically as "the supported way to scope these widgets", meaning the sys_audit_log distribution charts. So this is not a 7-day activity board whose labels are wrong — it is an inventory row that inherited an activity filter.

Fix: filterBindings: { created_at: false } on widget_total_users. That key is live and does what it says — objectui dashboard-filters.ts resolveBoundField honours false as an opt-out (packages/spec/liveness/dashboard.json, verified 2026-08-03).

Tile 2 — "Active Sessions" counted every session

sys_session_metrics is a bare count over sys_session and the widget carried no predicate, so a signed-out or long-expired session was still reported as active.

Premise checked — can sys_session express "active"? Yes, exactly. ADR-0069 D4 gives it revoked_at (set when a session is revoked by idle / absolute-max / concurrent-cap / admin) alongside the required expires_at. A session is live while it has not been revoked and has not yet expired:

filter: { revoked_at: null, expires_at: { $gt: '{now}' } },

{now} is a declared date macro resolved per request by resolveFilterTokens, which service-analytics' dataset-executor applies to a widget's filter (its runtimeFilter) — so this is a live predicate, not the unsubstituted NOW() - INTERVAL shape the row-3 comment warns about. Verified end to end before writing it: the token resolves to a full ISO timestamp and the predicate keeps exactly the unrevoked, unexpired rows.

This tile also opts out of the date bar. That is not scope creep, it is what the ruling means: "currently active" is a statement about now rather than about a window, so an old session that is still live must still count. Left in, the tile would have reported "sessions created in the last 7 days that are active" — neither the old number nor the labelled one.

The date bar still does its job

All six sys_audit_log widgets (rows 2-4) still inherit it, and the test asserts that explicitly. No labels changed, so no translation key moves — pnpm check:i18n is green and reports all 8 platform-objects bundles in sync.

The pin asserts agreement, not a snapshot

system-overview-tile-semantics.test.ts, 8 cases. A test that freezes today's numbers goes green again the day the label drifts back, so what is pinned is the property: the question a label asks and the question the effective query answers are the same question. Every claim carries its opposite direction in the same block, because each has a way to pass vacuously:

claim how it could pass vacuously the opposite direction that closes it
the total is invariant across windows the harness never applies a window an audit tile on the same board must move across the same two windows
the total is invariant across windows no fixture row sits outside the window the same tile computed without its opt-out reports strictly fewer
sessions equals the active-only count the predicate matched everything the expired and the revoked row must be dropped, count 2 of 4
sessions equals the active-only count the window happened not to bite an old-but-live session is kept, and would be dropped if windowed

The active-only count the tile is compared against is derived from the fixture directly, never from the widget's own filter — deriving it from the filter would make the comparison a tautology. Fixtures deliberately straddle the 7-day window, because a fixture where every row is recent makes every assertion in the file pass for free, which is the exact trap the card describes.

Only the composition of the dashboard filter into the widget query is modelled locally, because that step lives in objectui and no code in this repo performs it; the test states the precedence the filterBindings contract declares, the same rule @objectstack/lint's effectiveFilterField mirrors. Everything downstream is the real machinery — resolveFilterTokens and matchesFilterCondition, added as devDependencies — so a {now} that stopped resolving, or a $gt that stopped meaning $gt, fails here.

Reverse verification, direction predicted before running: red. Reverting the board file with the test in place turns 4 of the 8 cases red, naming the defect rather than a shape:

× reports the same users under any date-range window, and with none
  → window=7: expected [ 'u_this_week' ] to deeply equal [ Array(3) ]
× matches an independently-computed active-only count, under any window
  → window=7: expected [ Array(3) ] to deeply equal [ 's_active', 's_old_active' ]
× the predicate drops the expired and the revoked row
  → expected [ … ] to have a length of 2 but got 4

The four that stay green are the ones that describe the pre-fix board on purpose (the ignoreOptOut legs and the audit control), which is the expected direction for them.

Verification

command result
pnpm --filter @objectstack/platform-objects test 13 files, 304 passed (8 new)
pnpm --filter @objectstack/platform-objects typecheck clean
pnpm --filter '@objectstack/platform-objects^...' build built first, per the stale-dist rule
pnpm exec eslint packages/platform-objects/src/apps/dashboards 0 problems
node scripts/check-nul-bytes.mjs OK, 7047 files
pnpm check:i18n OK, 9 packages in sync
pnpm check:empty-changeset, pnpm check:adr-0087-registration both exit 0
validateWidgetBindings over the real board no errors from this change

pnpm check:i18n-coverage could not run in this worktree — @objectstack/connector-mcp has no build output, so 1 of 12 configs failed to lint and the gate refuses to judge a partial round. Environmental, unrelated to this diff; it needs a full pnpm build, and CI does one.

Out of scope, filed

setup-nav.contributions.ts was not touched, per the #7544 serialization constraint.


Generated by Claude Code

…r labels say (#7531)

"Total Users" reported users created in the last 7 days: the board's
`created_at` global filter is broadcast into every widget's analytics query
(#2501) and `sys_user.created_at` exists, so the broadcast landed on a tile
labelled "Total". "Active Sessions" counted every `sys_session` row, because
the dataset is a bare count and the widget carried no predicate at all.

Both are label/query disagreements on a shipped platform board, and both
numbers were genuinely live — the query was answering a different question
from the label.

- `widget_total_users` opts out of the date bar with
  `filterBindings: { created_at: false }`.
- `widget_active_sessions` filters `{ revoked_at: null, expires_at: { $gt:
  '{now}' } }` — the active predicate `sys_session` can actually express
  (ADR-0069 D4) — and opts out of the date bar too, because "currently
  active" is a statement about now rather than about a window.

The date bar still reaches all six `sys_audit_log` widgets, which is what it
was added for. No labels changed, so no translation key moves.

The pin asserts label/query agreement rather than a snapshot: a total that is
invariant across four windows, a sessions count equal to an independently
computed active-only count, and an opposite direction for each so neither can
hold vacuously.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XWfHvFJPt37LcT7SoF2dJ
@vercel

vercel Bot commented Aug 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 11, 2026 8:33am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/platform-objects.

2 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/plugins/packages.mdx (via @objectstack/platform-objects)
  • content/docs/ui/setup-app.mdx (via @objectstack/platform-objects)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file tests tooling labels Aug 11, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 11, 2026 09:07
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit 8c20f75 Aug 11, 2026
27 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-7531-system-overview-tile-labels branch August 11, 2026 09:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

System Overview board mislabels two tiles: "Total Users" is really users created in the last 7 days, and "Active Sessions" counts every session

1 participant