# 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-. 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}