# Warning Gate

> For agents: start with the [agent guide](https://pi-tui.ratstack.sh/llms.txt). Every page here has a Markdown twin, and every pattern has a JSON record.

Behavioral / Overlays and dialogs · `warning-gate` · [HTML](https://pi-tui.ratstack.sh/patterns/warning-gate/) · [JSON](https://pi-tui.ratstack.sh/patterns/warning-gate.json) · [all patterns](https://pi-tui.ratstack.sh/patterns.md)

Also known as Consequence confirmation.

## Intent

Follow a consequential selection with a separate warning confirmation.

## Motivation

Dot314's tool-horizon selector adds a separate warning for broad restore choices.

## Applicability

- Use this when a broad restore or destructive choice needs an explicit warning.

## Structure

```text
choose boundary -> broad?
broad -> warning -> confirm
cancel -> no action
```

## Participants

- [`ctx.ui.select`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#interact-with-the-user): Returns a selected string or cancellation.
- [`ctx.ui.confirm`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#interact-with-the-user): Returns a confirmation decision.
- `Warning policy`: Chooses which consequential actions require another prompt.

Pi screen APIs: [`ctx.ui.select`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#interact-with-the-user), [`ctx.ui.confirm`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#interact-with-the-user), `ctx.ui.setWidget`, `ctx.ui.setStatus`

## Consequences

- A consequential choice gets a distinct confirmation step.
- The extra prompt and its thresholds are workflow-specific.

## Implementation

- The source's restore thresholds are not universal policy.
- A cancelled confirmation must not trigger the selected action.

## States

Each state was rendered at 40, 60, 80 and 120 columns in Pi's dark and light themes. Each frame links one WebP. An animated frame links its first image, then the animation.

### Choose boundary

`select`: Show narrow and broad synthetic restore choices.

Checks at every width and theme:

- width: ✓ pass
- style-leak: ✓ pass
- hard-coded-colour: ✓ pass
- height: ✓ pass

Frames:

- 40 columns: ![Warning Gate, Choose boundary, 40 columns, dark theme](https://pi-tui.ratstack.sh/frames/warning-gate/select-40-dark.839b7924c8aa.webp) ![Warning Gate, Choose boundary, 40 columns, light theme](https://pi-tui.ratstack.sh/frames/warning-gate/select-40-light.3120082f49c9.webp)
- 60 columns: ![Warning Gate, Choose boundary, 60 columns, dark theme](https://pi-tui.ratstack.sh/frames/warning-gate/select-60-dark.a12d316b739f.webp) ![Warning Gate, Choose boundary, 60 columns, light theme](https://pi-tui.ratstack.sh/frames/warning-gate/select-60-light.a41e588dd913.webp)
- 80 columns: ![Warning Gate, Choose boundary, 80 columns, dark theme](https://pi-tui.ratstack.sh/frames/warning-gate/select-80-dark.3a9110df630e.webp) ![Warning Gate, Choose boundary, 80 columns, light theme](https://pi-tui.ratstack.sh/frames/warning-gate/select-80-light.c581878bc778.webp)
- 120 columns: ![Warning Gate, Choose boundary, 120 columns, dark theme](https://pi-tui.ratstack.sh/frames/warning-gate/select-120-dark.40eda69ccd29.webp) ![Warning Gate, Choose boundary, 120 columns, light theme](https://pi-tui.ratstack.sh/frames/warning-gate/select-120-light.22034a28456f.webp)

### Broad action warning

`warning`: Show a warning after the broad choice.

Checks at every width and theme:

- width: ✓ pass
- style-leak: ✓ pass
- hard-coded-colour: ✓ pass
- height: ✓ pass

Frames:

- 40 columns: ![Warning Gate, Broad action warning, 40 columns, dark theme](https://pi-tui.ratstack.sh/frames/warning-gate/warning-40-dark.ce05a3e34c0e.webp) ![Warning Gate, Broad action warning, 40 columns, light theme](https://pi-tui.ratstack.sh/frames/warning-gate/warning-40-light.571340875abc.webp)
- 60 columns: ![Warning Gate, Broad action warning, 60 columns, dark theme](https://pi-tui.ratstack.sh/frames/warning-gate/warning-60-dark.7c4bb8320a89.webp) ![Warning Gate, Broad action warning, 60 columns, light theme](https://pi-tui.ratstack.sh/frames/warning-gate/warning-60-light.3ad77029e4a7.webp)
- 80 columns: ![Warning Gate, Broad action warning, 80 columns, dark theme](https://pi-tui.ratstack.sh/frames/warning-gate/warning-80-dark.c325f189c9f9.webp) ![Warning Gate, Broad action warning, 80 columns, light theme](https://pi-tui.ratstack.sh/frames/warning-gate/warning-80-light.99ce6ce82d18.webp)
- 120 columns: ![Warning Gate, Broad action warning, 120 columns, dark theme](https://pi-tui.ratstack.sh/frames/warning-gate/warning-120-dark.e2c6ee1780a1.webp) ![Warning Gate, Broad action warning, 120 columns, light theme](https://pi-tui.ratstack.sh/frames/warning-gate/warning-120-light.72cde46fc250.webp)

### No action

`cancelled`: Show an unchanged host after declining the warning.

Checks at every width and theme:

- width: ✓ pass
- style-leak: ✓ pass
- hard-coded-colour: ✓ pass
- height: ✓ pass

Frames:

- 40 columns: ![Warning Gate, No action, 40 columns, dark theme](https://pi-tui.ratstack.sh/frames/warning-gate/cancelled-40-dark.cec3401af4b6.webp) ![Warning Gate, No action, 40 columns, light theme](https://pi-tui.ratstack.sh/frames/warning-gate/cancelled-40-light.fcb975cb7829.webp)
- 60 columns: ![Warning Gate, No action, 60 columns, dark theme](https://pi-tui.ratstack.sh/frames/warning-gate/cancelled-60-dark.880d770c22c6.webp) ![Warning Gate, No action, 60 columns, light theme](https://pi-tui.ratstack.sh/frames/warning-gate/cancelled-60-light.2e0ce7025f63.webp)
- 80 columns: ![Warning Gate, No action, 80 columns, dark theme](https://pi-tui.ratstack.sh/frames/warning-gate/cancelled-80-dark.2f1d74bdf4d5.webp) ![Warning Gate, No action, 80 columns, light theme](https://pi-tui.ratstack.sh/frames/warning-gate/cancelled-80-light.07dcbbf61323.webp)
- 120 columns: ![Warning Gate, No action, 120 columns, dark theme](https://pi-tui.ratstack.sh/frames/warning-gate/cancelled-120-dark.f23e1620675a.webp) ![Warning Gate, No action, 120 columns, light theme](https://pi-tui.ratstack.sh/frames/warning-gate/cancelled-120-light.b8ea2767180b.webp)

## Sample code

`stories/patterns/behavioral/warning-gate.ts`, the story the frames above were rendered from.

```ts
// Warning Gate: a broad selection must pass a separate consequence prompt.
import type { PatternStory } from "../../../src/pattern.ts";

export const story: PatternStory = {
  id: "warning-gate", title: "Warning Gate", kind: "screen",
  apis: ["ctx.ui.select", "ctx.ui.confirm", "ctx.ui.setWidget", "ctx.ui.setStatus"],
  states: [
    { id: "select", label: "Choose boundary" },
    { id: "warning", label: "Broad action warning", steps: [
      { type: "keys", data: "\x1b[B" }, { type: "keys", data: "\r" },
    ] },
    { id: "cancelled", label: "No action", steps: [
      { type: "keys", data: "\x1b[B" }, { type: "keys", data: "\r" },
    ] },
  ],
  setup({ ui, theme }) {
    const boundary = ["Restore latest task", "Restore all tasks"];
    const requiresWarning = (choice: string) => choice === boundary[1];
    // A synthetic policy, not a universal restore threshold.
    let applied = 0;
    ui.setEditorText("Draft task list");
    ui.setWidget("restore", [theme.fg("muted", "Checkpoint: 3 tasks · no changes applied")]);
    ui.setStatus("restore", theme.fg("muted", "unchanged"));

    function apply(choice: string) {
      applied++;
      ui.setWidget("restore", [theme.fg("success", choice + " · applied")]);
      ui.setStatus("restore", theme.fg("success", "applied " + applied));
    }
    void ui.select("Restore boundary", boundary).then(choice => {
      if (choice === undefined) return;
      if (!requiresWarning(choice)) { apply(choice); return; }
      void ui.confirm("Restore all tasks?", "Replaces all 3 task edits. Continue?").then(confirmed => {
        if (confirmed) { apply(choice); return; }
        ui.setWidget("restore", [
          theme.fg("success", "Declined · 3 task edits kept"),
          theme.fg("muted", "Applied actions: " + applied),
        ]);
        ui.setStatus("restore", theme.fg("success", "unchanged"));
      });
    });
  },
};
```

## Known uses: seen in Nico's repos

- [**dot314**](https://github.com/nicobailon/dot314): Select restore boundaries with explicit warnings
  - [extensions/tool-horizon/index.ts:146-170](https://github.com/nicobailon/dot314/blob/17cce138f3f687211d0485d204408a9650953c61/extensions/tool-horizon/index.ts#L146-L170) @17cce138
  - [extensions/tool-horizon/index.ts:40-90](https://github.com/nicobailon/dot314/blob/17cce138f3f687211d0485d204408a9650953c61/extensions/tool-horizon/index.ts#L40-L90) @17cce138
  - [extensions/tool-horizon/boundary-picker.ts:460-500](https://github.com/nicobailon/dot314/blob/17cce138f3f687211d0485d204408a9650953c61/extensions/tool-horizon/boundary-picker.ts#L460-L500) @17cce138

## For agents: choose and check

Choose Warning Gate when your job matches its intent and applicability above. Its neighbours in Overlays and dialogs are listed below. Read the one whose intent fits your job more closely before you commit.

- [Shared Shell](https://pi-tui.ratstack.sh/patterns/shared-shell.md): Wrap specialized dialog content in a shared themed frame.
- [Abort Lantern](https://pi-tui.ratstack.sh/patterns/abort-lantern.md): Settle foreground loading before opening a separate result view.
- [Dialog Fuse](https://pi-tui.ratstack.sh/patterns/dialog-fuse.md): Show remaining time before a transient dialog automatically dismisses.
- [Abort Tether](https://pi-tui.ratstack.sh/patterns/abort-tether.md): Tie a built-in dialog's lifetime to an operation's abort signal.
- [Idle Fuse](https://pi-tui.ratstack.sh/patterns/idle-fuse.md): Reset a component-owned inactivity timer after every input.
- [Settings Bench](https://pi-tui.ratstack.sh/patterns/settings-bench.md): Keep configuration interaction separate from the live activity view.
- [Action Sieve](https://pi-tui.ratstack.sh/patterns/action-sieve.md): Derive dialog choices from current control and completion state.
- [Done Contract](https://pi-tui.ratstack.sh/patterns/done-contract.md): Resolve each custom interaction with a typed selection or cancellation.

Check your version:

- Render your version at 40, 60, 80 and 120 columns in the dark and light themes.
- Check width: no rendered line is wider than the terminal.
- Check style-leak: no line ends with colour, bold or a link still switched on.
- Check hard-coded-colour: every colour on screen comes from the active theme.
- Check height: the output fits in the rows the terminal has.
- Read the Pi 1.0.3 docs for [`ctx.ui.select`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#interact-with-the-user), [`ctx.ui.confirm`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#interact-with-the-user), `ctx.ui.setWidget`, `ctx.ui.setStatus` before you use them.
- Every reference frame gets the verdict its state expects.

Next actions: `related({ id: "warning-gate" })` lists what to read next, and `states({ id: "warning-gate", width: 40 })` returns every frame and verdict at one width. The [build-pi-tui-component skill](https://pi-tui.ratstack.sh/skills/build-pi-tui-component.md) walks through the whole loop.

## Related

- [Action Sieve](https://pi-tui.ratstack.sh/patterns/action-sieve.md): filters choices before confirmation

## Linked from

No other pattern links here.
