-
Notifications
You must be signed in to change notification settings - Fork 56
fix(prune): add --errored mode for blanket exhausted-error sweep (PR-B G3 #2) #1637
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -668,6 +668,82 @@ export async function archiveExhaustedZombies(ttlHours = DEAD_PANE_ZOMBIE_TTL_HO | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Default TTL (hours) for `genie prune --errored` mode. Shorter than | ||
| * `DEAD_PANE_ZOMBIE_TTL_HOURS` because `--errored` is opt-in: an operator | ||
| * who runs it has already decided the rows are noise. The 1h floor still | ||
| * gives a brief grace window to inspect freshly-failed agents. | ||
| */ | ||
| const EXHAUSTED_ERRORED_TTL_HOURS = 1; | ||
|
|
||
| /** | ||
| * Archive any exhausted error-state agent older than the TTL, regardless | ||
| * of audit reason. Distinct from `archiveExhaustedZombies` which only | ||
| * touches reconciler-tagged dead-pane rows. Use this when you want a | ||
| * blanket sweep of inert error rows; use `auto_resume=true` to keep a | ||
| * row visible past the TTL. | ||
| * | ||
| * Audit reason: `errored_ttl_exhausted` (distinct from | ||
| * `dead_pane_zombie_ttl_exhausted` so forensics can tell which sweep | ||
| * archived the row). | ||
| * | ||
| * @param ttlHours - Minimum age in hours before archival (default: 1) | ||
| * @returns IDs of agents that were archived | ||
| */ | ||
| export async function archiveAllExhaustedErrored(ttlHours = EXHAUSTED_ERRORED_TTL_HOURS): Promise<string[]> { | ||
| try { | ||
| const sql = await getConnection(); | ||
| const rows = await sql<{ id: string }[]>` | ||
| UPDATE agents a | ||
| SET state = 'archived', last_state_change = now() | ||
| WHERE a.state = 'error' | ||
| AND a.auto_resume = false | ||
| AND a.last_state_change < now() - make_interval(hours => ${ttlHours}) | ||
| RETURNING id | ||
| `; | ||
| const auditPromises: Promise<void>[] = []; | ||
| 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(() => {}), | ||
| ); | ||
| } | ||
| await Promise.allSettled(auditPromises); | ||
| return rows.map((r: { id: string }) => r.id); | ||
| } catch { | ||
| return []; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Dry-run companion to `archiveAllExhaustedErrored` — lists rows that | ||
| * would be archived without mutating state. | ||
| */ | ||
| export async function listAllExhaustedErrored( | ||
| ttlHours = EXHAUSTED_ERRORED_TTL_HOURS, | ||
| ): Promise<Array<{ id: string; lastStateChange: string }>> { | ||
| try { | ||
| const sql = await getConnection(); | ||
| const rows = await sql<{ id: string; last_state_change: string }[]>` | ||
| SELECT a.id, a.last_state_change FROM agents a | ||
| WHERE a.state = 'error' | ||
| AND a.auto_resume = false | ||
| AND a.last_state_change < now() - make_interval(hours => ${ttlHours}) | ||
| ORDER BY a.last_state_change ASC | ||
| `; | ||
| return rows.map((r: { id: string; last_state_change: string }) => ({ | ||
| id: r.id, | ||
| lastStateChange: r.last_state_change, | ||
| })); | ||
|
Comment on lines
+738
to
+741
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The return rows.map((r: { id: string; last_state_change: string | Date }) => ({
id: r.id,
lastStateChange: ts(r.last_state_change),
})); |
||
| } catch { | ||
| return []; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Count dead-pane zombies eligible for TTL archive without mutating them. | ||
| * Used by `genie prune --zombies --dry-run`. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This loop contains redundant logging to
stderr(which is already handled by the CLI summary inprune.ts) and uses a hardcoded actor string. It is better to remove theconsole.errorand useprocess.env.GENIE_AGENT_NAME ?? 'cli'for the audit event actor, matching the pattern used in theupdatefunction and ensuring consistency across different execution environments.