Skip to content

refactor: replace /plan workflow with /triage for issue analysis and planning#816

Merged
stack72 merged 1 commit intomainfrom
triage-flow
Mar 22, 2026
Merged

refactor: replace /plan workflow with /triage for issue analysis and planning#816
stack72 merged 1 commit intomainfrom
triage-flow

Conversation

@stack72
Copy link
Copy Markdown
Contributor

@stack72 stack72 commented Mar 22, 2026

Summary

  • Replaces the issue-planner.yml workflow (/plan + /plan-update commands) with a single issue-triage.yml workflow driven by /triage
  • Adds a bug triage phase: Claude now traces through the codebase to confirm/deny bugs and identify root cause before producing an implementation plan
  • Makes /triage idempotent — re-running it reads the full comment thread for operator feedback and updates the existing triage in-place, eliminating the need for a separate /plan-update command
  • Removes duplicated code style rules from the prompt (CLAUDE.md is the source of truth) and adds missing conventions: license headers, libswamp import rule, dual output modes, design docs, integration tests

Test plan

  • Comment /triage on a bug report issue and verify it produces a triage analysis with root cause identification before the implementation plan
  • Comment /triage on a feature request issue and verify it classifies correctly and produces a plan
  • Leave feedback as a regular comment, then comment /triage again — verify it picks up the feedback and updates the existing triage comment with a revision history entry
  • Verify the triage comment starts with <!-- IMPLEMENTATION-PLAN --> marker

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Adversarial Review

Critical / High

None found.

Medium

  1. Missing pagination in gh api calls — silent data loss on issues with 30+ comments (issue-triage.yml:41 and issue-triage.yml:60)

    Both gh api calls to fetch issue comments lack the --paginate flag. GitHub's REST API returns 30 items per page by default. On an issue with more than 30 comments:

    • find-triage (line 41): If the existing triage comment is beyond page 1, it won't be found. The step will output found=false, and Claude will create a duplicate triage comment instead of updating the existing one. Each subsequent /triage will create yet another duplicate, since the search only ever sees the first 30 comments.
    • Collect issue comment thread (line 60): Maintainer feedback left after the 30th comment will be silently dropped from the context passed to Claude. The whole point of the re-triage feature is to incorporate feedback — this defeats it on active issues.

    Fix: Add --paginate to both gh api calls:

    gh api --paginate "/repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/comments" \
      --jq '...'
  2. Heredoc delimiter collision in steps.comments.outputs.thread (issue-triage.yml:63-67)

    The output is written to $GITHUB_OUTPUT using an EOF heredoc delimiter:

    echo "thread<<EOF"
    echo "$COMMENTS"
    echo "EOF"

    While $COMMENTS is JSON from jq (so newlines inside string values are \n-escaped), jq's formatted output itself contains literal newlines between JSON elements. If any comment body contains a JSON string value that, when formatted by jq, produces a line consisting of exactly EOF, the heredoc terminates early and $GITHUB_OUTPUT gets corrupted — subsequent steps would read a truncated or garbled thread.

    This is unlikely in practice (the string would need to be literally EOF as its own JSON value on its own line), but GitHub Actions recommends using a random delimiter for untrusted content.

    Fix: Use a unique delimiter:

    DELIMITER=$(openssl rand -hex 16)
    {
      echo "thread<<$DELIMITER"
      echo "$COMMENTS"
      echo "$DELIMITER"
    } >> "$GITHUB_OUTPUT"

Low

  1. Comment filter doesn't catch all /triage variants (issue-triage.yml:61)

    The jq filter excludes comments where .body == "/triage" (exact match). If someone posts a comment with trailing whitespace like "/triage " or "/triage\n", it won't be excluded and will appear in the thread passed to Claude. This is cosmetic — Claude will just see an extra /triage command in context — but it adds noise. Not worth blocking over since the workflow trigger itself also uses exact match.

  2. The marker <!-- IMPLEMENTATION-PLAN --> is shared with the now-deleted planner workflow (issue-triage.yml:42)

    Existing issues that had plan comments from the old issue-planner.yml workflow use the same <!-- IMPLEMENTATION-PLAN --> marker. Running /triage on those issues will find and overwrite the old plan comment. This is likely intentional migration behavior, but worth being aware of — any old plans will be replaced with triage output on first /triage run.

Verdict

PASS — The code is structurally sound and the consolidation from two workflows to one is a clear improvement. The missing --paginate flag (Medium #1) is the most actionable finding and would be worth fixing before or shortly after merge, but it only manifests on issues with 30+ comments, which is uncommon enough that it doesn't block.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Blocking Issues

  1. README.md references removed /plan and /plan-update commands — Lines 165-167 of README.md still describe the /plan + /plan-update workflow that this PR removes. After merge, contributors reading the README would try commands that no longer exist. Please update the README to reference /triage instead.

Suggestions (non-blocking)

  1. Heredoc EOF delimiter safety (.github/workflows/issue-triage.yml line 64) — The EOF delimiter used in the "Collect issue comment thread" step could break if any issue comment body contains a literal EOF on its own line. Consider using a more unique delimiter like SWAMP_COMMENTS_EOF.

  2. Loss of auto-triage for external issues — The old issue-triage.yml workflow automatically labeled non-maintainer issues with needs-triage and posted a welcome comment on issue open. This behavior is now completely removed (replaced with the manual /triage command). If this is intentional, no action needed — just flagging in case it was overlooked.

  3. Model version — The workflow uses claude-opus-4-5-20251101. You may want to update to a newer model ID in a follow-up.

Overall

The refactoring from split /plan + /plan-update into a single idempotent /triage command is a solid improvement — cleaner, less duplication, and the bug triage phase is a nice addition. The prompt is well-structured with clear phases. The only blocking issue is the stale README documentation.

…planning

## Summary

- Replaces the `issue-planner.yml` workflow (`/plan` + `/plan-update` commands) with a single `issue-triage.yml` workflow driven by `/triage`
- Adds a bug triage phase: Claude now traces through the codebase to confirm/deny bugs and identify root cause before producing an implementation plan
- Makes `/triage` idempotent — re-running it reads the full comment thread for operator feedback and updates the existing triage in-place, eliminating the need for a separate `/plan-update` command
- Removes duplicated code style rules from the prompt (CLAUDE.md is the source of truth) and adds missing conventions: license headers, libswamp import rule, dual output modes, design docs, integration tests

## Test plan

- [ ] Comment `/triage` on a bug report issue and verify it produces a triage analysis with root cause identification before the implementation plan
- [ ] Comment `/triage` on a feature request issue and verify it classifies correctly and produces a plan
- [ ] Leave feedback as a regular comment, then comment `/triage` again — verify it picks up the feedback and updates the existing triage comment with a revision history entry
- [ ] Verify the triage comment starts with `<!-- IMPLEMENTATION-PLAN -->` marker
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Review: Approve

This PR cleanly consolidates two workflows (/plan + /plan-update) into a single idempotent /triage command and adds a bug-verification phase. The workflow is well-structured with clear phases, proper author_association gating, and good idempotency via the <!-- IMPLEMENTATION-PLAN --> marker.

No blocking issues found.

Suggestions (non-blocking)

  1. Lost auto-triage for external contributors: The old issue-triage.yml automatically added a needs-triage label and posted a welcome comment when non-maintainers opened issues. This PR removes that behavior entirely. If that was intentional, great — just worth confirming. If not, consider adding it back as a separate job or workflow.

  2. Comment thread filtering edge case: The Collect issue comment thread step filters out comments matching . == "/triage" (exact match). If someone posts /triage with trailing whitespace or extra text, those comments would leak into the thread context. This is low-risk since the trigger itself requires an exact match, so non-exact /triage comments are unlikely to appear.

  3. GitHub API pagination: The gh api calls to fetch comments don't handle pagination. For issues with 100+ comments, this could silently drop older comments. Low-risk for now but worth noting if triage is used on long-lived issues.

🤖 Generated with Claude Code

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Adversarial Review

Medium

  1. Missing --paginate on gh api comment fetches.github/workflows/issue-triage.yml:41-42 and :60-61

    Both gh api calls that fetch issue comments lack --paginate. GitHub's REST API returns 30 items per page by default. On issues with 30+ comments:

    • find-triage (line 41-42): If the triage comment is beyond the first page, TRIAGE_COMMENT_ID will be empty, found will be false, and Claude will create a duplicate triage comment instead of updating the existing one.
    • comments (line 60-61): Maintainer feedback beyond page 1 is silently dropped, so Claude re-triages without the full context.

    Breaking example: Issue has 40 comments. Maintainer left detailed feedback at comment #35. The first /triage comment is at position #32. Re-running /triage finds neither — creates a duplicate plan and ignores the feedback.

    Fix: Add --paginate to both gh api calls. For the jq in find-triage, --paginate with --jq works correctly with gh api. For the comments step, add --paginate --slurp and adjust the jq to flatten: [.[][] | select(...)].

  2. No concurrency control.github/workflows/issue-triage.yml (top-level)

    If a maintainer comments /triage twice in quick succession (e.g., accidental double-post, or two maintainers independently), two workflow runs execute concurrently. Both find no existing triage comment → both create new ones → issue gets duplicate triage comments.

    Fix: Add a concurrency group keyed on the issue number:

    concurrency:
      group: triage-${{ github.event.issue.number }}
      cancel-in-progress: true

Low

  1. Heredoc delimiter collision in comments step.github/workflows/issue-triage.yml:64-67

    The multiline output uses EOF as the heredoc delimiter. In theory, if jq output contained a bare EOF on its own line, GITHUB_OUTPUT would be corrupted. In practice this is safe because jq JSON-encodes string values (newlines become \n literals), so a comment body containing "EOF" won't produce a bare EOF line in the output. Noting for awareness only.

  2. Removal of auto-welcome for external contributors — The old workflow auto-labeled needs-triage and posted a welcome comment for non-maintainer issues on open. The new workflow does nothing until a maintainer manually runs /triage. External contributors will see no automated acknowledgment. This appears intentional given the PR description, but worth confirming it's the desired UX.

Verdict

PASS — No critical or high severity issues. The pagination gap (Medium #1) is the most actionable finding and would cause real problems on active issues, but it's in a CI workflow with limited blast radius, not production code. The concurrency issue (Medium #2) is a standard GitHub Actions hardening concern. Both are worth fixing but do not block merge.

@stack72 stack72 merged commit 1b79568 into main Mar 22, 2026
9 checks passed
@stack72 stack72 deleted the triage-flow branch March 22, 2026 11:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant