refactor(#2772): enumflags2 for the edge set; drop re-export shims

Review follow-ups on #2785.

`DepWhen` wraps `BitFlags<TerminalState>` instead of a hand-rolled `u8`,
so the bit manipulation belongs to the library and `TerminalState` gains
its flag value from `#[bitflags]` rather than a `bit()` match anyone
could get wrong. `of`/`accepts`/`is_empty` become one-liners over it.

Serialization is written out by hand rather than derived: clippy's
`unsafe_derive_deserialize` fires on deriving over a type with unsafe
internals, and the honest fix is to say what the wire form is. It is now
the list of accepted outcomes — `["done","failed"]` — which reads better
than a bitmask and survives the bits being renumbered.

Also drops the `pub use` re-export of `DepWhen` / `TerminalState` from
hive-c0re's `model`. It existed so that `use super::model::…` kept
compiling, which is a shim for one consumer's convenience; the sites
import from `hive_jobq` directly now.

And removes comments narrating what the code used to be. Git holds that.
This commit is contained in:
atlas 2026-07-27 17:07:27 +02:00 committed by mara
commit 940c928fee
8 changed files with 74 additions and 50 deletions

View file

@ -11,7 +11,9 @@ use std::sync::Arc;
use anyhow::{Context as _, Result};
use super::Claim;
use super::model::{NodeKind, NodeSpec, TerminalState};
use hive_jobq::TerminalState;
use super::model::{NodeKind, NodeSpec};
use crate::coordinator::Coordinator;
use crate::power::{ReconcileAction, reconcile_action};

View file

@ -18,10 +18,9 @@
//! by a subtree root and borrowed by its descendants (continuity);
//! - per-DAG terminal work is an ordinary **tail node**
//! ([`NodeKind::ResolveApproval`] / [`NodeKind::EmitRebuilt`]) that the builder
//! appends in [`templates`], weak-edged (`AfterAny`) onto the DAG's other group
//! roots so it runs on success, failure and cancel alike. It reads how the work
//! went off its own [`Claim::deps`] — no inline hook fired from outside the
//! graph, no drained event stream.
//! appends in [`templates`], edged onto the DAG's other group roots by the
//! outcome it reports. Templates emit one tail per outcome and the graph runs
//! exactly one, so nothing branches at runtime.
//!
//! The queue is runtime-only (no persistence): an empty graph on boot; desired
//! state is re-derived by the reconcile sweep. A single scheduler task
@ -49,7 +48,8 @@ use hive_sh4re::wire_time::now_unix;
use tokio::sync::Notify;
use crate::coordinator::TransientKind;
pub use model::{DagSpec, DagView, NodeKind, NodeSpec, PermPayload, Source, State, TerminalState};
pub use hive_jobq::TerminalState;
pub use model::{DagSpec, DagView, NodeKind, NodeSpec, PermPayload, Source, State};
use resource::Resource;
/// How many terminal DAGs (`Done` / `Failed` / `Cancelled`) the snapshot

View file

@ -17,11 +17,7 @@ use serde::Serialize;
use crate::coordinator::TransientKind;
/// When a dependency edge is satisfied — re-exported from [`hive_jobq`] rather
/// than mirrored here. It used to be a duplicate enum with a `to_crate_when`
/// translation beside it; the copy bought nothing and had to be widened in
/// lockstep every time the crate's edge model grew.
pub use hive_jobq::{DepWhen, TerminalState};
use hive_jobq::{DepWhen, TerminalState};
/// A dependency edge (intra-DAG only — cross-DAG ordering comes from
/// the per-agent lease + dedup, never from edges between DAGs).
@ -248,14 +244,14 @@ pub enum NodeKind {
/// they `Failed`, and **nothing at all** when they `Cancelled` (a cancelled DAG
/// never ran, so there is no rebuild to report).
///
/// One node **per agent**, unlike the DAG-wide hook it replaces: a multi-agent
/// DAG now reports each agent's own outcome instead of painting every agent with
/// the whole DAG's roll-up. And one per *outcome* — `ok` isn't computed here,
/// it's which of the pair the graph let run.
/// One node per **agent** — a multi-agent DAG reports each agent's own
/// outcome rather than painting all of them with the whole DAG's roll-up —
/// and one per **outcome**: `ok` isn't computed here, it's which of the pair
/// the graph let run.
///
/// There is deliberately no cancel variant: a DAG dropped before it started
/// has no rebuild to report, and neither tail's edge accepts `Cancelled`, so
/// both are cancelled with the rest and nothing is emitted.
/// No cancel variant, deliberately: a DAG dropped before it started has no
/// rebuild to report, and neither tail's edge accepts `Cancelled`, so both
/// are cancelled with the rest and nothing is emitted.
EmitRebuilt { agent: String, ok: bool },
/// Write the agent's durable power intent (`wanted = Up` when `up`, else
/// `Offline`) as a first-class DAG node, at the head of a power-op

View file

@ -30,7 +30,9 @@
use anyhow::{Result, bail};
use super::model::{DagSpec, Dep, DepWhen, NodeKind, NodeSpec, PermPayload, Source, TerminalState};
use hive_jobq::{DepWhen, TerminalState};
use super::model::{DagSpec, Dep, NodeKind, NodeSpec, PermPayload, Source};
use crate::coordinator::TransientKind;
/// After-ok edge on the previous node — the common chain link. Shared with

View file

@ -6,7 +6,9 @@
//! scheduler's async loop is a thin claim/complete pump over the same
//! methods exercised here.
use super::model::{Dep, DepWhen, NodeKind, NodeSpec};
use hive_jobq::DepWhen;
use super::model::{Dep, NodeKind, NodeSpec};
use super::*;
fn submit(q: &JobQueue, spec: DagSpec) -> u64 {