fix(llm): two modules were posting to Anthropic behind the providers' back

The research scenario passed 4/4 and the log underneath it said:

  phase_summarizer: ... failed: anthropic 400 Bad Request: "Your credit
  balance is too low to access the Anthropic API"

`phase_summarizer` and `mission_refiner` each built their own reqwest POST to
the Messages API with `x-api-key: $ANTHROPIC_API_KEY`. No audit of `.complete(`
call sites could have found them — they never touched a provider — so every
phase summary and every mission-brief refinement on this deployment had been
failing against an empty account while the phases themselves ran fine. The
summarizer even persisted an error row per phase, which is why nothing ever
retried loudly enough to notice.

Both now go through `subscription::complete_with_fallback`, so they inherit the
subscription-first credential choice, the 429 backoff, and the opus -> haiku ->
glm chain. The summarizer records the model that ANSWERED in
mission_phase_summaries.model rather than the one it asked for.

The guard is a source WALK, not a file list: any .rs under cm-api/src that
mentions the Messages API host or `x-api-key` fails the test. A hand-listed set
of files is exactly what let these two hide.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Omar Sobh
2026-08-08 23:11:38 -07:00
co-authored by Claude Opus 5
parent 52500a689c
commit d48bdbc9a7
5 changed files with 91 additions and 115 deletions
+1 -1
View File
@@ -619,7 +619,7 @@ pub async fn refine(
Authed(user): Authed,
Path(id): Path<Uuid>,
) -> Result<Json<RefineResponse>, ApiError> {
let result = crate::mission_refiner::refine(&state.pool, user.workspace_id, id)
let result = crate::mission_refiner::refine(&state.pool, &state.runtime, user.workspace_id, id)
.await
.map_err(|e| {
eprintln!("mission {id}: refine failed: {e}");