fix(review-utils): stop headless review agent hanging on gh approval - #327
Conversation
…ovate The test job's `claude plugin validate` step has been failing on main with "claude native binary not installed" since Renovate auto-bumped this dep from 2.1.128 to 2.1.205 across three merged PRs. mise.toml's own comment already documented "Avoid 2.1.146+ which ships a broken native-binary install regardless" — nothing enforced it, so Renovate walked straight through the ceiling. Revert to the pinned-good 2.1.128 and add a renovate.json packageRule to disable updates for this dep, so it takes a deliberate manual bump (with verification) to move past the known-broken versions again. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012gUPPPteashVoJMa4cNDD6
…sion pin My earlier commit on this branch reverted the claude-code version to 2.1.128 and blocked renovate, on the theory that 2.1.146+ broke native-binary install. CI on this PR proved that wrong: 2.1.128 hit the identical "claude native binary not installed" failure. Actual cause: mise's npm backend passes --ignore-scripts=true by default, so @anthropic-ai/claude-code's postinstall (which fetches the native binary) never runs, at any version. `allow_builds` opts this package back into running its own lifecycle scripts. Dropped the renovate block since it was guarding against a version range that was never the problem. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012gUPPPteashVoJMa4cNDD6
Skips the npm package entirely so there's no postinstall script for mise's --ignore-scripts default to block, removing the need for depends="node" + allow_builds. Same native binary, no npm involved. Also adds the renovate.json packageRules guard that the PR description already claimed existed but was never actually committed.
…oval
Agent mode never set a non-interactive permission mode (unlike tag
mode's acceptEdits), so every Bash call -- including gh -- errored
"This command requires approval" with no human to answer it headlessly.
The agent's own transcript shows 15+ retries of `gh pr view` in every
shape, ending in an AskUserQuestion call nobody could answer.
Compounding it: the real GitHub MCP server (mcp__github__*, what
review-code/SKILL.md instructs using) only gets installed by
claude-code-action's prepareMcpConfig when --allowedTools names a
mcp__github__ tool. Nothing here ever set claude_args, so it was never
installed either -- mcp_servers came back empty every run.
Sets claude_args to `--permission-mode dontAsk --allowedTools
"mcp__github__*,Bash(gh:*),Bash(git:*)"`, which both installs the MCP
server and pre-approves exactly the tools the skill needs. dontAsk
denies (never prompts for) anything outside that list, and the
existing deny rules (git push, gh pr checks, CI-status MCP tools)
still apply on top per the permission-modes docs ("deny rules... apply
in every mode").
Plugin Version PreviewPreview only — plugin versions and
|
auto runs tool calls through background safety-check classifiers instead of a static allow/deny match, while still working headlessly (no interactive prompt). Requested over dontAsk for that reason.
lint/build/test were all failing: mise-action fetches whatever mise release is latest with no pin, and it silently picked up 2026.8.4, whose aqua backend fails installing aqua:anthropics/claude-code with "builder error: relative URL without a base" -- a URL-construction bug in that release, not a transient failure (retrying the same call produces the same error every time). Pins to 2026.8.3 (last known-good) via mise-action's version input on all three jobs. Tags each with a `# renovate:` annotation + a customManagers regex entry so Renovate proposes bump PRs against this pin same as any other dependency -- getting past 2026.8.3 is then a reviewed PR with its own CI run, not a silent runtime swap.
Same fix as fix/review-agent-permission-mode (#327): mise-action fetches whatever mise release is latest with no pin, and it silently picked up 2026.8.4, whose aqua backend fails installing aqua:anthropics/claude-code (this branch's own fix) with "builder error: relative URL without a base" -- a URL-construction bug in that release, reproduced deterministically, not a transient failure. Pins to 2026.8.3 (last known-good) via mise-action's version input on all three jobs, tagged with a `# renovate:` annotation + customManagers regex entry so Renovate proposes bump PRs against it same as any other dependency. Needed here too, not just #327: this PR's own CI was failing on the exact same mise regression, independent of anything #327 does.
This reverts commit 59f3868.
- Extract the repeated "Setup mise" + "Install deps" step pair from lint/build/test into .github/actions/setup-mise-and-bun. - Drop the mise CLI version pin from this branch -- it now lives on fix/mise-claude-code-pin (#325), which needs it for its own CI regardless of this PR. - Move permission-mode into settings.permissions.defaultMode alongside the existing additionalDirectories/deny, out of claude_args. --allowedTools stays in claude_args -- it's the only thing that triggers claude-code-action's GitHub MCP server install (prepareMcpConfig/hasGitHubMcpTools), settings.permissions.allow doesn't feed that check. - Trim the run-agent/action.yaml comments down to the one fact each needs. - show_full_output: false.
Applies the same npm→aqua backend fix validated on #325 directly to this branch so #327's test job passes standalone. mise's npm backend runs with --ignore-scripts, so claude-code's postinstall script never fetches its native binary, causing "claude native binary not installed" failures in `claude plugin validate`.
Local repro of the "relative URL without a base" failure hits a different error path (sandbox proxy 403 on the GitHub releases-list call) than real CI, so it isn't reliable evidence. Capturing verbose output from the actual failing runner to find the true root cause before deciding on a fix. Will be reverted once diagnosed.
Real CI evidence (verbose mise log on this branch) shows aqua:anthropics/claude-code fails instantly with "builder error: relative URL without a base" and zero network activity — unlike jq and tilt (both plain `type: github_release` registry entries), which install fine with full HTTP activity logged. The upstream aqua-registry entry for claude-code declares the top-level package as `type: http` (never actually used directly, version_constraint: "false") and switches to `type: github_release` inside version_overrides. mise's source (src/backend/aqua.rs) shows AquaPackageType::Http builds its download URL straight from the package's (here, empty) `url` field with no HTTP call — matching the observed zero-network, instant failure. mise 2026.8.4 evidently fails to apply the version_overrides type switch and falls through to the unused Http branch. Add a local aqua registry (.mise/aqua-registry.yaml, wired in via the mise 2026.8.4 `aqua.registries` setting) that defines claude-code directly as `type: github_release`, matching the upstream override's fields but skipping the type-switching resolution path that trips the bug. This is a registry-level fix, not a mise CLI version pin.
The aqua-registry override fix in 7cb9a6f is confirmed working (lint, build, test, version-preview all green) — no longer need verbose mise output in CI.
… workaround
The aqua-registry entry for anthropics/claude-code triggers a mise 2026.8.4
bug (version_overrides type-switching) and is separately excluded from
Renovate's mise-manager tracking ("aqua packages with http package type"
are unsupported). Switching to the npm backend sidesteps both: mise's npm
backend natively supports allow_builds to approve the postinstall script
that fetches the native binary, and npm: tools are natively tracked by
Renovate's mise manager — no custom registry override or regex manager
needed.
There was a problem hiding this comment.
✅ Fix is sound; a handful of P2 cleanups worth a follow-up
- ✅ Core fix (
--allowedTools in claude_args + defaultMode: "auto") matches claude-code-action's prepareMcpConfig/hasGitHubMcpTools behavior and Claude Code's permission-mode docs; will restore the GitHub MCP server + un-prompt gh in headless mode
- ✅
mise.toml allow_builds = ["@anthropic-ai/claude-code"] is the documented mechanism for mise's npm-backend default --ignore-scripts=true; version rollback to 2.1.128 matches the pin used by sibling agent repos
- ✅
.github/actions/setup-mise-and-bun/action.yaml cleanly DRYs three copies in test.yaml with no behavioral change (mise-action's install defaults to true; cache still routed through)
⚠️ show_full_output: true → false is undiscussed in the PR body; removes the exact debugging signal that made this fix possible
⚠️ Loss of the additionalDirectories-includes-runner.temp "why" comment; next cleanup could silently break the receiver's metrics gate
⚠️ Dropped depends = "node" from the npm tool spec without noting that allow_builds is not obviously a full replacement
- ❔ PR body says
--permission-mode auto lives in claude_args; it actually lives in settings.permissions.defaultMode
- ❔ Consistency:
jdx/mise-action@v4 in the new composite is version-floated while sibling third-party actions in this repo are SHA-pinned
Click to expand for full details
--allowedTools in claude_args + defaultMode: "auto") matches claude-code-action's prepareMcpConfig/hasGitHubMcpTools behavior and Claude Code's permission-mode docs; will restore the GitHub MCP server + un-prompt gh in headless modemise.toml allow_builds = ["@anthropic-ai/claude-code"] is the documented mechanism for mise's npm-backend default --ignore-scripts=true; version rollback to 2.1.128 matches the pin used by sibling agent repos.github/actions/setup-mise-and-bun/action.yaml cleanly DRYs three copies in test.yaml with no behavioral change (mise-action's install defaults to true; cache still routed through)show_full_output: true → false is undiscussed in the PR body; removes the exact debugging signal that made this fix possibleadditionalDirectories-includes-runner.temp "why" comment; next cleanup could silently break the receiver's metrics gatedepends = "node" from the npm tool spec without noting that allow_builds is not obviously a full replacement--permission-mode auto lives in claude_args; it actually lives in settings.permissions.defaultModejdx/mise-action@v4 in the new composite is version-floated while sibling third-party actions in this repo are SHA-pinnedHow I arrived at these scores
Quality (88%) — Fix is well-diagnosed and targeted: two failure modes (permission mode + MCP server install) fixed with the minimum viable change (claude_args + defaultMode). CI-regression side-fix (allow_builds) is the documented remedy for the exact symptom, chosen after explicitly ruling out two alternatives (local aqua-registry override, native http: backend) on Renovate-manageability grounds — that's the right kind of trade-off analysis. Points off for: (1) an unrelated show_full_output: true → false flip that isn't in the PR body, (2) removing a load-bearing "why" comment about additionalDirectories, (3) minor drift between PR-description-claimed change and shipped change (--permission-mode auto vs defaultMode).
Security (N/A) — No new secret handling, no expansion of network egress, no new external dependencies. The deny list is preserved (Bash(git push:*), Bash(gh pr checks:*), mcp__github_ci__*). auto mode still routes tool calls through a classifier rather than blanket-approving — no new attack surface.
Simplicity (85%) — Fix is a handful of lines and one refactor. The refactor is a straight DRY of three duplicated blocks and doesn't over-abstract (only exposes the input that actually varies — cache). Nothing feels premature.
Confidence (80%) — I did not exercise the fix end-to-end in CI myself; I'm reading against the linked claude-code-action internals as described in the PR body, Claude Code's permission-mode docs, and mise's allow_builds behavior. The core mechanism claims all check out. The depends = "node" removal is the one item I'm least sure about — flagged accordingly (P2, not P1).
Strengths
- Root-caused from real CI transcripts, not local repro — the PR body cites the specific failing run and the specific lines in
claude-code-actionsource that produce the failure. That's exactly the standard called out inAGENTS.md-style docs for infra fixes. - Ruled out two plausible alternatives before shipping — the aqua-registry override and native
http:backend paths were both built and rejected on the correct grounds (Renovate can tracknpm:sources but notaquaw/httppackage type norhttp:backend). Documenting the dead-ends in the PR body will save the next person a day. - Preserved the receiver-vs-direct-invocation
REVIEW_METRICS_PATHcontract — didn't touch step 11/12 lifecycle logic while fixing adjacent code. - Composite action cleanly matches the pattern already established in
.github/actions/lint-files.
Improvements (see inline comments for detail)
- Revert or gate
show_full_output— see comment onaction.yaml:246. - Restore the
additionalDirectories-includes-runner.tempcomment — see comment onaction.yaml:267. - Reconsider or document dropping
depends = "node"; consider preserving the "avoid ≥2.1.146" warning inmise.toml— see comment onmise.toml:11. - Reconcile PR body wording with actual
claude_argsvalue — see comment onaction.yaml:258. - Optional: SHA-pin
jdx/mise-action@v4in the new composite for consistency — see comment onsetup-mise-and-bun/action.yaml:15.
Critical issues
None — this PR fixes a real headless-CI outage and does not introduce a regression I can identify from the diff. All feedback is P2.
Test plan check
The PR body's test plan lists the final live-review check as unchecked ([ ] Next live PR review confirms the agent can now read the PR…). This review is that check-out: I was able to fetch the PR, its files, and post inline comments via mcp__github__* tools without hitting the "This command requires approval" failure mode from the linked broken run — direct evidence the fix works end-to-end.
Recommendation
COMMENT — PR is merged and the fix is correct. Five P2 items that are worth cleaning up in a follow-up PR but none block merge in retrospect.
Follow-ups:
- P0: none
- P1: none
- P2: revert/gate
show_full_output: false(action.yaml:246) - P2: restore
additionalDirectoriesrunner.temp"why" comment (action.yaml:267) - P2: document or restore
depends = "node"on the npm tool spec; add "avoid ≥2.1.146" warning to themise.tomlcomment (mise.toml:11) - P2: reconcile PR body "
--permission-mode autoinclaude_args" claim with the actualsettings.permissions.defaultModeimplementation (action.yaml:258) - P2: SHA-pin
jdx/mise-action@v4in the new composite for consistency with the rest of the repo (setup-mise-and-bun/action.yaml:15)
References
| anthropic_api_key: ${{ inputs.anthropic-api-key }} | ||
| claude_code_oauth_token: ${{ inputs.claude-code-oauth-token }} | ||
| show_full_output: true | ||
| show_full_output: false |
There was a problem hiding this comment.
show_full_output: true → false isn't mentioned in the PR body, and the whole reason this PR exists is that the previous outage was root-caused by reading the agent's own transcript (the linked failing run's tool-call log). Turning full output off in the same PR that fixes the last silent failure removes the exact signal that made that root-cause possible.
If the intent was to trim log noise now that the agent works, consider:
- keeping
truefor at least a few real-world runs to confirm the fix behaves as expected end-to-end, then flipping later, or - exposing it as an action input (defaulting to
false) so debugging future regressions doesn't require editing this file and re-releasing the composite action.
If it was accidental (i.e. bundled from a local experiment), revert it — the diff isn't otherwise related to output verbosity.
| # whether to install the GitHub MCP server (hasGitHubMcpTools) -- settings.json | ||
| # allow rules don't feed that check. | ||
| claude_args: | | ||
| --allowedTools "mcp__github__*,Bash(gh:*),Bash(git:*)" |
There was a problem hiding this comment.
❔ P2 — PR body / code discrepancy on where permission-mode auto lives
The PR body's "Fix" section says:
Add
claude_argsto theRun Claude Codestep:--permission-mode auto --allowedTools "mcp__github__*,Bash(gh:*),Bash(git:*)"
…but the actual claude_args value below only carries --allowedTools. auto is set via settings.permissions.defaultMode: "auto" (line 267) instead. Both are functionally valid, but this is a real divergence between "the fix I'm shipping" and "what's on disk," which matters if anyone later tries to reproduce the fix in another consumer of run-agent or claude-code-action from the PR description alone.
Two nits while here:
- The inline comment above
claude_argsexplains that--allowedToolsmust be aclaude_argsflag (becauseprepareMcpConfig/hasGitHubMcpToolsreads it to decide whether to install the GitHub MCP server) — that's a great note. It would be worth adding one sentence about whydefaultModemoved tosettings.jsonrather than--permission-modeinclaude_args, so a future reader doesn't try to "consolidate" them. - Optional consistency check: the deny list still uses
settings.permissions.denywhiledefaultModeis now also there and the allow list is viaclaude_args. If there's a reason (there is — the comment above covers--allowedTools), the same reason arguably applies asymmetrically: deny rules apply in every mode per the permission-modes docs, sosettings.jsonis fine for those. Worth a one-liner sibling comment near the deny list confirming the intent so it doesn't drift.
| settings: | | ||
| { | ||
| "permissions": { | ||
| "defaultMode": "auto", |
There was a problem hiding this comment.
additionalDirectories
The comment that used to sit above settings: | is gone:
# additionalDirectories includes runner.temp because REVIEW_METRICS_PATH
# (set above) points at $RUNNER_TEMP/review-metrics.yaml, outside the
# workspace — without this the skill's mandatory metrics write is
# sandbox-denied and the receiver's metrics gate always fails.The "${{ runner.temp }}" entry inside additionalDirectories is still there (line 272), but with no explanation, and the next person who "cleans up" that list has no way to know that dropping the entry silently breaks the receiver's metrics gate. This is exactly the kind of non-obvious "why" comment that should stay.
Suggest re-adding it just above "additionalDirectories": [ (or inline next to the "${{ runner.temp }}" entry). The PR body doesn't call out removing this comment, so I suspect it got lost in the reshuffle around adding claude_args.
| # npm's postinstall script fetches the native binary; mise's npm backend | ||
| # ignores lifecycle scripts by default, so allow_builds explicitly approves | ||
| # this package's postinstall to let that download run. | ||
| "npm:@anthropic-ai/claude-code" = { version = "2.1.128", allow_builds = ["@anthropic-ai/claude-code"] } |
There was a problem hiding this comment.
depends = "node" without acknowledging it
Old line:
"npm:@anthropic-ai/claude-code" = { version = "2.1.205", depends = "node" }New line:
"npm:@anthropic-ai/claude-code" = { version = "2.1.128", allow_builds = ["@anthropic-ai/claude-code"] }The removed comment said:
depends = "node"ensures node installs first, else the binary is missing ("claude native binary not installed", which failsclaude plugin validate).
The PR body reframes the "native binary not installed" symptom as being caused by mise's default --ignore-scripts=true (which allow_builds now overrides), and treats the previous fix as based on a wrong root-cause theory. That's plausible — mise's npm: backend does require a resolvable node, so an implicit ordering is usually there — but the two mechanisms aren't mutually exclusive, and depends = "node" was cheap defense-in-depth against tool-installation race conditions.
Two concrete asks:
- Note in the PR body (or a follow-up commit) why
depends = "node"is no longer needed alongsideallow_builds, so the reasoning survives if this regresses again. The current comment only explainsallow_builds. - If there's any chance mise's npm-backend install order isn't deterministic across versions, put
depends = "node"back — it's one field, doesn't conflict withallow_builds, and it costs nothing.
Also, the version downgrade 2.1.205 → 2.1.128 isn't loudly explained in the code. The PR body does say "the last version confirmed to install its native binary correctly" and "Avoid 2.1.146+ which ships a broken native-binary install regardless" — worth preserving that "avoid ≥2.1.146" warning in the mise.toml comment so Renovate reviewers don't just click "merge" on the next auto-bump PR.
Suggested comment update:
| "npm:@anthropic-ai/claude-code" = { version = "2.1.128", allow_builds = ["@anthropic-ai/claude-code"] } | |
| # npm's postinstall script fetches the native binary; mise's npm backend | |
| # ignores lifecycle scripts by default, so allow_builds explicitly approves | |
| # this package's postinstall to let that download run. | |
| # Pinned to 2.1.128: 2.1.146+ ships a broken native-binary install | |
| # regardless of allow_builds; do not bump past 2.1.145 without re-verifying | |
| # `claude plugin validate` succeeds in CI. | |
| "npm:@anthropic-ai/claude-code" = { version = "2.1.128", allow_builds = ["@anthropic-ai/claude-code"] } |
| steps: | ||
| - name: Setup mise | ||
| uses: jdx/mise-action@v4 | ||
| with: |
There was a problem hiding this comment.
✅ Nice DRY-up — three copies of the same "mise + bun install" pair collapse into one composite. The pre-refactor lint job passed install: true to jdx/mise-action@v4; that input defaults to true upstream, so dropping it here is a no-op. No behavior change intended.
Two minor consistency nits (P2):
- SHA-pin
jdx/mise-action. Elsewhere in this repo third-party actions are pinned by SHA + tag comment (e.g.LouisBrunner/checks-action@937cbbcde3259005b50746dc91cde29098aac2ff # v3.1.0inrun-agent/action.yaml,qoomon/actions--context@e12e182be797e3476990faf801dd1b87f107f91c # v5, etc.). This composite action uses a floating@v4. The pre-refactortest.yamlwas already floating so this doesn't regress, but centralizing the mise setup here is the right moment to also lock it — otherwise upstreamv4can silently move under CI. Not blocking. bun install --frozen-lockfileis hardcoded. If any consumer of this composite ever needs--no-frozen-lockfile(e.g. a lockfile-regeneration workflow), they'd have to fork. YAGNI-fine for today; leaving a note in case that comes up.
Summary
Every AI code review run through the
review-utilsrun-agentcomposite action has been silently failing to actually read or post reviews. Confirmed on both a historical run (nsheaps/greasemonkey-scripts#54) and live onnsheaps/agents#325's own review.Root cause, straight from a failing run's own transcript (nsheaps/.ai-agent-henry run 31452327086):
claude-code-action's tag mode (triggered by an@claudemention) defaults to--permission-mode acceptEdits, but agent mode (triggered by an explicitprompt:input, which is whatrun-agentuses) sets nothing — confirmed by readingsrc/modes/agent/index.tsandsrc/modes/tag/index.tsin the pinnedclaude-code-actioncommit. Left unset, permission mode falls back to Claude Code's interactivedefault, so every Bash call — includinggh— errors"This command requires approval". The agent triedgh pr viewin ~15 different shapes (different flags,curlfallbacks, wrapper scripts,dangerouslyDisableSandbox: true), then calledAskUserQuestion("The gh CLI requires approval. How should I proceed?") — a tool built for an interactive session, with nobody there to answer it in headless CI.claude-code-actiononly installs its bundledmcp__github__*server (the onereview-code/SKILL.mdinstructs using, e.g.mcp__github__create_pending_pull_request_review) when--allowedToolsnames anmcp__github__tool (seeprepareMcpConfig/hasGitHubMcpToolsinsrc/mcp/install-mcp-server.ts).run-agent/action.yamlnever setclaude_argsat all, somcp_serverscame back empty every run — confirmed directly in the transcript's session-init line and the agent's own diagnosis: "there is nomcp__github__*MCP server registered in this session."With no working
gh, no MCP server, and no PR data, the agent gave up and wrote a fabricatedCOMMENT / 0 follow_upsmetrics file without ever reading the PR.Related: #238 — a different root cause (missing
Checks: writeon theautomation-nsheapsApp) in the same review-dispatch pipeline that also blocks AI review from working. Not fixed by this PR; flagging as related context since both land in "AI review is broken" territory.Fix
Add
claude_argsto theRun Claude Codestep:autoroutes tool calls through background safety-check classifiers instead of a static prompt/allow-deny match, so it works headlessly while still applying judgment per call. The review agent already runs on Opus (satisfies auto mode's model requirement — confirmedclaude-opus-4-7in the failing run's own transcript).denylist (Bash(gh pr checks:*),Bash(git push:*), themcp__github_ci__*tools) still applies on top — deny rules apply in every permission mode per the permission-modes docs, so this doesn't loosen anything that was intentionally blocked.mcp__github__*in--allowedToolsboth grants the tool permission and (perprepareMcpConfig) triggers installation of the actual GitHub MCP server the skill depends on.CI fix (unrelated regression, needed to get this PR's own checks green)
test/lint/buildwere failing onclaude native binary not installed— mise'snpm:@anthropic-ai/claude-codeinstall was silently skipping itspostinstallscript (the one that fetches the native binary), because mise's npm backend passes--ignore-scripts=trueby default. Root-caused via a real-CI verbose-log investigation (not just local repro) after ruling out a version-pin issue and a mise-2026.8.4 aqua-backend regression (both explored and reverted along the way — see commit history).Fix: stay on the npm backend and set
allow_builds = ["@anthropic-ai/claude-code"], which explicitly approves that package's postinstall script to run despite the default--ignore-scripts. This is the documented mechanism for this exact situation (see mise's npm backend docs, "Lifecycle Scripts"/allow_builds). Kept the version pinned at2.1.128(the last version confirmed to install its native binary correctly).This approach was chosen over two alternatives that were built and validated first, then discarded:
.mise/aqua-registry.yamloverride to work around a real mise 2026.8.4 bug in theaquabackend'sversion_overridestype-switching — worked, but Renovate's own mise-manager docs confirm it does not track "aqua packages withhttppackage type" (which is exactly how upstream'sclaude-codeaqua-registry entry is structured), so this wouldn't have kept the version Renovate-manageable.http:backend (a real pattern used byigou-io/igou-devenvfor off-registry tools) — also not natively tracked by Renovate's mise manager (httpisn't in its supported-backends list), requiring a hand-rolled# renovate:comment + custom regex manager to track it at all.npm:tools, by contrast, are natively tracked by Renovate's mise manager (npmis a supported backend, using thenpmdatasource) — so this needs no registry override and no custom Renovate config, and Renovate can continue to propose version bumps for it same as before.Test plan
yaml.safe_load)MISE_VERBOSE=1), not local repronpm:@anthropic-ai/claude-codewithallow_builds— CI run in progress on latest commit, will confirmtest/lint/buildgreengh/mcp__github__*no longer denied) and posts an actual review instead of a fabricated empty metrics fileGenerated by Claude Code