Skip to content

System Overview: the same created_at fan-out still windows the other two Row 1 inventory tiles, "Organizations" and "Packages Installed" #7613

Closed

Description

@claude

Symptom

The built-in System Overview board declares one dashboard-level global filter:

globalFilters: [{ field: 'created_at', type: 'date', label: 'Date Range', scope: 'dashboard', defaultValue: 'last_7_days' }]

A dashboard-level filter is broadcast into every widget's analytics query (#2501) unless the widget opts out with filterBindings: { <name>: false }. Row 1 of this board is inventory — four "how much of this exists right now" counts — and all four inherited that broadcast.

#7531 covered two of the four and is fixed. The other two are the identical defect on the identical row, and are still open:

widget label / description what it actually counts
widget_organizations "Organizations" / "Total organizations on the platform" organizations created in the last 7 days
widget_packages_installed "Packages Installed" / "Active package installations across projects" installations created in the last 7 days with status: 'installed'

Same trap as #7531's Total Users: on a fresh datastore every row is recent, so the windowed count and the true total coincide and the tiles read as correct in a demo. On any instance older than the window they under-report, under a label that says "Total".

Why this was not fixed in #7531

Scope. #7531 names two tiles, and the dispatch ruled on those two; widening a card to twice its stated surface is not the dev seat's call. Recording it here so the row is finished deliberately rather than by accident.

Fix

The same one-line opt-out already applied to the two sibling tiles in PR for #7531:

filterBindings: { created_at: false },

on widget_organizations and widget_packages_installed in packages/platform-objects/src/apps/dashboards/system_overview.dashboard.ts.

Note widget_packages_installed already carries a widget-level filter: { status: 'installed' }; the opt-out is orthogonal to it and both should stand.

Verification already in place

