Skip to content

v0.42.4.0 fix: think --model fails loud — slash-form ids + never persist empty synthesis (#1698)#1736

Merged
garrytan merged 5 commits into
masterfrom
garrytan/think-model-fail-loud
Jun 2, 2026
Merged

v0.42.4.0 fix: think --model fails loud — slash-form ids + never persist empty synthesis (#1698)#1736
garrytan merged 5 commits into
masterfrom
garrytan/think-model-fail-loud

Conversation

@garrytan

@garrytan garrytan commented Jun 1, 2026

Copy link
Copy Markdown
Owner

What this fixes (#1698)

gbrain think --model anthropic/claude-sonnet-4-6 --save (slash form) silently
degraded to the no-LLM stub and wrote empty synthesis pages with exit 0. The
reporter ran it in a loop and got ~200 blank pages before noticing. This closes the
whole silent-failure class:

  • Slash-form model ids workanthropic/claude-sonnet-4-6 == anthropic:claude-sonnet-4-6; bare names still default to Anthropic.
  • An explicit --model that can't run is a hard error (exit 1, clear message + paste-ready fix), not a silent stub. Omitting --model keeps the graceful no-key gather-only path (exit 0).
  • Empty/malformed/empty-JSON synthesis is never persisted. --save with no real synthesis exits 1.
  • The nightly auto-think cycle no longer counts an empty synthesis as complete or advances the cooldown.

How

  • normalizeModelId (src/core/model-id.ts) — one shared provider:model normalizer, replacing 4 colon-only inlines that mangled slash form. Malformed leading separator (:foo) returned unchanged → resolver throws loud.
  • validateModelId + probeChatModel (src/core/ai/gateway.ts) — shared id-validity + Anthropic-key probe. runThink hard-errors on an explicit unusable model before retrieval.
  • ThinkResult.synthesisOk + persist-skip signal (SYNTHESIS_EMPTY_NOT_PERSISTED).
  • hasAnthropicKey consolidated into src/core/ai/anthropic-key.ts (3 copies → 1).
  • MCP think op sets modelExplicit; saved_slug ''→null.

Review

  • Eng review (diff-level): CLEAR. Faithful implementation of the cleared plan; DRY win (3 hasAnthropicKey copies + 4 colon-only inlines collapsed).
  • Codex diff-level pass: surfaced two real new fixes folded into this PR — normalizeModelId empty-provider guard, and the auto-think silent-success caller the original plan missed. One finding (D1: probeChatModel only pre-checks the Anthropic key) accepted-as-is and pinned by an end-to-end backstop test (non-Anthropic explicit model with no key builds, then create() hard-errors — never a silent stub). P3 follow-up for the provider-symmetric early gate filed in TODOS.md.

Tests

Targeted suite 107 pass / 0 fail on the merged state; bun run verify 29/29 green (typecheck, privacy, jsonb, the gateway-routed-no-direct-anthropic guard, wasm). New/extended: test/model-id.test.ts, test/ai/gateway-probe-chat-model.test.ts, test/ai/anthropic-key.test.ts, test/think-gateway-adapter.test.ts, test/think-pipeline.serial.test.ts, test/cycle/synthesize-gateway-adapter.test.ts, test/auto-think-phase.test.ts. The full 4-way parallel suite was run locally but the harness SIGKILLed the fan-out (resource limit, not assertions) — CI runs the full matrix.

🤖 Generated with Claude Code

Documentation

Post-ship doc audit (/document-release): no doc changes needed.

  • CHANGELOG.md — entry written in user-forward voice; scores 3/3 on the what/why/how sell test (slash-form + fail-loud / 200 blank pages / verify commands). Current.
  • README.md / AGENTS.md / CONTRIBUTING.md / docs/ — no reference to the old think --model silent-degrade behavior, so nothing went stale. Current.
  • VERSION — 0.42.4.0, matches the CHANGELOG header.
  • Coverage: the new surface (normalizeModelId, validateModelId, probeChatModel, anthropic-key.ts) is internal infrastructure, not user-facing CLI/API — no reference-doc debt. The one user-facing behavior change is covered by the CHANGELOG.

garrytan and others added 5 commits June 1, 2026 08:35
…pty synthesis (#1698)

Slash-form model ids (anthropic/claude-sonnet-4-6) silently degraded to the
no-LLM stub and wrote empty synthesis pages with exit 0 (reporter saw 200).
Three compounding defects, fixed:

- normalizeModelId (src/core/model-id.ts): one shared provider:model normalizer
  replacing 4 colon-only inlines; slash→colon, bare→default, malformed
  leading-separator (:foo) returned unchanged so resolveRecipe throws loud.
- validateModelId + probeChatModel (gateway.ts): shared id-validity + key probe;
  runThink hard-errors on an explicit --model it can't run (no silent degrade).
- synthesisOk + persist-skip (think/index.ts): empty/malformed/empty-JSON
  synthesis is never persisted; --save with no synthesis exits 1.
- auto-think (cycle/auto-think.ts): empty synthesis no longer counts complete or
  advances the cooldown (the autonomous third caller of persistSynthesis).
- hasAnthropicKey consolidated into src/core/ai/anthropic-key.ts (3 copies → 1).

MCP think op sets modelExplicit; saved_slug '' maps to null.
#1698 think --model fail-loud wave. Also files the P3 follow-up TODO for the
provider-symmetric early gate (D1 accept-as-is).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…l-fail-loud

# Conflicts:
#	CHANGELOG.md
#	VERSION
#	package.json
…l-fail-loud

# Conflicts:
#	CHANGELOG.md
#	VERSION
#	package.json
@garrytan garrytan merged commit 5911072 into master Jun 2, 2026
21 checks passed
mgunnin added a commit to mgunnin/gbrain that referenced this pull request Jun 3, 2026
* upstream/master:
  v0.42.8.0 feat: content-quality gate on sync — quarantine junk + flag boilerplate (garrytan#1699) (garrytan#1756)
  v0.42.7.0 feat(extract): link/timeline extraction freshness watermark — gbrain extract --stale + doctor lag check (garrytan#1696) (garrytan#1755)
  v0.42.6.0 feat(enrich): gbrain enrich --thin — brain-internal grounded synthesis for stub pages (garrytan#1700) (garrytan#1757)
  v0.42.5.0 fix(minions): RSS watchdog opacity + pooler-reap self-heal + silent lens backlog + cycle lint DB-disconnect (garrytan#1678) (garrytan#1735)
  v0.42.4.0 fix: think --model fails loud — slash-form ids + never persist empty synthesis (garrytan#1698) (garrytan#1736)
  v0.42.3.0 feat(search): autocut — score-discontinuity result-sizing (garrytan#1663 wave 1) (garrytan#1682)
  v0.42.2.0 feat: gbrain connect — one-command Claude Code onboarding from a bearer token (garrytan#1683)
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.

1 participant