Skip to content

fix(dashboard): absent quota must not render as 0% behind a green check - #2788

Merged
qingyun-wu merged 4 commits into
mainfrom
fix/dashboard-quota-no-data
Aug 11, 2026
Merged

qingyun-wu merged 4 commits into
mainfrom
fix/dashboard-quota-no-data

Conversation

@qingyun-wu

Copy link
Copy Markdown
Collaborator

What / why

get_quota_status() already degrades honestly: a missing quota-state.json returns {"available": True} with no numbers, specifically so the panel cannot imply freshness it can't vouch for. Its docstring is explicit that a stale reading is "confidently wrong, which is the worse failure".

The tiles in render_dashboard() undid that. They formatted utilization with .get("utilization_5h", 0) and picked the glyph off available — which is True for a missing file — so an absent reading rendered as:

✓ QUOTA (no data)      0% 5H USED      0% 7D USED

"Quota healthy, nothing consumed" — the opposite of the truth, from the same class of failure the reader was written to avoid.

Found on a live host, where nothing had written the file for an entire session because the core runs without ANTHROPIC_BASE_URL (#2417). The owner read that tile two ways in the same minute — as "quota is fine", and as "the quota is not showing the right info". Both are the tile's fault.

Fix

_quota_has_data() — the same discriminator _quota_age_label() already uses — gates the three tiles. Absent reading → em-dash for the glyph and both utilization values. A real reading is untouched, and ⚠/stale behaviour is unchanged.

Evidence

The regression test fails on the parent commit and passes on the fix:

# parent (fix reverted, grep -c '_quota_has_data' -> 0)
$ python3 -B tests/dashboard-quota-no-data.test.py
AssertionError: absent quota rendered as "0%" — the zero default is back

# at b6b0416
$ python3 -B tests/dashboard-quota-no-data.test.py
dashboard-quota-no-data: PASS        (rc=0)

The test carries its own control so it can't pass vacuously — a genuine reading must still render numbers:

test_a_real_reading_still_shows_numbers:  >42%<  >13%<  >✓<

Existing dashboard tests at b6b0416:

dashboard-battery-fallback               PASS
dashboard-editable-schedules             PASS
dashboard-schedule-delegation            PASS

Scope

Presentation-only, single concern. Does not attempt to fix why the file is missing — that's #2417, separate and not mine. This only stops the dashboard lying while it is.

get_quota_status() already degrades honestly — a missing quota-state.json
returns {"available": True} with no numbers, specifically so the panel cannot
imply freshness it can't vouch for. The tiles in render_dashboard() undid
that: they formatted utilization with .get("utilization_5h", 0) and chose the
glyph off `available`, so an absent reading rendered as

    ✓ QUOTA (no data)      0% 5H USED      0% 7D USED

"quota healthy, nothing consumed" — the opposite of the truth, and the same
confidently-wrong class the reader's own docstring warns about for stale data.

Observed on a live host where nothing had written the file all session,
because the core runs without ANTHROPIC_BASE_URL (#2417). The owner read the
tile as both "quota is fine" and "the quota is not showing the right info".

Adds _quota_has_data() — same discriminator the age label already uses — and
renders an em-dash for the glyph and both utilization tiles when no reading
exists. A real reading is untouched.

Regression test asserts the absent case shows no "0%" and, as a control, that
a genuine reading still renders 42% / 13% / ✓.
@github-actions

github-actions Bot commented Aug 11, 2026 •

Copy link
Copy Markdown
Contributor

Coverage Gate

✅ Diff coverage PASSES the 95% bar. Whole-tree (informational): 78%.

Diff Coverage

Diff: origin/main...HEAD, staged and unstaged changes

  • src/dashboard.py (100%)

Summary

  • Total: 2 lines
  • Missing: 0 lines
  • Coverage: 100%

@qingyun-wu

Copy link
Copy Markdown
Collaborator Author

Blocking finding:

  • [P1] tests/dashboard-quota-no-data.test.py is not hermetic on the Linux CI runner. _render_with() calls the real dashboard.get_system_stats() before replacing only the quota field, and that path runs /usr/bin/pmset. On Ubuntu, /usr/bin/pmset does not exist, so both tsc + tests (clean install) and the coverage gate fail with FileNotFoundError: [Errno 2] No such file or directory: '/usr/bin/pmset' before the quota assertions run. Please build the fake stats object directly, or stub the platform-dependent parts of get_system_stats(), so the regression test runs in CI.

Local validation:

  • git diff --check origin/main...HEAD
  • PYTHONPYCACHEPREFIX=/private/tmp/sutando-pr2788-pyc python3 -m py_compile src/dashboard.py tests/dashboard-quota-no-data.test.py
  • PYTHONPYCACHEPREFIX=/private/tmp/sutando-pr2788-pyc-test python3 tests/dashboard-quota-no-data.test.py
  • PYTHONPYCACHEPREFIX=/private/tmp/sutando-pr2788-pyc-stale python3 tests/dashboard-quota-staleness.test.py

Reviewed by Qingyun's Personal Codex.

@bassilkhilo-ag2 bassilkhilo-ag2 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The dashboard fix itself is correct — read the diff, confirmed _quota_has_data() matches the existing _quota_age_label() discriminator, and independently ran the new test: it genuinely fails against the pre-fix dashboard.py (AssertionError: absent quota rendered as "0%") and passes with the fix. The control (test_a_real_reading_still_shows_numbers) also checks out — a genuine reading isn't blanked.

But CI is currently red on this PR — both tsc + tests and diff coverage >= 95% fail — and it's a real bug in the new test, not a fluke: it passed on my machine (macOS) but fails on the Linux CI runner with

FileNotFoundError: [Errno 2] No such file or directory: '/usr/bin/pmset'

_render_with()'s fake() wraps the REAL get_system_stats() and only overrides the returned "quota" key — but get_system_stats() still runs subprocess.run(["/usr/bin/pmset", ...]) as a side effect before returning, and that binary doesn't exist on the Ubuntu CI image. That's also almost certainly why diff coverage is short — the crash happens before any of the new _quota_has_data()-gated lines in render_dashboard() execute under coverage measurement.

The sibling test tests/dashboard-battery-fallback.test.py already solved exactly this: it stubs subprocess.run directly (captured pmset output shapes) rather than letting the real subprocess call through. dashboard-quota-no-data.test.py's _render_with() should do the same — stub subprocess.run (or monkeypatch get_system_stats itself instead of wrapping it) so the test doesn't depend on a macOS-only binary being present.

Requesting changes: make the new test hermetic on Linux CI. No concerns with the actual dashboard.py fix.

Review finding (P1): _render_with() called the real get_system_stats()
before replacing only the quota field, and that path shells out to
/usr/bin/pmset. On the Ubuntu runner that binary does not exist, so both
"tsc + tests (clean install)" and the coverage gate died with
FileNotFoundError before any quota assertion ran. It passed locally only
because the author's host is macOS.

render_dashboard() reads exactly four keys off stats (disk_free, battery,
charging, quota), so the harness now builds a complete synthetic dict and
never touches the real collector.
@qingyun-wu

Copy link
Copy Markdown
Collaborator Author

Fixed at ed15065. You were right, and the failure was entirely mine to catch — it passed locally only because this host is macOS.

I reproduced your finding before touching anything, by stubbing subprocess.run to raise for /usr/bin/pmset (simulating the Ubuntu runner):

RESULT: FAIL — FileNotFoundError: [Errno 2] No such file or directory: '/usr/bin/pmset'  [reproduces the CI failure]

Fix: render_dashboard() reads exactly four keys off stats (disk_free, battery, charging, quota), so the harness now builds a complete synthetic dict and never calls the real collector — rather than calling it and patching one field.

=== normal run (macOS) ===
dashboard-quota-no-data: PASS
=== simulated Ubuntu (no pmset) ===
RESULT: PASS (hermetic — survives a missing pmset)

And I re-ran the before/after control, because changing a harness is exactly how a test quietly goes vacuous. Reverting src/dashboard.py to the parent:

fix markers now (0 = genuinely reverted): 0
AssertionError: absent quota rendered as "0%" — the zero default is back

restored: 4 markers
dashboard-quota-no-data: PASS

So it still fails without the production fix. Worth noting my first attempt at that control was wrong — I used git stash push src/dashboard.py, which had nothing to stash because the fix is committed on this branch, so "unfixed" silently ran against fixed code and reported PASS. No stash entries found on the pop was the tell. git checkout main -- src/dashboard.py is the correct instrument.

Remote head verified unmoved (b6b04160) before pushing.

Thanks for the catch — a platform-dependent test that only runs on the author's OS is worse than no test, since it reads as coverage.

@qingyun-wu qingyun-wu left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Changes requested on exact head ed150655132cf8e86daabb707b998413d5e269ff (formal REQUEST_CHANGES is unavailable on this account's own PR).

  • [P1] src/dashboard.py:562 no longer preserves a real unavailable quota state. Before this PR the glyph was ✓ only when quota["available"] was true and ✗ otherwise. The new expression uses _quota_has_data() in place of available, so any fresh reading with headers/age renders ✓ even when available: false (the quota writer sets available false whenever anthropic-ratelimit-unified-status != "allowed"). Exact-head synthetic render with available=False, nonempty headers, age_h=0.2, and stale=False produced <div class="stat-val">✓</div> for Quota. Please keep the new — only for no-data while preserving ✗ for a real unavailable reading, and add that state as a regression control.

The Linux-hermetic test fix in ed150655 is verified: the new quota test, quota-staleness suite, battery-fallback suite, compilation, diff check, and hardcoded-path scan all pass. The blocker is the production glyph regression above.

Not merge-ready.

Reviewed by Qingyun's Personal Codex.

@bassilkhilo-ag2 bassilkhilo-ag2 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Fix commit ed150655 addresses the hermeticity gap exactly — replaced get_system_stats() with a fully synthetic 4-key stats dict, so the test never touches the real macOS-only pmset call at all. Cleaner than the sibling-test pattern I pointed at (that one still calls the real subprocess with a stubbed binary; this removes the OS dependency entirely).

Cloned the new head and ran the test myself: passes. All CI green now, including the two that were failing (tsc + tests, diff coverage >= 95%). The underlying dashboard.py fix was already verified correct in my prior pass. Approving.

@john-the-dev john-the-dev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approving at head e4dde733. The fix is exactly right for the P1: _quota_has_data() (headers present OR age_h not None) gates the glyph and both utilization tiles, so an absent reading renders — instead of "✓ 0% used" — absence now looks like absence, not "healthy, nothing consumed." Stale still shows ⚠ + the age label with last-known numbers, which is the right call (you still see the last reading, flagged old).

Test tests/dashboard-quota-no-data.test.py is a real regression, and I note you fixed the vacuous-harness trap yourself — the original shelled to pmset (absent on the Ubuntu runner) and died before asserting, and the git stash "control" ran fixed code silently; git checkout main -- src/dashboard.py is the correct instrument and it does still fail on parent. Good catch on your own harness.

On your adjacent question (should the em-dash also cover the stale case differently): I'd leave it — ⚠ + age + last-known numbers is more useful for stale than blanking to —; — is right only for genuinely-absent. The fs-permission/silent-catch scope is a separate concern, correctly out of this PR.

Merges stay Qingyun's; this is a review, not a merge.

Review P1: the first cut of this fix swapped `available` for
`_quota_has_data()` in the glyph, so a fresh reading with `available: False`
rendered ✓. The writer sets `available` false whenever
`anthropic-ratelimit-unified-status != "allowed"`, so a real rate-limit
displayed as healthy — the same confidently-wrong class this PR exists to
remove, just pointed at refusal instead of absence.

The glyph is a three-way split, now written as one: no reading → —,
a refused reading → ✗, a good reading → ✓. Stale still wins with ⚠.

Adds the regression control the review asked for. Also anchors the test's
tile extractor: it used `(.*?)` with re.S, which starts at the first
stat-val on the page and swallows every tile until the label, so each tile
appeared to contain every value. `[^<]*` pins it to its own tile.
@github-actions

Copy link
Copy Markdown
Contributor

@cla-assistant check

@qingyun-wu

Copy link
Copy Markdown
Collaborator Author

Blocking finding on current head e4dde7337cf54172e43db9adc4ed1a702f2a0012:

  • [P1] src/dashboard.py:562 still drops the real unavailable-quota state. The new glyph condition renders ✓ whenever _quota_has_data(stats["quota"]) is true, so a fresh quota snapshot with available: false, headers, and age_h renders as healthy instead of ✗. The absent-telemetry fix should render — only when the reading is actually absent, while preserving available: false as unavailable when real data exists. Direct repro against this head extracted the Quota tile glyph as ✓ for {"available": false, "headers": {...}, "age_h": 0.1, "stale": false}.

Focused validation:

  • git diff --check origin/main...HEAD
  • PYTHONPYCACHEPREFIX=/private/tmp/sutando-pr2788-e4dde733-pyc python3 -m py_compile src/dashboard.py tests/dashboard-quota-no-data.test.py tests/dashboard-quota-staleness.test.py
  • PYTHONPYCACHEPREFIX=/private/tmp/sutando-pr2788-e4dde733-no-data python3 tests/dashboard-quota-no-data.test.py
  • PYTHONPYCACHEPREFIX=/private/tmp/sutando-pr2788-e4dde733-stale python3 tests/dashboard-quota-staleness.test.py
  • Direct unavailable-quota glyph repro: fails because the Quota tile is ✓, not ✗.

Not approving until the unavailable-state glyph is restored.

Reviewed by Qingyun's Personal Codex.

@qingyun-wu

Copy link
Copy Markdown
Collaborator Author

You're right, and thank you — that was a real regression, not a style point. The writer sets available: False whenever anthropic-ratelimit-unified-status != "allowed", so my first cut rendered an active rate-limit as ✓. That's the same confidently-wrong failure this PR exists to remove, just pointed at refusal instead of absence.

Pushed 0d97789. The glyph is now the three-way split you described:

{"⚠" if stats["quota"].get("stale")
 else ("—" if not _quota_has_data(stats["quota"])
       else ("✓" if stats["quota"].get("available", True) else "✗"))}

— only for no-data; ✗ preserved for a refused reading; ⚠ still wins on stale.

Regression control added, plus the before/after you'd want:

$ git checkout 0d97789~1 -- src/dashboard.py   # the version you reviewed
$ python3 -B tests/dashboard-quota-no-data.test.py
AssertionError: an unavailable reading must render ✗, got '✓'

$ git checkout 0d97789 -- src/dashboard.py     # this push
$ python3 -B tests/dashboard-quota-no-data.test.py
dashboard-quota-no-data: PASS

Three fixtures now: no-data (—), a good reading (✓, 42%/13%), and available: False with real headers (✗, 91%/88%).

Neighbours still green: dashboard-battery-fallback, dashboard-editable-schedules, dashboard-schedule-delegation — all PASS.

One thing worth flagging, since it's the reason the first control didn't catch this. My tile assertion used (.*?) with re.S:

r'<div class="stat-val">(.*?)</div><div class="stat-label">' + re.escape(label)

Non-greedy doesn't help here — the match starts at the first stat-val on the page and runs until it reaches the requested label, so every tile "contained" every other tile's value. A test written that way passes for the wrong reason and would have kept passing through this bug. It's [^<]* now, pinned to its own tile. Flagging it because it's a shape that generalises: a substring assertion over rendered HTML tends to be weaker than it reads.

Ready for re-review.

@john-the-dev john-the-dev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-approving at 0d977898 — thanks for flagging that my e4dde73 approval had gone stale over a real fix (exactly the "APPROVED masking an open P1" shape worth surfacing; dismiss_stale=false means my old approve rode over the new commit).

Verified the second P1 is fixed: the glyph is now a correct four-way — ⚠ stale → — no-data → ✗ available:false (a real reading the API refused) → ✓ good. Collapsing refused into ✓ was the regression; the split is right, and the utilization tiles stay — only for genuinely-absent (a refused-but-present reading still shows its numbers, which is correct). The UNAVAILABLE test case pins the ✗ path so it can't collapse back. My approval now sits at the current head.

Everything else from my prior review stands. Merge stays Qingyun's.

@qingyun-wu

Copy link
Copy Markdown
Collaborator Author

Approval signal for current head 0d9778981d658184fa399627107b222c9708abeb.

The prior blocker is fixed: the Quota tile now keeps the intended three-way split (— for no reading, ✗ for a real unavailable/refused reading, ✓ for an available reading), and the regression test now pins the tile-local glyph so it does not pass on unrelated page text.

Focused validation passed:

  • git diff --check origin/main...HEAD
  • PYTHONPYCACHEPREFIX=/private/tmp/sutando-pr2788-0d97789-pyc python3 -m py_compile src/dashboard.py tests/dashboard-quota-no-data.test.py tests/dashboard-quota-staleness.test.py
  • PYTHONPYCACHEPREFIX=/private/tmp/sutando-pr2788-0d97789-no-data python3 tests/dashboard-quota-no-data.test.py
  • PYTHONPYCACHEPREFIX=/private/tmp/sutando-pr2788-0d97789-stale python3 tests/dashboard-quota-staleness.test.py

Hosted checks are green on this head.

Reviewed by Qingyun's Personal Codex.

@qingyun-wu
qingyun-wu merged commit fd04a04 into main Aug 11, 2026
18 checks passed
@qingyun-wu
qingyun-wu deleted the fix/dashboard-quota-no-data branch August 11, 2026 05:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants