Repository navigation
Main-account hard lock never releases when the blocking 5h window stops being observed #6244
Description
Client or integration
OpenCodex dashboard
Area
Authentication and account pool
Summary
The 98% main-account hard lock (codexMainAccountHardLock) can never release when the observation that blocks it is a 5h (shortPercent) window that no longer appears in any new observation. The stale evidence is carried forward forever, so mainAccountHardLock.state stays blocked, the main account is permanently excluded from the pool, and the dashboard shows a permanent 98% protection badge for an account whose live weekly usage is 0%.
Observed for 19 days on this machine: every restart, every ocx account refresh openai, and the built-in runMainAccountHardLockRecovery() sweep produced the same blocked state.
Why it cannot self-heal:
getMainAccountHardLockStatus()(src/codex/main-account-hard-lock.ts:67-74) blocks while any governing window reads >= 98, and documents the release rule: "A predicted reset is not evidence of recovery either way: only a fresh lower reading releases." Because the blocking reset is in the past,resetAtis omitted from the status (line 73), so the dashboard renders a badge with no reset countdown.assignCarriedShort()(src/codex/quota.ts:257-269) deliberately refuses to expire blocking evidence:preserveBlockingEvidence = policyEvidence && shortPercent >= 98 && shortPercent <= 100, and only the!preserveBlockingEvidencebranch consultsshortResetHasElapsed(). The comment states "a reset clock cannot retract blocking hard-lock evidence".- This account's new observations never contain a 5h window:
quotas.__main__carries onlyweeklyPercent, andhistory.accountshas no__main__entry at all. So no freshshortPercentcan ever overwrite the 2026-09-11 reading, and nothing else is permitted to retract it. runMainAccountHardLockRecovery()(src/codex/auth-api/pool-mode-gate.ts:79-150) behaves as designed — it passes the "reset is already in the past" guard and keeps probing with backoff — but can only ever receive the same weekly-only snapshot. It retried for 19 days without effect.- Policy evidence has no TTL by design ("Policy evidence deliberately outlives the legacy six-hour rotation-cache TTL",
src/codex/quota.ts:693-697), so the stale tuple survives every restart.
ocx doctor additionally reports the usage probe failing, which cannot help either: https://chatgpt.com/backend-api/wham/usage -> error=timeout, 8010ms, authenticated, with PROBE_TIMEOUT_MS = 8000 (src/cli/doctor.ts:304). The same URL through the same outbound proxy returns 401 in 0.83s (curl -x http://127.0.0.1:7890 https://chatgpt.com/backend-api/wham/usage), so the route is healthy and the failure is probe-side.
Expected: a blocking reading whose window has already reset, and which no longer appears in any new observation, should not hold the lock indefinitely. Either apply the freshness rule that already exists for routing (isTerminalShortWindow() / TERMINAL_SHORT_WINDOW_FRESHNESS_MS in src/codex/quota-types.ts) to the policy windows, or drop a carried blocking tuple once no short window has been observed for N windows and degrade the state to unknown (which admits), or surface it as an operator-actionable state instead of a silent permanent blocked.
Reproduction
- Have a ChatGPT main account (native Codex App login,
authMode: forward, planprolite) whose 5h window is observed once at >= 98%. Here that was 2026-09-11. - Afterwards, have observations report only the weekly window (the plan/endpoint no longer returns a 5h window).
- Wait past
shortResetAt; restart the proxy (ocx service repair); runocx account refresh openai; leave it running for weeks. - Observe
GET /api/codex-auth/accounts(headerx-opencodex-api-key) still returning{"enabled":true,"state":"blocked"}for__main__, with noresetAt, whileweeklyPercentis 0. - Confirm the evidence is frozen:
~/.opencodex/codex-quota-cache.json->mainPolicyQuota.quota.shortObservedAtstays at 2026-09-11 whileupdatedAtkeeps advancing with weekly observations.
Verification after the workaround below: the same endpoint returns {"enabled":true,"state":"ready"} and the state does not regress, because weekly-only observations never re-add the short tuple.
Version
2.71.0
Operating system
macOS 26.6.2 (25G83), arm64
Provider and model
openai / Codex account pool (authMode: forward, main account plan prolite); models gpt-6-astra, gpt-5.6-luna
Logs or error output
GET /api/codex-auth/accounts (unchanged across restarts for 19 days):
{"id":"__main__","isMain":true,"plan":"prolite","paused":false,"needsReauth":false,
"mainAccountHardLock":{"enabled":true,"state":"blocked"},
"quota":{"weeklyPercent":0,"weeklyResetAt":1791303196,"resetCredits":1,"updatedAt":1790698396180}}~/.opencodex/codex-quota-cache.json -> mainPolicyQuota.quota:
{"updatedAt":1790698396180,
"weeklyPercent":0,"weeklyResetAt":1791303196,"resetCredits":1,
"shortPercent":100,
"shortObservedAt":1789098096600,
"shortResetAt":1789111776,
"shortWindowSeconds":18000}shortObservedAt = 2026-09-11T03:41:36Z, shortResetAt = 2026-09-11T07:29:36Z. The updatedAt field keeps moving because weekly observations keep landing, so the record looks fresh while the only honest age signal (shortObservedAt) is never consulted by the lock path.
ocx doctor:
WHAM reachability
-- https://chatgpt.com/backend-api/wham/usage
error=timeout, 8010ms, authenticated
Redacted configuration
{
"openaiProviderTierVersion": 1,
"activeCodexAccountId": "chatgpt-##########",
"codexAccounts": [
{ "id": "chatgpt-##########", "plan": "prolite", "isMain": false, "logLabel": "pe17f2a", "alias": "<secondary>" }
],
"providers": {
"openai": { "adapter": "openai-responses", "baseUrl": "https://chatgpt.com/backend-api/codex", "codexAccountMode": "pool", "authMode": "forward" }
}
}codexMainAccountHardLock is absent, i.e. the default (enabled). The main account is __main__ (native Codex App login) and is not listed in codexAccounts.
Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Workaround that unblocked this machine: with the proxy stopped, delete shortPercent, shortObservedAt, shortResetAt and shortWindowSeconds from mainPolicyQuota.quota in ~/.opencodex/codex-quota-cache.json (keep the weekly fields), then start. mainAccountHardLock.state immediately becomes ready and stays there. Setting codexMainAccountHardLock: false also works but gives up the protection entirely.
Related: #3552 (window-aware main-account hard lock), #6153 (pace hard-lock recovery and quota retries), #5743 (bundle L4 — 98% main lock).
Activity
github-actions commentedon Sep 29, 2026
Issue reopened
The report now contains the information required by the automated check. Thanks for updating it.
lidge-jun commentedon Sep 30, 2026
Fixed by #6287 (merged as f69918c). The main-account hard lock now releases on a fresh 5h reading below the threshold, or when WHAM explicitly reports the 5h window as absent and the weekly window is measured. Partial readings and elapsed reset times still keep it locked. It should clear on the first usage refresh after you update. If it stays stuck on a build that includes this fix, please reopen with the
ocx statusquota section.Howard-Jerry commentedon Oct 11, 2026
Real-world confirmation that #6287 released a previously-stuck lock, observed on this machine (macOS, arm64).
Timeline on @Howard-Jerry machine:
Installed build at the time:
@bitkyc08/opencodex@2.73.0(pre-fix(codex): retire main hard lock on authoritative absent 5h window #6287). WithcodexMainAccountHardLock: true, the main account stayedblockedacross proxy restarts andocx account refresh openai, consistent with this issue: carried short evidence with only weekly observations. End users saw only the bare client errorexceeded retry limit, last status: 429 Too Many Requestson the Responses path (the informative policy body did render on a non-streaming image call: "Codex main account is blocked by the 98% main-account quota policy...").After upgrading to
2.83.0and keeping the lock enabled, a forcedocx account refresh openaiproduced the release immediately, exactly matching the fix(codex): retire main hard lock on authoritative absent 5h window #6287 semantics (primaryabsent + measured weekly):main w***8@gmail.com pro weekly 0% resets 2026-10-17T13:54:40.000Z
GET /api/settings →
"mainAccountHardLock":{"enabled":true,"state":"ready","thresholds":{"short":90,"long":98}}Model-path smoke test (bundled codex-cli 0.162.0-alpha.17.2, gpt-6.1-sol, low effort) completed normally while the lock was enabled and
ready.So: no reopen from us — the release-on-fresh-observation behavior is verified working on 2.83.0. One note for future searchers landing here via the
exceeded retry limit, last status: 429text on pre-fix builds: the immediate local workaround iscodexMainAccountHardLock→ off (Settings), and the durable fix is upgrading to a build that includes #6287. If it ever gets stuck again on a current build, this thread asks for theocx statusquota section — attaching ours for reference.Thanks for the fast fix and the clear release semantics.