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

Download this collection ยท Source on GitHub

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.

More expert examples ยท Level guide

API contracts๏ƒ