Codex early weekly reset remains stale at 0–1% after #3177; 2% publishes normally

Open
#3,248 15 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
52/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
swift

Research direction

Start with Sources/CodexBar/Providers/Codex/CodexWeeklyResetConfirmation.swift, especially makeDelayedCandidate and its prerequisites, then inspect UsageStore+CodexWeeklyResetCandidatePersistence.swift for account-scoped guards. Build a focused regression through the real admission path and file-backed account-snapshot store, including repeated exact low values and a 2% control. Done means diagnostics identify the rejected stage and the valid post-reset state is eventually persisted without accepting rebound or changed-account evidence.

Written by the indexing model from the issue text.

Description

clawsweeper:needs-maintainer-review clawsweeper:needs-product-decision clawsweeper:no-new-fix-pr clawsweeper:source-repro impact:auth-provider impact:ux-friction issue-rating: 🦞 diamond lobster P2

Summary

After an early backend weekly reset, CodexBar continued showing and persisting the pre-reset weekly value of 53% used / 47% left while repeated direct reads from the packaged OAuth helper reported 0–1% used / 99–100% left for the same account, with exact confidence and a materially newer weekly reset boundary.

During the captured stale interval:

  • the account-snapshot file was rewritten at two automatic-refresh checkpoints without advancing the public weekly snapshot;
  • weeklyResetCandidate was absent in both persisted checkpoint records; and
  • manual Refresh left the snapshot timestamp, contents, and visible value unchanged.

A subsequent live inspection at 15:04:47 local time captured the persisted app state at 2% used / 98% left with the newer reset boundary. That later value no longer matched the guarded 0–1% reset shape: above 1%, initialDecision returns .publishInitial, so 2% is eligible for the ordinary publication path without delayed reset confirmation.

The live stale-publication symptom is established. The exact #3177 candidate-creation, compatibility, or persistence predicate that failed is not established by the available evidence. The original 59 ms reset-credit-expiry diagnosis is withdrawn.

Verified release context

#3177 was merged as commit 0a1aa53598c94003a87bcdcca4af88b0ad508421. That commit is an ancestor of the official v0.55.1 tag. This is therefore not a request to ship the already-merged #3177 change; it is a report about the reset shape that change was intended to recover.

Observed evidence

Observation Time, local Public/persisted weekly state Direct OAuth-helper state Delayed candidate
First captured mismatch 14:02 53% used / 47% left; snapshot still reported an older Sep 1 boundary 0% used / 100% left; newer Sep 3 boundary; exact not inspected at this instant
Automatic-refresh checkpoint 14:04:49 account file rewritten; public snapshot still 53% absent in persisted record
Second direct helper read 14:05 public snapshot still 53% 1% used / 99% left; same newer boundary; exact not inspected at this instant
Automatic-refresh checkpoint 14:09:49 account file rewritten again; public snapshot still 53% absent in persisted record
Manual Refresh 14:12 after 12 seconds, file timestamp and contents were unchanged; UI still showed 47% left absent in unchanged record
Final direct helper control 14:13 persisted public snapshot still 53% with Sep 1 boundary 1% used / 99% left with Sep 3 boundary; exact absent in persisted comparison
Later accepted app state 15:04:47 2% used / 98% left with Sep 3 boundary none persisted after publication

The directly captured stale interval runs from the first fresh helper observation at 14:02 through the failed manual refresh at 14:12. Sixty-two minutes elapsed between the 14:02 helper observation and the later 15:04 accepted state, but there is no retained sample for every intervening refresh. This report therefore does not claim that continuous staleness for the full 62 minutes is proven.

The direct packaged-helper reads are provider controls. They establish that OAuth authentication and upstream usage retrieval worked, but they do not establish the exact in-memory payload received by each automatic app refresh.

Why the 2% state is a useful control

In the shipped #3177 logic, the reset threshold is 1%. Confirmation is required only when the previous weekly usage is above 1% and the initial fresh usage is at most 1%; otherwise the initial snapshot publishes normally:

This gives a deterministic interpretation of the later observation:

  1. Fresh values at 0–1% match the guarded reset shape and require confirmation.
  2. A fresh value at 2% does not match that shape and can publish through .publishInitial.
  3. The later 2% publication is therefore not evidence that #3177's delayed-candidate recovery succeeded.
  4. It explains how the visible value could clear without a one-hour quota recalculation or a successful delayed confirmation.

At the two captured automatic-refresh checkpoints, the persisted public snapshot was still 53% and no delayed candidate was present. The evidence does not distinguish among these possibilities:

  • makeDelayedCandidate returned nil because one of its strict prerequisites failed;
  • a candidate was produced but rejected by the account-scoped persistence guard;
  • a candidate was created and discarded between the sampled file writes; or
  • the automatic app refresh received evidence different from the direct helper controls.

