Skip to content

feat(loop): GitHub issue lifecycle (#73) + optional fix_plan sections (#239)#294

Merged
frankbria merged 4 commits into
mainfrom
feature/issue-73-lifecycle-and-239-optional-sections
Jun 8, 2026
Merged

feat(loop): GitHub issue lifecycle (#73) + optional fix_plan sections (#239)#294
frankbria merged 4 commits into
mainfrom
feature/issue-73-lifecycle-and-239-optional-sections

Conversation

@frankbria

@frankbria frankbria commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Implements #73 (GitHub issue lifecycle management) and #239 (Optional/Future section support in fix_plan.md) in one PR.

#73 — GitHub issue lifecycle management

New ralph --github-issue <ref> tracking, backed by lib/github_lifecycle.sh. All actions are opt-in and require --github-issue (a number, #N, owner/repo#N, or issue URL):

Flag Effect
--comment-progress / --comment-interval N Post progress comments every N loops (default 5)
--close-summary Post a completion summary comment
--create-pr / --link-issue / --draft-pr Open a PR on completion, optionally Closes #N, optionally draft
--create-followups / --followup-label Open a grouped follow-up issue from TODO/FIXME markers added during dev
--auto-close / --add-label Close the issue (with labels) on completion

Adapted from the Traycer plan on the issue, which assumed a greenfield repo using raw REST + GITHUB_TOKEN. This repo uses the gh CLI everywhere and the .ralph/ subfolder, so the implementation uses gh issue comment/close/edit, gh pr create, gh issue create, with state at .ralph/.github_lifecycle_state (atomic temp+mv). Dropped as YAGNI: multi-repo/cross-repo, custom rate-limit backoff (gh handles its own), GITHUB_TOKEN scope validation.

Graceful degradation: every gh operation logs and returns non-zero on failure (e.g. missing permission) but the orchestration helpers always return 0 — a lifecycle hiccup never crashes the development loop.

#239 — Optional/Future sections in fix_plan.md

_count_blocking_unchecked() (awk, section-aware) makes the "all checkboxes complete" exit ignore unchecked - [ ] items under sections whose heading matches OPTIONAL_SECTIONS (default Optional,Future,Future Enhancements,Nice to Have; case-insensitive; configurable in .ralphrc). Optional context persists into deeper subsections and closes at the next same-or-higher-level heading. Resolves the deadlock where Claude treats low-priority items as skippable while Ralph keeps looping for them. Backward compatible — with no optional sections present, behavior is identical to the prior full-file count.

Tests

  • tests/unit/test_github_lifecycle.bats (29) — reference parsing, gh wrappers (mocked), generators, state, interval gating, completion-workflow ordering, graceful degradation
  • tests/unit/test_exit_detection.bats (+9) — optional-section exclusion, nesting, case-insensitivity, configurability, backward compat (real + inlined copy kept in sync)
  • tests/unit/test_cli_modern.bats (+3) — flag acceptance, --comment-interval validation, help text

Full suite green: 769 unit + 250 integration + 13 e2e = 1032, 0 failures.

Demo evidence

Both features were demoed against the real functions (gh mocked to capture exact commands). #239: should_exit_gracefully returns plan_complete with optional items present (counted 1/1, not 3/3) and "" when a required section has unchecked items. #73: full lifecycle issued, in order, gh issue commentgh pr create … --draft (body contains Closes #73) → gh issue create … --label tech-debtgh issue edit … --add-labelgh issue close; a 403 from gh left the loop running (returned 0).

Known limitations

  • Follow-up scanning keys off TODO/FIXME/HACK/XXX markers in the diff; this repo's own style forbids TODO comments, so it will rarely fire here (off by default).
  • --create-pr best-effort pushes the current branch; PR creation needs a pushed branch and push permission.

Closes #73
Closes #239

Summary by CodeRabbit

Release Notes

  • New Features

    • GitHub issue lifecycle automation: automatically track progress, post periodic updates, and create linked PRs for referenced issues
    • Auto-create follow-up issues from code TODOs/FIXMEs upon completion
    • Optional task sections in fix plans that don't block exit detection
    • Auto-close issues and apply labels on workflow completion
  • Documentation

    • Added GitHub issue lifecycle feature guide with configuration options
    • Updated exit detection documentation for optional sections

…#239)

Issue #73 — GitHub issue lifecycle management (lib/github_lifecycle.sh):
- New `ralph --github-issue <ref>` tracking with opt-in lifecycle actions:
  progress comments (--comment-progress/--comment-interval), completion
  summary (--close-summary), PR creation linked with "Closes #N"
  (--create-pr/--link-issue/--draft-pr), grouped follow-up issue from
  TODO/FIXME markers (--create-followups/--followup-label), and issue close
  with labels (--auto-close/--add-label).
- Uses the `gh` CLI exclusively (not raw REST/GITHUB_TOKEN); state at
  .ralph/.github_lifecycle_state (atomic temp+mv). Every gh op degrades
  gracefully — a permission failure is logged and the loop continues.
- Wired into ralph_loop.sh: init at startup, progress hook in the loop body,
  completion workflow on graceful exit. Config via flags or .ralphrc.

Issue #239 — Optional/Future sections in fix_plan.md:
- `_count_blocking_unchecked()` (awk, section-aware) excludes unchecked items
  under OPTIONAL_SECTIONS (default "Optional,Future,Future Enhancements,Nice
  to Have", case-insensitive, configurable) from the plan-complete exit check.
  Resolves the deadlock where Claude skips low-priority items while Ralph waits.
  Backward compatible when no optional sections are present.

Tests: +29 unit (test_github_lifecycle.bats), +9 (test_exit_detection.bats),
+3 (test_cli_modern.bats). Full suite green: 769 unit + 250 integration + 13 e2e.
Docs: CLAUDE.md, README.md, templates/fix_plan.md.
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@frankbria, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 8 minutes and 14 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

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.

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 configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5b30c4ae-ee36-4c75-bee2-e0e070282414

📥 Commits

Reviewing files that changed from the base of the PR and between 82668e4 and ebcb637.

📒 Files selected for processing (4)
  • lib/github_lifecycle.sh
  • ralph_loop.sh
  • tests/integration/test_tmux_integration.bats
  • tests/unit/test_github_lifecycle.bats

Walkthrough

This PR implements GitHub issue lifecycle automation (Issue #73) allowing Ralph to post progress comments, create PRs with issue linking, auto-close issues, and generate follow-up issues from TODOs. It also adds optional sections support (Issue #239) so unchecked items under configurable headings don't block exit. Includes new lib/github_lifecycle.sh (402 lines), integration into ralph_loop.sh (203 line changes), comprehensive tests, and documentation updates.

Changes

GitHub Issue Lifecycle & Optional Sections Support

Layer / File(s) Summary
Optional Sections Support (Issue #239)
ralph_loop.sh, templates/fix_plan.md, tests/unit/test_exit_detection.bats, README.md, CLAUDE.md
Adds _count_blocking_unchecked() helper that skips unchecked items under optional/future section headings (configured via OPTIONAL_SECTIONS in .ralphrc). Exit logic updated to use blocking-only count, preventing optional sections from deadlocking plan completion. Tests validate nested heading context, case-insensitive matching, section re-enabling, and backward compatibility.
GitHub Lifecycle Library
lib/github_lifecycle.sh
New Bash library providing issue lifecycle automation: parses issue references (bare numbers, URLs, owner/repo#N format), manages atomic JSON state file, wraps gh CLI with error handling and logging, generates progress/completion comments from fix_plan.md and git diffs, scans diffs for TODO/FIXME/HACK/XXX markers, and orchestrates completion workflows (PR creation with optional "Closes #N", issue closing, label application, follow-up issue generation). All operations gracefully degrade on gh errors.
Lifecycle Testing
tests/unit/test_github_lifecycle.bats
Comprehensive test suite with mocked gh binary capturing CLI args and stdin. Validates issue reference parsing, state persistence/mutation, gh wrapper argument construction, content generation from markdown, interval-gated progress posting, resilient completion handling when gh fails, conditional completion actions, and follow-up generation only when TODOs exist.
Lifecycle Integration & CLI
ralph_loop.sh, tests/unit/test_cli_modern.bats
Integrates lifecycle library into main loop: sources library, loads/persists configuration via environment and .ralphrc, applies CLI overrides, initializes lifecycle on startup, calls lifecycle_post_progress() after loop success and lifecycle_on_completion() during graceful exit. CLI parsing extended with 10+ new flags (--github-issue, --comment-progress, --comment-interval, --auto-close, --create-pr, --create-followups, --link-issue, --add-label, etc.) with repeatable label aggregation. Tests validate flag acceptance, interval validation, and help documentation.
Documentation
README.md, CLAUDE.md, templates/fix_plan.md
Explains optional sections mechanism (OPTIONAL_SECTIONS config), GitHub lifecycle feature overview with progress comment, PR, closing, and follow-up workflows. Documents lifecycle state storage in .ralph/.github_lifecycle_state, CLI flags table, and bash usage examples. Template clarifies that optional unchecked items don't block completion.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • frankbria/ralph-claude-code#158: Modifies exit-detection logic in ralph_loop.sh/test_exit_detection.bats for fix_plan.md checkbox counting (main PR adds optional-heading-aware blocking count; related PR changes checkbox regex/progress detection).
  • frankbria/ralph-claude-code#218: Touches graceful-exit and plan-complete gating in ralph_loop.sh/test_exit_detection.bats (main PR refines blocking logic via optional sections; related PR prevents premature exit via stale exit-signal reset).
  • frankbria/ralph-claude-code#90: Modifies graceful-exit logic in ralph_loop.sh/test_exit_detection.bats (main PR changes plan-complete gate with OPTIONAL_SECTIONS; related PR adds EXIT_SIGNAL-based completion gate).

Poem

🐰 A loop that closes the GitHub door,
Issues tracked, no more, no more!
Optional tasks won't block the way—
Ralph exits when work's done for the day!
Follow-ups bloom like springtime flowers,
Lifecycle magic working for hours! 🌸

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes both main features being implemented: GitHub issue lifecycle management (#73) and optional fix_plan sections (#239), using conventional commit format.
Linked Issues check ✅ Passed The PR implementation addresses all major coding requirements from #73 (progress comments, auto-close, PR creation, follow-up issues, gh-CLI integration) and #239 (optional section support via OPTIONAL_SECTIONS configuration), with comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the two linked issues: GitHub lifecycle implementation (lib/github_lifecycle.sh, ralph_loop.sh integration, CLI flags), optional sections support (OPTIONAL_SECTIONS logic in exit detection), documentation, templates, and corresponding tests.
Docstring Coverage ✅ Passed Docstring coverage is 85.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/issue-73-lifecycle-and-239-optional-sections

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

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

Code Review — PR 294: GitHub issue lifecycle + optional fix_plan sections

This is a well-executed pair of features. Both follow established Ralph conventions (atomic state via temp+mv, graceful degradation, gh CLI exclusivity, env/ralphrc/CLI precedence), the test suite is thorough, and the documentation is consistent. A few things worth addressing before merge:


Issue 239 — _count_blocking_unchecked

Duplicate implementation is a sync risk. The awk function is copied verbatim into tests/unit/test_exit_detection.bats (lines 922–954) with a comment noting the copies must be kept in sync. This means any algorithm change needs two edits — and the only guard is the tests themselves. There is no compile-time or lint-time enforcement. If the optional-section logic ever needs a fix, it is easy to patch one and miss the other. Consider whether an integration-style approach (sourcing a minimal stub of ralph_loop.sh with dependencies mocked) would be cleaner, even if it is more work upfront.

Progress comments count all unchecked items (including optional ones). generate_progress_comment uses a plain grep -cE "^[[:space:]]*- \[ \]" for the "remaining" figure, so near completion a progress comment might read "2 remaining" while Ralph is about to exit (because those 2 are in an Optional section). This won't break anything, but it can confuse users watching the issue comments. Worth a note in the progress comment body, something like "(some items may be in optional sections)", or just align the count with _count_blocking_unchecked.

The awk logic itself is correct — level-based optional context propagation, case-insensitive matching, backward compatibility with no optional sections. No issues there.


Issue 73 — lib/github_lifecycle.sh

Silent git push could surprise users. When --create-pr is used, lifecycle_on_completion silently runs git push -u origin "$branch" before calling gh pr create. It is guarded with || true so it will not fail the loop, but a user who runs Ralph in a CI environment with restricted push permissions, or a shared repo where they do not want the branch pushed yet, would have no indication this happened until they check the remote. The PR description's "Known limitations" section documents this, but it is not surfaced in the --help text or in a log line before the push attempt. Adding a log_status "INFO" before the push (similar to how PR creation is logged) would make this visible in the loop output.

Double-close with --link-issue + --auto-close. When both flags are active, the issue gets closed immediately by gh_close_issue, and will be closed again automatically by GitHub when the PR is merged (because Closes #N is in the PR body). GitHub treats the second close as a no-op so there is no functional breakage, but the lifecycle state file will show issue_closed: true before merge, which misrepresents the actual state if anyone reads it programmatically. This is an edge case but worth a comment in the code near step 4 of lifecycle_on_completion to set expectations.

GITHUB_PR_TITLE is undocumented. lifecycle_on_completion reads GITHUB_PR_TITLE to override the default PR title, but this variable does not appear in --help, the README table, or CLAUDE.md. A user who wants a custom PR title would not know to set it. Add it to the help text and the README flag table, or drop it if it was not intentional.

scan_for_todos runs three overlapping diffs. The function concatenates git diff -U0 HEAD, git diff -U0 --cached, and git diff -U0 HEAD~1 HEAD. In practice all three can cover the same added lines (e.g. lines committed in the last commit appear in both the last and the HEAD~1 HEAD diffs). The sort -u deduplicates the final markers, but the three separate git diff invocations still run. This is low overhead for typical repos but worth noting. Also git diff -U0 HEAD on a clean working tree returns nothing, so in that case HEAD~1 HEAD is doing the work. A comment explaining which diff covers which scenario would help.


Minor / Positive Observations

  • Using --body-file - (piped stdin) throughout the gh wrappers instead of --body "$variable" is the right call — avoids any shell-injection risk from body content containing special characters.
  • The _lifecycle_apply atomic update pattern matches _queue_apply exactly — consistent and safe.
  • The [[ "${_cli_COMMENT_PROGRESS:-false}" == "true" ]] CLI-override block in main() correctly follows the same pattern as all other flags so .ralphrc values are not silently ignored.
  • The 29 lifecycle unit tests are comprehensive: interval gating, ordering (summary → PR → followups → close), graceful degradation with a failing gh mock, and state persistence all covered.
  • Backward compatibility for Issue 239 is solid — the test "no optional sections present preserves prior behavior" explicitly validates this.

Summary

The implementation is clean and production-ready. Three actionable items before merge:

  1. Add a log_status "INFO" line before the git push in lifecycle_on_completion so users see it in the loop output.
  2. Document GITHUB_PR_TITLE in the help text and README, or remove it.
  3. Add a clarifying comment near step 4 of lifecycle_on_completion about the expected double-close behavior when --link-issue and --auto-close are both used.

The test duplication for _count_blocking_unchecked is a real maintenance risk but may be acceptable given the testing constraints — at minimum the existing sync comment should mention which test exercises which copy so reviewers know both exist.

Test User added 2 commits June 8, 2026 10:03
- P1: never push the default/protected branch when --create-pr is set. Detect the
  remote default branch (and main/master) and skip PR creation with a warning if
  Ralph is on it — pushing it would land work directly on the base instead of in a PR.
- P2: scan follow-up TODOs across the whole run, not just the last commit. Capture
  the HEAD SHA at lifecycle init (lifecycle.start_sha) and diff the working tree
  from it so TODO/FIXME markers in earlier development commits are included.

Tests: +2 (default-branch PR skip; multi-commit TODO scan). 771 unit pass.
- Log an INFO line before the best-effort git push so the push is visible in loop output.
- Drop the undocumented GITHUB_PR_TITLE override; PR title comes from the tracked issue
  title (falling back to a generated title). Updates the PR-title test accordingly.
- Add a clarifying comment on the intentional double-close when --auto-close and
  --link-issue are combined (GitHub treats the post-merge close as a no-op).
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

Follow-up Review — PR 294 (commit 238c044)

All three actionable items from my previous review have been addressed. Here's the rundown:

Items resolved

1. git push logging — Fixed. _lifecycle_log "INFO" "Pushing '$branch' to origin for PR creation" is now emitted before the push, so users see it in the loop output rather than having the push happen silently.

2. GITHUB_PR_TITLE undocumented variable — Resolved by removal. The title now falls back to the issue's stored title or "Ralph: resolve issue #N". Cleaner than a hidden env var.

3. Double-close comment — Added. The comment near step 4 of lifecycle_on_completion now explicitly documents the intentional double-close when --link-issue and --auto-close are both active, and that GitHub treats the second close as a no-op by design.


One remaining minor item (non-blocking)

The issue raised about generate_progress_comment using a plain grep for the "remaining" count is still open — it still counts all unchecked items, not just the blocking ones from _count_blocking_unchecked. This means a progress comment can read "2 remaining" while Ralph is simultaneously deciding to exit because those 2 are under an Optional section. This won't break anything (it was flagged as a cosmetic confusion risk), and closing this gap would require either passing the optional-sections logic into the lifecycle lib or accepting that the progress comment is approximate. Given the scope of this PR, it's reasonable to defer to a separate cleanup if it turns out to be confusing in practice.

The test duplication for _count_blocking_unchecked between ralph_loop.sh and test_exit_detection.bats also remains, as expected — flagged as a maintenance risk but acceptable given the bats subprocess boundary constraint.


Summary

The implementation is clean, all critical review items are resolved, the test suite is comprehensive (29 lifecycle unit tests, 9 exit-detection tests for optional sections), and the graceful-degradation contract is solid throughout. This is ready to merge.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ralph_loop.sh (1)

461-505: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Forward GitHub lifecycle flags into the tmux child command.

In --monitor mode, the script launches a fresh ralph process via ralph_cmd, but the new lifecycle CLI flags parsed at Line 2799+ are never appended there. So commands like ralph --monitor --github-issue 69 --auto-close silently lose lifecycle behavior.

Suggested patch
@@
     # Forward --backup if enabled (Issue `#23`)
     if [[ "$ENABLE_BACKUP" == "true" ]]; then
         ralph_cmd="$ralph_cmd --backup"
     fi
+
+    # Forward GitHub issue lifecycle flags (Issue `#73`)
+    if [[ -n "${GITHUB_ISSUE:-}" ]]; then
+        ralph_cmd="$ralph_cmd --github-issue '$GITHUB_ISSUE'"
+    fi
+    if [[ "${COMMENT_PROGRESS:-false}" == "true" ]]; then
+        ralph_cmd="$ralph_cmd --comment-progress"
+    fi
+    if [[ -n "${COMMENT_INTERVAL:-}" && "${COMMENT_INTERVAL}" != "5" ]]; then
+        ralph_cmd="$ralph_cmd --comment-interval $COMMENT_INTERVAL"
+    fi
+    [[ "${AUTO_CLOSE:-false}" == "true" ]] && ralph_cmd="$ralph_cmd --auto-close"
+    [[ "${CLOSE_SUMMARY:-false}" == "true" ]] && ralph_cmd="$ralph_cmd --close-summary"
+    [[ "${CREATE_PR:-false}" == "true" ]] && ralph_cmd="$ralph_cmd --create-pr"
+    [[ "${LINK_ISSUE:-false}" == "true" ]] && ralph_cmd="$ralph_cmd --link-issue"
+    [[ "${DRAFT_PR:-false}" == "true" ]] && ralph_cmd="$ralph_cmd --draft-pr"
+    [[ "${CREATE_FOLLOWUPS:-false}" == "true" ]] && ralph_cmd="$ralph_cmd --create-followups"
+    if [[ -n "${FOLLOWUP_LABEL:-}" && "${FOLLOWUP_LABEL}" != "tech-debt" ]]; then
+        ralph_cmd="$ralph_cmd --followup-label '$FOLLOWUP_LABEL'"
+    fi
+    if [[ -n "${ADD_COMPLETION_LABELS:-}" ]]; then
+        local _lbl
+        IFS=',' read -ra _labels <<< "$ADD_COMPLETION_LABELS"
+        for _lbl in "${_labels[@]}"; do
+            _lbl="$(echo "$_lbl" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
+            [[ -n "$_lbl" ]] && ralph_cmd="$ralph_cmd --add-label '$_lbl'"
+        done
+    fi

Also applies to: 2799-2864

🤖 Prompt for 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.

In `@ralph_loop.sh` around lines 461 - 505, The ralph_cmd builder ignores the
GitHub lifecycle CLI flags, so when launching the tmux child the lifecycle
options (e.g., --github-issue, --auto-close and related GitHub flags) are
dropped; update the ralph_cmd construction (the block that appends flags to
ralph_cmd) to forward the lifecycle variables parsed earlier by adding
conditional appends for the GitHub lifecycle variables (check the parsed
variables such as GITHUB_ISSUE, GITHUB_AUTO_CLOSE (or AUTO_CLOSE), GITHUB_REPO,
GITHUB_OWNER, GITHUB_TOKEN, GITHUB_LABELS, etc.) in the same style as the
existing flag forwards (use --github-issue "$GITHUB_ISSUE", --auto-close when
true, and the corresponding
--github-repo/--github-owner/--github-token/--github-labels when non-default) so
the tmux-launched ralph inherits lifecycle behavior.
🧹 Nitpick comments (1)
lib/github_lifecycle.sh (1)

288-300: ⚡ Quick win

Include file paths in scan_for_todos output for actionable follow-ups.

Current extraction emits marker text only, so identical TODO strings from different files collapse in sort -u, and generated follow-up issues lose location context.

Refactor sketch
 scan_for_todos() {
     local diff
     diff=$(git diff -U0 HEAD 2>/dev/null; git diff -U0 --cached 2>/dev/null; git diff -U0 HEAD~1 HEAD 2>/dev/null)
-    printf '%s\n' "$diff" \
-        | grep -E "^\+" \
-        | grep -vE "^\+\+\+" \
-        | grep -oiE "(TODO|FIXME|HACK|XXX):?.*" \
-        | sed 's/[[:space:]]*$//' \
-        | sort -u
+    printf '%s\n' "$diff" | awk '
+        /^diff --git / { file=$4; sub("^b/","",file); next }
+        /^\+\+\+ /      { file=$2; sub("^b/","",file); next }
+        /^\+/ && $0 !~ /^\+\+\+/ {
+            line = substr($0, 2)
+            upper = toupper(line)
+            if (match(upper, /(TODO|FIXME|HACK|XXX):?.*/)) {
+                marker = substr(line, RSTART, RLENGTH)
+                sub(/[[:space:]]+$/, "", marker)
+                key = file ": " marker
+                if (!seen[key]++) print key
+            }
+        }
+    ' | sort -u
 }
🤖 Prompt for 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.

In `@lib/github_lifecycle.sh` around lines 288 - 300, The scan_for_todos function
currently extracts marker text from the unified git diff stored in the local
diff variable, but loses file context so identical TODOs across files collapse;
update scan_for_todos to parse the unified-diff headers (e.g., lines starting
with "+++ " or "diff --git") to capture the current filename while processing
added lines, and emit entries that prefix each match with the file path (and
optional line number) such as "path: marker" or "path:line: marker" instead of
just the marker text; implement this by replacing the grep/sed pipeline with an
awk (or similar) script that tracks filename changes, matches "^\+" added lines
(excluding "^\+\+\+"), extracts the TODO/FIXME/HACK/XXX token and prints the
filename plus matched text, then sort -u so deduplication is per file.
🤖 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 `@lib/github_lifecycle.sh`:
- Around line 187-211: The current initialization writes directly to
$GITHUB_LIFECYCLE_STATE_FILE which can leave a truncated/corrupt file if
interrupted; change the write to generate the jq output into a temporary file in
the same directory (e.g., tmp="${GITHUB_LIFECYCLE_STATE_FILE}.tmp.$$" or mktemp
in that directory), check jq succeeded, then atomically mv the temp file to
$GITHUB_LIFECYCLE_STATE_FILE; ensure you still call _lifecycle_log on failure
and return 1 on error — update the block around get_iso_timestamp, the jq
invocation that writes the state file, and the error handling that currently
calls _lifecycle_log so the new flow writes to temp then mv (and cleans up temp
on failure) to make initialization atomic.

---

Outside diff comments:
In `@ralph_loop.sh`:
- Around line 461-505: The ralph_cmd builder ignores the GitHub lifecycle CLI
flags, so when launching the tmux child the lifecycle options (e.g.,
--github-issue, --auto-close and related GitHub flags) are dropped; update the
ralph_cmd construction (the block that appends flags to ralph_cmd) to forward
the lifecycle variables parsed earlier by adding conditional appends for the
GitHub lifecycle variables (check the parsed variables such as GITHUB_ISSUE,
GITHUB_AUTO_CLOSE (or AUTO_CLOSE), GITHUB_REPO, GITHUB_OWNER, GITHUB_TOKEN,
GITHUB_LABELS, etc.) in the same style as the existing flag forwards (use
--github-issue "$GITHUB_ISSUE", --auto-close when true, and the corresponding
--github-repo/--github-owner/--github-token/--github-labels when non-default) so
the tmux-launched ralph inherits lifecycle behavior.

---

Nitpick comments:
In `@lib/github_lifecycle.sh`:
- Around line 288-300: The scan_for_todos function currently extracts marker
text from the unified git diff stored in the local diff variable, but loses file
context so identical TODOs across files collapse; update scan_for_todos to parse
the unified-diff headers (e.g., lines starting with "+++ " or "diff --git") to
capture the current filename while processing added lines, and emit entries that
prefix each match with the file path (and optional line number) such as "path:
marker" or "path:line: marker" instead of just the marker text; implement this
by replacing the grep/sed pipeline with an awk (or similar) script that tracks
filename changes, matches "^\+" added lines (excluding "^\+\+\+"), extracts the
TODO/FIXME/HACK/XXX token and prints the filename plus matched text, then sort
-u so deduplication is per file.
🪄 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: CHILL

Plan: Pro

Run ID: 3e324231-e935-4bc2-936b-bc3afb1959cc

📥 Commits

Reviewing files that changed from the base of the PR and between 5dcba17 and 82668e4.

📒 Files selected for processing (8)
  • CLAUDE.md
  • README.md
  • lib/github_lifecycle.sh
  • ralph_loop.sh
  • templates/fix_plan.md
  • tests/unit/test_cli_modern.bats
  • tests/unit/test_exit_detection.bats
  • tests/unit/test_github_lifecycle.bats

Comment thread lib/github_lifecycle.sh Outdated
- Major: forward GitHub lifecycle flags into the tmux child command in --monitor
  mode. Previously `ralph --monitor --github-issue 69 --auto-close` silently
  dropped all lifecycle behavior because the relaunched child command omitted the
  new flags. The inlined tmux builder in test_tmux_integration.bats is kept in
  sync, with two new forwarding tests.
- Major: make init_github_lifecycle's state write atomic (temp file + mv) so an
  interrupted init can't leave a truncated/corrupt state file.
- Nitpick: prefix scan_for_todos output with the file each marker lives in
  (POSIX awk, case-insensitive), matching the issue's follow-up template intent.

Tests: +2 tmux forwarding, scan_for_todos file-path assertion. 771 unit + 252 integration pass.
@frankbria

Copy link
Copy Markdown
Owner Author

Review feedback addressed

codex (cross-family, primary):

  • [P1] Never push the default/protected branch on --create-pr. Detect the remote default branch (plus main/master) and skip PR creation with a warning when Ralph is on it. (ebcb637/29e6b3e)
  • [P2] Follow-up TODO scan now covers the whole run — start_sha is captured at lifecycle init and the working tree is diffed from it, so TODOs in earlier development commits are included.

CodeRabbit:

  • [Major] Forward lifecycle flags in --monitor — the tmux child command was dropping the new flags, so ralph --monitor --github-issue 69 … silently lost lifecycle behavior. Now forwarded (inlined tmux builder kept in sync; +2 forwarding tests).
  • [Major] Atomic init state writeinit_github_lifecycle now writes through a temp file + mv.
  • [Nitpick] File paths in scan_for_todos — output is now "<file>: <marker>" (POSIX awk, case-insensitive), matching the issue's follow-up template intent.

claude-review (advisory):

  • ✅ Log an INFO line before the best-effort git push.
  • ✅ Dropped the undocumented GITHUB_PR_TITLE; PR title comes from the tracked issue title.
  • ✅ Added a comment on the intentional double-close when --auto-close + --link-issue are combined.

Full local suite green after all fixes: 771 unit + 252 integration + 13 e2e = 1036, 0 failures.

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

Code Review Update — PR 294

Following up on my earlier review. After re-reading the diff more carefully, I need to correct two points I raised:

Previously raised — already present in the original submission:

  • Silent git push (point 3): The push is already logged — _lifecycle_log "INFO" "⬆️ Pushing '$branch' to origin for PR creation" appears on line 547 of lib/github_lifecycle.sh, immediately before the git push call. I missed this. No action needed.
  • Double-close comment (point 4): The comment is already in place at step 4 of lifecycle_on_completion, explaining that GitHub treats the second close as a no-op and this is intentional. I missed this too. No action needed.

Still open from the previous review:

1. Duplicate _count_blocking_unchecked in the test file

The awk function is copied verbatim into tests/unit/test_exit_detection.bats (the _count_blocking_unchecked helper at lines 30–64 of that file). The comment says both copies must be kept in sync. A future fix to the algorithm needs two edits, and the only safety net is the test suite noticing the divergence. This is the same concern as before — the PR is functional and tested, but the maintenance burden is real. No blocker, but the sooner this is addressed the better.

2. generate_progress_comment "remaining" count diverges from what Ralph considers blocking

generate_progress_comment uses a plain grep -cE "^[[:space:]]*- \[ \]" for its "remaining tasks" figure. Near completion this means a progress comment may say "2 remaining" while Ralph is about to exit (those 2 are under an Optional section). A small note in the comment body — e.g., "(some items may be in optional sections and do not block completion)" — or aligning the count with _count_blocking_unchecked would prevent user confusion. Still not a blocker.


Overall: The implementation is solid — atomic state management, graceful degradation on every gh call, correct level-based optional-section propagation in the awk parser, comprehensive test suite (29 unit + 9 exit-detection + 3 CLI tests). Both features are well-integrated with the rest of Ralph's conventions. The two remaining items above are quality-of-life improvements, not correctness issues. Ready to merge once the maintainer decides how to handle them.

@frankbria frankbria merged commit c8e65df into main Jun 8, 2026
5 checks passed
@frankbria frankbria deleted the feature/issue-73-lifecycle-and-239-optional-sections branch June 8, 2026 17:38
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.

Feature Request: Add "Optional" or "Future" Section Support in fix_plan.md [P4] Phase 5.5 Issue lifecycle management and completion workflows

1 participant