Skip to content

fix: re-read the pull request immediately before landing it - #15

Closed
kim-em wants to merge 1 commit into
mainfrom
fix/recheck-pr-before-landing
Closed

kim-em wants to merge 1 commit into
mainfrom
fix/recheck-pr-before-landing

Conversation

@kim-em

@kim-em kim-em commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

This PR closes a window between validation and landing in which a pull request can be closed and land anyway.

state is established once, during collection, and check_provenance refuses on it there. Everything afterwards trusts that snapshot: the land step re-reads only the tree of the pinned head and main's ref during the compare-and-swap, never the pull request. A report closed while the run was validating is therefore still landed.

That matters because closing one is exactly how a superseded report is retired. The cursor advances to the report somebody deliberately discarded, and the replacement that displaced it is orphaned -- permanently, since its from_sha no longer matches and the gate's append check can never pass again.

The window was academic while only a human ever closed these; it needed someone to close a pull request in the precise minutes a gate run was in flight. It is not academic now that the planner sweeps an area's stranded reports on a schedule, which was added in #13. A routine close now races a routine landing.

So: check as late as possible, immediately before the compare-and-swap, that the pull request is still open, still at the validated head, still targeting main, and still not a draft. A run that finds otherwise reports landed=false and exits cleanly -- the same benign non-landing as losing the compare-and-swap, which the surrounding step already handles.

This deliberately does not reintroduce the pull request as an input to what gets written, which is the property the explicit commit construction exists to protect. The tree and the parent still come from the two pinned SHAs. Nothing read here can cause a landing, only prevent one, so a forged answer can at worst fail to stop a report that was already fully validated: read to refuse, never to authorise. An unreadable answer refuses too, matching the fail-closed idiom used everywhere else in the gate.

Behaviour was exercised against all six states -- unchanged, closed, head moved, retargeted, converted to draft, and unreadable -- and the --jq shape checked against live open and closed pull requests.

Found by an adversarial review of #13.

🤖 Prepared with Claude Code

`state` was established during collection and everything after it trusted that snapshot, so a
pull request closed while the run was validating still landed. Closing one is exactly how a
superseded report is retired, so the cursor would advance to the report somebody deliberately
discarded and orphan the replacement that displaced it -- and the replacement can never append
again, because the cursor has moved past it.

The window was academic while only a human ever closed these. It is not, now that the planner
sweeps an area's stranded reports on a schedule: a routine close races a routine landing.

Check as late as possible, immediately before the compare-and-swap, that the pull request is still
open, still at the validated head, still targeting `main`, and still not a draft. A run that finds
otherwise reports `landed=false` and exits cleanly, the same benign non-landing as losing the
compare-and-swap.

This does not reintroduce the pull request as an input to what gets written, which is the property
the explicit commit construction exists to protect. The tree and the parent still come from the two
pinned SHAs; nothing read here can cause a landing, only prevent one. A forged answer can at worst
fail to stop a report that was already fully validated. Read to refuse, never to authorise. An
unreadable answer refuses too, as everywhere else in this gate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JedNDof6uYKixz6MvtZzCX
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.

1 participant