Skip to content

πŸ› dashboard: cap histories, dedupe intervals, cancel animations to stop tab memory growth - #10568

Merged
clubanderson merged 3 commits into
v5from
fix/dashboard-memory-10557
Oct 5, 2026
Merged

clubanderson merged 3 commits into
v5from
fix/dashboard-memory-10557

Conversation

@clubanderson

@clubanderson clubanderson commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

Closes #10557

Summary

  • capped client-side history/log arrays with shared ring-buffer helpers (360 live samples, 10k server-history samples, 500 log/prompt lines)
  • made recurring dashboard pollers idempotent through a keyed interval registry so deferred init/re-entry cannot stack timers
  • cancelled stale sparkline/KPI animation work before re-render and kept only one live EventSource/reconnect path
  • added an index.html guard test for unguarded intervals and uncapped histories

Measurement

Harness: local fixture-backed static dashboard served from src/pkg/dashboard/static/index.html, headless Chrome via puppeteer-core in ~/hc-wt-mem/.scratch, timers accelerated to 500ms after warmup; each row is an accelerated minute sample with forced GC and CDP heap usage. Heap snapshots scanned for Detached, HTML*Element, SVG*Element, and Array constructor strings.

run t0 heap t10 heap t20 heap t0 nodes t20 nodes detached start β†’ end constructor scan
before 3,920,488 4,177,012 4,306,508 8,057 8,058 5 β†’ 5 HTML 135β†’136, SVG 94β†’94, Array 203β†’203
after 3,908,064 4,097,176 4,237,532 6,856 6,856 5 β†’ 5 HTML 135β†’136, SVG 97β†’97, Array 202β†’202

The after run stayed within +8.4% heap growth over the accelerated t0β†’t20 window, with stable detached-node and DOM counts.

Static audit

  • Found 35 setInterval( sites at baseline. Recurring dashboard pollers now route through dashboardSetInterval; modal/countdown/carousel/auth-flow timers remain locally cleared/whitelisted with reasons in the guard test.
  • Found history/log accumulators for sparkline history, fact/cost/trend/overview history, audit entries, pane logs, prompt history, and chat transcript/context/command history. Each is now capped directly or covered by an existing named cap.
  • Sparkline draw-on and overview KPI RAF paths now cancel stale work on re-render/disconnect; EventSource reconnect now closes the previous source and dedupes the reconnect timer.

Validation

  • gofmt -l src/pkg/dashboard/dashboard_memory_guard_test.go
  • static sanity script over index.html/guard snippets
  • before/after puppeteer memory harness as above

Per AGENTS.md I did not run go test, go vet, or local go build; CI is the test verdict.

@kubestellar-prow

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign hanthor for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubestellar-prow kubestellar-prow Bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label Oct 5, 2026
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Changelog: this PR changes code but carries no changelog entry
(no changelog.d/ fragment and no CHANGELOG.md edit).

If it is user-visible β€” a feature, a fix an operator would notice, a
security change, a migration, a deprecation, or anything breaking β€”
please add a fragment file changelog.d/<category>-<pr-or-slug>.md
containing exactly your entry (see changelog.d/README.md; the
category is one of added/changed/deprecated/fixed/security). Please
do not append to CHANGELOG.md's ## Unreleased directly β€” that
shared section is the merge-conflict generator fragments replaced
(#5675). If it is a refactor, a test-only change, or dependency
churn, no entry is needed and you can ignore this.

This is a reminder, not a gate; it never blocks a merge.

@kubestellar-prow kubestellar-prow Bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Oct 5, 2026
@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Open PR overlap check

Base branch: v5

Conflicts are checked with every PR merged onto the current tip of v5, so a PR that only needs a rebase is not reported as conflicting with its siblings.

No conflicting open PRs or same-file overlaps were found.

clubanderson added a commit that referenced this pull request Oct 5, 2026
Generated by changelog-fragment-guard from the PR title (#5675).
Edit the wording freely, or replace this file with the no-changelog
label if the change is not user-visible.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: clubanderson <407614+clubanderson@users.noreply.github.com>
@clubanderson
clubanderson force-pushed the fix/dashboard-memory-10557 branch from dc61453 to 4c7ea85 Compare October 5, 2026 14:09
@github-actions github-actions Bot added the conflicts-with-open-pr Open PR has a merge conflict with another open PR label Oct 5, 2026
clubanderson added a commit that referenced this pull request Oct 5, 2026
Generated by changelog-fragment-guard from the PR title (#5675).
Edit the wording freely, or replace this file with the no-changelog
label if the change is not user-visible.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: clubanderson <407614+clubanderson@users.noreply.github.com>
@github-actions github-actions Bot removed the conflicts-with-open-pr Open PR has a merge conflict with another open PR label Oct 5, 2026
@clubanderson
clubanderson force-pushed the fix/dashboard-memory-10557 branch from 42e2f0e to 646c51f Compare October 5, 2026 14:23
clubanderson added a commit that referenced this pull request Oct 5, 2026
Generated by changelog-fragment-guard from the PR title (#5675).
Edit the wording freely, or replace this file with the no-changelog
label if the change is not user-visible.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: clubanderson <407614+clubanderson@users.noreply.github.com>
@clubanderson
clubanderson force-pushed the fix/dashboard-memory-10557 branch from c47e3a1 to 7dec7dd Compare October 5, 2026 14:33
clubanderson added a commit that referenced this pull request Oct 5, 2026
Generated by changelog-fragment-guard from the PR title (#5675).
Edit the wording freely, or replace this file with the no-changelog
label if the change is not user-visible.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: clubanderson <407614+clubanderson@users.noreply.github.com>
@clubanderson
clubanderson force-pushed the fix/dashboard-memory-10557 branch from e8d4f0b to 37d43b3 Compare October 5, 2026 14:42
clubanderson added a commit that referenced this pull request Oct 5, 2026
Generated by changelog-fragment-guard from the PR title (#5675).
Edit the wording freely, or replace this file with the no-changelog
label if the change is not user-visible.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: clubanderson <407614+clubanderson@users.noreply.github.com>
Signed-off-by: Andy Anderson <andy@clubanderson.com>
@clubanderson
clubanderson force-pushed the fix/dashboard-memory-10557 branch from f2c2ced to 901f094 Compare October 5, 2026 14:50
Generated by changelog-fragment-guard from the PR title (#5675).
Edit the wording freely, or replace this file with the no-changelog
label if the change is not user-visible.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: clubanderson <407614+clubanderson@users.noreply.github.com>

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One verified behaviour change that the body does not mention; everything else I traced looks correct.

Repo/governor trend sparklines shrink from ~7 days to ~30 hours. src/pkg/dashboard/static/index.html (PR head):

  • :7669-7671 sets SPARKLINE_MAX_POINTS = 360 and aliases CLIENT_HISTORY_MAX_SAMPLES to it. The constant it replaces was 2016, with the deleted comment stating the reason: "one week at the server's 5-min trend resolution".
  • mergeTrendHistory (:8057-8099) folds /api/trend/history into historyData and then caps it at DASHBOARD_HISTORY_CAP (:8096). The server keeps up to trendHistoryMaxEntries = 8640 five-minute samples (src/pkg/dashboard/server.go:1086-1088), so after the merge only the newest 360 survive β‰ˆ 30 hours.
  • Those are the points the repository-card and governor sparklines draw: sparkSvg(historyData.map(s => s.repos?.[r.name]?.issues …)) at :13225-13226, and the agentStats/token sparklines at :8790, :15132, :15198 read the same array.

Consequence: a tab that previously showed a week of issue/PR trend on each project card now shows a little over a day, and the persisted hive_sparkline_history in localStorage is truncated to 360 on the next persistSparklineHistory() (:7704), so the older points are gone for good on that browser. The memory saved is ~1.6k small objects per tab, which the "before" measurement in the body (4.3 MB heap at t20) suggests was not the growth source. If the shorter window is intended, it deserves a line in the changelog fragment; if not, keeping CLIENT_HISTORY_MAX_SAMPLES at 2016 (or decoupling it from SPARKLINE_MAX_POINTS) preserves the range while the rest of the PR still lands.

Minor, no action needed: :8097 capHistory(historyData) is a no-op now that capHistory returns a copy instead of splicing — the assignment on :8096 already did the work. All other capHistory callers (:7700, :7704, :8682) assign the return value, so the splice→slice change is safe.

Checked and fine: dashboardSetInterval clears before re-arming; cancelSparklineWork cancels both the stagger Set and the per-wrapper cleanup timers before innerHTML replacement; the KPI RAF path cancels the prior frame per node and bails on disconnected nodes.

β€” hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88

@clubanderson
clubanderson merged commit c60b0a3 into v5 Oct 5, 2026
103 of 107 checks passed
@kubestellar-prow
kubestellar-prow Bot deleted the fix/dashboard-memory-10557 branch October 5, 2026 15:09
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Thank you for your contribution! Your PR has been merged.

We'd love to hear how your experience was: share feedback

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Shared CI incident: the coverage check fails here with github: 88.9% (floor 89%) although this PR does not touch pkg/github β€” the v5 baseline dropped below the floor when #10586 merged red. Tracked in #10592; deferring this PR until the baseline fix lands, then re-run. No PR-local change needed.


🐝 Hive Agent: scanner | Instance: hosted-available-oke-11-placeholder-r05x | SHA: 42ceebb68

β€” hive: agent=scanner backend=copilot model=claude-fable-5.1 copilot=1.0.88

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

Labels

dco-signoff: yes Indicates the PR's author has signed the DCO. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

πŸ› dashboard: tab memory grows until Safari force-reloads it ("using significant memory")

1 participant