runbook-tutorials/docs/pack-spec-v0.2.md
tegwick f5619e1a52
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Work Records / validate (push) Successful in 14s
Rename open to stalled and autopilot to auto-confirm; add pushed state; declare idempotency; propose maturity and projects model (RBT-WP-0008)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: sonnet
Assistant-Process: 295952@bnt-lap001
Assistant-Session: e93f64ad-516c-46eb-9666-aad8d300c477
2026-09-29 12:19:58 +02:00

9.8 KiB

Runbook pack specification v0.2

Status: adopted 2026-09-29 (Bernd's review answers are in the Decisions section). Derived from docs/ux-review-2026-09-29.md. v0.1 stays valid; v0.2 is a superset. Machine-checkable form: schema/runbook-pack-v0.2.schema.json plus the semantic checks in rtut/v2.py. The engine and UI do not run v0.2 packs yet (RBT-WP-0007).

Principle

The spec describes what the procedure is: structure, data, actors, gates and order. It carries no presentation. Rendering (layout, theme, dark mode, the questionnaire and the dimension view) is the renderer's job and must follow from the semantics alone. If a UI feature needs a new spec field, that field has to be justified as meaning, not appearance.

The model

pack
 |- framing            what to keep in mind (shown first)
 |- actors             who does or approves what, with privileges
 |- datapoints         the non-secret facts collected and applied  -> state nil/set/err/ok
 |- stages             hierarchy of the procedure
 |   |- steps          the work                                 -> state todo/running/done/failed
 |   |- gates          QA checks tied to the stage and to goals -> state open/passed/failed/waived
 |- artefacts          what a run produces and where it lives (non-secret references)

Two states, two things

Thing States Meaning
Datapoint (parameter, role assignment, artefact location, custody reference) nil no value, set value given, err invalid or rejected, ok confirmed in the real system Is the data known and right?
Step todo, running, done, failed (skipped for read-only) Has it been applied?
Gate open, passed, failed, waived Is the quality condition met?

A datapoint becomes ok when the step or gate named in its confirmed_by passes. A gate must not require a datapoint (datapoints_ok) that it is itself confirmed_by: that is circular and the validator rejects it.

A v0.1 parameter is a datapoint that has a value type and is asked as a question. Steps uses: datapoints; steps may produces: datapoints (for example an artefact location).

Hierarchy and order

  • stages nest to at most three levels. A stage has title, goal, steps, and optional child stages.
  • Every step and stage may declare requires: (ids of steps, stages, gates, or datapoints in state ok). This forms a dependency graph, so alternatives and parallel work are expressible. one_of: groups declare alternatives: any one satisfies the group.
  • Canonical serialization. The order in which the pack lists things is the recommended order. The engine computes: ready = every requirement met; recommended next = the first ready item in canonical order. Operators may take any other ready item. A pack that lists no requires behaves as a linear sequence, which is exactly a v0.1 pack.

Gates

A gate is a QA condition, not a step.

gates:
  - id: custody-approved
    title: Custody strategy approved
    stage: custody            # exit gate of this stage
    goal: platform-root-custody   # quality objective; canon standard id where one exists
    blocking: true            # blocks dependents and the stage exit
    checks:                   # same check shape as step verify
      - {done_when: "signed roster verifies", command: "...", expect: exit-0}
      - {datapoints_ok: [custody_mode, roster_location]}
    waivable: {by: king, needs_reason: true}   # omit if never waivable
  • A gate is tied to exactly one stage (its exit or entry) and names the quality goal it protects, so gates are traceable to standards instead of floating.
  • requires: [gate:custody-approved] makes a step wait for a gate.
  • A waiver records who, when and why, and appears in the overview.

Actors, roles and privileges

actors:
  - id: king
    role: Platform-root custodian
    description: Holds platform-root recovery authority.
    privileges: [approve-custody, revoke-root-token]

Steps and gates name an actor (who acts or approves). owner stays the repository or tool that does the work. The pack thereby explains what is relevant and who is responsible; the overview can group by actor.

Datapoints and dimensions

datapoints:
  - id: custody_mode
    label: Custody mode
    type: enum
    values: [temporary-single-king, two-of-three-ready]
    dimensions: {actor: king, subsystem: openbao, kind: decision}
    ask_in: custody        # stage in which the questionnaire asks for it

dimensions are free key/value tags, using canon vocabulary where it exists (actor, role, privilege, subsystem, kind, assurance goal). They drive the dimension view: a random-access table of all datapoints grouped or filtered by any dimension, editable independently of the flow. Secrets are never datapoints; only references ("stored in the platform-root safe entry") are.

Artefacts

artefacts: lists what a run yields, each with a location datapoint (a reference, never a value) and the produced_by step. The artefacts view is what makes a run more than a script.

Confirmation

Each step declares reversible: true|false (default true).

  • reversible: a confirm button;
  • not reversible: the operator types the pack's confirm_phrase (default I understand this cannot be undone; a step may set its own).

This replaces v0.1's risk for the purpose of confirmation. v0.1 risk values map as: destructive gives reversible: false, all others true.

Framing

threat_checks becomes framing: (list of statements, optionally per stage): things to keep in mind, shown before the work starts. They are not gates. v0.1 threat_checks load as pack-level framing.

Compatibility

  • The engine loads runbook-pack/v0.1 and v0.2. A v0.1 pack is interpreted as one stage, a linear requires chain, no gates, no actors, its parameters as datapoints.
  • engine: legacy-command is unchanged.
  • The run record gains datapoints, gates and waivers sections (runbook-run/v0.2); v0.1 records still load.

What this is not

  • No layout, color, icon or copy-text fields.
  • No embedded scripting, and no execution mode (still RBT-WP-0006).
  • No secret values anywhere.

Operating modes, overrides and deviations

A run has a mode. The mode belongs to the run, not to the pack.

Mode Who confirms Checks, gates, preconditions
manual the operator shown with their state; the operator confirms each
auto-confirm the engine, when every precondition is met evaluated by the engine; confirmation is applied automatically

Manual mode: override

If preconditions are not met the operator may override and continue anyway. Doing so must (1) show a dialog that names the unmet preconditions and the downstream risk (downstream_risk text declared on the step or gate, else a generic warning), (2) require an explicit confirmation, and (3) record a deviation in the run.

Auto-confirm mode: timeout and push-through

  • A step or gate may declare timeout: {seconds: N, on_timeout: stop|push-through}; a run may set a default. Without a timeout, auto-confirm waits.
  • stop (default): on timeout the run stops and reports.
  • push-through: on timeout the engine confirms the item, records a deviation, and moves on, ignoring the problem. This gathers the most information about problems in one run and reduces refinement runs.
  • Irreversible steps are never confirmed automatically unless the run was started with an explicit, recorded pre-authorization naming those steps (and the pack's confirm_phrase). Push-through does not bypass that rule. This is a safety default, open to review.
  • A step may declare auto_confirm: manual-only to forbid automation entirely.
  • Auto-confirm applies confirmation only. It does not run a step's own command; execution is a later, separate level (RBT-WP-0006).

Deviations

An item passed over by push-through gets the distinct state pushed (steps, gates and datapoints): not done, not set, not an error.

Every override, waiver and push-through is a deviation in the run record: kind (override|waiver|push-through), item (step or gate id), mode, unmet (what was not satisfied), risk_acknowledged, reason (required for overrides and waivers; automatic text for push-through), who, at. A run with deviations is marked so in the overview and can never exercise a pack. A waiver is declared in advance (waivable on a gate); an override is not.

Decisions (2026-09-29, Bernd)

  1. Waivers: allowed only where a gate declares waivable, always with a reason. Undeclared departures are overrides (above), also recorded.
  2. Gate checks: a gate may run a command (operator-confirmed in manual mode) or read datapoint states and step results.
  3. Dimension vocabulary: free tags first; a shared registry may be promoted to canon.
  4. Nesting: at most three levels. If procedures grow beyond that, dependencies between runbooks are needed (see below), not deeper nesting.
  5. Datapoint ok: reached by a check, or by a recorded manual confirmation. Handling of missing preconditions is defined by the operating modes above.

Later: dependencies between runbooks

Idempotency is a declared characteristic of a step: idempotent: idempotent | non-idempotent | conditional (conditional needs an idempotent_note). Undeclared means unknown. The runbook's overall value is derived. See docs/maturity-and-projects.md.

Not in v0.2. When a procedure needs another runbook (for example "OpenBao operating path requires the SSH access pack"), packs will declare requires_packs with a required result (exercised, or a named gate passed). Tracked in RBT-WP-0006.

Recommendation (carried out)

Keep runbook-pack/v0.1 as shipped (three NetKingdom packs use it). Use the old console's seven runbooks and 14 gates as the first real v0.2 test.