fix: three things that were known and written nowhere
All three have the same shape — the system learns something and only stderr
hears it — and each was flagged in the handoff as a silent-discard defect.
The gate's install outcome. `container_tool_hooks::install` returned Some or
None and both call sites wrote `let _ =`. A mission whose gate never installed
left a record indistinguishable from one whose gate stood there and matched
nothing. `EnsuredContainer` now carries the outcome to the callers that have a
pool, and they record `gate.installed` (with the settings path) or
`gate.absent` on the mission, so "was this mission gated?" is answerable from
the mission.
The inert marker. `vm_tool_gate` writes an `inert` file when it cannot parse
its input and allows everything, precisely so an inert gate does not look like
a permissive one. The only reader was a unit test. `drain_inert` now reads and
clears it at every tap drain, and a `gate.inert` event with the occurrence count
lands beside the calls that ran unchecked.
The judge's spend. `LlmEvent::Usage` arrived on every judge call and was
matched by `Ok(_) => {}`. Two plan exhaustions (2026-08-29, 2026-09-09) with
no row anywhere saying a judge token had been spent; `usage_events` had no
provider or model column. The loop now accumulates requests and tokens onto the
Verdict — counting a request BEFORE the stream opens, so a 429 the provider
refused still counts, because the retry storm was made of those — and
`record` writes a `kind = 'judge'` row with provider, model, mission and
request count. Migration 0085 adds the columns, all nullable, so the two
existing writers are untouched.
Tests: a scripted-provider verdict records one request and nonzero tokens; a
provider that refuses still records the request and zero tokens.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WZb5A2kfVfjpdwSochkuHz
This commit is contained in:
co-authored by
Claude Opus 5
parent
758760cedb
commit
248948cc84
@@ -558,6 +558,14 @@ pub struct MissionRuntimeProvisioner {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EnsuredContainer {
|
||||
pub endpoint: String,
|
||||
/// Where the tool hooks were written, or `None` if installing them failed.
|
||||
///
|
||||
/// Carried out to the caller rather than only logged, because the caller
|
||||
/// has the pool and this struct's producer does not. Before this field
|
||||
/// the outcome went to stderr and nowhere else, so a mission whose gate
|
||||
/// never installed left a record indistinguishable from one whose gate
|
||||
/// stood there all night and matched nothing.
|
||||
pub hooks: Option<String>,
|
||||
/// One-time pairing code minted by the daemon at boot; may be
|
||||
/// None on the reuse-existing path when we couldn't scrape it
|
||||
/// back (log rotation). Callers keep the previously-persisted
|
||||
@@ -628,11 +636,12 @@ impl MissionRuntimeProvisioner {
|
||||
// Re-install on reuse: the container outlives the server
|
||||
// process, and a hook that exists only on first creation is a
|
||||
// hook that quietly disappears after a redeploy.
|
||||
let _ = crate::container_tool_hooks::install(&self.docker, &name).await;
|
||||
let hooks = crate::container_tool_hooks::install(&self.docker, &name).await;
|
||||
let pairing_code = self.mint_pairing_code(&name).await;
|
||||
return Ok(EnsuredContainer {
|
||||
endpoint: endpoint_url(&name),
|
||||
pairing_code,
|
||||
hooks,
|
||||
});
|
||||
}
|
||||
// Exists but not running — remove + recreate below rather
|
||||
@@ -842,11 +851,12 @@ impl MissionRuntimeProvisioner {
|
||||
// Gate and observe the tools claude runs inside its own subprocess.
|
||||
// Best-effort by design: a phase that runs unhooked still delivers, and
|
||||
// failing the launch to protect telemetry would be the wrong trade.
|
||||
let _ = crate::container_tool_hooks::install(&self.docker, &name).await;
|
||||
let hooks = crate::container_tool_hooks::install(&self.docker, &name).await;
|
||||
|
||||
Ok(EnsuredContainer {
|
||||
endpoint: endpoint_url(&name),
|
||||
pairing_code,
|
||||
hooks,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user