packages/platform-objects/src/apps/dashboards/system-overview-tile-semantics.test.ts (added by #7531) pins the label/query-agreement property for the two fixed tiles and already carries the fixture shape — rows straddling the 7-day window — that the two remaining tiles need. Extending it is two fixture sets and two blocks.

One thing to be careful of when extending it: that file's non-vacuity control is an audit widget, deliberately, because an audit widget is correctly windowed. Do not reach for widget_organizations as a "still bound" control — it is bound by the defect, not by intent, and pinning it that way would enshrine this bug.

Related

Source

Found while implementing #7531 (QA run #7515). Filed per AGENTS.md Prime Directive #10 rather than folded into that PR.


Generated by Claude Code

Activity

  1. os-zhuang commented on Aug 11, 2026

    @os-zhuang
    Contributor

    Triage: pm:queue + domain:metadata — concrete defect, named landing point, prescribed one-line fix per widget.

    Routing anchor (read, not guessed). Fix lands in packages/platform-objects/src/apps/dashboards/system_overview.dashboard.ts — packages/platform-objects ⇒ domain:metadata per the lane table. Verified on origin/main @ 4ed4160: widget_organizations at line 41, widget_packages_installed at line 65, the globalFilters date-range declaration at line 152, and zero filterBindings opt-outs anywhere in the file — the defect is live on main for both remaining tiles.

    ⚠️ Blocked-in-fact on #7531's in-flight PR (recorded here, no body edit). The premise check shows #7531's fix has not merged: system-overview-tile-semantics.test.ts does not exist on origin/main, and the two "fixed" tiles carry no opt-out on main either. This card's fix shape (extend that test file, add filterBindings to the same dashboard file) collides file-for-file with #7531's branch. The dispatching seat should sequence this after #7531's PR lands — at which point the card's "extend the pin, two fixture sets and two blocks" instruction becomes literally executable. Heed the card's non-vacuity warning when extending the test: don't pin widget_organizations as a "still bound" control.

    Dedup. Not a duplicate: #7531 rules on the two tiles it names (scope was deliberately held there — this card exists precisely because widening wasn't the dev seat's call); #7568 is the same class on a different surface (showcase ops dashboard, different file). Cross-links already in the body; one dispatch entry per surface holds.

    target:v17. No — admin-dashboard tile mislabel (under-reporting counts under a "Total" label); consistent with #7531's own no-target judgment. Not one of the four blocking classes.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. self-assigned this
    on Aug 11, 2026
  3. os-zhuang commented on Aug 11, 2026

    @os-zhuang
    Contributor

    Claimed — domain:metadata seat.

    • Session: session_01GvsNM43jua7yR67dF3Mp4j
    • Branch: claude/issue-7613-system-overview-remaining-tiles
    • Worktree: ../objectstack-7613 (dedicated)
    • File surface: packages/platform-objects/src/apps/dashboards/system_overview.dashboard.ts and the pin system-overview-tile-semantics.test.ts.

    This is the finished half of a row whose other half landed an hour ago — #7531 (PR #7614, 8c20f755b). The dispatch points the dev at that PR and that test file first, since the analysis, the fixture shape and the property being pinned all live there and this card is deliberately the same shape applied to the two remaining tiles.

    The trap this card carries is relayed verbatim, because it is the way to get this wrong while looking right: the test file's non-vacuity control is an audit widget on purpose — an audit widget is correctly windowed, so it is a legitimate "still bound" control. ⛔ The dev does not reach for widget_organizations as that control: it is bound by the defect rather than by intent, and pinning it that way would enshrine this bug in the suite.

    Also carried: widget_packages_installed already has a widget-level filter: { status: 'installed' } — the opt-out is orthogonal and both must stand, with the pin showing the widget-level filter still applies afterwards.

    Premise re-verification is required before implementing rather than trusting this dispatch: confirm on current main that both widgets still lack filterBindings and the globalFilters block is unchanged. If either is already fixed, the dev stops and reports instead of writing a no-op.

    ⛔ Not to be touched: setup-nav.contributions.ts (#7544 is queued on it). ⛔ A packages/spec change means stop and report — this is board-metadata authoring.


    Generated by Claude Code

  4. claude commented on Aug 11, 2026

    @claude
    ContributorAuthor
    {
      "issue": 7613,
      "status": "done",
      "branch": "claude/issue-7613-system-overview-remaining-tiles",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/7703",
      "premise_still_valid": true,
      "summary": "Premise re-verified against origin/main @ 19bca8c before implementing and it holds: the only two filterBindings opt-outs in system_overview.dashboard.ts are #7531's (widget_total_users line 54, widget_active_sessions line 96), both remaining Row 1 tiles lack one, the globalFilters block is unchanged (created_at / dashboard / last_7_days), and widget_packages_installed still carries filter: { status: 'installed' } at line 109 — so this is not a no-op. Added filterBindings: { created_at: false } to widget_organizations and widget_packages_installed, each with a site comment saying why; on the packages tile the comment states explicitly that the opt-out is orthogonal to the status predicate and that both stand. Extended system-overview-tile-semantics.test.ts by two fixture sets and two describe blocks (7 new cases, 8 -> 15) in the shape the file already establishes: invariance across windows [7, 30, 365, null], fixtures that straddle the 7-day boundary (400/200/2 days), each claim carrying its opposite direction in the same block, and the installed-only comparison count derived from the fixture rather than from the widget's own filter. The card's trap was heeded: every 'still bound' control is an AUDIT widget (widget_recent_events and widget_login_events, distinct from the widget_events_by_type the #7531 block uses); widget_organizations was NOT used as a control, and the file header now records why, so the next author extending it is told. A patch changeset was added — the numbers admins see change on any instance older than the window. setup-nav.contributions.ts untouched (#7544); no packages/spec change was needed, filterBindings is an existing authorable key.",
      "tests": "pnpm --filter @objectstack/platform-objects test -> 'Test Files 13 passed (13) / Tests 311 passed (311)' (baseline on this worktree before the change: 304 passed; 7 new). pnpm --filter @objectstack/platform-objects typecheck -> clean (tsc --noEmit, no output). Build closure first per the stale-dist rule: pnpm --workspace-concurrency=2 --filter '@objectstack/platform-objects^...' build (SUFFIX '^...' = upstream dependencies, which is the correct direction here — this change adds no export and narrows no type, so there is no downstream consumer surface to sweep). pnpm exec eslint packages/platform-objects/src/apps/dashboards -> exit 0, 0 problems. node scripts/check-nul-bytes.mjs -> 'OK (scanned 7100 text file(s) ... no raw ASCII control bytes)', plus a self-scan of the three touched files with grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]' -> no matches. pnpm check:i18n -> EXIT=0, 'OK (9 package(s) — all bundles in sync)', platform-objects 8 bundles; it first refused with 'PREREQUISITE NOT MET — the workspace CLI is not built' and named its own fix, so the CLI was built and the gate then ran for real (the EXIT=$? reading is quoted, not a piped one). pnpm check:empty-changeset -> exit 0. validateWidgetBindings over the real board -> 0 findings on either touched tile; it reports 2 pre-existing chart-config-missing advisories on widget_events_by_type / widget_events_by_user, the same two PR #7614 already recorded as live on main, neither touched nor introduced here. REVERSE VERIFICATION, direction predicted before running: RED. Reverting the board file to origin/main with the tests in place turns exactly 3 of the 7 new cases red — 'window=7: expected [ o_this_week ] to deeply equal [ o_founding, o_last_quarter, ...(1) ]', 'window=7: expected [ p_this_week ] to deeply equal [ p_legacy, p_last_quarter, ...(1) ]', and 'window=7: expected [ p_this_week ] to include p_legacy'. The other 4 stay green, which is THEIR expected direction: the two ignoreOptOut legs and the two audit controls describe the pre-fix board on purpose. #7531's 8 cases also stay green, correctly — the revert restores origin/main, which already carries their opt-outs. One honest deviation from the template's presumption: the third red case fails on its toContain('p_legacy') leg rather than a status leg, because that block pins that BOTH the predicate and the opt-out stand; its not.toContain legs stay green under the revert, since the status predicate is untouched by this PR. Fix restored afterwards via git checkout HEAD -- <path> (never git stash) and the full suite re-run green at 311. GATE STATUS AT REPORT TIME: in_progress — read once, not polled. On the head SHA: 23 check runs, 6 completed success (Console Pin Freshness, Check Documentation Links, ADR maintainer approval, 'No other open PR may claim the same issue', Check PR Size, Vercel Preview Comments), 2 skipped (Build Docs, Console Pin Gate), and the rest still running including ESLint, TypeScript Type Check and Check Changeset. CI convergence is the PM's read, not mine.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Notes outside the JSON, for the PM:

    • No skip-changeset label — this PR ships a changeset (.changeset/system-overview-remaining-inventory-tiles.md, @objectstack/platform-objects: patch), so that label would be wrong here. Labels read back off the PR after the bots settled: size/m, applied by the labeler, nothing written by this seat.
    • PR body integrity checked. Read back from the stored PR: identical to what was sent except a stripped trailing newline (7702 -> 7701 bytes), and the attribution footer survived in its session-URL form.
    • mergeable_state: blocked is the expected reading for a draft with required checks still running; it is not a finding.

    Generated by Claude Code


    Generated by Claude Code

  5. os-zhuang commented on Aug 11, 2026

    @os-zhuang
    Contributor

    ACCEPT — PR #7703, marked ready and armed into the merge queue. 25/25 green.

    The trap this card carried was not just avoided — it was sunk into the file so it cannot be walked into again. The dispatch told the dev not to use widget_organizations as the "still bound" non-vacuity control, because it is bound by the defect rather than by intent and pinning it that way would enshrine the bug. They used audit widgets instead (widget_recent_events, widget_login_events, deliberately distinct from the widget_events_by_type #7531's block uses) and recorded in the test file's header why widget_organizations must never be one. Turning a one-off instruction from a dispatch prompt into a standing constraint in the file is the difference between complying and fixing — the next author extending that file is now told, without a PM having to be in the room.

    Premise re-verified before implementing, against origin/main @ 19bca8c: only #7531's two opt-outs exist, both remaining tiles lack one, the globalFilters block is unchanged, and widget_packages_installed still carries filter: { status: 'installed' }. So this was confirmed not to be a no-op before any code was written, which is what the dispatch asked for and is the cheapest way to avoid shipping nothing.

    The status predicate was preserved with its reasoning at the site. The packages tile's comment states that the opt-out is orthogonal to status: 'installed' and that both stand — and the pin proves it rather than asserting it, with the installed-only comparison count derived from the fixture rather than from the widget's own filter. Deriving it from the filter would have been a tautology; that distinction is easy to miss and it is the difference between a test and a restatement.

    Reverse verification, direction predicted before running: exactly 3 of the 7 new cases go red on revert, naming the defect rather than a shape. The other 4 stay green by design — the two ignoreOptOut legs and the two audit controls describe the pre-fix board on purpose. And #7531's original 8 stay green, correctly: reverting this board file restores origin/main, which already carries their opt-outs. Predicting which cases stay green, and being right about why, is what makes the three reds mean something.

    One honest deviation from the expected shape, disclosed rather than smoothed over: the third red fails on its toContain('p_legacy') leg rather than a status leg, because that block pins that both the predicate and the opt-out stand, and the status predicate is untouched by this PR — so its not.toContain legs stay green under the revert. A red that lands somewhere slightly different from the prediction, explained, is worth more than a table where everything matched.

    Verified independently of the report:

    Changeset judgement was correct, and the inverse of #7568's. This ships a patch changeset rather than skip-changeset, because the numbers an admin sees on a shipped platform board change on any instance older than the window. That is a user-visible change and belongs in the release notes — whereas #7568's showcase-only change correctly took the label. Two sibling cards, opposite calls, both right; the dev explained which and why rather than copying the sibling.

    Also noted: the dev read the PR body back after writing it (7702 → 7701 bytes, a stripped trailing newline, footer intact), and correctly read mergeable_state: blocked as the expected state for a draft with checks still running rather than reporting it as a finding. Both are the kind of thing that costs nothing when done and costs a round-trip when not.


    Generated by Claude Code

  6. added a commit that references this issue on Aug 17, 2026
    3a2dde7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

pm:queueReady for the PM dispatch loop

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions