Skip to content

fix(codex): explain model access rejection (#613) - #614

Merged
PeterGuy326 merged 2 commits into
mainfrom
fix/613-codex-model-access-errors
Oct 20, 2026
Merged

PeterGuy326 merged 2 commits into
mainfrom
fix/613-codex-model-access-errors

Conversation

@Bindy-lbb

Copy link
Copy Markdown
Collaborator

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-luna for 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-retryable codex.model_access_denied failure, 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

Acceptance criterion Status Implementation / evidence
REQ-001 / AC-001: classify the observed rejection with one failed terminal and no opaque public JSON; preserve other failures PASS qoder-engine.mjs; executable-backed tests cover both engines and plain/JSON messages. Four unrelated-error controls retain their original codes.
REQ-002 / AC-002: localized model-specific recovery and unchanged ordinary failures PASS TurnThread.tsx, English/Chinese catalogs, renderer regressions. Requested model is shown; checking the same CLI login or choosing another model is explained.
REQ-003 / AC-003: distinguish catalog discovery from access and preserve explicit selection PASS 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.
REQ-004 / AC-004: regressions, complete local gate, docs, review handoff PASS See validation ledger; README and CHANGELOG updated. Independent review and current-head CI are merge prerequisites.

Validation ledger

Command or check Expected Actual Evidence
V1: new engine regressions against the unchanged base adapter Reproduce the missing model-access classification PASS: 4/4 targeted rejection tests FAIL on base; 4/4 negative controls PASS node --test --test-name-pattern='Codex model access|Codex does not classify' apps/server/dist/test/qoder-engine.test.js, base adapter from 7c8dd6a9ffbddad9afc946ffbc8ec4ec96306ea8; restored patched adapter afterward
V2: same executable-backed regressions with the fix Specific failure, unchanged requested --model, one invocation, no success/delta/fallback PASS: 8/8 tests PASS apps/server/test/qoder-engine.test.ts
V3: targeted renderer regressions Localized recovery, unchanged selection, refresh/manual switch, correct historical reminder scope PASS: 9/9 tests PASS npm run test:renderer -- apps/desktop/renderer/test/codex-model-access.test.tsx
V4: npm run check Build/type checks, all repository tests and dependency audit pass PASS: command exited 0; 3036 tests PASS, 4 existing skips; audit reports 0 vulnerabilities Local full-gate log; see totals below
V5: Chromium / Playwright on production components with isolated fixture data Correct page, meaningful content, no framework overlay or console errors, refresh/manual switch/localization work PASS: desktop 1280x800 and narrow 390x844; 0 console errors/warnings Temporary harness at http://127.0.0.1:48991/, page title RoleWeave model access regression; details below
V6: git diff --check No whitespace errors PASS Local diff
V7: live account inference / installed Windows desktop No paid requests or installed-client mutation for this change NOT VERIFIED: intentionally not invoked Offline executable fixtures and browser component flow cover error translation; upstream access cannot be granted by this PR

Full 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

  • Added 8 executable-backed engine cases (4 regression cases plus 4 controls) and 9 renderer cases.
  • Observed counts: 17/17 targeted tests PASS; baseline rejection cases 4/4 FAIL as expected.
  • Coverage before / after: not measured; no numeric coverage claim.
  • Intentionally uncovered: account rollout/plan entitlement, paid inference, installed-client deployment, and other browsers. No global model allow/deny list is introduced.

Change classification

  • User-visible behavior
  • Internal refactor or maintenance
  • Documentation only
  • Build, CI, dependency, or repository configuration
  • Breaking change
  • Security-sensitive change

Risk and rollback

  • Low risk: Codex failure presentation and model-menu guidance; no dependency, schema, credential, transport, or billing changes.
  • Recognition deliberately matches the observed ChatGPT-account rejection wording. If upstream wording changes, unrecognized errors retain the existing generic failure path.
  • The last-rejection reminder describes history, not present account entitlement; a catalog refresh alone cannot verify a model.
  • Rollback: revert this commit and rebuild the app; no migration or data repair is required.

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

  • A maintainer confirmed that the linked issue or tracking record was ready before implementation began, or the automation was pre-authorized under GOVERNANCE.md.
  • This branch was created from an up-to-date default branch and contains no unrelated changes.
  • I ran the repository's applicable tests, lint, type checks, builds, coverage, and security checks.
  • I added a regression test for a bug fix, or explained why one is impractical.
  • I updated relevant documentation and changelog files.
  • I reviewed the diff for secrets, personal data, generated artifacts, and dependency risk.
  • The PR is ready for CI and review by someone other than the sole author.
  • All reported results are reproducible.

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.

Refs #613, R1. Distinguish catalog discovery from inference access and guide recovery without changing the selected model or authentication boundary.
PeterGuy326
PeterGuy326 previously approved these changes Oct 20, 2026

@PeterGuy326 PeterGuy326 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@PeterGuy326

Copy link
Copy Markdown
Contributor

Maintainer note: the branch was behind main and conflicted, so I merged main (7373da8) into it to clear the structural blocker.

The merge is mechanical. The only conflict was the [Unreleased] list in CHANGELOG.md, resolved by keeping all entries — this PR's #613 line first, then #615, #611, #609 from main. No feature code was edited, and the auto-merged files (apps/server/bin/qoder-engine.mjs, locales, README.md) took main's content alongside this PR's additions unchanged.

Because the repository dismisses stale approvals on push, the previous approval no longer counts; I will re-review and approve the current head ecd4c81 once CI is green, then squash-merge.

@PeterGuy326 PeterGuy326 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.mjs adds 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-retryable codex.model_access_denied instead of a raw 400 payload. Malformed requests and login failures keep their existing codes; the four negative controls in qoder-engine.test.ts cover that separation on both codex and codex-local.
  • TurnThread.tsx only swaps the title, help text and message when that code is present and the turn's engine is a Codex engine, and falls back to turn.model when the model is unset, so no other failure renders differently.
  • ConversationOptions.tsx derives modelWasRejected from 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.

@PeterGuy326
PeterGuy326 merged commit 2dc7764 into main Oct 20, 2026
11 checks passed
@PeterGuy326
PeterGuy326 deleted the fix/613-codex-model-access-errors branch October 20, 2026 17:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Codex model access rejection exposes raw provider errors

2 participants