feat(#2450): append_subgraph primitive + sweep MetaLock grows rebuilds in-DAG

First half of making the startup sweep one DAG. Adds the runtime
subgraph-append machinery and switches the sweep MetaLock from fanning out
child Rebuild DAGs to growing one rebuild subgraph per stale agent into the
same DAG:

- JobQueue::append_subgraph(dag_id, nodes, dep_on) — the multi-node,
  multi-agent generalisation of append_node: rebases a subgraph's local deps
  onto the DAG's id space and roots it on the emitting node.
- NodeOutput.append_subgraph: Vec<Vec<NodeSpec>> — the executor→scheduler
  channel for it; scheduler drains it before completing the emitting node
  (same ordering as append_nodes).
- run_meta_lock sweep branch returns the stale agents' rebuild_nodes
  subgraphs via append_subgraph instead of fanout.

Follow-up commit collapses submit_boot_tree (drop boot_root + per-agent
reconcile child DAGs) so the whole boot is one DAG built inline.
This commit is contained in:
atlas 2026-07-15 01:11:01 +02:00 committed by mara
commit b6defdeaaf
3 changed files with 92 additions and 3 deletions

View file

@ -10,7 +10,7 @@ use std::sync::Arc;
use anyhow::{Context as _, Result};
use super::model::{NodeKind, State, Template};
use super::model::{NodeKind, NodeSpec, State, Template};
use super::{Claim, TerminalDag};
use crate::coordinator::Coordinator;
use crate::power::{ReconcileAction, reconcile_action};
@ -38,6 +38,16 @@ pub struct NodeOutput {
/// these *before* the emitting node's completion so the DAG never
/// rolls terminal with the appended work still pending.
pub append_nodes: Vec<NodeKind>,
/// Whole per-agent *subgraphs* to append into *this same* DAG at
/// runtime — the multi-node generalisation of `append_nodes`. Each
/// inner `Vec<NodeSpec>` is one independent subgraph whose `deps` are
/// local (0-based within that subgraph); the scheduler appends each via
/// [`JobQueue::append_subgraph`], which rebases the deps onto the DAG's
/// node-id space and roots the subgraph on the emitting node. The
/// startup sweep's `MetaLock` uses this to grow one stale-agent rebuild
/// subgraph per agent into the same boot DAG instead of fanning out
/// child DAGs. Same before-completion ordering as `append_nodes`.
pub append_subgraph: Vec<Vec<NodeSpec>>,
}
/// Step-label + build-log sink for one claimed node.
@ -276,8 +286,17 @@ async fn run_meta_lock(
if let Err(e) = crate::meta::lock_update_hyperhive().await {
tracing::warn!(error = ?e, "startup sweep: meta lock_update_hyperhive failed");
}
// Grow one rebuild subgraph per stale agent into *this* boot DAG
// (rooted on this `MetaLock`, so they build against the post-bump
// lock), rather than fanning out child DAGs. `relock = true` — a
// boot sweep relocks per-agent like a manual rebuild.
let append_subgraph = fanout
.unwrap_or_default()
.iter()
.map(|agent| super::templates::rebuild_nodes(agent, true, 0))
.collect();
return Ok(NodeOutput {
fanout: fanout.unwrap_or_default(),
append_subgraph,
..Default::default()
});
}