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
157 lines
7.6 KiB
YAML
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}
|