The z.ai credential expired mid-session and the first symptom was a two-phase
mission failing after BOTH its VMs had run — the phase completed, delivered,
pushed, and then one evaluation row said "the independent validator could not be
reached this pass".
`cross_provider_judge` refusing to fall back to the agent's own provider is
correct: a verdict from the same family is not an independent check, and
producing one quietly would claim a property the verdict does not have. The cost
of that refusal is that a dead validator makes EVERY `done_when` phase
unmeetable — and the information needed to know that existed from the moment the
server booted. Nobody was told until it was expensive.
The sibling of `runtime_preflight`, and the same stance: a report, not a gate.
The server must still boot with a broken validator — refusing to start turns a
degraded deployment into a dead one, and a mission that opts out
(`validator_model = ''`) is unaffected.
Two faults, kept distinguishable because they send an operator to different
places: `Unregistered` (no provider by that name — the evaluator will refuse it
rather than judge with the default, so register one) versus `Unreachable` (it
resolved and the call failed — fix the credential). Collapsing them into "the
validator is broken" is the kind of merge that costs an hour.
The probe is a real completion through `Runtime::complete` — the same
resolve-then-stream path the judge itself takes. A models-list or a HEAD would
pass for an expired key, a revoked key, and a key with no quota, which are
exactly the cases worth catching; and a probe that dialled the provider its own
way could pass while the real call fails.
`NotConfigured` is reported too, and not as an error: a deployment may choose the
house model. It is still worth saying out loud that the check running is not an
independent one.
551 tests pass, clippy clean.
Co-Authored-By: Claude Opus 5 <[email protected]>