runbook-tutorials/runbooks/showcase-lighthouse-v2/pack.yaml
tegwick 8d62c1fbe8
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 3s
Work Records / validate (push) Has been cancelled
Active user attribute set, latest activities, guarded changes to used values, artefact links, durations and averages; irreversible showcase step
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 15:50:56 +02:00

157 lines
7.6 KiB
YAML

# The same story as ../showcase-lighthouse, written in the v0.2 model: stages, parallel steps, alternatives, gates, actors,
# datapoints with dimensions, artefacts, irreversible confirmation, timeouts. It is the reference pack for the v0.2 walk-through UI.
spec: runbook-pack/v0.2
id: rtut.showcase-lighthouse-v2
title: "Showcase: a night at the lighthouse (v0.2)"
owner: runbook-tutorials
outcome: You have played a short interactive story that touches every feature of the runbook engine, using only harmless echo, printf and a scratch file under /tmp/rtut-.
exercise_status: unexercised
engine: native
confirm_phrase: I understand this cannot be undone
framing: # shown first; things to keep in mind, not gates
- This showcase never handles a secret. Datapoints hold references and facts, never secret values.
- Only /tmp/rtut-* is ever written or removed.
- Several things below can be done in any order; the guide recommends one.
actors:
- id: keeper
role: Lighthouse keeper
description: Runs the lamp and the signals. Does the everyday work.
privileges: [light-lamp, sound-signal, write-logbook]
- id: harbourmaster
role: Harbour master
description: Approves the irreversible closing of the night's log.
privileges: [close-log, waive-lamp-check]
datapoints:
- {id: keeper_name, label: Keeper's name, type: string, pattern: "[A-Za-z]+", default: Ada, dimensions: {actor: keeper, kind: identity}, ask_in: dusk}
- {id: lamp_fuel, label: Lamp fuel, type: enum, values: [whale-oil, paraffin, electric], default: paraffin, dimensions: {actor: keeper, kind: equipment}, ask_in: dusk}
- {id: weather, label: Tonight's weather, type: enum, values: [clear, fog, storm], default: fog, dimensions: {kind: condition}, ask_in: dusk}
- {id: motto, label: Motto, type: text, default: Steady light for those at sea, dimensions: {actor: keeper, kind: identity}, ask_in: dusk}
- {id: logdir, label: Scratch folder, type: path, pattern: "/tmp/rtut-[a-z0-9-]+", default: /tmp/rtut-lighthouse, dimensions: {kind: location, subsystem: logbook}, ask_in: dusk}
- {id: lamp_lit, label: Lamp is lit, type: bool, dimensions: {actor: keeper, kind: state}, produced_by: light-lamp, confirmed_by: light-lamp}
stages:
- id: dusk
title: Dusk - prepare
goal: The lamp is lit and the weather is known before dark.
steps: # no requires among these: they are parallel; list order is the recommended order
- id: read-the-sign
idempotent: idempotent
title: Read the poem over the door
actor: keeper
owner: the-lighthouse
command: printf '%s\n' 'Tower of stone, and a patient flame,' 'you keep no name, yet call each name' 'across the dark, across the foam:' 'come home, come home, come home.'
reversible: true
verify: {done_when: You read the poem, expect: manual}
- id: light-lamp
idempotent: idempotent
title: Light the lamp
actor: keeper
owner: the-lighthouse
uses: [keeper_name, lamp_fuel]
produces: [lamp_lit]
command: echo "{{keeper_name}} lights the {{lamp_fuel}} lamp."
reversible: true
downstream_risk: Without a lit lamp the night watch has no purpose and ships are not warned.
verify: {done_when: The lamp is lit, expect: manual}
- id: read-the-sky
idempotent: idempotent
title: Read the sky
actor: keeper
owner: the-lighthouse
uses: [weather]
command: echo "Weather tonight - {{weather}}."
reversible: true
verify: {done_when: You know the weather, command: 'echo "Weather tonight - {{weather}}."', expect: output-contains, contains: "{{weather}}"}
gates:
- id: lamp-check
title: The lamp burns steadily
goal: safe-navigation # quality objective; a canon standard id where one exists
blocking: true
timeout: {seconds: 120, on_timeout: stop}
downstream_risk: Ships may steer by a light that is not burning.
checks:
- {done_when: The light is visible from the water, expect: manual}
- {datapoints_ok: [lamp_lit]}
waivable: {by: harbourmaster, needs_reason: true}
- id: night
title: Night watch - give warning
goal: Ships are warned in a way that suits the weather.
requires: [gate:lamp-check]
steps:
- id: warn
idempotent: idempotent
title: Warn the ships
actor: keeper
owner: the-lighthouse
uses: [keeper_name, weather]
one_of: # alternatives: any one satisfies "warn"; the guide recommends by weather
- id: sound-horn
title: Sound the fog horn
recommended_when: {weather: [fog]}
command: echo "{{keeper_name}} sounds the horn through the {{weather}} night."
reversible: true
verify: {done_when: The horn has sounded, expect: manual}
- id: wave-flags
title: Signal with flags
recommended_when: {weather: [clear]}
command: echo "{{keeper_name}} signals with flags in the {{weather}} night."
reversible: true
verify: {done_when: The flags were seen, expect: manual}
- id: shelter
title: Bar the door and wait it out
recommended_when: {weather: [storm]}
command: echo "{{keeper_name}} bars the door. Nobody is warned tonight."
reversible: true
verify: {done_when: The door is barred, expect: manual}
- id: write-logbook
idempotent: non-idempotent
idempotent_note: Appends a line every time it runs; a second run leaves a duplicate entry.
title: Write tonight's entry
actor: keeper
owner: the-lighthouse
requires: [warn]
uses: [keeper_name, weather, lamp_fuel, motto, logdir]
produces: [logbook-file]
command: mkdir -p {{logdir}} && echo "Night watch by {{keeper_name}} at $(date -u +%H:%M:%S) UTC - {{weather}}, {{lamp_fuel}} lamp. {{motto}}." >> {{logdir}}/logbook.txt
reversible: true
rollback: rm -rf {{logdir}}
verify: {done_when: The logbook exists, command: 'test -s {{logdir}}/logbook.txt', expect: exit-0}
- id: dawn
title: Dawn - close the night
goal: The night is on record and the scratch space is clean.
requires: [night]
steps:
- id: close-log
idempotent: conditional
idempotent_note: Safe to repeat only while the log file exists; a second run fails on the read.
title: Close the log for good
description: The entry carries the exact time it was written, to the second. Once the scratch folder is removed it cannot be written again the same way, so this step cannot be undone.
auto_confirm: manual-only # never confirmed by the engine on its own
actor: harbourmaster
owner: the-lighthouse
uses: [logdir]
command: cat {{logdir}}/logbook.txt && rm -rf {{logdir}}
reversible: false # engine demands the typed confirm_phrase; no renderer can skip it
verify: {done_when: The scratch folder is gone, command: 'test ! -e {{logdir}}', expect: exit-0}
gates:
- id: night-on-record
title: Nothing left behind
goal: clean-handover
blocking: true
checks:
- {done_when: No files remain under the scratch folder, command: 'test ! -e {{logdir}}', expect: exit-0}
artefacts:
- id: logbook-file
title: The night's logbook entry
location: {datapoint: logdir, path: logbook.txt} # a reference, never a value
produced_by: write-logbook
lives_until: close-log
ownership:
- {concern: The story, owner: runbook-tutorials}