From 730c923a97fbfccc5e5488733fd6870705782740 Mon Sep 17 00:00:00 2001 From: atlas Date: Mon, 3 Aug 2026 21:47:51 +0200 Subject: [PATCH] docs: stop asserting DagView/NodeView after their deletion The deletion PR removed the types but left ~10 sites still describing them. Two are real breakage rather than staleness: rustdoc intra-doc links to deleted items ([NodeView::kind] and [Self::snapshot] in job_queue/mod.rs). Neither clippy --all-targets -D warnings nor cargo test resolves intra-doc links, so the tree was green with both already dangling. The rest reassert facts the deletion made false: docs/coordinator.md documented the event as RebuildQueueChanged { seq, queue: [DagView...] } with a per-node field list, and three sites pointed at the removed /api/state.rebuild_queue endpoint. One is pointer rot rather than a rename, and no grep for a deleted name finds it: SchedulesChanged justified itself as "same snapshot-shape rationale as RebuildQueueChanged" -- which the deletion turned into the one event that is not a snapshot. Repointed at TombstonesChanged / MetaInputsChanged, in both the Rust doc and the dashboard doc. Two are pre-existing and strictly out of scope, swept under the pfadfinderregel because the same grep surfaced them: hive-sh4re/README advertised a jobs module that crate has not had since the host-sock split, and hive-host-sock/README claimed its own payload types live in hive-sh4re. Docs and comments only -- no behaviour, no API, no test changes. --- docs/approvals.md | 4 ++-- docs/coordinator.md | 32 ++++++++++++++++++--------- docs/web-ui/dashboard.md | 29 ++++++++++++------------ hive-c0re/src/coordinator.rs | 12 ++++++---- hive-c0re/src/dashboard/build_logs.rs | 2 +- hive-c0re/src/dashboard_events.rs | 3 ++- hive-c0re/src/job_queue/mod.rs | 15 +++++++------ hive-c0re/src/job_queue/model.rs | 3 ++- hive-host-sock/README.md | 12 +++++++--- hive-sh4re/README.md | 2 -- 10 files changed, 67 insertions(+), 47 deletions(-) diff --git a/docs/approvals.md b/docs/approvals.md index 8d4b4207..998cbab8 100644 --- a/docs/approvals.md +++ b/docs/approvals.md @@ -441,8 +441,8 @@ the config PR, and for a spawn runs the post-spawn forge bookkeeping. Two visible consequences: - **Operator dashboard**: after clicking APPR0VE the work-in-progress - shows up on the *rebuild queue* card (`/api/state.rebuild_queue` - + live `rebuild_queue_changed` events), not on the approvals panel + shows up on the *rebuild queue* card (`GET /api/jobq/graph`, refetched + on every `rebuild_queue_changed` tick), not on the approvals panel (which already moved the row to "approved"). A long meta-update cascade renders as a parent DAG with one child rebuild per affected agent — see `docs/web-ui.md` for the layout. diff --git a/docs/coordinator.md b/docs/coordinator.md index cda161e3..e06d77fb 100644 --- a/docs/coordinator.md +++ b/docs/coordinator.md @@ -60,7 +60,7 @@ Cheap — no build slot: | `Drain` | await the harness clearing the fence, bounded by the 3-min graceful-stop timeout; resolves ok either way | | `WriteDropin` | `set_nspawn_flags` + `set_resource_limits` + daemon-reload | | `WritePermFile` | commit `tool-groups.json` / `capabilities.json` (single git commit under `META_LOCK`) + emit the P3RM1SS10NS snapshots | -| `Reparent` | `set-parent` / `set-parent-bulk`: apply every `(child, new_parent)` move under one `META_LOCK` commit (`meta::bulk_commit_topology`), send the per-agent move notifications, rescan + diff-emit. Agentless like `MetaLock` — a bulk move can span multiple agents, and a reparent touches the meta repo, not any one container. `moves` is `(Ident, Option)` pairs, not raw strings — mara: "use Ident type instead of string" (#2719, issuecomment 42691). Rides `Template::MetaUpdate` rather than a dedicated `Template` variant — that enum is on its way out (see `#2665`, still open/blocked on a scope question) and is already internal-only (not on `DagView`'s wire shape), so the stand-in only affects `terminal_hook` dispatch (resolves to no hook either way) and history-retention bucketing | +| `Reparent` | `set-parent` / `set-parent-bulk`: apply every `(child, new_parent)` move under one `META_LOCK` commit (`meta::bulk_commit_topology`), send the per-agent move notifications, rescan + diff-emit. Agentless like `MetaLock` — a bulk move can span multiple agents, and a reparent touches the meta repo, not any one container. `moves` is `(Ident, Option)` pairs, not raw strings — mara: "use Ident type instead of string" (#2719, issuecomment 42691). Rides `Template::MetaUpdate` rather than a dedicated `Template` variant — that enum is on its way out (see `#2665`, still open/blocked on a scope question) and is already internal-only (it never reaches the graph wire), so the stand-in only affects `terminal_hook` dispatch (resolves to no hook either way) and history-retention bucketing | There is deliberately **no `GitCommit` node**: `meta.rs` fuses each mutation with its commit under its internal `META_LOCK` mutex, so a standalone commit @@ -252,16 +252,26 @@ cancelled-while-queued, which fails the approval instead of dangling it). ### Wire shape -`RebuildQueueChanged { seq, queue: [DagView…] }` (event name kept). Each -`DagView` carries the entry-level fields (`id`, `kind` = template string, -roll-up `state`, `source`, `reason`, timestamps, `inputs`, -`approval_id`) plus `nodes: [NodeView…]` — per-node `agent`, `kind`, `deps`, -`state`, `build_log_id`, timestamps, `error`. There is **no -DAG-level `agent`** (agent is per-node, so a DAG can span agents); consumers -derive a DAG's agent(s) from its nodes. The node kind *is* the phase label — -there is no separate sub-step string; build logs are **per-node**. The -dashboard renders the node chain on each queue card and keys the live-log -panel off the running node. +`RebuildQueueChanged { seq }` (event name kept) — **a bare trigger, no +payload.** It says *the queue changed*; a client that wants to know how +re-fetches `GET /api/jobq/graph`. + +That endpoint serves the graph generically (`hive-jobq-wire`): every node +carries `id`, `parent`, `deps`, `state`, `label` (the node kind's own wire +string — the kind *is* the phase label, there is no separate sub-step +string) and free-form `data` for what only some kinds have (`agent`, +`approval_id`, `inputs`, `build_log_id`). Group roots ride as ordinary +nodes, so a group's state is just the root's own `state`. + +There is **no group-level `agent`** — agent is per-node, so one group can +span agents; consumers derive a group's agent(s) from its nodes. Build logs +are likewise **per-node**: the dashboard renders the node tree and keys the +live-log panel off the running node. + +The event used to ship the whole queue as a typed `DagView`/`NodeView` +projection. That was a second rendering of the same graph, kept in +agreement by hand with the endpoint every consumer actually read; it is +gone, and the event's whole job is now telling a client *when* to refetch. --- diff --git a/docs/web-ui/dashboard.md b/docs/web-ui/dashboard.md index a71ff7af..a25f6da2 100644 --- a/docs/web-ui/dashboard.md +++ b/docs/web-ui/dashboard.md @@ -225,12 +225,10 @@ does not render the queue itself; it just mounts the element and listens for its `hive-jobq-graph-update` event to drive the two things below it that the generic view doesn't show. The component owns fetching, cold and live: `GET /api/jobq/graph` on mount, and -`.refresh()` on every `rebuild_queue_changed` SSE tick (that event -still carries its own `Vec` payload — `DagView`-shaped, -also read by `hivectl`'s own wait/progress loop, a separate migration -— on the wire, but neither dashboard page reads it anymore; both -treat the tick as a pure refetch trigger against the generic -endpoint). +`.refresh()` on every `rebuild_queue_changed` SSE tick (that event is a +bare `{ seq }` trigger — it carried a typed queue snapshot until every +consumer had moved to the generic endpoint, and now carries none; both +dashboard pages treat the tick as a pure refetch trigger). Each row is one root graph node (`parent: null`); a multi-step op's per-agent subgraphs and sub-steps render as nodes within that one @@ -900,7 +898,8 @@ fetch entirely. life). Two consequences for anything rendering it: - The label vocabulary is **open** — it is the node's own wire tag - (`NodeKind::as_str`, the same strings `NodeView.kind` carries), + (`NodeKind::as_str`, the same strings the graph wire's node + labels carry), not a fixed set. Treat it as an opaque display string; do not switch on specific values. `restarting` in particular no longer exists, because no node kind is unique to a restart. @@ -1441,19 +1440,19 @@ payload): `crash_watch` poll. Client upserts/removes by name; the pending overlay is read from `transientsState` since the payload doesn't carry it. -- `rebuild_queue_changed` (seq, queue: `Vec`) — - full snapshot of the rebuild queue on every mutation (enqueue, - state transition, dedup collapse, terminal-history trim). - Same snapshot-over-diff rationale as `tombstones_changed` / - `meta_inputs_changed`: the list is small and the client renders - each DAG's multi-agent shape from its own `nodes` (no cross-DAG - grouping). Cold-loaded from `/api/state.rebuild_queue`. +- `rebuild_queue_changed` (seq) — **payload-free trigger**, fired on + every queue mutation (enqueue, state transition, dedup collapse, + terminal-history trim). Unlike the snapshot events below it ships + no state at all: the client re-fetches `GET /api/jobq/graph`, which + is where it reads the queue from cold too. There is no + `/api/state.rebuild_queue` — it went with the typed projection. - `schedules_changed` (seq, schedules: `Vec`) — full snapshot of all scheduled prompts. Emitted after every operator mutation via the `/api/schedules` surface (new / edit / cancel / fire-now) and after the worker fires or rearms a row. Same snapshot-shape rationale as - `rebuild_queue_changed`. The SCH3DUL3S tab subscribes and + `tombstones_changed` / `meta_inputs_changed` (small list, no + add/remove races). The SCH3DUL3S tab subscribes and re-renders `schedulesState` on receipt; tab activation still re-fetches as a safety net for approval-path inserts and disconnect windows. diff --git a/hive-c0re/src/coordinator.rs b/hive-c0re/src/coordinator.rs index 52dd4611..3e210bcc 100644 --- a/hive-c0re/src/coordinator.rs +++ b/hive-c0re/src/coordinator.rs @@ -635,10 +635,14 @@ impl Coordinator { } } - /// Emit a `RebuildQueueChanged` snapshot event. Called from the - /// queue mutation helpers (`enqueue` / `finish` / `cancel`-adjacent - /// wrappers below) and the worker so every state transition - /// surfaces on the dashboard without extra plumbing. + /// Emit a `RebuildQueueChanged` tick. Called from the queue mutation + /// helpers (`enqueue` / `finish` / `cancel`-adjacent wrappers below) and + /// the worker so every state transition surfaces on the dashboard without + /// extra plumbing. + /// + /// Carries no queue payload — clients refetch `/api/jobq/graph`. The name + /// keeps `snapshot` because *that* is still what a client ends up with; + /// what changed is who serves it. pub fn emit_rebuild_queue_snapshot(self: &Arc) { self.emit_dashboard_event(DashboardEvent::RebuildQueueChanged { seq: self.next_seq(), diff --git a/hive-c0re/src/dashboard/build_logs.rs b/hive-c0re/src/dashboard/build_logs.rs index 763ee9fb..f202060f 100644 --- a/hive-c0re/src/dashboard/build_logs.rs +++ b/hive-c0re/src/dashboard/build_logs.rs @@ -136,7 +136,7 @@ pub(super) async fn get_build_log_full( /// /// Same `BuildLogFull` JSON (`stdout` / `stderr` + header) as /// `get_build_log_full`; HTTP 404 when the node has no linked log (the -/// client gates the request on `NodeView.build_log_id`, but a vacuum +/// client gates the request on the wire node's `build_log_id`, but a vacuum /// race can still 404). This is the on-demand live-log-panel fetch, /// distinct from the `build_log_id` on the wire — that id is for /// deep-linking to the BUILD L0GS tab's full history view, not for diff --git a/hive-c0re/src/dashboard_events.rs b/hive-c0re/src/dashboard_events.rs index bf3245e6..b1874d6c 100644 --- a/hive-c0re/src/dashboard_events.rs +++ b/hive-c0re/src/dashboard_events.rs @@ -233,7 +233,8 @@ pub enum DashboardEvent { /// Full snapshot of all scheduled prompts. Emitted after every /// operator mutation (new / edit / cancel / fire-now) and after the /// worker fires or rearms a row. Same snapshot-shape rationale as - /// `RebuildQueueChanged` — the list is small and the client's + /// `TombstonesChanged` / `MetaInputsChanged` — the list is small and the + /// client's /// per-target `last_result` / `last_fired_at_unix` fields are most /// naturally re-derived from the full list. SchedulesChanged { diff --git a/hive-c0re/src/job_queue/mod.rs b/hive-c0re/src/job_queue/mod.rs index 97ae16c2..b9727493 100644 --- a/hive-c0re/src/job_queue/mod.rs +++ b/hive-c0re/src/job_queue/mod.rs @@ -308,9 +308,10 @@ impl JobQueue { /// so both are running and both name `a`. Anything keying this set by agent /// alone will silently drop one — see [`super::scheduler`]. /// - /// `label` is the node's own wire tag ([`NodeKind::as_str`]), the vocabulary - /// [`NodeView::kind`] already ships, so a pill and a DAG node name an - /// operation identically. `takes_container_down` is the crash watcher's + /// `label` is the node's own wire tag ([`NodeKind::as_str`]), the same + /// vocabulary the graph wire ships as a node's label, so a pill and a + /// graph node name an operation identically. `takes_container_down` is the + /// crash watcher's /// input and does **not** ride the wire to the frontend — a `Start` pill and /// a `Stop` pill are both pills; only one means a vanished container is /// expected. @@ -381,10 +382,10 @@ impl JobQueue { /// One or more nodes plus their live subtrees, as generic wire nodes — /// the `QueueNodes` polling surface behind `hivectl`'s wait/progress - /// loop. Sibling of [`Self::snapshot`] (which serves the same graph - /// through the typed `DagView`/`NodeView` projection for the - /// dashboard's `/api/state.rebuild_queue`), this one goes through - /// [`GraphWire::wire_snapshot`] instead — no `Done`-node filtering, no + /// loop. Goes through [`GraphWire::wire_snapshot`] — the same projection + /// [`Self::graph_snapshot`] serves the dashboard with, differing only in + /// *which* nodes it selects (caller-named ids and their subtrees, rather + /// than every visible root). No `Done`-node filtering, no /// roll-up field (a node's own `state` answers that, see /// `hive_jobq_wire`'s doc comment). Looks each id up by identity /// alone — no assumption that it names a DAG container or a root; diff --git a/hive-c0re/src/job_queue/model.rs b/hive-c0re/src/job_queue/model.rs index 849d8b04..769b86b6 100644 --- a/hive-c0re/src/job_queue/model.rs +++ b/hive-c0re/src/job_queue/model.rs @@ -322,7 +322,8 @@ impl hive_jobq_wire::WireNode for NodeKind { } impl NodeKind { - /// Wire string for `NodeView.kind`. + /// Wire string for the node's label on the graph wire + /// ([`hive_jobq_wire::WireNode::label`]). pub fn as_str(&self) -> &'static str { match self { NodeKind::MetaSync { .. } => "meta_sync", diff --git a/hive-host-sock/README.md b/hive-host-sock/README.md index d9f427cc..d8efdf36 100644 --- a/hive-host-sock/README.md +++ b/hive-host-sock/README.md @@ -15,9 +15,15 @@ thin dependency possible. ## Shape Serde-derived request/response enums for the host admin protocol. The larger -shared payload types some variants reference (`Approval`, `AgentStatusRow`, -`jobs::DagView`) stay in `hive-sh4re` — this crate is only the protocol -envelope, no server or client implementation. +shared payload types some variants reference (`Approval`, `AgentStatusRow`) +stay in `hive-sh4re` — this crate is only the protocol envelope, no server or +client implementation. + +Its own `jobs` module is the exception: the job-queue vocabulary `hivectl` +needs (`Source`, `State`, `PermPayload`, `NodeId`) is protocol-local. The typed +`DagView`/`NodeView` projection that used to live there is gone — the queue is +served as a generic graph (`hive-jobq-wire`), not as a second hand-written +view. See `docs/boundary.md` (host admin socket access) for the trust model around who may connect to the socket, and `hive-priv-sock` for the sibling split on the diff --git a/hive-sh4re/README.md b/hive-sh4re/README.md index 07bb7590..84e9f895 100644 --- a/hive-sh4re/README.md +++ b/hive-sh4re/README.md @@ -21,8 +21,6 @@ Those crates re-export or reference the payload types that still live here ## Modules -- **`jobs`** — the job-queue wire types (`DagView`) surfaced to the dashboard SSE - stream + hivectl. - **`wire_time`** — the timestamp convention: wire fields are `chrono::DateTime` (serialized RFC 3339), while sqlite storage + input args stay unix-epoch `i64`; this module owns the two boundary conversions.