Problem
tend-mention's handle job fails during POST-job cleanup when fired by an issue_comment on a stale PR whose head branch predates the local ./.github/actions/<setup> composite action. The Claude session itself completes successfully and uploads its artifact — the failure happens after, when GitHub Actions tries to run the POST steps of nested actions inside <setup> and re-reads the composite's action.yaml from the workspace, which by then has been switched to the stale PR branch by gh pr checkout.
#391 fixed the forward step ordering by moving uses: ./.github/actions/<setup> ahead of gh pr checkout. The current generated tend-mention.yaml (0.0.24) is:
- uses: actions/checkout@v6
with: { fetch-depth: 0, fetch-tags: true, token: ... }
- uses: ./.github/actions/tend-setup # ✅ resolves against main
- name: Check out PR branch
run: gh pr checkout "$PR_NUMBER" # switches workspace to PR tree
- uses: max-sixty/tend@0.0.24
This works at run time. But at job end, the runner walks the POST chain in reverse. The POST handler for ./.github/actions/tend-setup re-opens the composite from the workspace path (<workspace>/.github/actions/tend-setup/action.yaml) — and if the PR branch lacks that path, it errors:
##[error]Can't find 'action.yml', 'action.yaml' or 'Dockerfile' under '/home/runner/work/<repo>/<repo>/.github/actions/tend-setup'. Did you forget to run actions/checkout before running your local action?
The error fires because nested actions inside the composite — at minimum Swatinem/rust-cache@v2 — have real POST steps the runner needs to dispatch.
Evidence
PRQL/prql, run 25987714522 (2026-05-17):
- Triggered by
issue_comment on #5374 (Dependabot notify 7.0.0 → 8.2.0, opened 2025-09-12 — well before tend was added to PRQL on 2026-04-30 in #5727).
gh pr checkout 5374 switched workspace to dependabot/cargo/notify-8.2.0. That branch has no .github/actions/tend-setup — confirmed via gh api repos/PRQL/prql/contents/.github/actions/tend-setup?ref=dependabot/cargo/notify-8.2.0 → 404.
- The Claude session exited silently (self-loop guard, correct behaviour) and uploaded
claude-session-logs-6b8f824a.zip (36 KB).
- Then POST cleanup fired the error above. The job's
conclusion is failure despite the session being correct.
Sibling run 25987714377 at the same minute, for #5543 (dependabot/cargo/ariadne-0.6.0 — a branch that does contain .github/actions/tend-setup), succeeded cleanly. Same workflow, same code paths — the only difference is whether the PR's head tree carries the action directory.
Why this matters
- Every consumer with a
<setup> composite under .github/actions/ will hit this on any sufficiently old PR (long-lived feature branches, dependabot PRs that pre-date tend adoption, fork PRs not rebased).
- Failure is silent in the sense that the agent did its job correctly, but the run shows red on the PR's status rollup and looks indistinguishable from a real failure to a maintainer reading their CI dashboard.
- For PRQL specifically, the bot now needs maintainer attention on a comment thread where it actually did the right thing.
Possible fixes
Listing options without picking a winner — each has tradeoffs the maintainer is better placed to judge:
- Restore default-branch checkout after the session. Add a
post: step (or always() step before tend's own post chain) that does a git checkout origin/<default> of just the .github/actions/<setup>/ path, so the cleanup walker can find the action file. Smallest blast radius.
- Copy the action dir to a stable location. Before
gh pr checkout, copy .github/actions/<setup>/ to e.g. $RUNNER_TEMP/tend-setup/ and rewrite the workflow's uses: to that path. Defeats the issue but rewrites the action's resolution path.
- Ship
<setup> as a remote action, not a local composite. Resolves identically across all consumers; biggest change to the install-tend flow.
Same fix applies symmetrically to tend-review if/when it grows a gh pr checkout after the setup step (referenced as out-of-scope in #396).
Related
Problem
tend-mention'shandlejob fails during POST-job cleanup when fired by anissue_commenton a stale PR whose head branch predates the local./.github/actions/<setup>composite action. The Claude session itself completes successfully and uploads its artifact — the failure happens after, when GitHub Actions tries to run the POST steps of nested actions inside<setup>and re-reads the composite'saction.yamlfrom the workspace, which by then has been switched to the stale PR branch bygh pr checkout.#391 fixed the forward step ordering by moving
uses: ./.github/actions/<setup>ahead ofgh pr checkout. The current generatedtend-mention.yaml(0.0.24) is:This works at run time. But at job end, the runner walks the POST chain in reverse. The POST handler for
./.github/actions/tend-setupre-opens the composite from the workspace path (<workspace>/.github/actions/tend-setup/action.yaml) — and if the PR branch lacks that path, it errors:The error fires because nested actions inside the composite — at minimum
Swatinem/rust-cache@v2— have real POST steps the runner needs to dispatch.Evidence
PRQL/prql, run 25987714522 (2026-05-17):
issue_commenton #5374 (Dependabotnotify 7.0.0 → 8.2.0, opened 2025-09-12 — well before tend was added to PRQL on 2026-04-30 in #5727).gh pr checkout 5374switched workspace todependabot/cargo/notify-8.2.0. That branch has no.github/actions/tend-setup— confirmed viagh api repos/PRQL/prql/contents/.github/actions/tend-setup?ref=dependabot/cargo/notify-8.2.0→ 404.claude-session-logs-6b8f824a.zip(36 KB).conclusionisfailuredespite the session being correct.Sibling run 25987714377 at the same minute, for #5543 (
dependabot/cargo/ariadne-0.6.0— a branch that does contain.github/actions/tend-setup), succeeded cleanly. Same workflow, same code paths — the only difference is whether the PR's head tree carries the action directory.Why this matters
<setup>composite under.github/actions/will hit this on any sufficiently old PR (long-lived feature branches, dependabot PRs that pre-date tend adoption, fork PRs not rebased).Possible fixes
Listing options without picking a winner — each has tradeoffs the maintainer is better placed to judge:
post:step (oralways()step before tend's own post chain) that does agit checkout origin/<default>of just the.github/actions/<setup>/path, so the cleanup walker can find the action file. Smallest blast radius.gh pr checkout, copy.github/actions/<setup>/to e.g.$RUNNER_TEMP/tend-setup/and rewrite the workflow'suses:to that path. Defeats the issue but rewrites the action's resolution path.<setup>as a remote action, not a local composite. Resolves identically across all consumers; biggest change to the install-tend flow.Same fix applies symmetrically to
tend-reviewif/when it grows agh pr checkoutafter the setup step (referenced as out-of-scope in #396).Related
tend-mention(this issue is the POST-cleanup follow-up).tend-reviewas remaining but didn't cover the POST-cleanup path.