feat(dev-lead): retry failed initial issue implementations, never silent (#781) - #810
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Review limit reached
More reviews will be available in 52 minutes and 47 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the 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 credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. 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, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughImplements a bounded retry path for failed initial dev-lead issue implementations. ChangesIssue Retry End-to-End Flow
Sequence Diagram(s)sequenceDiagram
participant Engine as engine.sh (run_writer_with_fallback)
participant Sidecar as /tmp/dev-lead-failure-reason
participant FixIssue as dev-lead-fix-issue.sh (handle_engine_failure)
participant GitHub as GitHub Issue API
rect rgba(220, 80, 80, 0.5)
note over Engine,Sidecar: First attempt — engine fails
Engine->>Sidecar: write "engine-error"
Engine-->>FixIssue: return rc=1
end
FixIssue->>Sidecar: read reason
FixIssue->>GitHub: fetch prior attempt markers (count_prior_attempts)
alt attempt < MAX_ATTEMPTS and reason != missing-binary
FixIssue->>GitHub: post retry marker comment (status=failed, attempt=N, reason=engine-error)
FixIssue-->>FixIssue: exit 1
else missing-binary OR attempt >= MAX_ATTEMPTS
FixIssue->>GitHub: apply dev-lead:needs-human label
FixIssue->>GitHub: post needs-human marker comment
FixIssue-->>FixIssue: exit 1
end
sequenceDiagram
participant Cron as dev-lead-retry.sh (cron)
participant GitHub as GitHub API
participant Intent as dev-lead-intent.sh
participant FixIssue as dev-lead-fix-issue.sh
Cron->>GitHub: list open issues with dev-lead label
loop each issue
Cron->>GitHub: fetch issue comments (newest dev-lead-issue marker)
Cron->>GitHub: check open dev-lead/issue-N PR
alt retryable marker and no open PR and attempt < MAX_ATTEMPTS
Cron->>GitHub: POST repository_dispatch dev-lead-issue-retry (issue_number, attempt)
end
end
GitHub->>Intent: dev-lead-issue-retry event received
Intent->>Intent: validate issue_number, check hands-off label
Intent-->>FixIssue: emit intent=issue, reason=issue-retry-dispatch
FixIssue->>FixIssue: run engine, handle_engine_failure on failure
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
|
Advisory bots were rate-limited; auto-approval is withheld until they recover. pr-review-sweep will re-review this PR after 2026-06-19T20:42:43Z. |
Dev-Lead — fix-bot-comment (no-changes)Agent reasoning |
There was a problem hiding this comment.
Code Review
This pull request implements a bounded auto-retry mechanism for failed initial issue implementations, introducing unified engine-failure handling, sidecar-based failure classification, and automated re-dispatching via cron scans. The feedback highlights a critical, recurring issue in both dev-lead-fix-issue.sh and dev-lead-retry.sh where gh api --paginate is used; because paginated API responses return multiple sequential JSON arrays, processing them with jq without the -s (slurp) flag leads to incorrect maximum attempt calculations, broken 'newest marker' logic, and bash syntax errors due to multi-line outputs. Applying the suggested jq -s workarounds will ensure robust handling of paginated API data.
Phase 1) A dev-lead initial issue implementation that failed at the engine step (for any non-rate-limit reason) emitted only a generic "Engine failed to implement issue case: petry-projects/.github#478, a 600s deep-tier timeout kill surfaced only as exit 1). Phase 1 makes the failure never-silent and cause-aware (no caller-interface or workflow change): engine.sh: - run_writer_with_fallback writes a one-line cause class to /tmp/dev-lead-failure-reason (rate-limited | missing-binary | engine-error) before each terminal failure return, mirroring the existing /tmp/dev-lead-rate-limit-reset sidecar. Purely additive — no control-flow change. - run_writer's redact + persist + GITHUB_STEP_SUMMARY block now runs before the rate-limit early-return, so session output (where the real cause appears) is captured for ALL failure classes, not just generic ones. dev-lead-fix-issue.sh: - Replace the silent exit 1 and unify the rate-limit branch with a single handle_engine_failure: reads the cause + reset, computes attempt from prior <!-- dev-lead-issue N ... --> markers, builds a redacted 40-line session snippet + run deep-link, and applies a decision matrix: missing-binary → dev-lead:needs-human label + comment (no retry) rate-limited/engine-error & attempt<MAX → retryable marker + comment attempt>=MAX → dev-lead:needs-human label + "exhausted" comment Exit codes unchanged (2 rate-limit, 1 otherwise). The retryable marker is what Phase 2's retry cron will scan for. Tests: extend test_fix_issue.bats (engine-error marker+snippet+run link, missing-binary→needs-human, attempt ceiling→needs-human) and test_engine_fallback.bats (failure-reason sidecar per class, stale-reason clear, session-output persisted on the rate-limit path). Refs #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… Phase 2) Phase 1 made failed issue implementations cause-aware and left a retryable marker. Phase 2 closes the loop: the retry cron now requeues them. dev-lead-retry.sh: - New scan_repo_issues + scan_issue_for_retry + dispatch_issue_retry. Enumerates open dev-lead-labelled issues (filtering out PRs and dev-lead:needs-human), reads the newest <!-- dev-lead-issue N ... --> marker, and re-dispatches a dev-lead-issue-retry when retryable: honours the rate-limit reset= window, enforces attempt < MAX_ATTEMPTS (3), and skips issues that already have an open dev-lead PR. Called from scan_repo unconditionally (also when a repo has no open PRs — the common case for a stalled issue). main() now guarded behind a BASH_SOURCE check so the functions are unit-testable. dev-lead-intent.sh: - Restructure the repository_dispatch branch so issue-only payloads are no longer dropped by the hard pr_number requirement. Hands-off label lookup keys off a subject_number (pr_number or issue_number). New dev-lead-issue-retry type reads issue_number and routes to the existing `issue` intent (full-fidelity re-run); PR-based types keep their pr_number guard. Workflows: - dev-lead.yml (thin caller): add dev-lead-issue-retry to repository_dispatch .types (established pattern; allowed per AGENTS.md). - dev-lead-reusable.yml: add a client_payload.issue_number -> dev-lead-issue-<n> lane to the concurrency router so issue retries serialise on the issue lane. Tests/docs: - New tests/dev-lead/unit/test_dev_lead_retry.bats (decision matrix + payload). - test_intent_ci.bats: issue-retry routing, missing issue_number, hands-off. - New fixture repository_dispatch_issue_retry.json. - e2e scenario 07 Part I: full retry-script wiring requeues a failed issue. - docs/dev-lead/spec.md: dispatch table, §7.5 failure matrix, §10.1a issue-retry. Closes #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
d0b71ce to
ef55e5e
Compare
Dev-Lead — review-changes (applied)Changes committed and pushed. |
Dev-Lead — review-changes (applied)Changes committed and pushed. |
Dev-Lead — review-changes (applied)Changes committed and pushed. |
Dev-Lead — review-changes (applied)Changes committed and pushed. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/dev-lead/spec.md`:
- Around line 632-635: The document inconsistently uses both British English
("labelled") and American English ("labeled") variants for the same word.
Standardize the spelling throughout the document by replacing all instances of
"labelled" with "labeled" to maintain consistency, particularly in the section
describing the dev-lead-retry cron's scan_repo_issues function where
"dev-lead-labelled issues" should be changed to "dev-lead-labeled issues" to
match the American English variant used elsewhere in the specification.
In `@scripts/dev-lead-retry.sh`:
- Around line 316-326: The open_issue_pr_exists function only fetches the first
100 open PRs due to the per_page=100 parameter in the gh api call, which means
matching dev-lead/issue-<N>-* branches could be missed in repositories with more
than 100 open PRs. Add the --paginate flag to the gh api command to iterate
through all pages of results, ensuring all open PRs are checked regardless of
the total count.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 97dd1878-82e2-49eb-8d01-ae8f7a04cf30
📒 Files selected for processing (14)
.github/workflows/dev-lead-reusable.yml.github/workflows/dev-lead.yml.gitleaks.tomldocs/dev-lead/spec.mdscripts/dev-lead-fix-issue.shscripts/dev-lead-intent.shscripts/dev-lead-retry.shscripts/engine.shtests/dev-lead/e2e/scenarios/07-rate-limit-retry.shtests/dev-lead/fixtures/events/repository_dispatch_issue_retry.jsontests/dev-lead/unit/test_dev_lead_retry.batstests/dev-lead/unit/test_engine_fallback.batstests/dev-lead/unit/test_fix_issue.batstests/dev-lead/unit/test_intent_ci.bats
Dev-Lead — waiting on PR blockers (intent: review-changes)PR: #810 |
|
Note @don-petry I reviewed this PR and no code changes were needed, but it still has blocking checks or reviews (failing or cancelled checks, or changes-requested reviews), so I cannot mark it done yet. I'll re-check automatically. |
|
Dev-Lead — fix-bot-comment (no-changes)Agent reasoning |
…ent (#781) (#810) * feat(dev-lead): surface engine failure cause on failed issue impls (#781 Phase 1) A dev-lead initial issue implementation that failed at the engine step (for any non-rate-limit reason) emitted only a generic "Engine failed to implement issue case: petry-projects/.github#478, a 600s deep-tier timeout kill surfaced only as exit 1). Phase 1 makes the failure never-silent and cause-aware (no caller-interface or workflow change): engine.sh: - run_writer_with_fallback writes a one-line cause class to /tmp/dev-lead-failure-reason (rate-limited | missing-binary | engine-error) before each terminal failure return, mirroring the existing /tmp/dev-lead-rate-limit-reset sidecar. Purely additive — no control-flow change. - run_writer's redact + persist + GITHUB_STEP_SUMMARY block now runs before the rate-limit early-return, so session output (where the real cause appears) is captured for ALL failure classes, not just generic ones. dev-lead-fix-issue.sh: - Replace the silent exit 1 and unify the rate-limit branch with a single handle_engine_failure: reads the cause + reset, computes attempt from prior <!-- dev-lead-issue N ... --> markers, builds a redacted 40-line session snippet + run deep-link, and applies a decision matrix: missing-binary → dev-lead:needs-human label + comment (no retry) rate-limited/engine-error & attempt<MAX → retryable marker + comment attempt>=MAX → dev-lead:needs-human label + "exhausted" comment Exit codes unchanged (2 rate-limit, 1 otherwise). The retryable marker is what Phase 2's retry cron will scan for. Tests: extend test_fix_issue.bats (engine-error marker+snippet+run link, missing-binary→needs-human, attempt ceiling→needs-human) and test_engine_fallback.bats (failure-reason sidecar per class, stale-reason clear, session-output persisted on the rate-limit path). Refs #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dev-lead): bounded auto-retry for failed initial issue impls (#781 Phase 2) Phase 1 made failed issue implementations cause-aware and left a retryable marker. Phase 2 closes the loop: the retry cron now requeues them. dev-lead-retry.sh: - New scan_repo_issues + scan_issue_for_retry + dispatch_issue_retry. Enumerates open dev-lead-labelled issues (filtering out PRs and dev-lead:needs-human), reads the newest <!-- dev-lead-issue N ... --> marker, and re-dispatches a dev-lead-issue-retry when retryable: honours the rate-limit reset= window, enforces attempt < MAX_ATTEMPTS (3), and skips issues that already have an open dev-lead PR. Called from scan_repo unconditionally (also when a repo has no open PRs — the common case for a stalled issue). main() now guarded behind a BASH_SOURCE check so the functions are unit-testable. dev-lead-intent.sh: - Restructure the repository_dispatch branch so issue-only payloads are no longer dropped by the hard pr_number requirement. Hands-off label lookup keys off a subject_number (pr_number or issue_number). New dev-lead-issue-retry type reads issue_number and routes to the existing `issue` intent (full-fidelity re-run); PR-based types keep their pr_number guard. Workflows: - dev-lead.yml (thin caller): add dev-lead-issue-retry to repository_dispatch .types (established pattern; allowed per AGENTS.md). - dev-lead-reusable.yml: add a client_payload.issue_number -> dev-lead-issue-<n> lane to the concurrency router so issue retries serialise on the issue lane. Tests/docs: - New tests/dev-lead/unit/test_dev_lead_retry.bats (decision matrix + payload). - test_intent_ci.bats: issue-retry routing, missing issue_number, hands-off. - New fixture repository_dispatch_issue_retry.json. - e2e scenario 07 Part I: full retry-script wiring requeues a failed issue. - docs/dev-lead/spec.md: dispatch table, §7.5 failure matrix, §10.1a issue-retry. Closes #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * fix(bot): address bot feedback [skip ci-relay] * chore: apply manual instructions [skip ci-relay] --------- Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…ent (#781) (#810) * feat(dev-lead): surface engine failure cause on failed issue impls (#781 Phase 1) A dev-lead initial issue implementation that failed at the engine step (for any non-rate-limit reason) emitted only a generic "Engine failed to implement issue case: petry-projects/.github#478, a 600s deep-tier timeout kill surfaced only as exit 1). Phase 1 makes the failure never-silent and cause-aware (no caller-interface or workflow change): engine.sh: - run_writer_with_fallback writes a one-line cause class to /tmp/dev-lead-failure-reason (rate-limited | missing-binary | engine-error) before each terminal failure return, mirroring the existing /tmp/dev-lead-rate-limit-reset sidecar. Purely additive — no control-flow change. - run_writer's redact + persist + GITHUB_STEP_SUMMARY block now runs before the rate-limit early-return, so session output (where the real cause appears) is captured for ALL failure classes, not just generic ones. dev-lead-fix-issue.sh: - Replace the silent exit 1 and unify the rate-limit branch with a single handle_engine_failure: reads the cause + reset, computes attempt from prior <!-- dev-lead-issue N ... --> markers, builds a redacted 40-line session snippet + run deep-link, and applies a decision matrix: missing-binary → dev-lead:needs-human label + comment (no retry) rate-limited/engine-error & attempt<MAX → retryable marker + comment attempt>=MAX → dev-lead:needs-human label + "exhausted" comment Exit codes unchanged (2 rate-limit, 1 otherwise). The retryable marker is what Phase 2's retry cron will scan for. Tests: extend test_fix_issue.bats (engine-error marker+snippet+run link, missing-binary→needs-human, attempt ceiling→needs-human) and test_engine_fallback.bats (failure-reason sidecar per class, stale-reason clear, session-output persisted on the rate-limit path). Refs #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dev-lead): bounded auto-retry for failed initial issue impls (#781 Phase 2) Phase 1 made failed issue implementations cause-aware and left a retryable marker. Phase 2 closes the loop: the retry cron now requeues them. dev-lead-retry.sh: - New scan_repo_issues + scan_issue_for_retry + dispatch_issue_retry. Enumerates open dev-lead-labelled issues (filtering out PRs and dev-lead:needs-human), reads the newest <!-- dev-lead-issue N ... --> marker, and re-dispatches a dev-lead-issue-retry when retryable: honours the rate-limit reset= window, enforces attempt < MAX_ATTEMPTS (3), and skips issues that already have an open dev-lead PR. Called from scan_repo unconditionally (also when a repo has no open PRs — the common case for a stalled issue). main() now guarded behind a BASH_SOURCE check so the functions are unit-testable. dev-lead-intent.sh: - Restructure the repository_dispatch branch so issue-only payloads are no longer dropped by the hard pr_number requirement. Hands-off label lookup keys off a subject_number (pr_number or issue_number). New dev-lead-issue-retry type reads issue_number and routes to the existing `issue` intent (full-fidelity re-run); PR-based types keep their pr_number guard. Workflows: - dev-lead.yml (thin caller): add dev-lead-issue-retry to repository_dispatch .types (established pattern; allowed per AGENTS.md). - dev-lead-reusable.yml: add a client_payload.issue_number -> dev-lead-issue-<n> lane to the concurrency router so issue retries serialise on the issue lane. Tests/docs: - New tests/dev-lead/unit/test_dev_lead_retry.bats (decision matrix + payload). - test_intent_ci.bats: issue-retry routing, missing issue_number, hands-off. - New fixture repository_dispatch_issue_retry.json. - e2e scenario 07 Part I: full retry-script wiring requeues a failed issue. - docs/dev-lead/spec.md: dispatch table, §7.5 failure matrix, §10.1a issue-retry. Closes #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * fix(bot): address bot feedback [skip ci-relay] * chore: apply manual instructions [skip ci-relay] --------- Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…ent (#781) (#810) * feat(dev-lead): surface engine failure cause on failed issue impls (#781 Phase 1) A dev-lead initial issue implementation that failed at the engine step (for any non-rate-limit reason) emitted only a generic "Engine failed to implement issue case: petry-projects/.github#478, a 600s deep-tier timeout kill surfaced only as exit 1). Phase 1 makes the failure never-silent and cause-aware (no caller-interface or workflow change): engine.sh: - run_writer_with_fallback writes a one-line cause class to /tmp/dev-lead-failure-reason (rate-limited | missing-binary | engine-error) before each terminal failure return, mirroring the existing /tmp/dev-lead-rate-limit-reset sidecar. Purely additive — no control-flow change. - run_writer's redact + persist + GITHUB_STEP_SUMMARY block now runs before the rate-limit early-return, so session output (where the real cause appears) is captured for ALL failure classes, not just generic ones. dev-lead-fix-issue.sh: - Replace the silent exit 1 and unify the rate-limit branch with a single handle_engine_failure: reads the cause + reset, computes attempt from prior <!-- dev-lead-issue N ... --> markers, builds a redacted 40-line session snippet + run deep-link, and applies a decision matrix: missing-binary → dev-lead:needs-human label + comment (no retry) rate-limited/engine-error & attempt<MAX → retryable marker + comment attempt>=MAX → dev-lead:needs-human label + "exhausted" comment Exit codes unchanged (2 rate-limit, 1 otherwise). The retryable marker is what Phase 2's retry cron will scan for. Tests: extend test_fix_issue.bats (engine-error marker+snippet+run link, missing-binary→needs-human, attempt ceiling→needs-human) and test_engine_fallback.bats (failure-reason sidecar per class, stale-reason clear, session-output persisted on the rate-limit path). Refs #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dev-lead): bounded auto-retry for failed initial issue impls (#781 Phase 2) Phase 1 made failed issue implementations cause-aware and left a retryable marker. Phase 2 closes the loop: the retry cron now requeues them. dev-lead-retry.sh: - New scan_repo_issues + scan_issue_for_retry + dispatch_issue_retry. Enumerates open dev-lead-labelled issues (filtering out PRs and dev-lead:needs-human), reads the newest <!-- dev-lead-issue N ... --> marker, and re-dispatches a dev-lead-issue-retry when retryable: honours the rate-limit reset= window, enforces attempt < MAX_ATTEMPTS (3), and skips issues that already have an open dev-lead PR. Called from scan_repo unconditionally (also when a repo has no open PRs — the common case for a stalled issue). main() now guarded behind a BASH_SOURCE check so the functions are unit-testable. dev-lead-intent.sh: - Restructure the repository_dispatch branch so issue-only payloads are no longer dropped by the hard pr_number requirement. Hands-off label lookup keys off a subject_number (pr_number or issue_number). New dev-lead-issue-retry type reads issue_number and routes to the existing `issue` intent (full-fidelity re-run); PR-based types keep their pr_number guard. Workflows: - dev-lead.yml (thin caller): add dev-lead-issue-retry to repository_dispatch .types (established pattern; allowed per AGENTS.md). - dev-lead-reusable.yml: add a client_payload.issue_number -> dev-lead-issue-<n> lane to the concurrency router so issue retries serialise on the issue lane. Tests/docs: - New tests/dev-lead/unit/test_dev_lead_retry.bats (decision matrix + payload). - test_intent_ci.bats: issue-retry routing, missing issue_number, hands-off. - New fixture repository_dispatch_issue_retry.json. - e2e scenario 07 Part I: full retry-script wiring requeues a failed issue. - docs/dev-lead/spec.md: dispatch table, §7.5 failure matrix, §10.1a issue-retry. Closes #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * fix(bot): address bot feedback [skip ci-relay] * chore: apply manual instructions [skip ci-relay] --------- Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…ent (#781) (#810) * feat(dev-lead): surface engine failure cause on failed issue impls (#781 Phase 1) A dev-lead initial issue implementation that failed at the engine step (for any non-rate-limit reason) emitted only a generic "Engine failed to implement issue case: petry-projects/.github#478, a 600s deep-tier timeout kill surfaced only as exit 1). Phase 1 makes the failure never-silent and cause-aware (no caller-interface or workflow change): engine.sh: - run_writer_with_fallback writes a one-line cause class to /tmp/dev-lead-failure-reason (rate-limited | missing-binary | engine-error) before each terminal failure return, mirroring the existing /tmp/dev-lead-rate-limit-reset sidecar. Purely additive — no control-flow change. - run_writer's redact + persist + GITHUB_STEP_SUMMARY block now runs before the rate-limit early-return, so session output (where the real cause appears) is captured for ALL failure classes, not just generic ones. dev-lead-fix-issue.sh: - Replace the silent exit 1 and unify the rate-limit branch with a single handle_engine_failure: reads the cause + reset, computes attempt from prior <!-- dev-lead-issue N ... --> markers, builds a redacted 40-line session snippet + run deep-link, and applies a decision matrix: missing-binary → dev-lead:needs-human label + comment (no retry) rate-limited/engine-error & attempt<MAX → retryable marker + comment attempt>=MAX → dev-lead:needs-human label + "exhausted" comment Exit codes unchanged (2 rate-limit, 1 otherwise). The retryable marker is what Phase 2's retry cron will scan for. Tests: extend test_fix_issue.bats (engine-error marker+snippet+run link, missing-binary→needs-human, attempt ceiling→needs-human) and test_engine_fallback.bats (failure-reason sidecar per class, stale-reason clear, session-output persisted on the rate-limit path). Refs #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dev-lead): bounded auto-retry for failed initial issue impls (#781 Phase 2) Phase 1 made failed issue implementations cause-aware and left a retryable marker. Phase 2 closes the loop: the retry cron now requeues them. dev-lead-retry.sh: - New scan_repo_issues + scan_issue_for_retry + dispatch_issue_retry. Enumerates open dev-lead-labelled issues (filtering out PRs and dev-lead:needs-human), reads the newest <!-- dev-lead-issue N ... --> marker, and re-dispatches a dev-lead-issue-retry when retryable: honours the rate-limit reset= window, enforces attempt < MAX_ATTEMPTS (3), and skips issues that already have an open dev-lead PR. Called from scan_repo unconditionally (also when a repo has no open PRs — the common case for a stalled issue). main() now guarded behind a BASH_SOURCE check so the functions are unit-testable. dev-lead-intent.sh: - Restructure the repository_dispatch branch so issue-only payloads are no longer dropped by the hard pr_number requirement. Hands-off label lookup keys off a subject_number (pr_number or issue_number). New dev-lead-issue-retry type reads issue_number and routes to the existing `issue` intent (full-fidelity re-run); PR-based types keep their pr_number guard. Workflows: - dev-lead.yml (thin caller): add dev-lead-issue-retry to repository_dispatch .types (established pattern; allowed per AGENTS.md). - dev-lead-reusable.yml: add a client_payload.issue_number -> dev-lead-issue-<n> lane to the concurrency router so issue retries serialise on the issue lane. Tests/docs: - New tests/dev-lead/unit/test_dev_lead_retry.bats (decision matrix + payload). - test_intent_ci.bats: issue-retry routing, missing issue_number, hands-off. - New fixture repository_dispatch_issue_retry.json. - e2e scenario 07 Part I: full retry-script wiring requeues a failed issue. - docs/dev-lead/spec.md: dispatch table, §7.5 failure matrix, §10.1a issue-retry. Closes #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * fix(bot): address bot feedback [skip ci-relay] * chore: apply manual instructions [skip ci-relay] --------- Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…ent (#781) (#810) * feat(dev-lead): surface engine failure cause on failed issue impls (#781 Phase 1) A dev-lead initial issue implementation that failed at the engine step (for any non-rate-limit reason) emitted only a generic "Engine failed to implement issue case: petry-projects/.github#478, a 600s deep-tier timeout kill surfaced only as exit 1). Phase 1 makes the failure never-silent and cause-aware (no caller-interface or workflow change): engine.sh: - run_writer_with_fallback writes a one-line cause class to /tmp/dev-lead-failure-reason (rate-limited | missing-binary | engine-error) before each terminal failure return, mirroring the existing /tmp/dev-lead-rate-limit-reset sidecar. Purely additive — no control-flow change. - run_writer's redact + persist + GITHUB_STEP_SUMMARY block now runs before the rate-limit early-return, so session output (where the real cause appears) is captured for ALL failure classes, not just generic ones. dev-lead-fix-issue.sh: - Replace the silent exit 1 and unify the rate-limit branch with a single handle_engine_failure: reads the cause + reset, computes attempt from prior <!-- dev-lead-issue N ... --> markers, builds a redacted 40-line session snippet + run deep-link, and applies a decision matrix: missing-binary → dev-lead:needs-human label + comment (no retry) rate-limited/engine-error & attempt<MAX → retryable marker + comment attempt>=MAX → dev-lead:needs-human label + "exhausted" comment Exit codes unchanged (2 rate-limit, 1 otherwise). The retryable marker is what Phase 2's retry cron will scan for. Tests: extend test_fix_issue.bats (engine-error marker+snippet+run link, missing-binary→needs-human, attempt ceiling→needs-human) and test_engine_fallback.bats (failure-reason sidecar per class, stale-reason clear, session-output persisted on the rate-limit path). Refs #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dev-lead): bounded auto-retry for failed initial issue impls (#781 Phase 2) Phase 1 made failed issue implementations cause-aware and left a retryable marker. Phase 2 closes the loop: the retry cron now requeues them. dev-lead-retry.sh: - New scan_repo_issues + scan_issue_for_retry + dispatch_issue_retry. Enumerates open dev-lead-labelled issues (filtering out PRs and dev-lead:needs-human), reads the newest <!-- dev-lead-issue N ... --> marker, and re-dispatches a dev-lead-issue-retry when retryable: honours the rate-limit reset= window, enforces attempt < MAX_ATTEMPTS (3), and skips issues that already have an open dev-lead PR. Called from scan_repo unconditionally (also when a repo has no open PRs — the common case for a stalled issue). main() now guarded behind a BASH_SOURCE check so the functions are unit-testable. dev-lead-intent.sh: - Restructure the repository_dispatch branch so issue-only payloads are no longer dropped by the hard pr_number requirement. Hands-off label lookup keys off a subject_number (pr_number or issue_number). New dev-lead-issue-retry type reads issue_number and routes to the existing `issue` intent (full-fidelity re-run); PR-based types keep their pr_number guard. Workflows: - dev-lead.yml (thin caller): add dev-lead-issue-retry to repository_dispatch .types (established pattern; allowed per AGENTS.md). - dev-lead-reusable.yml: add a client_payload.issue_number -> dev-lead-issue-<n> lane to the concurrency router so issue retries serialise on the issue lane. Tests/docs: - New tests/dev-lead/unit/test_dev_lead_retry.bats (decision matrix + payload). - test_intent_ci.bats: issue-retry routing, missing issue_number, hands-off. - New fixture repository_dispatch_issue_retry.json. - e2e scenario 07 Part I: full retry-script wiring requeues a failed issue. - docs/dev-lead/spec.md: dispatch table, §7.5 failure matrix, §10.1a issue-retry. Closes #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * fix(bot): address bot feedback [skip ci-relay] * chore: apply manual instructions [skip ci-relay] --------- Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…ent (#781) (#810) * feat(dev-lead): surface engine failure cause on failed issue impls (#781 Phase 1) A dev-lead initial issue implementation that failed at the engine step (for any non-rate-limit reason) emitted only a generic "Engine failed to implement issue case: petry-projects/.github#478, a 600s deep-tier timeout kill surfaced only as exit 1). Phase 1 makes the failure never-silent and cause-aware (no caller-interface or workflow change): engine.sh: - run_writer_with_fallback writes a one-line cause class to /tmp/dev-lead-failure-reason (rate-limited | missing-binary | engine-error) before each terminal failure return, mirroring the existing /tmp/dev-lead-rate-limit-reset sidecar. Purely additive — no control-flow change. - run_writer's redact + persist + GITHUB_STEP_SUMMARY block now runs before the rate-limit early-return, so session output (where the real cause appears) is captured for ALL failure classes, not just generic ones. dev-lead-fix-issue.sh: - Replace the silent exit 1 and unify the rate-limit branch with a single handle_engine_failure: reads the cause + reset, computes attempt from prior <!-- dev-lead-issue N ... --> markers, builds a redacted 40-line session snippet + run deep-link, and applies a decision matrix: missing-binary → dev-lead:needs-human label + comment (no retry) rate-limited/engine-error & attempt<MAX → retryable marker + comment attempt>=MAX → dev-lead:needs-human label + "exhausted" comment Exit codes unchanged (2 rate-limit, 1 otherwise). The retryable marker is what Phase 2's retry cron will scan for. Tests: extend test_fix_issue.bats (engine-error marker+snippet+run link, missing-binary→needs-human, attempt ceiling→needs-human) and test_engine_fallback.bats (failure-reason sidecar per class, stale-reason clear, session-output persisted on the rate-limit path). Refs #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dev-lead): bounded auto-retry for failed initial issue impls (#781 Phase 2) Phase 1 made failed issue implementations cause-aware and left a retryable marker. Phase 2 closes the loop: the retry cron now requeues them. dev-lead-retry.sh: - New scan_repo_issues + scan_issue_for_retry + dispatch_issue_retry. Enumerates open dev-lead-labelled issues (filtering out PRs and dev-lead:needs-human), reads the newest <!-- dev-lead-issue N ... --> marker, and re-dispatches a dev-lead-issue-retry when retryable: honours the rate-limit reset= window, enforces attempt < MAX_ATTEMPTS (3), and skips issues that already have an open dev-lead PR. Called from scan_repo unconditionally (also when a repo has no open PRs — the common case for a stalled issue). main() now guarded behind a BASH_SOURCE check so the functions are unit-testable. dev-lead-intent.sh: - Restructure the repository_dispatch branch so issue-only payloads are no longer dropped by the hard pr_number requirement. Hands-off label lookup keys off a subject_number (pr_number or issue_number). New dev-lead-issue-retry type reads issue_number and routes to the existing `issue` intent (full-fidelity re-run); PR-based types keep their pr_number guard. Workflows: - dev-lead.yml (thin caller): add dev-lead-issue-retry to repository_dispatch .types (established pattern; allowed per AGENTS.md). - dev-lead-reusable.yml: add a client_payload.issue_number -> dev-lead-issue-<n> lane to the concurrency router so issue retries serialise on the issue lane. Tests/docs: - New tests/dev-lead/unit/test_dev_lead_retry.bats (decision matrix + payload). - test_intent_ci.bats: issue-retry routing, missing issue_number, hands-off. - New fixture repository_dispatch_issue_retry.json. - e2e scenario 07 Part I: full retry-script wiring requeues a failed issue. - docs/dev-lead/spec.md: dispatch table, §7.5 failure matrix, §10.1a issue-retry. Closes #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * fix(bot): address bot feedback [skip ci-relay] * chore: apply manual instructions [skip ci-relay] --------- Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…ent (#781) (#810) * feat(dev-lead): surface engine failure cause on failed issue impls (#781 Phase 1) A dev-lead initial issue implementation that failed at the engine step (for any non-rate-limit reason) emitted only a generic "Engine failed to implement issue case: petry-projects/.github#478, a 600s deep-tier timeout kill surfaced only as exit 1). Phase 1 makes the failure never-silent and cause-aware (no caller-interface or workflow change): engine.sh: - run_writer_with_fallback writes a one-line cause class to /tmp/dev-lead-failure-reason (rate-limited | missing-binary | engine-error) before each terminal failure return, mirroring the existing /tmp/dev-lead-rate-limit-reset sidecar. Purely additive — no control-flow change. - run_writer's redact + persist + GITHUB_STEP_SUMMARY block now runs before the rate-limit early-return, so session output (where the real cause appears) is captured for ALL failure classes, not just generic ones. dev-lead-fix-issue.sh: - Replace the silent exit 1 and unify the rate-limit branch with a single handle_engine_failure: reads the cause + reset, computes attempt from prior <!-- dev-lead-issue N ... --> markers, builds a redacted 40-line session snippet + run deep-link, and applies a decision matrix: missing-binary → dev-lead:needs-human label + comment (no retry) rate-limited/engine-error & attempt<MAX → retryable marker + comment attempt>=MAX → dev-lead:needs-human label + "exhausted" comment Exit codes unchanged (2 rate-limit, 1 otherwise). The retryable marker is what Phase 2's retry cron will scan for. Tests: extend test_fix_issue.bats (engine-error marker+snippet+run link, missing-binary→needs-human, attempt ceiling→needs-human) and test_engine_fallback.bats (failure-reason sidecar per class, stale-reason clear, session-output persisted on the rate-limit path). Refs #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dev-lead): bounded auto-retry for failed initial issue impls (#781 Phase 2) Phase 1 made failed issue implementations cause-aware and left a retryable marker. Phase 2 closes the loop: the retry cron now requeues them. dev-lead-retry.sh: - New scan_repo_issues + scan_issue_for_retry + dispatch_issue_retry. Enumerates open dev-lead-labelled issues (filtering out PRs and dev-lead:needs-human), reads the newest <!-- dev-lead-issue N ... --> marker, and re-dispatches a dev-lead-issue-retry when retryable: honours the rate-limit reset= window, enforces attempt < MAX_ATTEMPTS (3), and skips issues that already have an open dev-lead PR. Called from scan_repo unconditionally (also when a repo has no open PRs — the common case for a stalled issue). main() now guarded behind a BASH_SOURCE check so the functions are unit-testable. dev-lead-intent.sh: - Restructure the repository_dispatch branch so issue-only payloads are no longer dropped by the hard pr_number requirement. Hands-off label lookup keys off a subject_number (pr_number or issue_number). New dev-lead-issue-retry type reads issue_number and routes to the existing `issue` intent (full-fidelity re-run); PR-based types keep their pr_number guard. Workflows: - dev-lead.yml (thin caller): add dev-lead-issue-retry to repository_dispatch .types (established pattern; allowed per AGENTS.md). - dev-lead-reusable.yml: add a client_payload.issue_number -> dev-lead-issue-<n> lane to the concurrency router so issue retries serialise on the issue lane. Tests/docs: - New tests/dev-lead/unit/test_dev_lead_retry.bats (decision matrix + payload). - test_intent_ci.bats: issue-retry routing, missing issue_number, hands-off. - New fixture repository_dispatch_issue_retry.json. - e2e scenario 07 Part I: full retry-script wiring requeues a failed issue. - docs/dev-lead/spec.md: dispatch table, §7.5 failure matrix, §10.1a issue-retry. Closes #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * fix(bot): address bot feedback [skip ci-relay] * chore: apply manual instructions [skip ci-relay] --------- Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…ent (#781) (#810) * feat(dev-lead): surface engine failure cause on failed issue impls (#781 Phase 1) A dev-lead initial issue implementation that failed at the engine step (for any non-rate-limit reason) emitted only a generic "Engine failed to implement issue case: petry-projects/.github#478, a 600s deep-tier timeout kill surfaced only as exit 1). Phase 1 makes the failure never-silent and cause-aware (no caller-interface or workflow change): engine.sh: - run_writer_with_fallback writes a one-line cause class to /tmp/dev-lead-failure-reason (rate-limited | missing-binary | engine-error) before each terminal failure return, mirroring the existing /tmp/dev-lead-rate-limit-reset sidecar. Purely additive — no control-flow change. - run_writer's redact + persist + GITHUB_STEP_SUMMARY block now runs before the rate-limit early-return, so session output (where the real cause appears) is captured for ALL failure classes, not just generic ones. dev-lead-fix-issue.sh: - Replace the silent exit 1 and unify the rate-limit branch with a single handle_engine_failure: reads the cause + reset, computes attempt from prior <!-- dev-lead-issue N ... --> markers, builds a redacted 40-line session snippet + run deep-link, and applies a decision matrix: missing-binary → dev-lead:needs-human label + comment (no retry) rate-limited/engine-error & attempt<MAX → retryable marker + comment attempt>=MAX → dev-lead:needs-human label + "exhausted" comment Exit codes unchanged (2 rate-limit, 1 otherwise). The retryable marker is what Phase 2's retry cron will scan for. Tests: extend test_fix_issue.bats (engine-error marker+snippet+run link, missing-binary→needs-human, attempt ceiling→needs-human) and test_engine_fallback.bats (failure-reason sidecar per class, stale-reason clear, session-output persisted on the rate-limit path). Refs #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dev-lead): bounded auto-retry for failed initial issue impls (#781 Phase 2) Phase 1 made failed issue implementations cause-aware and left a retryable marker. Phase 2 closes the loop: the retry cron now requeues them. dev-lead-retry.sh: - New scan_repo_issues + scan_issue_for_retry + dispatch_issue_retry. Enumerates open dev-lead-labelled issues (filtering out PRs and dev-lead:needs-human), reads the newest <!-- dev-lead-issue N ... --> marker, and re-dispatches a dev-lead-issue-retry when retryable: honours the rate-limit reset= window, enforces attempt < MAX_ATTEMPTS (3), and skips issues that already have an open dev-lead PR. Called from scan_repo unconditionally (also when a repo has no open PRs — the common case for a stalled issue). main() now guarded behind a BASH_SOURCE check so the functions are unit-testable. dev-lead-intent.sh: - Restructure the repository_dispatch branch so issue-only payloads are no longer dropped by the hard pr_number requirement. Hands-off label lookup keys off a subject_number (pr_number or issue_number). New dev-lead-issue-retry type reads issue_number and routes to the existing `issue` intent (full-fidelity re-run); PR-based types keep their pr_number guard. Workflows: - dev-lead.yml (thin caller): add dev-lead-issue-retry to repository_dispatch .types (established pattern; allowed per AGENTS.md). - dev-lead-reusable.yml: add a client_payload.issue_number -> dev-lead-issue-<n> lane to the concurrency router so issue retries serialise on the issue lane. Tests/docs: - New tests/dev-lead/unit/test_dev_lead_retry.bats (decision matrix + payload). - test_intent_ci.bats: issue-retry routing, missing issue_number, hands-off. - New fixture repository_dispatch_issue_retry.json. - e2e scenario 07 Part I: full retry-script wiring requeues a failed issue. - docs/dev-lead/spec.md: dispatch table, §7.5 failure matrix, §10.1a issue-retry. Closes #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * fix(bot): address bot feedback [skip ci-relay] * chore: apply manual instructions [skip ci-relay] --------- Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…ent (#781) (#810) * feat(dev-lead): surface engine failure cause on failed issue impls (#781 Phase 1) A dev-lead initial issue implementation that failed at the engine step (for any non-rate-limit reason) emitted only a generic "Engine failed to implement issue case: petry-projects/.github#478, a 600s deep-tier timeout kill surfaced only as exit 1). Phase 1 makes the failure never-silent and cause-aware (no caller-interface or workflow change): engine.sh: - run_writer_with_fallback writes a one-line cause class to /tmp/dev-lead-failure-reason (rate-limited | missing-binary | engine-error) before each terminal failure return, mirroring the existing /tmp/dev-lead-rate-limit-reset sidecar. Purely additive — no control-flow change. - run_writer's redact + persist + GITHUB_STEP_SUMMARY block now runs before the rate-limit early-return, so session output (where the real cause appears) is captured for ALL failure classes, not just generic ones. dev-lead-fix-issue.sh: - Replace the silent exit 1 and unify the rate-limit branch with a single handle_engine_failure: reads the cause + reset, computes attempt from prior <!-- dev-lead-issue N ... --> markers, builds a redacted 40-line session snippet + run deep-link, and applies a decision matrix: missing-binary → dev-lead:needs-human label + comment (no retry) rate-limited/engine-error & attempt<MAX → retryable marker + comment attempt>=MAX → dev-lead:needs-human label + "exhausted" comment Exit codes unchanged (2 rate-limit, 1 otherwise). The retryable marker is what Phase 2's retry cron will scan for. Tests: extend test_fix_issue.bats (engine-error marker+snippet+run link, missing-binary→needs-human, attempt ceiling→needs-human) and test_engine_fallback.bats (failure-reason sidecar per class, stale-reason clear, session-output persisted on the rate-limit path). Refs #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dev-lead): bounded auto-retry for failed initial issue impls (#781 Phase 2) Phase 1 made failed issue implementations cause-aware and left a retryable marker. Phase 2 closes the loop: the retry cron now requeues them. dev-lead-retry.sh: - New scan_repo_issues + scan_issue_for_retry + dispatch_issue_retry. Enumerates open dev-lead-labelled issues (filtering out PRs and dev-lead:needs-human), reads the newest <!-- dev-lead-issue N ... --> marker, and re-dispatches a dev-lead-issue-retry when retryable: honours the rate-limit reset= window, enforces attempt < MAX_ATTEMPTS (3), and skips issues that already have an open dev-lead PR. Called from scan_repo unconditionally (also when a repo has no open PRs — the common case for a stalled issue). main() now guarded behind a BASH_SOURCE check so the functions are unit-testable. dev-lead-intent.sh: - Restructure the repository_dispatch branch so issue-only payloads are no longer dropped by the hard pr_number requirement. Hands-off label lookup keys off a subject_number (pr_number or issue_number). New dev-lead-issue-retry type reads issue_number and routes to the existing `issue` intent (full-fidelity re-run); PR-based types keep their pr_number guard. Workflows: - dev-lead.yml (thin caller): add dev-lead-issue-retry to repository_dispatch .types (established pattern; allowed per AGENTS.md). - dev-lead-reusable.yml: add a client_payload.issue_number -> dev-lead-issue-<n> lane to the concurrency router so issue retries serialise on the issue lane. Tests/docs: - New tests/dev-lead/unit/test_dev_lead_retry.bats (decision matrix + payload). - test_intent_ci.bats: issue-retry routing, missing issue_number, hands-off. - New fixture repository_dispatch_issue_retry.json. - e2e scenario 07 Part I: full retry-script wiring requeues a failed issue. - docs/dev-lead/spec.md: dispatch table, §7.5 failure matrix, §10.1a issue-retry. Closes #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * fix(bot): address bot feedback [skip ci-relay] * chore: apply manual instructions [skip ci-relay] --------- Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…ent (#781) (#810) * feat(dev-lead): surface engine failure cause on failed issue impls (#781 Phase 1) A dev-lead initial issue implementation that failed at the engine step (for any non-rate-limit reason) emitted only a generic "Engine failed to implement issue case: petry-projects/.github#478, a 600s deep-tier timeout kill surfaced only as exit 1). Phase 1 makes the failure never-silent and cause-aware (no caller-interface or workflow change): engine.sh: - run_writer_with_fallback writes a one-line cause class to /tmp/dev-lead-failure-reason (rate-limited | missing-binary | engine-error) before each terminal failure return, mirroring the existing /tmp/dev-lead-rate-limit-reset sidecar. Purely additive — no control-flow change. - run_writer's redact + persist + GITHUB_STEP_SUMMARY block now runs before the rate-limit early-return, so session output (where the real cause appears) is captured for ALL failure classes, not just generic ones. dev-lead-fix-issue.sh: - Replace the silent exit 1 and unify the rate-limit branch with a single handle_engine_failure: reads the cause + reset, computes attempt from prior <!-- dev-lead-issue N ... --> markers, builds a redacted 40-line session snippet + run deep-link, and applies a decision matrix: missing-binary → dev-lead:needs-human label + comment (no retry) rate-limited/engine-error & attempt<MAX → retryable marker + comment attempt>=MAX → dev-lead:needs-human label + "exhausted" comment Exit codes unchanged (2 rate-limit, 1 otherwise). The retryable marker is what Phase 2's retry cron will scan for. Tests: extend test_fix_issue.bats (engine-error marker+snippet+run link, missing-binary→needs-human, attempt ceiling→needs-human) and test_engine_fallback.bats (failure-reason sidecar per class, stale-reason clear, session-output persisted on the rate-limit path). Refs #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dev-lead): bounded auto-retry for failed initial issue impls (#781 Phase 2) Phase 1 made failed issue implementations cause-aware and left a retryable marker. Phase 2 closes the loop: the retry cron now requeues them. dev-lead-retry.sh: - New scan_repo_issues + scan_issue_for_retry + dispatch_issue_retry. Enumerates open dev-lead-labelled issues (filtering out PRs and dev-lead:needs-human), reads the newest <!-- dev-lead-issue N ... --> marker, and re-dispatches a dev-lead-issue-retry when retryable: honours the rate-limit reset= window, enforces attempt < MAX_ATTEMPTS (3), and skips issues that already have an open dev-lead PR. Called from scan_repo unconditionally (also when a repo has no open PRs — the common case for a stalled issue). main() now guarded behind a BASH_SOURCE check so the functions are unit-testable. dev-lead-intent.sh: - Restructure the repository_dispatch branch so issue-only payloads are no longer dropped by the hard pr_number requirement. Hands-off label lookup keys off a subject_number (pr_number or issue_number). New dev-lead-issue-retry type reads issue_number and routes to the existing `issue` intent (full-fidelity re-run); PR-based types keep their pr_number guard. Workflows: - dev-lead.yml (thin caller): add dev-lead-issue-retry to repository_dispatch .types (established pattern; allowed per AGENTS.md). - dev-lead-reusable.yml: add a client_payload.issue_number -> dev-lead-issue-<n> lane to the concurrency router so issue retries serialise on the issue lane. Tests/docs: - New tests/dev-lead/unit/test_dev_lead_retry.bats (decision matrix + payload). - test_intent_ci.bats: issue-retry routing, missing issue_number, hands-off. - New fixture repository_dispatch_issue_retry.json. - e2e scenario 07 Part I: full retry-script wiring requeues a failed issue. - docs/dev-lead/spec.md: dispatch table, §7.5 failure matrix, §10.1a issue-retry. Closes #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * fix(bot): address bot feedback [skip ci-relay] * chore: apply manual instructions [skip ci-relay] --------- Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…ent (#781) (#810) * feat(dev-lead): surface engine failure cause on failed issue impls (#781 Phase 1) A dev-lead initial issue implementation that failed at the engine step (for any non-rate-limit reason) emitted only a generic "Engine failed to implement issue case: petry-projects/.github#478, a 600s deep-tier timeout kill surfaced only as exit 1). Phase 1 makes the failure never-silent and cause-aware (no caller-interface or workflow change): engine.sh: - run_writer_with_fallback writes a one-line cause class to /tmp/dev-lead-failure-reason (rate-limited | missing-binary | engine-error) before each terminal failure return, mirroring the existing /tmp/dev-lead-rate-limit-reset sidecar. Purely additive — no control-flow change. - run_writer's redact + persist + GITHUB_STEP_SUMMARY block now runs before the rate-limit early-return, so session output (where the real cause appears) is captured for ALL failure classes, not just generic ones. dev-lead-fix-issue.sh: - Replace the silent exit 1 and unify the rate-limit branch with a single handle_engine_failure: reads the cause + reset, computes attempt from prior <!-- dev-lead-issue N ... --> markers, builds a redacted 40-line session snippet + run deep-link, and applies a decision matrix: missing-binary → dev-lead:needs-human label + comment (no retry) rate-limited/engine-error & attempt<MAX → retryable marker + comment attempt>=MAX → dev-lead:needs-human label + "exhausted" comment Exit codes unchanged (2 rate-limit, 1 otherwise). The retryable marker is what Phase 2's retry cron will scan for. Tests: extend test_fix_issue.bats (engine-error marker+snippet+run link, missing-binary→needs-human, attempt ceiling→needs-human) and test_engine_fallback.bats (failure-reason sidecar per class, stale-reason clear, session-output persisted on the rate-limit path). Refs #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dev-lead): bounded auto-retry for failed initial issue impls (#781 Phase 2) Phase 1 made failed issue implementations cause-aware and left a retryable marker. Phase 2 closes the loop: the retry cron now requeues them. dev-lead-retry.sh: - New scan_repo_issues + scan_issue_for_retry + dispatch_issue_retry. Enumerates open dev-lead-labelled issues (filtering out PRs and dev-lead:needs-human), reads the newest <!-- dev-lead-issue N ... --> marker, and re-dispatches a dev-lead-issue-retry when retryable: honours the rate-limit reset= window, enforces attempt < MAX_ATTEMPTS (3), and skips issues that already have an open dev-lead PR. Called from scan_repo unconditionally (also when a repo has no open PRs — the common case for a stalled issue). main() now guarded behind a BASH_SOURCE check so the functions are unit-testable. dev-lead-intent.sh: - Restructure the repository_dispatch branch so issue-only payloads are no longer dropped by the hard pr_number requirement. Hands-off label lookup keys off a subject_number (pr_number or issue_number). New dev-lead-issue-retry type reads issue_number and routes to the existing `issue` intent (full-fidelity re-run); PR-based types keep their pr_number guard. Workflows: - dev-lead.yml (thin caller): add dev-lead-issue-retry to repository_dispatch .types (established pattern; allowed per AGENTS.md). - dev-lead-reusable.yml: add a client_payload.issue_number -> dev-lead-issue-<n> lane to the concurrency router so issue retries serialise on the issue lane. Tests/docs: - New tests/dev-lead/unit/test_dev_lead_retry.bats (decision matrix + payload). - test_intent_ci.bats: issue-retry routing, missing issue_number, hands-off. - New fixture repository_dispatch_issue_retry.json. - e2e scenario 07 Part I: full retry-script wiring requeues a failed issue. - docs/dev-lead/spec.md: dispatch table, §7.5 failure matrix, §10.1a issue-retry. Closes #781 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * chore: apply manual instructions [skip ci-relay] * fix(bot): address bot feedback [skip ci-relay] * chore: apply manual instructions [skip ci-relay] --------- Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>



Summary
Failed initial issue implementations used to stall silently. When a dev-lead
issues-labeled run failed at theRun issueengine step for any non-rate-limit reason,dev-lead-fix-issue.shemitted only a genericEngine failed to implement issue #N/exit 1— no comment, no marker, no cause — anddev-lead-retryonly ever scanned PRs forstatus=rate-limited. So the issue kept itsdev-leadlabel, looked "in progress", and was never retried.This PR makes failed issue implementations never-silent, cause-aware, and auto-retried (bounded). Closes #781.
Step 0 — confirmed live root cause (petry-projects/.github#478)
Pulled the failed
Run issuejob log for run27733022075. The genericexit 1was hiding a 600-second per-tiertimeoutSIGTERM-kill of the opus 4.8 writer (02:37:30 → 02:47:30= a clean 600.2s wall;[headroom] 0% — okrules out rate-limit).DEEP_TIMEOUT_SEC=600(engine.sh:37), and124=GNU timeoutis classified transient (engine.sh:43). A transient failure with no retry path → permanent stall. Full trace in the findings comment.Phase 1 — never silent, with cause (no caller-interface change)
engine.sh—run_writer_with_fallbackwrites a one-line cause class to/tmp/dev-lead-failure-reason(rate-limited|missing-binary|engine-error), mirroring the existing rate-limit-reset sidecar.run_writer's redact + persist +$GITHUB_STEP_SUMMARYblock now runs before the rate-limit early-return, so session output is captured for all failure classes.dev-lead-fix-issue.sh— replaces the silentexit 1and unifies the rate-limit branch withhandle_engine_failure: reads cause + reset, computes attempt from prior markers, posts a comment with the cause + run deep-link + redacted 40-line snippet, and applies a decision matrix (missing-binary→dev-lead:needs-human; retryable &attempt<MAX→ retryable marker;attempt≥MAX→dev-lead:needs-human). Exit codes unchanged.Phase 2 — bounded auto-retry
dev-lead-retry.sh— newscan_repo_issues/scan_issue_for_retry/dispatch_issue_retry: enumerates opendev-leadissues (excludes PRs +dev-lead:needs-human), reads the newest<!-- dev-lead-issue N … -->marker, and re-dispatchesdev-lead-issue-retryhonouring thereset=window,attempt < MAX_ATTEMPTS (3), and "skip if an open PR exists". Runs even when a repo has no open PRs.dev-lead-intent.sh— restructured so issue-only dispatch payloads aren't dropped;dev-lead-issue-retryroutes back to the existingissueintent (full-fidelity re-run).dev-lead.yml(thin caller) — addsdev-lead-issue-retrytorepository_dispatch.types(established pattern, allowed per AGENTS.md).dev-lead-reusable.yml— adds aclient_payload.issue_number → dev-lead-issue-<n>concurrency lane.Tests & docs
tests/dev-lead/unit/test_dev_lead_retry.bats(new, 10 cases — decision matrix + dispatch payload).test_fix_issue.bats(+4) andtest_engine_fallback.bats(+5);test_intent_ci.bats(+3); new fixturerepository_dispatch_issue_retry.json; e2e scenario 07 Part I.--severity=warning -x); workflow YAML validates.docs/dev-lead/spec.md: dispatch table, §7.5 failure matrix, §10.1a issue-retry path.Follow-up (separate PR, other repo)
The org-level
standards/ci-standards.md/AGENTS.mdinpetry-projects/.githubshould document the newdev-lead-issue-retrydispatch type anddev-lead:needs-humansemantics for consumer repos — out of scope for this.github-privatePR.🤖 Generated with Claude Code
Summary by CodeRabbit