fix(#999): resolve all clippy warnings across the workspace

All crates now pass `cargo clippy --workspace -- -D warnings` cleanly.

Fixes span six crates (hive-sh4re, hive-ag3nt, hive-c0re, hive-forge,
hive-priv, hive-matrix-mcp was already clean):

- doc_markdown: wrap snake_case, type names, constants in backticks
- collapsible_if / collapsible_match: fold nested ifs into let-chains
- duration_suboptimal_units: Duration::from_secs(N) → from_mins/from_hours
- implicit_hasher: allow on HashMap-param fns where generalization is risky
- items_after_statements: hoist use to function tops
- map(f).unwrap_or(x) → map_or(x, f); map(f).unwrap_or_else(g) → map_or_else
- is_ok_and / is_none_or in place of map().unwrap_or(bool)
- needless_continue: {} instead of continue in loop match arms
- match_same_arms: Ok(None) | Err(_) merged
- format_push_str: write!() instead of push_str(&format!())
- while let replaces loop { let Some(..) = x else { break } }
- struct_excessive_bools / dead_code: allow on purpose-built structs
- too_many_lines / too_many_arguments: allow where refactor not worth it
- unused_async: remove async from poll_once in bash_runner
- needless_borrow: fix &repo deref in hive-forge comments verb
- cast_possible_truncation: allow u64→usize in fetch_tail

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
atlas 2026-06-01 22:02:21 +02:00 committed by mara
commit 5c5ca38fe8
32 changed files with 121 additions and 127 deletions

View file

@ -19,6 +19,7 @@ pub struct AgentSocket {
}
pub fn start(agent: &str, socket_path: &Path, coord: Arc<Coordinator>) -> Result<AgentSocket> {
use std::os::unix::fs::PermissionsExt as _;
let agent = agent.to_owned();
if let Some(parent) = socket_path.parent() {
std::fs::create_dir_all(parent)
@ -36,7 +37,6 @@ pub fn start(agent: &str, socket_path: &Path, coord: Arc<Coordinator>) -> Result
// perms (0755) lock it out. 0666 lets the agent user connect;
// the bind source dir is per-agent on host so blast radius is
// unchanged.
use std::os::unix::fs::PermissionsExt as _;
std::fs::set_permissions(socket_path, std::fs::Permissions::from_mode(0o666))
.with_context(|| format!("chmod agent socket {}", socket_path.display()))?;
tracing::info!(%agent, socket = %socket_path.display(), "agent socket listening");
@ -95,7 +95,7 @@ async fn serve(stream: UnixStream, agent: String, coord: Arc<Coordinator>) -> Re
/// cheap "is there anything pending?" check without blocking the
/// turn for 30 seconds. To actually park, the caller passes a
/// positive `wait_seconds`.
pub(crate) const RECV_LONG_POLL_MAX: std::time::Duration = std::time::Duration::from_secs(180);
pub(crate) const RECV_LONG_POLL_MAX: std::time::Duration = std::time::Duration::from_mins(3);
/// Server-side hard cap on `Recv.max`. Bounds the size of a single
/// round-trip so a confused caller can't drain the entire inbox in
@ -357,6 +357,7 @@ async fn dispatch(req: &AgentRequest, agent: &str, coord: &Arc<Coordinator>) ->
///
/// The manager is not exempt - grant `read_host_journal` in
/// `meta/capabilities.json` to enable it for any agent including the manager.
#[allow(clippy::too_many_arguments)]
pub async fn dispatch_host_journal(
agent: &str,
unit: &Option<String>,
@ -619,8 +620,7 @@ fn prepare_remind_storage(
fn auto_reminder_path(agent: &str) -> String {
let ts_ns = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos())
.unwrap_or(0);
.map_or(0, |d| d.as_nanos());
format!("/agents/{agent}/state/reminders/auto-{ts_ns}.md")
}

View file

@ -209,16 +209,16 @@ pub async fn ensure_manager(coord: &Arc<Coordinator>) -> Result<()> {
/// Sort `names` in-place so parents precede their children in the topology.
/// Uses BFS from root agents (depth 0). Agents absent from `topo` sort last,
/// alphabetically within their tier. Stable within each depth tier.
pub fn topology_sort(names: &mut Vec<String>, topo: &std::collections::BTreeMap<String, Option<String>>) {
pub fn topology_sort(names: &mut [String], topo: &std::collections::BTreeMap<String, Option<String>>) {
use std::collections::{HashMap, VecDeque};
// Build depth map using owned clones so the borrow on `names` is released
// before the sort_by mutable borrow.
let name_set: Vec<String> = names.clone();
let name_set: Vec<String> = names.to_vec();
let mut depth: HashMap<String, usize> = HashMap::new();
let mut queue: VecDeque<String> = VecDeque::new();
// Seed roots: entries with no parent, or names not present in topo at all.
for name in &name_set {
if topo.get(name).map_or(true, |p| p.is_none()) {
if topo.get(name).is_none_or(Option::is_none) {
depth.insert(name.clone(), 0);
queue.push_back(name.clone());
}

View file

@ -23,7 +23,7 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
use crate::coordinator::Coordinator;
const VACUUM_INTERVAL: Duration = Duration::from_secs(3600);
const VACUUM_INTERVAL: Duration = Duration::from_hours(1);
/// Keep completed task files for 48 hours before sweeping them.
const KEEP_SECS: i64 = 48 * 3600;
@ -97,7 +97,7 @@ fn should_delete(json_path: &Path, cutoff: i64) -> bool {
if !TERMINAL_STATUSES.contains(&status) {
return false;
}
let completed_at = v.get("completed_at").and_then(|t| t.as_i64()).unwrap_or(i64::MAX);
let completed_at = v.get("completed_at").and_then(serde_json::Value::as_i64).unwrap_or(i64::MAX);
completed_at < cutoff
}
@ -106,10 +106,10 @@ fn should_delete(json_path: &Path, cutoff: i64) -> bool {
fn delete_trio(dir: &Path, stem: &str) {
for ext in ["json", "out", "err"] {
let path = dir.join(format!("{stem}.{ext}"));
if path.exists() {
if let Err(e) = std::fs::remove_file(&path) {
tracing::warn!(path = %path.display(), error = ?e, "bash-tasks vacuum: remove failed");
}
if path.exists()
&& let Err(e) = std::fs::remove_file(&path)
{
tracing::warn!(path = %path.display(), error = ?e, "bash-tasks vacuum: remove failed");
}
}
}

View file

@ -410,7 +410,7 @@ pub fn spawn_vacuum(coord: &Arc<crate::coordinator::Coordinator>) {
use std::time::Duration;
let logs = coord.build_logs.clone();
let mut shutdown = coord.shutdown_rx();
let interval = Duration::from_secs(3_600);
let interval = Duration::from_hours(1);
tokio::spawn(async move {
loop {
match logs.vacuum() {

View file

@ -3,7 +3,7 @@
//! and `tool-groups.json`.
//!
//! Format: a JSON object mapping agent name to an array of
//! `hive_sh4re::Capability` snake_case strings:
//! `hive_sh4re::Capability` `snake_case` strings:
//!
//! ```json
//! {

View file

@ -217,12 +217,12 @@ fn read_dashboard_links(name: &str) -> Vec<DashboardLink> {
/// don't lose state during the transition window.
fn read_harness_flags(name: &str) -> (bool, bool) {
let dir = Coordinator::agent_notes_dir(name);
if let Ok(raw) = std::fs::read_to_string(dir.join("hyperhive-harness.json")) {
if let Ok(v) = serde_json::from_str::<serde_json::Value>(&raw) {
let rl = v.get("rate_limited").and_then(|x| x.as_bool()).unwrap_or(false);
let nl = v.get("needs_login").and_then(|x| x.as_bool()).unwrap_or(false);
return (rl, nl);
}
if let Ok(raw) = std::fs::read_to_string(dir.join("hyperhive-harness.json"))
&& let Ok(v) = serde_json::from_str::<serde_json::Value>(&raw)
{
let rl = v.get("rate_limited").and_then(serde_json::Value::as_bool).unwrap_or(false);
let nl = v.get("needs_login").and_then(serde_json::Value::as_bool).unwrap_or(false);
return (rl, nl);
}
// Legacy fallback: presence of individual sentinel files.
let rate_limited = dir.join("hyperhive-rate-limited").exists();

View file

@ -159,6 +159,7 @@ fn try_bind(addr: SocketAddr) -> std::io::Result<tokio::net::TcpListener> {
sock.listen(1024)
}
#[allow(clippy::struct_excessive_bools)]
#[derive(Serialize)]
struct StateSnapshot {
/// Broker seq at the moment this snapshot was assembled. Clients
@ -1833,7 +1834,7 @@ async fn get_build_log_stream(
match notify_rx.recv().await {
// Notification for a different build — ignore and wait
// for the next one.
Ok(notif_id) if notif_id != id => continue,
Ok(notif_id) if notif_id != id => {}
Ok(_) => {
match logs.get_progress(id, stdout_cursor, stderr_cursor) {
Ok(Some(prog)) => {
@ -1845,20 +1846,17 @@ async fn get_build_log_stream(
stderr_append: prog.stderr_append,
status: prog.status,
done,
}) {
if tx.send(Ok(Event::default().data(json))).await.is_err() {
return; // browser disconnected
}
}) && tx.send(Ok(Event::default().data(json))).await.is_err() {
return; // browser disconnected
}
if done {
return;
}
}
Ok(None) => return, // vacuum reaped the row
Err(_) => return,
Ok(None) | Err(_) => return, // vacuum reaped row / channel closed
}
}
Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => continue,
Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => {}
Err(tokio::sync::broadcast::error::RecvError::Closed) => return,
}
}

View file

@ -18,7 +18,7 @@ use rusqlite::{Connection, Result, params};
use crate::coordinator::Coordinator;
const VACUUM_INTERVAL: Duration = Duration::from_secs(3600);
const VACUUM_INTERVAL: Duration = Duration::from_hours(1);
const KEEP_SECS: i64 = 7 * 24 * 3600;
/// Background loop: sweep every existing agent state dir hourly, run

View file

@ -161,8 +161,7 @@ pub fn duplicate_groups(raw: &str) -> Result<Vec<DuplicateGroup>> {
pub async fn check_lock_in_sync(repo: &Path, tag: &str, approval_id: i64) -> Result<()> {
let suffix = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos())
.unwrap_or(0);
.map_or(0, |d| d.as_nanos());
let tmp_dir = std::env::temp_dir().join(format!("hive-flake-check-{approval_id}-{suffix}"));
// Detached worktree at the proposal tag — gives us a clean, mutable

View file

@ -276,8 +276,7 @@ async fn mint_token(name: &str, scopes: &str) -> Result<String> {
"{TOKEN_NAME_PREFIX}-{}",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0)
.map_or(0, |d| d.as_secs())
);
let stdout = forge_admin(&[
"user",

View file

@ -274,7 +274,7 @@ fn gateway_systemctl(args: &[&str]) -> bool {
/// Synchronise the gateway nginx unit with the current agents.conf:
///
/// - **active**: send `nginx -s reload` (SIGHUP to master, zero-downtime
/// worker replacement). Keeps RELOAD_PENDING set on failure so the
/// worker replacement). Keeps `RELOAD_PENDING` set on failure so the
/// next poll tick retries.
/// - **failed / start-limit-hit**: run `systemctl reset-failed nginx`
/// then `systemctl start nginx`. This is the self-healing path: a

View file

@ -181,7 +181,7 @@ async fn port_collision(self_name: &str) -> Option<String> {
None
}
#[allow(clippy::too_many_arguments)]
#[allow(clippy::too_many_arguments, clippy::implicit_hasher)]
pub async fn spawn(
name: &str,
hyperhive_flake: &str,
@ -324,8 +324,7 @@ pub async fn is_running(name: &str) -> bool {
.args(["is-active", "--quiet", &unit])
.status()
.await
.map(|s| s.success())
.unwrap_or(false)
.is_ok_and(|s| s.success())
}
/// Fully tear down a sub-agent's container: stop + remove via `nixos-container
@ -346,7 +345,7 @@ pub async fn destroy(name: &str) -> Result<()> {
Ok(())
}
#[allow(clippy::too_many_arguments)]
#[allow(clippy::too_many_arguments, clippy::implicit_hasher)]
pub async fn rebuild(
name: &str,
hyperhive_flake: &str,
@ -1004,7 +1003,7 @@ fn set_resource_limits(container: &str) -> Result<()> {
std::fs::create_dir_all(&dir).with_context(|| format!("create {dir}"))?;
let path = format!("{dir}/hyperhive-limits.conf");
let content =
format!("[Service]\nMemoryMax={DEFAULT_MEMORY_MAX}\nCPUQuota={DEFAULT_CPU_QUOTA}\n",);
format!("[Service]\nMemoryMax={DEFAULT_MEMORY_MAX}\nCPUQuota={DEFAULT_CPU_QUOTA}\n");
std::fs::write(&path, content).with_context(|| format!("write {path}"))?;
tracing::info!(
%path,
@ -1081,6 +1080,7 @@ fn bind_child_agent_dirs(child: &str, binds: &mut String) {
let _ = write!(binds, " --bind={config_dir}:/agents/{child}/config");
}
#[allow(clippy::too_many_lines)]
fn set_nspawn_flags(
container: &str,
runtime_dir: &Path,
@ -1265,8 +1265,7 @@ async fn run(args: &[&str]) -> Result<()> {
let agent = args
.get(1)
.copied()
.map(|c| c.strip_prefix(AGENT_PREFIX).unwrap_or(c).to_string())
.unwrap_or_else(|| "<unknown>".to_string());
.map_or_else(|| "<unknown>".to_string(), |c| c.strip_prefix(AGENT_PREFIX).unwrap_or(c).to_string());
let logs = crate::build_logs::global();
let log_id = logs.as_ref().and_then(|h| {

View file

@ -227,7 +227,7 @@ async fn cmd_serve(
let vacuum_coord = coord.clone();
let mut vacuum_shutdown = coord.shutdown_rx();
tokio::spawn(async move {
let interval = std::time::Duration::from_secs(3600);
let interval = std::time::Duration::from_hours(1);
let keep_secs: i64 = 30 * 24 * 3600;
loop {
match vacuum_coord.broker.vacuum_delivered(keep_secs) {

View file

@ -14,6 +14,7 @@ use crate::coordinator::Coordinator;
use crate::lifecycle;
pub fn start(coord: Arc<Coordinator>) -> Result<()> {
use std::os::unix::fs::PermissionsExt as _;
let dir = Coordinator::manager_dir();
std::fs::create_dir_all(&dir)
.with_context(|| format!("create manager dir {}", dir.display()))?;
@ -25,7 +26,6 @@ pub fn start(coord: Arc<Coordinator>) -> Result<()> {
.with_context(|| format!("bind manager socket {}", socket.display()))?;
// 0666 so the in-container root 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))
.with_context(|| format!("chmod manager socket {}", socket.display()))?;
tracing::info!(socket = %socket.display(), "manager socket listening");

View file

@ -49,7 +49,7 @@ pub fn meta_dir() -> PathBuf {
/// seed commit. Subsequent calls only touch `flake.nix` when the
/// rendered contents differ from disk; an unchanged `flake.nix` is a
/// no-op.
#[allow(dead_code)] // first caller lands in a later commit
#[allow(dead_code, clippy::implicit_hasher)] // first caller lands in a later commit
pub async fn sync_agents(
hyperhive_flake: &str,
dashboard_port: u16,

View file

@ -211,10 +211,10 @@ async fn rename_manager_container(coord: &Arc<Coordinator>) {
// Move rootfs if it exists (may be absent for ephemeral containers).
let old_rootfs = std::path::PathBuf::from("/var/lib/nixos-containers/root");
let new_rootfs = std::path::PathBuf::from("/var/lib/nixos-containers/h-root");
if old_rootfs.exists() && !new_rootfs.exists() {
if let Err(e) = std::fs::rename(&old_rootfs, &new_rootfs) {
tracing::warn!(error = ?e, "migration phase 5: rename rootfs failed (non-fatal)");
}
if old_rootfs.exists() && !new_rootfs.exists()
&& let Err(e) = std::fs::rename(&old_rootfs, &new_rootfs)
{
tracing::warn!(error = ?e, "migration phase 5: rename rootfs failed (non-fatal)");
}
// Daemon reload so systemd picks up the new container@h-root unit.

View file

@ -27,7 +27,7 @@ const POLL_INTERVAL: Duration = Duration::from_secs(5);
/// the dashboard list view doesn't accrue tombstones forever.
/// Cancelled rows live long enough that the operator can still
/// see what they cancelled in the recent past.
const CANCELLED_REAP_AGE: Duration = Duration::from_secs(3600);
const CANCELLED_REAP_AGE: Duration = Duration::from_hours(1);
pub fn spawn(coord: Arc<Coordinator>) {
let mut shutdown = coord.shutdown_rx();

View file

@ -15,7 +15,7 @@ use rusqlite::{Connection, Result, params};
use crate::coordinator::Coordinator;
const VACUUM_INTERVAL: Duration = Duration::from_secs(3600);
const VACUUM_INTERVAL: Duration = Duration::from_hours(1);
const KEEP_SECS: i64 = 90 * 24 * 3600;
/// Background loop: sweep every existing agent state dir hourly, run

View file

@ -3,7 +3,7 @@
//! and the meta `flake.nix`.
//!
//! Format: a JSON object mapping agent name to an array of
//! `hive_sh4re::ToolGroup` snake_case strings:
//! `hive_sh4re::ToolGroup` `snake_case` strings:
//!
//! ```json
//! {