Skill Tracer
Skills › Compound Engineering › ce-babysit-pr › settle.md

settle.md

37 lines · skills/ce-babysit-pr/references/settle.md at 3449230

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Stop conditions, settle, and the merge-ready judgment
2
3**"Looks ready" is a judgment, not just an elapsed timer.** It is never enough that CI is green and the PR has been quiet for a while — see the review-still-coming check below.
4
5**The in-progress signal gates only the *merge-ready declaration* — never the work.** Keep resolving open feedback as it arrives even while a review is in progress: **do not wait for the 👀 to clear before acting on the comments it has already posted.** Waiting for the review to *finish* before addressing feedback it already left would serialize the work the same way waiting for a full CI run before addressing comments would — the mistake the core principle forbids. Act on every open item continuously; the *only* thing the in-progress signal withholds is the "looks ready" call. (The engine reports only that the PR went quiet and for how long; whether a review is still coming is yours to judge at the settle decision, under the review-still-coming check in Step 3 below.)
6

Stop conditions, settle, and the merge-ready judgment

"Looks ready" is a judgment, not just an elapsed timer. It is never enough that CI is green and the PR has been quiet for a while — see the review-still-coming check below.

**The in-progress signal gates only the merge-ready declaration — never the work. Keep resolving open feedback as it arrives even while a review is in progress: do not wait for the 👀 to clear before acting on the comments it has already posted.** Waiting for the review to finish before addressing feedback it already left would serialize the work the same way waiting for a full CI run before addressing comments would — the mistake the core principle forbids. Act on every open item continuously; the only thing the in-progress signal withholds is the "looks ready" call. (The engine reports only that the PR went quiet and for how long; whether a review is still coming is yours to judge at the settle decision, under the review-still-coming check in Step 3 below.)

Raw lines 1 to 6
7## Step 3: Stop conditions
8
9In interactive runs (pipeline mode has its own stop in `references/pipeline.md`), classify each condition as one of two kinds. A **true stop** ends the watch and hands back. A **standing residual** is reported to the user and blocks a *merge-ready declaration*, but the self-sustaining watch **keeps running around** it — it does **not** end the loop. **Terminal**, **looks-merge-ready**, **budget**, and **`blocked-external-drained`** are true stops for the active PR (under `stack-ready`/`stack-land` a quiescent layer is a transition before any of these — `references/stack.md`). The first **`blocked-external`** observation starts the time-limited wait for review described below instead of stopping. **`needs-human`**, **`blocked-failing`**, `stack-sync-needed` or an uncertain result from the chain lookup, and an unresolved **semantic conflict** are standing residuals. A stale dependent above a target that is itself current is a stack-health residual, not a blocker to calling the target ready *as the next PR*. In **checkpoint mode** the single tick ends regardless of class; the distinction only changes what you report and whether you print a resume command.
11**True stops — the watch ends:**
13- **Terminal** — PR `MERGED` or `CLOSED`, except when this run just completed an authorized `stack-land` merge on that PR: that MERGED outcome is a layer transition (see the stack-land land step in `references/stack.md`), not a run-level Terminal stop.
14- **Looks merge-ready (settled)** — every one of the following holds. GitHub itself reports it mergeable: `mergeability_certain`, `mergeable == "MERGEABLE"`, and `merge_state_status == "CLEAN"` (this defers required-check and required-review policy to GitHub after the merge computation is bound to the independently proven current base and current head). `base_ref_blocker == null`. `checks_terminal` is true (nothing still running). There is **zero actionable backlog** — `counts.threads == 0` **and** `counts.comments == 0` (no unresolved inline threads and no un-acted top-level/review-body feedback) — **and `open_needs_human == 0`** (a thread or comment you deferred for a human decision means it is *not* ready — report it, do not call it merge-ready), **and `branch_currency_blocker == null`** (no open, claimed, or parked base-movement item). `quiet_seconds` has reached the settle threshold **and the review-still-coming check below is clear** — either no review looks to be on its way, or the bounded wait it allows has run out and you say so. "Mergeable against current base" does not mean the PR head contains the latest base commit: `BEHIND`, `DIRTY`, branch-protection requirements, or an explicitly selected always-current policy may require maintenance, while ordinary base movement with GitHub reporting `CLEAN` does not. Chain state further qualifies that result. A managed target requires `stack_blocker == null` (the snapshot defers to GitHub's certain `MERGEABLE`/`CLEAN` read for plain trunk drift); call it **"ready as the next PR in the stack"**, never independently ready, and list stale upstack entries separately. In a manual dependency chain, call it **"ready relative to its parent"** and name any open parent that must land first. Base identity `race`, `mergeability-pending`, or `probe-error`, chain `probe-error`, or an uncleared unknown managed freshness (`stack_blocker` present) blocks readiness only until a fresh observation proves the result. GitHub can leave its test merge on the old base indefinitely after main moves; when head and live base have been stable for the engine's stale window it emits `base.identity == "stale-computation"` with `merge_computation_stale: true`, which counts as certain — declare ready if the rest of the conditions hold, and disclose in the report that GitHub's cached merge computation was stale (a fresh recompute happens at merge time). The settle threshold is the script's **300s default**; the *only* thing that ever widens it is the re-arm after a `merge-ready` wake you judged not ready yet (the review-still-coming judgment below) — never widen the first arm in advance, review bots or not. The settle window is a *cooling-off* signal — evidence the PR stopped moving, **not** a guarantee no further review is coming. **Before you report it ready, check PR-description freshness (the final checkpoint).** A watch full of incremental commits — fixes, new behavior, resolved feedback, a base-into-head merge — routinely leaves the *original* PR description describing a PR that no longer exists. If what the PR now does has materially drifted from its description (new/removed behavior, a changed approach, resolved caveats), **refresh it autonomously: invoke `ce-commit-push-pr` in description-update mode, non-interactively (`mode:pipeline` — it rewrites and applies via `gh pr edit` directly, no preview prompt). Do not ask — a current description is part of leaving a PR merge-ready**, and updating it is one of `ce-commit-push-pr`'s own functions. If the description still reflects the change, leave it untouched. Report an independent PR as "looks ready — your call to merge," never "safe to merge." For a confirmed managed stack, apply the layer-transition rules in `references/stack.md` before treating this layer stop as the whole run's stop. In **checkpoint mode** you cannot enforce elapsed time between manual re-runs, so if it is otherwise clean but `quiet_seconds` is under the threshold, say "green now, re-run in ~5 min to confirm it stayed quiet before merging."
15- **Blocked on external CI approval, after draining review** — `checks_awaiting_approval > 0` with no actionable backlog means a workflow is **awaiting a base-repo maintainer's approval to run** (GitHub's fork-PR security gate). Neither you nor the loop can trigger it; **never auto-approve** the run. CI is blocked, but review may still move independently, so the first `blocked_external` observation is not an interactive stop:
16 - **Interactive self-sustaining watch:** without asking, apply the same review-still-coming judgment and re-arm at the normal polling interval (`--interval 150`) with `--blocked-external-drain-seconds 300` when no review looks to be on its way, or `--blocked-external-drain-seconds 900` when one does. The helper keeps a clock tied to the current head. New or edited external feedback, a submitted review or reviewer signal that moved, or a new head resets it; an unchanged approval gate, the loop's own replies, check/base/stack movement, and records of how an item was handled do not. Incoming feedback still wakes ahead of the approval gate — resolve it immediately, then re-arm the wait on the new evidence. If approval clears, return to the ordinary CI watch.
17 - **Drain expiry:** `blocked-external-drained` is the wake at which you decide. At 900 quiet seconds, concrete prior current-head timing from the same reviewer may justify one re-arm with `--blocked-external-drain-seconds 1800`; it may never shorten the 900-second floor or extend beyond 1800 on a merely missing completion signal. When no review looked to be coming, 300 seconds is terminal — but apply the review-still-coming judgment once more before handing back. A reviewer can announce itself after the wait length was chosen, and nothing during the wait observes that on its own, so the expiry wake is the only place that movement can still be caught. Only an explicit user request to keep watching the approval gate for a longer stated duration overrides these defaults, and it remains capped by this invocation's original budget.
18 - **Handback:** once the selected drain expires with the approval gate still present, stop without asking another question. Report that all observed feedback was handled, how long the current head was review-quiet, that CI never ran because maintainer approval is still required, and give the host-rendered resume invocation. A later notification or explicit re-invocation starts the next bounded watch.
19 - **Pipeline / unattended:** do **not** drain, ask, or spin — return a `blocked-external` residual with the run URL and terminate. Its bounded orchestrator contract explicitly does not wait on human review or approval.
20 - **Checkpoint:** process the current tick, report the approval gate, state that monitoring is paused, and give the resume invocation; it cannot enforce elapsed drain time itself.
21- **Budget exhausted** — active `invocation_elapsed_seconds` reaches the fixed invocation budget (default 8h of active watch time, or the duration the user selected at entry), **or** raw wall-clock reaches the 3-calendar-day backstop, a round-count cap the user set, or the user aborts. The `max-runtime` wake names which ceiling was hit via `max_runtime_ceiling` (`active-budget` or `backstop`). Watch re-arms and confirmed-managed-stack layer transitions must match the original ID, start, and budget; they can neither reset nor extend the cap and preserve accumulated dead time. The deadline's final refresh may still report `terminal` or an already-settled `merge-ready`; both stop immediately and start no new work. Otherwise `max-runtime` outranks actionable/residual work so no additional agent round begins. On `max-runtime`, report the emitted `invocation_elapsed_seconds` and budget, never `persisted_state_age_seconds`, and do not automatically start another invocation. This is the blunt cost floor beneath the stop in `references/tick.md` that fires when the PR's trajectory shows it is not converging — it catches a runaway that never trips that trigger, not the normal way a stuck PR ends. A bounded invocation hands control back; only a later explicit user/orchestrator invocation starts another budget.
23**Standing residuals — report them, then keep watching (these do NOT end the self-sustaining loop):**
25- **`needs-human`** — accumulated typed decisions from `ce-resolve-pr-feedback` or `ce-debug`, or a semantic merge conflict Step 2 (the tick) could not resolve mechanically. A managed upstack conflict follows the narrower rule of Step 7 (managed upstack maintenance): abort the manager transaction and report it rather than deciding another PR layer's semantics. Persist each complete residual through the shared atomic mark, show its full decision payload, and leave every covered review thread open. A parked decision blocks merge-ready, but in interactive continuous mode it does not end the watch: keep handling independent review and CI streams. The snapshot invalidates the grouped residual and makes every surviving source actionable again when any covered source changes or disappears; never maintain a separate route-specific decision or reopen path.
26- **`blocked-failing`** — a dispatched check `ce-debug` left terminally red (`has_failing_checks` with `counts.ci == 0`, nothing new to dispatch). Same shape: report the red residual, it blocks merge-ready, but a later commit or head SHA may clear it — **keep watching**, and the detector will not re-wake on the same red residual (it compares against the state recorded when the watch was armed). Only a **true stop** above, or the user, ends the loop.
27- **`stack-blocked`** — the target is manager-stale or of unknown managed freshness while GitHub does not report it certain `MERGEABLE`/`CLEAN` (plain trunk drift under a CLEAN read is not a blocker), manager discovery failed, or Step 7 could not complete its clean upstack transaction. Report the `stack_blocker` and relevant `pr_chain` entries; continue review/CI work, but do not perform an ordinary base update or declare the target ready. A later manager sync, successful probe, or successful Step 7 maintenance clears the residual. A remaining stale upstack entry is a stack-health residual even when the target can be reported ready as next.
29**Is a review still coming? (part of the looks-ready check).** The settle window tells you the PR stopped moving. It does not tell you a review is not on its way — the window can elapse before a backgrounded reviewer even starts. Judge that separately at the settle decision, from one cheap `gh` look at the current head, covering every place an announcement can arrive: reactions on the PR body, top-level comments, the check runs on that head, and reviews against it. A resumed run has no memory of an interim comment it already classified, and a dispatched one is absent from the snapshot, so the lookup is the only place it can still be seen.
31A reviewer that announces itself — a 👀 reaction, a "reviewing…" note — has told you it **started**. Nothing obliges it to retract that when it finishes, so a standing announcement is not evidence that work continues. Look instead for what that same reviewer produced on this head, and ask whether it accounts for the review it announced. Something carrying that reviewer's verdict — its review, its comment, or a check run that *is* its review — having reached a terminal conclusion means it stopped: say which, and never read a timeout or a skip as approval. Anything of its still running means it is still working. Output that does not account for the announced review leaves the review outstanding, so treat that reviewer like one that produced nothing: an unrelated check from the same app finishing while its review has not appeared is not the review finishing. A reviewer that announced itself and has nothing to show for it either way is the genuinely undecidable case.
33An announcement is not the only evidence a review is coming. A reviewer that reviewed an **earlier** head and not this one has told you the same thing through its own history on this PR, and many reviewers work that way without ever announcing anything — in some repos no reviewer announces at all. Treat that reviewer as one that announced with nothing to show yet, and it clears the same way: when it reviews this head, or when the bounded wait runs out.
35Keep the asymmetry in mind: a **present** signal is informative, an **absent** one tells you nothing, since many reviewers announce nothing and simply post. So never wait terminally for a done signal, and never let a missing one block on its own.
37Wait while you can see work in progress, and wait a bounded while when a reviewer announced itself with nothing to show for it. Re-arm by re-running the arm command with a longer `--settle-seconds` — passing it is what makes the re-arm real, since quiet already exceeds the 300s default and the ordinary arm would re-fire on the next poll. Use: about 900, extended once to no more than 1800 when concrete prior timing for that reviewer justifies it. Those are ceilings, not targets — announcing reviewers observed here finish in four to six minutes, while a slow reviewer that never announces had a 21.6-minute p90 over 157 reviews and a much longer tail beyond it. Once 1800 quiet seconds pass on unchanged evidence, stop and say plainly what you could not confirm; never re-arm past it on the same unchanged evidence. A widened window is your judgment about the evidence you looked at, so when that evidence moves the watch wakes you on `review-evidence-moved` rather than sleeping the window out against a state that has changed. Re-judge from the current head as at any settle decision: if what moved accounts for the review you were waiting on, the ordinary window decides again, and if it does not, re-arm as before. The engine reports only that something moved; whether it resolved anything is yours. Readiness is a recommendation to the user and never authorization to merge, except under `posture:stack-land`, where selecting that posture was the user's advance yes and a settled prefix does land. So calling it early usually costs only a disclosure, while under `stack-land` it costs landing sooner than the reviewer finished — and holding forever costs the PR in every posture.

Step 3: Stop conditions

In interactive runs (pipeline mode has its own stop in references/pipeline.md), classify each condition as one of two kinds. A true stop ends the watch and hands back. A standing residual is reported to the user and blocks a merge-ready declaration, but the self-sustaining watch keeps running around it — it does not end the loop. Terminal, looks-merge-ready, budget, and **blocked-external-drained** are true stops for the active PR (under stack-ready/stack-land a quiescent layer is a transition before any of these — references/stack.md). The first **blocked-external observation starts the time-limited wait for review described below instead of stopping. needs-human, blocked-failing**, stack-sync-needed or an uncertain result from the chain lookup, and an unresolved semantic conflict are standing residuals. A stale dependent above a target that is itself current is a stack-health residual, not a blocker to calling the target ready as the next PR. In checkpoint mode the single tick ends regardless of class; the distinction only changes what you report and whether you print a resume command.

True stops — the watch ends:

  • Terminal — PR MERGED or CLOSED, except when this run just completed an authorized stack-land merge on that PR: that MERGED outcome is a layer transition (see the stack-land land step in references/stack.md), not a run-level Terminal stop.
  • Looks merge-ready (settled) — every one of the following holds. GitHub itself reports it mergeable: mergeability_certain, mergeable == "MERGEABLE", and merge_state_status == "CLEAN" (this defers required-check and required-review policy to GitHub after the merge computation is bound to the independently proven current base and current head). base_ref_blocker == null. checks_terminal is true (nothing still running). There is zero actionable backlog — counts.threads == 0 and counts.comments == 0 (no unresolved inline threads and no un-acted top-level/review-body feedback) — **and open_needs_human == 0** (a thread or comment you deferred for a human decision means it is not ready — report it, do not call it merge-ready), **and branch_currency_blocker == null** (no open, claimed, or parked base-movement item). quiet_seconds has reached the settle threshold and the review-still-coming check below is clear — either no review looks to be on its way, or the bounded wait it allows has run out and you say so. "Mergeable against current base" does not mean the PR head contains the latest base commit: BEHIND, DIRTY, branch-protection requirements, or an explicitly selected always-current policy may require maintenance, while ordinary base movement with GitHub reporting CLEAN does not. Chain state further qualifies that result. A managed target requires stack_blocker == null (the snapshot defers to GitHub's certain MERGEABLE/CLEAN read for plain trunk drift); call it "ready as the next PR in the stack", never independently ready, and list stale upstack entries separately. In a manual dependency chain, call it "ready relative to its parent" and name any open parent that must land first. Base identity race, mergeability-pending, or probe-error, chain probe-error, or an uncleared unknown managed freshness (stack_blocker present) blocks readiness only until a fresh observation proves the result. GitHub can leave its test merge on the old base indefinitely after main moves; when head and live base have been stable for the engine's stale window it emits base.identity == "stale-computation" with merge_computation_stale: true, which counts as certain — declare ready if the rest of the conditions hold, and disclose in the report that GitHub's cached merge computation was stale (a fresh recompute happens at merge time). The settle threshold is the script's 300s default; the only thing that ever widens it is the re-arm after a merge-ready wake you judged not ready yet (the review-still-coming judgment below) — never widen the first arm in advance, review bots or not. The settle window is a cooling-off signal — evidence the PR stopped moving, not a guarantee no further review is coming. Before you report it ready, check PR-description freshness (the final checkpoint). A watch full of incremental commits — fixes, new behavior, resolved feedback, a base-into-head merge — routinely leaves the original PR description describing a PR that no longer exists. If what the PR now does has materially drifted from its description (new/removed behavior, a changed approach, resolved caveats), **refresh it autonomously: invoke ce-commit-push-pr in description-update mode, non-interactively (mode:pipeline — it rewrites and applies via gh pr edit directly, no preview prompt). Do not ask — a current description is part of leaving a PR merge-ready**, and updating it is one of ce-commit-push-pr's own functions. If the description still reflects the change, leave it untouched. Report an independent PR as "looks ready — your call to merge," never "safe to merge." For a confirmed managed stack, apply the layer-transition rules in references/stack.md before treating this layer stop as the whole run's stop. In checkpoint mode you cannot enforce elapsed time between manual re-runs, so if it is otherwise clean but quiet_seconds is under the threshold, say "green now, re-run in ~5 min to confirm it stayed quiet before merging."
  • Blocked on external CI approval, after draining review — checks_awaiting_approval > 0 with no actionable backlog means a workflow is awaiting a base-repo maintainer's approval to run (GitHub's fork-PR security gate). Neither you nor the loop can trigger it; never auto-approve the run. CI is blocked, but review may still move independently, so the first blocked_external observation is not an interactive stop:
  • Interactive self-sustaining watch: without asking, apply the same review-still-coming judgment and re-arm at the normal polling interval (--interval 150) with --blocked-external-drain-seconds 300 when no review looks to be on its way, or --blocked-external-drain-seconds 900 when one does. The helper keeps a clock tied to the current head. New or edited external feedback, a submitted review or reviewer signal that moved, or a new head resets it; an unchanged approval gate, the loop's own replies, check/base/stack movement, and records of how an item was handled do not. Incoming feedback still wakes ahead of the approval gate — resolve it immediately, then re-arm the wait on the new evidence. If approval clears, return to the ordinary CI watch.
  • Drain expiry: blocked-external-drained is the wake at which you decide. At 900 quiet seconds, concrete prior current-head timing from the same reviewer may justify one re-arm with --blocked-external-drain-seconds 1800; it may never shorten the 900-second floor or extend beyond 1800 on a merely missing completion signal. When no review looked to be coming, 300 seconds is terminal — but apply the review-still-coming judgment once more before handing back. A reviewer can announce itself after the wait length was chosen, and nothing during the wait observes that on its own, so the expiry wake is the only place that movement can still be caught. Only an explicit user request to keep watching the approval gate for a longer stated duration overrides these defaults, and it remains capped by this invocation's original budget.
  • Handback: once the selected drain expires with the approval gate still present, stop without asking another question. Report that all observed feedback was handled, how long the current head was review-quiet, that CI never ran because maintainer approval is still required, and give the host-rendered resume invocation. A later notification or explicit re-invocation starts the next bounded watch.
  • Pipeline / unattended: do not drain, ask, or spin — return a blocked-external residual with the run URL and terminate. Its bounded orchestrator contract explicitly does not wait on human review or approval.
  • Checkpoint: process the current tick, report the approval gate, state that monitoring is paused, and give the resume invocation; it cannot enforce elapsed drain time itself.
  • Budget exhausted — active invocation_elapsed_seconds reaches the fixed invocation budget (default 8h of active watch time, or the duration the user selected at entry), or raw wall-clock reaches the 3-calendar-day backstop, a round-count cap the user set, or the user aborts. The max-runtime wake names which ceiling was hit via max_runtime_ceiling (active-budget or backstop). Watch re-arms and confirmed-managed-stack layer transitions must match the original ID, start, and budget; they can neither reset nor extend the cap and preserve accumulated dead time. The deadline's final refresh may still report terminal or an already-settled merge-ready; both stop immediately and start no new work. Otherwise max-runtime outranks actionable/residual work so no additional agent round begins. On max-runtime, report the emitted invocation_elapsed_seconds and budget, never persisted_state_age_seconds, and do not automatically start another invocation. This is the blunt cost floor beneath the stop in references/tick.md that fires when the PR's trajectory shows it is not converging — it catches a runaway that never trips that trigger, not the normal way a stuck PR ends. A bounded invocation hands control back; only a later explicit user/orchestrator invocation starts another budget.

Standing residuals — report them, then keep watching (these do NOT end the self-sustaining loop):

  • **needs-human** — accumulated typed decisions from ce-resolve-pr-feedback or ce-debug, or a semantic merge conflict Step 2 (the tick) could not resolve mechanically. A managed upstack conflict follows the narrower rule of Step 7 (managed upstack maintenance): abort the manager transaction and report it rather than deciding another PR layer's semantics. Persist each complete residual through the shared atomic mark, show its full decision payload, and leave every covered review thread open. A parked decision blocks merge-ready, but in interactive continuous mode it does not end the watch: keep handling independent review and CI streams. The snapshot invalidates the grouped residual and makes every surviving source actionable again when any covered source changes or disappears; never maintain a separate route-specific decision or reopen path.
  • **blocked-failing** — a dispatched check ce-debug left terminally red (has_failing_checks with counts.ci == 0, nothing new to dispatch). Same shape: report the red residual, it blocks merge-ready, but a later commit or head SHA may clear it — keep watching, and the detector will not re-wake on the same red residual (it compares against the state recorded when the watch was armed). Only a true stop above, or the user, ends the loop.
  • **stack-blocked** — the target is manager-stale or of unknown managed freshness while GitHub does not report it certain MERGEABLE/CLEAN (plain trunk drift under a CLEAN read is not a blocker), manager discovery failed, or Step 7 could not complete its clean upstack transaction. Report the stack_blocker and relevant pr_chain entries; continue review/CI work, but do not perform an ordinary base update or declare the target ready. A later manager sync, successful probe, or successful Step 7 maintenance clears the residual. A remaining stale upstack entry is a stack-health residual even when the target can be reported ready as next.

Is a review still coming? (part of the looks-ready check). The settle window tells you the PR stopped moving. It does not tell you a review is not on its way — the window can elapse before a backgrounded reviewer even starts. Judge that separately at the settle decision, from one cheap gh look at the current head, covering every place an announcement can arrive: reactions on the PR body, top-level comments, the check runs on that head, and reviews against it. A resumed run has no memory of an interim comment it already classified, and a dispatched one is absent from the snapshot, so the lookup is the only place it can still be seen.

A reviewer that announces itself — a 👀 reaction, a "reviewing…" note — has told you it started. Nothing obliges it to retract that when it finishes, so a standing announcement is not evidence that work continues. Look instead for what that same reviewer produced on this head, and ask whether it accounts for the review it announced. Something carrying that reviewer's verdict — its review, its comment, or a check run that is its review — having reached a terminal conclusion means it stopped: say which, and never read a timeout or a skip as approval. Anything of its still running means it is still working. Output that does not account for the announced review leaves the review outstanding, so treat that reviewer like one that produced nothing: an unrelated check from the same app finishing while its review has not appeared is not the review finishing. A reviewer that announced itself and has nothing to show for it either way is the genuinely undecidable case.

An announcement is not the only evidence a review is coming. A reviewer that reviewed an earlier head and not this one has told you the same thing through its own history on this PR, and many reviewers work that way without ever announcing anything — in some repos no reviewer announces at all. Treat that reviewer as one that announced with nothing to show yet, and it clears the same way: when it reviews this head, or when the bounded wait runs out.

Keep the asymmetry in mind: a present signal is informative, an absent one tells you nothing, since many reviewers announce nothing and simply post. So never wait terminally for a done signal, and never let a missing one block on its own.

Wait while you can see work in progress, and wait a bounded while when a reviewer announced itself with nothing to show for it. Re-arm by re-running the arm command with a longer --settle-seconds — passing it is what makes the re-arm real, since quiet already exceeds the 300s default and the ordinary arm would re-fire on the next poll. Use: about 900, extended once to no more than 1800 when concrete prior timing for that reviewer justifies it. Those are ceilings, not targets — announcing reviewers observed here finish in four to six minutes, while a slow reviewer that never announces had a 21.6-minute p90 over 157 reviews and a much longer tail beyond it. Once 1800 quiet seconds pass on unchanged evidence, stop and say plainly what you could not confirm; never re-arm past it on the same unchanged evidence. A widened window is your judgment about the evidence you looked at, so when that evidence moves the watch wakes you on review-evidence-moved rather than sleeping the window out against a state that has changed. Re-judge from the current head as at any settle decision: if what moved accounts for the review you were waiting on, the ordinary window decides again, and if it does not, re-arm as before. The engine reports only that something moved; whether it resolved anything is yours. Readiness is a recommendation to the user and never authorization to merge, except under posture:stack-land, where selecting that posture was the user's advance yes and a settled prefix does land. So calling it early usually costs only a disclosure, while under stack-land it costs landing sooner than the reviewer finished — and holding forever costs the PR in every posture.

Raw lines 7 to 37
Names a skill ce-commit-push-pr :14
Names a skill ce-resolve-pr-feedback :25
Names a skill ce-debug :25
Starts an agent dispatched :26
Starts an agent dispatch :26
Involves a person and wait :37