Skip to content

fix(ci): report docs-check on Claude-authored PRs - #131

Open
claude[bot] wants to merge 7 commits into
mainfrom
fix/docs-check-bot-authored-prs
Open

fix(ci): report docs-check on Claude-authored PRs#131
claude[bot] wants to merge 7 commits into
mainfrom
fix/docs-check-bot-authored-prs

Conversation

@claude

@claude claude Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Requested via Slack thread

Status: one change, read-only. The docs check has now reached a real documentation verdict on
this PR and passed — but only on a human-triggered run. The second gate is still unfixed.

Workflow-level gate fix — the required context docs-check / docs-check now reports on
PRs authored by this repo's Claude app, where before it never appeared at all. Matched on the
immutable numeric account id, not on a [bot] login substring. This part is real and durable:
it holds on every trigger, for every author.

On head 2cb77e0 the check passed with a genuine documentation verdict
verdict: PASS,
zero missing updates: "Documentation change accurately mirrors the workflow code change; no
plugin package touched so version bump rule is not applicable."
That is the first time the
required context has produced an actual docs answer on a bot-authored PR here, rather than
nothing at all or an infrastructure error.

It passed because that run was triggered by a human push. Nick's commit made github.actor
a User (wkoutre), which is what satisfied the second gate. That gate is unchanged by this
PR
— it lives in anthropics/claude-code-action, and allowed_bots is still empty in
ai-toolkit — so a run triggered by the bot fails again on the same actor check. Read the pass as
"the workflow-level fix works and the check can now produce a verdict", not as "the gate is
fixed". It is not. See Two gates.

Demonstrated on the current head. The follow-up whitespace commit 7eb5122 was pushed by
the bot, which made github.actor claude[bot] again — and docs-check / docs-check went back
to failure with Workflow initiated by non-human actor: claude (type: Bot). Nothing about the
documentation changed between 2cb77e0 and 7eb5122; only the pusher did. The docs verdict
on this PR is a function of who pushed last, not of the docs.
That is the clearest possible
statement of what is still broken, and it is why the ai-toolkit follow-up matters.

auto_fix was removed from this PR at Nick's direction. The docs check stays read-only on
automatic triggers: it reports a verdict and leaves suggestions, and never commits to or pushes
a contributor's branch. No permission, secret, or write behaviour changes here — the job's
existing contents: write and WORKFLOW_PAT predate this PR and are untouched.

Before / after

Before. Any PR opened by the repo's own agent could never be merged. The main ruleset requires the status context docs-check / docs-check, but the docs-check job skipped every bot author — and a skipped job does not report that context, so the requirement sat unsatisfied forever. There was no failing check to look at and nothing to re-run; the PR just showed mergeable_state: blocked indefinitely. PR #121 is deadlocked this way right now.

After. The job runs on the agent's PRs and reports the required context under the exact required name, so the requirement is satisfiable rather than permanently pending. Unrelated bots (Dependabot, Renovate) are still skipped, and the check itself is unchanged — nothing is bypassed or weakened.

On head 2cb77e0 the reported conclusion was success, carrying a real documentation verdict rather than an infrastructure error: PASS, zero missing updates, with the one attached suggestion being informational ("documentation already covers the change"). Process Results ran, so that verdict is genuine and not the empty-VERDICT false pass described below.

Still outstanding. That pass is not evidence the second gate is fixed, because it is not. The run that produced it was triggered by a human push, so github.actor was wkoutre (User) and the actor check never engaged. The very next commit on this branch (7eb5122, a whitespace-only prettier fix pushed by the bot) put github.actor back to claude[bot], and the same context returned to failure with Workflow initiated by non-human actor — same docs, same gate condition, different pusher. What this PR durably delivers is the workflow-level fix — the required context reports at all, under the exactly required name — which is a precondition for any docs verdict, human- or bot-triggered. Making that verdict independent of who pushed last needs a change in Uniswap/ai-toolkit, not here.

Why a skip deadlocked instead of passing

This is the non-obvious part, and it is why the usual intuition ("a skipped required job reports skipped and satisfies the rule") does not apply.

docs-check calls a reusable workflow. A job that does so reports one check per job inside that workflow, named <caller-job-id> / <inner-job-name> — hence the required docs-check / docs-check. Skip the caller and there are no inner jobs to report, so GitHub emits a single check named plain docs-check, which nothing requires. The required two-part context never appears at all, and GitHub treats a required context that never reports as still pending.

Observed directly, before and after:

PR / head PR author Run triggered by Context reported Conclusion
#121 claude[bot] wkoutre (User) docs-check (not the required name) skipped
#128 wkoutre wkoutre (User) docs-check / docs-check success
this PR, head c25b390 claude[bot] claude[bot] (Bot) docs-check / docs-check failure — inner actor gate, no docs verdict
this PR, head 2cb77e0 claude[bot] wkoutre (User) docs-check / docs-check success — real verdict, PASS
this PR, head 7eb5122 (current) claude[bot] claude[bot] (Bot) docs-check / docs-check failure — inner actor gate, no docs verdict

The name now matches the required context exactly, and the bare docs-check variant is gone. That is the behaviour change this PR delivers, and it is visible in every row where the job ran.

Row 1 is worth reading carefully: #121's most recent Claude Docs Check run was itself triggered by a human (wkoutre), and it still skipped and still reported the wrong context name. That is because the gate that skipped it is the workflow-level one, read from #121's own branch, which still carries the old [bot]-substring condition. A human trigger cannot rescue #121 until it picks up this fix — the two gates are independent and #121 is currently stopped at the first one.

The last three rows are the same branch and the same PR author, and the gate condition under test is byte-identical across all three heads — the only difference relevant to the outcome is who triggered the run. 2cb77e07eb5122 is the cleanest pair: a whitespace-only commit, no documentation change whatsoever, and the conclusion flipped from success back to failure purely because the pusher changed from a User to a Bot.

That is the sharpest available statement of what is fixed and what is not: the workflow-level if: no longer skips, so the context always reports; the inner actor gate still decides whether that report is a docs verdict or an actor rejection, and it decides per run.

How

One change, in .github/workflows/claude-docs-check.yml.

The gate condition

Before:

if: |
  github.event_name == 'workflow_dispatch' ||
  (github.event_name == 'pull_request' &&
   !contains(github.event.pull_request.user.login, '[bot]') &&
   github.event.pull_request.head.repo.full_name == github.repository)

After:

if: |
  github.event_name == 'workflow_dispatch' ||
  (github.event_name == 'pull_request' &&
   github.event.pull_request.head.repo.full_name == github.repository &&
   (github.event.pull_request.user.type != 'Bot' ||
    github.event.pull_request.user.id == 209825114))

Plus comments recording what 209825114 is.

Two gates, and only the first is in this repo

1. The workflow-level if: — decides whether the job runs at all. This caused the deadlock; this PR fixes it, durably and on every trigger, and this PR proves it.

2. anthropics/claude-code-action's own actor check — reached only once the job starts, and it rejects any bot-triggered run, whoever authored the PR:

Workflow initiated by non-human actor: claude (type: Bot).
Add bot to allowed_bots list or use '*' to allow all bots.

This PR does not fix gate 2 and does not touch it. The gate compares github.actor — the actor that triggered the run — so it is evaluated per run rather than per PR. A human push to a bot-authored PR walks straight past it, which is exactly why head 2cb77e0 produced a PASS; the next bot-triggered run on the same branch fails again on the same line, which is exactly what 7eb5122 did. Do not read the green docs check on 2cb77e0 as the gate being resolved.

No value can be passed from this repo, because both ai-toolkit reusable workflows decide allowed_bots themselves and expose no input for it:

Reusable workflow What it passes for allowed_bots Result for claude
_claude-docs-check.yml nothing — action default "" rejected (no bots allowed)
_generate-pr-metadata.yml allowed_bots: dependabot, hardcoded at line 950 rejected (not in list)

_claude-docs-check.yml declares 14 workflow_call inputs, none named allowed_bots, and neither of its two claude-code-action steps forwards one. Checked at the pinned SHA c4820d6 and at the toolkit's main and next — byte-identical, so there is no input to pass and no newer ref that helps. Nothing was guessed at here and nothing was set speculatively: there is no field in this repo that accepts the value.

I did not use '*', and did not route around the gate, because either would defeat the purpose of the PR.

What the matching code actually says

Read at the pinned action SHA 787c5a0, src/github/validation/actor.ts:

  • checkHumanActor reads githubContext.actor — i.e. github.actor, GitHub's authenticated triggering actor — and resolves its account type via octokit.users.getByUsername before consulting the allow-list, so the allow-list can only ever widen access for a non-User account.
  • isAllowedBot splits the input on commas, then lowercases and strips a trailing [bot] from both the configured entries and the actor. claude, claude[bot], and Claude[bot] are therefore one and the same entry.
  • The error string is built as actor.toLowerCase().replace(/\[bot\]$/, ""), which is why it prints claude.

So the claude vs claude[bot] spelling is a red herring: the suffix is normalised away on both sides, and the printed form is cosmetic. Had there been anywhere to put the value, either spelling would have worked.

Reading the log correctly

On a rejected run, Run Claude Docs Check (step 18) fails and Process Results is skipped, so no verdict exists — yet Set Exit Code prints ✅ Documentation check passed against an empty VERDICT. The tail of the log therefore reads as a pass when nothing was checked. Judge these runs by the step list, not the last line.

The passing run on 2cb77e0 is distinguishable on exactly that basis: steps 18 and 19 both succeeded and Set Exit Code printed VERDICT: PASS — a populated verdict, not an empty one. When quoting a green docs check as evidence, check that Process Results actually ran.

The second gate is name-based, and I could not make it otherwise

Flagging this explicitly against Nick's "nothing easily spoofable" instruction rather than letting it be discovered later: allowed_bots matches on name, and the action exposes no id-based equivalent anywhere. Within that interface there is no stronger option.

Two properties make it defensible; one does not:

  • The compared value is github.actor, populated by GitHub from the authenticated triggering actor. Nothing in a PR's branch, diff, or title can influence it.
  • The list is consulted only for actors GitHub's Users API reports as non-User, so a human registering the account claude never reaches it and gains nothing.
  • Residual risk, unfixable in that interface: if the app were renamed, or a different app were named claude, the name would match.

That asymmetry is exactly why the gate this repo does control uses the numeric id.

Which of Nick's two options this is — and why option 2 now looks stronger

This PR is option 1 (enable docs-check for this bot). It was the right first move: it is the only one of the two that lands entirely in this repo, and it is what proved where the real blocker is.

But the investigation strengthened the case for option 2, and that is worth saying plainly. The actor gate is inherited by any workflow here that wraps claude-code-action, and by only those. claude-code-review.yml invokes @uniswap/review-cli directly and references the action nowhere, so it has no actor check to satisfy. Empirically, the reviewer's Triage and AI review checks pass regardless of who triggered the run, while the two claude-code-action-based workflows pass only when a human triggered it:

Workflow Wraps claude-code-action? Bot-triggered run Human-triggered run
claude-code-review.yml (review-cli) no passes passes
claude-docs-check.yml yes fails on actor gate passes
generate-pr-title-description.yml yes fails on actor gate passes

Both claude-code-action workflows flipped from failure to success between heads c25b390 and 2cb77e0 on this PR, and both flipped straight back to failure on 7eb5122, without either workflow's logic changing on that axis — the only difference was the triggering actor. That is the dependency option 2 removes.

So option 2 does not merely relocate the docs check — it moves it onto the one execution path in this repo that is not subject to the gate, and removes a cross-repo dependency instead of adding a fix to it. The status quo it replaces is one where a merge-blocking docs verdict is contingent on a human having pushed last.

What still has to be true for option 2, and why it cannot be this PR:

  • It is not a change to this repo alone. @uniswap/review-cli lives in Uniswap/internal-tools and is consumed here as a published GitHub Packages version pin (REVIEW_CLI_VERSION, default 1.10.1). It means changing that repo, cutting a release, then bumping the pin here.
  • Deleting this workflow first would widen the outage. docs-check / docs-check is required by repo ruleset 12307596, and this repo has no ruleset-as-code (no .github/rulesets). Removing the workflow would stop the required context reporting for every PR from every author, turning a bot-only deadlock into a repo-wide one. Only an admin can retire the context; a PR cannot. Correct order: ship the capability in the CLI → admin drops the required context → then remove this workflow.
  • Capability delta to decide on. The reusable workflow is ~1,230 lines and supports suggestion modes, branch creation, and auto_commit/auto_fix, holding WORKFLOW_PAT with contents: write. The review CLI deliberately pushes nothing and runs on GITHUB_TOKEN only. Because this PR leaves the write-back path dormant, that gap stays theoretical rather than becoming something the repo depends on — which keeps option 2 open.

Recommendation. Land this PR for the workflow-level fix and the documented diagnosis, then choose one of:

  1. Short path — one small ai-toolkit change (add an allowed_bots input to _claude-docs-check.yml, forward it to both action steps; add claude to the metadata workflow's hardcoded list). Fixes docs-check and generate-metadata together, keeps the inner gate name-based.
  2. Durable path (option 2) — port the docs check into @uniswap/review-cli, have an admin swap the required context, then delete this workflow. More work, but it retires the gate, the cross-repo reusable-workflow dependency, and the fragile two-part required context in one go.

The identity check, and why it is not spoofable

The gate matches github.event.pull_request.user.id == 209825114. Values read off the live API, GET /repos/Uniswap/uniswap-ai/pulls/121.user:

Field Value
login claude[bot]
id 209825114
node_id BOT_kgDODIGtWg
type Bot
html_url https://github.com/apps/claude
avatar_url https://avatars.githubusercontent.com/in/1236702?v=4 → App id 1236702

Same id on both bot-authored PRs in this repo (#120, #121), so it is the account's stable handle and not a per-PR artifact.

Why this holds where a name does not:

  • The id is immutable and not chosen by the account holder. GitHub assigns it at creation. Renaming the account keeps the id; you cannot register an account and pick its id. A login is mutable, and contains(login, '[bot]') tests a naming convention — trust granted to a shape of string rather than to an identity.
  • The payload is written by GitHub, not by the PR author. github.event.pull_request.user is populated server-side from the authenticated actor that opened the PR. Nothing in the branch, diff, title, or commit metadata can influence it — unlike github.actor, which on some event types reflects whoever last triggered the run rather than the PR author.
  • user.type is GitHub's own account-kind field, so "is this a bot" no longer leans on the [bot] suffix either.

Considered and rejected: node_id (BOT_kgDODIGtWg) is equally immutable but opaque and no more secure; the App id 1236702 is arguably the most precise identity, but the pull_request payload does not expose it for the PR author — it appears only inside the avatar URL, and parsing a URL for it would be strictly more fragile than reading the documented numeric field.

Scope of the claim: the id proves the PR was opened by that app installation. It does not attest to branch contents, which remain author-controlled — but that is equally true of every human PR the check already runs on, so this is not a new trust surface. The fork guard is untouched, so no untrusted fork gains access to secrets.

Verifying it works

This PR is its own test case — it is authored by claude[bot], so it exercises the change on itself. docs-check / docs-check reports here; on #121 it never appeared at all. On the human-triggered head 2cb77e0 it went the whole way to a genuine documentation verdict (PASS), which is what the required context is supposed to produce and what it has never produced on a bot-authored PR in this repo before. On the bot-triggered heads c25b390 and 7eb5122 it reports failure from the inner actor gate instead. Both outcomes are the workflow-level fix working as designed; only gate 2 decides which of the two you get, and it will keep deciding that until ai-toolkit changes.

Practical consequence for merging this: because the current head was pushed by the bot, docs-check / docs-check is currently red, and the required context is satisfied-but-failing rather than pending. A human pushing any commit — or an empty one — to this branch is enough to turn it green again, as 2cb77e0 showed. That is a workaround, not a fix.

The workflow-level behaviour change is one row:

Case type id Before After
#121 claude[bot] Bot 209825114 SKIP RUN
#128 wkoutre User 13321210 RUN RUN
dependabot[bot] Bot 49699333 SKIP SKIP
renovate[bot] Bot 29139614 SKIP SKIP
human fork PR User SKIP SKIP

To check the context name on any bot-authored PR:

SHA=$(gh api repos/Uniswap/uniswap-ai/pulls/131 --jq .head.sha)
gh api "repos/Uniswap/uniswap-ai/commits/$SHA/check-runs?per_page=100" \
  --jq '.check_runs[] | select(.name | test("docs-check")) | "\(.name) :: \(.conclusion)"'

On #121 that prints docs-check :: skipped — wrong name, requirement unsatisfied. Here it prints docs-check / docs-check :: success on the human-triggered head 2cb77e0, and docs-check / docs-check :: failure on the bot-triggered heads c25b390 and 7eb5122. Either way it is the required name, so the requirement reports instead of hanging; the conclusion tells you which gate you landed on.

Checks run locally

  • actionlint v1.7.11 — the exact version zizmor.yml pins — invoked as CI does (-shellcheck=""): clean across all workflows, exit 0.
  • bunx nx format:write then bunx nx format:check: clean, exit 0. (The web-editor edit that removed auto_fix reintroduced prettier drift — a dropped blank line before one heading and two trailing blank lines — which failed Validate Installation & Build; a follow-up whitespace-only commit restores it. No semantic change.)
  • bunx markdownlint-cli2 --fix on the touched markdown: 0 errors.
  • Both auto_fix and auto_commit were read at the pinned toolkit SHA c4820d6 (_claude-docs-check.yml lines 61 and 122) to confirm that leaving both off means no write path is exercised.

Follow-ups, not done here

  • Resolve the inner actor gate — either of the two paths in the recommendation above. This is the substantive follow-up: it is what makes the docs verdict independent of who triggered the run, instead of requiring a human push to get one.
  • #121 is still deadlocked, and merging this does not free it on its own. Its branch still carries the old [bot]-substring condition, so the job keeps skipping there and the required context keeps not reporting. It needs this merged into main and picked up on that branch, and then a human-triggered run to clear gate 2 — two steps, not one.
  • Confirm WORKFLOW_PAT is populated on this repo. Passed by this call before and after this PR; the run on 2cb77e0 logged HAS_WORKFLOW_PAT: true, so it is present, though this change pushes nothing either way.
  • generate-metadata / generate-metadata behaves identically and is out of scope: it passed on the human-triggered head 2cb77e0 and fails on the bot-triggered heads, for the same actor-gate reason. Fixing the metadata workflow's hardcoded allowed_bots: dependabot in ai-toolkit clears it. It is not a required check, so it does not block merges.
  • Fork PRs hit the identical deadlock. They are still skipped by design (no secrets), so the required context never reports for them either. It has not bitten anyone because no fork PR has needed to merge, but the durable fix is to require a context that always reports rather than one that exists only when the job runs.
  • claude-code-review.yml still gates on user.login == 'claude[bot]' in three places. Not a required check, so a mis-fire skips a review rather than deadlocking a merge — lower stakes, but worth converting to the numeric id for consistency.

`docs-check / docs-check` is a required status check in the `main`
ruleset, and that two-part context name only exists while the job runs:
the job calls a reusable workflow, so GitHub reports one check per inner
job prefixed by the caller's job id. When the caller is skipped there are
no inner jobs, so a single check named `docs-check` is reported instead
and the required `docs-check / docs-check` context never reports at all.
A required context that never reports counts as pending forever, so any
bot-authored PR sat at `mergeable_state: blocked` with no failing check
to point at. PR #121 is currently deadlocked this way.

The job's `if:` skipped every bot via
`!contains(github.event.pull_request.user.login, '[bot]')`. Replace that
with a check on the immutable numeric account id so this repo's agent
PRs are documentation-checked while unrelated bots stay skipped:

    github.event.pull_request.user.type != 'Bot' ||
    github.event.pull_request.user.id == 209825114

209825114 is the `claude[bot]` account (Claude GitHub App, app id
1236702), read off the author of PRs #120 and #121. GitHub assigns that
id at account creation and it survives renames, whereas a login is
mutable and a `[bot]` suffix is a naming convention rather than an
identity. `user.type` is GitHub's own account-kind field, so Dependabot
and Renovate remain skipped without matching on that suffix.

The check itself is unchanged — it now runs and reports on bot PRs
rather than being bypassed. Fork PRs are still skipped, as they have no
access to the secrets the reusable workflow needs.
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
uniswap-ai-docs Ready Ready Preview Aug 10, 2026 7:30pm

Request Review

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

🤖 Claude PR Metadata Generation

Status: ❌ Error
Job: View workflow run


⚠️ Generation Failed

The automated PR title and description generation encountered an error.

Next Steps:

  1. Check the workflow logs for details
  2. Verify the GitHub Actions configuration
  3. Ensure the Anthropic API key is valid

You can manually set the PR title and description, or re-trigger by pushing a new commit.

@datadog-official

datadog-official Bot commented Aug 8, 2026

Copy link
Copy Markdown

Pipelines

⚠️ Warnings

🚦 2 Pipeline jobs failed

Claude Docs Check | docs-check / docs-check   View in Datadog   GitHub Actions

See error Workflow initiated by non-human actor: claude (type: Bot). Add bot to allowed_bots list or use '*' to allow all bots.

Claude: Generate PR Title &amp; Description | generate-metadata / generate-metadata   View in Datadog   GitHub Actions

See error Workflow initiated by non-human actor: claude (type: Bot). Add bot to allowed_bots list or use '*' to allow all bots.

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 7eb5122 | Docs | Datadog PR Page | Give us feedback!

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

● Reviewed · against 7eb5122 · 2026-08-10 19:38 UTC · 4 reviews · view run ↗

Note

Approved.

Fixes the workflow-level gate so docs-check / docs-check reports on Claude-authored PRs, converting merge deadlock into actionable diagnostics.

Assessment

Gate switches from login pattern matching to immutable numeric ID (209825114). Fork protection preserved; unrelated bots still skipped. auto_fix removal keeps the workflow read-only.

Partial fix: resolves the workflow-level gate but not the inner claude-code-action actor check in ai-toolkit, which still rejects bot-triggered runs. Required context now reports instead of never appearing.

Iteration history · 4 reviews
2026-08-10 19:38 UTC · ✅ approved · 0 findings · 7eb5122 · run ↗

(no findings)

2026-08-10 19:20 UTC · ✅ approved · 0 findings · 2cb77e0 · run ↗

(no findings)

2026-08-08 01:29 UTC · ✅ approved · 0 findings · c25b390 · run ↗

(no findings)

2026-08-08 01:17 UTC · ✅ approved · 0 findings · 693892c · run ↗

(no findings)

Tip

Teach the reviewer. React 👍 on findings that helped, 👎 on false positives. Reply to push back or add context — we aggregate this weekly to tune the bot.

Comment @request-claude-review to re-run.

Clearing the workflow-level `if:` was necessary but not sufficient. The
job now starts and reports the required `docs-check / docs-check` context
(the deadlock is broken), but it then fails inside
`anthropics/claude-code-action`'s own actor check:

    Workflow initiated by non-human actor: claude (type: Bot).
    Add bot to allowed_bots list or use '*' to allow all bots.

That action gates on its `allowed_bots` input, which defaults to ""
(allow no bots). This repo cannot set it: `_claude-docs-check.yml` in
Uniswap/ai-toolkit declares 14 workflow_call inputs, none of them
`allowed_bots`, and neither of its two claude-code-action steps forwards
one. Verified against the pinned SHA c4820d6 and against the toolkit's
`main` and `next`, which are byte-identical to it — so there is no input
to pass and no newer ref that helps. The fix belongs in ai-toolkit.

Document both gates in the workflow comment and in
.github/workflows/CLAUDE.md so the next person does not conclude the
workflow-level condition is the whole story, and record why the
follow-up gate is name-based: the action matches `github.actor` with
case-folding and a stripped `[bot]` suffix, consults the list only for
accounts GitHub reports as non-User, and offers no id-based equivalent.
The gate this repo does control keeps using the numeric account id.

No behaviour change; comments and docs only.
…lers

Pin down why the inner actor check cannot be satisfied from this repo, so
nobody spends another cycle looking for a value to set here.

Both ai-toolkit reusable workflows this repo calls decide `allowed_bots`
themselves and expose no input for it:

  _claude-docs-check.yml      passes nothing -> action default ""
  _generate-pr-metadata.yml   passes `allowed_bots: dependabot` (hardcoded)

So `claude` is rejected by the first because no bot is allowed, and by the
second because it is not in the list. Same actor check, same root cause,
and neither is reachable from a caller. That also explains why
generate-metadata fails on bot PRs.

Also correct a plausible-looking dead end: the error text prints the actor
as `claude` rather than `claude[bot]`, which reads like a spelling
mismatch. It is not. The action's `isAllowedBot` lowercases and strips a
trailing `[bot]` from both the configured entries and the actor, so
`claude` and `claude[bot]` are the same entry; the message just prints the
normalized form.

Record the diagnostic tell as well: on a rejected run `Run Claude Docs
Check` fails and `Process Results` is skipped, so no verdict exists, while
`Set Exit Code` still prints "Documentation check passed" against an empty
VERDICT. Reading only the last line of the log suggests the docs were
checked and passed, which is the opposite of what happened.

No behaviour change; docs only.
…n gate

The actor gate is inherited by any workflow in this repo that wraps
`anthropics/claude-code-action`, and only by those. `claude-code-review.yml`
runs `@uniswap/review-cli` directly and references the action nowhere, so
it has no actor check to satisfy.

Confirmed empirically: on the two claude[bot]-authored PRs (#121, #131) the
reviewer's `Triage` and `AI review` checks pass, while both
claude-code-action-based workflows (docs-check, generate-metadata) fail on
those same PRs.

This is a substantive argument for folding the docs check into the review
CLI rather than repairing the toolkit call, so record it next to the gate
it bears on.

No behaviour change; docs only.
github-actions[bot]
github-actions Bot previously approved these changes Aug 8, 2026

@github-actions github-actions 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.

Note

Approved — see full review in the sticky comment ↑

Set `auto_fix: true` on the `_claude-docs-check.yml` call so a FAIL verdict
is repaired and pushed instead of only reported. The toolkit runs a second
Claude pass scoped to Read/Edit/Write/Grep/Glob/Bash(git:*), commits as
`docs(claude): fix documentation issues (auto-fix)`, and pushes directly to
the PR head branch using `WORKFLOW_PAT` so the push re-triggers the check.

`auto_commit` is deliberately left dispatch-only. It is a different
mechanism — it overwrites whole files with the model's `suggested_content`
and carries no loop guard — and its commit subject does not match the
anchored regex `auto_fix`'s loop guard keys on, so enabling both would make
the two push over each other indefinitely.

Fork PRs are unaffected: the job-level `if:` already requires
`head.repo.full_name == github.repository`, and every auto-fix step inside
the reusable workflow re-checks the PR's live head repo independently.

Auto-fix is dormant on bot-authored PRs until ai-toolkit plumbs
`allowed_bots` through, because the job still fails at claude-code-action's
actor check before any verdict is produced.
@claude claude Bot changed the title fix(ci): run docs-check on claude[bot] PRs via immutable account id fix(ci): unblock docs-check on bot PRs and auto-commit doc fixes Aug 8, 2026
@wkoutre
wkoutre marked this pull request as ready for review August 10, 2026 18:45
Removes `auto_fix: true` from this change at Nick's direction.

The identity-gate fix is kept: the required context `docs-check / docs-check`
now reports on PRs authored by the Claude GitHub App, matched on the immutable
numeric account id 209825114 rather than a mutable `[bot]` login substring.
Other bots and fork PRs are still skipped.

The docs check stays read-only. It reports a verdict and leaves suggestions;
it never commits to or pushes a contributor's branch. `auto_commit` remains
manual-dispatch-only and is unchanged.

Documentation for the deadlock mechanism is retained; the section describing
auto-committing doc fixes is removed along with the feature.
@wkoutre wkoutre changed the title fix(ci): unblock docs-check on bot PRs and auto-commit doc fixes fix(ci): report docs-check on Claude-authored PRs Aug 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📚 Documentation Check ✅

Verdict: Passed

Documentation change accurately mirrors the workflow code change; no plugin package touched so version bump rule is not applicable.


This PR changes the docs-check job if condition in claude-docs-check.yml to an id-based bot check and documents the change thoroughly and accurately in .github/workflows/CLAUDE.md. No packages/plugins files changed, so no version bump required.

Suggestions (1)

💡 Inline suggestions have been posted as review comments. Click "Commit suggestion" to apply each fix directly.

  • ℹ️ .github/workflows/CLAUDE.md: documentation already covers the change

🤖 Generated by Claude Documentation Validator | Mode: suggest

github-actions[bot]
github-actions Bot previously approved these changes Aug 10, 2026

@github-actions github-actions 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.

Note

Approved — see full review in the sticky comment ↑

The web-UI edit dropped the blank line before `### Generate PR Title &
Description` in `.github/workflows/CLAUDE.md` and left a trailing blank line
at the end of that file and of `.github/workflows/claude-docs-check.yml`,
which failed `nx format:check`.

Applied via `nx format:write`; whitespace only, no semantic change.

@github-actions github-actions 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.

Note

Approved — see full review in the sticky comment ↑

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.

2 participants