fix(ai): move the Codex slug ladder onto the gpt-5.6 line

The ChatGPT Codex backend now rejects every slug from gpt-5.5 down, so a
deploy without a CODEX_MODEL_FALLBACK_CHAIN override walked the whole
default ladder into "all configured Codex slugs were rejected". The
default now starts at gpt-5.6-terra, with its luna and sol siblings and
gpt-5.5 as the last rung.

The gpt-6 line stays out of the default: the reasoning, sampling and
vision gates do not recognise that family yet, and a test now holds every
default slug to a family the reasoning gate knows.
This commit is contained in:
Marc-André Bombeck committed 2026-10-24 08:06:33 +02:00
1 parent 685b46fa04
commit 810a949d2b
4 files changed
+37 -33

No files matched your search

+6 -6
View File
@@ -630,7 +630,8 @@ Confirmed-rejected slugs (despite the source-tree references in the table above)
Confirmed-accepted slugs on a ChatGPT Plus subscription (per `available_in_plans` in `models.json`):
- `gpt-5.5` — HealthLog's default (first chain entry) as of 2026-06
- `gpt-5.6-terra` — HealthLog's default (first chain entry) as of 2026-10-24, with `gpt-5.6-luna` and `gpt-5.6-sol` behind it; the backend rejected `gpt-5.5` and everything below it that day
- `gpt-5.5` — the default from 2026-06 until 2026-10-24
- `gpt-5.4` / `gpt-5.4-mini` / `gpt-5.2` — accepted per plan
- `gpt-5.3-codex` — was the default (verified 2026-05-09); the backend rotated off the `-codex` line on 2026-06-02 and this slug is now only accepted intermittently, so it sits on a late chain rung
@@ -646,11 +647,10 @@ To eliminate that risk class, HealthLog's `CodexClient` walks an ordered chain o
```ts
const DEFAULT_SLUG_FALLBACK_CHAIN = [
"gpt-5.5", // current default across paid tiers as of 2026-06-02
"gpt-5.4", // documented fallback
"gpt-5.4-mini", // documented lighter-weight fallback
"gpt-5.3-codex", // late rung — still accepted intermittently
"gpt-5.2", // legacy floor
"gpt-5.6-terra", // current default, verified against the backend 2026-10-24
"gpt-5.6-luna", // lighter sibling on the same line
"gpt-5.6-sol", // heavier sibling on the same line
"gpt-5.5", // previous default, kept as the last rung while plans differ
];
```
@@ -1,7 +1,7 @@
{
"$comment": "Production files over 800 lines and their length. Maintained by src/__tests__/source-size-ratchet.test.ts.",
"count": 89,
"total": 99598,
"total": 99593,
"entries": {
"app/medications/page-client.tsx": 839,
"components/charts/mood-chart.tsx": 1166,
@@ -29,7 +29,7 @@
"lib/ai/coach/stream-events.ts": 817,
"lib/ai/coach/turn/model.ts": 820,
"lib/ai/coach/types.ts": 1011,
"lib/ai/codex-client.ts": 1094,
"lib/ai/codex-client.ts": 1089,
"lib/ai/local-client.ts": 880,
"lib/ai/prompts/insight-generator.ts": 1110,
"lib/ai/provider.ts": 1632,
@@ -1,6 +1,7 @@
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { CodexClient, __test } from "../codex-client";
import { singleUserTurn } from "../types";
import { openAIReasoningFamily } from "../reasoning/support";
import {
clearCodexSlugCache,
getCachedCodexSlug,
@@ -341,17 +342,26 @@ describe("Codex slug fallback chain", () => {
});
it("DEFAULT_SLUG_FALLBACK_CHAIN tracks the current ChatGPT-auth ladder", () => {
// The backend rotated its ChatGPT-auth slugs onto the gpt-5.x line on
// 2026-06-02; the in-code default must match the accepted set, in order.
// The backend rejected every slug from gpt-5.5 down on 2026-10-24 and
// served the gpt-5.6 line; the in-code default must match the accepted
// set, in order.
expect([...__test.DEFAULT_SLUG_FALLBACK_CHAIN]).toEqual([
"gpt-5.6-terra",
"gpt-5.6-luna",
"gpt-5.6-sol",
"gpt-5.5",
"gpt-5.4",
"gpt-5.4-mini",
"gpt-5.3-codex",
"gpt-5.2",
]);
});
it("DEFAULT_SLUG_FALLBACK_CHAIN holds only slugs the reasoning gate recognises", () => {
// A slug whose family the reasoning gate does not know goes out with the
// wrong parameters. A new line (gpt-6) joins the default only together
// with its family support.
for (const slug of __test.DEFAULT_SLUG_FALLBACK_CHAIN) {
expect(openAIReasoningFamily(slug), slug).toBe("gpt-5.1+");
}
});
it("loadFallbackChain falls back to the default ladder with no env override", () => {
const origModel = process.env.CODEX_MODEL;
const origChain = process.env.CODEX_MODEL_FALLBACK_CHAIN;
@@ -359,11 +369,10 @@ describe("Codex slug fallback chain", () => {
delete process.env.CODEX_MODEL_FALLBACK_CHAIN;
try {
expect(__test.loadFallbackChain()).toEqual([
"gpt-5.6-terra",
"gpt-5.6-luna",
"gpt-5.6-sol",
"gpt-5.5",
"gpt-5.4",
"gpt-5.4-mini",
"gpt-5.3-codex",
"gpt-5.2",
]);
} finally {
if (origModel === undefined) delete process.env.CODEX_MODEL;
+10 -15
View File
@@ -51,23 +51,18 @@ import {
const CODEX_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
/**
* Default fallback chain — most-current-first as of 2026-06-02. Override
* via `CODEX_MODEL_FALLBACK_CHAIN` (comma-separated) on apps01 if a
* specific plan ladder needs different ordering. `CODEX_MODEL` is
* folded into position 0 of the chain when set; duplicates are dropped.
*
* The ChatGPT Codex backend rotated its ChatGPT-auth slugs off the
* `-codex` specialist line onto the plain `gpt-5.x` line on 2026-06-02;
* the former `-codex` defaults are now rejected with a 503 "all
* configured Codex slugs were rejected". The ladder below tracks the
* current accepted set.
* Default fallback chain, most-current-first as of 2026-10-24. Override via
* `CODEX_MODEL_FALLBACK_CHAIN` (comma-separated); `CODEX_MODEL` is folded
* into position 0 when set, duplicates dropped. The backend rotates its
* ChatGPT-auth slugs without notice: by 2026-10-24 it rejected everything
* from `gpt-5.5` down and served the `gpt-5.6-*` line. The `gpt-6` line is
* left out until the reasoning, sampling and vision gates recognise it.
*/
const DEFAULT_SLUG_FALLBACK_CHAIN = [
"gpt-5.5", // current default across paid tiers as of 2026-06-02
"gpt-5.4", // documented fallback
"gpt-5.4-mini", // documented lighter-weight fallback
"gpt-5.3-codex", // late rung — still accepted intermittently
"gpt-5.2", // legacy floor
"gpt-5.6-terra", // current default, verified against the backend 2026-10-24
"gpt-5.6-luna", // lighter sibling on the same line
"gpt-5.6-sol", // heavier sibling on the same line
"gpt-5.5", // previous default, kept as the last rung while plans differ
] as const;
/**