Skip to content

Free reset never offered for a seat blocked by credits AND an exhausted window #38

Description

Symptom

A seat that is blocked by both a credits flag and an exhausted usage window is never offered the free reset that would unblock it. The grant sits unused until it expires.

Live example from 2026-09-20: backup1 shows

backup1  team  100% · in 1h23m (Mon 00:09)   31% · in 6d15h   none   RESETS 1   cooling (credits) until 11:45 PM
  backup1: backend reports workspace_member_credits_depleted

It holds 1 grant expiring 2026-10-04, and its 5h window is exhausted — precisely what a "Full reset (Weekly + 5 hr)" lifts — yet it is filtered out of reset_eligible_seats.

Cause

src/seat.rs:189-221:

let cooling = st.cooldown_until.is_some_and(|u| u > now);
let reason = CooldownReason::parse(st.cooldown_reason.as_deref().unwrap_or(""));
if cooling && !reason.is_lifted_by_reset() {
    // A per-model cap, credits or a spend cap all survive a reset.
    return None;
}

is_lifted_by_reset is true only for RateLimit (src/ratelimit.rs:51). The comment's reasoning is sound when credits are the only block, but verdict() checks rate_limit_reached_type before the windows (src/usage.rs:1066), so a seat that is window-exhausted and credit-flagged records credits and the window exhaustion underneath becomes invisible to the eligibility filter.

This is the same error as #37 in the opposite direction: credits only matter once included quota is gone, so restoring the quota makes the credits block irrelevant.

Suggested direction

Treat a seat as reset-eligible when its own enforced window is at 100% with a reset still ahead, regardless of whether the recorded cooldown reason is credits — because a reset lifts that half, and with quota restored the seat no longer needs credits.

What needs verifying first

I have not confirmed that the backend stops reporting workspace_member_credits_depleted once the window resets. That assumption is what the fix rests on. seat reset --dry-run lists grants without redeeming, so it cannot settle it; only redeeming can, and a failed attempt still spends a finite grant.

Mitigating factor: clear_window_cooldown_after_reset already declines to clear when the refreshed reading still says exhausted, so the machinery fails safe — it would just have wasted the grant.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions