Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions scripts/loop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -515,15 +515,25 @@ was *correct*, and whether new events produce proposals that match reality.
returned `noop` for any PR without `loop-task:`, which is right about the
**metric** (not loop-produced ⇒ never in the acceptance rate) but wrong
about the **task**: ops.md maps "(none, merged) → accepted" and "(none,
closed unmerged) → rejected" regardless of provenance. Every owner or
dependabot PR gets a task from `pull_request` triage, so each merged PR left
a zombie in `waiting-human` — the task for the very PR that fixed D30 (#39)
demonstrated it live — visible forever under "Inbox" in SUMMARY.md and
closed unmerged) → rejected" regardless of provenance. Every owner PR gets a
task from `pull_request` triage, so each merge left a zombie in
`waiting-human` — the task for the very PR that fixed D30 (#39) showed it
live — visible forever under "Inbox" in SUMMARY.md and, in general,
uncorrectable by sweep, which lists *open* GitHub items and so cannot see a
closure. The router now emits a `terminal` decision for that case; the
entry handles it through the same `markTaskTerminal` as the metrics path, so
"what terminal means" has one definition, and the acceptance row is still
never written for a non-loop PR.
closure. (Dependabot PRs are skipped before triage by the credential guard
(D28), so for them the new branch is a no-op; it still matters if D28 is
ever lifted, and it correctly terminalises the older dependabot task #35.)
The router now emits a `terminal` decision for that case; the entry handles
it through the same `markTaskTerminal` as the metrics path, so "what
terminal means" has one definition, and the acceptance row is still never
written for a non-loop PR.
Verified live on 2026-09-11 (`34595150462`, PR #40 merged): `task #40:
waiting-human → accepted`, and R2 then reported `closed=1 accepted=9` with
acceptance rows still at 3 — no metric for a non-loop PR.
The #39 instance was **not** this fix's doing: the drift was self-healed by
the 09-11 daily sweep (`r-20260911-080231-zja0`), which only found it
because the #40 triage report had mentioned it in passing. That is the
accidental path D30/D33 exist to remove.

## Environment facts

Expand Down
9 changes: 5 additions & 4 deletions scripts/loop/shared/route.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,11 @@ export function route({ eventName, action, event = {} }) {
// Not loop-produced, so it must not enter the acceptance metric — but its own
// task still has to reach a terminal state, or it sits in the inbox forever
// (ops.md maps "(none, merged) -> accepted", "(none, closed unmerged) ->
// rejected"). Every owner/dependabot PR gets a task from `pull_request`
// triage, so without this each one strands a zombie in the state layer, and
// sweep cannot repair it: sweep lists *open* GitHub items, which cannot see
// a closure.
// rejected"). Every owner PR gets a task from `pull_request` triage, so
// without this each merge strands a zombie in the state layer, and sweep
// cannot repair it: sweep lists *open* GitHub items, which cannot see a
// closure. (Dependabot PRs are skipped before triage by the credential
// guard, D28, so for them this branch is a no-op.)
return terminal({
reason: `non-loop PR ${merged ? 'merged' : 'closed-unmerged'} `
+ '(not counted for auto-acceptance)',
Expand Down
Loading