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

Download this collection ยท Source on GitHub

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.

More expert examples ยท Level guide

API contracts๏ƒ