wrzonance

review-remote-pr

Use when asked to review, babysit, monitor, or clean up a remote PR, including PRs in git worktrees — triggered by "/review-remote-pr", "/review-pr", "review remote PR", "babysit PR".

wrzonance 0 Updated 2h ago

Resources

2
GitHub

Install

npx skillscat add wrzonance/agent-kit/review-remote-pr

Install via the SkillsCat registry.

SKILL.md

Review Remote PR

Draft loop. Phase A: root owns CI/conflicts, materiality, fix delegation, adversarial review, publication. Phase B: user marks ready. Phase C: assess findings in one-push cycles. Human feedback is confirmation-gated.

Consent context rule: consent-bearing sends run in the consent-holding context; typed approval is context-local. Dispatched loop agents never stall waiting for consent; root/holder launches.

References are read once, batched, and never sized first. Open "$agentkit/<path>";
read "$agentkit/references.md" for paths and purposes instead of searching.
Read each named reference fully at its step, once per uninterrupted context, batching reads.
Sole re-read exception: after compaction/resume since Step 1a, if provider-rules content
was not preserved in the resumable artifact/context, re-read provider-rules.md exactly once
before Phase C. Never probe reference sizes (wc -l, stat, head); no step needs them.

Before any multi-line recipe, read "$agentkit/.shared/shell-portability.md" and execute each bash fence via its bash -c boundary.

Non-negotiables

  • Never run gh pr ready — draft-to-ready is the user's call.
  • Never trigger any provider (@coderabbitai review/full review/pause/resume, any bot command), ever.
  • Never resolve a human-touched thread, including the account gh api user returns.
  • Run the adversarial review ONCE per PR, as the LAST draft step; publish its receipt ($agentkit/review-remote-pr/scripts/post-receipt.sh) after the fix push, before handoff — incomplete without one.
  • Never bypass a repository hook (no --no-verify, core.hooksPath, piped y).
  • Batch each cycle's fixes into ONE push; cap 3 cycles, then escalate.
  • Every wait is bounded (rounds/duration/marker); no model turns on sleep + re-check.

Flags

Flag Aliases Effect
--auto-review --auto-approve Standing consent; launch stays in the consent-holding context (root default), not loops.

Read only from the invocation line, never worker prompts; the consent-holding root owns the send —
review loops do not receive or forward this flag.
--auto-review authorises exactly one thing: it is not permission to flip a PR ready, merge,
trigger a review bot, resolve a human's thread, or act without per-item confirmation.

Session decision ledger

After setup sets a stable LEDGER="$REPO_ROOT/.agent/session-ledger.ndjson", bind the ledger identity to this invocation's authorization input before recording any decision:

