From 673aea4e50813c95e2c94bd657c21e7fb1a80a82 Mon Sep 17 00:00:00 2001 From: damocles Date: Wed, 15 Jul 2026 23:54:43 +0200 Subject: [PATCH] fold hive-c0re module tree into the daemon binary + drop dead pub items surfaced by bin-only (#2513) --- hive-c0re/src/agent_config/topology.rs | 31 +------- hive-c0re/src/coordinator.rs | 22 +++--- hive-c0re/src/forge/mod.rs | 17 ---- hive-c0re/src/job_queue/mod.rs | 2 - hive-c0re/src/job_queue/templates.rs | 10 ++- hive-c0re/src/lib.rs | 54 ------------- hive-c0re/src/lifecycle/host_config.rs | 23 ++---- hive-c0re/src/lifecycle/mod.rs | 44 ++--------- hive-c0re/src/main.rs | 79 +++++++++++++------ hive-c0re/src/paths.rs | 6 -- hive-c0re/src/priv_client.rs | 20 ----- .../src/socket_server/config_approvals.rs | 2 +- hive-c0re/src/stats/sweep_health.rs | 12 +-- hive-c0re/src/stores/approvals.rs | 16 +--- hive-c0re/src/stores/audit_log.rs | 7 -- 15 files changed, 95 insertions(+), 250 deletions(-) delete mode 100644 hive-c0re/src/lib.rs diff --git a/hive-c0re/src/agent_config/topology.rs b/hive-c0re/src/agent_config/topology.rs index cdbdb510..1ac11516 100644 --- a/hive-c0re/src/agent_config/topology.rs +++ b/hive-c0re/src/agent_config/topology.rs @@ -54,14 +54,6 @@ pub fn read() -> BTreeMap> { serde_json::from_str(&raw).unwrap_or_default() } -/// Look up one agent's parent. Returns `None` when the agent is root -/// or absent from the file. Cheap convenience over `read()` for -/// callers that want a single entry. -#[must_use] -pub fn parent_of(name: &str) -> Option { - read().get(name).cloned().flatten() -} - /// Return the direct children of `name` — agents whose `topology.json` /// entry has `name` as their parent. Reads the map once and scans all /// entries; cheap enough for the fan-out path (one disk read per send @@ -489,30 +481,9 @@ pub fn has_role_in(roles: &BTreeMap>, name: &str, role: &str .is_some_and(|rs| rs.iter().any(|r| r == role)) } -/// Grant or revoke a role for `name`. Idempotent — no disk write when the -/// state is already correct. -/// -/// Empty role lists are kept in the map (never removed). An absent key means -/// "never seen" (seed on next `reconcile_roles`); an empty list means -/// "explicitly revoked" (do not re-seed). Callers that want to remove an -/// agent from the map entirely should use `reconcile_roles` (agent departure). -pub fn set_role(name: &str, role: &str, enabled: bool) -> Result<(), String> { - let mut roles = read_roles(); - let list = roles.entry(name.to_owned()).or_default(); - let held = list.iter().any(|r| r == role); - match (enabled, held) { - (true, false) => list.push(role.to_owned()), - (false, true) => list.retain(|r| r != role), - _ => return Ok(()), - } - // Intentionally do NOT remove empty entries — an empty list signals an - // explicit revoke and prevents reconcile_roles from re-seeding the role. - write_roles(&roles).map_err(|e| format!("write roles.json: {e}")) -} - /// Reconcile `roles.json` against the current agent set: /// - Seeds root's default `can_manage_top_level_agents` role on first -/// appearance (operator can revoke with `set_role`). +/// appearance. /// - Drops entries for agents that no longer exist. /// /// Returns true when the file changed. diff --git a/hive-c0re/src/coordinator.rs b/hive-c0re/src/coordinator.rs index 66e3fd48..2e488e16 100644 --- a/hive-c0re/src/coordinator.rs +++ b/hive-c0re/src/coordinator.rs @@ -305,15 +305,15 @@ mod serve_config_tests { #[derive(Clone, Debug)] pub struct AgentPaths { /// Runtime socket dir (tmpfs, recreated per boot). - pub agent_dir: PathBuf, + pub agent: PathBuf, /// Manager-editable proposed config repo. - pub proposed_dir: PathBuf, + pub proposed: PathBuf, /// Hive-c0re-authoritative applied config repo. - pub applied_dir: PathBuf, + pub applied: PathBuf, /// Claude OAuth credentials (survives purge boundary). - pub claude_dir: PathBuf, + pub claude: PathBuf, /// Agent durable notes + forge token (survives purge boundary). - pub notes_dir: PathBuf, + pub notes: PathBuf, } /// Per-agent in-progress state that the dashboard surfaces between approve @@ -377,7 +377,7 @@ pub enum TransientKind { Starting, /// `lifecycle::kill` is running. Stopping, - /// `lifecycle::restart` is running. + /// A restart (`lifecycle::kill` then `lifecycle::start`) is running. Restarting, /// `lifecycle::rebuild` is running (nixos-container update). Rebuilding, @@ -542,11 +542,11 @@ impl Coordinator { #[must_use] pub fn agent_paths(name: &str, agent_dir: PathBuf) -> AgentPaths { AgentPaths { - agent_dir, - proposed_dir: Self::agent_proposed_dir(name), - applied_dir: crate::paths::applied_dir(name), - claude_dir: Self::agent_claude_dir(name), - notes_dir: Self::agent_notes_dir(name), + agent: agent_dir, + proposed: Self::agent_proposed_dir(name), + applied: crate::paths::applied_dir(name), + claude: Self::agent_claude_dir(name), + notes: Self::agent_notes_dir(name), } } diff --git a/hive-c0re/src/forge/mod.rs b/hive-c0re/src/forge/mod.rs index 26708c91..b54a661a 100644 --- a/hive-c0re/src/forge/mod.rs +++ b/hive-c0re/src/forge/mod.rs @@ -99,13 +99,6 @@ const AGENTS_ORG: &str = "agents"; /// references this team by name for the merge/approval whitelist, so the /// rule never hardcodes a specific reviewer agent (which may not exist). const OPERATORS_TEAM: &str = "operators"; -/// Hive-managed Forgejo namespaces that agent-initiated repo creation must -/// never target. `internal` is operator-curated shared content; -/// `agent-configs` + `core` are hive-c0re-internal mirror/meta namespaces. -/// (`hyperhive` is NOT managed — it's just a repo that happens to be built -/// by this hive.) hive-c0re's create path forces [`AGENTS_ORG`], so this is -/// a defensive guard against any future caller passing an explicit owner. -const HIVE_MANAGED_NAMESPACES: &[&str] = &[SHARED_ORG, CONFIG_ORG, "core"]; /// Forgejo orgs hive-c0re ensures on startup. The meta repo lives at /// `core/meta` (the `core` user's own namespace — no org needed). const SEEDED_ORGS: &[&str] = &[CONFIG_ORG, SHARED_ORG, AGENTS_ORG]; @@ -152,16 +145,6 @@ pub(crate) fn api(token: &str) -> Result { Forgejo::new(Auth::Token(token), url).context("build forgejo api client") } -/// Whether `ns` is a hive-managed Forgejo namespace that agent-initiated -/// repo creation must never target — `internal` (operator-curated -/// shared content) + `agent-configs` / `core` (hive-c0re-internal). The -/// create path forces [`AGENTS_ORG`], so this guards a future surface that -/// might accept an explicit owner. -#[must_use] -pub fn is_hive_managed_namespace(ns: &str) -> bool { - HIVE_MANAGED_NAMESPACES.contains(&ns) -} - /// Per-agent forge sync: ensure the agent has a forgejo user + token, /// a mirrored config repo, read access to `core/meta`, and the `meta` /// remote in its proposed repo. All operations are idempotent; failures diff --git a/hive-c0re/src/job_queue/mod.rs b/hive-c0re/src/job_queue/mod.rs index f9d6cdc0..c7362cea 100644 --- a/hive-c0re/src/job_queue/mod.rs +++ b/hive-c0re/src/job_queue/mod.rs @@ -65,7 +65,6 @@ pub struct Claim { /// it. pub agent: String, pub template: Template, - pub source: Source, pub approval_id: Option, pub inputs: Vec, pub perm_payload: Option, @@ -330,7 +329,6 @@ impl JobQueue { kind: dag.node(node_id).expect("node").kind.clone(), agent: node_agent, template: dag.template, - source: dag.source, approval_id: dag.approval_id, inputs: dag.inputs.clone(), perm_payload: dag.perm_payload.clone(), diff --git a/hive-c0re/src/job_queue/templates.rs b/hive-c0re/src/job_queue/templates.rs index 2d20d0df..ca7069b6 100644 --- a/hive-c0re/src/job_queue/templates.rs +++ b/hive-c0re/src/job_queue/templates.rs @@ -112,10 +112,12 @@ pub fn approval_deploy(agent: &str, approval_id: i64, reason: String) -> DagSpec } } -/// Boot-time reconcile: a single `Reconcile` node that converges observed -/// power state to the persisted intent — `wanted` is untouched (no -/// `SetWanted`), unlike the operator `start`/`stop` templates. Used only -/// by the boot sweep now. +/// A single `Reconcile` node that converges observed power state to the +/// persisted intent — `wanted` is untouched (no `SetWanted`), unlike the +/// operator `start`/`stop` templates. Test-only helper now (used to build +/// single-node lifecycle DAGs that exercise per-agent lease serialization +/// in the queue tests); production paths no longer emit a bare reconcile. +#[cfg(test)] pub fn reconcile_only( template: Template, agent: &str, diff --git a/hive-c0re/src/lib.rs b/hive-c0re/src/lib.rs deleted file mode 100644 index ab6c4724..00000000 --- a/hive-c0re/src/lib.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! `hive-c0re` library — the coordinator daemon's module surface -//! (coordinator, broker, axum dashboard, admin/manager/agent unix -//! sockets, background sweepers). Consumed by the `hive-c0re` daemon -//! binary (`src/main.rs`). -//! -//! The operator CLI lives in the **standalone `hivectl` crate**, which -//! talks to the daemon over the host admin socket (`hive-host-sock` wire -//! types) rather than linking this crate — so `hive-c0re` is daemon-only, -//! not a library shared with a CLI. -//! -//! Every module is re-exported `pub` so anything in the crate is -//! addressable from the daemon binary; the lib doesn't have a curated -//! surface beyond "this is where the modules live". -//! -//! Cohesive clusters live in directory submodules (`stores`, `stats`, -//! `agent_config`, `workers`); each of their children is re-exported -//! at the crate root so pre-existing `crate::broker::…` / -//! `hive_c0re::broker::…` paths keep compiling unchanged. - -pub mod actions; -pub mod agent_config; -pub mod container_view; -pub mod coordinator; -pub mod dashboard; -pub mod dashboard_events; -pub mod forge; -pub mod gateway_nginx; -pub mod job_queue; -pub mod lifecycle; -pub mod loose_ends; -pub mod matrix; -pub mod meta; -pub mod migrate; -pub mod paths; -pub mod priv_client; -pub mod questions; -pub mod server; -pub mod socket_server; -pub mod stats; -pub mod stores; -pub mod webhook_secret; -pub mod workers; - -// Root re-exports: keep every pre-grouping `crate::` / -// `hive_c0re::` path compiling without touching consumers. -pub use agent_config::{capabilities, limits, tool_groups, topology}; -pub use stats::{container_stats, hive_stats, host_stats, otel_metrics, sweep_health, warnings}; -pub use stores::{ - approvals, audit_log, broker, build_logs, db, operator_questions, power, scheduled_prompts, -}; -pub use workers::{ - agent_sockets, auto_update, crash_watch, knowledge, mcp_sockets, reminder_scheduler, - scheduled_prompts_worker, -}; diff --git a/hive-c0re/src/lifecycle/host_config.rs b/hive-c0re/src/lifecycle/host_config.rs index 1b1a93ec..247b4f6a 100644 --- a/hive-c0re/src/lifecycle/host_config.rs +++ b/hive-c0re/src/lifecycle/host_config.rs @@ -22,13 +22,7 @@ use super::{ pub async fn write_dropins(name: &str, hive: &HiveEnv, paths: &AgentPaths) -> Result<()> { validate(name)?; let container = container_name(name); - set_nspawn_flags( - &container, - &paths.agent_dir, - &paths.claude_dir, - &paths.notes_dir, - ) - .await?; + set_nspawn_flags(&container, &paths.agent, &paths.claude, &paths.notes).await?; set_resource_limits(&container, &hive.agent_cpu_quota, &hive.agent_memory_max).await?; systemd_daemon_reload().await } @@ -44,16 +38,6 @@ async fn systemd_daemon_reload() -> Result<()> { crate::priv_client::daemon_reload().await } -/// Idempotently rewrite the lines in `/etc/nixos-containers/.conf` -/// that hive-c0re owns: `PRIVATE_NETWORK` (forced 0 so the agent's web UI port -/// is reachable on the host) and `EXTRA_NSPAWN_FLAGS` (the runtime-dir bind). -/// The start script expands `$EXTRA_NSPAWN_FLAGS` unquoted into the -/// `systemd-nspawn` command. -/// Where in the container's filesystem the manager sees its agents tree. -/// Matches the `/agents` path that pre-Phase-8 hosts declared via -/// `containers.root.bindMounts."/agents"`. -pub const CONTAINER_MANAGER_AGENTS_MOUNT: &str = "/agents"; - /// Where the manager sees the applied trees of every agent, read-only. /// Manager runs `git fetch /applied//.git refs/tags/*:refs/tags/applied/*` /// to learn what hive-c0re deployed (or rejected, or failed to @@ -115,6 +99,11 @@ fn hive_load_credentials() -> Vec { out } +/// Idempotently rewrite the lines in `/etc/nixos-containers/.conf` +/// that hive-c0re owns: `PRIVATE_NETWORK` (forced 0 so the agent's web UI port +/// is reachable on the host) and `EXTRA_NSPAWN_FLAGS` (the runtime-dir bind). +/// The start script expands `$EXTRA_NSPAWN_FLAGS` unquoted into the +/// `systemd-nspawn` command. #[allow( clippy::too_many_lines, reason = "one contiguous nspawn-flag assembly block; the length is the flag \ diff --git a/hive-c0re/src/lifecycle/mod.rs b/hive-c0re/src/lifecycle/mod.rs index acfa722a..1419f354 100644 --- a/hive-c0re/src/lifecycle/mod.rs +++ b/hive-c0re/src/lifecycle/mod.rs @@ -10,16 +10,12 @@ pub use git::{ git, git_command, git_read_tree_reset, git_rev_parse, git_tag, git_tag_annotated, git_update_ref, }; -pub use host_config::{ - CONTAINER_MANAGER_AGENTS_MOUNT, CONTAINER_MANAGER_APPLIED_MOUNT, write_dropins, -}; +pub use host_config::write_dropins; pub use setup::{ ensure_agent_state_subvolume, ensure_claude_dir, ensure_state_dir, initial_flake_nix, setup_applied, setup_proposed, }; -use std::path::Path; - use anyhow::{Context, Result, bail}; use tokio::process::Command; @@ -164,23 +160,6 @@ pub fn agent_uid_gid(agent_name: &str) -> Option<(u32, u32)> { None } -/// Best-effort `chown(path, agent_uid, agent_gid)`. Resolves the agent's -/// uid/gid via [`agent_uid_gid`] and shells out to `std::os::unix::fs::chown`. -/// Silently no-ops when the container isn't built yet (`None` from -/// [`agent_uid_gid`]) and logs at debug on chown syscall failure — the -/// activation script in the harness user module is the steady-state safety -/// net. Used by per-agent state writers in `forge` + `matrix` so the -/// agent can read the file without waiting for the next container -/// rebuild. -pub fn chown_to_agent(name: &str, path: &Path, subsystem: &str) { - let Some((uid, gid)) = agent_uid_gid(name) else { - return; - }; - if let Err(e) = std::os::unix::fs::chown(path, Some(uid), Some(gid)) { - tracing::debug!(%name, %subsystem, path = %path.display(), error = %e, "chown to agent failed"); - } -} - fn validate(name: &str) -> Result<()> { if name.is_empty() { bail!("agent name must not be empty"); @@ -239,11 +218,11 @@ pub async fn provision_container(name: &str, hive: &HiveEnv, paths: &AgentPaths) agent_web_port(name) ); } - setup_proposed(&paths.proposed_dir, name).await?; - setup_applied(&paths.applied_dir, Some(&paths.proposed_dir), name).await?; + setup_proposed(&paths.proposed, name).await?; + setup_applied(&paths.applied, Some(&paths.proposed), name).await?; ensure_agent_state_subvolume(name).await?; - ensure_claude_dir(&paths.claude_dir)?; - ensure_state_dir(&paths.notes_dir)?; + ensure_claude_dir(&paths.claude)?; + ensure_state_dir(&paths.notes)?; // Meta flake gets the new agent's input + nixosConfiguration // before `nixos-container create` so the `--flake meta#` // ref resolves. @@ -278,10 +257,10 @@ pub async fn prepare_rebuild_dirs(name: &str, paths: &AgentPaths) -> Result<()> agent_web_port(name) ); } - setup_applied(&paths.applied_dir, None, name).await?; + setup_applied(&paths.applied, None, name).await?; ensure_agent_state_subvolume(name).await?; - ensure_claude_dir(&paths.claude_dir)?; - ensure_state_dir(&paths.notes_dir)?; + ensure_claude_dir(&paths.claude)?; + ensure_state_dir(&paths.notes)?; Ok(()) } @@ -515,13 +494,6 @@ async fn start_with_fallback_inner(name: &str) -> Result<()> { .with_context(|| format!("cold-start fallback also failed for {name}")) } -/// Stop + start without regenerating any config. For "kick the container" -/// without touching the flake or nspawn flags. -pub async fn restart(name: &str) -> Result<()> { - kill(name).await?; - start(name).await -} - /// True when the container's systemd unit is active. Used by the dashboard /// to gate stop/restart buttons. pub async fn is_running(name: &str) -> bool { diff --git a/hive-c0re/src/main.rs b/hive-c0re/src/main.rs index 3997238f..d3dd110e 100644 --- a/hive-c0re/src/main.rs +++ b/hive-c0re/src/main.rs @@ -4,23 +4,58 @@ use std::sync::Arc; use anyhow::{Context as _, Result}; use clap::{Parser, Subcommand}; -// Every module hangs off the `hive_c0re` library (see `src/lib.rs`). -// The daemon and the `hivectl` sibling binary share the same module -// tree — no per-binary duplication. Enumerated rather than wildcard -// so clippy stays happy + the lib surface this bin consumes is -// explicit (any new daemon entry point reads off the next add). -use hive_c0re::coordinator::{Coordinator, HiveEnv, ServeConfig}; -use hive_c0re::{ - agent_sockets, auto_update, broker, crash_watch, dashboard, dashboard_events, forge, - host_stats, job_queue, knowledge, matrix, mcp_sockets, migrate, reminder_scheduler, - scheduled_prompts_worker, server, socket_server, sweep_health, warnings, +// `hive-c0re` is bin-only: this binary owns the whole daemon module +// tree. The operator CLI moved to the standalone `hivectl` crate (it +// talks to the daemon over the host admin socket), so there's no longer +// a library shared between two binaries — the modules that used to live +// in `src/lib.rs` are declared here directly. +// +// Cohesive clusters live in directory submodules (`stores`, `stats`, +// `agent_config`, `workers`); each child is re-exported at the crate +// root so `crate::broker::…` style paths keep resolving unchanged. +mod actions; +mod agent_config; +mod container_view; +mod coordinator; +mod dashboard; +mod dashboard_events; +mod forge; +mod gateway_nginx; +mod job_queue; +mod lifecycle; +mod loose_ends; +mod matrix; +mod meta; +mod migrate; +mod paths; +mod priv_client; +mod questions; +mod server; +mod socket_server; +mod stats; +mod stores; +mod webhook_secret; +mod workers; + +pub(crate) use agent_config::{capabilities, limits, tool_groups, topology}; +pub(crate) use stats::{ + container_stats, hive_stats, host_stats, otel_metrics, sweep_health, warnings, +}; +pub(crate) use stores::{ + approvals, audit_log, broker, build_logs, db, operator_questions, power, scheduled_prompts, +}; +pub(crate) use workers::{ + agent_sockets, auto_update, crash_watch, knowledge, mcp_sockets, reminder_scheduler, + scheduled_prompts_worker, }; +use coordinator::{Coordinator, HiveEnv, ServeConfig}; + #[derive(Parser)] -#[command(name = "hive-c0re", about = "hyperhive coordinator daemon and CLI")] +#[command(name = "hive-c0re", about = "hyperhive coordinator daemon")] struct Cli { /// Path to the host admin socket. - #[arg(long, global = true, default_value = hive_c0re::paths::HOST_SOCKET)] + #[arg(long, global = true, default_value = crate::paths::HOST_SOCKET)] socket: PathBuf, #[command(subcommand)] @@ -32,7 +67,7 @@ enum Cmd { /// Run the coordinator daemon. Serve { /// Path to a JSON config file holding the host-level daemon config - /// (the [`ServeConfig`](hive_c0re::coordinator::ServeConfig) shape: + /// (the [`ServeConfig`](crate::coordinator::ServeConfig) shape: /// the container-injected `HiveEnv` fields + the hive-c0re-local /// `model_prices` table). Used as the base; any per-flag override /// below wins over the file. Absent → start from the built-in @@ -42,7 +77,7 @@ enum Cmd { #[arg(long)] config: Option, /// Path to the sqlite message store. - #[arg(long, default_value = hive_c0re::paths::BROKER_DB)] + #[arg(long, default_value = crate::paths::BROKER_DB)] db: PathBuf, /// Override: URL of the hyperhive flake. Inlined into each /// per-agent `flake.nix` as the `hyperhive` input. @@ -174,7 +209,7 @@ async fn main() -> Result<()> { )] async fn cmd_serve( env: HiveEnv, - model_prices: hive_c0re::hive_stats::PriceTable, + model_prices: crate::hive_stats::PriceTable, build_slots: usize, db: std::path::PathBuf, socket: &std::path::Path, @@ -183,7 +218,7 @@ async fn cmd_serve( // subdir (`db/`, `forge/`, `matrix/`, `run/`) BEFORE opening the // broker db — the broker + build-logs dbs are among the relocated // files. Idempotent; a no-op once migrated. - hive_c0re::paths::relocate_legacy_state(); + crate::paths::relocate_legacy_state(); // `dashboard_port` is consumed into the Coordinator below; capture the // Copy value first for the dashboard + knowledge-webhook tasks. let dashboard_port = env.dashboard_port; @@ -208,7 +243,7 @@ async fn cmd_serve( // Sync /etc/tmpfiles.d/hyperhive-agents.conf so agent runtime dirs are // pre-declared for the next boot. Best-effort background task — a failure // here must not block hive-c0re startup. See lifecycle::sync_tmpfiles. - tokio::spawn(hive_c0re::lifecycle::sync_tmpfiles()); + tokio::spawn(crate::lifecycle::sync_tmpfiles()); // Auto-update in the background — don't block service start. // Sub-agent rebuilds can take tens of seconds; we want the admin // socket up immediately. @@ -228,7 +263,7 @@ async fn cmd_serve( // Webhook HMAC secret: load from state dir or generate on first run. // Used by both the webhook handlers (verification) and the Forgejo // hook registrations (so Forgejo signs deliveries with the same key). - let webhook_secret: Option = match hive_c0re::webhook_secret::load_or_generate() { + let webhook_secret: Option = match crate::webhook_secret::load_or_generate() { Ok(s) => Some(s), Err(e) => { tracing::error!( @@ -427,18 +462,18 @@ async fn cmd_serve( // + writable rootfs every ~5 min, cached so the 5s container-load // poll stays cheap cgroup-only reads. Feeds `disk_bytes` on the LOAD // tab. See container_stats::disk_sampler_loop. - hive_c0re::container_stats::spawn_disk_sampler(); + crate::container_stats::spawn_disk_sampler(); // Per-agent container-resource OTEL export: rides the same // cgroup gauges out to the configured OTLP endpoint, reusing the hive // `services.hyperhive.otel` config (endpoint + LoadCredential auth). // No-op when OTEL isn't configured. - hive_c0re::otel_metrics::spawn_exporter(); + crate::otel_metrics::spawn_exporter(); // build_logs.sqlite vacuum: c0re-side (single db). Failures kept // 30d, successes 24h — see `build_logs::vacuum` for the rule. - hive_c0re::build_logs::spawn_vacuum(&coord); + crate::build_logs::spawn_vacuum(&coord); // audit_log.sqlite vacuum: agent-initiated privileged-action trail, // 90d retention — see `audit_log::vacuum`. - hive_c0re::audit_log::spawn_vacuum(&coord); + crate::audit_log::spawn_vacuum(&coord); // Container crash watcher: emits HelperEvent::ContainerCrash // when a previously-running container goes away without an // operator-initiated transient state. diff --git a/hive-c0re/src/paths.rs b/hive-c0re/src/paths.rs index 4c5a2d7b..74b2ee39 100644 --- a/hive-c0re/src/paths.rs +++ b/hive-c0re/src/paths.rs @@ -283,12 +283,6 @@ pub fn agent_runtime_dir(name: &str) -> PathBuf { agent_runtime_root().join(name) } -/// `/run/hive-agent` — per-agent socket dir root (web + bound markers). -#[must_use] -pub fn agent_socket_dir() -> PathBuf { - PathBuf::from(AGENT_SOCKET_DIR) -} - /// Move any host-side state file still at its legacy flat location /// (directly under [`STATE_ROOT`]) into its new subdir. Idempotent and /// rename-based: a move only happens when the old path exists and the diff --git a/hive-c0re/src/priv_client.rs b/hive-c0re/src/priv_client.rs index 3d24bdbc..3bd202ca 100644 --- a/hive-c0re/src/priv_client.rs +++ b/hive-c0re/src/priv_client.rs @@ -94,16 +94,6 @@ pub async fn kill_container(name: &str) -> Result<()> { .await?) } -pub async fn update_container(name: &str) -> Result<(String, String)> { - check( - call(&PrivRequest::UpdateContainer { - name: name.to_owned(), - stream: false, - }) - .await?, - ) -} - /// Streaming variant: forward stdout/stderr lines to `on_line` as they /// arrive. Returns `Ok(())` on success; the callback is responsible for /// appending lines to `build_logs` or otherwise capturing the output. @@ -121,16 +111,6 @@ pub async fn update_container_streaming( .await?) } -pub async fn create_container(name: &str) -> Result<(String, String)> { - check( - call(&PrivRequest::CreateContainer { - name: name.to_owned(), - stream: false, - }) - .await?, - ) -} - /// Streaming variant: forward stdout/stderr lines to `on_line` as they /// arrive. Returns `Ok(())` on success. pub async fn create_container_streaming( diff --git a/hive-c0re/src/socket_server/config_approvals.rs b/hive-c0re/src/socket_server/config_approvals.rs index a0aaa987..02ed9b39 100644 --- a/hive-c0re/src/socket_server/config_approvals.rs +++ b/hive-c0re/src/socket_server/config_approvals.rs @@ -125,7 +125,7 @@ pub(crate) async fn submit_merge_config_pr( } // Fetch the current PR head sha — becomes the "reviewed" sha. // Submitted together with the approval row (atomic single INSERT) so a - // crash between submit and set_fetched_sha cannot leave a stranded row. + // crash mid-submit cannot leave a stranded sha-less row. let sha = crate::forge::pr_head_sha(&repo, pr_number) .await .map_err(|e| anyhow::anyhow!("fetch PR head sha for {agent} PR #{pr_number}: {e}"))?; diff --git a/hive-c0re/src/stats/sweep_health.rs b/hive-c0re/src/stats/sweep_health.rs index 2dceb863..42637538 100644 --- a/hive-c0re/src/stats/sweep_health.rs +++ b/hive-c0re/src/stats/sweep_health.rs @@ -93,12 +93,6 @@ impl SweepHealth { None => self.guard = Some(set_warning(self.kind, self.level, msg)), } } - - /// Whether the banner warning is currently raised for this sweep. - #[must_use] - pub fn is_warning(&self) -> bool { - self.guard.is_some() - } } /// Compact human-readable age (e.g. `"45s"`, `"12m"`, `"3h"`, `"2d"`) for a @@ -135,7 +129,7 @@ mod tests { let mut h = SweepHealth::new("sh_below", "warn", 3); h.record_err(|_| "boom".to_owned()); h.record_err(|_| "boom".to_owned()); - assert!(!h.is_warning()); + assert!(h.guard.is_none()); assert!(banner("sh_below").is_none()); } @@ -146,9 +140,9 @@ mod tests { assert!(banner("sh_raise").is_none(), "one miss < threshold"); h.record_err(|c| format!("fail #{}", c.consecutive)); assert_eq!(banner("sh_raise").as_deref(), Some("fail #2")); - assert!(h.is_warning()); + assert!(h.guard.is_some()); h.record_ok(); - assert!(!h.is_warning()); + assert!(h.guard.is_none()); assert!(banner("sh_raise").is_none(), "success clears the banner"); } diff --git a/hive-c0re/src/stores/approvals.rs b/hive-c0re/src/stores/approvals.rs index e8021852..3c8afe33 100644 --- a/hive-c0re/src/stores/approvals.rs +++ b/hive-c0re/src/stores/approvals.rs @@ -75,8 +75,7 @@ impl Approvals { /// when the sha is already known at submission time (e.g. `MergeConfigPr` /// fetches the PR head before inserting), making the insert + sha-set /// atomic. Pass `None` when the kind carries no sha (e.g. `Spawn` / - /// `InitConfig`) or the sha is resolved after insertion, then call - /// [`set_fetched_sha`] separately. + /// `InitConfig`). pub fn submit_kind( &self, agent: &str, @@ -126,17 +125,6 @@ impl Approvals { Ok(submitter) } - /// Record the canonical sha hive-c0re fetched from the proposed repo - /// into applied at submission time. Idempotent on identical values. - pub fn set_fetched_sha(&self, id: i64, sha: &str) -> Result<()> { - let conn = self.conn.lock().unwrap(); - conn.execute( - "UPDATE approvals SET fetched_sha = ?1 WHERE id = ?2", - params![sha, id], - )?; - Ok(()) - } - /// Return the `(id, fetched_sha)` of the pending `merge_config_pr` /// approval for `(agent, pr_number)`, if one exists. Drives /// `submit_merge_config_pr`'s idempotency + PR-drift handling: same @@ -583,7 +571,7 @@ mod tests { fn fetched_sha_in_insert_is_readable_via_get() { // `submit_kind` with `Some(sha)` must store it atomically in the // INSERT — the `get()` row must reflect it without a separate - // `set_fetched_sha` call. This is the MergeConfigPr path. + // sha-set step. This is the MergeConfigPr path. let (_dir, _path, db) = open_temp(); let sha = "abc1234567890abc1234567890abc1234567890ab"; let id = db diff --git a/hive-c0re/src/stores/audit_log.rs b/hive-c0re/src/stores/audit_log.rs index 6dee6ea0..8e8bc160 100644 --- a/hive-c0re/src/stores/audit_log.rs +++ b/hive-c0re/src/stores/audit_log.rs @@ -40,13 +40,6 @@ pub fn install(handle: Arc) { let _ = GLOBAL.set(handle); } -/// Fetch the process-wide handle, or `None` if `install` hasn't run yet -/// (early startup, or unit tests). Callers must gracefully no-op on `None`. -#[must_use] -pub fn global() -> Option> { - GLOBAL.get().cloned() -} - /// Retain audit rows for 90 days. Longer than build-log retention — this /// is a security/accountability record, not debug noise; the operator may /// want to review "who restarted what" well after the fact.