Pull Request Review Loop
Trackers: pm-hq28, pm-0fxa, pm-zpwfzy, pm-cp5pbo, pm-8we38i
Use scripts/reviews/pr-review-loop.mjs to inventory every GitHub pull-request
conversation surface before deciding that review is complete. The inventory includes
top-level comments, submitted reviews, inline review threads, edited timestamps,
reaction state, thread resolution, outdated markers, and the reviewed head SHA.
GitHub command responses have a 64 MiB transport bound and fail visibly on overflow; an overflow never certifies a complete inventory. Acknowledgement lookups retain every page but project only comment IDs, bodies, and reply-parent IDs before capture, avoiding repeated diff hunks that are irrelevant to marker matching.
node scripts/reviews/pr-review-loop.mjs inventory --pr 123 > /tmp/pr-123-review-inventory.json
node scripts/reviews/pr-review-loop.mjs watch --pr 123 --interval 30 > /tmp/pr-123-review-inventory.json
node scripts/reviews/pr-review-loop.mjs watch --pr 123 --phase reviews --interval 30 > /tmp/pr-123-full-review-inventory.json
node scripts/reviews/pr-review-loop.mjs react --node-id IC_kw... --reaction THUMBS_UP
node scripts/reviews/pr-review-loop.mjs acknowledge --pr 123 --node-id PRR_kw... --revision '<revision>' --reaction THUMBS_UP --body "CodeRabbit feedback implemented: https://github.com/owner/repo/pull/123#pullrequestreview-456. The suggested edge case is covered by test X."
node scripts/reviews/pr-review-loop.mjs reply-inline --pr 123 --comment-id 456 --body "Addressed in abc123."
node scripts/reviews/pr-review-loop.mjs acknowledge-inline --pr 123 --comment-id 456 --node-id PRRC_kw... --revision '<revision>' --reaction THUMBS_UP --body "Addressed in abc123."
Choose THUMBS_UP when feedback is useful or correct and THUMBS_DOWN when a
finding is materially incorrect. Use acknowledge-inline so the reaction and
explanation land on the actual review comment and its thread. GitHub does not expose
a reply thread for top-level PR conversation comments or submitted review summaries.
Use acknowledge for those surfaces: its PR comment must identify the bot, link the
exact GitHub artifact, and explain whether the feedback was implemented or declined.
That keeps the response auditable without pretending GitHub created a direct thread.
The command adds a hidden artifact marker and reuses an existing marked comment on
retry, so a lost response cannot create duplicate acknowledgements. It reports a
partial result and exits unsuccessfully when either the comment or reaction write
fails, allowing the missing write to be retried safely.
Each comment and review also carries a revision: a SHA-256 identity of its
body and review state. Compare these identities after each completed check watch
and immediately before merge. A changed body or review verdict needs fresh
triage even when its node ID already has an acknowledgement. Reaction timestamp
changes alone do not create a new revision. Pass the observed revision to both
acknowledge and acknowledge-inline with --revision <revision>; their hidden
markers then distinguish revised feedback and suppress duplicate retry replies
for that same revision. Inline markers are matched only within the selected
reply thread. Legacy calls without the flag retain their existing behavior.
After every push or reviewer retrigger, run watch. Its default checks phase
delegates waiting to gh pr checks --watch --fail-fast, returning the complete
exact-head conversation inventory as soon as a check fails, even while an optional
reviewer remains pending. Fix that failure before starting another wait. Use
--phase reviews for the separate blocking review-completion phase: it delegates
to gh pr checks --watch without fail-fast and waits for every emitted check.
Both phases record pendingChecks and unavailableChecks from the final rollup,
including names, states, URLs and whether each context is required. Neutral,
skipped, canceled and other unavailable signals do not establish review approval;
inspect the retained conversations for provider quota or service limitations.
Pending checks prevent a successful receipt even if GitHub reports CLEAN.
This behavior is tracked by pm-jm7m3o.
Native watch success covers emitted checks only: a required provider may
never emit its context. The helper unions classic branch-protection requirements
with all effective ruleset requirements and retains publisher bindings in
mergeReadiness.requiredChecks alongside requiredContexts. Bound requirements
need both a name in the head rollup and paginated exact-head check-run evidence
from the expected app. A wrong or unavailable check-run publisher remains in
missingContexts; unbound legacy contexts retain name-based presence checks.
Commit statuses expose no app identity in the rollup. Status-only bound contexts
are disclosed in publisherUnverifiable with source commit_status and rely on
GitHub's CLEAN verdict to enforce the publisher binding. If the same context is
also emitted as a check run, that run still requires exact-head app evidence.
The receipt records GitHub's mergeStateStatus independently: an attempt is
passed only when no requirement is missing and GitHub reports CLEAN.
Publisher presence does not establish a passing verdict; GitHub retains that
enforcement along with other merge requirements. Publisher evidence is tracked by
pm-5p48kf. Missing contexts and blocked or
unknown merge state remain incomplete; native watch failures remain failed.
Superseded attempts carry superseded: true and never certify readiness. Unavailable policy or status reads
fail visibly instead of certifying readiness. Successful
coverage uploads alone cannot certify a downstream provider's patch status.
The direct watch command emits its complete JSON receipt before exiting 1
for incomplete or failed, and exits 0 only for passed. Shell automation
can therefore stop on the exit status while retaining all findings for triage.
A failed check is still an actionable signal: watch records the failed outcome
and returns all findings instead of aborting before inventory. A fail-fast receipt
does not establish completion of pending reviews; the explicit review phase and
final inventory retain that separate obligation.
If the PR head or target branch changes during the wait or final readiness read,
the helper watches the new target, up to three consecutive attempts, before
returning exact-head state. It does not poll an absent required provider status.
A review pass is complete only when every bot surface in that inventory has been
handled appropriately, every actionable thread is resolved, and required checks
have completed successfully.
Do not use timed sleeps or repeated inventory polling while hosted checks and bot
reviews run. Let watch block on the GitHub checks once, then act on the returned
pullRequest.headRefOid, check outcomes, comments, reviews, and review threads.
From docs/PR_REVIEW_LOOP.md in pm 2026.11.13. View on GitHub