diff --git a/hive-c0re/src/approvals.rs b/hive-c0re/src/approvals.rs index df9979fd..436fa095 100644 --- a/hive-c0re/src/approvals.rs +++ b/hive-c0re/src/approvals.rs @@ -246,7 +246,7 @@ impl Approvals { Ok(()) } - /// Withdraw a pending approval (closes #250). Returns the now-updated + /// Withdraw a pending approval. Returns the now-updated /// row so the caller can emit `ApprovalResolved` with the right /// kind / agent / sha. Errors if the approval isn't pending — once /// it's approved/denied/failed/cancelled, the resolution is final. @@ -329,8 +329,7 @@ impl Approvals { /// deserialize. A single malformed / unknown-kind row must never blank /// the whole list: `collect::>()` is all-or-nothing, so one /// bad row used to make `pending()` / `recent_resolved()` error out -/// wholesale — the dashboard then rendered an empty approvals queue -/// (issue #160, an unhandled `init_config` kind poisoning every read). +/// wholesale — the dashboard then rendered an empty approvals queue. fn collect_lenient(rows: impl Iterator>) -> Vec { rows.filter_map(|r| match r { Ok(a) => Some(a), @@ -435,7 +434,7 @@ mod tests { #[test] fn init_config_approval_round_trips() { - // Regression for #160: an `init_config` row used to fail + // Regression test: an `init_config` row used to fail // deserialization (row_to_approval matched only apply_commit + // spawn), erroring out the whole `pending()` query — every // approval then vanished from the dashboard. @@ -465,9 +464,9 @@ mod tests { #[test] fn mark_cancelled_transitions_pending_row() { - // #250: manager withdraws a pending approval. Row leaves - // pending(), shows up in recent_resolved() with the cancelled - // status + a "cancelled by " note. + // Manager withdraws a pending approval. Row leaves pending(), + // shows up in recent_resolved() with the cancelled status + a + // "cancelled by " note. let (_dir, _path, db) = open_temp(); let id = db .submit_kind( diff --git a/hive-c0re/src/bin/hivectl.rs b/hive-c0re/src/bin/hivectl.rs index 92d4e396..f7632820 100644 --- a/hive-c0re/src/bin/hivectl.rs +++ b/hive-c0re/src/bin/hivectl.rs @@ -1,4 +1,4 @@ -//! `hivectl` — operator-facing host CLI for hyperhive (#655). +//! `hivectl` — operator-facing host CLI for hyperhive. //! //! Sibling binary to the `hive-c0re` daemon. Where `hive-c0re`'s //! subcommands focus on the broker / approval / topology surface @@ -7,7 +7,7 @@ //! starting with manual user provisioning on the bundled forge + //! matrix containers when c0re's automatic boot-time sweep is //! inappropriate (recovery, debugging, single-shot reprovisioning, -//! verifying the registration token path post-#644). +//! verifying the registration token path). //! //! Verbs read configuration off the same on-disk paths c0re uses //! (`/var/lib/hyperhive/forge-core-token`, @@ -69,11 +69,11 @@ enum ForgeCmd { /// When `` is **not** an agent (a human or any other /// non-container account), creates the forgejo user and prints the /// freshly-minted token to stdout — no `/var/lib/hyperhive/agents/` - /// directory is created for the user (#662). + /// directory is created for the user. /// /// Without `--password` / `--password-stdin` a random throwaway is /// used (fine for agents — they auth by token via tea / hive-forge). - /// Set a password to log into the forge web UI afterwards (#663). + /// Set a password to log into the forge web UI afterwards. /// `--password` is idempotent: re-running with the same value sets /// the same password (covers password resets on already-created /// accounts since `forgejo admin user create` silently no-ops once @@ -111,21 +111,20 @@ enum MatrixCmd { /// When `` is **not** an agent (a human or any other /// non-container account), registers the matrix user and prints /// the freshly-minted access token to stdout — no - /// `/var/lib/hyperhive/agents/` directory is created for the user - /// (#662). + /// `/var/lib/hyperhive/agents/` directory is created for the user. /// /// Without `--password` / `--password-stdin` a random throwaway is /// used (fine for agents — they auth by `access_token`, never by /// password). Set a password to log into a matrix web client - /// afterwards (#663). + /// afterwards. CreateUser { /// Matrix localpart. For agents: the container/agent name. /// For humans: any matrix localpart — `mara`, `damocles`, etc. name: String, /// Set the account password to this string instead of a random /// throwaway. Use this for operator accounts that need to log - /// into matrix web clients via `m.login.password` (#663). - /// Mutually exclusive with `--password-stdin`. WARNING: the + /// into matrix web clients via `m.login.password`. Mutually + /// exclusive with `--password-stdin`. WARNING: the /// password is visible in shell history + process listings; /// prefer `--password-stdin` for anything sensitive. #[arg(long)] diff --git a/hive-c0re/src/main.rs b/hive-c0re/src/main.rs index d053a1f8..7553b746 100644 --- a/hive-c0re/src/main.rs +++ b/hive-c0re/src/main.rs @@ -84,8 +84,9 @@ enum Cmd { Deny { id: i64 }, /// Move an agent in the topology tree. Set `--parent` to a new /// parent agent name; pass `--root` to promote the agent to root - /// (no parent). Refuses cycles, unknown agents, and any attempt - /// to reparent the manager. + /// (no parent). Refuses cycles and unknown agents. The manager + /// is reparentable like any other agent — its privileges come + /// from the privileged MCP socket, not its tree position. SetParent { child: String, /// New parent agent name. Mutually exclusive with `--root`. diff --git a/hive-c0re/src/manager_server.rs b/hive-c0re/src/manager_server.rs index 8729fd18..d2f85f89 100644 --- a/hive-c0re/src/manager_server.rs +++ b/hive-c0re/src/manager_server.rs @@ -23,7 +23,7 @@ pub fn start(coord: Arc) -> Result<()> { } let listener = UnixListener::bind(&socket) .with_context(|| format!("bind manager socket {}", socket.display()))?; - // 0666 so the in-container hm1nd user (post-#658) can connect; + // 0666 so the in-container hm1nd user (non-root) can connect; // the bind source dir is manager-only on host. See agent_server.rs. use std::os::unix::fs::PermissionsExt as _; std::fs::set_permissions(&socket, std::fs::Permissions::from_mode(0o666)) @@ -116,8 +116,9 @@ async fn dispatch(req: &ManagerRequest, coord: &Arc) -> ManagerResp // Resolve magic-recipient sentinels (currently ``) // against topology.json; no-op for ordinary names. The // manager has no parent in topology, so `` - // resolves to OPERATOR_RECIPIENT — matching mara's - // "no parent → tell the operator" rule (#692). + // resolves to OPERATOR_RECIPIENT — the "no parent → tell + // the operator" fallback. See `docs/conventions.md:: + // Recipient sentinels`. let resolved = crate::topology::resolve_recipient(MANAGER_AGENT, to); match coord.broker.send(&Message { from: MANAGER_AGENT.to_owned(), @@ -502,7 +503,7 @@ async fn dispatch(req: &ManagerRequest, coord: &Arc) -> ManagerResp } } ManagerRequest::SetStatus { text } => { - // #720: cap length + reject multi-line so a confused caller + // Cap length + reject multi-line so a confused caller // can't dump a multi-paragraph session report into the // dashboard chip. if let Err(message) = crate::limits::check_status_text(text) { @@ -533,10 +534,10 @@ async fn dispatch(req: &ManagerRequest, coord: &Arc) -> ManagerResp } ManagerRequest::GetAgentMeta { name } => { let target = name.as_deref().unwrap_or(MANAGER_AGENT); - // #432: gate status on the target's running state so a - // stopped container's stale on-disk status doesn't leak - // through. Also surface `running` itself so callers can - // tell (e.g. "iris is down" vs "iris has no status set"). + // Gate status on the target's running state so a stopped + // container's stale on-disk status doesn't leak through. + // Also surface `running` itself so callers can tell + // (e.g. "iris is down" vs "iris has no status set"). let (status_text, status_set_at, running) = crate::container_view::read_agent_status_live(target).await; let role = if target == MANAGER_AGENT { @@ -676,7 +677,7 @@ async fn submit_apply_commit( .approvals .set_fetched_sha(id, &sha) .map_err(|e| anyhow::anyhow!("persist fetched_sha: {e:#}"))?; - // #317 pre-flight gates: both reject the apply before approval if + // Pre-flight gates: both reject the apply before approval if // the agent's flake state would inflate meta's lock with duplicates // or lie about what nix will fetch. Both checks independently read // `:flake.lock` via git — they don't share state. Order matters @@ -889,8 +890,8 @@ async fn handle_fire_schedule_now( } } -/// Authorize + dispatch a `EditSchedule` patch (#474). Same -/// ownership rules as `CancelSchedule` — the manager can edit +/// Authorize + dispatch a `EditSchedule` patch. Same ownership +/// rules as `CancelSchedule` — the manager can edit /// schedules it owns + any owned by an agent in its subtree. /// Forwards the partial payload to /// `ScheduledPrompts::update` which enforces the cancelled-row / diff --git a/hive-c0re/src/questions.rs b/hive-c0re/src/questions.rs index 339d377c..64ca7218 100644 --- a/hive-c0re/src/questions.rs +++ b/hive-c0re/src/questions.rs @@ -209,11 +209,11 @@ pub fn handle_cancel_loose_end( } /// Manager-only guard on the `Approval` cancel arm. Pulled out so -/// the auth check has its own focused unit test (argus nit on #508) -/// — testing the full `handle_cancel_loose_end` flow would need a -/// `Coordinator` fixture (broker + sqlite + in-memory questions), -/// which we don't have today. The check is a single string compare, -/// so a function-level test gives the same coverage with no harness. +/// the auth check has its own focused unit test — testing the full +/// `handle_cancel_loose_end` flow would need a `Coordinator` fixture +/// (broker + sqlite + in-memory questions), which we don't have +/// today. The check is a single string compare, so a function-level +/// test gives the same coverage with no harness. fn check_approval_canceller_is_manager(canceller: &str) -> Result<(), String> { if canceller != hive_sh4re::MANAGER_AGENT { return Err("cancel_loose_end: only the manager can cancel approval rows".to_owned()); @@ -227,9 +227,9 @@ mod tests { #[test] fn approval_cancel_rejects_sub_agent_callers() { - // Argus nit on #508: sub-agents must not be able to cancel - // approval rows even if they invent an id. The guard is - // server-side so client cooperation is irrelevant. + // Sub-agents must not be able to cancel approval rows even + // if they invent an id. The guard is server-side so client + // cooperation is irrelevant. let err = check_approval_canceller_is_manager("bitburner").unwrap_err(); assert!(err.contains("only the manager"), "{err}"); // Bonus: empty / operator strings also rejected (only the