-
Notifications
You must be signed in to change notification settings - Fork 1.1k
fix(codex): warm up new ChatGPT Free accounts instead of blaming the credential (#4126) #4230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| # Dispatch packet — L3 (revision 5) | ||
|
|
||
| Round unit: `devlog/_plan/260911_lane_dispatch_round` on `dev`. Base freeze: `origin/dev` `6d3ad12e3` (2.51.0). | ||
| Five audit rounds shaped this packet. The last one was a seven-lane feasibility check that asked whether each stack is implementable inside its owned paths; three lanes came back with gaps, and the fixes are folded here. `010_lane_partition.md` is the authoritative ownership list; `130_wp4_feasibility.md` records why each path was granted. | ||
|
|
||
|
|
||
| ## Shared frame | ||
|
|
||
| **Repository.** Your worktree is named in your packet, already checked out on your lane branch, cut | ||
| from `origin/dev` `6d3ad12e3` (2.51.0). Work only there. Do not add, move, or remove a worktree. | ||
|
|
||
| **Loop.** Run `$codexclaw:cxc-loop` as HOTL for your lane: one work-phase per issue, in order. Your | ||
| goal ends when your last PR is green and reported, not when the code looks right. | ||
|
|
||
| **Subagents.** Unlimited `xai/grok-4.6` subagents, read-only, spawned with `spawn_agent` | ||
| (`model: "xai/grok-4.6"`). Use them to reproduce, to read the call sites you are about to change, to | ||
| find a second caller of a helper you are touching, and to review your staged diff adversarially | ||
| before you push. A finding enters your work only with an exact `path:line` anchor. Subagents never | ||
| write, commit, push, or call a mutating `gh`. Treat a `fail` verdict the way this round did: fold it | ||
| in and re-audit. This packet is at revision 3 because two audit rounds rejected revisions 1 and 2. | ||
|
|
||
| **MUST NOT.** | ||
|
|
||
| - No local product suite: no `bun test`, no `bun run test`, no `bun run test:changed`, no | ||
| `bun run typecheck`, no `bun run build:gui`, no `bun install`. Report them as `NOT RUN`. | ||
| - No merge, no release, no force-push to a shared branch, no direct push to `dev`. | ||
| - No path outside your owned list, including paths a carried PR happens to touch. Dropping a hunk | ||
| from a carried PR is expected; report what you dropped. | ||
| - No locale key in `gui/src/i18n/*`. If you need one, stop and report. | ||
| - No security write-up in `devlog/`; scratch space only, per `AGENTS.md`. | ||
|
|
||
| **MUST.** | ||
|
|
||
| - Prefix every mutating git command with `git -c core.hooksPath=/dev/null`. This repository's hooks | ||
| can start a GUI install, typecheck, and build, which the no-local-suite rule forbids. | ||
| - Push with `--no-verify`. | ||
| - Write the focused regression test `AGENTS.md` requires for a behaviour change, in the domain | ||
| directory beside the existing tests for that subsystem, and register it in both | ||
| `scripts/test-layout/layout.json` `explicit` and `tests/fixtures/test-layout-expected.json`. You | ||
| will not run it; hosted CI will. Those two maps are append-only and other lanes are adding to them | ||
| too; the orchestrator resolves the conflicts at merge, so do not skip the entry. | ||
| - Fill every section of `.github/PULL_REQUEST_TEMPLATE.md` and put `Closes #<issue>` in the body. In | ||
| **Verification**, state that the local suite, typecheck, and build were `NOT RUN` by operator | ||
| instruction and that hosted CI on the exact pushed head is the proof. | ||
| - When you carry another author's PR, add a `Co-authored-by` trailer in a branch commit. Resolve the | ||
| address with `gh api users/<login> --jq '.id'` and use `<id>+<login>@users.noreply.github.com`. | ||
| - Keep a devlog unit under `devlog/_plan/260911_l<N>_<slug>/`. | ||
|
|
||
| **Stacking.** First PR targets `dev`; the second targets the first PR's head branch, the third the | ||
| second. Retarget a child to `dev` after its parent lands. No native GitHub stacks. | ||
|
|
||
| **Decisions already made for you.** Both audit rounds found items where the issue left a real choice | ||
| open. Those calls are recorded in your packet in bold. Implement the recorded decision; if you think | ||
| it is wrong, report the reason and stop. | ||
|
|
||
| **Stop conditions.** Stop and report when the fix needs a path you do not own, when it needs a policy | ||
| no issue has fixed, when a locale key is unavoidable, or when hosted CI fails for a reason outside | ||
| your diff. | ||
|
|
||
| **Report format.** Per PR: number, exact head SHA, CI run id and conclusion, the issue it closes, the | ||
| co-authors credited, the hunks you dropped from a carried PR, and any decision you made. Say | ||
| `NOT RUN` for local checks. | ||
|
|
||
| **Decision boundary.** You do not merge, do not close another author's PR, and do not rank your lane | ||
| against another. When your last PR is green, report and stop. | ||
|
|
||
| ## L3 — Codex account pool | ||
|
|
||
| Worktree `~/.codex/worktrees/260911-l3/opencodex`, branch `codex/260911-l3-account-pool`. | ||
|
|
||
| Owned: `src/codex/account-usability.ts`, `account-pause.ts`, `account-store.ts`, | ||
| `account-runtime-state.ts`, `plan.ts`, `plan-from-token.ts`, `warmup.ts`, `model-entitlements.ts`, `auth-api.ts`, `routing.ts` | ||
| (all under `src/codex/`), plus `src/server/responses/codex-auth-error.ts`, `src/types/config.ts`, | ||
| the single key `codexPool.excludedPlans` in | ||
| `src/config.ts`, and `docs-site/src/content/docs/guides/codex-integration.md` and its seven locale copies under | ||
| `docs-site/src/content/docs/{fr,ja,ko,ru,tr,zh-cn,zh-tw}/guides/codex-integration.md`. | ||
|
|
||
| 1. **#4126 — a newly created ChatGPT Free account fails Codex warmup with HTTP 404.** Carry PR #4188 | ||
| by `chilung-cgu` (open **draft**, `REVIEW_REQUIRED`, reset by the readiness gate rather than | ||
| rejected). It carries `src/codex/warmup.ts`, its test, and eight `codex-integration.md` pages — | ||
| all of which you own. | ||
| 2. **#4212 — an account stuck on a failed credential refresh silently drops its models.** The ask is | ||
| attribution, not new routing. **Decision: this round covers the refusal string | ||
| (`codex-auth-error.ts:35`), the account-health surface, and the management route | ||
| on the Codex account surface, which is `poolAccountDto` in `src/codex/auth-api.ts:377` under | ||
| `/api/codex-auth/accounts`. The feasibility audit found the earlier grant of | ||
| `oauth-account-routes.ts` was the wrong route: it serves the generic `/api/oauth/accounts` and | ||
| `src/oauth/index.ts:331` excludes ChatGPT from it. The reporter's 503 is inlined at | ||
| `responses/core.ts:2336` and `compact.ts:383`, which L1 owns, and the model-list drop is published | ||
| from `catalog/sync.ts:1777`. Both are out of scope: write `Refs #4212`, not `Closes`,** and record | ||
| them as follow-ups. | ||
| 3. **#4211 — keep Free-tier accounts out of pool selection.** **Decision: ship** | ||
| **`codexPool.excludedPlans` as an array, absent by default, filtered in `getEligiblePoolAccounts`** | ||
| **at `src/codex/routing.ts:1248` rather than in `isCodexAccountUsable`, which is where pause already | ||
| lives, and explicit namespace selection at `auth-context.ts:922` keeps working,** so an existing install sees no | ||
| behaviour change. Do not ship `minimumPlan`: ranking plans needs an ordering this repository does | ||
| not have. **Decision: this round ships selection only.** If the dashboard or CLI display the issue | ||
| also asks for needs `src/cli/account.ts`, a GUI component, or a locale key, stop and report; write | ||
| `Refs #4211` rather than `Closes #4211` when the display half is not included. | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| # WP1 — #4126 newly created ChatGPT Free account fails Codex warmup with HTTP 404 | ||
|
|
||
| ## What the issue reports | ||
|
|
||
| OAuth login succeeds, then warmup fails with `http_status:404` and the dialog tells the operator to | ||
| reauthenticate. The account is a brand-new ChatGPT Free account that works normally on chatgpt.com, | ||
| so the credential was never the problem. | ||
|
|
||
| ## Carried work | ||
|
|
||
| PR #4188 by `chilung-cgu` (open draft, reset by the readiness gate rather than rejected). Every file | ||
| it touches — `src/codex/warmup.ts`, `tests/codex-integration/warmup.test.ts`, and the eight | ||
| `codex-integration.md` locale pages — is inside the L3 owned list, so **no hunks were dropped**. It | ||
| applied cleanly onto the rebased lane branch with `git apply -3`. | ||
|
|
||
| What it changes: | ||
|
|
||
| - `FALLBACK_MODELS` gains `gpt-5.6-luna`, which a Free account can actually run. | ||
| - 404 joins 400 as a retryable warmup status, behind one shared `isRetryableWarmupStatus()` predicate. | ||
| - The fallback loop stops on a non-retryable retry error instead of walking the rest of the list. | ||
|
|
||
| ## The gap this lane closed | ||
|
|
||
| PR #4188's description claims it updates `verifyCodexAccountWarmup` in `src/codex/auth-api.ts` to | ||
| stop claiming reauthentication is required. Its diff contains no such change. The issue asks for the | ||
| same thing directly: distinguish 401/403 authentication failures from 404 provisioning failures. | ||
|
|
||
| `src/codex/auth-api.ts` is an L3 owned path, so this lane finished it. `warmup.ts` now exports | ||
| `isCodexWarmupProvisioningFailure()`, which reuses the retry predicate, and `verifyCodexAccountWarmup` | ||
| picks its message from it. Reusing the predicate is the point: a future change to the retryable set | ||
| cannot leave the operator-facing message disagreeing with the policy that produced the error. | ||
|
|
||
| The HTTP status stays 401. The only consumer is the OAuth login-state wrapper at | ||
| `auth-api.ts:2845`, which reads the JSON body and ignores the status, so changing it would have been | ||
| an unrelated contract move with no caller asking for it. | ||
|
|
||
| ## Audit | ||
|
|
||
| A read-only `xai/grok-4.6` subagent reviewed the staged diff against five questions. Verdict: pass. | ||
|
|
||
| - The early throw changes no caller's outcome for the worse. `token-guardian.ts:264` persists | ||
| `codexWarmupFailureReason`, and a mid-chain 401 is now preserved instead of being overwritten by a | ||
| later 404. `quota-auto-refresh.ts:180` and `:217` branch on `error.status === 401` and now see it | ||
| sooner. The `http_status:401`/`http_status:403` branch at `auth-api.ts:1573` stays reachable. | ||
| - A repeating 404 costs at most 3 upstream POSTs per `warmCodexAccount()` call, bounded by | ||
| `quota-auto-refresh`'s 5-minute retry floor and `token-guardian`'s 300s–3600s backoff. | ||
| - `isCodexWarmupProvisioningFailure(new CodexWarmupError("http_status"))` is `false`, which is | ||
| correct: production always carries `res.status`, and a statusless construct is not evidence of a | ||
| provisioning refusal. | ||
| - No existing test asserts the old message, the 401 on that response, or a one-entry | ||
| `FALLBACK_MODELS`. | ||
|
|
||
| ## Verification | ||
|
|
||
| Local suite, typecheck, and build: NOT RUN by operator instruction. Hosted CI on the pushed head is | ||
| the evidence. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -375,7 +375,7 @@ délégation v1/base/v2 et de ses mécanismes de repli. | |
|
|
||
| ## Préchauffage des comptes Codex | ||
|
|
||
| L’ajout ou la réauthentification vérifie normalement le compte avant son enregistrement par une petite requête attendant `response.completed`. Le modèle par défaut est `gpt-5.4-mini`, avec un essai sur `gpt-5.5` en cas de HTTP 400. Les erreurs publiques contiennent des catégories fixes, sans corps de réponse brut. | ||
| L’ajout ou la réauthentification vérifie normalement le compte avant son enregistrement par une petite requête attendant `response.completed`. Le modèle par défaut est `gpt-5.4-mini`, avec un essai sur `gpt-5.5` et `gpt-5.6-luna` en cas de HTTP 400 ou HTTP 404. Les erreurs publiques contiennent des catégories fixes, sans corps de réponse brut. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Document the warmup failure distinction in the canonical guide and both translations.
🧰 Tools🪛 LanguageTool[typographical] ~378-~378: Caractère d’apostrophe incorrect. (APOS_INCORRECT) [typographical] ~378-~378: Caractère d’apostrophe incorrect. (APOS_INCORRECT) 🤖 Prompt for AI Agents |
||
|
|
||
| Si la lecture authentifiée des quotas avec le nouveau jeton OAuth confirme un quota de 5 heures, hebdomadaire ou mensuel épuisé, le compte est enregistré sans appel au modèle et affiche **Validation en attente**. Il reste exclu du routage après un redémarrage ou un renouvellement du jeton. Après récupération du quota, actualisez les quotas : une lecture récente et complète avec de la capacité disponible permet une petite requête de validation. Seule sa réussite active le compte. Tout échec conserve la restriction. Les lectures passives ne déclenchent pas cette requête. Un quota inconnu à l’inscription conserve la vérification habituelle. | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit identifies PR #4188 as carried work, but commit
24a1040contains noCo-authored-bytrailer, and the cited branch commit7f91737c2is not its ancestor, so GitHub will not creditchilung-cguafter the squash. Add the actual trailer to the PR description or resulting squash message rather than referring to an unreachable branch commit in prose.AGENTS.md reference: AGENTS.md:L279-L283
Useful? React with 👍 / 👎.