refactor(#2897): carry the approval id on the deploy nodes, not the Dag
`DagSpec`/`NodeKind::Dag` carried an `Option<i64>` approval id that four
deploy phases read back out through `Claim`, via a fallible helper whose
error ("approval deploy dag N has no approval_id") described a state the
type system should have forbidden. Two other templates (`spawn`,
`meta_update`) set the field for nothing: their approval is resolved by
the `ResolveApproval` tails, which already carry the id themselves.
So the id moves onto the nodes that actually need it —
`DeployWindow` / `MergeVerify` / `DeployApply` / `FinalizeDeploy` /
`DeployTail` each take an `i64`, the same way `ResolveApproval` always
has. `templates::approval_deploy` builds all of them in one place with
the value in hand, and `deploy_rebuild_nodes` takes it as a parameter so
the `FinalizeDeploy` it appends at runtime is constructed the same way.
Falls out of that:
- `deploy_approval_id` and its runtime error path delete; each executor
takes the id from its own node payload at dispatch.
- `run_deploy_window` had nothing left to do but validate that id, so the
node joins `Dag` on the shared no-op arm.
- `Claim::approval_id` and `DagMeta::approval_id` delete.
- `dag_view`'s DAG-level projection onto `DeployWindow` reads the payload
instead. The wire `NodeView::approval_id` is unchanged: still set on
the deploy root alone, so the dashboard still renders one approval link
per DAG rather than one per phase.
No option surface is touched, so there is no nix-eval gate here; checked
with clippy (`--all-targets -D warnings`), `cargo test -p hive-c0re`
(320 passed) and `nix fmt`.
This commit is contained in:
parent
772482a52a
commit
84aed5fb51
7 changed files with 91 additions and 99 deletions
|
|
@ -92,21 +92,29 @@ pub(super) async fn run_node(coord: &Arc<Coordinator>, claim: &Claim) -> Result<
|
|||
NodeKind::WriteDropin { .. } => run_write_dropin(coord, claim).await,
|
||||
NodeKind::WritePermFile { .. } => run_write_perm_file(coord, claim).await,
|
||||
NodeKind::Reparent { .. } => run_reparent(coord, claim).await,
|
||||
NodeKind::DeployWindow { .. } => run_deploy_window(claim),
|
||||
NodeKind::MergeVerify { .. } => run_merge_verify(coord, claim).await,
|
||||
NodeKind::DeployApply { .. } => run_deploy_apply(coord, claim).await,
|
||||
NodeKind::FinalizeDeploy { .. } => run_finalize_deploy(coord, claim).await,
|
||||
NodeKind::DeployTail { .. } => run_deploy_tail(coord, claim).await,
|
||||
NodeKind::MergeVerify { approval_id, .. } => run_merge_verify(coord, *approval_id).await,
|
||||
NodeKind::DeployApply { approval_id, .. } => {
|
||||
run_deploy_apply(coord, claim, *approval_id).await
|
||||
}
|
||||
NodeKind::FinalizeDeploy { approval_id, .. } => {
|
||||
run_finalize_deploy(coord, *approval_id).await
|
||||
}
|
||||
NodeKind::DeployTail { approval_id, .. } => {
|
||||
run_deploy_tail(coord, claim, *approval_id).await
|
||||
}
|
||||
NodeKind::ResolveApproval {
|
||||
approval_id,
|
||||
outcome,
|
||||
} => run_resolve_approval(coord, claim, *approval_id, *outcome).await,
|
||||
NodeKind::EmitRebuilt { ok, .. } => Ok(run_emit_rebuilt(coord, claim, *ok)),
|
||||
NodeKind::SetWanted { up, .. } => run_set_wanted(coord, claim, *up),
|
||||
// Pure grouping container — no work; completing it lets it reach
|
||||
// `Finishing` so its child work nodes start. The DAG's terminal side
|
||||
// effect, if any, is its own tail node in the graph.
|
||||
NodeKind::Dag { .. } => Ok(NodeOutput::default()),
|
||||
// The two nodes that carry no work of their own; completing either
|
||||
// lets it reach `Finishing` so the nodes under it start.
|
||||
// - `Dag`: pure grouping container. The DAG's terminal side effect, if
|
||||
// any, is its own tail node in the graph.
|
||||
// - `DeployWindow`: pure resource holder — the meta window, agent lease
|
||||
// and build slot it declares stay held until its subtree settles.
|
||||
NodeKind::Dag { .. } | NodeKind::DeployWindow { .. } => Ok(NodeOutput::default()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -587,36 +595,11 @@ async fn run_reparent(coord: &Arc<Coordinator>, claim: &Claim) -> Result<NodeOut
|
|||
Ok(NodeOutput::default())
|
||||
}
|
||||
|
||||
/// The approval id every deploy phase re-reads its approval row by. Fails the
|
||||
/// node when the DAG carries none, which would mean a `MergeConfigPr` DAG was
|
||||
/// built without going through `templates::approval_deploy`.
|
||||
fn deploy_approval_id(claim: &Claim) -> Result<i64> {
|
||||
claim
|
||||
.approval_id
|
||||
.with_context(|| format!("approval deploy dag {} has no approval_id", claim.dag_id))
|
||||
}
|
||||
|
||||
/// The deploy subtree's root: pure resource holder, no work of its own.
|
||||
///
|
||||
/// It exists so the global meta window (plus the agent lease and a build slot)
|
||||
/// is held continuously across every phase below it. `prepare_deploy` leaves
|
||||
/// `flake.lock` staged-uncommitted for the whole container build, and any other
|
||||
/// meta mutation landing inside that span would sweep the staged lock into its
|
||||
/// own commit and neuter `abort_deploy` — so the window has to outlive any one
|
||||
/// node, which the `MutexGuard` this replaced could not do.
|
||||
///
|
||||
/// Completing immediately moves it to `Finishing`, which is what starts the
|
||||
/// children; the resources stay held until the whole subtree settles.
|
||||
fn run_deploy_window(claim: &Claim) -> Result<NodeOutput> {
|
||||
deploy_approval_id(claim)?;
|
||||
Ok(NodeOutput::default())
|
||||
}
|
||||
|
||||
/// Deploy phase 1 — drift gate, fetch, eval-verify. Mutates nothing, so a
|
||||
/// failure here cancel-cascades the rest of the subtree with the forge and the
|
||||
/// applied repo exactly as they were.
|
||||
async fn run_merge_verify(coord: &Arc<Coordinator>, claim: &Claim) -> Result<NodeOutput> {
|
||||
crate::actions::run_deploy_merge_verify(coord, deploy_approval_id(claim)?)
|
||||
async fn run_merge_verify(coord: &Arc<Coordinator>, approval_id: i64) -> Result<NodeOutput> {
|
||||
crate::actions::run_deploy_merge_verify(coord, approval_id)
|
||||
.await
|
||||
.map(|()| NodeOutput::default())
|
||||
}
|
||||
|
|
@ -630,18 +613,25 @@ async fn run_merge_verify(coord: &Arc<Coordinator>, claim: &Claim) -> Result<Nod
|
|||
/// their `MetaSync` declares is re-entered rather than deadlocked against the
|
||||
/// ancestor already holding it. On failure nothing is appended and the tail
|
||||
/// compensates, exactly as before.
|
||||
async fn run_deploy_apply(coord: &Arc<Coordinator>, claim: &Claim) -> Result<NodeOutput> {
|
||||
crate::actions::run_deploy_apply(coord, deploy_approval_id(claim)?).await?;
|
||||
async fn run_deploy_apply(
|
||||
coord: &Arc<Coordinator>,
|
||||
claim: &Claim,
|
||||
approval_id: i64,
|
||||
) -> Result<NodeOutput> {
|
||||
crate::actions::run_deploy_apply(coord, approval_id).await?;
|
||||
Ok(NodeOutput {
|
||||
append_subgraph: vec![super::templates::deploy_rebuild_nodes(claim.kind.agent())],
|
||||
append_subgraph: vec![super::templates::deploy_rebuild_nodes(
|
||||
claim.kind.agent(),
|
||||
approval_id,
|
||||
)],
|
||||
})
|
||||
}
|
||||
|
||||
/// Deploy phase 3 — close the staged-lock window once the appended rebuild has
|
||||
/// come up clean: drop the rollback ref, plant the `deployed/<id>` tag, commit
|
||||
/// the staged lock.
|
||||
async fn run_finalize_deploy(coord: &Arc<Coordinator>, claim: &Claim) -> Result<NodeOutput> {
|
||||
crate::actions::run_finalize_deploy(coord, deploy_approval_id(claim)?)
|
||||
async fn run_finalize_deploy(coord: &Arc<Coordinator>, approval_id: i64) -> Result<NodeOutput> {
|
||||
crate::actions::run_finalize_deploy(coord, approval_id)
|
||||
.await
|
||||
.map(|()| NodeOutput::default())
|
||||
}
|
||||
|
|
@ -653,14 +643,13 @@ async fn run_finalize_deploy(coord: &Arc<Coordinator>, claim: &Claim) -> Result<
|
|||
///
|
||||
/// Takes the agent from the node payload so the tail can still compensate when
|
||||
/// the approval row is gone (deny race, purge).
|
||||
async fn run_deploy_tail(coord: &Arc<Coordinator>, claim: &Claim) -> Result<NodeOutput> {
|
||||
crate::actions::run_deploy_tail(
|
||||
coord,
|
||||
Some(claim.dag_id),
|
||||
claim.kind.agent(),
|
||||
deploy_approval_id(claim)?,
|
||||
)
|
||||
.await;
|
||||
async fn run_deploy_tail(
|
||||
coord: &Arc<Coordinator>,
|
||||
claim: &Claim,
|
||||
approval_id: i64,
|
||||
) -> Result<NodeOutput> {
|
||||
crate::actions::run_deploy_tail(coord, Some(claim.dag_id), claim.kind.agent(), approval_id)
|
||||
.await;
|
||||
Ok(NodeOutput::default())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@ pub struct Claim {
|
|||
/// The agent this node targets (its own, not a DAG-level field). Empty for
|
||||
/// the agentless [`NodeKind::MetaLock`] + [`NodeKind::Dag`] container nodes.
|
||||
pub agent: String,
|
||||
pub approval_id: Option<i64>,
|
||||
pub inputs: Vec<String>,
|
||||
/// Transient pill kind for the lease window (from the spec). Whether the
|
||||
/// pill is currently shown is derived from live lease ownership
|
||||
|
|
@ -94,7 +93,6 @@ struct DagMeta {
|
|||
source: Source,
|
||||
reason: String,
|
||||
transient: Option<TransientKind>,
|
||||
approval_id: Option<i64>,
|
||||
inputs: Vec<String>,
|
||||
created_at: i64,
|
||||
}
|
||||
|
|
@ -220,7 +218,6 @@ impl JobQueue {
|
|||
source: spec.source,
|
||||
reason: spec.reason,
|
||||
transient: spec.transient,
|
||||
approval_id: spec.approval_id,
|
||||
inputs: spec.inputs,
|
||||
created_at: now_unix(),
|
||||
},
|
||||
|
|
@ -307,7 +304,6 @@ impl JobQueue {
|
|||
node_id: id,
|
||||
kind,
|
||||
agent,
|
||||
approval_id: meta.approval_id,
|
||||
inputs: meta.inputs,
|
||||
transient: meta.transient,
|
||||
});
|
||||
|
|
@ -485,7 +481,6 @@ impl QueueInner {
|
|||
source,
|
||||
reason,
|
||||
transient,
|
||||
approval_id,
|
||||
inputs,
|
||||
created_at,
|
||||
} = &self.sched.graph().node(container)?.payload
|
||||
|
|
@ -496,7 +491,6 @@ impl QueueInner {
|
|||
source: *source,
|
||||
reason: reason.clone(),
|
||||
transient: *transient,
|
||||
approval_id: *approval_id,
|
||||
inputs: inputs.clone(),
|
||||
created_at: *created_at,
|
||||
})
|
||||
|
|
@ -547,13 +541,14 @@ impl QueueInner {
|
|||
Dep::Resource { .. } => None,
|
||||
})
|
||||
.collect();
|
||||
// Non-derivable per-node payload rides the node that owns it. For a
|
||||
// deploy that's the subtree root: the phases below it are ordinary
|
||||
// nodes, and hanging the approval link off all four would render the
|
||||
// same card four times.
|
||||
let approval_id = matches!(node.payload, NodeKind::DeployWindow { .. })
|
||||
.then_some(meta.approval_id)
|
||||
.flatten();
|
||||
// Non-derivable per-node payload rides the node that owns it. Every
|
||||
// deploy phase carries the approval id, but only the subtree root
|
||||
// projects it onto the wire — hanging the approval link off all of
|
||||
// them would render the same card once per phase.
|
||||
let approval_id = match &node.payload {
|
||||
NodeKind::DeployWindow { approval_id, .. } => Some(*approval_id),
|
||||
_ => None,
|
||||
};
|
||||
let inputs = if matches!(node.payload, NodeKind::MetaLock { .. }) {
|
||||
meta.inputs.clone()
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -154,13 +154,17 @@ pub enum NodeKind {
|
|||
/// Cheap, too: the window has to span the container build regardless (see
|
||||
/// [`NodeKind::DeployApply`]), so nothing is over-serialised by hoisting
|
||||
/// the slot and the lease up alongside it.
|
||||
DeployWindow { agent: String },
|
||||
///
|
||||
/// Carries the approval row every phase below it re-reads, like each of
|
||||
/// those phases does — the id is the node's own payload, not something a
|
||||
/// DAG-level catch-all hands down.
|
||||
DeployWindow { agent: String, approval_id: i64 },
|
||||
/// Deploy phase 1 — **verify only, mutates nothing.** Drift-gate the
|
||||
/// approval's PR head, fetch it into the applied repo, and eval-verify the
|
||||
/// merge head. Any failure here aborts the deploy with the forge state
|
||||
/// untouched, so it is safely retryable and cancel-safe: nothing downstream
|
||||
/// has happened yet.
|
||||
MergeVerify { agent: String },
|
||||
MergeVerify { agent: String, approval_id: i64 },
|
||||
/// Deploy phase 2 — the irreversible fast-forward plus the *opening* half of
|
||||
/// the two-phase meta deploy: park the rollback ref, ff-merge the reviewed
|
||||
/// head to `main` via the forge API, ff `applied/main`, and
|
||||
|
|
@ -174,7 +178,7 @@ pub enum NodeKind {
|
|||
/// staged-lock window is likewise its own node
|
||||
/// ([`NodeKind::FinalizeDeploy`]), and the compensation path is
|
||||
/// [`NodeKind::DeployTail`].
|
||||
DeployApply { agent: String },
|
||||
DeployApply { agent: String, approval_id: i64 },
|
||||
/// Deploy phase 3 — close the two-phase meta deploy once the rebuild
|
||||
/// subgraph under [`NodeKind::DeployApply`] has come up clean: drop the
|
||||
/// rollback ref, plant the `deployed/<id>` tag, commit the staged
|
||||
|
|
@ -190,7 +194,7 @@ pub enum NodeKind {
|
|||
/// The trailing `meta::finalize_deploy` stays warn-only: by then the
|
||||
/// container already runs the new config, and an uncommitted staged lock is
|
||||
/// something the operator can commit by hand.
|
||||
FinalizeDeploy { agent: String },
|
||||
FinalizeDeploy { agent: String, approval_id: i64 },
|
||||
/// Deploy compensation **and bookkeeping** tail — `AfterAny`
|
||||
/// [`NodeKind::DeployApply`], so it runs on success, failure, and cancel
|
||||
/// alike, in the same spirit as the rebuild template's tail `Reconcile`
|
||||
|
|
@ -215,7 +219,7 @@ pub enum NodeKind {
|
|||
/// this node a no-op. Parking it in git rather than in a node payload also
|
||||
/// means it survives a `hive-c0re` restart mid-deploy, which an in-memory
|
||||
/// queue does not.
|
||||
DeployTail { agent: String },
|
||||
DeployTail { agent: String, approval_id: i64 },
|
||||
/// Tail node of an approval-carrying DAG (spawn / opaque deploy / config-PR
|
||||
/// merge): resolve the approval row from how the work actually ended.
|
||||
///
|
||||
|
|
@ -277,7 +281,6 @@ pub enum NodeKind {
|
|||
source: Source,
|
||||
reason: String,
|
||||
transient: Option<TransientKind>,
|
||||
approval_id: Option<i64>,
|
||||
inputs: Vec<String>,
|
||||
created_at: i64,
|
||||
},
|
||||
|
|
@ -336,11 +339,11 @@ impl NodeKind {
|
|||
| NodeKind::Drain { agent }
|
||||
| NodeKind::WriteDropin { agent }
|
||||
| NodeKind::WritePermFile { agent, .. }
|
||||
| NodeKind::DeployWindow { agent }
|
||||
| NodeKind::MergeVerify { agent }
|
||||
| NodeKind::DeployApply { agent }
|
||||
| NodeKind::FinalizeDeploy { agent }
|
||||
| NodeKind::DeployTail { agent }
|
||||
| NodeKind::DeployWindow { agent, .. }
|
||||
| NodeKind::MergeVerify { agent, .. }
|
||||
| NodeKind::DeployApply { agent, .. }
|
||||
| NodeKind::FinalizeDeploy { agent, .. }
|
||||
| NodeKind::DeployTail { agent, .. }
|
||||
| NodeKind::EmitRebuilt { agent, .. }
|
||||
| NodeKind::SetWanted { agent, .. } => agent,
|
||||
NodeKind::MetaLock { .. }
|
||||
|
|
@ -456,13 +459,6 @@ pub struct DagSpec {
|
|||
pub source: Source,
|
||||
/// Free-form "why".
|
||||
pub reason: String,
|
||||
/// The approval row this DAG belongs to, for display + the `approval_id` on
|
||||
/// every [`Claim`]. The *resolving* of it rides the
|
||||
/// [`NodeKind::ResolveApproval`] tail node instead — this field does not
|
||||
/// drive it.
|
||||
///
|
||||
/// [`Claim`]: super::Claim
|
||||
pub approval_id: Option<i64>,
|
||||
/// Meta-update only: the inputs to bump. Display copy lives on the DAG.
|
||||
pub inputs: Vec<String>,
|
||||
/// Dashboard transient pill (and crash-watch suppression) held for
|
||||
|
|
|
|||
|
|
@ -207,7 +207,6 @@ fn power_dag(
|
|||
DagSpec {
|
||||
source,
|
||||
reason,
|
||||
approval_id: None,
|
||||
inputs: Vec::new(),
|
||||
transient: Some(transient),
|
||||
nodes,
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ pub(crate) fn rebuild_nodes(agent: &str, opts: RebuildOpts, base: u64) -> Vec<No
|
|||
/// inside the `DeployWindow`'s subtree — so the `MetaWindow` this subgraph's
|
||||
/// `MetaSync` and `FinalizeDeploy` declare is re-entered from the ancestor
|
||||
/// already holding it rather than deadlocking against it.
|
||||
pub(crate) fn deploy_rebuild_nodes(agent: &str) -> Vec<NodeSpec> {
|
||||
pub(crate) fn deploy_rebuild_nodes(agent: &str, approval_id: i64) -> Vec<NodeSpec> {
|
||||
let mut nodes = rebuild_nodes(
|
||||
agent,
|
||||
RebuildOpts {
|
||||
|
|
@ -318,6 +318,7 @@ pub(crate) fn deploy_rebuild_nodes(agent: &str) -> Vec<NodeSpec> {
|
|||
nodes.push(node(
|
||||
NodeKind::FinalizeDeploy {
|
||||
agent: agent.to_owned(),
|
||||
approval_id,
|
||||
},
|
||||
vec![
|
||||
Dep {
|
||||
|
|
@ -366,7 +367,6 @@ pub fn rebuild(agent: &str, source: Source, reason: String, relock: bool) -> Dag
|
|||
DagSpec {
|
||||
source,
|
||||
reason,
|
||||
approval_id: None,
|
||||
inputs: Vec::new(),
|
||||
transient: Some(TransientKind::Rebuilding),
|
||||
nodes,
|
||||
|
|
@ -403,16 +403,38 @@ pub fn approval_deploy(agent: &str, approval_id: i64, reason: String) -> DagSpec
|
|||
DagSpec {
|
||||
source: Source::Approval,
|
||||
reason,
|
||||
approval_id: Some(approval_id),
|
||||
inputs: Vec::new(),
|
||||
transient: Some(TransientKind::Rebuilding),
|
||||
nodes: vec![
|
||||
node(NodeKind::DeployWindow { agent: a() }, Vec::new()),
|
||||
child(0, NodeKind::MergeVerify { agent: a() }, Vec::new()),
|
||||
child(0, NodeKind::DeployApply { agent: a() }, after_ok(1)),
|
||||
node(
|
||||
NodeKind::DeployWindow {
|
||||
agent: a(),
|
||||
approval_id,
|
||||
},
|
||||
Vec::new(),
|
||||
),
|
||||
child(
|
||||
0,
|
||||
NodeKind::DeployTail { agent: a() },
|
||||
NodeKind::MergeVerify {
|
||||
agent: a(),
|
||||
approval_id,
|
||||
},
|
||||
Vec::new(),
|
||||
),
|
||||
child(
|
||||
0,
|
||||
NodeKind::DeployApply {
|
||||
agent: a(),
|
||||
approval_id,
|
||||
},
|
||||
after_ok(1),
|
||||
),
|
||||
child(
|
||||
0,
|
||||
NodeKind::DeployTail {
|
||||
agent: a(),
|
||||
approval_id,
|
||||
},
|
||||
vec![Dep {
|
||||
on: 2,
|
||||
when: DepWhen::AFTER_ANY,
|
||||
|
|
@ -440,7 +462,6 @@ pub fn reconcile_only(
|
|||
DagSpec {
|
||||
source,
|
||||
reason,
|
||||
approval_id: None,
|
||||
inputs: Vec::new(),
|
||||
transient,
|
||||
nodes: vec![node(
|
||||
|
|
@ -467,7 +488,6 @@ pub fn spawn(agent: &str, approval_id: i64, reason: String) -> DagSpec {
|
|||
DagSpec {
|
||||
source: Source::Approval,
|
||||
reason,
|
||||
approval_id: Some(approval_id),
|
||||
inputs: Vec::new(),
|
||||
transient: Some(TransientKind::Spawning),
|
||||
nodes: {
|
||||
|
|
@ -513,7 +533,6 @@ pub fn perm_change(agent: &str, source: Source, reason: String, payload: PermPay
|
|||
DagSpec {
|
||||
source,
|
||||
reason,
|
||||
approval_id: None,
|
||||
inputs: Vec::new(),
|
||||
transient: Some(TransientKind::Rebuilding),
|
||||
nodes,
|
||||
|
|
@ -553,7 +572,6 @@ pub fn meta_update(
|
|||
DagSpec {
|
||||
source,
|
||||
reason,
|
||||
approval_id,
|
||||
inputs,
|
||||
transient: Some(TransientKind::Rebuilding),
|
||||
nodes,
|
||||
|
|
@ -577,7 +595,6 @@ pub fn reparent(
|
|||
DagSpec {
|
||||
source,
|
||||
reason,
|
||||
approval_id: None,
|
||||
inputs: Vec::new(),
|
||||
transient: None,
|
||||
nodes: vec![node(NodeKind::Reparent { moves }, Vec::new())],
|
||||
|
|
|
|||
|
|
@ -246,7 +246,6 @@ fn graceful_rebuild_chain_drains_before_stopping() {
|
|||
let spec = DagSpec {
|
||||
source: Source::AutoUpdate,
|
||||
reason: "sweep".to_owned(),
|
||||
approval_id: None,
|
||||
inputs: Vec::new(),
|
||||
transient: None,
|
||||
nodes: templates::rebuild_nodes(
|
||||
|
|
@ -725,7 +724,6 @@ fn append_subgraph_roots_on_emitter_and_rebases_local_deps() {
|
|||
let spec = DagSpec {
|
||||
source: Source::AutoUpdate,
|
||||
reason: "sweep".to_owned(),
|
||||
approval_id: None,
|
||||
inputs: Vec::new(),
|
||||
transient: None,
|
||||
nodes: vec![NodeSpec {
|
||||
|
|
@ -1214,7 +1212,7 @@ fn deploy_apply_grows_rebuild_subgraph_and_finalizes_after_it() {
|
|||
// gate immediately and letting the deploy "finish" before it had built.
|
||||
let grown = q.append_subgraph(
|
||||
id,
|
||||
&templates::deploy_rebuild_nodes("agent-a"),
|
||||
&templates::deploy_rebuild_nodes("agent-a", 11),
|
||||
apply.node_id,
|
||||
);
|
||||
assert!(!grown.is_empty(), "subgraph grafted onto the apply node");
|
||||
|
|
@ -1272,7 +1270,7 @@ fn deploy_dag_skips_finalize_but_still_tails_a_failed_graft() {
|
|||
let apply = claim_one(&q);
|
||||
q.append_subgraph(
|
||||
id,
|
||||
&templates::deploy_rebuild_nodes("agent-a"),
|
||||
&templates::deploy_rebuild_nodes("agent-a", 13),
|
||||
apply.node_id,
|
||||
);
|
||||
q.complete_node(apply.node_id, Ok(()));
|
||||
|
|
@ -1470,7 +1468,6 @@ fn spawn_shape_provision_create_dropin_reconcile() {
|
|||
for expected in ["provision", "create", "write_dropin", "reconcile"] {
|
||||
let c = claim_one(&q);
|
||||
assert_eq!(c.kind.as_str(), expected);
|
||||
assert_eq!(c.approval_id, Some(7));
|
||||
q.complete_node(c.node_id, Ok(()));
|
||||
}
|
||||
settle_approval_tail(&q, 7, TerminalState::Done);
|
||||
|
|
|
|||
|
|
@ -347,7 +347,6 @@ fn submit_boot_tree(
|
|||
// land; the boot DAG as a whole has no terminal side effect, so no tail.
|
||||
source: Source::AutoUpdate,
|
||||
reason,
|
||||
approval_id: None,
|
||||
inputs: Vec::new(),
|
||||
// Rebuilding when the sweep will grow rebuild subgraphs (per-agent
|
||||
// crash-watch suppression during their Swap, applied at claim time);
|
||||
|
|
|
|||
Loading…
Reference in a new issue