Skip to content

fix(dashboard): rework the usage panel per #960 — split-bar limit control, pace deviation, continuous quota boundary - #1229

Merged
brillout merged 22 commits into
mainfrom
claude/framework-issue-960-psx76q
Jul 26, 2026
Merged

fix(dashboard): rework the usage panel per #960 — split-bar limit control, pace deviation, continuous quota boundary#1229
brillout merged 22 commits into
mainfrom
claude/framework-issue-960-psx76q

Conversation

@brillout

@brillout brillout commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

Started as the label-collision fix reported at #960 (comment) and grew, over the review rounds in this thread, into the full ## Edit redesign of the usage panel plus two framework-side policy changes. Current state:

Dashboard (@gemstack/framework-dashboard)

  • One track, split in two: the week bar's fill is "Used" (solid) plus "Budget for Autonomous AI" (same tone, dimmed) — and the dimmed segment's right edge is the auto-spend limit control, a real <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.
  • Calendar-day axis: 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.
  • Pace deviation as the main figure: "Over-consuming: 1d" / "Under-consuming: 2h" (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).
  • Reset caption: "resets Tuesday 8:59pm" (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.
  • Legend + status row: swatches for Used / Budget / "Quota boundary ⓘ" (tooltip, ending on the fun fact), an ✅/❌ "Autonomous AI enabled/disabled" status read off the knob's remaining room (with tooltips), and a "⚠️ Eager consumption" warning only once the knob clears a full day above the boundary, its tooltip naming the knob's actual deviation.
  • Removed from this panel: the "Spend what's left on the roadmap" toggle + auto-PM readout (still in Routine work and Settings) and the separate full-width slider block.

Framework (@gemstack/the-framework)

  • Continuous quota boundary: boundaryFromResetsAt now reports percent as the plain elapsed share of the week rather than a stepped day/7 that unlocked a whole day's allowance at each rollover (the entire week's worth on the last day). day still names the day for display.
  • Half-day default cushion: new 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 through dashboard/quota.ts, Settings, and the panel; an explicit slider value still overrides it.
  • Per-run guard keeps the same cushion (added in the fix(quota): review fixes for #1229 — per-run guard cushion, Settings default, stale comments #1239 review round): the continuous boundary starts the week at zero, so the offset-less startConsumptionGuard would 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/formatResetTooltip unit tests, including the exact mid-day-start scenario from the bug report
  • Component tests for the split bar, knob scale + ±50 clamping, tooltips, eager-consumption threshold, status line, and the "show all limits" table
  • quota-boundary, consumption-guard, auto-pm, dashboard/quota tests updated for the continuous boundary and default cushion
  • Full dashboard suite (550 tests) and framework suite (modulo the pre-existing environmental daemon/serve + ticket-format failures, identical on the base commit) pass; typecheck clean on both packages
  • Visually verified across the review rounds with rendered previews at each step (attached in the thread)

Generated by Claude Code

…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.

Copy link
Copy Markdown
Member Author

The build check's test failure (the ticket-format spec ships in the package... (#684/#674) in tickets.test.ts) is pre-existing on main — I reproduced it on the base commit (c7fb48f) in isolation, unrelated to this PR's diff (which only touches packages/framework-dashboard). TICKETING_FORMAT now documents Priority: 10-0 but the test still asserts the old priority: low/medium/high/urgent wording. Will re-run once the base branch is green again.


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.

Copy link
Copy Markdown
Member Author

Pushed a follow-up (f543072): you were right, the ## Edit wasn't actually implemented — the "Unattended work stops at" limit was rendering as its own full-width native <input type="range"> underneath the week bar, a second visually distinct bar rather than the single unified control.

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 <input type="range">, just styled so only its thumb is visible.


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.

Copy link
Copy Markdown
Member Author

Pushed the redesign (e9fb5d3) implementing your latest feedback:

  • Days shown once, in the middle: the week is now cut into 7 equal 24h stretches from the account's own start moment (not walked from local midnight), each labelled once at its own centre, with a | delimiter between each pair.
  • Single bar split in two: the track itself now splits left-to-right into "used" (solid) and "room left before the limit" (dimmed) — dragging the dimmed segment's own right edge sets the limit, replacing the separate handle/slider from the last round.
  • Legend added below the bar naming the two shades and the daily-boundary line.

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.

Copy link
Copy Markdown
Member Author

Pushed (cd2047c):

  • Replaced the bracket-shaped [] thumb with a classic round knob.
  • Added a status line to the legend naming whether Autonomous AI currently has room to spend — ✅ enabled (with "move slider to the left to disable") once there's room, ❌ disabled (with "move slider to the right to enable") once the knob is dragged all the way onto the used fill.

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.

Copy link
Copy Markdown
Member Author

Pushed (fdce931), addressing all the latest feedback:

  • Day separators: wider now.
  • No rounded seam: the used/projected fill segments no longer round their own corners — one seamless bar, only the outer track rounds the ends.
  • Calendar-day segments: this was the biggest change. Segments are now local-midnight to local-midnight (not equal sevenths), so a label sits where most of that day actually falls. Your case (reset "Jul 28, 8:59pm") is exactly the mid-day-start scenario: the account's start day splits into a small sliver right after the week begins and a much bigger one right before the reset a week later — both "Tuesday", but now only the bigger one (at the end of the bar) keeps the label, which is what you expected.
  • Removed "Spend what's left on the roadmap" (whole toggle + status), the "Unattended work stops at" caption block, and "Under the line, with room to spend." (the whole tone-note line, actually — replaced by the resets text below).
  • "51% used · resets Tuesday 8:59pm", with a tooltip showing "Quota resets on Jul 28, 8:59pm (Europe/Berlin)" — computed from the boundary's own reset timestamp, so the zone shown is whatever your browser resolves to (matches yours since that's presumably where you're viewing it from). I left the other-windows row's reset text as-is for now — it comes from Claude Code's own raw prose with no parsed timestamp behind it in this codebase, so I can't reformat it the same way without re-implementing date parsing there; let me know if you want me to look at that separately.
  • "Autonomous AI usage (projected)" and "Daily boundary ⓘ" with the pro-rated-share tooltip on both the text and icon.
  • Warning when the knob is dragged past the daily boundary.

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.

Copy link
Copy Markdown
Member Author

Pushed (dbddfc2):

  • Legend now comes first; the ✅/❌ status line moved below it, on its own row shared with the warning (right-aligned).
  • Removed the underline from "resets Tuesday 7:00pm".
  • "Daily boundary" → "Daily budget" everywhere.
  • Warning is now "⚠️ Past daily budget" with its own question-icon tooltip: "Autonomous AI will spend tokens faster than the week's pace allows" — same pattern as the daily-budget legend tooltip.
  • The account's own week is no longer excluded from the windows list below — every window now gets a line in its natural order, so "Current week (all models)" appears between "Current session" and a model's own week.

26 tests in Quota, 531 total, typecheck clean. Preview attached.


Generated by Claude Code

Copy link
Copy Markdown
Member Author

Diagnosed the build failure on dbddfc2: daemon-workspace.test.ts › "binding a topic run re-homes it into the bound project..." (#1122) failed with ENOTEMPTY: directory not empty, rmdir '/tmp/framework-rehome-target-.../.the-framework'. That's in packages/the-framework — unrelated to this PR's diff, which only touches packages/framework-dashboard. Ran the same test 5/5 in isolation locally with no failure, so this reads as a filesystem-cleanup race under full-suite load/CI concurrency rather than a real regression.

(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".

Copy link
Copy Markdown
Member Author

Pushed (a9813d4):

  • Day axis removed entirely — no more weekday labels or separator notches; just the bar, the boundary line, and the knob. (weekDays() is now unused, so it and its tests are gone from quota-bar.ts too.)
  • "show all limits": the session/model-week rows move from an always-visible block into a tooltip next to "resets Tuesday 8:59pm" — only shown when there's something beyond the account's own week to add. A fallback still lists them directly for the rare case there's no bar to hang the tooltip on (unplaceable/unparseable week).
  • Legend + status share one row: status moved to the right side of the legend's row; the "⚠️ Past daily budget" warning now sits directly to its left instead of on its own line.
  • Renamed: "Daily boundary" → "Daily soft limit"; "Autonomous AI usage (projected)" → "Budget for Autonomous AI".

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.

Copy link
Copy Markdown
Member Author

Pushed (1d81201):

  • Tooltip added on the main figure, explaining what it measures.
  • "show all limits" fixed: it now renders as a real <table> instead of independent flex rows, so the label/value columns actually line up across every window.
  • Main figure now reads against the daily budget: dailyLimitPercent() expresses consumption in units of a full day's budget relative to the boundary — 0% is exactly on pace, negative is behind, positive is ahead, and it can run well past ±100% (e.g. -260% used when 20% of the week is used against a 57% pace — day 4 of 7). That's the point: the old weekly percentage told you almost nothing about whether today's pace was being kept.

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.

Copy link
Copy Markdown
Member Author

Pushed (eae84c2): the main figure now reads "Over-consuming: 1d" / "Under-consuming: 2h" instead of a percentage.

  • paceDeviationMs() (replacing dailyLimitPercent()) computes the same deviation from the boundary's pace, but as a signed real-time duration within the week rather than a multiple-of-a-day percentage.
  • formatDuration() floors to the largest whole unit — 2s / 10m / 2h / 1d — same style as the existing formatAge().
  • Kept the tooltip, updated to explain what "Over-consuming" (spending faster than the week's pace allows) and "Under-consuming" (spending slower) mean.

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."

Copy link
Copy Markdown
Member Author

Pushed (7b58674) the unambiguous parts:

  • The duration ("2d", "1d", ...) is now bold and coloured to match the bar's own tone; the "Under-consuming:"/"Over-consuming:" label is plain.
  • Its tooltip: "You are 2 days below the quota boundary — you're under-consuming: you spend slower than the week's pace allows." (and the mirrored wording for over-consuming/above).
  • "Daily soft limit" → "Quota boundary", with the tooltip text you gave (typo-corrected "page" → "pace", since the rest of the copy already says "the week's pace allows").

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 offset = 0 (limit == boundary), and that's not just a dashboard default — it's packages/the-framework/src/quota-boundary.ts's own documented policy (input.limitOffset ?? 0, explicitly commented "Omitted or 0 is the #879 policy: the limit is the boundary"). Two ways I could take this:

  1. Dashboard-only cosmetic default — change the fallback in useSpendOffset (serverOffset ?? 0serverOffset ?? ~7). Problem: once a real reading loads, the backend always reports a concrete offset (0 for "never customized," since that's its own default too), so this never actually visibly changes anything once the bar renders — it'd be a no-op in practice.
  2. Real framework default — change quota-boundary.ts's own default from 0 to a half-day's worth of percentage points. This actually produces the behavior you're describing, but it changes when unattended/autonomous work actually stops by default for every account using this framework, not just what the dashboard shows — a real behavior change to a documented policy, not a cosmetic one.

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.

Copy link
Copy Markdown
Member Author

Pushed 94fd720, implementing the last two requests:

  • Slider's default position: the auto-spend slider now defaults to half a day's cushion above the quota boundary instead of sitting exactly on it. Per the earlier discussion, this is a real framework default (packages/the-framework/src/preference-defaults.ts's new DEFAULT_SPEND_OFFSET, wired through dashboard/quota.ts), not a dashboard-only cosmetic fallback — it's what auto PM and the panel both fall back to when autoSpendOffset has never been set. Added a changeset for @gemstack/the-framework and a dashboard/quota.test.ts test covering it.
  • Confirmed the build check failure on 7b58674 was the same pre-existing daemon-workspace.test.ts ENOTEMPTY flake diagnosed earlier (reproduces on the base branch too) — requeued via rerun_failed_jobs.

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

 Edit)

Brings back weekDays() (calendar-midnight segments, deduped so a
mid-day week start still labels each day exactly once) and renders it
above and through the bar: a two-letter weekday label per day, and a
white separator through the fill at each day's own start.

Copy link
Copy Markdown
Member Author

Pushed 1e2a807: restored the day labels and separators on the bar.

Brought weekDays() back into lib/quota-bar.ts (calendar-midnight segments, deduped so a mid-day week start still labels each day exactly once — TU lands wherever most of Tuesday actually falls) and wired it back into WeekBar: a two-letter weekday label row above the bar, and a white separator through the fill at each day's start. Same behavior as before it was dropped, just reattached to the current single-track bar (used/dimmed split, boundary line, knob).

Restored the 6 weekDays() unit tests in quota-bar.test.ts and updated the one component test that had asserted the axis was gone. Dashboard suite: 545/545 passing; typecheck clean.


Generated by Claude Code

brillout and others added 4 commits July 26, 2026 19:48
… 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.

Copy link
Copy Markdown
Member Author

Pushed 899f76b, rebased on top of the direct edits pushed to this branch (the SEP/paragraph-break tweak to the pace-deviation tooltip) — no conflicts, both sets of changes coexist cleanly.

This round:

  • The warning (renamed "⚠️ Past daily budget" → "⚠️ Eager consumption") now only shows once the knob clears a full day above the boundary, not merely past it — resting a few points ahead is normal since the boundary itself steps a day at a time. New tooltip: "Autonomous AI will spend tokens more than 1-day faster than the week's pace allows".
  • The enabled/disabled status line now has its own tooltip explaining what it means for the AI queue.
  • The "Quota boundary" tooltip is now its own paragraphs, ending on a fun fact pointing back at the bar.

Also fixes the build check failure on 23fae6b (job 89824836962) — a pre-existing test asserted the old em-dash phrasing of the pace-deviation tooltip, which the <br/><br/> formatting change broke. Updated the assertion to match. Full dashboard suite: 549/549 passing; typecheck clean.


Generated by Claude Code

claude and others added 4 commits July 26, 2026 18:10
…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.

Copy link
Copy Markdown
Member Author

Pushed dfdf6c9/399c381: the "Eager consumption" tooltip now reads the knob's actual deviation instead of the fixed "1-day" — it computes the same pace-deviation duration as the main figure, but of the limit rather than actual consumption (e.g. "spend tokens 1 day faster..." at a 20-point offset, "2 days" at 40). Rebased on top of the "usage bar graphic above" → "usage bar above" wording tweak, and fixed the test that had pinned the old text (which is also what the build failure on 45666bb was — already resolved). 550/550 tests passing, typecheck clean.


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.

Copy link
Copy Markdown
Member Author

Pushed feca9a5: boundaryFromResetsAt() in packages/the-framework/src/quota-boundary.ts now computes percent as the plain continuous elapsed share of the week (elapsedMs / weekMs) instead of a stepped day/7 fraction that only jumped once every 24 hours.

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. day is unchanged, still naming which day of the week now falls on for display purposes.

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 boundary.percent the framework reports.

Updated tests in quota-boundary.test.ts, auto-pm.test.ts, and consumption-guard.test.ts that had asserted the old stepped values. Full framework suite (1381 tests, same 11 pre-existing/environmental failures as every prior round) and dashboard suite (550/550) both pass; typecheck clean on both packages. Added a changeset for @gemstack/the-framework.


Generated by Claude Code

@brillout brillout left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

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

@brillout brillout changed the title fix(dashboard): drop a colliding day label to a second line on the quota bar fix(dashboard): rework the usage panel per #960 — split-bar limit control, pace deviation, continuous quota boundary Jul 26, 2026
@brillout
brillout merged commit 847c041 into main Jul 26, 2026
1 check passed
@brillout
brillout deleted the claude/framework-issue-960-psx76q branch July 26, 2026 19:50
@brillout

Copy link
Copy Markdown
Member Author

Didn't read the code

brillout pushed a commit that referenced this pull request Jul 26, 2026
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
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.

2 participants