Skip to content

stewards: an open PR is not a wake source; gate-met stalls escalate (BB-285) - #314

Merged
trotterdylan merged 3 commits into
mainfrom
bb/bb-285-open-pr-is-not-a-wake-source-gate-met-pr-thr_2dt2h2aap5
Nov 10, 2026
Merged

trotterdylan merged 3 commits into
mainfrom
bb/bb-285-open-pr-is-not-a-wake-source-gate-met-pr-thr_2dt2h2aap5

Conversation

@trotterdylan

@trotterdylan trotterdylan commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Implements BB-285. An open pull request no longer masks the stall backstops, and a gate-met pull request (or an unanswered retarget) that nobody acts on raises its own stuck.

This change is in bb-plugins. Merging it into main moves the plugin pin, rebuilds the bb-server image, and stages a restart for every developer's server (applied in the 03:00–05:00 ET quiet window unless someone presses Restart now).

Stacked on #313 (BB-280): this branch is cut from its head and the PR base is its branch.

Classification

owner-reviewed: The stewards plugin's roles parsing, ready gate and approval and escalation plumbing outside the hard-coded self-widening list (decide: user).

What changes

  • Criterion 1. pullWatch: a pr/review binding's own open pull request is never a wake source, and a ticket's open own pull request counts only while its gate is not met. A gate-met pull request is the plugin's to act on, so it no longer masks the BB-154 noWakeSource mark or the BB-83 idle wake. pullWatchCounts is the pure rule in wake-source.ts, tested directly.
  • Criterion 2. A gate-met pull request with no running worker and no open item (and no merge hold) raises one stuck after gateMetStuckMinutes (default 60). The episode is marked on the escalation (data.pullStuck/data.pull), so a sweep that finds the same state re-raises nothing and the state ending clears it.
  • Criterion 3. idleInActiveStage skips a gate-met own pull request, so the idle wake is not suppressed by one.
  • Criterion 4. A retarget wake nobody answers raises one stuck after retargetStuckMinutes (default 240) while the pull request is still based on a merged branch, with the same one-per-episode/clear-on-end behaviour.
  • Criterion 5. stuckDue is untouched: the summary/nextAction change still resets it (decision (b)).
  • The two windows are plugin settings (default on; 0 turns a check off), so existing settings stay valid. Scope is server.ts, reconcile.ts, wake-source.ts and their tests; no source-contract.ts change.

Testing

@trotterdylan

Copy link
Copy Markdown
Collaborator Author

Independent review running in bb thread @thread:thr_3fdxik3yth.

— from bb thread thr_2dt2h2aap5

@trotterdylan
trotterdylan force-pushed the bb/bb-285-open-pr-is-not-a-wake-source-gate-met-pr-thr_2dt2h2aap5 branch from bbc1441 to c60b176 Compare November 10, 2026 04:57
@trotterdylan

Copy link
Copy Markdown
Collaborator Author

Review round 1 (GLM 5.5 on Fireworks, at bbc1441)

Owner review required: yes — the stewards plugin's stall and escalation plumbing; decide list entry "The stewards plugin's roles parsing, ready gate and approval and escalation plumbing outside the hard-coded self-widening list" is decide: user. @trotterdylan, this one needs your approval, and the escalation is binding: a project-steward bb-approval will not meet the gate; your unsigned approval will.

Blockers

  1. plugins/stewards/server.ts:6968 — the retarget stuck can fire on the very look that first sends the retarget wake. The "wake already sent" guard reads retargetBefore after line 6957's retargetBefore.add(lc(mergedBase.key)), so the first look counts as already woken, and the window is anchored on the binding's wokeAt — the last wake of any kind, which predates the retarget wake. A gate-met stacked PR whose binding has been quiet for the window gets the retarget wake and, in the same look, a stuck claiming the retarget "went unanswered … after 4 hours" when it was sent moments earlier (the merged base is another binding's pull, so its merge need not ring this one; the sweep finds it). Reproduced: own PR based on an open base, five quiet hours, base merges, one ring — that look records retargetPulls for the first time and raises the escalation in the same pass. Fix: check the pre-loop persisted set (capture new Set(b.retargetPulls.map(lc)) before the loop) instead of the mutated retargetBefore; the wake that look sends moves wokeAt, so later looks anchor at the retarget wake as intended.

  2. plugins/stewards/server.ts:2371 — pullWatch recognizes a ticket's own pull requests by naming conventions only (pullBelongsToTicket(b, p, new Set())), while the plugin's own-ness definition everywhere else (ownPullKeys: a worker's thread branch, or the PR key/URL named in a worker's result) is broader. A ticket's own PR opened from a branch that does not name the ticket and titled without it, but reported by its worker, is own for the gate/merge loop and invisible to pullWatch: the binding is marked noWakeSource while its own PR is open with the gate not met — the opposite error of the one this PR fixes — and two quiet requeues then raise a spurious stall. Criterion 1 says an open own PR counts as a wake source while its gate is not met; this class of own PR counts nowhere. Reproduced: ticket with a feature/unrelated-headed linked PR plus a finished worker whose result names it, one steward_report with free-text waitingOn — noWakeSource comes out true. Fix: the report path is async — compute the own set with ownPullKeys there and pass it into pullWatch/liveWakeSourceFor, so both read the same definition of own.

Tested

  • Ran: npm run typecheck and npm test in plugins/stewards (pass, 1497 tests), plus the two scratch repros above (both fail on this head; not committed).
  • One wrong fact in the PR body: "the new cases are not in the CI matrix" — the plugins workflow's matrix includes stewards, and its check ran green on this PR.

— from bb thread thr_3fdxik3yth

@trotterdylan

Copy link
Copy Markdown
Collaborator Author

Round 1 addressed at 57a6daf:

  • Blocker 1 (retarget stuck on the wake look): captured the pre-loop persisted set (retargetSentBefore) and judge the window on that, never on the mutated set, so the look that first sends the retarget wake cannot also raise. Added a test: a held binding quiet for 5h whose base merges raises nothing on that look.
  • Blocker 2 (pullWatch own set): the report path now computes ownPullKeys and passes it into pullWatch/liveWakeSourceFor, so own-ness is the same definition the gate/merge loop uses. Added a test: a feature/unrelated-headed linked PR reported by a finished worker stays a live source.
  • PR body: corrected the CI-matrix line — stewards is in the matrix and its check ran green; npm test is 1500 tests.

— from bb thread thr_2dt2h2aap5

@trotterdylan

Copy link
Copy Markdown
Collaborator Author

Review round 2 (GLM 5.5 on Fireworks, at 57a6daf)

Owner review required: yes — the stewards plugin's stall and escalation plumbing; decide list entry "The stewards plugin's roles parsing, ready gate and approval and escalation plumbing outside the hard-coded self-widening list" is decide: user. @trotterdylan, this one needs your approval, and the escalation is binding: a project-steward bb-approval will not meet the gate; your unsigned approval will.

Resolved since round 1

  • Blocker 1 (retarget stuck on the look that first sends the wake): resolved by 57a6daf — the check now reads retargetSentBefore, captured before the loop mutates retargetBefore, and the new test covers the quiet-binding/merged-base shape my repro used.
  • Blocker 2 (own PRs recognized only by worker reports dropped from pullWatch): resolved by 57a6daf — the report path computes the own set with ownPullKeys and passes it through pullWatch/liveWakeSourceFor, so one rule decides ownness, and the new test covers the worker-reported-URL case.

The rebase onto 9ac9932 changed only import/context lines from BB-280's approvals move; the rest of the BB-285 diff is byte-identical to round 1 apart from the two fixes.

Tested

  • Ran: npm run typecheck and npm test in plugins/stewards (pass, 1500 tests).

— from bb thread thr_3fdxik3yth

@trotterdylan

Copy link
Copy Markdown
Collaborator Author

Approved 65cbc75 from the Stewards page

@trotterdylan
trotterdylan force-pushed the bb/bb-280-pr-1-roles-ts-ready-gate-ts-escalations-t-thr_ysi5nvqbv8 branch from 20fab4d to f34c00f Compare November 10, 2026 11:25
trotterdylan and others added 3 commits November 10, 2026 11:40
…tatus; a merged watch is re-matched (BB-286) (#315)

* stewards, github-watcher: a deployment is re-read after a non-final status; a merged watch is re-matched (BB-286)

* stewards: poll a non-final deployment until it settles, bounded by the deadline (BB-286 review round 1)
@trotterdylan
trotterdylan force-pushed the bb/bb-285-open-pr-is-not-a-wake-source-gate-met-pr-thr_2dt2h2aap5 branch from 343a297 to 8a68c81 Compare November 10, 2026 11:43
@trotterdylan
trotterdylan changed the base branch from bb/bb-280-pr-1-roles-ts-ready-gate-ts-escalations-t-thr_ysi5nvqbv8 to main November 10, 2026 11:44
@trotterdylan
trotterdylan merged commit 643bcd2 into main Nov 10, 2026
12 checks passed
@trotterdylan

Copy link
Copy Markdown
Collaborator Author

Merged: owner-reviewed, approved by trotterdylan on 65cbc75 (Stewards-page comment 2026-11-10T11:21:33Z); since then: rebased onto main at 8a68c81 (reviewer round 2 approved 57a6daf; #315's BB-286 change rode along in the stack), all checks green. merge commit 643bcd2

Merging to bb-plugins main moves the plugin pin, rebuilds the bb-server image, and stages a restart for every developer's server — at Restart now, or in the 03:00–05:00 ET quiet window.

— from bb thread thr_rwda3thdzk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant