On this page
Rewiring a running world๏
๐ต Expert ยท Lesson 16
CHANGING THE WIRING WHILE THE WORLD RUNS. A dynamic world can gain a relationship after it is built: two conduits link, one pulls a spell it does not own into its contract, and the next meld resolves through the new edge. Three verbs, no ceremony.
owner.link(borrower) borrower.add_spell_to_contract(spell_id=..., conduit=owner, ...) borrower.meld(...)
EACH VERB IS COMPLETE IN ITSELF. There is no window to open, no session to hold, nothing to commit afterwards. A structural verb does its own bookkeeping and either finishes or refuses - so the only thing a caller has to get right is the ORDER, and the order is just dependency order.
SHARING IS A PULL, AND THE DIRECTION IS THE COMMON MISTAKE borrower.add_spell_to_contract(spell_id=S, conduit=owner) reads "borrower pulls S from owner", and the conduit NAMED in the call must OWN S. An owner trying to PUSH its spell into someone else's contract is refused with "not owned by this conduit". The receiver asks; the provider does not give.
THE ORDER OF OPERATIONS, PER DEPENDENCY EDGE 1. conjure the PROVIDER conduit 2. conjure the CONSUMER conduit 3. link() - only after BOTH exist 4. the consumer pulls the provider's spell into the contract 5. meld - this completes the late binding for that world Chains assemble edge by edge. Skip step 5 on a middle world and its consumer constructs with its Python default instead of the melded object - that is a usage error with a visible symptom, not a runtime gap.
WHY YOU DO NOT HAVE TO THINK ABOUT CONCURRENCY HERE Melder serializes structural change internally, at a grain fine enough that independent work overlaps: two agents adding to the same spellbook do not wait on each other, while an operation that changes what that spellbook IS excludes them both. None of that vocabulary belongs in your code. If it ever shows up in a traceback you will get the blocking holder named, not a hang.
AND A WORLD CAN BE TOLD IT DOES NOT DO THIS link() asks the frame posture FIRST, and the posture gate answers for both of the obvious cases: a dynamic world with disable_linking=True -> refused an ordinary static world -> refused BOTH GET THE SAME SENTENCE - "Linking is disabled for the current frame posture." - and that surprised the author of this lesson, who expected the static world to complain about dynamic mode. It does not, because an unconfigured non-dynamic frame is already "not allowed to link" as far as the posture gate is concerned; the separate dynamic-mode message sits behind that gate and only surfaces when the posture passes and the CONDUIT was nevertheless conjured non-dynamic. The lesson: the message names the GATE that refused, not the property you were thinking about. Two different worlds, one gate, one sentence.
Before you run๏
Use the Expert guide for prerequisite concepts. Run from a checkout with Melder installed and Python 3.14 free-threading selected. The collection download includes the level's local helper modules.
Run the saved script๏
python UX_and_AIX_experiences/04_expert/16_rewiring_a_running_world.py
py -3.14t UX_and_AIX_experiences/04_expert/16_rewiring_a_running_world.py
Public surface๏
md.Spellbook.bind / conjure / configure_aether_frame, Conduit.link / add_spell_to_contract / meld
Code๏
1"""
2TIER: expert (16)
3GOAL: CHANGING THE WIRING WHILE THE WORLD RUNS. A dynamic world can gain
4 a relationship after it is built: two conduits link, one pulls a
5 spell it does not own into its contract, and the next meld resolves
6 through the new edge. Three verbs, no ceremony.
7
8 owner.link(borrower)
9 borrower.add_spell_to_contract(spell_id=..., conduit=owner, ...)
10 borrower.meld(...)
11
12 EACH VERB IS COMPLETE IN ITSELF. There is no window to open, no
13 session to hold, nothing to commit afterwards. A structural verb
14 does its own bookkeeping and either finishes or refuses - so the
15 only thing a caller has to get right is the ORDER, and the order
16 is just dependency order.
17
18 SHARING IS A PULL, AND THE DIRECTION IS THE COMMON MISTAKE
19 borrower.add_spell_to_contract(spell_id=S, conduit=owner)
20 reads "borrower pulls S from owner", and the conduit NAMED in the
21 call must OWN S. An owner trying to PUSH its spell into someone
22 else's contract is refused with "not owned by this conduit". The
23 receiver asks; the provider does not give.
24
25 THE ORDER OF OPERATIONS, PER DEPENDENCY EDGE
26 1. conjure the PROVIDER conduit
27 2. conjure the CONSUMER conduit
28 3. link() - only after BOTH exist
29 4. the consumer pulls the provider's spell into the contract
30 5. meld - this completes the late binding for that world
31 Chains assemble edge by edge. Skip step 5 on a middle world and its
32 consumer constructs with its Python default instead of the melded
33 object - that is a usage error with a visible symptom, not a
34 runtime gap.
35
36 WHY YOU DO NOT HAVE TO THINK ABOUT CONCURRENCY HERE
37 Melder serializes structural change internally, at a grain fine
38 enough that independent work overlaps: two agents adding to the
39 same spellbook do not wait on each other, while an operation that
40 changes what that spellbook IS excludes them both. None of that
41 vocabulary belongs in your code. If it ever shows up in a
42 traceback you will get the blocking holder named, not a hang.
43
44 AND A WORLD CAN BE TOLD IT DOES NOT DO THIS
45 `link()` asks the frame posture FIRST, and the posture gate answers
46 for both of the obvious cases:
47 a dynamic world with disable_linking=True -> refused
48 an ordinary static world -> refused
49 BOTH GET THE SAME SENTENCE - "Linking is disabled for the current
50 frame posture." - and that surprised the author of this lesson,
51 who expected the static world to complain about dynamic mode. It
52 does not, because an unconfigured non-dynamic frame is already
53 "not allowed to link" as far as the posture gate is concerned; the
54 separate dynamic-mode message sits behind that gate and only
55 surfaces when the posture passes and the CONDUIT was nevertheless
56 conjured non-dynamic.
57 The lesson: the message names the GATE that refused, not the
58 property you were thinking about. Two different worlds, one gate,
59 one sentence.
60SURFACE EXERCISED: md.Spellbook.bind / conjure / configure_aether_frame,
61 Conduit.link / add_spell_to_contract / meld
62VERIFY: went RED 2026-08-03 and was fixed the same day; awaiting
63 re-run. See the header note for what the failure taught.
64"""
65import melder as md
66
67
68class Service:
69 def __init__(self) -> None:
70 self.label = "service"
71
72
73class Consumer:
74 def __init__(self) -> None:
75 self.label = "consumer"
76
77
78def _pair(frame_name: str, **posture: object) -> tuple[md.Conduit, md.Conduit]:
79 """An owner and a borrower in one world, each from its own book.
80
81 Both books are EMPTY on purpose. link() asks the frame posture before
82 it reads a single spell, so these worlds need nothing bound to be
83 refused - and Service and Consumer are already one spell each in
84 rewire-world: a spell_id is the SHA256 of the class's code, so
85 binding them again here, under any binding_name, would be refused
86 before the posture gate ever spoke (advanced 02)."""
87 owner_book = md.Spellbook(aetheric_frame=frame_name)
88 borrower_book = md.Spellbook(aetheric_frame=frame_name)
89 if posture:
90 owner_book.configure_aether_frame(
91 disposal=None, disposal_method_names=None, **posture,
92 )
93 dynamic = posture.get("system_state") == "dynamic"
94 owner = owner_book.conjure(dynamic=dynamic, name=f"{frame_name}-owner")
95 borrower = borrower_book.conjure(
96 dynamic=dynamic, name=f"{frame_name}-borrower",
97 )
98 return owner, borrower
99
100
101def main() -> None:
102 # STEPS 1 AND 2: both conduits exist before anything is wired.
103 owner_book = md.Spellbook(aetheric_frame="rewire-world")
104 borrower_book = md.Spellbook(aetheric_frame="rewire-world")
105 service_id = owner_book.bind(
106 spell=Service, existence="unique", permissions="create",
107 binding_name="rewire-service",
108 )
109 borrower_book.bind(
110 spell=Consumer, existence="unique", permissions="create",
111 binding_name="rewire-consumer",
112 )
113 owner = owner_book.conjure(dynamic=True, name="owner")
114 borrower = borrower_book.conjure(dynamic=True, name="borrower")
115 print("two conduits up, nothing wired between them yet")
116
117 # The owner resolves its own spell. This works before any linking -
118 # ownership and sharing are different questions.
119 assert owner.meld("Service",
120 binding_name="rewire-service").label == "service"
121 print("owner melds its own spell -> service")
122
123 # STEP 3: link, now that both ends exist.
124 assert owner.link(borrower) is True
125 print()
126 print("link() -> True")
127
128 # STEP 4: the CONSUMER pulls. Naming `owner` here is not a style
129 # choice - the conduit named must own the spell.
130 assert borrower.add_spell_to_contract(
131 spell_id=service_id,
132 conduit=owner,
133 permissions="create",
134 )
135 print("borrower pulled the owner's spell into its contract")
136 print(" sharing is a PULL - the named conduit must OWN the spell")
137
138 # STEP 5: meld completes the late binding across the new edge.
139 borrowed = borrower.meld("Service", binding_name="rewire-service")
140 assert borrowed.label == "service"
141 print("borrower melds it ->", borrowed.label)
142 print()
143 print("the world was rewired while running, in three ordinary calls")
144
145 # A WORLD TOLD NOT TO LINK REFUSES, AND SAYS WHY. This one IS
146 # dynamic; it has simply been braked.
147 braked_owner, braked_borrower = _pair(
148 "rewire-braked", system_state="dynamic", disable_linking=True,
149 )
150 try:
151 braked_owner.link(braked_borrower)
152 raise AssertionError("expected a refusal: linking is braked")
153 except RuntimeError as error:
154 assert "posture" in str(error)
155 print()
156 print("braked world refused link() -")
157 print(" ", error)
158
159 # AN ORDINARY STATIC WORLD REFUSES TOO - and with the SAME sentence,
160 # because the posture gate answers first and an unconfigured
161 # non-dynamic frame is already "not allowed to link" to it.
162 static_owner, static_borrower = _pair("rewire-static")
163 try:
164 static_owner.link(static_borrower)
165 raise AssertionError("expected a refusal: static cannot link")
166 except RuntimeError as error:
167 assert "posture" in str(error)
168 print()
169 print("static world refused link() -")
170 print(" ", error)
171 print(" SAME sentence as the braked world: the message names the")
172 print(" GATE that refused, not the property you had in mind")
173
174 print()
175 print("link, pull, meld - and the order is just dependency order")
176 print("nothing here opens, holds, or commits anything by hand")
177
178
179if __name__ == "__main__":
180 main()
Check the outcome๏
The script contains its own assertions or demonstrated refusal paths. Run it to evaluate those checks against your installed version. The code above is taken directly from the saved file; no run output is invented here.