fix(mission-runtime): a mission with no egress no longer launches
`clawmates_core` is `internal: true`. Verified from a container attached to it
and nothing else: no default route, and every external address unreachable —
the positive control fails, which is what makes the network's own configuration
visible rather than inferred.
So the attach to `clawmates_edge` is not an optimisation. Without it a mission
has no route off the host: no provider call, no fetch, no work. The result was
discarded:
let _ = self.docker.connect_network(EDGE_NETWORK, …).await;
which makes a failure here indistinguishable from success. The mission starts,
the phase runs, every tool call fails for a reason nothing reports, and the
phase can still reach `completed`. Green-with-nothing, again.
Not fatal on the error alone: re-attaching an already-connected container is
also an error, and a benign one on any relaunch path. So the container's own
network list settles it rather than the return code — already attached is
logged and continues, genuinely not attached fails the launch with a message
that says what it means. `inspect` failing counts as NOT attached, because the
whole point is to stop guessing that egress is present.
Behaviour change worth stating plainly: a mission that would previously have
run blind now refuses to start. That is the intended trade — a mission which
cannot reach anything cannot do the work it reports having done.
Suite: 108 binaries, 838 tests, green.
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
fe5c7d2c87
commit
bd7fd46305
@@ -591,6 +591,20 @@ impl MissionRuntimeProvisioner {
|
|||||||
Some(MissionRuntimeProvisioner { docker, image })
|
Some(MissionRuntimeProvisioner { docker, image })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is this container actually attached to the egress network?
|
||||||
|
///
|
||||||
|
/// Asked only when the attach reported an error, to tell "already connected"
|
||||||
|
/// apart from "not connected". Inspect failing is treated as NOT attached:
|
||||||
|
/// the whole point is to stop guessing that egress is present.
|
||||||
|
async fn is_on_edge_network(&self, name: &str) -> bool {
|
||||||
|
self.docker
|
||||||
|
.inspect_container(name, None::<bollard::query_parameters::InspectContainerOptions>)
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
.and_then(|c| c.network_settings?.networks)
|
||||||
|
.is_some_and(|nets| nets.contains_key(EDGE_NETWORK))
|
||||||
|
}
|
||||||
|
|
||||||
/// Idempotent: returns the endpoint URL, creating the container
|
/// Idempotent: returns the endpoint URL, creating the container
|
||||||
/// on first call. If the container exists but is stopped, starts
|
/// on first call. If the container exists but is stopped, starts
|
||||||
/// it. If it exists and is running, returns its endpoint.
|
/// it. If it exists and is running, returns its endpoint.
|
||||||
@@ -775,7 +789,19 @@ impl MissionRuntimeProvisioner {
|
|||||||
.map_err(|e| format!("create mission runtime container: {e}"))?;
|
.map_err(|e| format!("create mission runtime container: {e}"))?;
|
||||||
|
|
||||||
// Attach to the edge network for outbound provider egress.
|
// Attach to the edge network for outbound provider egress.
|
||||||
let _ = self
|
//
|
||||||
|
// `clawmates_core` is `internal: true` and has NO default route —
|
||||||
|
// verified from a container on it, where every external address is
|
||||||
|
// unreachable. So this attach is not an optimisation: without it the
|
||||||
|
// mission cannot reach a provider, cannot fetch anything, and cannot do
|
||||||
|
// its work. The result used to be discarded, which made a failure here
|
||||||
|
// indistinguishable from success and produced the green-with-nothing
|
||||||
|
// shape this codebase keeps meeting.
|
||||||
|
//
|
||||||
|
// Not fatal on the error alone: re-attaching an already-connected
|
||||||
|
// container is an error too, and a benign one on any relaunch path. The
|
||||||
|
// container's own network list is the fact that settles it.
|
||||||
|
if let Err(e) = self
|
||||||
.docker
|
.docker
|
||||||
.connect_network(
|
.connect_network(
|
||||||
EDGE_NETWORK,
|
EDGE_NETWORK,
|
||||||
@@ -784,7 +810,23 @@ impl MissionRuntimeProvisioner {
|
|||||||
endpoint_config: Some(EndpointSettings::default()),
|
endpoint_config: Some(EndpointSettings::default()),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await;
|
.await
|
||||||
|
{
|
||||||
|
if self.is_on_edge_network(&name).await {
|
||||||
|
eprintln!(
|
||||||
|
"mission_runtime: {name} was already on {EDGE_NETWORK} ({e}) — \
|
||||||
|
egress is present, continuing"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Err(format!(
|
||||||
|
"attach mission runtime container to {EDGE_NETWORK}: {e} — \
|
||||||
|
{CORE_NETWORK} is internal and has no route off the host, so \
|
||||||
|
this mission would run with no egress at all: every provider \
|
||||||
|
call and every fetch would fail while the phase still \
|
||||||
|
reported completion"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.docker
|
self.docker
|
||||||
.start_container(&name, None::<StartContainerOptions>)
|
.start_container(&name, None::<StartContainerOptions>)
|
||||||
|
|||||||
Reference in New Issue
Block a user