From dd7f8c5ebb965cadb47193ce4f27d6276a9bf350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?m=C3=BCde?= Date: Sun, 5 Jul 2026 22:27:09 +0200 Subject: [PATCH] docs(turn-loop): document PromptTooLong archive+requeue, TurnOutcome=Result, credential-file session detection --- docs/turn-loop.md | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/docs/turn-loop.md b/docs/turn-loop.md index 2f940e0e..3e9d75f0 100644 --- a/docs/turn-loop.md +++ b/docs/turn-loop.md @@ -43,14 +43,18 @@ Each agent harness (`hive serve` — one binary for all agents) runs: the per-agent web UI login flow; on success the sentinel is cleared and the queued message drives the next turn normally. **Mtime-snapshot resumption**: `wait_for_login` - snapshots the `~/.claude/` dir (newest file mtime + file count) - at entry and only resumes when that snapshot advances — not - just when credentials exist on disk. This prevents a silent - infinite-401 loop: stale credentials already on disk at the - time of the 401 no longer cause an immediate false-resume. The - `DirSnapshot` struct tracks both axes; either a mtime advance - OR a file-count change triggers resume (the count axis handles - filesystems where `modified()` errors on every file). + snapshots the `~/.claude/` dir (newest mtime + count over the + credential files in `login::CRED_FILE_NAMES`) at entry and only + resumes when that snapshot advances — not just when credentials + exist on disk. This prevents a silent infinite-401 loop: stale + credentials already on disk at the time of the 401 no longer cause + an immediate false-resume. The `DirSnapshot` struct tracks both + axes; either a mtime advance OR a file-count change triggers resume + (the count axis handles filesystems where `modified()` errors on + every file). Boot detection (`login::has_session`, deciding Online + vs NeedsLogin) keys off the same `CRED_FILE_NAMES` set — the files + `/logout` deletes — so leftover session-history files don't read as + a live session after a logout + container recreate. 7. Emit `LiveEvent::TurnEnd { ok, note }`. Sleep `poll_ms` to avoid tight loops on transient failures. @@ -108,14 +112,16 @@ and the manager fall through to operator). ### Turn outcomes -`turn::TurnOutcome` drives the post-claude branch: +`turn::TurnOutcome` (`Result` — `Ok(compacted)` on success, +else a `TurnError`) drives the post-claude branch: | Outcome | Action | | --- | --- | -| `Ok` / `Compacted` | `ack_turn` | -| `RateLimited` | sleep `HIVE_RATE_LIMIT_SLEEP_SECS` (default 300), requeue inflight, status back to `online` | -| `AuthFailed` | emit `needs_login_idle` sentinel, requeue inflight, park in `wait_for_login` | -| `Failed(err)` | route `[system] \`\` claude turn failed:\n` to `` via `send_to_parent` | +| `Ok(_)` (`false` normal / `true` compacted) | `ack_turn` | +| `Err(PromptTooLong)` | `drive_turn` archived the session (the lib already compacted + retried and it still overflowed); requeue inflight so the message redelivers into a fresh session that fits — no status park | +| `Err(RateLimited)` | sleep `HIVE_RATE_LIMIT_SLEEP_SECS` (default 300), requeue inflight, status back to `online` | +| `Err(AuthFailed)` | emit `needs_login_idle` sentinel, requeue inflight, park in `wait_for_login` | +| `Err(Failed(err))` | route `[system] \`\` claude turn failed:\n` to `` via `send_to_parent` | After the outcome handler, the stats sink records a row and the `hyperhive-continue` sentinel (dropped by the `request_next_turn` @@ -233,7 +239,12 @@ window with two triggers baked into its `run`: - **Reactive** — claude-code prints `Prompt is too long`. The session is *already* past the window, so no turn can run on it — the session `/compact`s straight away and retries the same wake-up prompt once. No - notes-checkpoint turn is possible here: the detail is gone. + notes-checkpoint turn is possible here: the detail is gone. If the retry + *still* overflows, `run` surfaces `Error::PromptTooLong`; `drive_turn` + then archives the session (session lifecycle stays hive-side) and the + serve loop requeues the message so it redelivers into a fresh session + (see [Turn outcomes](#turn-outcomes) — the wake prompt itself is tiny, so + the overflow was the accumulated context the archive clears). - **Proactive** — a turn finishes cleanly but the last inference's context size crossed the policy watermark. While the session is still healthy it runs one synthetic *notes-checkpoint* turn (`CHECKPOINT_PROMPT` —