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.
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.
40SURFACE EXERCISED: research_create_lane / research_attach /
41 research_detach / research_archive / research_join /
42 research_heads,
43 ResearchSet.lane_names, Conduit.bind_inactive
44VERIFY: rides the owner's 3.14t harness; asserts are the contract.
45"""
46import melder as md
47
48
49FRAME = "organise-world"
50
51
52class Rule:
53 def __init__(self) -> None:
54 self.tag = "v1"
55
56
57class RuleV2:
58 def __init__(self) -> None:
59 self.tag = "v2"
60
61
62def main() -> None:
63 crystallizer = md.Crystallizer()
64 crystallizer.activate(
65 md.CrystallizerConfigurationBuilder().with_defaults().activate(),
66 )
67 research = md.MutationResearch()
68 configuration = research.create_configuration()
69 configuration.with_defaults().activate()
70 research.activate(configuration)
71
72 spellbook_configuration = (
73 md.SpellbookConfiguration(FRAME).with_defaults().finalize()
74 )
75 book = md.Spellbook(aetheric_frame=FRAME,
76 configuration=spellbook_configuration)
77 book.configure_aether_frame(
78 system_state="dynamic",
79 disposal=None,
80 disposal_method_names=None,
81 rift_enabled=True,
82 ai_native=True,
83 )
84 v1 = book.bind(spell=Rule, existence="unique", permissions="create",
85 binding_name="organise-rule")
86 conduit = book.conjure(name="organise-root")
87
88 nexus = md.Nexus()
89 system_configuration = nexus.create_configuration()
90 system_configuration.with_rift_creation_enabled(True)
91 system_configuration.with_allowed_target_frame_names([FRAME])
92 nexus.activate(system_configuration)
93 rift_configuration = nexus.create_rift_configuration()
94 rift_configuration.with_space_type("codegen")
95 rift = nexus.create_rift(configuration=rift_configuration,
96 rift_name="organiser")
97 rift.mark_active()
98 rift.create_frame_link(FRAME)
99 commands = rift.space.command_system
100 research_set = research.research_set()
101 print("v1 on the default lane:", v1[:12], "...")
102
103 # A lane cut with NO anchor - a perfectly legal shape, and the one
104 # `attach` exists to repair.
105 unanchored = commands.research_create_lane(
106 "unanchored", reason="cut without an anchor on purpose",
107 )
108 assert unanchored["anchor_spell_id"] is None
109 assert len(unanchored["nodes"]) == 0
110 print("cut 'unanchored' -> anchor is None, nodes 0")
111
112 # ATTACH IS ALL-OR-NOTHING and refuses before doing anything.
113 try:
114 commands.research_attach("unanchored", onto="default")
115 raise AssertionError("expected a refusal: anchor is all-or-nothing")
116 except TypeError:
117 print("attach(onto=) without at_spell_id -> TypeError (both or none)")
118
119 # Now anchor it properly, after the fact.
120 commands.research_attach("unanchored", onto="default", at_spell_id=v1,
121 reason="organising after the fact")
122 print("attach(onto='default', at_spell_id=v1) accepted")
123 print(" ancestry only - no node was copied, moved or created")
124
125 # A clean join is now possible, because the receiver is still at v1.
126 commands.research_join("unanchored", into="default",
127 reason="anchored, and the receiver has not moved")
128 print("join('unanchored') accepted - re-anchoring made it joinable")
129
130 # DETACH: a second lane, anchored, then deliberately un-anchored.
131 commands.research_create_lane(
132 "forgetful", attach_to="default", attach_at_spell_id=v1,
133 reason="this one will forget where it came from",
134 )
135 commands.research_detach("forgetful", reason="dropping the anchor")
136 print()
137 print("detach('forgetful') - the lane now remembers no origin")
138
139 # Move the receiver so the contrast is honest, then show that a
140 # detached lane joins only as an explicit supersede.
141 v2 = conduit.bind_inactive(
142 spell=RuleV2,
143 spell_index=conduit.get_spell_by_spell_id(v1).spell_index,
144 existence="unique", permissions="create",
145 )
146 print("default moved on:", v2[:12], "...")
147
148 try:
149 commands.research_join("forgetful", into="default")
150 raise AssertionError("expected a refusal: no anchor means divergent")
151 except RuntimeError as error:
152 print("join('forgetful') refused -", str(error)[:100])
153 print(" no anchor means nothing for the tip to agree with, so the")
154 print(" join is divergent BY DEFINITION - not by drift")
155
156 commands.research_join("forgetful", into="default", force=True,
157 reason="explicit supersede of an unanchored line")
158 print("join(force=True) accepted")
159
160 # ARCHIVE: retire a dead end. It is hidden, not unmade.
161 commands.research_create_lane(
162 "dead-end", attach_to="default", attach_at_spell_id=v1,
163 reason="an experiment that went nowhere",
164 )
165 # OPEN BUT EMPTY IS A REAL STATE. heads() carries the lane with a tip
166 # of None - "absent" and "None" mean different things here.
167 assert commands.research_heads()["dead-end"] is None
168 print()
169 print("'dead-end' is open with tip None - empty, not absent")
170
171 commands.research_archive("dead-end", reason="went nowhere")
172
173 # HIDDEN, NOT UNMADE - and the two reads disagree ON PURPOSE.
174 assert "dead-end" not in commands.research_heads(), "left the active view"
175 assert "dead-end" in research_set.lane_names(), "still exists - no delete"
176 print("archive('dead-end'):")
177 print(" heads() -> dropped (OPEN lanes only)")
178 print(" lane_names() -> still there (ALL lanes, any state)")
179 print(" the two reads disagree deliberately, and that gap IS the")
180 print(" difference between hidden and unmade. Residence stays")
181 print(" PERMANENT: the versions remain resident in the archived")
182 print(" container and a network snapshot can restore a view that")
183 print(" contained it")
184
185 # THE DEFAULT LANE NEVER ARCHIVES.
186 try:
187 commands.research_archive("default")
188 raise AssertionError("expected a refusal: default is guaranteed")
189 except RuntimeError as refusal:
190 print()
191 print("archive('default') refused -", str(refusal)[:100])
192 print(" it is the guaranteed world-entry record: register_spell")
193 print(" with no lane records THERE, so a set that archived it")
194 print(" could not serve its own default")
195
196 # A JOIN FINISHES THE SOURCE: both joined lanes are terminal, and the
197 # archived one is retired, so `default` is the only lane left open.
198 open_lanes = commands.research_heads()
199 assert set(open_lanes) == {"default"}, sorted(open_lanes)
200 print()
201 print("open lanes now:", sorted(open_lanes),
202 "- a join finishes its source")
203 print()
204 print("attach, detach, archive - all organisation, none content")
205 print("nodes never move, so a wrong shape is a wrong label, not lost work")
206
207
208if __name__ == "__main__":
209 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.