Watch
0
0
Fork
You've already forked hyperhive
0

hive-agent: correct doc comments that describe sentinel files, session flags and outcomes the code no longer has

This commit is contained in:
damocles 2026-10-21 22:13:54 +02:00 • committed by mara
commit ac0bed47e9
11 changed files with 40 additions and 38 deletions

View file

@ -46,8 +46,8 @@ pub fn announce(label: &str, todos: &Todos, wake: &Notify) {
let summary = format!(
"You were just (re)started. If you were mid-task, check \
`/agents/{label}/state/` for your notes and pick up where you left \
off — claude's `--continue` session is intact, so prior context is \
still in your window."
off — your claude session (resumed by title) is intact, so prior \
context is still in your window."
);
match todos.upsert(SUBSYSTEM, Some(KEY), &summary, None, true) {
Ok((_, true)) => wake.notify_one(),

View file

@ -302,10 +302,9 @@ pub struct Bus {
last_cost_usage: Arc<Mutex<Option<TokenUsage>>>,
/// True while the harness is parked after a rate-limit response.
/// Set by `emit_status("rate_limited")`, cleared by
/// `emit_status("online")`. Also mirrored to a sentinel file at
/// `{state_dir}/hyperhive-rate-limited` so the host-side
/// `container_view` can surface the status on the dashboard without
/// a live socket call.
/// `emit_status("online")`. `emit_status` also persists it in
/// `hyperhive-harness.json` (see `harness_state`), so the host can
/// surface the status on the dashboard without a live socket call.
rate_limited: Arc<AtomicBool>,
/// One-shot: operator asked to reset the claude session (`POST
/// /api/new-session`). Consumed at the *next* turn boundary by

View file

@ -30,10 +30,10 @@ pub fn hive_domain() -> Option<String> {
/// Human display name of this hive (e.g. `pr1ma`). Distinct from
/// [`hive_domain`] — the domain is the machine-readable DNS address;
/// this is the prose label humans use in conversation. Returns None
/// when `/etc/hyperhive-hive-facts` carries no name (the host's
/// `services.hyperhive.hiveName` is unset), in which case callers fall
/// back to the domain or the short label at their discretion.
/// this is the prose label humans use in conversation. Reads the
/// `HYPERHIVE_HIVE_NAME` env var; returns None when it is unset or empty
/// (the host's `services.hyperhive.hiveName` is unset), in which case
/// callers fall back to the domain or the short label at their discretion.
#[must_use]
pub fn hive_name() -> Option<String> {
non_empty_env("HYPERHIVE_HIVE_NAME")

View file

@ -75,7 +75,7 @@ pub struct ClearedSession {
/// Delete the credential files (see [`CRED_FILE_NAMES`]) from `dir`, forcing a
/// re-login on the next turn, while preserving the session-history files
/// alongside them so `claude --continue` keeps working after a fresh login.
/// alongside them so the session resumed by title survives a fresh login.
/// Idempotent: an already-absent file is skipped, not reported. This is the
/// write-side counterpart to [`has_session`]; `/logout` (`web_ui::auth`) drives
/// it.
@ -165,13 +165,12 @@ pub async fn wait_for_login(
claude_dir = %claude_dir.display(),
"no claude session — staying in partial-run mode (web UI only)"
);
// Announce `needs_login_idle` to the bus so the sentinel file
// (`{state_dir}/hyperhive-needs-login`) gets written on every entry
// path — cold-boot, 401-mid-turn, and `/api/logout`. The host's
// `auth_failed_sentinel` reads that file to surface `needs_login`
// on the dashboard. Idempotent — `emit_status` is a `write` on a
// small empty file, so re-entering this function after a transient
// operator action is a no-op for the on-disk state.
// Announce `needs_login_idle` to the bus so
// `hyperhive-harness.json` records it on every entry path —
// cold-boot, 401-mid-turn, and `/api/logout`. The host reads that
// file to surface `needs_login` on the dashboard. Idempotent —
// re-entering this function after a transient operator action
// rewrites the same on-disk state.
bus.emit_status("needs_login_idle");
// Baseline for the unreadable-mtime fallback in `has_fresh_credentials`
// — captured once, here, not recomputed per poll. See that fn's doc

View file

@ -614,9 +614,8 @@ async fn serve_main<S: Surface>(socket: &Path, poll_ms: u64) -> Result<()> {
)
.await;
} else {
// Clear any stale `hyperhive-needs-login` sentinel left over
// from a prior boot — `online` status writes the sentinel
// cleanup in `Bus::emit_status`.
// Record `online` in `hyperhive-harness.json`, which clears a
// `needs_login` left over from a prior boot (`Bus::emit_status`).
bus.emit_status("online");
}
serve_loop::<S>(

View file

@ -6,7 +6,7 @@
//! only the harness-only concepts: wall-clock turn duration as *this harness*
//! measures it (not Claude's own per-request latency), what woke the turn,
//! the harness's own outcome classification, the loose-ends backlog at turn
//! end, session boundaries (fresh vs. `--continue`'d), context-window fill,
//! end, session boundaries (fresh vs. resumed by title), context-window fill,
//! and the cost an ACP agent reports — claude's runtime reports none.
//!
//! Synchronous instruments, not observable ones: unlike hive-c0re's

View file

@ -1,5 +1,5 @@
//! Pure helpers factored out of the harness serve loop
//! (`bin/hive-agent.rs`).
//! (`serve_main` in `main.rs`).
//! Only functions with no wire-type dependency live here;
//! request/response-flavored helpers (`requeue_inflight`, `ack_turn`, etc.)
//! stay in the binary because they touch the request enum variants directly.

View file

@ -151,9 +151,9 @@ pub struct Snapshot {
pub first_turn_ctx: Option<u64>,
/// Number of fresh claude sessions (i.e. rows in the `sessions` table)
/// that started within the window. A new session is minted whenever the
/// harness runs a turn without `--continue` (manual `/new-session`,
/// auto-compaction fallback, or first-ever turn). `None` when the
/// `sessions` table doesn't exist yet (older db) — same inert-until-data
/// harness creates a session instead of resuming it by title (manual
/// `/new-session`, auto-compaction fallback, or first-ever turn). `None` when
/// the `sessions` table doesn't exist yet (older db) — same inert-until-data
/// pattern as `first_turn_ctx`.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub session_count: Option<u64>,
@ -380,7 +380,7 @@ fn snapshot(path: &Path, window: Window) -> Result<Snapshot> {
/// First-turn input tokens of the most recent fresh claude session that
/// started in `[from, now]`. Tracks system-prompt + AGENTS.md sprawl:
/// the first turn of a fresh session (`--continue` suppressed) pays the
/// the first turn of a fresh session (created, not resumed by title) pays the
/// full static prefix as uncached input, so watching this over time
/// surfaces creep. Uses the agreed per-session derive — the first turn
/// (`ORDER BY started_at LIMIT 1`) of the latest session row.
@ -404,8 +404,9 @@ fn read_first_turn_ctx(conn: &Connection, from: i64) -> rusqlite::Result<u64> {
/// Count of fresh claude sessions that started within `[from, now]`.
///
/// Each row in the `sessions` table represents one fresh `claude --print`
/// invocation (without `--continue`): a manual `/new-session`, an
/// auto-compaction fallback, or the very first turn after spawning.
/// invocation that created a session rather than resuming by title: a manual
/// `/new-session`, an auto-compaction fallback, or the very first turn after
/// spawning.
///
/// Returns `Err` when the `sessions` table doesn't exist (older db) so the
/// caller can map to `None` — same inert-until-data pattern as

View file

@ -717,8 +717,9 @@ fn claude_config(bus: &Bus, files: &TurnFiles) -> Config {
/// Map a `hive_claude::Error` onto the harness's `TurnOutcome`. The recognized
/// sentinels become their matching outcomes; a residual `SessionNotFound`
/// (create path itself missed — shouldn't happen) settles as `Ok`; genuine
/// failures become `Failed` (converting the typed lib error into `anyhow`).
/// (create path itself missed — shouldn't happen) stays `Err(SessionNotFound)`
/// for `handle_turn_error_recovery` to requeue; genuine failures become
/// `Failed` (converting the typed lib error into `anyhow`).
fn error_to_turn(err: hive_claude::Error) -> TurnOutcome {
use hive_claude::Error;
match err {

View file

@ -10,8 +10,9 @@
//! `open_reminders_count` (planned: a loose-ends-over-time trend), and
//! `note` (failure detail for `result_kind = "failed"`).
//!
//! Lives next to `hyperhive-events.sqlite` in the agent's state dir
//! so the host-side state vacuum sweep can reach both. Schema is
//! Lives in the harness dir (`HYPERHIVE_HARNESS_DIR`) as
//! `hyperhive-turn-stats.sqlite`; the dashboard reads it read-only and no
//! vacuum sweeps it. Schema is
//! intentionally append-only — every column has a default so future
//! additions don't break old readers; new columns land via
//! `ALTER TABLE ... ADD COLUMN ... DEFAULT ...` in the migration
@ -62,7 +63,8 @@ CREATE INDEX IF NOT EXISTS idx_turn_stats_started
-- (the old table has no session_id column), so indexing session_id in this
-- batch would fail with `no such column` and abort the whole SCHEMA apply —
-- which disables the stats sink. The column is added by MIGRATIONS first.
-- One row per fresh claude session (minted when --continue is suppressed).
-- One row per fresh claude session (minted when a session is created rather
-- than resumed by title).
-- turn_stats.session_id FKs here so per-session stats (first-turn tokens,
-- per-session totals, turn count, duration) are one GROUP BY away.
CREATE TABLE IF NOT EXISTS sessions (

View file

@ -169,11 +169,12 @@ pub async fn serve(
Ok(())
}
/// Bind a `UnixListener` at `path` and drop a `.bound` marker next
/// to it so c0re's gateway-map writer knows the socket is live.
/// Bind a `UnixListener` at `path` and drop a `hyperhive-socket-bound` marker
/// next to it so c0re's gateway-map writer knows the socket is live.
/// Best-effort unlinks any stale socket left from a crashed previous
/// harness (clean exit removes it, but `bind(2)` refuses to overwrite
/// an existing file) and `mkdir -p`s the parent for first-boot. Mode
/// harness (nothing removes the socket or marker on exit, and `bind(2)`
/// refuses to overwrite an existing file) and `mkdir -p`s the parent for
/// first-boot. Mode
/// `0o666` — world-accessible so the gateway's nginx process can
/// `connect(2)` without sharing a group with the agent user. What bounds
/// that is the per-agent subdir (`/run/hive-agent/<name>/`): the socket