Repository navigation
tend-review drops the verdict on every draft-to-ready PR: the sandbox has no $GITHUB_EVENT_PATH #665
Description
Activity
Triage: this is a permission request awaiting a yes/no, not a repo-local bug —
review_preflight.pyships inside the pinnedmax-sixty/tend/claude@0.2.7action, so there is nothing in this checkout to fix. Three things I verified that bear on the decision, and one correction to the framing above.The root cause is live in this session, not specific to the review workflow. This triage run sees
GITHUB_EVENT_PATHset and unreadable, and/home/runner/workabsent (ls: cannot access '/home/runner/work': No such file or directory). Every tend session in the sandbox is in the same state, so_event_forces_review()returnsFalseunconditionally for all of them — #655 was not an unlucky run.A second instance, independent of #655. #642 flipped to ready at
2026-09-14T22:26:13Z; run 34904096802 fired two seconds later on that event against the PR's headcddbfd6bd33764cc2542bd1effb1e25288c603c9, concludedsuccess, and posted nothing. The PR merged 5.5 minutes after that carrying only the draft-modeCOMMENTEDreview. Across the last 20 PRs the soleAPPROVEDfrom the bot is #655's, which I placed by hand.Correction to my title: it is not every draft-to-ready PR.
already_reviewedkeys on a bot review standing at the current head, so any push after the ready flip moves the head,at_headgoes back toNone, and the next run posts normally — #659 shows that shape, a draft review followed by three ordinary ones. The verdict is lost precisely whenready_for_reviewis the last event before merge, which is the common case for a clean Renovate bump and the reason this reads as intermittent rather than total. The upstream body should say that, because the symptom as titled will not reproduce for anyone who pushes after marking ready.The narrower alternative is as expensive as described. This repo's
tend-review.yamlpasses no event data into the agent step — the prompt is/tend-ci-runner:review ${{ github.event.pull_request.number }}and nothing else — so aTEND_EVENT_ACTIONenv var really does require regenerating the workflow in every adopter repo. The API-derived condition needs no workflow change anywhere.Nothing matching this exists upstream: searches of
max-sixty/tendforGITHUB_EVENT_PATH,ready_for_review draft, anddraft-reviewturn up no open or closed issue on the gate.So the ask stands unchanged — OK to file at
max-sixty/tend?Resolved — the sandbox now mounts the runner's
_temp, so_event_forces_review()reads the event file and the draft → ready verdict lands.The environment changed, not the upstream code:
plugins/tend-ci-runner/scripts/review_preflight.pystill carries the same_event_forces_review()and the same silentexcept OSError. What is different is that/home/runner/work/_temp/_github_workflow/event.jsonnow exists and parses inside the agent sandbox — this nightly session read it and got{organization, repository, schedule, workflow}, the correct shape for ascheduleevent with noactionkey, where the September runs found/home/runner/workmissing entirely.#754 is the end-to-end confirmation, and it is the exact path this issue said was broken:
Time (UTC) Event 00:34:04 draft-mode COMMENTEDreview carrying<!-- tend:draft-review -->01:09:37 ready_for_reviewby nedtwigg01:09:39 tend-reviewrun 35805139428 fires on that event01:13:04 APPROVEDreview posted, no draft markerNo hand-run
gh apibypass was involved. #750 and #757 show the same draft-marker → non-draft replacement.Closing, and withdrawing the ask to file upstream. Two points from the analysis survive the fix and would still be worth reporting if they ever bite: the gate fails closed and logs nothing when the event file is unreadable, which is why this went unnoticed for weeks; and it cannot recover a
ready_for_reviewevent lost or coalesced by the concurrency queue, since it reads the event rather than deriving the state fromisDraftplus the standing review'sdraft_mode. Neither is observable here today. If the verdict starts dropping again I will re-derive from this thread and ask before filing.
tend-reviewskips the verdict on every PR that goes draft → ready, becausethe sandbox cannot read
$GITHUB_EVENT_PATH. Asking before I file this atmax-sixty/tend.
What happens
tend-review's draft mode posts a COMMENT carrying the hidden marker<!-- tend:draft-review -->, and the marker is what lets a later run replacethat COMMENT with a real verdict once the PR is marked ready. Both halves of
the replacement are gated on
_event_forces_review()inplugins/tend-ci-runner/scripts/review_preflight.py:In the agent sandbox
GITHUB_EVENT_PATHis set to/home/runner/work/_temp/_github_workflow/event.json, and/home/runner/workdoes not exist — the runner's
_tempis not mounted. Theexcept OSErrorswallows the
FileNotFoundError, so the function returnsFalseon everyrun,
ready_for_reviewincluded. Two consequences:startreportsalready_reviewed: true, so the skill's Pre-flightchecks step tells the run to finish without posting.
postskips withalready carries a COMMENTED review, so the APPROVEcannot land even if the run gets that far.
This is not a corner case here: AGENTS.md says "Open every PR as a draft",
so draft → ready is the normal path for every PR in this repo, and the review
that matters is the one being dropped.
Evidence
#655 — a clean Renovate cargo
bump. The draft review landed at 16:39:03Z,
ready_for_reviewat 16:39:45Z,and this run
(34996406538)
fired on that event and got:
I verified the event file is absent rather than merely unreadable
(
ls: cannot access '/home/runner/work': No such file or directory), did thefull review by hand, and posted the APPROVE with a direct
gh apicall afterre-checking that the PR was open, non-draft, and still at the head I read.
That bypass is not something a session should be doing routinely, which is
why I want the gate fixed upstream.
Proposed fix
Derive the condition from the API data the script already has, instead of from
the event file. "Not a draft, and the review standing at head is a draft-mode
one" is exactly the state the marker exists to encode, and it needs no event:
startalready readsinitial["isDraft"];postwould needisDraftaddedto its
_pr_view(pr, repo, "headRefOid,state")projection. This also fixesthe case where the
ready_for_reviewevent is lost or coalesced by theconcurrency queue, which the event check cannot recover from.
The narrower alternative is to keep the event check and feed it from the
environment — have
tend initemitTEND_EVENT_ACTION: ${{ github.event.action }}on the review job and read that, falling back to the event file. It needs a
workflow regeneration in every adopter repo, and it still leaves the lost-event
case broken.
Either way the silent
except OSErroris worth a log line: a gate that failsclosed on a missing file and says nothing is why this went unnoticed.
Ask
OK for me to file this at
max-sixty/tend?