On this page
Organising lanes after the fact๏
๐ต Expert ยท Lesson 31
LANES ARE ORGANISED AFTER THE FACT, NOT PLANNED IN ADVANCE. Expert 23 cut branches and joined them. This is the other three verbs - the ones for when you got the shape wrong the first time.
research_attach(lane, onto=, at_spell_id=) re-anchor ancestry research_detach(lane) forget the anchor research_archive(lane) retire a dead end
ANCESTRY IS ORGANISATION, NOT CONTENT. Every one of these moves where a lane SAYS it came from. None of them copies, moves or deletes a version. That separation is why re-organising is cheap and safe: the nodes never move, so a wrong anchor is a wrong label rather than lost work.
ATTACH IS ALL-OR-NOTHING, and it refuses before taking a lock: onto and at_spell_id must both be supplied. There is no "anchor to whatever the tip is" shorthand, because the anchor is the one fact a later join reasons about - a shorthand would let you record a different anchor than you meant.
DETACH IS NOT A DELETE. It removes the anchor, leaving a lane that remembers nothing about where it came from. A detached lane can still be joined, but the join is DIVERGENT by definition - no anchor means nothing for the receiver's tip to agree with - so it needs the same explicit force=True supersede.
ARCHIVE RETIRES A LANE WITHOUT LOSING IT. Residence is permanent: the versions stay resident in the archived container, rediscovery still points at it, and a network snapshot can restore a view that contained it. Archiving hides a dead end from the ACTIVE view; it does not unmake it.
AND THE DEFAULT LANE NEVER ARCHIVES. It is the guaranteed world-entry record - register_spell without a lane records there, and default_lane resolves by well-known name - so a set that archived it could not serve its own default. The refusal is checked at the door rather than discovered later.
THE RECEIVER MOVES BY A NEW VERSION, BOUND THE WAY THE FIRST WAS. Rule is bound under the string category 'Rule' - the address a bare bind of Rule has - with binding name 'organise-rule', and RuleV2 is staged the same way; bind_inactive refuses a version bound any other way (2026-10-25).
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/31_organising_lanes_after_the_fact.py
py -3.14t UX_and_AIX_experiences/04_expert/31_organising_lanes_after_the_fact.py
Public surface๏
research_create_lane / research_attach / research_detach / research_archive / research_join / research_heads, ResearchSet.lane_names, Conduit.bind_inactive
Code๏
1"""
2TIER: expert (31)
3GOAL: LANES ARE ORGANISED AFTER THE FACT, NOT PLANNED IN ADVANCE. Expert
4 23 cut branches and joined them. This is the other three verbs -
5 the ones for when you got the shape wrong the first time.
6
7 research_attach(lane, onto=, at_spell_id=) re-anchor ancestry
8 research_detach(lane) forget the anchor
9 research_archive(lane) retire a dead end
10
11 ANCESTRY IS ORGANISATION, NOT CONTENT. Every one of these moves
12 where a lane SAYS it came from. None of them copies, moves or
13 deletes a version. That separation is why re-organising is cheap
14 and safe: the nodes never move, so a wrong anchor is a wrong label
15 rather than lost work.
16
17 ATTACH IS ALL-OR-NOTHING, and it refuses before taking a lock:
18 `onto` and `at_spell_id` must both be supplied. There is no
19 "anchor to whatever the tip is" shorthand, because the anchor is
20 the one fact a later join reasons about - a shorthand would let you
21 record a different anchor than you meant.
22
23 DETACH IS NOT A DELETE. It removes the anchor, leaving a lane that
24 remembers nothing about where it came from. A detached lane can
25 still be joined, but the join is DIVERGENT by definition - no
26 anchor means nothing for the receiver's tip to agree with - so it
27 needs the same explicit `force=True` supersede.
28
29 ARCHIVE RETIRES A LANE WITHOUT LOSING IT. Residence is permanent:
30 the versions stay resident in the archived container, rediscovery
31 still points at it, and a network snapshot can restore a view that
32 contained it. Archiving hides a dead end from the ACTIVE view; it
33 does not unmake it.
34
35 AND THE DEFAULT LANE NEVER ARCHIVES. It is the guaranteed
36 world-entry record - `register_spell` without a lane records there,
37 and `default_lane` resolves by well-known name - so a set that
38 archived it could not serve its own default. The refusal is checked
39 at the door rather than discovered later.
40
41 THE RECEIVER MOVES BY A NEW VERSION, BOUND THE WAY THE FIRST WAS.
42 Rule is bound under the string category 'Rule' - the address a
43 bare bind of Rule has - with binding name 'organise-rule', and
44 RuleV2 is staged the same way; bind_inactive refuses a version
45 bound any other way (2026-10-25).
46SURFACE EXERCISED: research_create_lane / research_attach /
47 research_detach / research_archive / research_join /
48 research_heads,
49 ResearchSet.lane_names, Conduit.bind_inactive
50VERIFY: RUN GREEN 2026-10-25 on 3.14t, GIL off and on; asserts are the
51 contract.
52"""
53import melder as md
54
55
56FRAME = "organise-world"
57
58
59class Rule:
60 def __init__(self) -> None:
61 self.tag = "v1"
62
63
64class RuleV2:
65 def __init__(self) -> None:
66 self.tag = "v2"
67
68
69def main() -> None:
70 crystallizer = md.Crystallizer()
71 crystallizer.activate(
72 md.CrystallizerConfigurationBuilder().with_defaults().activate(),
73 )
74 research = md.MutationResearch()
75 configuration = research.create_configuration()
76 configuration.with_defaults().activate()
77 research.activate(configuration)
78
79 spellbook_configuration = (
80 md.SpellbookConfiguration(FRAME).with_defaults().finalize()
81 )
82 book = md.Spellbook(aetheric_frame=FRAME,
83 configuration=spellbook_configuration)
84 book.configure_aether_frame(
85 system_state="dynamic",
86 disposal=None,
87 disposal_method_names=None,
88 rift_enabled=True,
89 ai_native=True,
90 )
91 v1 = book.bind(spell=Rule, spellframe="Rule", existence="unique",
92 permissions="create", binding_name="organise-rule")
93 conduit = book.conjure(name="organise-root")
94
95 nexus = md.Nexus()
96 system_configuration = nexus.create_configuration()
97 system_configuration.with_rift_creation_enabled(True)
98 system_configuration.with_allowed_target_frame_names([FRAME])
99 nexus.activate(system_configuration)
100 rift_configuration = nexus.create_rift_configuration()
101 rift_configuration.with_space_type("codegen")
102 rift = nexus.create_rift(configuration=rift_configuration,
103 rift_name="organiser")
104 rift.mark_active()
105 rift.create_frame_link(FRAME)
106 commands = rift.space.command_system
107 research_set = research.research_set()
108 print("v1 on the default lane:", v1[:12], "...")
109
110 # A lane cut with NO anchor - a perfectly legal shape, and the one
111 # `attach` exists to repair.
112 unanchored = commands.research_create_lane(
113 "unanchored", reason="cut without an anchor on purpose",
114 )
115 assert unanchored["anchor_spell_id"] is None
116 assert len(unanchored["nodes"]) == 0
117 print("cut 'unanchored' -> anchor is None, nodes 0")
118
119 # ATTACH IS ALL-OR-NOTHING and refuses before doing anything.
120 try:
121 commands.research_attach("unanchored", onto="default")
122 raise AssertionError("expected a refusal: anchor is all-or-nothing")
123 except TypeError:
124 print("attach(onto=) without at_spell_id -> TypeError (both or none)")
125
126 # Now anchor it properly, after the fact.
127 commands.research_attach("unanchored", onto="default", at_spell_id=v1,
128 reason="organising after the fact")
129 print("attach(onto='default', at_spell_id=v1) accepted")
130 print(" ancestry only - no node was copied, moved or created")
131
132 # A clean join is now possible, because the receiver is still at v1.
133 commands.research_join("unanchored", into="default",
134 reason="anchored, and the receiver has not moved")
135 print("join('unanchored') accepted - re-anchoring made it joinable")
136
137 # DETACH: a second lane, anchored, then deliberately un-anchored.
138 commands.research_create_lane(
139 "forgetful", attach_to="default", attach_at_spell_id=v1,
140 reason="this one will forget where it came from",
141 )
142 commands.research_detach("forgetful", reason="dropping the anchor")
143 print()
144 print("detach('forgetful') - the lane now remembers no origin")
145
146 # Move the receiver so the contrast is honest, then show that a
147 # detached lane joins only as an explicit supersede. The new version
148 # is bound the way the index's first one was.
149 v2 = conduit.bind_inactive(
150 spell=RuleV2,
151 spell_index=conduit.get_spell_by_spell_id(v1).spell_index,
152 spellframe="Rule", binding_name="organise-rule",
153 existence="unique", permissions="create",
154 )
155 print("default moved on:", v2[:12], "...")
156
157 try:
158 commands.research_join("forgetful", into="default")
159 raise AssertionError("expected a refusal: no anchor means divergent")
160 except RuntimeError as error:
161 print("join('forgetful') refused -", str(error)[:100])
162 print(" no anchor means nothing for the tip to agree with, so the")
163 print(" join is divergent BY DEFINITION - not by drift")
164
165 commands.research_join("forgetful", into="default", force=True,
166 reason="explicit supersede of an unanchored line")
167 print("join(force=True) accepted")
168
169 # ARCHIVE: retire a dead end. It is hidden, not unmade.
170 commands.research_create_lane(
171 "dead-end", attach_to="default", attach_at_spell_id=v1,
172 reason="an experiment that went nowhere",
173 )
174 # OPEN BUT EMPTY IS A REAL STATE. heads() carries the lane with a tip
175 # of None - "absent" and "None" mean different things here.
176 assert commands.research_heads()["dead-end"] is None
177 print()
178 print("'dead-end' is open with tip None - empty, not absent")
179
180 commands.research_archive("dead-end", reason="went nowhere")
181
182 # HIDDEN, NOT UNMADE - and the two reads disagree ON PURPOSE.
183 assert "dead-end" not in commands.research_heads(), "left the active view"
184 assert "dead-end" in research_set.lane_names(), "still exists - no delete"
185 print("archive('dead-end'):")
186 print(" heads() -> dropped (OPEN lanes only)")
187 print(" lane_names() -> still there (ALL lanes, any state)")
188 print(" the two reads disagree deliberately, and that gap IS the")
189 print(" difference between hidden and unmade. Residence stays")
190 print(" PERMANENT: the versions remain resident in the archived")
191 print(" container and a network snapshot can restore a view that")
192 print(" contained it")
193
194 # THE DEFAULT LANE NEVER ARCHIVES.
195 try:
196 commands.research_archive("default")
197 raise AssertionError("expected a refusal: default is guaranteed")
198 except RuntimeError as refusal:
199 print()
200 print("archive('default') refused -", str(refusal)[:100])
201 print(" it is the guaranteed world-entry record: register_spell")
202 print(" with no lane records THERE, so a set that archived it")
203 print(" could not serve its own default")
204
205 # A JOIN FINISHES THE SOURCE: both joined lanes are terminal, and the
206 # archived one is retired, so `default` is the only lane left open.
207 open_lanes = commands.research_heads()
208 assert set(open_lanes) == {"default"}, sorted(open_lanes)
209 print()
210 print("open lanes now:", sorted(open_lanes),
211 "- a join finishes its source")
212 print()
213 print("attach, detach, archive - all organisation, none content")
214 print("nodes never move, so a wrong shape is a wrong label, not lost work")
215
216
217if __name__ == "__main__":
218 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.