fix(initiative-driver): auto-drive every initiative:auto epic, not just #495 - #683
Conversation
#495 The driver only ran for a single hard-coded epic (#495): on schedule and issues:closed events EPIC defaulted to '495', and nothing triggered the driver from the act of arming an epic. So adding `initiative:auto` to a new epic (e.g. #676) flipped the safety gate but never started any work — the documented "human adds initiative:auto -> initiative-driver -> dev-lead" hand-off had no trigger edge, and the schedule/close paths could never pick up any epic other than #495. Changes: - initiative-driver.sh: add sweep mode — when EPIC is empty, discover every open issue carrying initiative:auto and drive each. Per-epic logic extracted into drive_epic(); single-epic mode (explicit dispatch) is unchanged. - initiative-driver.yml: trigger on issues:[labeled] (arming an epic starts it immediately, filtered to the gate label), stop defaulting EPIC to 495 so the automatic triggers sweep all armed epics, only pass CLOSED_ISSUE on close events, and use a single global concurrency lane. - tests: add sweep-mode bats coverage (multi-epic discovery + empty no-op). - docs: document the labeled trigger + sweep behavior; resolve the two follow-ups (bats coverage, generalize EPIC beyond 495). https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3
|
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 54 minutes and 36 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 We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. 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 (2)
📝 WalkthroughWalkthrough
ChangesInitiative Driver Sweep Mode
Sequence Diagram(s)sequenceDiagram
participant GH as GitHub Events
participant WF as initiative-driver.yml
participant SH as initiative-driver.sh
participant API as gh CLI / Issues API
GH->>WF: issues.labeled (initiative:auto) OR issues.closed OR workflow_dispatch
WF->>WF: if labeled event, guard: label == initiative:auto?
WF->>SH: run with EPIC (blank or number), CLOSED_ISSUE (close events only)
alt EPIC is set
SH->>SH: drive_epic(EPIC)
else EPIC is blank (sweep)
SH->>API: gh search: open issues with GATE_LABEL
API-->>SH: list of epic numbers
loop for each epic
SH->>SH: drive_epic(epic)
end
end
SH->>SH: gate check, sub-issue filter, blocker check, in-flight cap
SH->>API: gh issue edit --add-label DEV_LEAD_LABEL (or DRY_RUN log)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 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 |
Dev-Lead — waiting on PR blockers (intent: review-changes)PR: #683 |
|
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. |
There was a problem hiding this comment.
Code Review
This pull request introduces a 'sweep' mode to the initiative driver script, allowing it to automatically discover and drive all open epics carrying the 'initiative:auto' label when no specific epic is provided. It refactors the core logic into a reusable 'drive_epic' function, updates the documentation, and adds BATS tests to verify the new sweep behavior. The review feedback highlights a critical Bash issue where 'set -e' is disabled inside the function when executed as part of an OR list, which could silently mask API failures. Additionally, the feedback recommends declaring the loop variable 'n' as local to prevent scope leakage and removing a redundant associative array re-initialization that could cause errors in older Bash versions.
Dev-Lead — fix-bot-comment (no-changes)Agent reasoning |
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 `@scripts/initiative-driver.sh`:
- Around line 66-68: The regex pattern `^[0-9]+$` in the EPIC validation check
(line 66) currently allows "0" as a valid value, but the error message correctly
states that EPIC must be a "positive integer," which excludes zero. Fix this by
replacing the regex pattern with one that rejects zero while accepting all
positive integers, such as `^[1-9][0-9]*$`, which ensures the first digit is 1-9
followed by any number of digits 0-9, thereby excluding zero and matching the
positive-integer contract stated in the error message.
In `@tests/test_initiative_driver.bats`:
- Around line 171-194: The test "sweep: drives every open epic carrying
initiative:auto when EPIC is empty" verifies that the script logs discovery and
driving messages correctly, but lacks an explicit assertion that no label
mutations occur when both epics have no sub-issues. Add a GH_LOG check after the
existing output assertions to verify that the gh command log contains only the
discovery query and no mutation commands (no edits to labels), similar to the
pattern used in the empty-sweep test.
🪄 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: 4917eb78-2b75-46cc-bb7a-9b68a08b646b
📒 Files selected for processing (4)
.github/workflows/initiative-driver.ymldocs/initiatives/agentic-release-strategy-orchestration.mdscripts/initiative-driver.shtests/test_initiative_driver.bats
Address review feedback on the sweep loop: - set -e masking (high): `drive_epic "$e" || …` disabled errexit inside the function (Bash ignores -e for a function run in an OR/if/&& context), so a gh API failure fell through and was silently treated as a false "no sub-issues" no-op. Run each epic in a standalone `( set -e; drive_epic )` subshell with errexit OFF in the parent, capturing the status — fail-fast per epic, sweep continues, real failures surface as errors. - Declare loop var `n` local to drive_epic (no scope leakage). - Drop redundant `released=()` (already `local -A`; the re-init is fatal on Bash <=4.3). - Add a regression test asserting a per-epic gh failure now surfaces (rc!=0) instead of being masked, and the sweep still drives the next epic. https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3
Address CodeRabbit review: - EPIC validation regex tightened to ^[1-9][0-9]*$ so EPIC=0 is rejected, matching the "positive integer" contract (MAX_IN_FLIGHT keeps ^[0-9]+$ — 0 is a valid non-negative cap). - Multi-epic sweep test now asserts no `issue edit` occurs when the swept epics have no sub-issues. https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3
|
Dev-Lead — waiting on PR blockers (intent: fix-reviews)PR: #683 |
Dev-Lead — fix-reviews (no-changes)Agent reasoning |
donpetry-bot
left a comment
There was a problem hiding this comment.
Automated review — APPROVED ✓
Risk: MEDIUM
Reviewed commit: 07763f78a4725014f9d4a53ef6b06e608a9f9560
Cascade: triage → deep (triage: haiku 4.5 → deep: opus 4.8 + duck: o4-mini → audit: fable 5)
Summary
Adds sweep mode to initiative-driver so automatic triggers drive every initiative:auto epic instead of the hard-coded #495, plus an issues:[labeled] trigger gated to the gate label. The triage's escalation signal (Gemini 'n not local') is already resolved at head, and the errexit OR-list trap is correctly avoided with a per-epic subshell. Both CodeRabbit findings (EPIC regex accepting '0'; missing mutation assertion in sweep test) are fixed and CodeRabbit re-approved; functional CI gates (shellcheck, bats/unit-tests, CodeQL, SonarCloud, gitleaks) are green.
Findings
- INFO: Gemini's escalated finding ('n' leaking to global scope in drive_epic) is already addressed at head: 'n' is in the local declaration list (scripts/initiative-driver.sh:95). Triage's signal was stale.
- INFO: Errexit handling for the sweep is correct: each epic runs in a standalone 'set -e' subshell '( set -e; drive_epic "$e" )' rather than an OR-list, so a gh API failure aborts that epic (surfaced as ::error:: and rc=1) instead of being silently masked as a false 'no sub-issues'. The single-epic dispatch path calls drive_epic as a simple command, keeping errexit active.
- INFO: No security regression: workflow permissions remain 'contents: read' (mutations use the PAT); the issues:[labeled] trigger is gated by job-level if to the 'initiative:auto' label; EPIC/CLOSED_ISSUE flow through env vars (not ${{ }} run-shell interpolation) and are regex-validated in the script; discovery/sweep values are integer issue numbers from jq.
- INFO: EPIC validation tightened per CodeRabbit: now '^[1-9][0-9]*$' (rejects '0' and empty-vs-number ambiguity) with empty permitted for sweep mode.
Reviewed by the PR-review cascade (triage: haiku 4.5 → deep: opus 4.8 + duck: o4-mini → audit: fable 5). Reply if you need a human review.
#495 (#683) * fix(initiative-driver): auto-drive every initiative:auto epic, not just #495 The driver only ran for a single hard-coded epic (#495): on schedule and issues:closed events EPIC defaulted to '495', and nothing triggered the driver from the act of arming an epic. So adding `initiative:auto` to a new epic (e.g. #676) flipped the safety gate but never started any work — the documented "human adds initiative:auto -> initiative-driver -> dev-lead" hand-off had no trigger edge, and the schedule/close paths could never pick up any epic other than #495. Changes: - initiative-driver.sh: add sweep mode — when EPIC is empty, discover every open issue carrying initiative:auto and drive each. Per-epic logic extracted into drive_epic(); single-epic mode (explicit dispatch) is unchanged. - initiative-driver.yml: trigger on issues:[labeled] (arming an epic starts it immediately, filtered to the gate label), stop defaulting EPIC to 495 so the automatic triggers sweep all armed epics, only pass CLOSED_ISSUE on close events, and use a single global concurrency lane. - tests: add sweep-mode bats coverage (multi-epic discovery + empty no-op). - docs: document the labeled trigger + sweep behavior; resolve the two follow-ups (bats coverage, generalize EPIC beyond 495). https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3 * fix(initiative-driver): preserve errexit per-epic in sweep; tidy locals Address review feedback on the sweep loop: - set -e masking (high): `drive_epic "$e" || …` disabled errexit inside the function (Bash ignores -e for a function run in an OR/if/&& context), so a gh API failure fell through and was silently treated as a false "no sub-issues" no-op. Run each epic in a standalone `( set -e; drive_epic )` subshell with errexit OFF in the parent, capturing the status — fail-fast per epic, sweep continues, real failures surface as errors. - Declare loop var `n` local to drive_epic (no scope leakage). - Drop redundant `released=()` (already `local -A`; the re-init is fatal on Bash <=4.3). - Add a regression test asserting a per-epic gh failure now surfaces (rc!=0) instead of being masked, and the sweep still drives the next epic. https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3 * fix(initiative-driver): reject EPIC=0; assert no-mutation in sweep test Address CodeRabbit review: - EPIC validation regex tightened to ^[1-9][0-9]*$ so EPIC=0 is rejected, matching the "positive integer" contract (MAX_IN_FLIGHT keeps ^[0-9]+$ — 0 is a valid non-negative cap). - Multi-epic sweep test now asserts no `issue edit` occurs when the swept epics have no sub-issues. https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3 --------- Co-authored-by: Claude <noreply@anthropic.com>
#495 (#683) * fix(initiative-driver): auto-drive every initiative:auto epic, not just #495 The driver only ran for a single hard-coded epic (#495): on schedule and issues:closed events EPIC defaulted to '495', and nothing triggered the driver from the act of arming an epic. So adding `initiative:auto` to a new epic (e.g. #676) flipped the safety gate but never started any work — the documented "human adds initiative:auto -> initiative-driver -> dev-lead" hand-off had no trigger edge, and the schedule/close paths could never pick up any epic other than #495. Changes: - initiative-driver.sh: add sweep mode — when EPIC is empty, discover every open issue carrying initiative:auto and drive each. Per-epic logic extracted into drive_epic(); single-epic mode (explicit dispatch) is unchanged. - initiative-driver.yml: trigger on issues:[labeled] (arming an epic starts it immediately, filtered to the gate label), stop defaulting EPIC to 495 so the automatic triggers sweep all armed epics, only pass CLOSED_ISSUE on close events, and use a single global concurrency lane. - tests: add sweep-mode bats coverage (multi-epic discovery + empty no-op). - docs: document the labeled trigger + sweep behavior; resolve the two follow-ups (bats coverage, generalize EPIC beyond 495). https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3 * fix(initiative-driver): preserve errexit per-epic in sweep; tidy locals Address review feedback on the sweep loop: - set -e masking (high): `drive_epic "$e" || …` disabled errexit inside the function (Bash ignores -e for a function run in an OR/if/&& context), so a gh API failure fell through and was silently treated as a false "no sub-issues" no-op. Run each epic in a standalone `( set -e; drive_epic )` subshell with errexit OFF in the parent, capturing the status — fail-fast per epic, sweep continues, real failures surface as errors. - Declare loop var `n` local to drive_epic (no scope leakage). - Drop redundant `released=()` (already `local -A`; the re-init is fatal on Bash <=4.3). - Add a regression test asserting a per-epic gh failure now surfaces (rc!=0) instead of being masked, and the sweep still drives the next epic. https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3 * fix(initiative-driver): reject EPIC=0; assert no-mutation in sweep test Address CodeRabbit review: - EPIC validation regex tightened to ^[1-9][0-9]*$ so EPIC=0 is rejected, matching the "positive integer" contract (MAX_IN_FLIGHT keeps ^[0-9]+$ — 0 is a valid non-negative cap). - Multi-epic sweep test now asserts no `issue edit` occurs when the swept epics have no sub-issues. https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3 --------- Co-authored-by: Claude <noreply@anthropic.com>
#495 (#683) * fix(initiative-driver): auto-drive every initiative:auto epic, not just #495 The driver only ran for a single hard-coded epic (#495): on schedule and issues:closed events EPIC defaulted to '495', and nothing triggered the driver from the act of arming an epic. So adding `initiative:auto` to a new epic (e.g. #676) flipped the safety gate but never started any work — the documented "human adds initiative:auto -> initiative-driver -> dev-lead" hand-off had no trigger edge, and the schedule/close paths could never pick up any epic other than #495. Changes: - initiative-driver.sh: add sweep mode — when EPIC is empty, discover every open issue carrying initiative:auto and drive each. Per-epic logic extracted into drive_epic(); single-epic mode (explicit dispatch) is unchanged. - initiative-driver.yml: trigger on issues:[labeled] (arming an epic starts it immediately, filtered to the gate label), stop defaulting EPIC to 495 so the automatic triggers sweep all armed epics, only pass CLOSED_ISSUE on close events, and use a single global concurrency lane. - tests: add sweep-mode bats coverage (multi-epic discovery + empty no-op). - docs: document the labeled trigger + sweep behavior; resolve the two follow-ups (bats coverage, generalize EPIC beyond 495). https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3 * fix(initiative-driver): preserve errexit per-epic in sweep; tidy locals Address review feedback on the sweep loop: - set -e masking (high): `drive_epic "$e" || …` disabled errexit inside the function (Bash ignores -e for a function run in an OR/if/&& context), so a gh API failure fell through and was silently treated as a false "no sub-issues" no-op. Run each epic in a standalone `( set -e; drive_epic )` subshell with errexit OFF in the parent, capturing the status — fail-fast per epic, sweep continues, real failures surface as errors. - Declare loop var `n` local to drive_epic (no scope leakage). - Drop redundant `released=()` (already `local -A`; the re-init is fatal on Bash <=4.3). - Add a regression test asserting a per-epic gh failure now surfaces (rc!=0) instead of being masked, and the sweep still drives the next epic. https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3 * fix(initiative-driver): reject EPIC=0; assert no-mutation in sweep test Address CodeRabbit review: - EPIC validation regex tightened to ^[1-9][0-9]*$ so EPIC=0 is rejected, matching the "positive integer" contract (MAX_IN_FLIGHT keeps ^[0-9]+$ — 0 is a valid non-negative cap). - Multi-epic sweep test now asserts no `issue edit` occurs when the swept epics have no sub-issues. https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3 --------- Co-authored-by: Claude <noreply@anthropic.com>
#495 (#683) * fix(initiative-driver): auto-drive every initiative:auto epic, not just #495 The driver only ran for a single hard-coded epic (#495): on schedule and issues:closed events EPIC defaulted to '495', and nothing triggered the driver from the act of arming an epic. So adding `initiative:auto` to a new epic (e.g. #676) flipped the safety gate but never started any work — the documented "human adds initiative:auto -> initiative-driver -> dev-lead" hand-off had no trigger edge, and the schedule/close paths could never pick up any epic other than #495. Changes: - initiative-driver.sh: add sweep mode — when EPIC is empty, discover every open issue carrying initiative:auto and drive each. Per-epic logic extracted into drive_epic(); single-epic mode (explicit dispatch) is unchanged. - initiative-driver.yml: trigger on issues:[labeled] (arming an epic starts it immediately, filtered to the gate label), stop defaulting EPIC to 495 so the automatic triggers sweep all armed epics, only pass CLOSED_ISSUE on close events, and use a single global concurrency lane. - tests: add sweep-mode bats coverage (multi-epic discovery + empty no-op). - docs: document the labeled trigger + sweep behavior; resolve the two follow-ups (bats coverage, generalize EPIC beyond 495). https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3 * fix(initiative-driver): preserve errexit per-epic in sweep; tidy locals Address review feedback on the sweep loop: - set -e masking (high): `drive_epic "$e" || …` disabled errexit inside the function (Bash ignores -e for a function run in an OR/if/&& context), so a gh API failure fell through and was silently treated as a false "no sub-issues" no-op. Run each epic in a standalone `( set -e; drive_epic )` subshell with errexit OFF in the parent, capturing the status — fail-fast per epic, sweep continues, real failures surface as errors. - Declare loop var `n` local to drive_epic (no scope leakage). - Drop redundant `released=()` (already `local -A`; the re-init is fatal on Bash <=4.3). - Add a regression test asserting a per-epic gh failure now surfaces (rc!=0) instead of being masked, and the sweep still drives the next epic. https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3 * fix(initiative-driver): reject EPIC=0; assert no-mutation in sweep test Address CodeRabbit review: - EPIC validation regex tightened to ^[1-9][0-9]*$ so EPIC=0 is rejected, matching the "positive integer" contract (MAX_IN_FLIGHT keeps ^[0-9]+$ — 0 is a valid non-negative cap). - Multi-epic sweep test now asserts no `issue edit` occurs when the swept epics have no sub-issues. https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3 --------- Co-authored-by: Claude <noreply@anthropic.com>



Why
While monitoring the auto-implementation of epic #676, I found it had silently stalled. Adding
initiative:autoto #676 flipped the safety gate but started nothing, and on its own it never would, because of two gaps in the driver:initiative-driver.ymlonly ran onissues:closed, a 6-hourlyschedule, andworkflow_dispatch. No trigger fired wheninitiative:autowas added — so the documented hand-off (★ human adds initiative:auto → initiative-driver → dev-lead) had no edge.EPIC: ${{ github.event.inputs.epic || '495' }}— onschedule/issues:closedthere are no inputs, soEPICalways resolved to495. The cron and every issue-close drove only Initiative: Safe Release Strategy for Agentic Workflows (versioning · rings · canary) #495; MCP-powered review enrichment for the self-hosted Claude review engine (engine.sh) #676 (and any future epic) could never be picked up automatically.This is the exact follow-up the design doc already flagged: "Generalize
EPICbeyond the hard-coded495default if a second initiative adopts the driver."(Adding the label did fire
dev-lead.ymlviaissues:[labeled], but dev-lead acts only on thedev-leadlabel, so that run was a harmless no-op.)What changed
scripts/initiative-driver.sh— add sweep mode: whenEPICis empty, discover every open issue carryinginitiative:autoand drive each. Per-epic logic is extracted intodrive_epic(); single-epic mode (explicit dispatch) is byte-for-byte unchanged..github/workflows/initiative-driver.yml—issues:[labeled]so arming an epic starts it immediately (jobiffilters to theinitiative:autolabel so unrelated label changes don't sweep);EPICto495— automatic triggers run blank ⇒ sweep all armed epics;workflow_dispatchstill accepts an optionalepicto target one;CLOSED_ISSUEon actual close events (avoids mistaking a labeled epic's own number for a closed sub-issue);tests/test_initiative_driver.bats— add sweep-mode coverage (multi-epic discovery + empty no-op). All 10 tests pass.Verification
shellcheck --severity=warning -x scripts/initiative-driver.sh— cleanbats tests/test_initiative_driver.bats— 10/10 pass (8 existing + 2 new)Note on #676
This PR fixes the mechanism but does not itself kick off #676 (that spends agent budget and opens PRs). Once merged, arming any epic — or re-arming #676 — will start it automatically. If you'd rather start #676 now without waiting for the merge, I can dispatch
initiative-driver.ymlwithepic=676.https://claude.ai/code/session_01RfwDpKTkNEBHjEMDcGkTY3
Generated by Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests