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

@ -229,7 +229,7 @@ async fn run_loop(socket: PathBuf) {
let claimed: Arc<Mutex<HashSet<String>>> = Arc::new(Mutex::new(HashSet::new()));
loop {
poll_once(&socket, &claimed).await;
poll_once(&socket, &claimed);
tokio::time::sleep(POLL_INTERVAL).await;
}
}
@ -258,7 +258,7 @@ async fn mark_interrupted(socket: &Path) {
}
}
async fn poll_once(socket: &Path, claimed: &Arc<Mutex<HashSet<String>>>) {
fn poll_once(socket: &Path, claimed: &Arc<Mutex<HashSet<String>>>) {
let Ok(rd) = std::fs::read_dir(tasks_dir()) else { return };
for entry in rd.flatten() {
let path = entry.path();

View file

@ -117,7 +117,7 @@ async fn main() -> Result<()> {
/// Surface a `SYSTEM_SENDER` message in the live event bus + tracing
/// log. Both agents and the manager receive `QuestionAnswered`,
/// `ContainerCrash`, reparent notifications, and friends; the parse
/// + log path is identical. Quiet no-op when `from` isn't
/// and log path is identical. Quiet no-op when `from` isn't
/// `SYSTEM_SENDER`.
fn log_system_event(bus: &Bus, from: &str, body: &str) {
if from != SYSTEM_SENDER {
@ -165,7 +165,7 @@ fn consume_continue_sentinel() -> bool {
/// What a `Recv` long-poll returned. Decoupled from the per-role
/// Response enum so `serve_loop` can pattern-match without seeing
/// either AgentResponse or ManagerResponse directly.
/// either `AgentResponse` or `ManagerResponse` directly.
enum RecvOutcome {
/// Long-poll returned at least one message; first one is detached.
Message(hive_sh4re::DeliveredMessage),
@ -212,7 +212,7 @@ trait Surface {
fn send_to_parent(socket: &Path, body: String) -> impl Future<Output = ()>;
/// Fire a `Wake { from: "self", body: "continue" }` at our own
/// inbox — the request_next_turn sentinel pickup.
/// inbox — the `request_next_turn` sentinel pickup.
fn self_wake(socket: &Path) -> impl Future<Output = ()>;
/// Long-poll the broker for the next message. Wraps the

View file

@ -80,12 +80,12 @@ fn harness_json_path() -> PathBuf {
fn read_harness_state() -> (bool, bool) {
// Try the new consolidated file first.
if let Ok(raw) = std::fs::read_to_string(harness_json_path()) {
if let Ok(v) = serde_json::from_str::<serde_json::Value>(&raw) {
let rate_limited = v.get("rate_limited").and_then(|x| x.as_bool()).unwrap_or(false);
let needs_login = v.get("needs_login").and_then(|x| x.as_bool()).unwrap_or(false);
return (rate_limited, needs_login);
}
if let Ok(raw) = std::fs::read_to_string(harness_json_path())
&& let Ok(v) = serde_json::from_str::<serde_json::Value>(&raw)
{
let rate_limited = v.get("rate_limited").and_then(serde_json::Value::as_bool).unwrap_or(false);
let needs_login = v.get("needs_login").and_then(serde_json::Value::as_bool).unwrap_or(false);
return (rate_limited, needs_login);
}
// Fall back to legacy sentinel files written by older harness builds.
let state_dir = crate::paths::state_dir();

View file

@ -88,8 +88,7 @@ pub async fn run(socket: PathBuf) {
// HIVE_FORGE_KEEP_SUBSCRIPTIONS=1 disables auto-unsubscribe for agents
// that intentionally consume the full repo notification firehose (e.g. triage).
let keep_subscriptions = std::env::var("HIVE_FORGE_KEEP_SUBSCRIPTIONS")
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
.unwrap_or(false);
.is_ok_and(|v| v == "1" || v.eq_ignore_ascii_case("true"));
// Optional reason drop-list — comma-separated Forgejo `reason`
// values to silently mark-read instead of deliver. See
@ -159,7 +158,7 @@ fn notif_type_label(t: &str) -> &str {
/// inside the forge-notify wrapper, so a leading `## title` line
/// doesn't blow into an h2 in the dashboard render. See
/// `docs/forge.md::Body excerpt + truncation + heading escape` for
/// the strict-ATX-vs-`#tag` rationale and the split_inclusive
/// the strict-ATX-vs-`#tag` rationale and the `split_inclusive`
/// trailing-newline contract.
fn escape_md_headings(body: &str) -> String {
let mut out = String::with_capacity(body.len());

View file

@ -448,20 +448,20 @@ fn format_bash_status(id: &str) -> String {
let age = crate::serve_common::now_unix() - t;
let _ = write!(out, ", running for {age}s");
}
if let Some(t) = task.completed_at {
if let Some(s) = task.started_at {
let _ = write!(out, ", took {}s", t - s);
}
if let Some(t) = task.completed_at
&& let Some(s) = task.started_at
{
let _ = write!(out, ", took {}s", t - s);
}
if let Some(ref stdout) = task.stdout_tail {
if !stdout.trim().is_empty() {
let _ = write!(out, "\n\nstdout:\n```\n{}\n```", stdout.trim());
}
if let Some(ref stdout) = task.stdout_tail
&& !stdout.trim().is_empty()
{
let _ = write!(out, "\n\nstdout:\n```\n{}\n```", stdout.trim());
}
if let Some(ref stderr) = task.stderr_tail {
if !stderr.trim().is_empty() {
let _ = write!(out, "\n\nstderr:\n```\n{}\n```", stderr.trim());
}
if let Some(ref stderr) = task.stderr_tail
&& !stderr.trim().is_empty()
{
let _ = write!(out, "\n\nstderr:\n```\n{}\n```", stderr.trim());
}
out
}
@ -1913,14 +1913,14 @@ pub enum Flavor {
}
/// Env var written by the meta renderer with a comma-separated list of
/// `hive_sh4re::ToolGroup` snake_case names (e.g. `"messaging,inbox,meta"`).
/// `hive_sh4re::ToolGroup` `snake_case` names (e.g. `"messaging,inbox,meta"`).
/// When present, the harness expands the groups into per-tool allow entries
/// instead of using the hardcoded flavor default. See `docs/conventions.md::Tool groups`.
const TOOL_GROUPS_ENV: &str = "HIVE_TOOL_GROUPS";
/// `HIVE_CAPABILITIES` env var injected by `meta::render_flake` when the
/// operator grants capabilities to this agent. Comma-separated
/// `hive_sh4re::Capability` snake_case names. Absent = no extra capabilities.
/// `hive_sh4re::Capability` `snake_case` names. Absent = no extra capabilities.
const CAPABILITIES_ENV: &str = "HIVE_CAPABILITIES";
/// Returns the MCP tool names (without `mcp__hyperhive__` prefix) that are
@ -1976,14 +1976,12 @@ fn effective_tool_groups(flavor: Flavor) -> Vec<hive_sh4re::ToolGroup> {
for token in raw.split(',') {
let t = token.trim().to_ascii_lowercase();
// Parse via serde_json (the canonical deserialization path).
match serde_json::from_value::<hive_sh4re::ToolGroup>(
if let Ok(g) = serde_json::from_value::<hive_sh4re::ToolGroup>(
serde_json::Value::String(t.clone()),
) {
Ok(g) => groups.push(g),
Err(_) => tracing::warn!(
token = %t,
"{TOOL_GROUPS_ENV}: unknown tool group, skipping"
),
groups.push(g);
} else {
tracing::warn!(token = %t, "{TOOL_GROUPS_ENV}: unknown tool group, skipping");
}
}
if groups.is_empty() {

View file

@ -423,8 +423,7 @@ fn maybe_auto_reset(bus: &Bus) {
// Compute idle seconds using the same clock as now_unix (unix epoch, i64).
let now = 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 idle_secs = now.saturating_sub(u64::try_from(last_ended).unwrap_or(0));
let ttl = cache_ttl_secs();
if idle_secs < ttl {
@ -482,7 +481,7 @@ pub fn emit_turn_end(bus: &Bus, outcome: &TurnOutcome) {
/// snapshot advances (mtime OR file-count change), avoiding the
/// infinite-401 loop a bare-existence check would produce when stale
/// credentials are already on disk. Mtime-snapshot resumption rationale
/// + DirSnapshot two-axis design: see
/// and `DirSnapshot` two-axis design: see
/// [`docs/turn-loop.md::The loop`](../../docs/turn-loop.md).
///
/// # Panics

View file

@ -173,6 +173,7 @@ pub async fn serve(
/// Marker-gating + the gateway-side consumer: see
/// [`docs/gateway.md::Per-agent unix-socket upstream`](../../../docs/gateway.md).
fn bind_unix(path: &Path) -> Result<tokio::net::UnixListener> {
use std::os::unix::fs::PermissionsExt;
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)
.with_context(|| format!("create socket parent dir {}", parent.display()))?;
@ -183,7 +184,6 @@ fn bind_unix(path: &Path) -> Result<tokio::net::UnixListener> {
let _ = std::fs::remove_file(path);
let listener = tokio::net::UnixListener::bind(path)
.with_context(|| format!("bind unix socket at {}", path.display()))?;
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o666))
.with_context(|| format!("set perms on {}", path.display()))?;
// Best-effort ready marker: failed write isn't fatal (the harness
@ -319,11 +319,10 @@ async fn relay_ws_vnc(socket: axum::extract::ws::WebSocket, vnc_port: u16) {
let ws_to_tcp = tokio::spawn(async move {
while let Some(Ok(msg)) = futures_util::StreamExt::next(&mut ws_rx).await {
match msg {
Message::Binary(data) => {
if tcp_tx.write_all(&data).await.is_err() {
Message::Binary(data)
if tcp_tx.write_all(&data).await.is_err() => {
break;
}
}
Message::Close(_) => break,
_ => {} // ping/pong/text: ignore
}