review_invocation_flags="auto-review=${auto_review:-false}"
normalize_run_input() {
    local value=$1
    value=${value//[^A-Za-z0-9._-]/-}
    printf '%s' "$value"
}
review_run_inputs="pr=$PR;repo=$REPO;flags=$(normalize_run_input "$review_invocation_flags")"
RUN_ID="review-pr-$(printf '%s' "$review_run_inputs" | sha256sum | cut -c1-32)"
: "$RUN_ID"

This stops replay across differently-flagged invocations. Append every human grant, steer, or review adjudication immediately with "$agentkit/.shared/scripts/session-ledger.sh" append --ledger "$LEDGER" --run-id "$RUN_ID" --skills-path "$agentkit" --procedure-set review-remote-pr --decision "$DECISION" --scope "$SCOPE" --quote "$QUOTE".
QUOTE is the verbatim quote; never put secrets in any field.
After compaction/resume, run "$agentkit/.shared/scripts/session-ledger.sh" read --ledger "$LEDGER" --run-id "$RUN_ID" and treat its output as durable.

Runtime and provider neutrality

A missing jq/python3 is blocking, never a silent "no findings":
command -v jq >/dev/null 2>&1 || { printf '%s\n' 'jq is not installed; evidence unavailable' >&2; exit 1; }
Before any GitHub body mutation, follow "$agentkit/.shared/github-body-policy.md".
Read "$agentkit/review-remote-pr/references/environment-contract.md" in full before Step 0a for the environment-contract mechanics.

Automated review provider rules

CodeRabbit and github-code-quality[bot] get provider-specific handling; other bots and humans have their
own lanes. Authoritative signals: GraphQL author.__typename == "Bot", REST author.type == "Bot", or an
exact [bot] login suffix — a login merely containing bot is human. A generic automated finding is an automated B-item, never
H; H labels are human-only. Every automated reply passes the reply-body integrity gate
($agentkit/review-remote-pr/scripts/gh-comment.sh: resolve/dismiss only on its printed stdout line + exit 0). Never resolve a
human-touched thread.

Read "$agentkit/review-remote-pr/references/provider-rules.md" in full before Step 1a — the
provider table, classifier, human gate, and settlement recipes. Reuse that loaded content in Step 5; do not re-read it.

Inputs

  • PR number (required) — passed as arg or ask once if missing
  • Repo — the contract's repo= line ($agentkit/.shared/scripts/contract-read.sh --repo-root DIR --get repo.slug; none means no GitHub origin — re-run the Step 0 preflight); override with owner/repo arg
  • Worktree — reuse the PR branch worktree if present, else the helper derives/prints <worktree-root>/pr-<PR> as $PR_WORKTREE (an output, not an input)

Resolver (run once per session)

The warm-up writes data-only .agent/cache/contract-session.env (never sourced); a changed input makes it stale until refreshed.

# Resolve the skill tree from the environment contract at the repository
# root; trust it only when it is an untracked regular file owned by this
# user -- a tracked, symlinked, or foreign-owned contract could redirect
# helper execution.
agentkit=''
contract_root="$(git rev-parse --show-toplevel 2>/dev/null)" || contract_root=''
contract="$contract_root/.agent/env-contract.txt"
if [[ -n $contract_root && -r $contract && -f $contract && ! -L $contract && -O $contract ]] &&
    ! git -C "$contract_root" ls-files --error-unmatch -- .agent/env-contract.txt > /dev/null 2>&1; then
    agentkit=$(sed -n "s/^skills= path=//p" "$contract" 2>/dev/null | head -n 1)
fi
if [[ -z $agentkit ]]; then
    printf '%s\n' 'agentkit: skills path is absent from .agent/env-contract.txt; run onboarding first' >&2
    exit 1
fi
[ -d "$agentkit/.shared/scripts" ] || { printf "%s\n" "agentkit: invalid skills path: $agentkit" >&2; exit 1; }
agentkit_provenance=ok; : "$agentkit_provenance"

Shell state is not persistent; later standalone blocks rehydrate the validated data record before their guard, and a missing or stale record fails loudly.

THE CACHE REHYDRATION (prepend to each later guarded block)

Replace STEP_0_AGENTKIT with Step 0's exact absolute skills= path; never read it from cache. The trusted reader rehydrates and validates current data.

agentkit='STEP_0_AGENTKIT'; [[ $agentkit == /* && $agentkit != STEP_0_AGENTKIT ]] || { printf '%s\n' 'replace STEP_0_AGENTKIT with the Step 0 skills path' >&2; exit 1; }; expected_agentkit=$agentkit; shared="$agentkit/.shared/scripts"; cache_reader="$agentkit/.shared/scripts/lib/contract-cache.sh"
[[ -d "$shared" && ! -L "$shared" && -O "$shared" && -f "$cache_reader" && ! -L "$cache_reader" && -O "$cache_reader" && -r "$cache_reader" && -x "$cache_reader" ]] || exit 1
contract_root=$(git rev-parse --show-toplevel) && contract_root=$(cd -P -- "$contract_root" && pwd -P) || exit 1; IFS=$'\t' read -r agentkit shared agentkit_provenance loaded_root _ < <("$cache_reader" --read-session-context --repo-root "$contract_root") && [[ $agentkit == "$expected_agentkit" && $shared == "$expected_agentkit/.shared/scripts" && $agentkit_provenance == ok && $loaded_root == "$contract_root" ]] || exit 1

Implementation-worker gate (MANDATORY for every non-exempt code change)

The PR loop orchestrates; implementation workers are sole writers for fix batches. The two allowed
exceptions are spawn unavailable and qualifying bounded inline correction. Resolve model/effort,
then — at the first fix batch, before choosing between a dispatch, a bounded inline correction, or a worker=self path, never as a pre-read — read "$agentkit/review-remote-pr/references/worker-gate.md", "$agentkit/.shared/spawn-contract.md", and "$agentkit/.shared/six-step-loop.md" in full; workers validate/commit/push, root owns PR metadata/posts.

The Loop

Repeat until exit condition met:

PHASE A — DRAFT (mechanical work; never initiate a provider review)
  0. SETUP    — enter/create the PR worktree, run agent-preflight ONCE, merge if conflicts
  1. CHECK    — one $agentkit/review-remote-pr/scripts/gh-pr-state.sh --full call: digest + durable artifacts
  1a. HUMAN   — surface human-authored content; gate every action/reply on per-item confirmation
  2. FIX CI   — diagnose, dispatch the implementation worker, review the worker's pushed diff and re-check CI and review state after its push; repeat 1–2 until green
  2a. FRESHEN — digest `base:` stale=yes? run 0b's merge recipe before the review
  2b. ADVERSARIAL — LAST draft step (CI green, base current): materiality gate, then one cross-harness review with confirmed findings fixed, or a documented verified skip
PHASE B — HANDOFF: 3. WAIT-READY — report draft-phase complete; the USER flips ready and triggers any provider review, never this skill
PHASE C — REVIEW (when provider findings land)
  3a. FRESHEN — stale `base:`? rerun 0b's merge recipe once before Step 4
  4. WAIT     — gh-pr-state.sh --wait-ci in bounded rounds; escalate, don't wait
  5. FIX      — approved human actions first (threads stay unresolved); body nitpicks + github-code-quality[bot]; each CodeRabbit thread fix/decline → reply → settle; ONE push per batch
  6. REPEAT   — while CI failures, unresolved automated threads, or unhandled findings remain (cap 3 cycles); a later provider pass may need repo config or a user trigger — report and let the user decide
  7. GROOM    — (after exit) propose Ready candidates from the Backlog

Exit condition: all CI green; all CodeRabbit/generic/Code Quality threads resolved or
auto-cleared/dismissed; all body nitpicks fixed or declined+documented; every confirmed adversarial
finding fixed or declined with a PR comment; every human-lane item has an explicit decision
(replies posted+verified, threads left unresolved). A deferred item blocks Ready to merge unless
the user says otherwise. After exit, run Backlog grooming before handing back; a stale base line means checks are not green, and any pre-retarget provider approval must surface as knowing acceptance, never silently inherited or re-pinged.

CodeRabbit's auto-approve (when enabled) needs settled replies on every thread it opened and no
failing checks — never resolve before its fresh acknowledgement. Disabled →
no formal approval ever comes; "green" is threads resolved + nitpicks handled.


Step 0: Setup (ALWAYS run first, before any local edits)

0a — Enter the PR worktree

Reuse the worktree already checked out for the PR's head branch; otherwise create a sibling one.
Never switch branches in a worktree that may belong to another issue/PR.

# >>> prepend THE RESOLVER (initial warm-up only) <<<
# At the TOP of the fence, not inside the create branch below: the reuse path
# skips that branch and still runs "$agentkit/.shared/scripts/agent-preflight.sh".
[ -d "${agentkit:-}/.shared/scripts" ] && [ "${agentkit_provenance:-}" = ok ] || { printf "%s\n" "agentkit unresolved: prepend the Step 0 resolver block" >&2; exit 1; }
if ! setup_output=$("$agentkit/review-remote-pr/scripts/pr-worktree.sh" --pr "$PR" --repo "$REPO" 2>&1); then
  printf '%s\n' "$setup_output" >&2
  printf '%s\n' 'STOP: PR worktree helper failed; no worktree output will be parsed.' >&2
  exit 1
fi
printf '%s\n' "$setup_output"
PR_WORKTREE=$(sed -n 's/^worktree=//p' <<<"$setup_output" | tail -n 1 | sed 's/ branch=.*//')
[[ -n $PR_WORKTREE ]] || { echo 'STOP: worktree helper returned no worktree path'; exit 1; }
cd "$PR_WORKTREE" || { echo "STOP: worktree missing at $PR_WORKTREE"; exit 1; }
contract_root="$(git rev-parse --show-toplevel)" || exit 1
shared="$agentkit/.shared/scripts"
[[ -x "$agentkit/.shared/scripts/contract-read.sh" ]] || { printf '%s\n' 'agentkit: contract reader is missing' >&2; exit 1; }
contract_path=$("$shared/contract-read.sh" --repo-root "$contract_root" --get skills.path) || exit 1
[[ $contract_path == "$agentkit" ]] || { printf '%s\n' 'agentkit: contract skills path mismatch' >&2; exit 1; }
"$shared/lib/contract-cache.sh" --read-session-context --repo-root "$contract_root" > /dev/null || exit 1
# The helper excludes .agent/* as local state; never git add -A.

Run all later commands from $PR_WORKTREE; commits target its PR branch. Carry the printed preflight block verbatim into workers. Follow its decision lines: project-scope=no → fix App/OAuth scope; peer-cli= <name> absent → blind same-harness fallback; git=… writable=no → expect commit-helper exit 2.

0b — Check for merge conflicts

A protected path caught in a base merge uses the commit helper's named-base affordance and reports
merge-inherited paths parked/handed off (exit 3, an attended park; exit 2 is the git-metadata elevation
handback). A hook refusal is one bounded named park: never bypass with --no-verify, core.hooksPath, an alias, or any equivalent.

MERGEABLE=$(gh pr view "$PR" --repo "$REPO" --json mergeable --jq '.mergeable'); echo "Mergeable: $MERGEABLE"

If CONFLICTING, root merges the base into the PR branch — never rebase a published branch, never
force-push it. Resolve (git checkout --ours|--theirs <path> or edit; strip markers with sed, never
python3 -c), grep-verify no <<<<<<</=======/>>>>>>> remain, then commit via
$agentkit/.shared/scripts/worktree-commit.sh and verify via $agentkit/.shared/scripts/agent-run.sh:

BASE_BRANCH=$(gh pr view "$PR" --repo "$REPO" --json baseRefName --jq '.baseRefName')
git fetch origin "$BASE_BRANCH" && git merge "origin/$BASE_BRANCH"
git diff --name-only --diff-filter=U   # resolve each listed file, then:
[ -d "${agentkit:-}/.shared/scripts" ] && [ "${agentkit_provenance:-}" = ok ] || { printf "%s\n" "agentkit unresolved: prepend THE CACHE REHYDRATION block" >&2; exit 1; }
resolved=src/example.ts   # repeat per resolved path
# harness.trailer composes a full "Co-Authored-By: ..." line already; pass it verbatim.
contract_root="$(git rev-parse --show-toplevel)"
worker_model=$("$agentkit/.shared/scripts/repo-config.sh" --repo-root "$contract_root" \
  --get AGENT_WORKER_MODEL 2>/dev/null || true)
[ -n "$worker_model" ] || { printf 'no worker model; re-run agent-preflight.sh\n' >&2; exit 1; }
worker_attribution=$("$agentkit/.shared/scripts/contract-read.sh" \
  --repo-root "$contract_root" --get harness.trailer --worker-model "$worker_model" 2>/dev/null || true)
[ -n "$worker_attribution" ] || { printf 'no harness= trailer; re-run agent-preflight.sh\n' >&2; exit 1; }
# Chained: no `set -e` here, so unchained these would push even after the commit
# helper or a verification failed -- what the rule below forbids.
"$agentkit/.shared/scripts/worktree-commit.sh" --message 'fix(example): resolve merge conflicts with the base branch' \
  --trailer "$worker_attribution" -- "$resolved" &&
"$agentkit/.shared/scripts/agent-run.sh" --cmd lint --if-declared &&
"$agentkit/.shared/scripts/agent-run.sh" --cmd test &&
git push   # upstream set in 0a; fork PRs push to the fork via gh pr checkout's config

Run only declared agent-run.sh --cmd commands, directly, no approval step: a focused suite during red/green, full suite before commit, never push without local verification. Commit-helper exit 2 needs the elevated retry. 2a/3a reuse this whenever base: reads stale=yes; a clean merge auto-commits — skip to agent-run.sh --cmd test then git push.

0c — Resolve the durable per-PR review-artifact directory

Resolve one private run directory for this PR, carried as RUN_DIR in every later block — never hand-roll a mktemp path:

[ -d "${agentkit:-}/.shared/scripts" ] && [ "${agentkit_provenance:-}" = ok ] || { printf "%s\n" "agentkit unresolved: prepend THE CACHE REHYDRATION block" >&2; exit 1; }
RUN_DIR=$("$agentkit/review-remote-pr/scripts/run-dir.sh" --pr "$PR") || exit 1
printf 'Review artifacts: %s\n' "$RUN_DIR"

Same path every session (<repo>/.agent/evidence/pr-<N>, mode 0700); falls back to ${TMPDIR:-/tmp} only when
.agent/ is unwritable. Keep it for audit. Re-set it at the top of every later block: : "${RUN_DIR:?re-set RUN_DIR to the Step 0c output; shell state does not persist}"


Step 1: Check

One helper call replaces the whole fetch-then-summarize cluster:

[ -d "${agentkit:-}/.shared/scripts" ] && [ "${agentkit_provenance:-}" = ok ] || { printf "%s\n" "agentkit unresolved: prepend THE CACHE REHYDRATION block" >&2; exit 1; }
: "${RUN_DIR:?re-set RUN_DIR to the Step 0c output; shell state does not persist}"
"$agentkit/review-remote-pr/scripts/gh-pr-state.sh" \
  --pr "$PR" --repo "$REPO" --full --tmpdir "$RUN_DIR/state"

Pass --repo explicitly. CI state is data, not an error: unlike gh pr checks (exit 8 on pending/failing), this stays exit 0; exit 1 = usage/API failure. --full writes five
PR-namespaced files under $RUN_DIR/state that Step 1a/5/6 re-read — read full bodies before
triaging
. threads: truncated=yes means paginate with after: before trusting any count.

Step 1a — surface human review content: route every item through the classifier; exclude
recognized providers, authoritative Bot/[bot] authors, and exact
<!-- review-remote-pr:agent-doc|agent-reply --> comments — not the gh api user login. Read
"$agentkit/review-remote-pr/references/provider-rules.md" for the H/B presentation formats and
wait for an explicit per-item decision before acting.

Step 1b (runs as 2b): Adversarial Review — ONCE, at the end of the draft phase

Read "$agentkit/review-remote-pr/references/adversarial-review.md" in full before running
or skipping — it carries materiality, attribution, consent, exit codes, and the one-shot runner
contract. Provider selection uses harness=/peer-cli=; pass --peer-cli-absent only when absent.

Spent-budget precheck (must precede launch). Before review, run post-receipt.sh precheck on
the Step 1 PR-conversation artifact:

[ -d "${agentkit:-}/.shared/scripts" ] && [ "${agentkit_provenance:-}" = ok ] || { printf "%s\n" "agentkit unresolved: prepend THE CACHE REHYDRATION block" >&2; exit 1; }
: "${PR:?set PR}" "${PR_WORKTREE:?set PR_WORKTREE}" "${REPO:?set REPO}" "${BASE_BRANCH:?set BASE_BRANCH}"
: "${RUN_DIR:?re-set RUN_DIR to the Step 0c output; shell state does not persist}"
receipt_comments="$RUN_DIR/state/pr_${PR}_issue_comments.json"
current_diff_payload=$("$agentkit/review-remote-pr/scripts/consent-record.sh" payload --worktree "$PR_WORKTREE" --run-dir "$RUN_DIR" --repo "$REPO" --pr "$PR" --base-ref "$BASE_BRANCH") || exit 1
precheck_rc=0
"$agentkit/review-remote-pr/scripts/post-receipt.sh" precheck --issue-comments "$receipt_comments" --diff-payload "$current_diff_payload" || precheck_rc=$?
case "$precheck_rc" in
    0)  printf '%s\n' 'adversarial review budget spent; do not rerun reviewer'; exit 0 ;;
    10) printf '%s\n' 'not spent — proceed to the adversarial review gate below' ;;
    *)  exit 1 ;; # evidence unavailable (missing jq, unreadable/invalid artifact) -- fails closed
esac

Do not treat a missing/unreadable artifact as an empty comment set — that is a no-silent-skip
failure; stop with evidence unavailable. A receipt marker is authoritative from the PR alone.


Step 2: Fix CI Failures

Step 1c — batch pushes: review behavior after a push is provider configuration, not a
workflow guarantee — still batch each cycle's fixes into one push; never post
@coderabbitai pause/resume.

Diagnose the causal failure (gh run view --log-failed "$run_id" | grep -E "FAIL|error|Error",
run ID from the gh pr checks URL column), then run the Implementation-worker gate above.
The worker verifies independently before its cycle push, through agent-run.sh:

[ -d "${agentkit:-}/.shared/scripts" ] && [ "${agentkit_provenance:-}" = ok ] || { printf "%s\n" "agentkit unresolved: prepend THE CACHE REHYDRATION block" >&2; exit 1; }
agent_run="$agentkit/.shared/scripts/agent-run.sh"
"$agent_run" --cmd lint --if-declared
"$agent_run" --cmd test

For red/green iterations the worker uses "$agent_run" --cmd test --only NAME[,NAME...] (forwards through the
repo's AGENT_CMD_TEST_FOCUS declaration); after the final tree change, the worker must run the unfocused "$agent_run" --cmd test once for the full-suite verdict
before worker publication. A successful run prints one PASS: line; a failure prints FAIL(rc=N):,
context, note: lines, matched errors, and the log path. Never push without local verification passing — on FAIL, having set check, log, and failing_paths from its output:

[ -d "${agentkit:-}/.shared/scripts" ] && [ "${agentkit_provenance:-}" = ok ] || { printf "%s\n" "agentkit unresolved: prepend THE CACHE REHYDRATION block" >&2; exit 1; }
: "${RUN_DIR:?re-set RUN_DIR to the Step 0c output; shell state does not persist}"
tmp=$(mktemp "$RUN_DIR/.baseline.XXXXXX") && chmod 600 -- "$tmp"
rc=0
"$agentkit/review-remote-pr/scripts/verification-baseline.sh" --base "origin/$BASE_BRANCH" \
    --log "$log" --check "$check" --paths "${failing_paths[@]}" >"$tmp" || rc=$?
# exit 0: mv to baseline-evidence.md, publish --baseline-file; exit 1: rm tmp, fix as change-caused today.
if ((rc == 0)); then mv -f -- "$tmp" "$RUN_DIR/baseline-evidence.md"; else rm -f -- "$tmp"; fi

Wait contract: one turn-free wait

Read "$agentkit/.shared/wait-discipline.md" before waits (no-model-turn, bounds, durable-state; Step 4 adds CI settlement). Keep waits silent until terminal: log heartbeats, emit one completion/expiry line.

Adversarial-review receipt:

After all confirmed adversarial findings are fixed or explicitly declined, push those fixes; the receipt publishes after fixes are pushed and before draft-phase-complete handoff, as one durable top-level PR comment — required for a material review or a verified trivial-diff skip. It records provider, model, effort, mode (cross-provider or blind fallback + reason), P1/P2/total counts, one confirmed finding line per finding (title, verdict, fix commit SHA(s) or decline rationale), or the verified-skip rationale + oracle.
Order is executable: $agentkit/review-remote-pr/scripts/adversarial-run.sh must return 0 before $agentkit/review-remote-pr/scripts/finding-ledger.sh add records any disposition (exit 13 = review missing/incomplete), and publication consumes that ledger. Create an empty $RUN_DIR/findings.ndjson for a clean review or verified skip.
post-receipt.sh publish derives it from RUN_DIR like finding-ledger.sh does, refusing evidence-unavailable if RUN_DIR is bad. Run it (only after the finding-fix push — the final Phase A action):

: "${RUN_DIR:?re-set RUN_DIR to the Step 0c output; shell state does not persist}"
: "${PR:?re-set PR to the current pull request; shell state does not persist}"
: "${REPO:?re-set REPO to OWNER/REPO; shell state does not persist}"
[ -d "${agentkit:-}/.shared/scripts" ] && [ "${agentkit_provenance:-}" = ok ] || { printf "%s\n" "agentkit unresolved: prepend THE CACHE REHYDRATION block" >&2; exit 1; }
receipt_comments="$RUN_DIR/state/pr_${PR}_issue_comments.json"
# Repeat the ledger command once per confirmed outcome, after the runner returned 0:
"$agentkit/review-remote-pr/scripts/finding-ledger.sh" add --title 'SHORT_TITLE' --severity P1 --verdict fixed --sha SHA
"$agentkit/review-remote-pr/scripts/finding-ledger.sh" add --title 'OTHER_TITLE' --severity P2 --verdict declined --rationale 'RATIONALE'
publish_rc=0
# --head-sha/--diff-payload/--harness unlock post-receipt.sh's own ledger write-back (issue #486 item 4).
rhs=$(gh api "repos/$REPO/pulls/$PR" --jq '.head.sha') || rhs=''
rh=$("$agentkit/.shared/scripts/contract-read.sh" --repo-root "$contract_root" --get harness.name 2>/dev/null) || rh=''
rdp=$("$agentkit/review-remote-pr/scripts/consent-record.sh" payload --repo "$REPO" --pr "$PR" --base-ref "$BASE_BRANCH" --diff "$RUN_DIR/adversarial.diff" 2>/dev/null) || rdp=''
rla=(); [[ -z $rhs ]] || rla+=(--head-sha "$rhs"); [[ -z $rdp ]] || rla+=(--diff-payload "$rdp"); [[ -z $rh ]] || rla+=(--harness "$rh")
RUN_DIR="$RUN_DIR" "$agentkit/review-remote-pr/scripts/post-receipt.sh" publish \
    --pr "$PR" --repo "$REPO" --issue-comments "$receipt_comments" --require-pushed \
    --provider "$PROVIDER" --model "$MODEL" --effort "$EFFORT" \
    --mode "$MODE" --mode-reason "$MODE_REASON" --p1 "$P1_COUNT" --p2 "$P2_COUNT" \
    --agent-identity "$AGENT_IDENTITY" "${rla[@]}" || publish_rc=$?
# The ledger owns titles/dispositions/SHAs/rationales; the script owns every
# receipt byte (--findings-file PATH overrides RUN_DIR). --skip-rationale S --oracle S for a skip.
case "$publish_rc" in
    0)  : ;; # posted and byte-verified
    11) printf '%s\n' 'receipt already spent -- no second post, no rerun' ;;
    12) printf '%s\n' 'receipt refused: fixes are dirty or not reachable from origin' >&2; exit 1 ;;
    13) printf '%s\n' 'receipt refused: finding pipeline is out of order' >&2; exit 1 ;;
    *)  printf '%s\n' 'receipt publication failed' >&2; exit 1 ;;
esac
# Any other nonzero has already triggered a fresh live comment re-fetch inside
# post-receipt.sh. Do not retry from receipt_comments; inspect the fresh live comments first.

Step 3 (Phase B): Wait for the user to decide the ready transition

Never run gh pr ready. The draft-to-ready flip is always the user's call.

When Phase A is done, report the draft-phase summary (Exit Report) and wait per
"$agentkit/.shared/wait-discipline.md" — no gh pr view + sleep loop. Then
observe a real CodeRabbit review landing (walkthrough body, not an ack); if none arrives, report it. If
rate-limited, perform bounded blocking re-check rounds (~10 minutes each, up to ~90 minutes total): use
one blocking helper/harness wait to own the rounds, then escalate to the user. Never trigger a review.


Step 4: Wait for CI

Wait in bounded rounds — never one unbounded wait:

[ -d "${agentkit:-}/.shared/scripts" ] && [ "${agentkit_provenance:-}" = ok ] || { printf "%s\n" "agentkit unresolved: prepend THE CACHE REHYDRATION block" >&2; exit 1; }
"$agentkit/review-remote-pr/scripts/gh-pr-state.sh" \
  --pr "$PR" --repo "$REPO" --wait-ci --rounds 4 --interval 60

Bounds 1–60 rounds, 1–3600 seconds; progress on stderr, Step 1's digest on stdout. Never grep
repo-specific check names; SKIPPED/NEUTRAL count as passing; /coderabbit/i checks are ignored
for settlement but still counted in pending=. Still pending after the bounded rounds →
stop and escalate; do not keep raising --rounds. Never infer review behavior from a push.


Step 5: Assess Automated-Review & Adversarial-Review Findings

Before assessing any saved artifact, prove its parser is available — a missing parser is a
blocked check and must never be summarized as “no findings.”

Use the provider-rules.md content loaded in Step 1a: cycle order (approved human
actions first → nitpicks + Code Quality → one implementation-worker batch → post/verify replies → CodeRabbit settlement
LAST), the VALID/INVALID/NITPICK recipes, and reply/settlement shapes. Adversarial findings from
$RUN_DIR/adversarial.result.json take the same assess → fix → document path, in a PR comment.
Post declines before the cycle's single push (Step 1c); root reviews the pushed diff, never git add -A.


Step 6: Evaluate and Repeat

Refresh every artifact with the same single call as Step 1 — no separate gh pr checks, no
hand-rolled GraphQL re-query:

[ -d "${agentkit:-}/.shared/scripts" ] && [ "${agentkit_provenance:-}" = ok ] || { printf "%s\n" "agentkit unresolved: prepend THE CACHE REHYDRATION block" >&2; exit 1; }
: "${RUN_DIR:?re-set RUN_DIR to the Step 0c output; shell state does not persist}"
"$agentkit/review-remote-pr/scripts/gh-pr-state.sh" \
  --pr "$PR" --repo "$REPO" --full --tmpdir "$RUN_DIR/state"

The digest's agent-docs: N eligible line reports this workflow's marked agent-doc threads
(rule: provider-rules.md, Step 1a). Any CI failure, unhandled automated-review thread/finding, or
unaddressed body nitpick/adversarial finding → back to Step 1 (max 3 cycles — The Loop's cap).
Human-authored content lacking an explicit user decision surfaces the gate and waits; never post,
resolve, or claim readiness.


Exit Report

One template for both the draft-phase report (end of Phase A, before the Step 3 wait) and the final report (loop exit):

PR #N: [draft phase complete | all CI green] — CI green, conflicts none, N/N CodeRabbit threads handled, all body nitpicks handled,
GitHub Code Quality: [no findings | auto-cleared | dismissed with reasons | blocked],
CodeRabbit approval: [approved | changes requested | commented | not observable | no provider review observed],
Adversarial review [Claude Opus 5 | blind Codex-agent fallback (reason: <blockedReason>|absent) | verified skip (oracle: <oracle>) | already spent | none (reason)]: M findings, M handled.
Implementation worker: [<model> <effort> | worker=self — reason: <why>], six-step gate complete.
Human review: [none | H1 approved/replied/open | H2 awaiting confirmation].
[Waiting for you to mark it ready — this skill will not trigger a review. | Ready to merge | Awaiting user confirmation; not claiming readiness]

(Draft phase: report the observed thread and approval state; 0/0 and "no provider review observed" only when evidence shows none. Name the reviewer/fallback reason, the worker's model/effort or
worker=self reason, and each human-review item's decision and thread state.)

Then run Backlog grooming — read "$agentkit/review-remote-pr/references/grooming.md" in full —
before handing back. It proposes Ready candidates, never auto-promotes, and
no-ops silently with no board/scope, never failing the handoff.