Skip to content

dashboard auto-refresh: one timer instead of two byte-identical copies, and a test that observes it FIRING — the two pieces the 17.4.0 rename does not carry #8820

Description

@os-steve

⚠️ Re-scoped 2026-09-09 by the epic PM who filed it (session_01DuzfS5chho38Yx1jxx9DEj). The rename itself is NOT this card's — it is #7783's, and it is implemented in open draft PR #8783. What this card was originally asking for has been deleted from it. See the re-scope comment for the full record of the mistake.

Blocked-by: #8783 (chore(deps): take the 17.4.0 @objectstack/* line). ⛔ Do not start before that floor lands.

Why this card still exists after the duplicate was found

#8783 renames the key everywhere it is declared and read. Two things it does not do, both of them squarely this repo's own quality question rather than the rename's:

  1. Nothing observes the timer firing. The dashboard tests chore(deps): take the 17.4.0 @objectstack/* line #8783 touches — dashboardAuthoredInputs, ConfigPanel.i18nWiring, dashboard-config, page-app-dashboard-spec-parity — are declaration pins to a schema. Every one of them stays green if the interval never fires. That is exactly the class of gate the 2026-08-31 ruling is about: a test that goes green while the feature is dead.
  2. The timer exists twice, byte-identical. packages/plugin-dashboard/src/DashboardGridLayout.tsx:147-152 and DashboardRenderer.tsx:450-455 carry the same if (!schema.<key> || <= 0 || !onRefresh) return; setInterval(handleRefresh, <key> * 1000). Two copies means the rename — and every future change to the refresh contract — has to be made twice and can drift once.

Prior art on the branch — read it before you write anything

Branch claude/issue-8820-dashboard-refresh-interval-seconds, commit e5d95e1a, pushed, no PR (it would have fought #8783 for six files). It already contains a working version of both pieces:

  • the two timers collapsed into one useDashboardAutoRefresh hook;
  • a 16-case pin that mounts both components and asserts onRefresh call counts under fake timers — including the 0 trap case (0 is a configured value, not "unset");
  • ablation-proven: removing the new key from the reader's key list turns 6 of 16 red, including the case on both surfaces; restore verified by blob hash back to 37fb2b61, tree clean.

One thing on that branch must be dropped when you rebase: it reads both spellings by presence, as a pre-bump compatibility shim. Once #8783's floor lands the old key is a tombstone that refuses at parse, so the fallback becomes unreachable code. Keep the hook and the pin; delete the both-spelling read.

Acceptance

  • One timer implementation, used by both surfaces; ⛔ no behaviour change beyond de-duplication.
  • A test that fails when the interval does not fire — assert call counts under fake timers, ⛔ not the presence of a prop.
  • Rebased onto chore(deps): take the 17.4.0 @objectstack/* line #8783's floor, reading only refreshIntervalSeconds.
  • Prove the pin is load-bearing: ablate the reader, show the specific cases go red, restore, show the tree clean.
  • The repo's verify slice green.

⛔ Not in this card

Refs: #7783 (the rename, the duplicate this card was) · #8783 (its implementation, the floor) · hotcrm#1579 (the epic that filed this).

Activity

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions