diff --git a/.github/workflows/claude-implement.yml b/.github/workflows/claude-implement.yml index 35542b4b5..4923a09f4 100644 --- a/.github/workflows/claude-implement.yml +++ b/.github/workflows/claude-implement.yml @@ -106,7 +106,7 @@ jobs: claude_args: | --max-turns 150 --model claude-sonnet-5 - --allowedTools "Bash(pnpm install:*),Bash(pnpm run:*),Bash(pnpm test:*),Bash(pnpm exec:*),Bash(pnpm --filter:*),Bash(pnpm ls:*),Bash(pnpm why:*),Bash(node:*),Bash(git status:*),Bash(git diff:*),Bash(git log:*),Bash(git show:*),Bash(git checkout:*),Bash(git switch:*),Bash(git branch:*),Bash(git add:*),Bash(git commit:*),Bash(git push:*),Bash(git config:*),Bash(mkdir:*),Bash(gh issue view:*),Bash(gh issue comment:*),Bash(gh pr create:*),Bash(gh pr view:*),Bash(gh pr edit:*),Bash(gh pr diff:*),Bash(gh pr checks:*)" + --allowedTools "Bash(pnpm install:*),Bash(pnpm run:*),Bash(pnpm test:*),Bash(pnpm exec:*),Bash(pnpm --filter:*),Bash(pnpm ls:*),Bash(pnpm why:*),Bash(node:*),Bash(rg:*),Bash(grep:*),Bash(cat:*),Bash(sed:*),Bash(ls:*),Bash(head:*),Bash(tail:*),Bash(wc:*),Bash(find:*),Bash(git status:*),Bash(git diff:*),Bash(git log:*),Bash(git show:*),Bash(git checkout:*),Bash(git switch:*),Bash(git branch:*),Bash(git add:*),Bash(git commit:*),Bash(git push:*),Bash(git config:*),Bash(mkdir:*),Bash(gh issue view:*),Bash(gh issue comment:*),Bash(gh pr create:*),Bash(gh pr view:*),Bash(gh pr edit:*),Bash(gh pr diff:*),Bash(gh pr checks:*)" prompt: | REPO: ${{ github.repository }} ISSUE NUMBER: ${{ github.event.issue.number }} @@ -174,6 +174,20 @@ jobs: to main, and never write "@claude" or "@coderabbitai" in any comment, commit message, or PR text. + # Observability: the action writes a full turn-by-turn stream (every + # tool call, and every permission denial) to this file. Upload it so a + # failed/thrashing run is diagnosable after the fact — the Actions log + # itself only carries the init + final result. `always()` so it is kept + # even when the Claude step fails (exactly when it is needed). + - name: Upload Claude execution log + if: always() && steps.perm.outputs.allowed == 'true' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: claude-implement-log-${{ github.event.issue.number }} + path: ${{ runner.temp }}/claude-execution-output.json + if-no-files-found: ignore + retention-days: 14 + # Optional second reviewer (repo variable AI_LOOP_COPILOT=true). # Copilot's automatic-review ruleset skips bot-authored PRs on personal # repos, so the review must be requested explicitly. diff --git a/.github/workflows/claude-pr-loop.yml b/.github/workflows/claude-pr-loop.yml index 2786bac99..c1fcdfb9e 100644 --- a/.github/workflows/claude-pr-loop.yml +++ b/.github/workflows/claude-pr-loop.yml @@ -421,6 +421,20 @@ jobs: (every remaining thread is refuted), say so in the summary comment and stop — do not make cosmetic commits. + # Observability: the action writes a full turn-by-turn stream (every + # tool call, and every permission denial) to this file. Upload it so a + # failed/thrashing fix pass is diagnosable after the fact — the Actions + # log itself only carries the init + final result. `always()` so it is + # kept even when the fix step fails (exactly when it is needed). + - name: Upload Claude execution log + if: always() && steps.claude.conclusion != 'skipped' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: claude-fix-log-pr${{ needs.gate.outputs.pr }}-iter${{ needs.gate.outputs.iteration }} + path: ${{ runner.temp }}/claude-execution-output.json + if-no-files-found: ignore + retention-days: 14 + # No push + threads still open would stall the loop forever (no event # fires). End in a named state instead. - name: Terminal state check