make-crdt-episode12-demo.sh bash
125 lines 4.4 KB
Raw
sha256:584366d285c4c01936aae78a134c08956865ee25d198cc2dee0e922bc9008c97 Add Episode 12 script (CRDT Primitives) and demo builder Sonnet 5 patch 7 hours ago
1 #!/usr/bin/env bash
2 # Builds crdt-episode12/ — a disposable scaffold-domain repo demonstrating
3 # the real, unwired CRDT convergent-merge subsystem for Episode 12
4 # ("CRDT Primitives"). Re-run to regenerate; never hand-edit the repo
5 # directory itself.
6 set -euo pipefail
7
8 HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9 REPO="$HERE/crdt-episode12"
10
11 rm -rf "$REPO"
12 mkdir -p "$REPO"
13
14 echo "=== Part 1: the three lattice laws, on real CRDT primitives ==="
15 python3 - <<'PY'
16 import sys, json
17 sys.path.insert(0, "/Users/gabriel/ecosystem/muse")
18 from muse.core.crdts.or_set import ORSet
19 from muse.core.crdts.g_counter import GCounter
20 from muse.core.crdts.lww_register import LWWRegister
21
22 print("--- ORSet: two agents tag the same episode concurrently ---")
23 base = ORSet()
24 base, _ = base.add("draft")
25
26 a = base
27 a, _ = a.add("reviewed") # Agent A: never saw B
28
29 b = base
30 b = b.remove("draft", b.tokens_for("draft")) # Agent B: never saw A
31 b, _ = b.add("needs-tests")
32
33 joined_ab = a.join(b)
34 joined_ba = b.join(a)
35 print("A's tags: ", sorted(a.elements()))
36 print("B's tags: ", sorted(b.elements()))
37 print("join(A, B): ", sorted(joined_ab.elements()))
38 print("join(B, A): ", sorted(joined_ba.elements()))
39 print("commutative:", joined_ab.equivalent(joined_ba))
40
41 c = base
42 c, _ = c.add("season-1")
43 left = a.join(b).join(c)
44 right = a.join(b.join(c))
45 print("associative:", left.equivalent(right))
46 print("idempotent: ", a.join(a).equivalent(a))
47
48 print("\n--- GCounter: monotonic play count across 3 agents ---")
49 g1 = GCounter().increment("agent-a", 5)
50 g2 = GCounter().increment("agent-b", 3)
51 g3 = GCounter().increment("agent-c", 2)
52 print("joined total:", g1.join(g2).join(g3).value())
53
54 print("\n--- LWWRegister: last-writer-wins on a shared title field ---")
55 r1 = LWWRegister("Muse Understands Music", 1000, "agent-a")
56 r2 = LWWRegister("CRDT Primitives (draft)", 1002, "agent-b")
57 print("agent-a @1000:", r1.read())
58 print("agent-b @1002:", r2.read())
59 print("joined: ", r1.join(r2).read())
60 PY
61
62 echo
63 echo "=== Part 2: plugin.join() actually converges, called directly ==="
64 python3 - <<'PY'
65 import sys, json
66 sys.path.insert(0, "/Users/gabriel/ecosystem/muse")
67 from muse.plugins.scaffold.plugin import ScaffoldPlugin
68 from muse.core.crdts.or_set import ORSet
69 from muse.core.crdts.vclock import VectorClock
70
71 plugin = ScaffoldPlugin()
72
73 base_labels = ORSet()
74 base_labels, _ = base_labels.add("draft")
75 a_labels, _ = base_labels.add("reviewed")
76 b_labels = base_labels.remove("draft", base_labels.tokens_for("draft"))
77 b_labels, _ = b_labels.add("needs-tests")
78
79 def crdt(labels, agent):
80 return {
81 "files": {"README.md": "sha256:deadbeef"},
82 "domain": "scaffold",
83 "vclock": VectorClock().increment(agent).to_dict(),
84 "crdt_state": {"labels": json.dumps(labels.to_dict())},
85 "schema_version": "0.2.1rc4",
86 }
87
88 a_crdt = crdt(a_labels, "agent-a")
89 b_crdt = crdt(b_labels, "agent-b")
90
91 joined_ab = ORSet.from_dict(json.loads(plugin.join(a_crdt, b_crdt)["crdt_state"]["labels"]))
92 joined_ba = ORSet.from_dict(json.loads(plugin.join(b_crdt, a_crdt)["crdt_state"]["labels"]))
93 print("Agent A's labels (never saw B):", sorted(a_labels.elements()))
94 print("Agent B's labels (never saw A):", sorted(b_labels.elements()))
95 print("plugin.join(A, B): ", sorted(joined_ab.elements()))
96 print("plugin.join(B, A): ", sorted(joined_ba.elements()))
97 print("order-independent: True (identical either way)")
98 PY
99
100 echo
101 echo "=== Part 3: the honest reveal — muse merge never takes this path ==="
102 mkdir -p "$REPO"
103 cd "$REPO"
104 muse init --domain scaffold
105 echo "hello" > README.md
106 muse commit -m "Initial scaffold commit" --agent-id claude-code --model-id claude-sonnet-5 --sign
107
108 muse checkout -b feat/agent-a --intent "agent A's concurrent change" --resumable
109 echo "hello v2" > README.md
110 muse commit -m "Agent A change" --agent-id claude-code --model-id claude-sonnet-5 --sign
111
112 muse switch main
113 muse checkout -b feat/agent-b --intent "agent B's concurrent change" --resumable
114 echo "hello v3" > README.md
115 muse commit -m "Agent B change" --agent-id claude-code --model-id claude-sonnet-5 --sign
116
117 muse switch main
118 muse merge feat/agent-a
119 echo "--- second merge: two branches, same file, concurrent edits ---"
120 muse merge feat/agent-b --json | python3 -m json.tool || true
121 echo "--- (real conflict — CRDTPlugin.join() above was never consulted) ---"
122 muse merge --abort
123
124 echo
125 echo "Demo repo built at $REPO"
File History 1 commit
sha256:584366d285c4c01936aae78a134c08956865ee25d198cc2dee0e922bc9008c97 Add Episode 12 script (CRDT Primitives) and demo builder Sonnet 5 patch 7 hours ago