fix(microvm): a mission with no repository can run in a VM, and its work comes back
Two halves, and the first was worse than the plan assumed. `run_phase_in_vm`
packed `<missions_root>/<mission>/repo` unconditionally — a directory a
repo-less mission does not have — and then required `/mission/repo/.git` inside
the guest before spending a turn. So a repo-less microVM phase did not merely
go uncaptured: it failed before the agent ran.
A repo-less mission now gets an EMPTY workspace at the same guest path, created
host-side so the collect unpacks back over it with no special case, and the
readiness probe asks for what was actually sent — the directory rather than a
`.git` that was never going to be there.
`mission_outputs` then drops its `runtime_kind <> 'microvm'` exclusion, whose
stated reason ("a microVM mission always has a checkout") is exactly what
stopped being true. Where the files come from now depends on the runtime, and
the difference is not cosmetic: a container mission's output is still inside a
running container, while a VM's has already been unpacked onto the host by the
end-of-turn collect. Asking docker for a VM mission's files would query a
container that never existed.
The recursive copy skips symlinks rather than following them — a link out of
the tree would publish whatever it points at.
`research-vm` is the proof, added to the suite as well as the dispatch: the same
assertions as `research-only` with `runtime_kind: microvm`. A scenario nobody
runs is a scenario that does not exist.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
e4bddeb1ba
commit
768e106614
@@ -286,8 +286,11 @@ async fn run_composed(
|
||||
OrchestratorError::Executor("a composed run must belong to a mission phase".into())
|
||||
})?;
|
||||
|
||||
let mission: (Option<Uuid>, Option<String>, Option<String>) =
|
||||
sqlx::query_as("SELECT target_node_id, backend, team_engine FROM missions WHERE id = $1")
|
||||
let mission: (Option<Uuid>, Option<String>, Option<String>, bool) =
|
||||
sqlx::query_as(
|
||||
"SELECT target_node_id, backend, team_engine, (repo_id IS NOT NULL) \
|
||||
FROM missions WHERE id = $1",
|
||||
)
|
||||
.bind(mission_id)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
@@ -312,6 +315,11 @@ async fn run_composed(
|
||||
phase_id,
|
||||
iteration: job.iteration.unwrap_or(1),
|
||||
repo: crate::mission_workspace::checkout_path(mission_id),
|
||||
// A repo-less composed mission gets an empty shared workspace, the
|
||||
// same as a solo phase — the graph's whole property is that node 2
|
||||
// sees node 1's files, and that holds whether or not it is a git
|
||||
// checkout.
|
||||
has_repo: mission.3,
|
||||
target_node_id: mission.0,
|
||||
backend: mission.1,
|
||||
team_engine: mission.2,
|
||||
|
||||
Reference in New Issue
Block a user