Relevant seams:

Correction to the original 59 ms diagnosis

The original comparison normalized the persisted credit expiry to Unix seconds with a fractional component and compared it with the packaged CLI's whole-second ISO-8601 rendering.

That crossed serialization formats:

  • the CLI explicitly sets JSONEncoder.dateEncodingStrategy = .iso8601;
  • the account-snapshot store uses a default JSONEncoder, whose numeric Date representation preserves fractional precision.

Source references:

Those outputs are compatible with the same in-memory Date. The available CLI output does not prove that the previous, initial, and confirmation observations differed by 59 ms inside the app. Exact expiry equality may still be a brittle seam, but it is not established as the cause of this incident, and this report does not request a Date-comparison change.

Expected behavior

When #3177's bounded sequence receives sufficient consistent exact OAuth evidence for the same account, source, plan, reset boundary, and unchanged positive reset-credit inventory, CodexBar should eventually publish the 0–1% post-reset weekly state. The user should not need to consume enough quota to produce a value above the 1% confirmation threshold.

Actual behavior

  • Direct exact OAuth-helper reads returned the fresh 0–1% state and newer reset boundary.
  • At two automatic-cadence file writes, the public snapshot remained at 53% and no delayed candidate was persisted.
  • Manual Refresh did not advance the snapshot, boundary, update time, or visible value.
  • A later 2% state published after the fresh value was above the guarded threshold.

Live reproduction shape

The backend reset is externally timed, so the complete trigger is not locally deterministic.

  1. Begin with a persisted exact OAuth weekly snapshot above 1% used and an old future reset boundary.
  2. Have the backend perform an early weekly reset without consuming the available reset credit.
  3. Use the packaged OAuth helper as a provider control and observe repeated exact 0–1% values with a materially advanced, consistent reset boundary for the same account.
  4. Observe the app through multiple automatic refresh intervals and invoke manual Refresh.
  5. Inspect the persisted account record after each checkpoint for the public weekly state and weeklyResetCandidate.
  6. Separately retain a later observation above 1% as a control for the ordinary publication path.

Requested investigation and safe fix boundary

Please identify the failed candidate stage before changing reset-admission policy. A focused regression should drive the complete sequence through the real admission and file-persistence seams while recording reason-coded outcomes:

  • previous exact OAuth state above 1% with the old future boundary;
  • repeated exact OAuth states at 0–1% with a consistent advanced boundary;
  • stable account, plan, and source;
  • the same observed credit ID, reset type, status, and available count across the sequence;
  • raw in-memory expiry values captured from the same test observations rather than inferred across encoders;
  • at least one refresh after the delayed minimum age;
  • a real file-backed account-snapshot store; and
  • a 2% control observation proving the ordinary publication path.

Diagnostics should distinguish:

  • which makeDelayedCandidate prerequisite failed, if creation returned nil;
  • whether account-scoped candidate persistence rejected the refresh guard; and
  • which compatibility or age check discarded an existing candidate.

Existing safeguards should remain for single transient low samples, account/source/plan changes, non-exact data, non-monotonic timestamps, inconsistent boundaries, missing credit evidence, changed credit identity/status/count, and stale or expired candidates.

A counterexample that must remain rejected is a single 0–1% observation followed by a rebound, or a low sequence whose account, source, plan, reset boundary, or credit identity changes between observations.

Related work

  • #2790: original early-reset stale-quota report.
  • #2897: explicitly-zero-credit subcase.
  • #3179: unchanged-positive-credit follow-up.
  • #3177: merged delayed-candidate recovery intended to address this reset shape; its merge commit is included in v0.55.1.
  • #3194: similar successful-fetch/stale-publication symptom; this report does not claim every instance shares one cause.
  • #3200: automatic-refresh persistence coverage uses 31%, 42%, and 56%, all above the reset-confirmation threshold.

Evidence status

The UI screenshots, persisted percentages and reset boundaries, helper results, file-write times, candidate absence at the two captured checkpoints, and failed manual-refresh result remain valid observations.

Any earlier evidence text attributing the incident to a 59 ms expiry mismatch is superseded. The corrected evidence preserves the raw observations but classifies the exact failed predicate as unknown.

CodexBar-quota-reset-evidence-20260827-1415.zip

Dominant language
Swift
Stars
21.6k
Forks
2k
Avg merge
1d 9h
Merged PRs (30d)
385

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from steipete/CodexBar

All issues in steipete/CodexBar

Similar issues

More Swift issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.