Run delegated work reliably — writing subagent charters, verifying subagent claims, keeping judgment at the orchestrator tier, ledger discipline, recovering from interruptions, and shipping/merging lane PRs. Use when spawning subagents or workflows, coordinating parallel lanes, resuming after a session limit or compaction, or rebasing and merging a lane's PR. The subagents skill covers task sizing and model choice; this skill covers everything after the spawn.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Instruções da origem · Visualização somente leitura
name
orchestration
description
Run delegated work reliably — writing subagent charters, verifying subagent claims, keeping judgment at the orchestrator tier, ledger discipline, recovering from interruptions, and shipping/merging lane PRs. Use when spawning subagents or workflows, coordinating parallel lanes, resuming after a session limit or compaction, or rebasing and merging a lane's PR. The subagents skill covers task sizing and model choice; this skill covers everything after the spawn.
Orchestration
Delegation only works when the orchestrator treats every subagent claim as unverified and every judgment call as its own. These rules were each paid for by a real incident.
Charters
A charter is the task prompt a subagent receives. Requirements:
Reference every document by absolute path, and only paths that live in the repository — repo skills under .claude/skills/, repo scripts behind their package commands. A relative path resolves differently (or not at all) in the agent's working directory, and a personal home-directory path can vanish out from under a live agent: ~/.claude/skills was deleted mid-goal to end personal/project skill drift, leaving in-flight charters instructing agents to sweep browsers from a path that no longer existed while the repo's own pnpm run browser:sweep was the live command.
When parallel lanes could touch the same module, name the sibling lanes and give each an explicit do-not-touch list of files/functions the others own. For genuinely shared append-only files (routes config, nav layout, seeds), say up front that rebase conflicts there resolve keep-both. A fence names artifact classes as well as files — E2E specs, docs articles, and seed sections are the verification stage's territory — because a file-level list cannot fence a file that does not exist yet, and a build stage drifted into writing the spec its verification stage owned.
Assign each subagent an explicit scratch-file namespace — its lane or task name as a filename prefix — and forbid it from writing any shared scratchpad file, above all the orchestrator's LEDGER.md. Parallel agents that share a scratch filename clobber each other's state, and a fix agent that writes its own notes over the session ledger destroys the orchestrator's recovery record.
Include a stop-on-contradiction clause: if the charter's factual premise (a claimed bug, a claimed missing feature, a spec citation) doesn't survive verification against the primary source, the agent halts that item and reports with citations instead of inventing. "Verified already correct, no change made" is a valid, expected outcome. Charter-supplied names — slugs, titles, feature labels — fall under the same clause: an agent that discovers the real feature differs from the charter's name must correct the name and flag it, not ship correct content under a stale identifier.
When two reference sources disagree, the charter names the conflict for adjudication — it never silently picks one. A charter's factual claims are no more trustworthy than a builder's until verified.
A charter or goal text that enumerates a derivable structure — a dependency graph, a consumer list, a coverage set — instructs the agent to re-derive the complete set from primary sources and treat the enumeration as examples to check against, never as the whole set. Stop-on-contradiction cannot catch an incomplete list: nothing contradicts it, so its gaps ship. A five-edge dependency graph hand-written into a goal text was encoded verbatim as a registry's whole truth, and the guard built on it approved variants that then died mid-transaction on a generic error.
A charter for any agent that publishes text — an issue, a PR body, review comments — forbids personal data from customer datasets (names, emails) in the published artifact unless strictly necessary, and the orchestrator scans the artifact for it before shipping. A dump-sourced operator email once shipped inside a published investigation issue and had to be redacted after the fact.
Instruct agents to run slow verification commands (build, tsc, tests) synchronously in the foreground, and to deliver their full final report as their last message — never to end the turn "waiting on CI" or any background process. An agent that backgrounds a check and ends its turn waiting on a notification is terminally stalled — its turn ending is final, and a lane that signed off with "clean, waiting on CI" had to be resumed just to extract the report it never sent. An agent never polls a process it backgrounded either — one foreground wait, or hand the wait up. Machine-level waits (a Docker image pull, an environment stall) belong to the orchestrator, who takes them over machine-side while the agent proceeds; repeated "check the state" turns have eaten a whole stage's context window.
Write each new charter/script fresh with the Write tool. Deriving one by programmatically splicing a previous one introduces silent syntax errors.
A parameterized script must parse args defensively (string-or-object) and hard-throw on any missing required field — a silently-undefined interpolation produces a plausible-looking empty result that reads as a clean pass.
A multi-stage script carries its charter discipline in the shared preamble from the first draft — commit at every milestone, read targeted ranges instead of whole generated files — never patched into one stage after a failure exposes the gap. A stage whose preamble lacked it was stopped at its context threshold with zero commits and eleven uncommitted files; the sibling stage that carried it landed five milestone commits over a comparable span.
Every build charter carries a classify-the-disk-state-first preamble from its first draft: before building anything, read git status and git log in the lane's worktree, classify every commit and dirty file as done, partial, or untouched, verify-don't-redo whatever is already correct, and run worktree:setup only when the lane's worktree does not exist. A workflow auto-retries a dead agent straight back into the same worktree, so half-finished work on disk is a normal starting state rather than an exception. An API-level event killed a four-lane wave whose charters said only "run worktree:setup if the worktree does not exist yet"; the retries landed in worktrees holding three to five commits and dirty trees apiece and classified them only on their own initiative, and the preamble had to be patched in at relaunch.
A slice that ships a route, loader, or form must drive that surface live at least once — a minimal browser interaction or a real-Request smoke — before handoff. A unit-only exit bar passes code whose query crashes at runtime or whose form cannot submit (a select with no name attribute).
A live proof binds only the commits that preceded it. Sequence the browser walkthrough as the charter's last step, after the final commit, and redo it after any later change to the proven surface — a proof that predates a schema or handler commit is evidence of nothing, and a redone proof regularly catches what the suite missed (a coercion regression, a state-update race). The same binding governs specs across stage boundaries: a later stage can invalidate a spec an earlier stage wrote, so the verification stage re-runs every one of the lane's specs after the last build commit — a refusal spec asserting one stage's toast went red the moment the next stage reshaped that refusal, and nothing had re-run across the boundary.
A skeptic or verifier charter carries TWO acceptance rubrics, not one: a finding stands if either (a) its concrete-input failure scenario occurs at runtime, or (b) it identifies a violation of a codified house rule or doctrine in the work under review. A runtime-only rubric refutes correct doctrine findings — a migration that models a reversible toggle as one action-enum table where the database-design skill prescribes paired event tables — exactly when the fix is cheapest. Doctrine findings against unmerged schema or shape default to fix-now, because schema shapes are effectively permanent once merged.
Verify, never trust
Re-run the gates yourself before advancing any stage on a subagent's self-report.
Reconcile numbers exactly: baseline + computed delta = measured, and identical across two runs. A mismatch is a hard stop, not noise.
A task counts as launched only when its task/run id from the tool result is in the ledger. A written script or a narrated intent is not a running task. Copy every id out of the returned tool result — never from memory or prediction; when a launch and its ledger entry go out in one parallel call, write TBD and fill it in after the result returns. An id written in the same message that launched the task is a prediction, and twice it was wrong.
Independent lanes launch simultaneously, never in staggered waves. Host contention (CPU, database) slows every lane's gates but never justifies holding a lane back — an idle lane costs more than a slow gate.
A review or QA returning zero findings is only a clean pass if its agents all completed. Errored finders, an implausibly fast run, or a wrong agent count mean the run is broken — relaunch it.
Findings about uncommitted working-tree state from a parallel review fan-out are suspect: when finders share one worktree, one finder's in-flight mutation-proof — code deliberately broken to validate a test, then restored — is visible to its siblings and reports as a phantom defect. Verify any working-tree observation against the commit under review (git show HEAD:file), and either require finders to mutation-prove only against committed state and restore immediately, or discount working-tree-only observations at the verify stage.
Independently probe a shipping agent's claimed git state (git merge-base <lane> origin/main vs origin/main's tip) before merging. Verify mechanical batch edits landed by grepping the expected before/after state, not by exit code.
A mutation test must sabotage the transformation under test, never the input it reads. When a gate re-derives both sides of its comparison from the same source — a parser diffed against its own re-parse — mutating the source leaves both sides agreeing and the gate green, proving nothing; break the transformation (drop a word inside the parser) and watch every output fail. A wrong-sided mutation test once read as a proven gate when it had exercised nothing.
Before treating a probe's mismatch as a finding, validate the probe itself against a known-good case — a fidelity spot-check once "failed" solely because the probe's own text flattening left timing lines interleaved with the prose it matched against. And prefer the dumbest direct check over a clever detector: an n-gram loop detector reported zero loops on a file whose raw line counts (sort | uniq -c) showed one line repeated 1,691 times.
The orchestrator's PR review reads every line of the diff against the binding doctrine of the surfaces it touches — a shaped project's document contracts, the reference implementations it names, and the repo's codified skills — regardless of what the PR body flags. The author's flag is never the safeguard: a page-wide raw-fetch store with bespoke retry and revalidation machinery shipped through review while the shaping document prescribed inheriting the framework's own submission machinery, because everyone read only what the body mentioned — the departure sat unflagged in plain sight in the diff. A goal is never met while its implementation contradicts its shaping document, and conformance is checked at every PR, not discovered at goal close.
Judgment stays at the top
Never trade the mainline for an edge case: a fix whose cost lands on the bulk of use cases to close a rare corner is the wrong shape, however clean the mechanism looks. Accept the residual and record it, or scope the mitigation to the edge itself. Shipping the full route manifest up front (routeDiscovery: 'initial') to close one offline corner — a submit to a never-visited write route — was denied for exactly this: it reverses lazy route discovery, which exists because full manifests scale badly, and charges every session to fix a case almost nobody hits.
Every demand gets an architecture round before any delegation: zoom out and map the mechanism behind the ask, where else that mechanism lives, and the repercussions of candidate fixes — then design at the level the root cause lives. A defect surfacing in one route but rooted in a shared primitive gets the primitive fixed, never a route-local workaround; a batch of demands gets grouped by mechanism, not by surface, before lanes are cut. Zoom in only with full domain over the systemic impact. A route-local patch of a polling defect owned by a framework hook would have left the same bug live in fifteen sibling routes; fixing the hook also surfaced a second latent defect in it.
A stakeholder's demand names what they see. Before designing or interviewing against it, translate every term through the navigation the requester actually uses (app/routes/app/nav.ts), never through internal section, module, or schema names — an analysis framed on internals reads as wrong to the user even when technically coherent, and one design interview had to be restarted after the user caught the frame ("recipes" meant the Production menu's entry, not the seed section).
Answer any question about repo machinery only after reading the primary source completely: every file in .github/workflows/ before stating what CI does — one check name can live in two workflows, a per-PR job and a scheduled twin — and real run history (gh run list) before stating what a job costs in time, since a job's timeout is a ceiling and never an estimate. When the user's question hints that something is missing, it is a diligence probe, not a request for a guess: assemble the complete factual picture from the sources, then answer once. Seven consecutive user messages on one thread went into forcing a workflow-file read that should have preceded the first answer, every probe meeting a fresh inference instead — and in delegated work nobody is there to supply that correction.
Design and adjudication are orchestrator-tier work. When the evidence under a design changes (stale reference, corrected spec), redo the design at the orchestrator tier — never hand the stale design down with a "re-verify your citations" instruction.
Synthesizing a multi-agent review's findings into an adjudicated register is itself adjudication, not mechanical distillation. Read every report yourself and build the register personally — a synthesis delegated to a subagent launders the miners' claims into rulings nobody made, and the fix program built on it inherits judgments the orchestrator never exercised.
Ledger discipline
Structure the ledger as a STANDING DIRECTIVES head (settled policy, kept current) plus a chronological log. Reground after compaction from the head AND the tail — a tail-only reground lets settled directives fade.
The ledger keeps exactly one live head. When a new head goes in, move the superseded one to an archive file beside the ledger instead of stacking it below — stacked dead heads push the file past what a single read returns and tax every reground with prose no longer true. One goal's ledger reached ~390KB carrying eleven stacked superseded heads, and by the end every update to it needed byte-offset reads and count-asserted scripted edits.
Record launches with their task/run ids, lanes with their base commits, and verdicts with their evidence.
When a long effort concludes, externalize the durable record (decisions, divergences, audit results) to a permanent artifact — a GitHub issue or PR body — before the scratchpad is cleaned up.
Recovery after an interruption
Step 0 is always to positively enumerate what is alive (task list, workflow roster) — a missing state file or empty output file usually means still-running, not dead. Declaring a live task dead and relaunching into its worktree corrupts both. Then, for tasks with positive evidence of death:
Audit the worktree first: git status/git log. Clean tree at a known commit → relaunch the charter unedited. Dirty tree → launch a continuation agent on the same worktree whose first step is diffing working tree vs last commit to classify done/partial/untouched, then finishing — never a blind restart. A continuation charter lists the remainder and says explicitly that when the listed remainder is done, STOP: a continuation that finishes early otherwise runs on into the next stage's ground, and one built two of a later stage's commits plus a half-written file nobody had chartered.
Audit the remote before writing any continuation charter: git ls-remote for the lane's branch and gh pr list --head <branch> for its PR. A dead agent may have finished — one continuation was chartered on a "nothing pushed" premise while the original agent's PR was already open with green CI, and the charter sent the new agent to redo completed work.
A QA agent killed mid-mutation-proof can leave deliberately broken code on disk — check for a live mutation before anything else runs there.
An agent that is still addressable resumes by message from its last checkpoint, keeping its context, instead of restarting cold — but NEVER message an agent a live workflow still owns. The message forks the transcript into two live instances sharing one worktree: each sees the other's edits as a foreign actor's, and one fork's honorable stop can strand half the work. Deliver mid-flight course corrections to a workflow-owned agent only through the workflow (edit the script and resume the run), or wait for the run to end and relaunch with an amended charter.
Probe returned capacity by attempting real work. Never idle-wait.
Shipping and merging a lane
Write every PR title and description for an external reader: someone with zero knowledge of the execution that produced the change must understand what it is and why it matters. No orchestration vocabulary (goals, lanes, charters, sanctioned allowances, finder/verifier counts, workspace skills or tooling-repo names), and no superseded project state — describe what the change IS in the product's own terms, and rewrite the body as the work evolves so it always reads as current truth, not history.
When the user shares another organization's work (a PR, a repo, a pattern) as the model for a change here, that source never appears in anything visible in this repo — PR bodies, commit messages, code, comments, or issues. Describe the change entirely on its own terms; the reference lives only in the conversation.
Merge PRs with a merge commit (gh pr merge --merge) — the repo's convention. Never squash or rebase-merge.
Never chain the merge with branch or worktree teardown. A merge can be rejected transiently (after a force-push, GitHub recomputes mergeability for ~30s and gh pr merge fails with "not mergeable"), and a chained cleanup then runs anyway — deleting the remote branch auto-closes the open PR. Merge, confirm the merged state with a fresh read, then tear down, each step checked. If a branch deletion does close a PR, the commits survive at pull/<n>/head: restore the branch (or repush the surviving local one), gh pr reopen, and merge properly.
Before every teardown, positively enumerate the live-agent roster and confirm none is pointed at that worktree. Read-only scouts and auditors carry worktree paths in their charters and leave no trace in the lane's own PR state, so a merged-and-shipped lane is not evidence its worktree is free — one had to be restored mid-flight as a plain checkout because a live agent's charter cited the path.
The repo requires a PR's head branch to be up to date with its base before merging. When gh pr merge is rejected with "the head branch is not up to date", run gh pr update-branch <n>, wait for the new check run to register (~45s), watch it, then take a fresh gh pr checks read and merge on that.
Verify a large PR's scope with git diff --stat against the merge base — gh pr view --json files silently caps at 100 files, and a scope check that only sees the first 100 blesses whatever hides past the cap.
Before rebasing, predict the conflict surface: intersect the lane's touched files with what main gained since the lane's base. Empty intersection → expect a clean rebase; non-empty → you know exactly which files need care.
On a non-empty intersection, a conflict-free rebase is not evidence of correctness. Git auto-merges a lane's hunks around a sibling's rewrite of the same function, leaving code that references symbols the lane deleted — and the lane's analysis, written against pre-merge main, can assert facts the sibling has since made false. Re-derive the lane's claims about the intersecting files against post-merge main, and resolve the rebase semantically — take the sibling's merged shape as authoritative and re-apply the lane's intent on top — never by accepting whatever auto-merge produced.
Personally source-read any confirmed "inconsistent with spec/reference" finding before directing the fix — especially when the fix would reverse a prior ruling. A finding's observation can be accurate while its verdict of "wrong" is not. Doctrine-flavored findings get the same read, not a shortcut: a builder's confident "this is exactly the hazard CLAUDE.md names" was false on the file it cited, on the kind of date the rows actually carried, and on the ordering it predicted, and a whole fix lane was spent proving the premise false. Charter every fix lane to verify its premise before changing anything.
An investigation chartered around a stated finding tends to confirm and amplify it: the charter's frame decides what the agent looks for, so a mechanism living in an adjacent flow stays invisible even when the agent's own appendix names it. Before designing on, escalating, or alarming the user with an investigation's headline conclusion, commission one independent second perspective under a different frame (compare against a reference implementation, or charter a refuter) and adjudicate any disagreement yourself against primary sources.
An agent's claim that a symbol has a single consumer ("only seed.ts imports this") is a factual claim — grep the whole repo, tests/ included, before directing a refactor that removes or narrows a shared contract on its strength. It bites hardest when the claim justifies reversing another agent's deliberate earlier design, and green CI is no safety net when the broken consumer only runs against state CI never exercises, like a converging seed over a persistent local database.
Audit PR-body citations ("per spec X", "per source Y at file:line") against the actual cited location, and check any "deferred as polish / out of scope" claim against the actual contract. Builders produce plausible but fabricated attributions.
Never conclude something is absent from a truncated search: a grep … | head that fills its quota hides the line that would refute the absence. Re-run unbounded, or open the file at the cited range, before acting on any missing-symbol or missing-assertion claim — a truncated pipe nearly directed a fix for a "missing" test assertion that existed exactly where cited.
Any change to app/framework/ made by a fix/QA agent gets the orchestrator's personal diff read before shipping — its blast radius exceeds any lane's review scope.
When a builder reports it verified a UI flow by simulating requests (fetching the form's FormData, forging a session) instead of real interaction, treat that as an unverified claim and dispatch a real-interaction prober before relying on it. A "harness quirk" explanation for why real clicks failed is itself a claim to verify.
A goal text, design document, or any other foundational artifact drafted for the user is built on a verified inventory of the current codebase, never on memory of it — commission or perform the primary-source study first. A goal draft written without that diligence missed a whole class of existing sync machinery and had to be redone after the user caught it.
At design time, inventory every seam the build cannot exercise without something only the user can supply — a vendor API key, a paid account, a physical device — and hand that list to the user while the design is still open, never at verification time when the arrangement no longer fits. When a dependency cannot be arranged in time, shipping that seam reviewed-but-never-exercised is the user's explicit decision to make, recorded as a known risk. A machine-translation vendor seam was already built before anyone said out loud that no test ever calls the real API, by which point the account could not be set up in time, and the user had to ask the question the design should have answered: "Is there any other part of this project that will not be able to be exercised during building unless I provide you with something?"
When keeping an approach green demands case-by-case fixes that each breed new edge cases — or a single lane grinds for hours on one defect — that is a design smell in the approach itself, not a hard fix: pause the lane and re-open the shape question with the user instead of pushing through. A pixel-equality gate consumed a four-hour masking war, and the user, not the orchestrator, had to call the smell; the reshaped design (gate only the deterministic subset, report the rest for human eyes) held immediately.
Grounding priority when state or policy is uncertain: primary sources (git, live files, the actual spec) beat live skills, and live skills beat ledger notes or compacted memory. On a policy detail, the live skill file always wins over ledger shorthand.
When parallel lanes independently invent shapes for the same shared surface, adjudicate one canon and give later-shipping lanes an explicit adopt-the-canon duty at rebase.
An invariant that spans several lanes' data — a shared ledger fixture, a balance every lane's writes must conserve — is orchestrator-tier design work. Derive it yourself from primary sources, commit it as a fixture, and hand lanes only consumption rules; never let each lane implement its local view of the global rule. Two successive lane agents each handled their own slice of a shared stock balance plausibly and broke the global invariant both times — a lane cannot see the whole.
A lane reports out-of-scope findings with repro evidence; it never fixes them inline. Every finding gets its disposition the moment it reaches the orchestrator, from whatever surface — a lane's report, an audit register, or a finding read in a PR body at review time — and the disposition is fix-now by default: a finding that is small, well-scoped, and needs no user ruling gets fixed immediately — folded into the reporting lane's open PR when it owns the file, otherwise a fresh fix lane — never parked. A GitHub issue is legitimate only for a decision the user must make, work blocked on other work, or an unknown-cause investigation someone will actually run. Never file an issue as idea storage — no "maybe someday" refactors, no future-abstraction notes (Shape Up's no-backlogs rule: really important ideas come back on their own; a standing pile only makes everyone feel behind). During a scoped goal, a findings register is fine as a cycle-scoped working list — it dissolves into fixes and decision issues when the effort ends, never outliving it.
A designer's "too invasive / out of scope" blast-radius claim is a factual claim, not a judgment call — grep it before accepting the compromise it justifies.
Any selection of an external tool, model, library, or service starts with live web research, never training knowledge alone — that landscape moves faster than any cutoff, and a recommendation grounded on months-stale knowledge reads as authoritative while comparing options that have since been superseded. The user had to order the search mid-design once ("your cut-off is ~6 months old"); in delegated work nobody is there to.
A shared shrink-only registry (a pending list every lane deletes entries from) is resolved by construction, never by conflict-hunk surgery: take the merge base's current copy, delete exactly this lane's originally-removed entries (captured from its diff before the rebase), then verify the removed set stays inside the lane's slice and the count arithmetic closes. Deleting conflict blocks textually silently drops neighboring keep-lines the moment a hunk mixes entries being removed with entries that must stay.
Run rebase and post-rebase gates as separate, individually-checked steps — a chained command can swallow a mid-rebase conflict's exit code.
After rebasing an approved commit, run a patch-identity check: diff the rebased patch against the approved patch (sorted added/removed line sets). A rebase is itself a mutation risk — a failed automated edit can commit conflict markers, and only an identity check catches it.
When two open PRs both carry migrations, the second to merge must rename its migration file to a timestamp later than every migration already on main, then re-rebase and regenerate types from a freshly migrated database after the first lands — a migration that is new but timestamped earlier than an already-applied one can break the migrator, and git can auto-merge a semantically wrong types.d.ts. When two lanes touch the same seam, merge the larger diff first and let the smaller one absorb the rebase.
A lane that changes user-visible copy, CTAs, or navigation greps tests/ for the retired words before pushing — a spec asserting the old copy lives outside the lane's own files, the unit gate never executes Playwright specs, and the full E2E suite runs only on the PR's CI (never locally, per CLAUDE.md), so the grep is what catches it before the CI round trip.
A lane that changes product semantics — what a status does, what an action permits — additionally greps the whole repo for prose stating the old behavior: UI helper text, tooltips, empty states, emails, not just docs and tests/*.spec.ts. Stale in-app copy contradicting shipped semantics survives every gate — no spec asserts it, the docs live elsewhere, and it reads fine to a reviewer who doesn't know the new rules — so only the grep catches it before a user does.
Watch CI with gh pr checks <n> --watch (exit code as verdict, not parsed text). Before merging, do one fresh direct gh pr checks read — never merge on a monitor's word, monitors die on network timeouts and carry parsing bugs.
A PR whose files all fall inside the CI path filter's skip trees (the changes job in .github/workflows/ci.yml is the authority on which paths) runs only that classification job: E2E, lint/tsc/unit, and docs-screenshots report "skipping" by design, and the skipped required checks satisfy branch protection — mergeStateStatus goes CLEAN and the merge proceeds. Live-proven on a skills-only PR. Don't wait for, re-trigger, or investigate jobs whose status is "skipping" on such a PR; do run the fast gates locally when the change could affect them, since nothing on the PR will.
A PR showing zero checks is not "CI hasn't started" — after a couple of minutes it means CI will never start. The pull_request workflow runs on the merge commit, so a PR whose branch conflicts with base (gh pr view <n> --json mergeStateStatus → DIRTY) has no merge commit to build and fires no checks at all. Binary files make this likely (two lanes regenerating the same screenshot conflict invisibly — no textual merge exists). The fix is a rebase resolving the conflict; for a generated binary, take either side, then regenerate it authoritatively against the rebased tree rather than trusting the manual resolution.
Arm gh pr checks <n> --watch only after the push's new check run has registered (sleep ~30s or poll first). A watch armed immediately binds to the superseded run and exits nonzero the moment that run disappears, reading as a false CI failure. A single update-branch can also spawn two check sets moments apart, so a pending-poll can bind the watch to the first while the second becomes the one that counts — the watch then exits green early. When the fresh pre-merge read shows pending checks after a green watch, that is what happened: re-arm the watch on the current set and keep the merge gated on the fresh read.
Take full commit SHAs only from git rev-parse or the API — never expand a short SHA by guessing. A fabricated SHA in a check-run poll loop waits forever on a ref that does not exist, and its silence reads as CI still pending.
update-branch mutates the remote PR head with a merge commit, and calling it immediately after your own push can 422 on a stale-head race (retry after settling). Fetch and reconcile the remote head before pushing any further commits, or the push is rejected as non-fast-forward.
A lane's local branch and its PR head branch can differ — a finalizer that pushed via refspec leaves the worktree on worktree/<lane> while the PR head carries another name. Push follow-up commits with git push origin HEAD:<pr-head-branch>, taking the head name from gh pr view --json headRefName, never from the local branch name.
A "failed" CI job with no step concluding failure/cancelled (check gh api .../jobs) is infrastructure death — rerun it. A job with a real failing step is investigated before anything merges.
Prepared-ahead scripts (placeholders patched at launch) keep the pipeline saturated, but audit a prepared script's content immediately before launching it — staleness there has shipped wrong charters.