← Files Compound EngineeringARCHIVED FILE

skills/ce-babysit-pr/references/stack.md

14.4 KB · Oct 2, 2026 · 00:33 UTC

↓ Download file

# Managed stacks: posture, discovery, transitions, upstack maintenance, landing

## Posture (full text)

Hold exactly one posture for the run. Carrier: `posture:target|stack-ready|stack-land` — distinct from `watch` / `checkpoint` / `mode:pipeline` / duration. Re-state the same posture on every managed-stack layer `--continue-invocation` transition alongside the existing budget flags.

| Posture | Behavior |
| --- | --- |
| `target` | Only the named PR. Stop at looks-ready. May offer stack-wide once when a confirmed multi-layer managed stack needs work; decline keeps the target-local stop. Never merges. |
| `stack-ready` | Once the active layer is **quiescent** — zero actionable backlog (`counts.threads/comments/ci == 0`), **no standing residual** (no open `needs-human`, no `blocked-failing` — `has_failing_checks` with nothing left to dispatch — no `stack-blocked`, no open or claimed currency item), and no delegate work in flight — automatically continue to the next open non-draft upstack layer that needs work, even while the quiescent layer's CI is still running or its settle window has not elapsed. Lower layers stay under the watcher's downstack probe; the lowest one that re-opens pulls the walk back. Never merges. Persist for the run; do not re-ask each layer. |
| `stack-land` | Like `stack-ready` for traversal. Selecting or handing off `posture:stack-land` **is** run-level land authorization. Landing still requires **settled**, not merely quiescent: once the bottom-most open layer looks ready (full Step 3 gate), merge it via `gh stack merge` + `gh stack sync`, then continue. |

**Selection:** named one PR / no stack language → default `target`, but if confirmed multi-layer managed stack ask once (only this PR vs whole stack to ready). Intent to own/finish the stack → `stack-ready`. Intent to land/merge when green → `stack-land`. Prefer intent over keyword regex. An explicit "babysit the managed stack" request selects `stack-ready` (or `stack-land` when land intent is also clear). In `mode:pipeline`, use only the posture/scope already supplied on the invocation — never ask.

When a confirmed managed stack is in play and you need CLI recipes, load `references/stack-commands.md`.

## Discovery and continuation

**Automatically classify the target's PR chain; never rely on the user to announce a stack.** The first snapshot and every later poll probe the read-only local manager with `gh stack view --json`, accepting it only when its branch list contains the target PR. If that cannot prove membership, the helper uses a read-only GraphQL fallback. A successful null stack means `pr_chain.manager_status == "absent"`. The specific stack-field schema-unavailable response also means `"absent"` only when a separate read-only lookup resolves the repository's default branch; auth, transport, rate-limit, malformed, other GraphQL, or failed default-branch probes mean `"probe-error"`. When no manager is confirmed, ordinary open-PR base/head relationships distinguish an independent PR from a manual dependency chain. Discovery never runs `gh stack checkout`, imports a stack, switches branches, or changes remote state.

**Only when the fresh snapshot has `manager_status == "confirmed"` may stack-wide continuation activate; no other classification authorizes it.** A manual dependency chain never activates stack-wide continuation: keep it target-local even when its base/head topology resembles the manager's ordered branches. `probe-error` also stays target-local and mutation-conservative until a later snapshot positively confirms the manager. Discovery still runs for every babysit — posture does not disable confirmed-manager detection or Step 7 upstack maintenance.

For a confirmed managed stack, inspect the manager's ordered entries once before choosing the active layer; this is read-only orientation, not multi-PR monitoring. Resolve **posture** per the table above before semantic work. If posture is still `target` and the requested middle PR has an unsettled downstack layer, offer once to begin at the lowest unsettled non-draft layer and proceed upward (`stack-ready`), with target-only as the alternative; do not silently redirect semantic work to another PR. If posture is already `stack-ready` or `stack-land` and the requested PR has an unsettled downstack layer, begin at the lowest unsettled non-draft layer without asking (downstack-to-upstack). If all downstack layers are settled, begin on the requested PR. When the requested PR already looks ready or later settles under `target`, offer once to continue to the immediate open non-draft upstack layer if it needs work (accepting selects `stack-ready` for the rest of the run). That one-time offer expands semantic babysit scope on an already confirmed managed stack — it is **not** a proactive suggestion to create or adopt PR stacks. An explicit request to babysit the managed stack counts as `stack-ready` acceptance, so do not ask redundantly. In `mode:pipeline`, which cannot ask, continue beyond the requested PR only when the invocation already supplied `posture:stack-ready`, `posture:stack-land`, or equivalent stack-wide scope; otherwise return the next candidate as a residual.

Once `stack-ready` or `stack-land` is in effect, that posture authorizes sequential semantic babysitting through the confirmed managed stack without asking again at each layer. Keep one active PR target and one watcher: revalidate manager membership and ordered state at each transition, stop the old watcher, switch/check out the next immediate layer, then initialize its own snapshot state with `--continue-invocation` and the same three recorded values on the flags the first snapshot used — `--invocation-id "$RUN_INVOCATION_ID" --session-started-at "$RUN_STARTED_AT" --invocation-budget-seconds "$RUN_BUDGET_SECONDS"` (the anchor flag is `--session-started-at`, not `--invocation-started-at`) — plus `--continue-dead-time-seconds <prior layer's `invocation_dead_time_seconds`>` so the shared active-time budget carries the suspended time already excluded on earlier layers (each layer's state dir accumulates its own dead time, so without this the new layer would count that prior suspend as active) — **and re-state the same `posture:` value on the continue invocation**. The invocation budget is not renewed per layer. Never skip past a draft or enter it unless the user explicitly included that draft; never advance past a layer with a `needs-human` blocker. Stop at the first draft outside scope, human-blocked layer, end of the stack, budget, or user stop. Reconfirm `manager_status == "confirmed"` before every cross-PR transition — loss of positive confirmation ends stack-wide continuation rather than degrading into manual-chain behavior.

## Pre-push baseline

**Managed-stack pre-push baseline.** Before invoking a delegate that may push the active target in a confirmed managed stack, record a recoverable baseline from a fresh `gh stack view --json`: the manager-ordered open branches at or above the target (target plus open dependents) and each branch's current remote-tracking OID on the tracking remote. Require a clean worktree and still-confirmed manager membership for the target/current branch. If either precondition fails, this is a true stop for the active invocation in every mode: do not invoke a delegate, run another tick, or arm/re-arm a watcher; state the residual and give the host-rendered resume invocation. Do not stop for missing atomic multi-ref push proof — current `gh stack push` may update branches non-atomically (`github/gh-stack#216`); prefer all-or-none when an installed manager later proves atomic push, but always re-probe after push rather than assuming it.

## Step 7: upstack maintenance after an authorized target push

7. **After an authorized target-head push in a confirmed managed stack, preserve the upstack before resuming the watch.** This is manager-owned maintenance implicitly authorized by babysitting a managed layer, not permission for arbitrary history edits. Retain the delegate-reported pushed SHA, re-run read-only `gh stack view --json`, and require that it still identifies the target PR on the current local branch. Require a clean worktree, fetch the target branch from its tracking remote, and verify both the target's local head and remote-tracking tip still equal that pushed SHA; a moved target becomes an upstack residual, never something this step rebases or overwrites. From the fresh manager order, select the first open dependent branch immediately above the target. If there is none, no cascade is needed. If any precondition fails, leave an upstack residual without importing, checking out, or guessing at the stack. Otherwise run `gh stack rebase "<first-dependent-branch>" --upstack --no-trunk --remote <tracking-remote>`, verify the target local head is still unchanged at the pushed SHA, then run `gh stack push --remote <tracking-remote>` only — never raw `git push --force`. Starting at the first dependent excludes the target from the cascading rebase; `--no-trunk` confines the operation to inter-branch propagation and avoids a stale local trunk. After push success or rejection, fetch and re-probe: verify the target still equals the delegate-reported pushed SHA (already checked above); for every **open dependent** in the baseline, compare local and remote-tracking heads to the recorded pre-push OIDs and expected post-rebase tips — do **not** treat the target's intentional post-push OID change as divergence. Do not assume all-or-none. Treat already-updated dependent remotes as observed progress; name the first rejected or divergent dependent layer and return a precise recoverable upstack residual (retry from that layer after the cause is fixed). Never claim stack readiness until manager order, ancestry, review, and CI are re-proven on every current head. If the rebase conflicts, immediately run `gh stack rebase --abort` and surface a `needs-human`/stack-sync residual — do not decide conflict semantics in another PR layer. If the target moved or a lease rejects unexpected remote state, do not retry with raw force; surface the residual. This route never applies to a manual dependency chain, and the delegated target fixers never perform it.

During accepted managed-stack continuation there is one watcher and one mutated target, but the watcher probes below: arm it with `--downstack-pr <N>` for every open lower layer in the manager order (repeat the flag per PR). It wakes `downstack-actionable` (with `downstack_prs`) when a lower layer gains a new thread, comment, failing check, or head beyond what was there at arm time; on that wake stop the watcher and return to the **lowest** re-opened non-draft layer with `--continue-invocation`, handle it, cascade, and walk back up. Also recheck the manager's ordered entries and downstack quiescence at every layer transition, immediately before an active-target mutation, and at the looks-ready decision. Never mutate two layers concurrently: a downstack return waits for any in-flight delegate on the current layer to finish. If manager confirmation disappears, end continuation and surface the classification residual.

## Layer transitions and the stack-land land step

**A confirmed managed-stack layer stop may be a run transition.** Under `stack-ready` the transition condition is quiescence (table above; a layer carrying any standing residual is not quiescent, so the walk never leaves a red or human-blocked layer behind), not settle: when the active layer has nothing actionable, report its state in one line ("quiescent, CI running" / "ready as next"), revalidate the manager and downstack, then advance to the immediate next open non-draft layer that needs work without asking again; pass through already-quiescent non-draft layers only after freshly confirming each one. Its settle window keeps running under the downstack probe; the final report states each layer's settled/quiescent state from a fresh probe. Under `stack-land`, run the land step below **before** any plain advance once the bottom-most open layer is settled (do not skip merge and walk upstack while a settled prefix is still OPEN); a merely quiescent bottom layer may be walked past but not landed. Stop before a draft unless the user explicitly included that draft in scope. Under `target`, if no continuation decision has been made and this is the originally requested PR, use Step 1's one-time offer. A decline makes the target-local looks-ready result the final stop. A `needs-human` layer remains the active layer — keep watching its independent streams, but do not advance upstack. These transition rules apply only while a fresh probe still reports `manager_status == "confirmed"`; independent PRs, manual chains, and probe errors always use the target-local stop.

**`stack-land` land step (after settle / pipeline green gates, before any plain advance).** When posture is `stack-land` and the active layer looks ready (interactive settle) **or** satisfies the pipeline success gates above, identify the **bottom-most open settled** PR in the manager order (CLI `gh stack merge <PR>` merges the full prefix through that PR atomically — never merge an upstack active PR while downstack PRs remain open when single-prefix landing is intended). Load `references/stack-commands.md` if needed, then run `gh stack merge <that-PR> --yes --squash` followed by `gh stack sync --remote <tracking-remote>`. Re-probe the landed PR's `pr_state` / queue status before treating the land as complete: on merge-queue bases, `gh stack merge` may succeed after **enqueue** while the PR stays OPEN — keep watching that PR (or return a queued residual in `mode:pipeline`) until it is actually `MERGED`; do not advance or declare pipeline success on a still-open queued prefix. Only when re-probe shows `MERGED`, treat that just-landed MERGED as a **managed-stack layer transition**: stop the watcher, re-probe the stack, and `--continue-invocation` onto the next open non-draft needing work with the same posture restated — **not** a run-level Terminal true stop for this babysit invocation. Distinguish that from externally observed `MERGED`/`CLOSED` on a layer this run did not just land (those remain true Terminal stops). On merge/sync failure, surface a needs-human / stack residual; do not fall back to `gh pr merge`. In `mode:pipeline` with `posture:stack-land`, do **not** return success on a green settled prefix until this land+sync has completed to actual `MERGED` (or failed into a residual); after a successful land transition, continue the pipeline bound on the next layer.

CLI recipes: `references/stack-commands.md`.

SHA-256: 270bddf178bd049f0a32cbbbf2fd68b32d6801b106f78a1c4578a09273345571