Skip to content

fix(wire): drop fallback-credit from opus-5/fable-5 betas (CC 2.1.282) - #1425

Merged
askalf merged 5 commits into
masterfrom
fix/wire-drift-fallback-credit-2026-06-01
Sep 25, 2026
Merged

askalf merged 5 commits into
masterfrom
fix/wire-drift-fallback-credit-2026-06-01

Conversation

@askalf

@askalf askalf commented Sep 25, 2026

Copy link
Copy Markdown
Owner

What

The scheduled Wire drift (self-hosted) run 36136501329 on master (0338eba) failed with beta.transform findings for claude-opus-5 and claude-fable-5. It was the first run against CC 2.1.282. The previous run, 36087960858 on CC 2.1.281, was green.

In check-wire-drift.mjs, expected is CC's captured header and got is dario's betaForModel output. Here is the captured header on CC 2.1.282:

model CC 2.1.281 CC 2.1.282
opus-4-8 (base) base base
opus-5 base + fallback-credit-2026-06-01 base
fable-5 base + fallback-credit-2026-06-01 base

So CC 2.1.282 stopped sending fallback-credit-2026-06-01. dario still adds it for opus-5 and fable-5, and that extra flag is the drift. (The auto-filed ticket reads it the other way, as dario missing the flag. The run output shows the opposite.)

Change

  • src/proxy.ts: betaForModel no longer adds fallback-credit-2026-06-01 for fable or opus-5, so both now get the base set. I also removed the now-unused insertBetaBefore helper and updated the docblocks. FABLE_FALLBACK_CREDIT_BETA stays exported because scripts/drift-report.mjs still lists it as model-conditional.
  • test/beta-matrix.mjs, test/fable-beta.mjs: now expect opus-5 and fable-5 (plain, [1m] and no-afk variants) to match the base or base-1m shape. A base that already carries the flag is still passed through as-is, with no duplicate.

No version or CHANGELOG bump; a separate release: PR will handle that.

Risk for the reviewer

The 2026-06-09 note on FABLE_FALLBACK_CREDIT_BETA says fable traffic without this flag got soft-refused upstream (200, stop_reason: "refusal", empty content). CC 2.1.282 itself no longer sends it, so matching CC is the documented policy. Still, this PR changes what goes on the wire for fable and opus-5 in production. If you have a way to check a live fable completion through a build of this branch before release (for example the autodeploy smoke test, which runs opus-5), please do.

Test plan

  • CI test (beta-matrix, fable-beta) green
  • Re-dispatch Wire drift (self-hosted) on this branch (or wait for the next scheduled run after merge). It should report "drift": false on CC 2.1.282.

Source ticket: 00MUGYLOAI168DE8CD42EF8BAF

@github-actions github-actions Bot added the tests Test suite changes label Sep 25, 2026
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

✅ Release gate looks satisfied

version bumped 6.12.2 -> 6.12.3

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Live test: ✅ PASS

Head f1cbd678d9bc70be687919ad072662b5de4415d3 on the self-hosted runner: All stages PASS: install/build/test(244/244)/cli/doctor/live-probe(pong)

Stages
install: PASS
build: PASS
test: PASS
cli: PASS
doctor: PASS (exit 1, 18 rows; no credentials, reported cleanly)
live: PASS (pong)

Full workflow run

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 25, 2026
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Wire drift: ✅ CLEAN

Ran node scripts/check-wire-drift.mjs against the runner's claude for commit f1cbd678d9bc70be687919ad072662b5de4415d3 — per-model anthropic-beta (betaForModel) + billing-block cch gate vs the installed claude.

Report
[dario] live fingerprint refreshed from CC 2.1.282
  Codex accounts: fleet → https://chatgpt.com/backend-api/codex
  Pool strategy: headroom (default) — new conversations go to the seat with the most headroom; 2% floor
  Device identity: detected
