Skip to content

Codex account-status parity with Hermes Accounts tooltip: quota, sign-in health and actionable checks #40

Open

Description

@Majber

Summary

Codex account status in Resetwatch can disagree with Hermes Desktop's model/account tooltip. Some differences are expected because the views refresh independently, but Resetwatch currently drops invalid/expired logins before producing a status row, and cached quota percentages can be mistaken for current availability after a window reset.

Please distinguish live quota, cached/expired quota observations, and sign-in health, so users can tell which account has a quota cap versus which credential needs reauthentication.

Environment and scope

  • Linux, Hermes Desktop with local gateway, default profile, multiple Codex OAuth pool entries.
  • Updated installation: catalog Resetwatch v0.2.21, commit d460334db633fbaa91f0f8b96679e8463bad2a04. Verified both the installed catalog package and the Desktop-loaded plugin.js report 0.2.21.
  • Post-update source inspection confirms that the installed 0.2.21 probe still skips dead/expiring Codex entries and returns cached snapshot lists without their original fetched_at envelope. Account-ID deduplication is present. After updating, user-provided screenshots confirm that the quota windows agree between the two views, but the Desktop tooltip includes a sign-in-required account that Resetwatch omits.
  • Also inspected current main f0dc5704e20945b6b53618920462c56142dc6d29 before filing: account-ID deduplication and the newer popup's cache/staleness labels already exist. This report does not request those features as if they were missing upstream.
  • No credential refresh, auth-store mutation, or inference request is required for the usage probe.

Confirmed behavior in v0.2.21 and requested account-status parity

In v0.2.21, screenshots of Resetwatch and Hermes Desktop’s Accounts tooltip show matching quota values when compared by the same window. The tooltip summarizes the tightest relevant window; Resetwatch shows Session and Weekly separately. The remaining functional gap is the account roster and actionable authentication status: the tooltip shows Sign in again for an account absent from Resetwatch.

A targeted hermes auth refresh openai-codex <entry-id> for that account also failed with the saved session is no longer valid; sign in again. This was an explicit diagnostic action outside Resetwatch, not a proposal to make the background usage probe refresh tokens. Earlier direct usage requests returned HTTP 401 token_revoked. The revocation cause is not established.

Desired UX: the same useful answers as the Accounts tooltip and a targeted diagnostic check

For every configured account, show a compact summary alongside its detailed windows:

  • Available: latest usage API succeeded and reports allowance available; label this as quota/auth verification, not proof of successful inference for every model.
  • Usage limit reached — resets at …: authenticated but a relevant quota window blocks usage; no re-login recommendation.
  • Sign in again: known revoked/invalid grant, or failed renewal confirming the saved session cannot be renewed.
  • Expired token / not checked: access token cannot be queried read-only; do not assume its refresh grant is invalid.
  • Unknown / check failed: network/server error, stale data, or unsupported response; no fabricated quota or false sign-in instruction.

Also show the account label, a privacy-preserving identity (masked email if available), active-account marker where Hermes exposes it, last actual vendor check time, the tightest relevant window summary, and expandable Session/Weekly/additional windows. Keep account counts consistent with identity-based deduplication. If one account has valid and revoked credential entries, show the account as available via the healthy entry and expose the bad duplicate separately if helpful.

Provide a Check status / Refresh usage action using the read-only vendor usage endpoint and existing backoff. For an authentication problem, show actionable guidance or a supported Hermes sign-in action. If an explicit user-triggered Renew sign-in action is feasible, delegate it to Hermes’s supported credential manager for the exact entry rather than directly rotating tokens in the probe; distinguish successful renewal from continued quota exhaustion. Never renew tokens on a Resetwatch polling timer. A permanently invalid grant requires interactive sign-in; do not promise automatic reauthentication or bypass login/2FA.

Prefer a supported shared Hermes account-status source when available, so Resetwatch and the Accounts tooltip agree on identities and auth status. Preserve read-only probing rather than importing private helpers with auth-store write side effects.

Current code findings

In main probe.py::_codex_pool_accounts:

  • last_status == "dead" is skipped;
  • missing tokens and tokens considered expiring are skipped;
  • only the remaining entries become fetchers/cards.

Consequently a known configured account can disappear instead of showing a sign-in/unknown status. Expiring access tokens must not automatically be described as revoked grants: Resetwatch deliberately does not refresh OAuth, and Hermes may still be able to renew them.

Current main correctly deduplicates account IDs. Please retain that improvement, but ensure mixed healthy/revoked entries for the same account yield one usable account row rather than a misleading account-wide sign-in failure.

The probe cache stores a fetched_at timestamp, while _read_probe_result_cache() returns the snapshot list. The UI's fetchLiveCards() reports a new checkedAt: Date.now(). A UI refresh that reuses the probe cache is therefore not necessarily a new vendor observation. The popup now has stale/offline labels; preserving the actual observation time through this boundary would make those labels more reliable.

Reproduction scenarios

A. Invalid credential silently disappears

  1. Have a configured Codex pool account whose only entry is dead (or whose access token has expired).
  2. Open/refresh Resetwatch and compare its account roster with Hermes Desktop's account tooltip.
  3. Actual: the entry is skipped before fetching, so no actionable status card is emitted.
  4. Expected: show a nonnumeric status row: reauthentication required for a known dead grant; expired/not checked for an access token that cannot be queried read-only.

B. Cached exhausted window crosses its reset

  1. Cache a session window at 100% used with reset time shortly in the future.
  2. Keep/show the cached snapshot after that timestamp, before a successful new vendor fetch.
  3. Expected: retain the historical percentage only with an explicit observation time and reset elapsed / awaiting refresh state; do not imply either continued exhaustion or guaranteed replenishment until checked.

C. Mixed credential health for one account

  1. Have two entries for the same OpenAI account, one valid and one revoked.
  2. Expected: one account row, using the valid entry's quota; optionally disclose a stale credential separately. A bad duplicate should not make the entire account unavailable.

Requested behavior / acceptance criteria

  • Keep configured Codex accounts visible when quota cannot be fetched, with explicit unknown/expired/sign-in-required status and no invented percentage.
  • Separate account availability (allowed, limit_reached, relevant windows) from local credential cooldown and authentication state.
  • Display both session and weekly windows (and any named additional limits already supported); make clear that one exhausted relevant window can block usage despite remaining weekly allowance.
  • Carry the actual vendor observation timestamp through cached probe results and UI caching; distinguish it from the time the UI last requested data.
  • Mark an exhausted cached window whose reset has elapsed as pending recheck, not a definitive current limit and not automatically refilled.
  • Preserve account-ID deduplication and read-only credential handling. Prefer a usable credential when the same account has mixed credential health.
  • Preserve current polling/backoff limits; no need for aggressive polling or token refresh in the plugin.

Suggested regression tests: post-update tooltip/Resetwatch account-roster parity; available versus quota-limited versus revoked/expired/unknown status; mixed-credential active-account identity; targeted user-triggered check and renewal outcomes; dead-only account; expiring-token-only account; healthy+revoked duplicate; cached exhausted window crossing reset; UI refresh served from probe cache preserving observation time; session exhausted with weekly allowance remaining.

No email addresses, account IDs, tokens, or full auth files are included.

Suggested implementation plan (proposal, not a tested patch)

Implement the read-only status/accuracy changes first; account selection and interactive renewal can be a separate follow-up.

  1. Separate account inventory from fetch eligibility in probe.py. Retain configured rows even when dead, missing an access token, or expiring. Group by provider + normalized route host + decoded OpenAI account identity; use a credential-scoped opaque fallback when identity is unavailable. Keep secrets internal. Do not deduplicate by label or email. An identity decoded from a JWT is grouping metadata, not proof that the credential is accepted by OpenAI.
  2. Evaluate credentials within each account group. Prefer a non-dead, non-expiring candidate. If it receives an auth failure, try another eligible candidate for that same account within the existing time budget. Emit one account row: one successful candidate wins over failed duplicates; only a group with no usable candidate gets an auth/unknown row. No token refresh and no auth-file writes in background polling.
  3. Add optional, backward-compatible status metadata to snapshots. Suggested fields (names are illustrative): auth_state, quota_state, observed_at, last_attempt_at, source, and a sanitized reason_code. Use empty windows/null percentages for status-only cards, not zero. Preserve the last successful observation separately from the latest failed attempt. Extend the snapshot keep/filter logic so status-only configured-account cards survive through collection, serialization, UI normalization and both renderers.
  4. Classify results without conflating failures. Known local dead/revoked grant or vendor token_revoked -> sign-in required for that credential. Expiring access token -> expired/not checked, not necessarily a dead refresh grant. Generic 401 -> authentication problem, renewal may help; do not assert permanent revocation without evidence. Timeout/5xx/unrecognized body -> unknown/check failed. Usage HTTP 200 means auth/usage lookup succeeded, not model inference tested; use allowed, limit_reached and relevant quota windows to describe quota. Preserve model-specific scope and paid-credit semantics rather than treating every extra model limit as an account-wide block.
  5. Propagate observation age through both caches. Stamp successful per-account fetches at the vendor response, preserve that timestamp on probe cache reads, and carry it through fetchLiveCards() and persistent UI cards. Keep checkedAt/last-attempt time separate. Older cache entries lacking observation metadata should show age unknown or be re-fetched, not receive a new vendor timestamp. Reconcile cached roster with current configured accounts so removed/replaced credentials do not linger or hide newly configured accounts; a non-secret inventory fingerprint can invalidate roster cache while honoring the manual-refresh floor.
  6. Render status consistently in the full page and popup. Reuse one derived-status helper for badges, compact tightest-window summary and detail windows. Retain expired/invalid accounts with actionable text. After an exhausted cached window passes its reset timestamp, display reset elapsed / awaiting check; do not fabricate replenishment or retain a definitive exhausted-state claim. Preserve existing stale/offline indicators and locale support.
  7. Actions and integration. Reuse the existing manual fresh-usage path and polling/backoff limits for Check status. Initially provide safe sign-in guidance. Add active-account identity or explicit Renew sign-in only through a supported Hermes API, with exact credential targeting and explicit user consent; provider-level sign-in can replace a singleton rather than repair the intended pooled entry. Do not invent an RPC or shell-login automation, and do not modify grants from the read-only probe. Share the supported account-status source with the Accounts tooltip if practical.
  8. Targeted tests and packaging. Use mocked usage responses and a frozen clock: dead-only and expired-only groups remain visible; valid+revoked duplicate yields one available row; all-invalid duplicates yield one sign-in row; same identity on different hosts is not merged; 200 available/limited and 401/5xx are distinguished; cached exhausted window crosses reset without invented quota; cached reads preserve original observation time; roster changes invalidate old cards; full-page/popup status-only rendering agrees. Run the relevant probe/UI tests, then regenerate the catalog artifacts using the repository's normal build process so standalone and catalog distributions stay aligned.

This is deliberately an incremental plan: it does not require automatic re-login, additional inference requests, aggressive polling, or private Hermes helpers that mutate credential stores.

Activity

  1. changed the title [-]Codex status accuracy: show invalid logins and preserve quota observation time across caches[/-] [+]Codex account-status parity with Hermes Accounts tooltip: quota, sign-in health and actionable checks[/+] on Oct 12, 2026
  2. Adolanium commented on Oct 13, 2026

    @Adolanium
    Owner

    Thanks for the detailed report. In #41 a dead or expired Codex login now shows as a card that says why, instead of disappearing. I'll handle keeping the real check time through the cache separately.

  3. Adolanium commented on Oct 17, 2026

    @Adolanium
    Owner

    #43 carries the real check time through the cache. Each probe snapshot keeps observed_at from the vendor's answer, and the page and popup show that time and base the stale marker on it, not on when the UI asked. It's in catalog-v0.2.23.

    Still open from this report: grouping mixed-health credentials per account, and the user-triggered check and renew actions. I'm keeping this issue open for those.

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions