Symptom
Running a batch of gbrain think --anchor <slug> --take --save --model "anthropic/claude-sonnet-4-6" (slash form) on v0.41.38.0, the first pass silently produced empty synthesis pages. No model ran, no error was thrown, and --save still persisted a near-empty synthesis page + take row. The failure only became visible because the output was obviously empty on inspection — the command exited 0.
Re-running the identical batch with the colon form --model "anthropic:claude-sonnet-4-6" worked perfectly: 95/95 people + 104/104 company pages enriched with real, cited synthesis.
Why this is surprising
v0.41.21.0's parseModelId (src/core/ai/model-resolver.ts) explicitly added slash-form support, with a comment that this 'Closes the end-to-end bug class.' Yet on v0.41.38.0 the slash form still failed for think — either:
think's model-resolution path doesn't route through the fixed parseModelId, or
- it catches the resolution failure and falls back to a no-LLM/title-only path instead of surfacing it.
Either way the fail-silent + save-anyway behavior is the real bug, independent of the slash/colon parsing question. A model override that can't be resolved should be a hard error, never a silent degrade that still writes persisted pages.
Proposed fixes
- Fail loud on unresolvable
--model. If the operator explicitly passed --model X and X can't be resolved to a working recipe/provider, throw AIConfigError and exit non-zero. Never fall back to no-LLM when the model was explicitly requested. (Implicit/default model fallback is fine; explicit override is a contract.)
- Never
--save an empty synthesis. Guard persistSynthesis: if the synthesis body is empty / the LLM didn't actually run (Pages: N | Citations: 0 AND zero generated prose), refuse to persist and warn. Writing empty synthesis pages pollutes the brain and is worse than no page.
- Normalize slash→colon at every CLI entry point so
--model anthropic/claude-sonnet-4-6 and --model anthropic:claude-sonnet-4-6 are interchangeable everywhere, matching the documented --model <alias or full id> help text. Confirm think specifically routes through parseModelId post-v0.41.21.0.
- Surface the resolved model in output even on success (
Model: anthropic:claude-sonnet-4-6 (resolved from 'anthropic/claude-sonnet-4-6')) so silent degrades are caught immediately in logs.
Impact
In a 200-page batch this silently burned a full pass and wrote 200 empty pages before detection. For any unattended/cron enrichment job this is a data-quality landmine: the job reports success, exits 0, and quietly degrades the brain.
Symptom
Running a batch of
gbrain think --anchor <slug> --take --save --model "anthropic/claude-sonnet-4-6"(slash form) on v0.41.38.0, the first pass silently produced empty synthesis pages. No model ran, no error was thrown, and--savestill persisted a near-empty synthesis page + take row. The failure only became visible because the output was obviously empty on inspection — the command exited 0.Re-running the identical batch with the colon form
--model "anthropic:claude-sonnet-4-6"worked perfectly: 95/95 people + 104/104 company pages enriched with real, cited synthesis.Why this is surprising
v0.41.21.0's
parseModelId(src/core/ai/model-resolver.ts) explicitly added slash-form support, with a comment that this 'Closes the end-to-end bug class.' Yet on v0.41.38.0 the slash form still failed forthink— either:think's model-resolution path doesn't route through the fixedparseModelId, orEither way the fail-silent + save-anyway behavior is the real bug, independent of the slash/colon parsing question. A model override that can't be resolved should be a hard error, never a silent degrade that still writes persisted pages.
Proposed fixes
--model. If the operator explicitly passed--model Xand X can't be resolved to a working recipe/provider, throwAIConfigErrorand exit non-zero. Never fall back to no-LLM when the model was explicitly requested. (Implicit/default model fallback is fine; explicit override is a contract.)--savean empty synthesis. GuardpersistSynthesis: if the synthesis body is empty / the LLM didn't actually run (Pages: N | Citations: 0AND zero generated prose), refuse to persist and warn. Writing empty synthesis pages pollutes the brain and is worse than no page.--model anthropic/claude-sonnet-4-6and--model anthropic:claude-sonnet-4-6are interchangeable everywhere, matching the documented--model <alias or full id>help text. Confirmthinkspecifically routes throughparseModelIdpost-v0.41.21.0.Model: anthropic:claude-sonnet-4-6 (resolved from 'anthropic/claude-sonnet-4-6')) so silent degrades are caught immediately in logs.Impact
In a 200-page batch this silently burned a full pass and wrote 200 empty pages before detection. For any unattended/cron enrichment job this is a data-quality landmine: the job reports success, exits 0, and quietly degrades the brain.