Adopt spec v0.2: schema, semantic validator, operating modes; workplans updated
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
This commit is contained in:
parent
b6868a3a58
commit
79996ab249
15 changed files with 1090 additions and 64 deletions
207
docs/pack-spec-v0.2.md
Normal file
207
docs/pack-spec-v0.2.md
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
# 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
|
||||
|
||||
```text
|
||||
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 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.
|
||||
|
||||
```yaml
|
||||
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
|
||||
|
||||
```yaml
|
||||
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
|
||||
|
||||
```yaml
|
||||
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 |
|
||||
| **autopilot** | 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.
|
||||
|
||||
### Autopilot 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, autopilot 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 `autopilot: manual-only` to forbid automation entirely.
|
||||
|
||||
### Deviations
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue