Skip to content

test: property-check the unsupported-model fallback invariants#574

Merged
ndycode merged 2 commits into
mainfrom
claude/audit-55-model-fallback-property
Jun 11, 2026
Merged

test: property-check the unsupported-model fallback invariants#574
ndycode merged 2 commits into
mainfrom
claude/audit-55-model-fallback-property

Conversation

@ndycode

@ndycode ndycode commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Summary

Companion to the direct-coverage wave (#559#573), in the repo's existing test/property/ tradition. resolveUnsupportedCodexFallbackModel steers which model the proxy retries with when ChatGPT accounts reject a Codex model — a wrong fallback means silent infinite retry loops or model downgrades the user never asked for. The existing example-based coverage (via the fetch-helpers suites) pins specific cases; this adds test/property/model-fallback.property.test.ts (6 fast-check properties) pinning the invariants across the whole input space.

The generator produces every default-chain model under provider prefixes (openai/, models/), reasoning-effort suffixes (-low, -xhigh, …), and arbitrary casing — exactly the spellings canonicalizeModelName must normalize.

Invariants pinned

  • The feature toggle off, or an error body that is not an unsupported-model error, always yields undefined.
  • Any returned fallback is a member of the canonical chain for the requested model, is never the current model, never an already-attempted model, and respects the gpt-5.3-codex → gpt-5.2-codex legacy-edge toggle.
  • With nothing attempted, the first chain target wins (deterministic retry order); with every chain target attempted, the resolver gives up rather than looping.
  • Attempted-model spellings canonicalize the same way as requested models — an attempt recorded as OPENAI/GPT-5.3-CODEX-HIGH still skips gpt-5.3-codex.

Validation

  • vitest run test/property/model-fallback.property.test.ts — 6/6 passing (default fast-check run counts)
  • npm run typecheck — clean
  • npx eslint test/property/model-fallback.property.test.ts --max-warnings=0 — clean

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB


Generated by Claude Code

note: greptile review for oc-chatgpt-multi-auth. cite files like lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.

Greptile Summary

adds test/property/model-fallback.property.test.ts — 6 fast-check properties that pin the fallback invariants of resolveUnsupportedCodexFallbackModel across the full input space of provider prefixes, effort suffixes, and arbitrary casing. the local canonicalize helper now passes chain values through normalization before comparison, closing the coupling issue flagged in the previous wave.

  • properties 1–2 check the toggle-off and wrong-error-body guard paths; properties 3–6 cover chain membership, ordering, exhaustion, and attempted-model spelling normalization.
  • two coverage gaps: property 6 only generates lowercase attempted-model spellings (missing the uppercase path the PR description claims to cover), and property 4 hardcodes the legacy-edge toggle to true, leaving the gpt-5.3-codex + toggle-off = undefined branch untested.

Confidence Score: 5/5

test-only addition; no production code changes, no concurrency or token-safety surface introduced.

all changes are confined to a new property test file; the implementation under test is unchanged. the two gaps noted leave a small slice of the stated invariants unexercised, but neither gap conceals a defect in the resolver itself.

test/property/model-fallback.property.test.ts — properties 4 and 6 have the coverage gaps described above.

Important Files Changed

Filename Overview
test/property/model-fallback.property.test.ts adds 6 fast-check properties for resolveUnsupportedCodexFallbackModel; local canonicalize helper now correctly mirrors the implementation; two minor coverage gaps: property 6 never generates uppercase attempted-model spellings, and property 4 hardcodes the legacy-edge toggle to true

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["resolveUnsupportedCodexFallbackModel(options)"] --> B{fallbackOnUnsupportedCodexModel?}
    B -- false --> Z1[return undefined]
    B -- true --> C{errorBody is unsupported-model error?}
    C -- no --> Z2[return undefined]
    C -- yes --> D["canonicalize requestedModel → currentModel"]
    D --> E{currentModel in chain?}
    E -- no --> Z3[return undefined]
    E -- yes --> F["iterate chain targets"]
    F --> G{legacyEdge=false AND target=gpt-5.2-codex AND current=gpt-5.3-codex?}
    G -- yes --> H[skip target]
    H --> F
    G -- no --> I{target === currentModel?}
    I -- yes --> H
    I -- no --> J{target in attempted set?}
    J -- yes --> H
    J -- no --> K[return target]
    F -- exhausted --> Z4[return undefined]
Loading

Fix All in Codex

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
test/property/model-fallback.property.test.ts:156-181
**property 6 never generates uppercase attempted-model spellings**

`prefix` and `suffix` are both drawn from lowercase constants, and `firstTarget` is already canonical (lowercase). the composed `attemptedModels` entry is therefore always lowercase — e.g. `openai/gpt-5.2-codex-high` — so the uppercase case the PR description calls out (`OPENAI/GPT-5.3-CODEX-HIGH`) is never exercised. adding `fc.boolean()` to produce an upper-cased variant (mirroring what `arbSpelledModel` does) would close the gap.

### Issue 2 of 2
test/property/model-fallback.property.test.ts:124-138
**property 4 hardcodes `fallbackToGpt52OnUnsupportedGpt53: true`**

`gpt-5.3-codex` has only one chain target (`gpt-5.2-codex`). with the toggle forced `true`, `firstTarget` is always `gpt-5.2-codex` and the assertion passes. with `false`, the resolver skips that target and returns `undefined`, so `expect(result).toBe(firstTarget)` would fail — but this path is never reached. parameterising the toggle and asserting `result === undefined` when `canonical === "gpt-5.3-codex" && !legacyEdge` would give this property real coverage of the toggle interaction.

Reviews (2): Last reviewed commit: "test: canonicalize expected chain target..." | Re-trigger Greptile

fast-check properties over resolveUnsupportedCodexFallbackModel (via
the fetch-helpers facade), generating every default-chain model under
provider prefixes, reasoning-effort suffixes, and arbitrary casing:

- the feature toggle off, or a non-unsupported error body, always
  yields undefined
- any returned fallback is a member of the canonical chain for the
  requested model, is never the current model, never an
  already-attempted model, and respects the gpt-5.3 -> gpt-5.2 legacy
  edge toggle
- with nothing attempted the first chain target wins; with every
  target attempted the resolver gives up
- attempted-model spellings canonicalize the same way as requested
  models, so a differently-spelled attempt still skips its target

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@ndycode, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 6 minutes and 3 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6ef54776-df2f-4844-a39f-35133b96db45

📥 Commits

Reviewing files that changed from the base of the PR and between b566656 and 3c60683.

📒 Files selected for processing (1)
  • test/property/model-fallback.property.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/audit-55-model-fallback-property
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/audit-55-model-fallback-property

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread test/property/model-fallback.property.test.ts
The resolver normalizes chain values through canonicalizeModelName;
the test helper now mirrors that transform so the expectations stay
valid even if a future chain entry is added in a non-canonical
spelling.

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
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.

2 participants