jobq: split RebuildOpts into two rebuild entry points

RebuildOpts held one real parameter (relock) and one single-call-site
flag (graceful). The struct justified itself as swap-protection for two
positional bools; with graceful out of the signature there is nothing
left to swap.

graceful stays an internal switch rather than moving to the caller: it
re-parents the stop root (StopForUpdate goes from part_of(prebuild) to
part_of(signal)) rather than prepending nodes, so a caller could only
declare it by being handed the subtree's internals — and that nesting
keeps the agent lease continuous across the whole stop.

run_meta_lock no longer returns options: both fields were a pure
function of the sweep flag its caller had just passed in.

315 tests pass unchanged.
This commit is contained in:
atlas 2026-08-03 02:00:16 +02:00
commit 05f84191fb
4 changed files with 80 additions and 110 deletions

View file

@ -427,15 +427,7 @@ fn graceful_rebuild_chain_drains_before_stopping() {
let q = JobQueue::new(1);
let id = q
.submit(Source::AutoUpdate, "sweep".to_owned(), |b: &Job| {
templates::rebuild_nodes(
b,
"agent-a",
templates::RebuildOpts {
relock: true,
graceful: true,
},
None,
);
templates::graceful_rebuild_nodes(b, "agent-a", true, None);
})
.expect("valid shape");
assert_eq!(
@ -469,15 +461,7 @@ fn non_graceful_rebuild_has_no_signal_or_drain() {
// observable where it matters — in what the scheduler runs.
let q = JobQueue::new(1);
let id = submit(&q, "manual", |b| {
templates::rebuild_nodes(
b,
"agent-a",
templates::RebuildOpts {
relock: true,
graceful: false,
},
None,
);
templates::rebuild_nodes(b, "agent-a", true, None);
});
assert_eq!(
declared_shape(&q, id)
@ -957,9 +941,10 @@ fn a_fanned_out_mechanical_node_declares_its_agent_lease() {
/// against the lock the emitter just bumped.
///
/// Replaces `grown_subgraph_roots_on_emitter_and_rebases_local_deps` and
/// `meta_update_grows_cascade_in_dag`, which differed only in `RebuildOpts` and
/// each minted a builder by hand to simulate the graft. What they were checking
/// is `templates::grown_rebuilds`, so this calls it.
/// `meta_update_grows_cascade_in_dag`, which differed only in which rebuild
/// flavour they grew and each minted a builder by hand to simulate the graft.
/// What they were checking is the `grown_*_rebuilds` templates, so this calls
/// one — the boot sweep's, since that is the caller that grows a graceful one.
///
/// That the grafted work lands under the emitter, and that the emitter parks in
/// `Finishing` until it settles, is `hive_jobq`'s
@ -970,14 +955,7 @@ fn a_meta_lock_grows_one_rebuild_subgraph_per_agent() {
let agents = vec!["alice".to_owned(), "bob".to_owned()];
let id = q
.submit(Source::AutoUpdate, "sweep".to_owned(), |b: &Job| {
templates::grown_rebuilds(
b,
&agents,
templates::RebuildOpts {
relock: true,
graceful: true,
},
);
templates::grown_graceful_rebuilds(b, &agents, true);
})
.expect("valid shape");