Skip to content

fix: restore ready-for-work label when a dispatched job fails after exhausting retries - #478

Merged
getappz merged 2 commits into
masterfrom
task/463-failed-jobs-retries-exhausted-leave-item
Aug 13, 2026
Merged

fix: restore ready-for-work label when a dispatched job fails after exhausting retries#478
getappz merged 2 commits into
masterfrom
task/463-failed-jobs-retries-exhausted-leave-item

Conversation

@getappz

@getappz getappz commented Aug 13, 2026

Copy link
Copy Markdown
Owner

Committed as 635d1c8 on the current branch task/463-failed-jobs-retries-exhausted-leave-item.

Summary

Fixed item #463: items whose dispatched job cleanly failed after exhausting max_retries stayed labeled dispatched forever, invisible to every future discovery tick.

Root cause: agentflare_jobs::Queue::fail() decides retry-vs-terminal but never told any caller which happened. orphan_reconcile.rs's label-restore logic only fired for crashed/orphaned jobs (state = 'running' at daemon startup), never for a job that ran to completion and cleanly failed.

Fix:

  • Queue::fail() now returns Result<bool, Error>true when the failure was terminal.
  • WorkerPool gains with_terminal_failure_hook(...); run_in_process invokes it exactly once, only on a genuine terminal failure (verified by a new test asserting it fires once after 2 retries, not on either retry).
  • The daemon (dashboard/server.rs) wires that hook to a new dashboard::orphan_reconcile::handle_terminal_job_failure, which removes the dispatched label and adds needs-manual-dispatch (falling back to ready-for-work if that label was never created for the project) — avoiding a bare requeue that would just retry-loop against the same broken agent (e.g. the reproduced billing-balance failure).
  • Made NEEDS_MANUAL_LABEL pub(crate) in supervisor.rs as the shared source of truth.

Added tests covering: the label swap to needs-manual-dispatch, the fallback to ready-for-work, a no-op for non-in_process jobs, and the WorkerPool hook firing correctly through the real retry/terminal-failure flow. All new and pre-existing tests pass; cargo fmt clean.

…ries (#463)

Queue::fail now reports whether a failure was terminal (retries
exhausted) vs a requeue. WorkerPool gains a terminal_failure_hook fired
from run_in_process on that terminal case; the daemon wires it to
dashboard::orphan_reconcile::handle_terminal_job_failure, which swaps
the item off dispatched onto needs-manual-dispatch (or ready-for-work
as a fallback) -- the clean-failure counterpart to reconcile_orphaned_jobs,
which only ever covered a job whose process crashed mid-flight.

Previously an item whose dispatched job failed for an ordinary reason
(no billing balance, transient network error) stayed labeled dispatched
forever, invisible to every future discovery tick.

Agentflare-Agent: claude-code
Agentflare-Branch: task/463-failed-jobs-retries-exhausted-leave-item
Agentflare-Item: 463
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 53 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b687cb25-a5b7-416a-83bf-17e39e42bc36

📥 Commits

Reviewing files that changed from the base of the PR and between 373a96f and 529d9ff.

📒 Files selected for processing (7)
  • crates/agentflare-jobs/src/lib.rs
  • crates/agentflare-jobs/src/queue.rs
  • crates/agentflare-jobs/src/worker.rs
  • crates/agentflare-jobs/tests/in_process_test.rs
  • src/dashboard/orphan_reconcile.rs
  • src/dashboard/server.rs
  • src/supervisor.rs

Comment @coderabbitai help to get the list of available commands.

@getappz getappz changed the title Failed jobs (retries exhausted) leave items stuck labeled dispatched, never restored to ready-for-work — silently undispatchable forever fix: restore ready-for-work label when a dispatched job fails after exhausting retries Aug 13, 2026
@getappz
getappz enabled auto-merge (squash) August 13, 2026 08:01
@getappz
getappz merged commit 9e32c07 into master Aug 13, 2026
16 checks passed
@getappz
getappz deleted the task/463-failed-jobs-retries-exhausted-leave-item branch August 13, 2026 08:09
getappz added a commit that referenced this pull request Aug 16, 2026
…d judge replies (#516)

The SDD-loop judge parser found the first '{' and last '}' in the
whole reply and parsed the slice between them. Reproduced live
(item #478, 2026-08-15): trailing commentary containing its own
unrelated braces, or a JSON object missing a required field,
either corrupted the extracted span or hard-failed the step.

Prefer an explicit fenced code block (```json ... ```) when
present, and otherwise scan forward from the first '{' for its own
matching '}' (tracking nesting depth and skipping brace-like bytes
inside string literals) instead of blindly spanning to the last
'}' anywhere in the reply. A genuine parse failure -- including
syntactically valid JSON missing a field -- still returns Err,
retried by the step's own RetryPolicy as before.

Agentflare-Agent: claude-code_2-1-233_agent
Agentflare-Branch: fix/harden-judge-decision-parser
getappz added a commit that referenced this pull request Aug 18, 2026
…wnstream (#546)

real_agent_send_hook fed every role's raw --output-format stream-json
transcript (one JSON object per line: system init, tool_use, ..., final
result) straight into role_reply, since #498 deleted the old coder step's
transcript parsing without giving sdd_loop's shared hook an equivalent.
For the judge specifically, parse_judge_decision then parsed the
transcript's first line -- a valid-but-action-less system/init event --
instead of the judge's actual decision on the last line, hard-failing
every judge turn with "missing field `action`" (items #478/#502/#503).

Restore transcript parsing (parse_claude_reply, agent_launch.rs) and
apply it to every Claude Code role's reply via clean_agent_reply, not
just the judge's, since role_reply also gets embedded verbatim into
build_judge_prompt.

Agentflare-Agent: claude-code
Agentflare-Branch: task/489-sdd-loop-judge-reply-deterministically-m
Agentflare-Item: 489
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant