Skip to content

feat(quota-plane): quota credential lifecycle — expiry watch, renewal surfacing, per-provider renewal paths #1269

Closed

Description

@dezren39

Part of epic #1149; generalizes #1251 item 3. Priority P1. Problem observed 2026-10-26: the claude quota credential had EXPIRED silently ("Claude session expired. Open Claude Code to sign in again") — discovered only by running the CLI by hand. The fleet's quota credentials all expire on their own clocks: Claude Code OAuth session, Open Design Better Auth cookie (sandbox session expires 2026-11-02), Codex token-sharing logins (~1h tokens), Cline WorkOS session, Go console session. Today nothing watches any of them.
Feature: a credential lifecycle pass inside the gatherer tick — per managed/quota credential: type, issued/expires (where knowable), last-verified, state (ok / expiring <=48h / expired / rejected). Expiring/expired states surface as (a) a card state on /quota, (b) an attention item in the hub payload, and (c) a user/owned task for the ones only Drew can renew (browser SSO re-login), raised BEFORE expiry when the expiry is knowable. Renewal paths documented per provider in the registry (who renews, how, where the new credential is filed).
Acceptance: the lifecycle table exists for every credential the quota module reads; expiring the claude credential in a test produces the attention item + task; no credential value ever appears in output.

Acceptance criteria

  • The expiry watch covers every credential the quota plane depends on (OpenCode Go key, ClinePass JWT + refresh token, Open Design session cookie, Antigravity accounts, Meta OAuth token) and names each one's expiry or absence.
  • Each credential's renewal path is the one already proven for it; no credential is renewed through an unproven route.
  • An expired-or-missing credential is surfaced as a finding before it takes a provider dark, not after.

Activity

  1. developing-today commented on Oct 27, 2026

    @developing-today
    Contributor
  2. added
    kind/featureNew feature or capability request
    source/humanFiled directly by a human
    priority/normalOrdinary priority (the default)
    effort/mMedium: expected under 1 day of work
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 28, 2026
  3. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    Intake review

    Fleet-monitor intake pass (protocol §5), 2026-10-28. Filed with only meta/follow-up; labels normalised in this pass (kind/feature, source/human — author dezren39 — status/needs-triage, priority/normal, effort/m). The body's Acceptance line named the credential set and the session-end silent-death failure mode (ClinePass JWT, 2026-10-26); the appended criteria restate it in checkable form.

    Still live: no merged or open PR references this issue (checked 2026-10-28T01:47Z); nothing has implemented it yet.

    Related: part of epic #1149; sibling #1270 (reconciliation diff) is the natural consumer of this watch's findings, and #1268 (parallel fetching) covers the same providers' read path.

    Notes / risks: credential handling must stay reference-by-name only — the watch reports expiry/absence, never values. Renewal paths differ per credential and some need Drew at a console; the watch should surface those early rather than attempt them.

    Suggested approach: inventory every credential the quota plane reads, record expiry source per credential, and emit findings into the same stewardship surface #1270 uses.

  4. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    event: picked_up
    task: 2531 (repo-health-code-pilot, openchamber scheduled lane)
    state: Claimed triage; checking current issue, ownership and current-main evidence before routing.

  5. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed on Nov 1, 2026
  6. 74 remaining items

  7. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/triageQueue packet kind: verify, reproduce, and route this item
    on Nov 3, 2026
  8. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    state: triaged (coverage pass)
    Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as triage at priority 40 (priority/normal). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
    Found via: coverage pass 2026-11-03

  9. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 3, 2026
  10. added a commit that references this issue on Nov 3, 2026
  11. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    Landed — implementation merged (queue task 7669, 2026-11-03)

    PR #4853 (feat(quota-plane): surface credential lifecycle (#1269)) merged as bc50cba06 onto main; --delete-branch removed the remote branch (queue/4981-1269-quota-credential-lifecycle-resume).

    Verification at the PR head c8cf4467d (laptop, not just the author's claim): bun test test/credential-lifecycle.test.ts test/quota-gather-map.test.ts test/quota-contract.test.ts in pm-stack/aggregator → 59 pass, 0 fail, 549 expect() calls. No CI workflow covers this path (the only check is CodeRabbit, which skipped), so the merge rested on that targeted run plus the diff review below.

    Diff reviewed against the 2026-11-03 ruling (Muse acting for Drew):

    • credential-lifecycle.ts introduces the lifecycle states ok / expiring (≤48h) / expired / rejected / provider-error / not-configured / unknown. unconfigured maps to not-configured, provider errors stay provider-error, and only explicitly recognised rejection text maps to rejected — so a missing credential is never surfaced as an auth failure.
    • safeProviderReason redacts bearer tokens, JWTs, *token/secret/password/cookie/api_key assignments and sk-… keys, and caps reasons at 240 chars, before any feed, heartbeat or log output. The gatherer change reads only Claude expiry metadata (expiresAt, source class) and discards the credential object.
    • Renewal is surfaced as a user-owned next step only for the one proven route (Claude: Claude Code / OpenCode / environment sign-in, phrased by credential source). #1270 reconciliation is untouched, per the ruling's boundary.

    Acceptance criteria:

    • Expiry watch covers the credentials the quota plane reads: the Claude credential now reports expiresAt + source; every other credential appears with an explicit state (not-configured when the provider set says it is unconfigured; unknown when no expiry is knowable) rather than silently absent.
    • Renewal paths stay proven-only — the only automated/attention path added is Claude sign-in, the route already documented for it.
    • An expired credential surfaces before it takes a provider dark when the expiry is knowable (≤48h expiring state + attention item), which is the observed 2026-10-26 failure mode.
    • No credential value appears in output (redaction + metadata-only read).

    Follow-ups that remain, deliberately not in this PR: the Open Design cookie, ClinePass JWT, Antigravity accounts and Meta OAuth token need their own expiry sources before they can report a real expiresAt — they currently report unknown/not-configured, which is honest but not yet the full watch the epic wants.

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

Metadata

Metadata

Assignees

Labels

effort/mMedium: expected under 1 day of workkind/featureNew feature or capability requestmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedmeta/follow-upFollow-up spun out of earlier workmode/onlineFully doable remotely: design, config, code, cloudpriority/normalOrdinary priority (the default)source/humanFiled directly by a humantask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions