gates · git:20261024.096391f · 2026-10-24 · sha256 1228fc98b580b957

gates git:20261024.096391fA

Immutable. This exact content never changes and is served at /api/v1/blob/1228fc98b580b957.

---
name: gates
description: The canonical AskUserQuestion conventions for every orc gate — class-tagged header chips, Recommended-first options, side-by-side `preview` for preview-then-confirm, multiSelect chunking, notes as the rewrite channel, and the --auto ladder
when_to_use: Use when about to render an orc gate.
---

# Gates

Every orc gate is ONE `AskUserQuestion` call shaped by these rules. The gate classes themselves (hard-outward / soft-inward / escalation-only) are defined in `orc:using-orc`; the 1–3 line context block before the call is the **⛔ Gate** callout from `orc:callouts`. Options never go inside the callout — the question widget renders them.

## 1. Header chip = gate class

The `header` chip (≤12 chars) tells the user what kind of decision this is. Hard-outward and escalation gates use a **closed vocabulary**, so the class is readable at a glance — and the orc mod reads it to draw a gate badge above the dialog:

| Class | Chips | Rule |
|---|---|---|
| Hard-outward | `Publish` (evidence / artifact upload) · `Post` (PR review, replies, comments) · `Tracker` (issue / Jira writes) | Always asks — no flag, policy, or settled decision skips it. Name the exact target (repo, PR #, ticket key) in the question. |
| Escalation-only | `Escalation` | Never asked proactively; stops the run at every policy level. |
| Soft-inward | Free, short noun: `Plan`, `Driver`, `PR size`, `Compose`, `Next step`, … | Never reuse an outward or escalation chip. |

## 2. Options

- 2–4 options. Never add an "Other" option — the widget always provides free text.
- Recommended option **first**, label suffixed `(Recommended)`. Exactly one, or none when there is no defensible default.
- Each `description` states the consequence ("pushes to origin", "posts 6 comments to #123"), not a restatement of the label.
- A destructive or outward option names its target in the label or description.

## 3. `preview` for preview-then-confirm

When the user approves a payload (PR body, review comments, upload manifest, slice table, stack split, Jira tree):

- Put the payload in the option's `preview` field (markdown, monospace) — single-select only. Alternatives render side by side: give each variant its own option + preview (e.g. caveman vs full PR body).
- The `📋 Preview` callout stays as a one-line headline; do not also print the full payload in a fence — one rendering.
- Payload over ~60 lines: write it to `${ORC_STATE_DIR}/<branch>/files/` and preview the head plus the path.
- No `AskUserQuestion` available (headless): if `ORC_FACTORY=1`, follow §8. Otherwise print the callout + fenced payload, then stop for a plain-text answer. Hard-outward gates still never auto-proceed.

## 4. Picking items: `multiSelect` chunks

To drop / keep items from a numbered list (replies, comments, slices):

- `multiSelect: true`, one question per chunk of **4 items** ("Drop which of comments 1–4?"), up to 4 questions in the same call (16 items max). Default = keep all.
- Never one question per item; never more than one extra round trip to apply edits.

## 5. Rewrites ride the notes

Edits to an item travel in the selection's **notes** annotation, one per line: `<n>: <new text>`. The free-text answer is accepted as a fallback in the same shape. Edited payloads re-render once in a final preview before anything outward happens.

## 6. Autopilot ladder (`--auto[=guided|full]`)

Commands that take `--auto` point here instead of restating it. The flag overrides the `interaction_policy` userConfig; resolution and the settled-decisions store live in `orc:state-protocol`.

- `manual` (default) — every soft-inward gate asks.
- `guided` — mechanical confirms auto-advance with a printed one-liner (`➡️ auto: <choice> — guided`); judgment calls still ask.
- `full` (bare `--auto`) — soft-inward gates resolve from settled decisions; the run stops only on escalation-only conditions.
- Hard-outward gates are unaffected at every level. Auto never picks an option that writes outward or overrides a budget (e.g. never "Open as one big PR").
- An escalation-only stop during a `full` run is the moment an unattended user must hear about: send a `PushNotification` (when the tool is available) naming the phase and the blocker, then ask.

## 7. Batching

One decision point = one `AskUserQuestion` call, up to 4 questions. Ask everything that's answerable now in that call; don't serialize questions the user could answer together.

## 8. Factory mode (`ORC_FACTORY=1`)

No human is present. A controller writes `/in/stage.json`; you write `/out/result.json`.

- Never call `AskUserQuestion` at any gate.
- Soft-inward gate: read `orc-state decision get <key>`; if unset, read `decisions[]` in the stage input.
- No decision exists and the call is a true judgment: end the stage with `outcome: needs_input`.
- `needsInput[]` holds at most 3 `{question, recommended}` items; `recommended` is mandatory.
- Hard-outward action (tracker write, PR review post, evidence publish, `gh pr create`, `gh issue`): never perform it.
- Append `{kind, target, payload}` to `requested[]`; the controller's board approves it. `kind` is one of `tracker_write`, `pr_review_post`, `publish`; no other value.
- Escalation-only condition: end the stage with `outcome: fail`.
- Set `summary` to the escalation callout text and `error` to the context fence.
- Iron rules and hooks apply unchanged.
- On a `rate_limit_event`, set `rateLimited: true`.