Repository navigation
Conversation
🤖 AI code reviewDecision: Ready for human review Overall PR risk: Medium. The change modifies the CI review path by switching 🔎 Reviewer summaries (3)
No findings. This review is advisory — it never blocks a merge and never auto-approves. |
…run cannot swap the diff gh pr diff takes no commit, and reading the head again after it missed a push followed by a force-push back to the same commit. getChangedFiles now fetches the compare of the base and head OIDs the metadata read, the same commits the trees are checked out at, and falls back to gh pr diff only when an OID is unknown. That removes the second head read and HeadMovedError. --expect-head's note now states what was seen: the PR's head and the commit the review was requested for, or that the head is unknown.
…ore it parseValueFlag keeps the first occurrence, so a second --expect-head was ignored without a word. Releases from before the flag ignore it like any unknown argument, so the README and LLP 0007 say to pin a release that has it.
|
I pushed two fixes from a multi-model review:
In the description, the first "Change" bullet and the LLP 0008 caveat about the push and force-push now describe the old approach. Known gaps, left out of this PR:
|
Why
A workflow that reviews on a label event knows the commit the maintainer labeled, but
ecr cistarts minutes later and reviews the PR's head at that time. A push in between gets reviewed, with the workflow's secrets in place, instead of the labeled code. On fork PRs that's content no maintainer has seen (raised on expo/expo#52375).The diff had a second, smaller gap:
ecr cireads the head commit once and checks the tree out at it, butgh pr diffreturns the PR's current diff, so a push between those calls gave the agents a diff from a newer commit than the tree.Change
GitHubPRSource.getChangedFilesreads the PR's head again aftergh pr diffand throwsHeadMovedErrorwhen it isn't the OIDgetMetadataread. The check runs whenever the metadata has a head OID, with or without the new flag.ecr ci --expect-head <sha>takes a full commit hash. Both CI paths compare it with the head they read, after the break-glass check and before any model call, and stop when the head differs or is unknown.couldNotComplete, so the inline sync stays additive and the ready label goes). It posts its usual failure note for aHeadMovedErrorfrom the diff check.--scopesrun would lose the other scopes' results. The routed break-glass check now runs before the diff is fetched, so a skip note is never replaced either.--expect-head=<sha>, an empty value (a workflow expression that's empty for the event), or a short hash. An ignored flag would review an unpinned head without a word.A workflow can then pass
github.event.pull_request.head.shaon label events. expo/expo will do that in a follow-up once this is released.Test Plan
bun test(927 pass), typecheck, lint,fmt:checkandllp:checkpass.src/__tests__/github-pr-head.test.tscovers--expect-headparsing (full hash only, lowercased; the=form and an empty value are errors), the mismatch rule (an unknown head fails closed), and, through a fakegh, that the head is read again after the diff and that a moved head throwsHeadMovedError. The CI paths' use of the mismatch rule, and the order of the break-glass and head checks, aren't covered by a test that runsecr ciend to end.