From 7069f762e58f2ca66f8f1524b11af81356c0fc98 Mon Sep 17 00:00:00 2001 From: gastown/crew/max Date: Wed, 31 Dec 2025 01:56:13 -0800 Subject: [PATCH] Add Hanoi demo documentation and scripts (gt-brd1b.4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add docs/hanoi-demo.md with full execution instructions - Add scripts/gen_hanoi.py for generating larger formulas - Include pre-generated 7-disk formula (127 moves) - 9 and 10 disk formulas already committed Speed test results: 127 issues close in 14 sec (~109ms each) Expected 1K run time: ~2 minutes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../formulas/towers-of-hanoi-7.formula.toml | 812 ++++++++++++++++++ docs/hanoi-demo.md | 169 ++++ scripts/gen_hanoi.py | 103 +++ 3 files changed, 1084 insertions(+) create mode 100644 .beads/formulas/towers-of-hanoi-7.formula.toml create mode 100644 docs/hanoi-demo.md create mode 100644 scripts/gen_hanoi.py diff --git a/.beads/formulas/towers-of-hanoi-7.formula.toml b/.beads/formulas/towers-of-hanoi-7.formula.toml new file mode 100644 index 00000000..4ae41674 --- /dev/null +++ b/.beads/formulas/towers-of-hanoi-7.formula.toml @@ -0,0 +1,812 @@ +description = """ +AGENT EXECUTION PROTOCOL - Towers of Hanoi (7 disks, 127 moves) + +PURPOSE: This is a durability proof, not computation. Steps are pre-computed. +Your job is to execute them mechanically, proving crash-recovery at scale. + +EXECUTION LOOP: +1. Find current state: bd mol current +2. Find the next ready (unblocked) step +3. Close it: bd close +4. Repeat until no ready steps remain + +ON RESUME (after crash/restart/handoff): +- Same as fresh start. The molecule IS the state. +- Query `bd mol current `, continue from there. +- No memory of previous session needed. + +DO: +- Close steps as fast as possible (they're trivial mechanical moves) +- Use `gt handoff` when context fills (proactive cycling) +- Trust the pre-computed solution - every move is already correct + +DO NOT: +- Try to solve Hanoi yourself - moves are already computed +- Mark steps in_progress - just close them directly +- Ask for permission - this is GUPP territory, just execute +- Stop for human input - run autonomously until complete + +MONITORING: +- Progress: Count closed children of the molecule +- For mega-molecules: Use convoy dashboard when available +- Completion: All steps closed = molecule complete + +This proves Gas Town can execute arbitrarily long workflows with +nondeterministic idempotence - different sessions, same outcome. +""" +formula = "towers-of-hanoi-7" +version = 1 + +[[steps]] +id = "setup" +title = "Verify initial state" +description = "All 7 disks stacked on peg A. Largest on bottom." + + +[[steps]] +id = "move-1" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 1/127)" +needs = ["setup"] + +[[steps]] +id = "move-2" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 2/127)" +needs = ["move-1"] + +[[steps]] +id = "move-3" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 3/127)" +needs = ["move-2"] + +[[steps]] +id = "move-4" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 4/127)" +needs = ["move-3"] + +[[steps]] +id = "move-5" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 5/127)" +needs = ["move-4"] + +[[steps]] +id = "move-6" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 6/127)" +needs = ["move-5"] + +[[steps]] +id = "move-7" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 7/127)" +needs = ["move-6"] + +[[steps]] +id = "move-8" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 8/127)" +needs = ["move-7"] + +[[steps]] +id = "move-9" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 9/127)" +needs = ["move-8"] + +[[steps]] +id = "move-10" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 10/127)" +needs = ["move-9"] + +[[steps]] +id = "move-11" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 11/127)" +needs = ["move-10"] + +[[steps]] +id = "move-12" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 12/127)" +needs = ["move-11"] + +[[steps]] +id = "move-13" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 13/127)" +needs = ["move-12"] + +[[steps]] +id = "move-14" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 14/127)" +needs = ["move-13"] + +[[steps]] +id = "move-15" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 15/127)" +needs = ["move-14"] + +[[steps]] +id = "move-16" +title = "Move disk 5: A → C" +description = "Move disk 5 from peg A to peg C. (Move 16/127)" +needs = ["move-15"] + +[[steps]] +id = "move-17" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 17/127)" +needs = ["move-16"] + +[[steps]] +id = "move-18" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 18/127)" +needs = ["move-17"] + +[[steps]] +id = "move-19" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 19/127)" +needs = ["move-18"] + +[[steps]] +id = "move-20" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 20/127)" +needs = ["move-19"] + +[[steps]] +id = "move-21" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 21/127)" +needs = ["move-20"] + +[[steps]] +id = "move-22" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 22/127)" +needs = ["move-21"] + +[[steps]] +id = "move-23" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 23/127)" +needs = ["move-22"] + +[[steps]] +id = "move-24" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 24/127)" +needs = ["move-23"] + +[[steps]] +id = "move-25" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 25/127)" +needs = ["move-24"] + +[[steps]] +id = "move-26" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 26/127)" +needs = ["move-25"] + +[[steps]] +id = "move-27" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 27/127)" +needs = ["move-26"] + +[[steps]] +id = "move-28" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 28/127)" +needs = ["move-27"] + +[[steps]] +id = "move-29" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 29/127)" +needs = ["move-28"] + +[[steps]] +id = "move-30" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 30/127)" +needs = ["move-29"] + +[[steps]] +id = "move-31" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 31/127)" +needs = ["move-30"] + +[[steps]] +id = "move-32" +title = "Move disk 6: A → B" +description = "Move disk 6 from peg A to peg B. (Move 32/127)" +needs = ["move-31"] + +[[steps]] +id = "move-33" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 33/127)" +needs = ["move-32"] + +[[steps]] +id = "move-34" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 34/127)" +needs = ["move-33"] + +[[steps]] +id = "move-35" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 35/127)" +needs = ["move-34"] + +[[steps]] +id = "move-36" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 36/127)" +needs = ["move-35"] + +[[steps]] +id = "move-37" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 37/127)" +needs = ["move-36"] + +[[steps]] +id = "move-38" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 38/127)" +needs = ["move-37"] + +[[steps]] +id = "move-39" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 39/127)" +needs = ["move-38"] + +[[steps]] +id = "move-40" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 40/127)" +needs = ["move-39"] + +[[steps]] +id = "move-41" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 41/127)" +needs = ["move-40"] + +[[steps]] +id = "move-42" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 42/127)" +needs = ["move-41"] + +[[steps]] +id = "move-43" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 43/127)" +needs = ["move-42"] + +[[steps]] +id = "move-44" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 44/127)" +needs = ["move-43"] + +[[steps]] +id = "move-45" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 45/127)" +needs = ["move-44"] + +[[steps]] +id = "move-46" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 46/127)" +needs = ["move-45"] + +[[steps]] +id = "move-47" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 47/127)" +needs = ["move-46"] + +[[steps]] +id = "move-48" +title = "Move disk 5: C → B" +description = "Move disk 5 from peg C to peg B. (Move 48/127)" +needs = ["move-47"] + +[[steps]] +id = "move-49" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 49/127)" +needs = ["move-48"] + +[[steps]] +id = "move-50" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 50/127)" +needs = ["move-49"] + +[[steps]] +id = "move-51" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 51/127)" +needs = ["move-50"] + +[[steps]] +id = "move-52" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 52/127)" +needs = ["move-51"] + +[[steps]] +id = "move-53" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 53/127)" +needs = ["move-52"] + +[[steps]] +id = "move-54" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 54/127)" +needs = ["move-53"] + +[[steps]] +id = "move-55" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 55/127)" +needs = ["move-54"] + +[[steps]] +id = "move-56" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 56/127)" +needs = ["move-55"] + +[[steps]] +id = "move-57" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 57/127)" +needs = ["move-56"] + +[[steps]] +id = "move-58" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 58/127)" +needs = ["move-57"] + +[[steps]] +id = "move-59" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 59/127)" +needs = ["move-58"] + +[[steps]] +id = "move-60" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 60/127)" +needs = ["move-59"] + +[[steps]] +id = "move-61" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 61/127)" +needs = ["move-60"] + +[[steps]] +id = "move-62" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 62/127)" +needs = ["move-61"] + +[[steps]] +id = "move-63" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 63/127)" +needs = ["move-62"] + +[[steps]] +id = "move-64" +title = "Move disk 7: A → C" +description = "Move disk 7 from peg A to peg C. (Move 64/127)" +needs = ["move-63"] + +[[steps]] +id = "move-65" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 65/127)" +needs = ["move-64"] + +[[steps]] +id = "move-66" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 66/127)" +needs = ["move-65"] + +[[steps]] +id = "move-67" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 67/127)" +needs = ["move-66"] + +[[steps]] +id = "move-68" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 68/127)" +needs = ["move-67"] + +[[steps]] +id = "move-69" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 69/127)" +needs = ["move-68"] + +[[steps]] +id = "move-70" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 70/127)" +needs = ["move-69"] + +[[steps]] +id = "move-71" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 71/127)" +needs = ["move-70"] + +[[steps]] +id = "move-72" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 72/127)" +needs = ["move-71"] + +[[steps]] +id = "move-73" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 73/127)" +needs = ["move-72"] + +[[steps]] +id = "move-74" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 74/127)" +needs = ["move-73"] + +[[steps]] +id = "move-75" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 75/127)" +needs = ["move-74"] + +[[steps]] +id = "move-76" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 76/127)" +needs = ["move-75"] + +[[steps]] +id = "move-77" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 77/127)" +needs = ["move-76"] + +[[steps]] +id = "move-78" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 78/127)" +needs = ["move-77"] + +[[steps]] +id = "move-79" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 79/127)" +needs = ["move-78"] + +[[steps]] +id = "move-80" +title = "Move disk 5: B → A" +description = "Move disk 5 from peg B to peg A. (Move 80/127)" +needs = ["move-79"] + +[[steps]] +id = "move-81" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 81/127)" +needs = ["move-80"] + +[[steps]] +id = "move-82" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 82/127)" +needs = ["move-81"] + +[[steps]] +id = "move-83" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 83/127)" +needs = ["move-82"] + +[[steps]] +id = "move-84" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 84/127)" +needs = ["move-83"] + +[[steps]] +id = "move-85" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 85/127)" +needs = ["move-84"] + +[[steps]] +id = "move-86" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 86/127)" +needs = ["move-85"] + +[[steps]] +id = "move-87" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 87/127)" +needs = ["move-86"] + +[[steps]] +id = "move-88" +title = "Move disk 4: C → A" +description = "Move disk 4 from peg C to peg A. (Move 88/127)" +needs = ["move-87"] + +[[steps]] +id = "move-89" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 89/127)" +needs = ["move-88"] + +[[steps]] +id = "move-90" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 90/127)" +needs = ["move-89"] + +[[steps]] +id = "move-91" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 91/127)" +needs = ["move-90"] + +[[steps]] +id = "move-92" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 92/127)" +needs = ["move-91"] + +[[steps]] +id = "move-93" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 93/127)" +needs = ["move-92"] + +[[steps]] +id = "move-94" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 94/127)" +needs = ["move-93"] + +[[steps]] +id = "move-95" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 95/127)" +needs = ["move-94"] + +[[steps]] +id = "move-96" +title = "Move disk 6: B → C" +description = "Move disk 6 from peg B to peg C. (Move 96/127)" +needs = ["move-95"] + +[[steps]] +id = "move-97" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 97/127)" +needs = ["move-96"] + +[[steps]] +id = "move-98" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 98/127)" +needs = ["move-97"] + +[[steps]] +id = "move-99" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 99/127)" +needs = ["move-98"] + +[[steps]] +id = "move-100" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 100/127)" +needs = ["move-99"] + +[[steps]] +id = "move-101" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 101/127)" +needs = ["move-100"] + +[[steps]] +id = "move-102" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 102/127)" +needs = ["move-101"] + +[[steps]] +id = "move-103" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 103/127)" +needs = ["move-102"] + +[[steps]] +id = "move-104" +title = "Move disk 4: A → B" +description = "Move disk 4 from peg A to peg B. (Move 104/127)" +needs = ["move-103"] + +[[steps]] +id = "move-105" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 105/127)" +needs = ["move-104"] + +[[steps]] +id = "move-106" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 106/127)" +needs = ["move-105"] + +[[steps]] +id = "move-107" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 107/127)" +needs = ["move-106"] + +[[steps]] +id = "move-108" +title = "Move disk 3: C → B" +description = "Move disk 3 from peg C to peg B. (Move 108/127)" +needs = ["move-107"] + +[[steps]] +id = "move-109" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 109/127)" +needs = ["move-108"] + +[[steps]] +id = "move-110" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 110/127)" +needs = ["move-109"] + +[[steps]] +id = "move-111" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 111/127)" +needs = ["move-110"] + +[[steps]] +id = "move-112" +title = "Move disk 5: A → C" +description = "Move disk 5 from peg A to peg C. (Move 112/127)" +needs = ["move-111"] + +[[steps]] +id = "move-113" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 113/127)" +needs = ["move-112"] + +[[steps]] +id = "move-114" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 114/127)" +needs = ["move-113"] + +[[steps]] +id = "move-115" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 115/127)" +needs = ["move-114"] + +[[steps]] +id = "move-116" +title = "Move disk 3: B → A" +description = "Move disk 3 from peg B to peg A. (Move 116/127)" +needs = ["move-115"] + +[[steps]] +id = "move-117" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 117/127)" +needs = ["move-116"] + +[[steps]] +id = "move-118" +title = "Move disk 2: C → A" +description = "Move disk 2 from peg C to peg A. (Move 118/127)" +needs = ["move-117"] + +[[steps]] +id = "move-119" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 119/127)" +needs = ["move-118"] + +[[steps]] +id = "move-120" +title = "Move disk 4: B → C" +description = "Move disk 4 from peg B to peg C. (Move 120/127)" +needs = ["move-119"] + +[[steps]] +id = "move-121" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 121/127)" +needs = ["move-120"] + +[[steps]] +id = "move-122" +title = "Move disk 2: A → B" +description = "Move disk 2 from peg A to peg B. (Move 122/127)" +needs = ["move-121"] + +[[steps]] +id = "move-123" +title = "Move disk 1: C → B" +description = "Move disk 1 from peg C to peg B. (Move 123/127)" +needs = ["move-122"] + +[[steps]] +id = "move-124" +title = "Move disk 3: A → C" +description = "Move disk 3 from peg A to peg C. (Move 124/127)" +needs = ["move-123"] + +[[steps]] +id = "move-125" +title = "Move disk 1: B → A" +description = "Move disk 1 from peg B to peg A. (Move 125/127)" +needs = ["move-124"] + +[[steps]] +id = "move-126" +title = "Move disk 2: B → C" +description = "Move disk 2 from peg B to peg C. (Move 126/127)" +needs = ["move-125"] + +[[steps]] +id = "move-127" +title = "Move disk 1: A → C" +description = "Move disk 1 from peg A to peg C. (Move 127/127)" +needs = ["move-126"] + +[[steps]] +id = "verify" +title = "Verify final state" +description = "All 7 disks now on peg C. Tower intact, all moves were legal." +needs = ["move-127"] diff --git a/docs/hanoi-demo.md b/docs/hanoi-demo.md new file mode 100644 index 00000000..886717fc --- /dev/null +++ b/docs/hanoi-demo.md @@ -0,0 +1,169 @@ +# Towers of Hanoi Demo + +A durability proof demonstrating Gas Town's ability to execute arbitrarily long +sequential workflows with crash recovery and session cycling. + +## What This Proves + +1. **Large Molecule Creation**: Creating 1000+ issues in a single workflow +2. **Sequential Execution**: Dependencies chain properly across many steps +3. **Crash Recovery**: Work resumes correctly after session restart +4. **Nondeterministic Idempotence**: Different sessions, same outcome + +## The Math + +Towers of Hanoi requires `2^n - 1` moves for `n` disks: + +| Disks | Moves | Formula Size | Est. Runtime | +|-------|---------|--------------|--------------| +| 7 | 127 | ~19 KB | ~14 sec | +| 9 | 511 | ~74 KB | ~1 min | +| 10 | 1,023 | ~149 KB | ~2 min | +| 15 | 32,767 | ~4.7 MB | ~1 hour | +| 20 | 1M+ | ~163 MB | ~30 hours | + +## Pre-Generated Formulas + +Located in `.beads/formulas/`: + +- `towers-of-hanoi-7.formula.toml` - 127 moves (quick test) +- `towers-of-hanoi-9.formula.toml` - 511 moves (medium test) +- `towers-of-hanoi-10.formula.toml` - 1023 moves (standard demo) + +## Running the Demo + +### Quick Test (7 disks, ~14 seconds) + +```bash +# Create wisp +bd mol wisp towers-of-hanoi-7 --json | jq -r '.new_epic_id' +# Returns: gt-eph-xxx + +# Get all child IDs +bd list --parent=gt-eph-xxx --limit=200 --json | jq -r '.[].id' > /tmp/ids.txt + +# Close all issues (serial) +while read id; do bd --no-daemon close "$id" >/dev/null; done < /tmp/ids.txt + +# Burn the wisp (cleanup) +bd mol burn gt-eph-xxx --force +``` + +### Standard Demo (10 disks, ~2 minutes) + +```bash +# Create wisp +WISP=$(bd mol wisp towers-of-hanoi-10 --json | jq -r '.new_epic_id') +echo "Created wisp: $WISP" + +# Get all 1025 child IDs (1023 moves + setup + verify) +bd list --parent=$WISP --limit=2000 --json | jq -r '.[].id' > /tmp/ids.txt +wc -l /tmp/ids.txt # Should show 1025 + +# Time the execution +START=$(date +%s) +while read id; do bd --no-daemon close "$id" >/dev/null 2>&1; done < /tmp/ids.txt +END=$(date +%s) +echo "Completed in $((END - START)) seconds" + +# Verify completion +bd list --parent=$WISP --status=open # Should be empty + +# Cleanup +bd mol burn $WISP --force +``` + +## Why Wisps? + +The demo uses wisps (ephemeral molecules) because: + +1. **No Git Pollution**: Wisps don't sync to JSONL, keeping git history clean +2. **Auto-Cleanup**: Wisps can be burned without leaving tombstones +3. **Speed**: No export overhead during rapid closes +4. **Appropriate Semantics**: This is operational testing, not auditable work + +## Key Insights + +### `bd ready` Excludes Wisps + +By design, `bd ready` filters out ephemeral issues: +```go +"(i.ephemeral = 0 OR i.ephemeral IS NULL)", // Exclude wisps +``` + +For wisp execution, query children directly: +```bash +bd list --parent=$WISP --status=open +``` + +### Dependencies Work Correctly + +Each move depends on the previous one via `needs`: +```toml +[[steps]] +id = "move-42" +needs = ["move-41"] +``` + +This creates proper `blocks` dependencies. Parent-child relationships +provide hierarchy only - they don't block execution. + +### Close Speed + +With `bd --no-daemon close`: +- ~109ms per close (serial) +- ~9 closes/second + +Parallelization would improve throughput but requires careful +dependency ordering. + +## Generating Larger Formulas + +Use the generator script: + +```bash +# Generate 15-disk formula (32K moves) +python3 scripts/gen_hanoi.py 15 > .beads/formulas/towers-of-hanoi-15.formula.toml +``` + +**Warning**: 20-disk formula is ~163MB and creates 1M+ issues. Only for +stress testing post-launch. + +## Monitoring Progress + +For long-running executions: + +```bash +# Count closed issues +bd list --parent=$WISP --status=closed --json | jq 'length' + +# Count remaining +bd list --parent=$WISP --status=open --json | jq 'length' + +# Progress percentage +TOTAL=1025 +CLOSED=$(bd list --parent=$WISP --status=closed --limit=2000 --json | jq 'length') +echo "$CLOSED / $TOTAL = $((CLOSED * 100 / TOTAL))%" +``` + +## Session Cycling + +The beauty of this demo: you can stop at any time and resume later. + +```bash +# Session 1: Start the wisp, close some issues +WISP=$(bd mol wisp towers-of-hanoi-10 --json | jq -r '.new_epic_id') +# ... close some issues ... +# Context fills, need to cycle + +gt handoff -s "Hanoi demo" -m "Wisp: $WISP, progress: 400/1025" +``` + +```bash +# Session 2: Resume where you left off +# (Read handoff mail for wisp ID) +bd list --parent=$WISP --status=open --limit=2000 --json | jq -r '.[].id' > /tmp/ids.txt +# ... continue closing ... +``` + +The molecule IS the state. No memory of previous session needed. diff --git a/scripts/gen_hanoi.py b/scripts/gen_hanoi.py new file mode 100644 index 00000000..50a484c6 --- /dev/null +++ b/scripts/gen_hanoi.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +""" +Generate Towers of Hanoi formula with pre-computed moves. + +Usage: + python3 gen_hanoi.py [n_disks] > formula.toml + +Examples: + python3 gen_hanoi.py 7 # 127 moves (~19KB) + python3 gen_hanoi.py 10 # 1023 moves (~149KB) + python3 gen_hanoi.py 15 # 32767 moves (~4.7MB) + python3 gen_hanoi.py 20 # 1048575 moves (~163MB) + +The generated formula creates a sequential workflow where each move +depends on the previous one. This tests Gas Town's ability to: +- Create large molecule hierarchies +- Execute sequential workflows across session boundaries +- Maintain state through crash recovery (idempotence) +""" + +import sys + +def hanoi_moves(n, source='A', target='C', auxiliary='B'): + """Generate all moves for n-disk Hanoi using iterative algorithm.""" + moves = [] + def solve(n, src, tgt, aux): + if n == 1: + moves.append((1, src, tgt)) + else: + solve(n - 1, src, aux, tgt) + moves.append((n, src, tgt)) + solve(n - 1, aux, tgt, src) + solve(n, source, target, auxiliary) + return moves + +def generate_formula(n_disks): + moves = hanoi_moves(n_disks) + total = len(moves) + + print(f'''description = """ +AGENT EXECUTION PROTOCOL - Towers of Hanoi ({n_disks} disks, {total} moves) + +PURPOSE: This is a durability proof, not computation. Steps are pre-computed. +Your job is to execute them mechanically, proving crash-recovery at scale. + +EXECUTION LOOP: +1. Find current state: bd mol current +2. Find the next ready (unblocked) step +3. Close it: bd close +4. Repeat until no ready steps remain + +ON RESUME (after crash/restart/handoff): +- Same as fresh start. The molecule IS the state. +- Query `bd mol current `, continue from there. +- No memory of previous session needed. + +DO: +- Close steps as fast as possible (they're trivial mechanical moves) +- Use `gt handoff` when context fills (proactive cycling) +- Trust the pre-computed solution - every move is already correct + +DO NOT: +- Try to solve Hanoi yourself - moves are already computed +- Mark steps in_progress - just close them directly +- Ask for permission - this is GUPP territory, just execute +- Stop for human input - run autonomously until complete + +MONITORING: +- Progress: Count closed children of the molecule +- For mega-molecules: Use convoy dashboard when available +- Completion: All steps closed = molecule complete + +This proves Gas Town can execute arbitrarily long workflows with +nondeterministic idempotence - different sessions, same outcome. +""" +formula = "towers-of-hanoi-{n_disks}" +version = 1 + +[[steps]] +id = "setup" +title = "Verify initial state" +description = "All {n_disks} disks stacked on peg A. Largest on bottom." +''') + + for i, (disk, src, tgt) in enumerate(moves, 1): + prev = "setup" if i == 1 else f"move-{i-1}" + print(f''' +[[steps]] +id = "move-{i}" +title = "Move disk {disk}: {src} → {tgt}" +description = "Move disk {disk} from peg {src} to peg {tgt}. (Move {i}/{total})" +needs = ["{prev}"]''') + + print(f''' +[[steps]] +id = "verify" +title = "Verify final state" +description = "All {n_disks} disks now on peg C. Tower intact, all moves were legal." +needs = ["move-{total}"]''') + +if __name__ == "__main__": + n = int(sys.argv[1]) if len(sys.argv) > 1 else 10 + generate_formula(n)