From 1162372ca3e6c684ab60aa001f52315c02bb0238 Mon Sep 17 00:00:00 2001 From: Adnaan Badr Date: Mon, 20 Jul 2026 00:57:18 +0000 Subject: [PATCH 1/2] ci(review): keep the review run log so failures are diagnosable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the review job fails, the job log reports only the aggregate result — is_error: true alongside a permission_denials_count — and never names the tool that was denied. That is the one fact needed to fix it, and it lives in the execution output file, which is written to the runner temp dir and discarded with the runner. Diagnosing the current failures ruled out three plausible causes and confirmed none: auth is fine (the run initializes and bills), quota is fine (it spent real budget across 4 turns), and the action version is unchanged (the v1 tag has not moved since before the last green run). The denial itself is all that is left, and it is the part not recorded. Upload it unconditionally. Re-triggering a run is cheap but reproducing one is not: which tool the model reaches for varies per PR, so a failure not captured when it happens may not recur on demand. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01Ui2cwpeGkrUfRt8rh2FgGG --- .github/workflows/claude-code-review.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index b5e8cfd..a40bc80 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -42,3 +42,20 @@ jobs: # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md # or https://code.claude.com/docs/en/cli-reference for available options + # The run's turn-by-turn log, kept whatever the outcome. When the review + # fails, the job log reports only the aggregate — `is_error: true` with a + # `permission_denials_count` — and never names the tool that was denied, + # which is the one fact needed to fix it. That detail lives in this file, + # written to the runner's temp dir and otherwise discarded with the runner. + # Runs are cheap to re-trigger but not to reproduce: which tool the model + # reaches for varies per PR, so a failure not captured when it happens may + # not recur on demand. + - name: Upload review execution log + if: always() + uses: actions/upload-artifact@v4 + with: + name: claude-review-execution-log + path: ${{ steps.claude-review.outputs.execution_file }} + if-no-files-found: warn + retention-days: 14 + From 497069488758030ce46f28afe1b0c665245b1b13 Mon Sep 17 00:00:00 2001 From: Adnaan Badr Date: Mon, 20 Jul 2026 01:12:08 +0000 Subject: [PATCH 2/2] fix(ci): fall back to the temp path when the review step fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upload added in the parent commit produced no artifact on the very first failing run it was meant to capture. The job log showed the step running with an empty path: with: name: claude-review-execution-log if-no-files-found: warn A step that fails never sets its outputs, so steps.claude-review.outputs .execution_file is empty in exactly the case this upload exists for — it would only ever have captured the runs that did not need capturing. Fall back to the action documented temp path, which is where it writes the file regardless of outcome. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01Ui2cwpeGkrUfRt8rh2FgGG --- .github/workflows/claude-code-review.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index a40bc80..5419ca0 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -55,7 +55,10 @@ jobs: uses: actions/upload-artifact@v4 with: name: claude-review-execution-log - path: ${{ steps.claude-review.outputs.execution_file }} + # Falls back to the action's documented temp path: a step that FAILED + # never sets its outputs, so execution_file is empty in exactly the + # case this upload exists for. + path: ${{ steps.claude-review.outputs.execution_file || format('{0}/claude-execution-output.json', runner.temp) }} if-no-files-found: warn retention-days: 14