Judge the sweep's cap readiness per agent account, and read a dated reset as a date - #180
Open
MJohnson459 wants to merge 1 commit into
Open
Judge the sweep's cap readiness per agent account, and read a dated reset as a date#180MJohnson459 wants to merge 1 commit into
MJohnson459 wants to merge 1 commit into
Conversation
The nudge sweep asked each badged session's own reading whether its reset had gone by. That rebuilds a fact that is not per-session: a usage cap belongs to the account a session was launched under, so every session on it reports the same window, and the only way two of them can differ is that one is stale — still displaying the window it was capped in hours ago. Judged alone that fossil reads ready, quite correctly, and since #428 nudging it stops a live session to spend a turn the account re-caps at once. The verdict now moves to voro-core as plan_sweep, taken once per agent entry, which is Voro's proxy for the account. One live reading holds every badged session of that agent, untimed ones included; a group with no live reading is swept entire, so a lone untimed cap is still the operator's call. The proxy errs in the conservative direction on purpose: two agent entries sharing an account are not pooled (no worse than judging each session alone), while one entry across two accounts costs a delay rather than a stopped session. The other half is that a weekly cap reads ready days early. Its reset carries a date — resets Aug 17, 9pm — and only the clock half was read, resolved to the nearest occurrence, so it flipped to "reset passed" the moment tonight's 9pm went by. Both halves are read now, dates compared like clocks on a synthetic ordinal of twelve 31-day months, since only the sign of the difference is ever read and no calendar dependency is wanted. The badge still shows the clock and never the date; the sweep's report names both. The status line stops counting sessions before their reset and names the hold: "claude capped until Aug 17 21:00 — 3 sessions". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkiuQnYkEhGcsKvWfbe4kV
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The nudge sweep asked each badged session's own
CapReadingwhether its resethad gone by, and that rebuilds a fact that is not per-session. A usage cap
belongs to the account a session was launched under: every session on it reports
the same window, and the only way two of them can differ is that one is stale,
still displaying the window it was capped in hours ago. Judged alone that fossil
reads ready — correctly, its window did reopen — and since #428 nudging it stops
a live session to spend a turn the account re-caps at once. Separately, a weekly
cap read as ready days early: its reset carries a date (
resets Aug 17, 9pm),only the clock half was read, and resolved to the nearest occurrence it flipped
to
⚠ capped · reset passedthe moment tonight's 9pm went by.What changed.
voro-core/src/cap.rs:CapReadinggainsreset_date, parsed from themon dimmediately before the clock in the same post-signature window that alreadyfed the clock parse.
reset_passedis now defined in terms of a signedminutes_until, so the sweep can rank two live readings; where reading andclock both carry a date the date decides, compared nearest-occurrence on a
synthetic ordinal of twelve 31-day months. Only the sign of that difference is
ever read, so short months and leap years do not enter into it and no calendar
dependency is needed.
LocalNowcarries the clock and today's date together.plan_sweep(new,voro-core): takes the badged readings as(task, agent, reading)plusnow, returns the task ids to nudge in ascending order and oneCapHoldper held agent. One live reading holds its whole group, untimedsiblings included; a group with no live reading is swept entire, so a lone
untimed cap is still the operator's call. The hold is labelled with the
furthest-out live reset — the binding one. Grouping by agent entry is Voro's
proxy for the account and errs conservatively on purpose: two entries sharing
an account are not pooled (no worse than judging each session alone), while one
entry across two accounts costs a delay rather than a stopped session.
voro/src/app.rs:nudge_cappedpairs each cap with its agent vialast_sessions(a task whose session has vanished names no agent and isskipped), calls
plan_sweep, and nudges through the unchangednudge_one. Thestatus line stops counting sessions before their reset and names the hold:
claude capped until Aug 17 21:00 — 3 sessions, ornudged 2 capped sessions — codex capped until 21:50 (1 session)when mixed.App::now_minutesbecomesApp::now: Option<LocalNow>.voro/src/session_probe.rs:local_minutesbecomeslocal_now, onesubprocess returning clock and date (
date '+%H:%M %m-%d') so a reading takena second before midnight cannot pair yesterday's date with today's clock.
voro/src/ui.rs: the badge keeps its three shapes and still shows a clock andnever a date; it inherits the corrected verdict, so
⚠ capped · reset passedstops appearing days early.
docs/DESIGN.md§8 records account-scoped readiness, the agent-entry proxy andboth directions it can be wrong in, that the model is read off Claude Code and
other agents may cap differently, the dated comparison behind a clock-only
badge, and the untimed-sibling rule.
CHANGELOG.mdamended under unreleased.How it was verified.
cargo test --workspace(892 pass),cargo clippy --workspace --all-targets -- -D warningsandcargo fmt --all --checkallclean. New
cap.rstests cover the dated parse, a reset three days out at everyhour of today, a date two days behind, both directions across the year boundary,
a date with no clock and a date-shaped fragment with no signature; every existing
undated case keeps its answer. New plan tests cover a fossil beside a live
sibling of the same agent, the same two under different agents, an untimed
reading alone and beside a live sibling of the same and of a different agent, the
furthest-out label, an unknown clock, and ready-id ordering. The five existing
utests stay green in substance (only the held case's status string changed),joined by one for a weekly cap dated three days out and one for two same-agent
sessions where a single text is fresh — both driving the real key handler against
a scratch store with real stub agent verbs. The badge test draws the real cockpit
and asserts a dated future reset badges
⚠ capped ↻21:00with no date and no"reset passed".
Not verified through a live TUI drive: the
verifyskill isolates config withXDG_CONFIG_HOME, which this session's worktree guard refuses, and voro has noconfig flag to isolate it another way. The paths that would have shown are
covered by the tests above, which run the real subprocess verbs.
One thing to sequence. #441 (in review,
cap-epoch-441) also makes the capreading account-scoped, from the other end — an exact instant from a
capverb,resolved in
CapWindow::resolve. The two do not conflict in substance but do incap.rsandnudge_capped, and the seam holds a real decision (shouldplan_sweeptake the account instant as a group-level input; which speaks whenan account instant and a further-out screen reading disagree). Filed as task #460
rather than decided here.