Repository navigation
fix(codex): explain model access rejection (#613) - #614
Conversation
Refs #613, R1. Distinguish catalog discovery from inference access and guide recovery without changing the selected model or authentication boundary.
PeterGuy326
left a comment
There was a problem hiding this comment.
Re-reviewed current head ecd4c81 against main 7373da8. No blocking code findings in the 9-file feature diff. The narrow error classifier, localized recovery and explicit model selection remain intact; main's #612 stdin transport and #616 task progress/process cleanup are preserved. No automatic model/account/billing fallback is introduced.
Independent WSL / Node 24.11.1 validation: full npm run check PASS on local integration d5c317c (3058 passed, 0 failed, 3 existing conditional skips; audit 0). Compared with the author's newly published head: the only difference is one blank CHANGELOG line; every executable/test/config file is identical. Then switched to the author's exact ecd4c81 head and reran build plus the targeted server model-access suite (8/8) and renderer model-access suite (9/9), all PASS. No local integration branch was pushed over the author's update.
Hosted required checks for this new head are still running. The earlier approval was dismissed by the update; it must not count for this head. This COMMENT review records verified evidence, not a fresh approval or permission to bypass pending checks. Final approval/guarded squash merge can proceed once exact-head required checks pass and no unresolved findings remain.
|
Maintainer note: the branch was behind The merge is mechanical. The only conflict was the Because the repository dismisses stale approvals on push, the previous approval no longer counts; I will re-review and approve the current head |
PeterGuy326
left a comment
There was a problem hiding this comment.
Re-reviewed at ecd4c81 (this PR's 01ffe50 plus a mechanical merge of main 7373da8). All 11 checks are green on this head, including both Node 24 legs, the two staging-smoke and installer legs, and the required CodeQL (javascript-typescript) / Dependency review / OpenSSF Scorecard.
The change does what the issue asks and stays inside the existing contract:
apps/server/bin/qoder-engine.mjsadds one branch on the exact provider wording ("model is not supported when using Codex with a ChatGPT account") after the 401 branch, so a ChatGPT-login model rejection becomes a non-retryablecodex.model_access_deniedinstead of a raw 400 payload. Malformed requests and login failures keep their existing codes; the four negative controls inqoder-engine.test.tscover that separation on bothcodexandcodex-local.TurnThread.tsxonly swaps the title, help text and message when that code is present and the turn's engine is a Codex engine, and falls back toturn.modelwhen the model is unset, so no other failure renders differently.ConversationOptions.tsxderivesmodelWasRejectedfrom the last completed turn on the same engine and the currently selected model, which is why a later success or a different selection clears the reminder; refreshing the catalog cannot clear it, which matches the "discovery is not entitlement" requirement.- No credential, endpoint or model is inferred or rewritten, and no entitlement probe is issued — the picker only explains.
Merging with squash once this approval lands.
Tracking record
Closes #613
Consumed revision: R1
Decision: DEC-ROLEWEAVE-613-001. Follow-up to the catalog freshness fix in #610; the Windows prompt transport fix in #612 remains independent.
Summary
When Codex rejects
gpt-6-lunafor a ChatGPT-authenticated request, the conversation currently shows the raw 400 JSON and generic task/connection advice. Translate that specific provider rejection into a non-retryablecodex.model_access_deniedfailure, with localized recovery that names the requested model.The Codex picker now explains that catalog entries and recommendations are not access checks. It flags the last matching rejected request and clears that reminder after a subsequent success or a different selected model. Refresh preserves the selection. No account eligibility is inferred, no inference probe is made, and no model, credentials, endpoint, or billing source is automatically changed. Historical generic failures remain historical records; upstream model access is outside this fix.
Acceptance criteria
qoder-engine.mjs; executable-backed tests cover both engines and plain/JSON messages. Four unrelated-error controls retain their original codes.TurnThread.tsx, English/Chinese catalogs, renderer regressions. Requested model is shown; checking the same CLI login or choosing another model is explained.ConversationOptions.tsx; discovery caveat is Codex-only, refresh does not select a model, and the historical reminder matches engine/model and the latest durable result.Validation ledger
node --test --test-name-pattern='Codex model access|Codex does not classify' apps/server/dist/test/qoder-engine.test.js, base adapter from7c8dd6a9ffbddad9afc946ffbc8ec4ec96306ea8; restored patched adapter afterward--model, one invocation, no success/delta/fallbackapps/server/test/qoder-engine.test.tsnpm run test:renderer -- apps/desktop/renderer/test/codex-model-access.test.tsxnpm run checkhttp://127.0.0.1:48991/, page titleRoleWeave model access regression; details belowgit diff --checkFull local gate totals: scripts 233/233 PASS; UI 53/53 PASS; server 958 PASS and 4 existing skips; renderer 1234/1234 PASS; desktop 558/558 PASS. Total: 3036 PASS, 0 FAIL, 4 skipped. Build, UI/renderer type checks, renderer production build, updater preparation, and dependency audit passed.
The host's small ephemeral-port pool and root-only filesystem permissions distort existing integration tests. The same validation wrapper used for #610/#612 runs Node test invocations in a disposable loopback network namespace with a larger namespace-local port range and drops root DAC-bypass capabilities. The repository command and test assertions are unchanged. The host port range remains 48800–49100. Existing jsdom pseudo-element warnings are not browser console errors.
Browser plugin not available; used existing Playwright/Chromium without dependency changes. Flow: failed Codex request → localized explanation → open employee model picker → catalog/access caveat and last-rejection reminder → refresh keeps
gpt-6-luna→ manually select another model → old reminder disappears → switch to English and verify the narrow viewport. Page identity, nonblank content, framework-overlay check, console health, screenshots, and interaction proof all passed. This is a production-component fixture, not an Electron or paid inference end-to-end claim.Tests and coverage
Change classification
Risk and rollback
Breaking or security notes
None. Recognized failures replace provider JSON with bounded, static recovery text. No credentials or live account data are included in fixtures or evidence.
Author checklist
GOVERNANCE.md.Reviewer notes
Please review the narrow error classification, authentication-boundary wording, and preservation of explicit model selection. In particular, a listed or recommended model is not proof of inference access (OpenAI documentation). Review is requested from Hu through DingTalk; no independent approval is claimed here. Codex assisted implementation and validation; Git authorship remains human.