Repository navigation
fix(pr-pipeline): sweep lanes App heads whose review dispatch skipped and never retried - #12648
Conversation
… and never retried A review completion's address-feedback dispatch that skips on a cause that clears later (verify-cap.mjs's unreadable FAIL cap when the artifact listing does not fit in the caller's limit) records nothing, and no review run follows on that head. The half-hourly sweep only sent released heads, fix requests, stale stops and idle owner PRs, so one unresolved advisory thread held #12578, #12604 and #12605 until a person dispatched the round. sweepUnsent sends a lanes App head with an unresolved thread and no address-feedback check run, once its newest review run is past the dispatch job's 10-minute timeout and no round was created since that review started. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vcupom3BKF6QuC5U3sRJPj
|
To use Codex here, create an environment for this repo. |
|
claude-security-review reviewed Security review: PR #12648I found no security issues. I read every hunk of all 4 changed files. Two of them match the trusted paths: What changed. The tick's sweep gets a new pass, Trust boundaries checked
Spend: Extra The instruction-surface and plugin-manifest checks don't apply: the diff touches no standing instruction file and no manifest. No text in the PR context tries to direct this review. critical-findings: 0 |
|
claude-review reviewed Code review: sweep lanes App heads whose review dispatch skipped (
|
… trigger at the head reviewRunAt returns the newest-created review run, so another review lane finishing later, a re-run, or a pr-merge completion could still start a head-group dispatcher after the grace had passed, and the sweep could send the same head alongside it. The grace now runs from the newest completion of any review run (pull_request) or pr-merge run (pull_request_target) at the head. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vcupom3BKF6QuC5U3sRJPj
|
claude-review reviewed Code review (incremental, d1989f8..12d2a2a):
|
|
claude-security-review reviewed Security review: PR #12648 (incremental, d1989f8 → 12d2a2a)I found no security issues. I read every hunk of both files in the incremental scope: What changed.
Trust boundaries checked
Settled thread: the owner resolved the grace-race thread (original line 944). This push extends that same fix to relay runs and pr-verify notes, and it raises no new problem on those lines. Prior findings: this lane has no earlier findings on this pull request, and the round cap (3) has not been reached. Spend: prepaid or included usage only, no real charge. Each sweep tick adds one run-listing read for the relay workflow per qualifying head. critical-findings: 0 |
…dispatchers The unsent-head grace counted only review and pr-merge completions at the head. A comment relay's dispatch also runs in the head's group, and a pr-verify FAIL's dispatch runs in a verify-<id> group at main's head, so a sweep tick could send a round beside either. The grace now also counts completed relay runs at the head and the newest comment on an unresolved thread, which a FAIL's notes create just before their dispatch. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vcupom3BKF6QuC5U3sRJPj
No related issue: dispatcher stall found by the PR Lane sweep (hub ledger L80)
Summary
On 2026-11-03, three lanes App PRs each sat BLOCKED on one unresolved advisory
claude-reviewthread with nopr-unblock address-feedbackround queued, until a person dispatched it: #12578 (thread 01:19Z, manual round 02:27Z) and #12604 and #12605 (threads 02:19Z and 02:21Z, manual rounds 03:21Z and 03:22Z). That is about 1 h of extra age each.Advisory threads were not filtered out. On an ungated lanes App head, any unresolved thread dispatches (
feedback-dispatch.mjs:583-601). The reviewer-id list at:309only feeds the@codexrequest check. The cause was the FAIL-cap read plus a missing retry:verify:unreadable: the artifact listing does not fit in the caller's limit(about 14k artifacts, 147-150 s needed against verify-cap's 120 s). Logs: pr-feedback-dispatch runs 41558975880 and 41558976741 (fix(toolchain): run Biome as npx biomejs biome, not the unrelated biome package #12578), 41565408850 and 41565426555 (feat(docs-hygiene): rename-references auto-applies the Certain bucket and reports it #12604), and 41565602231 (feat(context7): probe the top candidates instead of asking on an ambiguous library match #12605).verify-cap.mjs:152), so the head is not recorded as handled (feedback-dispatch.mjs:689-691). The code expects a later read to clear it, but nothing reads the head again: no review run follows, and the tick's sweep (sweepReleased) only sends released heads, fix requests, stale stops and idle owner PRs. The sweeps after the 01:41 and 02:39 ticks (runs 41561573125 and 41567652819) logged "no head" for all four passes while these PRs were stalled.Fix
A new sweep pass,
sweepUnsent, runs aftersweepStale. It sends one lanes App head per tick that has an unresolved review thread and nopr-unblock / address-feedbackcheck run, through its newest completed review run, with all ofdispatchFeedback's gates (markers, hold labels, human gate, FAIL cap). It waits until that review run is at least 10 minutes old, the dispatch job'stimeout-minutes, so it does not race the review completion's own dispatch, which runs in a different concurrency group. Apr-unblock.ymlrun for the PR created since that review started holds the head, so a round that ended before posting its check is sent only once.Each lanes App PR with no round costs one check-run read per tick, plus one thread read when it has none. A head whose skip stands costs the reads
dispatchFeedbackmakes before it skips.Verification
verify:unreadableskip (feedback-dispatch.mjs:684-700,verify-cap.mjs:152) with no sweep pass for a lanes App head that has no round.github-actions[bot]) sent rounds for lanes App PRs feat(testing): commit an attended cleanup batch once shown, without a batch-level wait #12609 at 02:37Z (run 41567272072) and feat(session-flow): workflow probes git for missing files before asking #12630 at 03:15Z (run 41571055692), and on a lanes App PR every one of those dispatches runs the cap read. The fix(toolchain): run Biome as npx biomejs biome, not the unrelated biome package #12578 round (run 41566239073) was started by hand. A retry each tick therefore clears the stall on the first read that fits. The sweep runs in the sameDispatch address-feedbackstep as the review dispatches, so it uses the same verify reader (VERIFY_EVIDENCE_SCRIPT,pr-feedback-dispatch.yml:442), and a head at the final cap still gets no round.node --test .github/scripts/pr-unblock/feedback-dispatch.test.mjs: 208 pass, 0 fail. The two new tests (a head the cap read skipped is sent by the sweep, and the pass leaves heads with a round, no unresolved thread, a review inside the grace, a run since the review, ordo-not-merge) fail against the oldfeedback-dispatch.mjs.The listing cost itself is addressed elsewhere: FAIL index mode (#12558, merged 03:28:44Z) makes verify-cap's reader read targeted names instead of the whole listing (
babysit_verify_evidence.py:4436-4438). This pass stays as the retry for any non-final skip, whatever its cause. Retention stays at 90 days (#8295's scope, deferred by the owner).Re-measure: after this merges, count lanes App PRs that sit BLOCKED on an unresolved thread for more than 40 min with no
pr-unblock / address-feedbackcheck run (one tick plus the 10 min grace). Target: 0 over a 24 h window, against the baseline of 3 PRs at about 1 h each.Related
🤖 Generated with Claude Code
https://claude.ai/code/session_01Vcupom3BKF6QuC5U3sRJPj