fix(placement): a composed graph needs every backend its nodes name
The full harness found it — 12 of 13 scenarios green, `roster` red:
roster: the planner sized this mission at 2 member(s) PASS
roster: the approved roster is on the mission (2 nodes, composed) PASS
roster: this run added 1 line(s) for a 2-member roster FAIL
topology_runs.error: turn executor failed: node n1 in a microVM:
vm_create failed: no rootfs for backend "canary-claude" on this node
The roster proposed `verifier@canary-claude`. Placement asked
`online_for_backend` about the MISSION's backend — `claude` — and architect
answered, holding `claude` and `local-ornith`. The graph's first node ran and
delivered, the second could not boot, and the mission finished half-done. The
question placement asked was true and insufficient.
A composed graph runs on ONE node, so that node needs every image its nodes ask
for. `required_backends` collects the mission's plus each
`config.roster.nodes[].attrs.backend`, and `online_for_backends` passes the
whole set to the same jsonb `@>` — containment already means "contains ALL of
these", so the query shape did not have to change, only what it was asked.
This is the failure mode the roster feature creates by existing: its entire
purpose is putting a verifier on a different provider, which is exactly what
makes one node insufficient. Nothing before the full suite had a reason to
exercise it — the composed scenario uses one backend for all five nodes.
`NoCapableNode` now names the set and says why one node must hold all of them.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
171f901bcd
commit
529497febb
@@ -420,7 +420,12 @@ pub async fn capacity(
|
||||
) -> Result<Json<Value>, ApiError> {
|
||||
let ws = user.workspace_id.as_uuid().to_owned();
|
||||
let (fit, unfit) =
|
||||
crate::vm_placement::survey(&state.pool, &state.node_hub, ws, q.backend.as_deref())
|
||||
crate::vm_placement::survey(
|
||||
&state.pool,
|
||||
&state.node_hub,
|
||||
ws,
|
||||
&crate::vm_placement::required_backends(q.backend.as_deref(), None),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
eprintln!("fleet capacity survey failed: {e}");
|
||||
|
||||
Reference in New Issue
Block a user