fix(dashboard): rework the usage panel per #960 — split-bar limit control, pace deviation, continuous quota boundary - #1229
Conversation
…ota bar (#960) A quota week that starts mid-day packs its second label into a sliver of the bar (as little as a few minutes' worth), landing it almost on top of the first label — exactly what the reported screenshot shows. tickRows() now flags any tick too close to the last one placed on the line, and the component draws it a line lower instead of overlapping.
|
The Generated by Claude Code |
#960 Edit) The "Unattended work stops at" limit rendered as its own full-width native <input type="range"> underneath the week bar — a second, visually distinct bar, not the single unified control the issue's Edit asked for. The limit is now a draggable handle layered directly on the week track, valued on the same 0-100 percent scale as the fill and boundary beneath it (a native thumb's position is always (value - min) / (max - min) of the box, so min/max have to stay 0/100 for it to land where the boundary tick does). The ±MAX_SPEND_OFFSET reach is enforced by clamping the resulting offset in the change handler instead of via the input's own min/max. At rest the handle sits exactly on the boundary tick; dragging it is what draws it as a mark of its own.
|
Pushed a follow-up (f543072): you were right, the It's now a draggable handle layered directly on the week track itself, sharing the same 0-100% coordinate system as the fill and the boundary tick beneath it. At rest it sits exactly on the boundary (so it reads as one mark); dragging it separates it visibly, still on the same bar. Click-anywhere-on-the-bar and keyboard operation both still work since it's a real Generated by Claude Code |
…r day (#960) Two more requests from the issue: - Day labels: walking local midnights split the account's start day into a sliver at each end of the bar, so it had to be labelled twice (`TU...TU`). weekDays() now cuts the week into seven equal 24h stretches from the account's own start moment instead, each labelled once at its own centre, with a delimiter between each pair. Every day is shown exactly once. - The limit: previously a draggable handle marked where unattended work stops, floating over the fill. It's now the bar's own shape — the track splits into what's used (solid) and the room left before the limit (dimmed), and dragging the dimmed segment's own right edge is the control. A legend names the two shades and the daily-boundary line. projectedRange() computes the dimmed segment (clamped to empty once the limit has already been reached), kept in quota-bar.ts alongside weekDays() so both are tested without a DOM.
|
Pushed the redesign (e9fb5d3) implementing your latest feedback:
33 tests in the Quota suite (525 total in the package), typecheck clean. Verified visually with a rendered preview — attaching it below. Generated by Claude Code |
… room Replaces the bracket-shaped `[]` thumb mark with a classic round knob — the split fill already shows the range it sets, so the thumb only needs to read as a handle, not a second indicator. Also adds a status line to the legend naming whether autonomous AI currently has room to spend: enabled (✅) once the knob is anywhere right of the used fill, disabled (❌) once dragged all the way onto it, each with a hint on how to reach the other state.
|
Pushed (cd2047c):
35 tests in the Quota suite (527 total), typecheck clean. Attaching a rendered preview of both states below. Generated by Claude Code |
…ltip, boundary warning (#960) - weekDays() now cuts the week at local midnights instead of equal sevenths, so a segment's width says how much of that day is actually in the week. The account's start day still splits into two same-named slivers straddling the reset a week apart; only the larger keeps its label, so "TU" lands wherever most of Tuesday actually falls (often the end of the bar, not the start) instead of showing twice. - Day separators are wider; the used/projected fill segments no longer round their own corners, so the bar reads as one seamless track instead of two pills glued together. - The caption now says when the week resets ("resets Tuesday 8:59pm", full date and zone in a tooltip via formatResetDay/formatResetTooltip) instead of a generic tone note ("Tracking with the week.", "Under the line, with room to spend.", etc — all removed). - A warning appears once the knob is dragged past the daily boundary. - Legend: "Autonomous AI usage (projected)", and "Daily boundary" gets a tooltip explaining it is a pace indicator, not a hard limit. - Removed the "Spend what's left on the roadmap" toggle and its status line from this panel, and the "Unattended work stops at" caption block — the draggable control itself stays, now labelled only by its own aria-label.
|
Pushed (fdce931), addressing all the latest feedback:
23 tests in Quota, 528 total in the package, typecheck clean. Attaching a rendered preview matching your reset-time scenario. Generated by Claude Code |
#960) - The enabled/disabled status now sits below the legend, and the past-budget warning shares its row (right side) instead of stacking a line beneath it. - Dropped the underline from the "resets ..." tooltip trigger. - "Daily boundary" -> "Daily budget" throughout. - The warning is now "Past daily budget" with its own question-icon tooltip ("Autonomous AI will spend tokens faster than the week's pace allows"), matching the daily-budget legend item's pattern instead of a long inline sentence. - The account's own week is no longer excluded from the other-windows list — every window Claude Code reports gets a line, in its own order, so "Current week (all models)" shows between "Current session" and a model's own week instead of only being drawn as the bar.
|
Pushed (dbddfc2):
26 tests in Quota, 531 total, typecheck clean. Preview attached. Generated by Claude Code |
|
Diagnosed the (Had to pull the raw log archive directly — the earlier "ticket-format" failure from this morning is fixed now too, confirming the base has moved forward since.) Requeued the failed job via rerun. Will watch for the result. Generated by Claude Code |
#960) - Removed the day-label row and separator notches entirely (weekDays() is now unused, so it and its tests are gone from quota-bar.ts too) — just the bar, the boundary line, and the knob. - The other windows (session, per-model week) move from an always-visible block into a "show all limits" tooltip next to the reset caption, shown only when there's something beyond the account's own week to add. A fallback still lists them directly when there's no bar to hide them in (an unplaceable week, or a week that failed to parse) — that data was never meant to depend on the bar existing. - The legend and the enabled/disabled status now share one row (status on the right), with the past-budget warning between them instead of on a separate line. - "Daily boundary" -> "Daily soft limit"; "Autonomous AI usage (projected)" -> "Budget for Autonomous AI".
|
Pushed (a9813d4):
28 tests in Quota, 527 total, typecheck clean. Preview (including what the "show all limits" tooltip shows) attached below. Generated by Claude Code |
…e limits table (#960) - dailyLimitPercent() (quota-bar.ts): consumption against the boundary in units of a full day's budget rather than a share of the week — 0% exactly on pace, negative behind, positive ahead, and it can run well past ±100% (e.g. -260%), which is the point: "20% used" read against the week said almost nothing about whether today's pace was being kept. - The main figure now shows this instead of the plain weekly percentage, with its own tooltip explaining what it measures. - "show all limits" now renders as a real <table>, so the label and value columns line up across every window instead of each row's flex sizing its own two items independently.
|
Pushed (1d81201):
32 tests in Quota, 534 total, typecheck clean. Preview attached. Generated by Claude Code |
…960) "−260% used" told a viewer there was a gap, but not how big it actually was in a unit anyone thinks in. Replaces it with "Over-consuming: 1d" / "Under-consuming: 2h": - paceDeviationMs() (quota-bar.ts) replaces dailyLimitPercent(): the same deviation from the boundary's pace, but as a signed real-time duration within the week instead of a multiple of a day's percentage. - formatDuration() (format-date.ts): floors to the largest whole unit ("2s" / "10m" / "2h" / "1d"), the same style as the existing formatAge(). - The tooltip explains what "Over-consuming" and "Under-consuming" mean.
|
Pushed (eae84c2): the main figure now reads "Over-consuming: 1d" / "Under-consuming: 2h" instead of a percentage.
33 tests in Quota, 537 total, typecheck clean. Preview attached. Generated by Claude Code |
…uota boundary (#960) - The main figure's label ("Under-consuming: ", "Over-consuming: ") is no longer bold; the duration itself now is, and coloured to match the bar's own tone (TONE_TEXT, mirroring TONE_FILL). - Its tooltip now names the deviation directly: "You are 2 days below the quota boundary — you're under-consuming: you spend slower than the week's pace allows." formatDurationLong() (format-date.ts) spells the duration out ("2 days") for this sentence, alongside the existing abbreviated formatDuration() ("2d") the figure itself uses. - "Daily soft limit" -> "Quota boundary", with its tooltip explaining what matching it means: "you're spending exactly what the week's pace allows."
|
Pushed (7b58674) the unambiguous parts:
One thing I want to flag before touching it: "Set the default position of the slider at half-a-day above the quota boundary." The slider's resting position when a user has never touched it is currently
Given every other change in this PR has been dashboard-only, I didn't want to quietly cross that line without checking — do you want (2), or is there a third option I'm missing (e.g. only apply this once the user has interacted with the slider at all, or store the default as an explicit dashboard preference rather than changing the framework's own resolution)? 34 tests in Quota, 539 total, typecheck clean. Preview of the styling attached. Generated by Claude Code |
… the boundary (#960 Edit) Sitting exactly on the boundary looked generous on paper but stopped unattended work on ordinary jitter around the line rather than actual overspending. A fresh install (or any account that has never touched the slider) now defaults to half a day of room instead — a real framework default (packages/the-framework), not a dashboard-only one, since auto PM and the dashboard both read it from the same source.
|
Pushed
Full framework typecheck + test suite (1380 tests, same 12 pre-existing/environmental failures as on the unmodified base commit — daemon.test.ts 503s and the ticket-format spec, none touching quota code) and the dashboard's 539 vitest tests both pass. Generated by Claude Code |
|
Pushed Brought Restored the 6 Generated by Claude Code |
… the status line and boundary (#960 Edit) - The "Eager consumption" warning (renamed from "Past daily budget") only shows once the knob clears a full day above the boundary, not merely past it — the boundary steps a day at a time on its own, so resting a few points ahead is normal. New tooltip spells out the 1-day threshold. - The enabled/disabled status line gets its own tooltip naming what it actually means for the AI queue. - The "Quota boundary" tooltip now reads as its own paragraphs and ends on a fun fact pointing back at the bar above.
|
Pushed This round:
Also fixes the Generated by Claude Code |
…sing The assertion still expected the single-sentence, em-dash wording an earlier direct push replaced with a period and a line break.
…not a fixed "1-day" (#960 Edit) Computes the same pace-deviation duration as the main figure, but of the knob's limit rather than actual consumption, so the tooltip names how far ahead of the week's pace the slider itself currently sits.
|
Pushed Generated by Claude Code |
…nce a day (#960 Edit) boundaryFromResetsAt() now computes percent as the plain elapsed share of the week (elapsedMs / weekMs) instead of a stepped day/7 fraction. The stepped version unlocked a whole day's allowance the instant a new day began — including the full week's worth on the last day — which let a burst of spending land the moment the clock ticked over rather than pacing with it continuously. day is unchanged and still names which day of the week `now` falls on, independently of percent. This also fixes the dashboard's usage bar: since the boundary now rises on the same continuous elapsed-time axis the calendar-day labels are drawn on, the boundary tick always falls inside the correct day segment rather than looking visually offset from it. The dashboard code itself needed no changes — it already just draws whatever boundary.percent the framework reports.
|
Pushed This was a real enforcement change (auto PM gates on this value), not a dashboard tweak — confirmed via the earlier boundary-position question: the old stepped version unlocked a whole day's allowance the instant a new day began (including the entire week's worth on the last day), which let a burst of spending land the moment the clock ticked over rather than pacing continuously with it. As a side effect this also resolves the visual mismatch reported earlier (the boundary tick landing between two day labels): since the boundary now rises on the same continuous elapsed-time axis the calendar-day labels are drawn on, it always falls inside the correct day segment. The dashboard code itself needed zero changes — it was already just drawing whatever Updated tests in Generated by Claude Code |
brillout
left a comment
There was a problem hiding this comment.
Reviewed the full diff at feca9a5 (19 files). The split-bar control, calendar-day axis, and the continuous boundary are all well built, and the test coverage is thorough — the component tests in particular pin real behavior (thumb scale, clamping, tooltip content) rather than implementation details. I found one real regression and a few smaller issues; all are fixed in #1239, which targets this branch so merging it folds the fixes into this PR.
1. The continuous boundary silently tightened the per-run gate on the user's own runs. startConsumptionGuard — the gate every non-transparent CLI run starts, the one that logs "Quota boundary reached — pausing the session" — measures against the same boundary.percent this PR made continuous, with no offset. The stepped day/7 line always kept at least the current day's seventh in hand (14.3 points at day start); the continuous line starts the week at zero. Reproduced against this branch: half an hour into a fresh week, percentUsed 1% >= boundary 0.3% pauses the user's own session, where main's stepped gate (14.29%) carried on. It also inverted the PR's own philosophy: unattended work got the half-day cushion while user-asked work got none, so auto PM could spend past the point where the user's own runs pause. The quota-boundary-continuous changeset says the change is "purely a change to what auto PM and the panel treat as 'on pace'" — the guard was the third consumer. Fix: the guard now carries the same fixed half-day cushion (deliberately not the slider — holding unattended work back must never tighten the gate on work the user asked for), and the changeset now discloses it.
2. Settings still shows "Spend offset: 0" while the limit in force is +7.1. SettingsPage.tsx's number box falls back to ?? 0, which stopped being the real default when DEFAULT_SPEND_OFFSET landed. Now shows the shared default to one decimal.
3. quotaHeadroom's refusal reason prints the raw double once the fractional default is in force: (+7.142857142857143 on the week's 32%). Now rounded to one decimal.
4. Doc drift from the last commit. Three comments still justify thresholds with "the boundary steps a day at a time" (the eager-consumption threshold in Quota.tsx, ONE_DAY_PERCENT, the quotaTone test), which feca9a5 made untrue; the test fixtures' "resets in 5 days 19 hours" comments are off by a day (Jul 20 12:00 → Jul 25 07:00 UTC is 4d19h — the ~31.5% beside it was already right); RoutineWork still points at this panel's removed autoPm toggle.
Two observations, no action taken: weekDays() dropped the old 9-tick guard against a pathological span — fine, since both callers derive startsAt/resetsAt exactly one week apart; and the ✅/❌ status line reads only the knob's room, not the autoPm preference — matches what was asked for, just noting the on/off switch now lives solely in Routine work / Settings.
Verification on this branch + fixes: framework quota tests 79/79, full suite matches the known baseline (10 environmental daemon/serve failures + the pre-existing ticket-format spec failure), dashboard 550/550, tsc --noEmit clean.
I've also refreshed this PR's title and description — they still described the original tickRows() label fix, which later rounds evolved away entirely (that helper no longer exists in the diff).
Generated by Claude Code
…default, stale comments (#1239)
|
Didn't read the code |
Resolves the routine-concurrency work against main's usage-panel rework (#1229), the Quick wins preset removal (#1240), the describe-only-for- maintenance routine list (#1242), and the always-live Trigger button (#1248). The sweep's batched spawn loop adopts main's doing() wording; the auto-PM copy that lived on the usage panel is gone with the panel, and its concurrent-agent fine print lives on the Routine work card. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AoDsAvEMKzShkiRY6Wba9z
Summary
Started as the label-collision fix reported at #960 (comment) and grew, over the review rounds in this thread, into the full
## Editredesign of the usage panel plus two framework-side policy changes. Current state:Dashboard (
@gemstack/framework-dashboard)<input type="range">styled down to a round knob riding the track itself, valued on the bar's own 0–100 scale so the thumb sits exactly on the segment edge and the boundary tick when at rest.weekDays()cuts the week at local midnights, labels each day once at its own centre (TU,WE, …), and for a mid-day-start week gives the split day's label to whichever sliver is larger — the original overlap bug can no longer occur. White separators mark each day's start in the fill.paceDeviationMs+formatDuration), bold and toned like the bar, instead of a week-percentage that said nothing about today's pace — with a tooltip spelling it out in full (formatDurationLong).formatResetDay) with the exact moment and zone in a tooltip, and a "show all limits" tooltip rendering every reported window (session, account week, per-model weeks) as a real table.Framework (
@gemstack/the-framework)boundaryFromResetsAtnow reportspercentas the plain elapsed share of the week rather than a steppedday/7that unlocked a whole day's allowance at each rollover (the entire week's worth on the last day).daystill names the day for display.DEFAULT_SPEND_OFFSET(100/14) — the auto-spend limit's resting position is half a day ahead of the boundary instead of exactly on it, so an account tracking its pace isn't stopped by ordinary jitter. Wired throughdashboard/quota.ts, Settings, and the panel; an explicit slider value still overrides it.startConsumptionGuardwould otherwise pause the user's own first run of a fresh week over its first reported percent.Three changesets: two patches for
@gemstack/the-framework(continuous boundary + guard cushion, default offset), one for@gemstack/framework-dashboard(the panel rework).Test plan
weekDays,paceDeviationMs,projectedRange,formatDuration/formatDurationLong/formatResetDay/formatResetTooltipunit tests, including the exact mid-day-start scenario from the bug reportquota-boundary,consumption-guard,auto-pm,dashboard/quotatests updated for the continuous boundary and default cushionGenerated by Claude Code