fix(planner): the other four server-side calls were still on the metered key

The test that was supposed to prevent this grepped for the literal
`runtime.complete(` and passed while the phase planner (`mission_plan.rs`),
both swarm calls, and a second enhance path in `claws.rs` still billed the
pay-as-you-go account. They spell the receiver `state.runtime` or wrap the
call across lines, so the receiver name was never the thing to match. The
test now matches the METHOD, and covers all five files.

`complete_or` gains the rule that makes it safe to apply everywhere: a
`name:model` spec is an operator's explicit provider choice — the swarm
worker model is configured exactly that way — and is passed straight to
`Runtime::resolve_provider` untouched. Only a bare name is ambiguous, and a
bare name is precisely what resolves to the default provider. Hijacking a
chosen Kimi or GLM model onto Anthropic would be the same silent-substitution
bug pointed the other way.

`validator_preflight` and the evaluator judge keep calling the runtime
directly, on purpose: both exist to exercise the CONFIGURED spec.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Omar Sobh
2026-08-08 15:55:52 -07:00
co-authored by Claude Opus 5
parent deed591da6
commit ee5a939ce6
4 changed files with 86 additions and 26 deletions
+39 -4
View File
@@ -68,14 +68,27 @@ pub async fn complete_or(
// web search away from two features while every test still passed.
web_search: bool,
) -> Result<String, String> {
let Some(provider) = provider() else {
// A `name:model` spec is an operator's explicit provider choice — the swarm
// worker model is literally configured that way (`kimi:kimi-k2.6`), and
// `Runtime::resolve_provider` honours it. Forcing that onto Anthropic would
// silently run someone's chosen model on the wrong provider, which is the
// same class of bug as this module exists to fix, only pointed the other
// way. Only a BARE name is ambiguous, and a bare name is what resolves to
// the default provider — the metered key.
if !is_bare_model_name(model) || provider().is_none() {
return runtime
.complete(system, user, model, max_tokens, web_search)
.await;
};
}
let provider = provider().expect("checked just above");
complete_with(&provider, system, user, model, max_tokens, web_search).await
}
/// Whether a model string names a model without naming a provider.
pub fn is_bare_model_name(model: &str) -> bool {
!model.contains(':')
}
/// How long to wait before each retry. Four attempts, ~30s of patience total.
///
/// The subscription has no credit wall, but it does have a rate limit, and a
@@ -205,19 +218,27 @@ mod tests {
/// spec an operator configured (today `glm:glm-4.7`), and forcing it onto
/// Anthropic would make it prove the wrong thing — it exists to answer "is
/// the configured validator reachable".
/// The first version of this test grepped for the literal
/// `runtime.complete(` and passed while FOUR more call sites — the phase
/// planner, both swarm calls, and a second enhance path — still billed the
/// metered key. They were spelled `state.runtime` or wrapped across lines,
/// so the receiver name was never the thing to look for. Match the METHOD.
#[test]
fn no_server_side_call_silently_uses_the_metered_key() {
let sources = [
("routes/mission_roster.rs", include_str!("routes/mission_roster.rs")),
("routes/mission_plan.rs", include_str!("routes/mission_plan.rs")),
("routes/planner.rs", include_str!("routes/planner.rs")),
("routes/claws.rs", include_str!("routes/claws.rs")),
("swarm.rs", include_str!("swarm.rs")),
];
for (name, src) in sources {
assert!(
!src.contains("runtime.complete("),
!src.contains(".complete("),
"{name} calls Runtime::complete directly — a bare model name there \
resolves to the DEFAULT provider, which is the metered API key. \
Use `subscription::complete_or`."
Use `subscription::complete_or`, which passes a `name:model` \
spec through untouched."
);
}
// And the exception stays an exception, on purpose.
@@ -254,6 +275,20 @@ mod tests {
assert!(!is_transient(&LlmError::Wire("bad json".into())));
}
/// An operator's explicit provider choice is never hijacked.
///
/// The swarm worker model is a configured `name:model` spec. Routing that
/// onto the subscription would run someone's chosen Kimi or GLM model on
/// Anthropic and report success — the same silent-substitution bug as the
/// metered key, aimed the other way.
#[test]
fn a_provider_qualified_spec_is_left_alone() {
assert!(is_bare_model_name("claude-opus-4-8"));
assert!(is_bare_model_name("claude-haiku-4-5-20251001"));
assert!(!is_bare_model_name("kimi:kimi-k2.6"));
assert!(!is_bare_model_name("glm:glm-4.7"));
}
/// A metered key in the OAuth slot must be REFUSED, not used.
///
/// Accepting it would authenticate, work, and bill the pay-as-you-go account