[dario] model catalog: no accounts yet — serving baked list until one is added
[dario] template: live capture, CC v2.1.282 (7s old), variants: fable+opus-5+sonnet-5
[dario] template: 1 tool definition without input_schema.type — known, never advertised: advisor
[dario] ⚠  TLS fingerprint: Node v22.22.3 — Bun not installed; proxy-mode TLS fingerprint diverges from Claude Code
[dario]    → Install Bun (https://bun.sh) so dario can auto-relaunch under it and its TLS ClientHello matches Claude Code's.
[dario]    (silence with DARIO_QUIET_TLS=1, or use --strict-tls to hard-fail)

  dario — http://localhost:39877

  Your Claude subscription is now an API.

  Usage:
    ANTHROPIC_BASE_URL=http://localhost:39877
    ANTHROPIC_API_KEY=dario

  OAuth: none (expires in api-key mode)
  Model: passthrough (client decides)
  Claude auth: disabled (--no-claude-auth) — OpenAI-compatible backends only; Claude token untouched
  Pool: empty (admin bootstrap / api-key mode) — no accounts loaded

{
  "drift": false,
  "checkedAt": "2026-09-25T13:09:44.633Z",
  "ccVersion": "2.1.282",
  "captured": {
    "claude-opus-4-8": {
      "beta": "claude-code-20250219,interleaved-thinking-2025-05-14,thinking-token-count-2026-05-13,context-management-2025-06-27,prompt-caching-scope-2026-01-05,mid-conversation-system-2026-04-07,mid-conversation-tool-changes-2026-07-01,advisor-tool-2026-03-01,effort-2025-11-24",
      "cchEmitted": false,
      "billing": "x-anthropic-billing-header: cc_version=2.1.282.132; cc_entrypoint=sdk-cli;"
    },
    "claude-opus-5": {
      "beta": "claude-code-20250219,interleaved-thinking-2025-05-14,thinking-token-count-2026-05-13,context-management-2025-06-27,prompt-caching-scope-2026-01-05,mid-conversation-system-2026-04-07,mid-conversation-tool-changes-2026-07-01,advisor-tool-2026-03-01,effort-2025-11-24",
      "cchEmitted": false,
      "billing": "x-anthropic-billing-header: cc_version=2.1.282.132; cc_entrypoint=sdk-cli;"
    },
    "claude-sonnet-5": {
      "beta": "claude-code-20250219,interleaved-thinking-2025-05-14,thinking-token-count-2026-05-13,context-management-2025-06-27,prompt-caching-scope-2026-01-05,mid-conversation-system-2026-04-07,advisor-tool-2026-03-01,effort-2025-11-24",
      "cchEmitted": false,
      "billing": "x-anthropic-billing-header: cc_version=2.1.282.132; cc_entrypoint=sdk-cli;"
    },
    "claude-haiku-4-5": {
      "beta": "interleaved-thinking-2025-05-14,thinking-token-count-2026-05-13,context-management-2025-06-27,prompt-caching-scope-2026-01-05,claude-code-20250219,advisor-tool-2026-03-01",
      "cchEmitted": false,
      "billing": "x-anthropic-billing-header: cc_version=2.1.282.132; cc_entrypoint=sdk-cli;"
    },
    "claude-fable-5": {
      "beta": "claude-code-20250219,interleaved-thinking-2025-05-14,thinking-token-count-2026-05-13,context-management-2025-06-27,prompt-caching-scope-2026-01-05,mid-conversation-system-2026-04-07,mid-conversation-tool-changes-2026-07-01,advisor-tool-2026-03-01,effort-2025-11-24",
      "cchEmitted": false,
      "billing": "x-anthropic-billing-header: cc_version=2.1.282.132; cc_entrypoint=sdk-cli;"
    }
  },
  "ccHeaderOrder": [
    "accept",
    "content-type",
    "user-agent",
    "x-claude-code-session-id",
    "x-stainless-arch",
    "x-stainless-lang",
    "x-stainless-os",
    "x-stainless-package-version",
    "x-stainless-retry-count",
    "x-stainless-runtime",
    "x-stainless-runtime-version",
    "x-stainless-timeout",
    "anthropic-beta",
    "anthropic-dangerous-direct-browser-access",
    "anthropic-version",
    "x-api-key",
    "x-app",
    "connection",
    "host",
    "accept-encoding",
    "content-length"
  ],
  "ccBodyKeys": [
    "model",
    "messages",
    "system",
    "tools",
    "metadata",
    "max_tokens",
    "thinking",
    "context_management",
    "output_config",
    "stream"
  ],
  "findings": []
}

Full workflow run

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Compat test: ✅ PASSED

Ran node test/compat.mjs against dario proxy --passthrough on the self-hosted runner for commit f1cbd678d9bc70be687919ad072662b5de4415d3.

Output
============================================================
  dario Compatibility Validation (--passthrough via dario)
  2026-09-25T13:10:17.002Z
============================================================

--- Anthropic Messages API (Hermes) ---
✅ #1 Anthropic non-stream: "COMPAT OK" | thinking_injected=false | service_tier=-
✅ #2 Anthropic stream: 8 events | order=correct | "**STREAM COMPAT**"
✅ #3 SSE framing: event:/data: pairs correctly paired

--- Passthrough Verification ---
✅ #4 No thinking injection: No thinking block in response (passthrough clean)
✅ #5 Client betas preserved: Client-requested thinking honored (status=200)

--- Tool Use (OpenClaw) ---
✅ #6 Tool use: tool=get_weather | input={"location":"Tokyo"}
✅ #7 Tool use stream: 11 events | tool_use=true | input_json_delta=true

--- OpenAI Compat ---
✅ #8 OpenAI non-stream: "OPENAI COMPAT"
✅ #9 OpenAI stream: 3 chunks | [DONE]=true | "**STREAM OPENAI**"

--- Header Visibility ---
✅ #10 Header visibility: request-id=true | ratelimit=true (12 headers)

============================================================
  RESULTS: 10 passed, 0 failed, 0 warnings
============================================================

Full workflow run

@sprayberry-redline sprayberry-redline left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Automated review from the Sprayberry Labs fleet code reviewer.
Reviewed by the gating lane (gating review).

Verdict: changes requested. The code change is correct and matches the CC 2.1.282 capture, but newly added public comments, test headers and test names carry generated-writing tells (em dashes, "no longer" narration). rule:reads-as-generated

Blocking: generated-writing tells in newly added public text

Every one of these lines is added by this PR (none exist at the base blob). The first-party strict gate on this repo blocks an em dash anywhere in added code, comments or tests, and blocks test names that narrate the patch instead of stating the behaviour; that is the same standard applied to #1409, #1413 and #1419.

Em dashes in added lines:

src/proxy.ts:495

* before afk-mode — wire-drift live capture 2026-09-25)

test/beta-matrix.mjs:33

// that equals the base — sonnet-5[1m], the opus-4-x line, and (since CC

test/fable-beta.mjs:2

// betaForModel — the retired fable/opus-5 \fallback-credit-2026-06-01` beta.`

test/fable-beta.mjs:27

console.log('\n=== betaForModel — fable no longer gets the fallback-credit beta (CC 2.1.282) ===');

test/fable-beta.mjs:39

console.log('\n=== betaForModel — fallback-credit: no family adds it ===');

Test names that narrate the change rather than the behaviour (test/beta-matrix.mjs:65 and :67); the file's other membership checks are present-tense state ("haiku drops afk-mode", "sonnet-5 KEEPS mid-conversation-system"):

eq('fable no longer has fallback-credit (CC 2.1.282)',
eq('opus-5 no longer has fallback-credit (CC 2.1.282)',

Suggested fix (delete the dash or use a plain separator; state the behaviour in the test names):

 *                 before afk-mode; wire-drift live capture 2026-09-25)
// that equals the base: sonnet-5[1m], the opus-4-x line, and (since CC
// betaForModel: the retired fable/opus-5 `fallback-credit-2026-06-01` beta.
console.log('\n=== betaForModel: fable gets no fallback-credit beta (CC 2.1.282) ===');
console.log('\n=== betaForModel: fallback-credit is added for no family ===');
eq('fable has no fallback-credit (CC 2.1.282)',
eq('opus-5 has no fallback-credit (CC 2.1.282)',

Minor (non-blocking)

  • The PR body says "No version or CHANGELOG bump; a separate release: PR will handle that", but commit 51f7af2 adds a CHANGELOG [Unreleased] entry. Update the body so it matches the commits.

What I checked

  • The bug is real: wire-drift run 36136501329 on master reports beta.transform drift for claude-opus-5 and claude-fable-5, and in both entries expected (CC 2.1.282's captured header) ends at effort-2025-11-24 while got (dario) has fallback-credit-2026-06-01 appended. So dario is adding a flag CC no longer sends; the PR's reading is correct and the auto-filed ticket's reading was inverted.
  • src/proxy.ts:553-556: removing the fable || opus-5 branch makes both families fall through to the base set. insertBetaBefore has no remaining callers at the head (only insertBetaAfter at line 559 for context-1m), so deleting it is right, and its docblock was correctly re-pointed to insertBetaAfter with "AFTER". FABLE_FALLBACK_CREDIT_BETA stays exported and is still referenced by both test files and scripts/drift-report.mjs:16,20.
  • Boundaries covered by the updated tests: plain, [1m], uppercase id, skipContext1m=true, empty base ('' in, '' out), a base that already carries the flag (passthrough, no duplicate, for both fable and opus-5), the no-afk-mode base, and the CC 2.1.265 base for both families. The [1m] cases still pin context-1m at position 2, so the surviving insert rule is exercised. The inverted assertions fail on base (base emits the flag) and pass at the head.
  • Required CI is green at 51f7af2 (test, live-test, build 18/20/22, analyze, docker-cap-drop-smoke, actionlint, validate-package-json); only fleet/review is pending, which is this review.
  • Commit messages and the PR title carry no AI attribution and no tells.
  • Not done: I did not run a live fable completion through this branch; the body's "Risk for the reviewer" request is for the operator's autodeploy smoke test.

@askalf

askalf commented Sep 25, 2026

Copy link
Copy Markdown
Owner Author

Pushed the release bump as 7111925: package.json and package-lock.json go to 6.12.3, and the existing [Unreleased] entry now sits under ## [6.12.3] - 2026-09-25. Master is still at 6.12.2 (v6.12.2 is the latest tag), so 6.12.3 is the next free slot. scripts/preflight.mjs passes locally, and the version-bump-advice comment now says the release gate is satisfied.

This commit only touches version metadata. It does not address the open CHANGES_REQUESTED review from 51f7af2, which still needs its own follow-up.

@sprayberry-redline sprayberry-redline left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Automated review from the Sprayberry Labs fleet code reviewer.
Reviewed by the gating lane (gating review).

Verdict: approved at f1cbd67. Every blocking finding from my review at 51f7af2 is fixed, and the two commits since (7111925 release bump, f1cbd67 test wording) introduce nothing new to block on.

What changed since my last verdict

51f7af2...f1cbd67 touches only the lines I cited plus the release bump:

  • src/proxy.ts:494-495: 2.1.220–2.1.281 / before afk-mode — wire-drift are now 2.1.220 to 2.1.281 / before afk-mode; wire-drift. src/proxy.ts:449: "betaForModel no longer adds it" is now "adds it for no family".
  • test/beta-matrix.mjs:28,33: both em dashes replaced with plain separators. test/beta-matrix.mjs:65,67: the test names now state the behaviour (fable has no fallback-credit (CC 2.1.282), opus-5 has no fallback-credit (CC 2.1.282)) instead of narrating the change.
  • test/fable-beta.mjs:2,12,27,39: em dashes and "no longer" removed; section headers are betaForModel: fable gets no fallback-credit beta (CC 2.1.282) and betaForModel: fallback-credit is added for no family.
  • 7111925: package.json/package-lock.json 6.12.2 to 6.12.3 and the CHANGELOG entry moved under a new ## [6.12.3] - 2026-09-25 heading. Version strings match in both files; [Unreleased] is left empty above it, consistent with the file's layout.

I re-ran the tell grep over every added line of the full diff: no em dashes, no (control), no "before the fix"/"previously"/"the old code", no "ensure"/"gracefully"/"robust"/"leverage"/"Note that"/"Importantly". The only "no longer" left is the CHANGELOG entry's "Opus 5 and Fable 5 requests no longer carry ...", which is a release note describing a user-visible behaviour change in the same register as the neighbouring 6.12.2 entry, not patch narration in code or tests.

What I checked on the code (unchanged from 51f7af2, re-read at the head)

  • src/proxy.ts:553-556: deleting the m.includes('fable') || /opus-5(?!\d)/.test(m) branch makes both families fall through to the base set; the if/else if chain for sonnet-4, haiku and sonnet-5 is intact. insertBetaBefore has no remaining callers (only insertBetaAfter at :559 for context-1m), so its removal is dead-code deletion, and its docblock was re-pointed to insertBetaAfter with "AFTER". FABLE_FALLBACK_CREDIT_BETA stays exported for scripts/drift-report.mjs and both test files.
  • The bug is real on the base: wire-drift run 36136501329 reports beta.transform drift for claude-opus-5 and claude-fable-5, where expected (CC 2.1.282 capture) ends at effort-2025-11-24 and got (dario) appends fallback-credit-2026-06-01.
  • Boundaries pinned by the updated tests: plain id, [1m], uppercase id, skipContext1m=true, empty base ('' in, '' out), a base already carrying the flag (passthrough, no duplicate, fable and opus-5), the no-afk-mode base, the CC 2.1.265 base for both families, and [1m] still placing context-1m at position 2 so the surviving insert rule is exercised. The inverted assertions (=== BASE, includes(...) === 'false') fail on the base, which emits the flag, and pass at the head.
  • Required CI is green at f1cbd67: test, live-test, build (18/20/22), analyze, docker-cap-drop-smoke, actionlint, validate-package-json. Only fleet/review is pending, which is this review.
  • Commit messages, branch name and title carry no AI attribution and no tells.

Minor (non-blocking)

  • The PR body still says "No version or CHANGELOG bump; a separate release: PR will handle that", but the PR now carries 7111925 chore(release): 6.12.3 and the CHANGELOG entry sits under [6.12.3]. Worth editing the body so it matches the commits before merge.
  • Not done: no live fable completion was run through this branch; the body's "Risk for the reviewer" request remains for the operator's autodeploy smoke test.

@askalf
askalf merged commit 5ca2fac into master Sep 25, 2026
25 checks passed
@askalf
askalf deleted the fix/wire-drift-fallback-credit-2026-06-01 branch September 25, 2026 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation tests Test suite changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants