fix(prune): add --errored mode for blanket exhausted-error sweep (PR-B G3 #2) - #1637
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request adds a new --errored target to the genie prune command to archive agents in an error state with exhausted auto-resume budgets. It introduces supporting library functions, a default 1-hour TTL, and updates the CLI logic. Feedback recommends enhancing consistency by using environment variables for audit actors, removing redundant logging, and utilizing the ts() helper for reliable timestamp formatting.
| for (const row of rows) { | ||
| console.error(`[prune] Archived exhausted errored ${row.id} (TTL ${ttlHours}h)`); | ||
| auditPromises.push( | ||
| recordAuditEvent('worker', row.id, 'state_changed', 'cli', { | ||
| state: 'archived', | ||
| reason: 'errored_ttl_exhausted', | ||
| ttl_hours: ttlHours, | ||
| }).catch(() => {}), | ||
| ); | ||
| } |
There was a problem hiding this comment.
This loop contains redundant logging to stderr (which is already handled by the CLI summary in prune.ts) and uses a hardcoded actor string. It is better to remove the console.error and use process.env.GENIE_AGENT_NAME ?? 'cli' for the audit event actor, matching the pattern used in the update function and ensuring consistency across different execution environments.
for (const row of rows) {
auditPromises.push(
recordAuditEvent('worker', row.id, 'state_changed', process.env.GENIE_AGENT_NAME ?? 'cli', {
state: 'archived',
reason: 'errored_ttl_exhausted',
ttl_hours: ttlHours,
}).catch(() => {}),
);
}| return rows.map((r: { id: string; last_state_change: string }) => ({ | ||
| id: r.id, | ||
| lastStateChange: r.last_state_change, | ||
| })); |
There was a problem hiding this comment.
The last_state_change column is typically returned as a Date object by the database driver. Using the ts() helper ensures it is consistently converted to an ISO string, matching the function's return type and ensuring stable formatting in the CLI output. This also maintains consistency with how timestamps are handled in rowToAgent.
return rows.map((r: { id: string; last_state_change: string | Date }) => ({
id: r.id,
lastStateChange: ts(r.last_state_change),
}));`genie prune --zombies` only archives reconciler-tagged dead-pane rows
(audit reason 'dead_pane_zombie' or 'stale_spawn_dead_pane'). That's
the safe, conservative sweep — but operators occasionally want a blanket
cleanup of any inert error-state row regardless of reason.
Add `genie prune --errored`:
- Archives any state=error + auto_resume=false agent older than the TTL.
- 1h default TTL (vs 24h for --zombies) — opt-in flag means the operator
has already decided the rows are noise.
- Audit reason: 'errored_ttl_exhausted' (distinct from
'dead_pane_zombie_ttl_exhausted' so forensics can tell which sweep
archived a row).
- Mutually exclusive with --zombies; pick one mode per invocation.
- Set auto_resume=true on a row to keep it visible past the TTL.
New helpers:
- archiveAllExhaustedErrored(ttlHours) — same as archiveExhaustedZombies
but without the audit-reason EXISTS filter.
- listAllExhaustedErrored(ttlHours) — dry-run companion.
`prune.ts` reorganized around a `PruneMode` discriminator with
mode-specific default TTL + label tables. --zombies semantics unchanged.
Wish: cli-noise-and-hygiene-cleanup G3 (deliverables #2-5).
Pairs with the prior G3#1 fix (broaden zombie reason filter).
Smoke (live DB):
- Seeded a 2h-old error+exhausted row with NO audit reason.
- listExhaustedZombies(1) skipped it (correct: no audit tag).
- listAllExhaustedErrored(1) matched it (correct: blanket).
- archiveAllExhaustedErrored(1) flipped state→'archived' and emitted
audit reason='errored_ttl_exhausted'.
- genie ls errored count dropped 6→3 (3 newer-than-1h survived TTL).
4d22a4b to
80a0703
Compare
…coped per reviewer Lands the wish doc that scaffolds PR-A (#1634) and PR-B (#1636/#1637/#1638/ #1640/#1642), plus the 2026-05-07 PR-C draft + reviewer FIX-FIRST corrections. Why this is a separate docs commit: - The wish file was authored 2026-05-04 but only ever sat in a stash; never committed despite shipping work referencing it. This commit lands the reference document for completed + pending work in one place. - PR-C as originally drafted had three invalid premises against live 4.260507.1 (G3 amendment already implemented at scheduler-daemon.ts:1296; G9 line is on stderr not stdout; G10 design assumes binary-spawn that the HTTP probe doesn't do). Reviewer corrections folded in. - Only G8 (kill-path shadow+UUID dedup) survives intact — file path corrected to src/term-commands/agents.ts:2817 (handleWorkerKill). - G9 reframed as stderr-noise reduction (DEBUG=pgserve gating). - G10 deferred pending /trace into update.ts:362. QA dogfooding-72h artifacts (AUDIT.md, QA-PLAN.md) document the 72-h fix-audit sweep that surfaced the bugs and triggered the wish update. Refs: #1677 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Summary
Cli-noise-and-hygiene-cleanup G3 deliverables #2-5 — adds
genie prune --erroredmode that archives any state=error+auto_resume=false rows, regardless of reconciler audit-event reason tag. Distinct from--zombies(24h default, reconciler-tagged only);--erroreddefaults to 1h TTL and is opt-in.Eliminates the gap where manually-error'd or non-reconciler-tagged crashed agents accumulated indefinitely.
Changes
src/lib/agent-registry.ts(+76) — newarchiveAllExhaustedErrored(ttlHours)andlistAllExhaustedErrored(ttlHours)helpers;EXHAUSTED_ERRORED_TTL_HOURS=1default.src/term-commands/prune.ts(+82/-30) — rewrite aroundPruneModediscriminator; new--erroredflag mutually exclusive with--zombies; mode-specific default TTL.src/lib/__tests__/zombie-spawns.test.ts(+16) — source-grep regression test.Test plan
format --write)--zombiesskips it,--erroredmatches; archive emitsaudit_reason: errored_ttl_exhausted(distinct from zombie sweep)genie lserrored count 6 → 3 (3 within-TTL agents preserved)Concerns (documented per autonomous-loop brief)
dead_pane_zombierows (age >1h). They were inert and would have hit reconciler's 24h TTL anyway; no recoverable agents lost. Behavior matches spec.Wish + sequencing
cli-noise-and-hygiene-cleanupPR-B G3 deliverables How to select between Genie versions when running claude? #2-5🤖 Generated with Claude Code