On this page

Opening a rift๏ƒ

๐ŸŸ  Advanced ยท Lesson 09

OPENING A RIFT - and meeting melder's most repeated law for the third time in three lessons.

THE PATH (each step needs the one above it) nexus = md.Nexus() nexus.activate(nexus.create_configuration()) # lesson 08 rift_config = nexus.create_rift_configuration() rift_config.with_space_type("static") rift = nexus.create_rift(configuration=rift_config, rift_name="ops")

THE RIFT CONFIGURATION IS CONSUMED. create_rift() takes ownership. Hand the same configuration to a second create_rift() and it refuses with "RiftConfiguration has already been consumed." One configuration, one rift - the same one-shot law AetherConfigurationBuilder.build() follows (lesson 07). If you want two rifts, you ask the factory twice.

THE LAW YOU HAVE NOW SEEN THREE TIMES Melder never conflates "this exists" with "this is live". Every subsystem splits it into two bits, and only the names change:

lesson 07 config frozen / activated lesson 08 nexus is_configured / is_activated lesson 09 rift is_registered / is_active

Once you have seen it three times it stops being trivia and starts being the thing you predict. When you meet a melder object you have never used, look for its two bits first - presence and liveness are always separate questions, and the answer to one never implies the other.

WHAT THIS LESSON DELIBERATELY DOES NOT DO: AR targeting. That needs rift_enabled=True on the target frame's posture - the frame's opt-in to being observable, and it defaults False. Setting it is a FRAME concern, not a rift one, which is why it is not shown here: you posture the frame first, then attach. Rifts, rooms and workstations are what this lesson covers.

Before you run๏ƒ

Use the Advanced 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/03_advanced/09_opening_a_rift.py
py -3.14t UX_and_AIX_experiences/03_advanced/09_opening_a_rift.py

Download this collection ยท Source on GitHub

Public surface๏ƒ

md.Nexus.create_rift_configuration, create_rift, md.RiftConfiguration, md.Rift, md.RiftSpaceType

Code๏ƒ

  1"""
  2TIER: advanced (09)
  3GOAL: OPENING A RIFT - and meeting melder's most repeated law for the
  4      third time in three lessons.
  5
  6      THE PATH (each step needs the one above it)
  7        nexus = md.Nexus()
  8        nexus.activate(nexus.create_configuration())    # lesson 08
  9        rift_config = nexus.create_rift_configuration()
 10        rift_config.with_space_type("static")
 11        rift = nexus.create_rift(configuration=rift_config, rift_name="ops")
 12
 13      THE RIFT CONFIGURATION IS CONSUMED.
 14      create_rift() takes ownership. Hand the same configuration to a
 15      second create_rift() and it refuses with "RiftConfiguration has
 16      already been consumed." One configuration, one rift - the same
 17      one-shot law AetherConfigurationBuilder.build() follows (lesson 07).
 18      If you want two rifts, you ask the factory twice.
 19
 20      THE LAW YOU HAVE NOW SEEN THREE TIMES
 21      Melder never conflates "this exists" with "this is live". Every
 22      subsystem splits it into two bits, and only the names change:
 23
 24        lesson 07  config   frozen         / activated
 25        lesson 08  nexus    is_configured  / is_activated
 26        lesson 09  rift     is_registered  / is_active
 27
 28      Once you have seen it three times it stops being trivia and starts
 29      being the thing you predict. When you meet a melder object you have
 30      never used, look for its two bits first - presence and liveness are
 31      always separate questions, and the answer to one never implies the
 32      other.
 33
 34      WHAT THIS LESSON DELIBERATELY DOES NOT DO: AR targeting. That needs
 35      `rift_enabled=True` on the target frame's posture - the frame's
 36      opt-in to being observable, and it defaults False. Setting it is a
 37      FRAME concern, not a rift one, which is why it is not shown here:
 38      you posture the frame first, then attach. Rifts, rooms and
 39      workstations are what this lesson covers.
 40SURFACE EXERCISED: md.Nexus.create_rift_configuration, create_rift,
 41                   md.RiftConfiguration, md.Rift, md.RiftSpaceType
 42VERIFY: rides the owner's 3.14t run; asserts are the contract.
 43"""
 44import melder as md
 45
 46
 47def main() -> None:
 48    nexus = md.Nexus()
 49
 50    # A rift needs a live nexus underneath it - lesson 08's ladder.
 51    system_config = nexus.create_configuration()
 52    system_config.with_rift_creation_enabled(True)
 53    nexus.activate(system_config)
 54    assert nexus.is_activated is True
 55    print("nexus enabled; rift creation permitted")
 56
 57    # The per-rift configuration is its own object with its own factory.
 58    # Note the shape is identical to every other config in melder: with_*
 59    # verbs that mutate and return self, ending in a terminator.
 60    rift_config = nexus.create_rift_configuration()
 61    assert isinstance(rift_config, md.RiftConfiguration)
 62    rift_config.with_space_type("static")
 63    rift_config.with_space_name("health")
 64    print("rift configuration staged: static room named 'health'")
 65
 66    # create_rift finalizes the configuration on the way through - the same
 67    # courtesy Nexus.activate() extended in lesson 08, and still the opposite
 68    # of what Aether does.
 69    rift = nexus.create_rift(configuration=rift_config, rift_name="ops")
 70    assert isinstance(rift, md.Rift)
 71    print("rift opened:", rift.rift_name, "| id:", rift.id)
 72
 73    # ONE CONFIGURATION, ONE RIFT. The object was consumed by the call.
 74    try:
 75        nexus.create_rift(configuration=rift_config, rift_name="ops-again")
 76        raise AssertionError("expected ValueError: configuration consumed")
 77    except ValueError as error:
 78        print("second use refused:", error)
 79
 80    # THE TWO BITS, third appearance. Creation registered it; being
 81    # registered is not the same as being live.
 82    assert rift.is_registered is True
 83    print("after create - registered:", rift.is_registered,
 84          "active:", rift.is_active)
 85
 86    rift.mark_active()
 87    assert rift.is_active is True
 88    print("after mark_active - registered:", rift.is_registered,
 89          "active:", rift.is_active)
 90
 91    rift.mark_inactive()
 92    assert rift.is_active is False
 93    assert rift.is_registered is True, "liveness went; registration stayed"
 94    print("after mark_inactive - registered:", rift.is_registered,
 95          "active:", rift.is_active)
 96
 97    # The rift owns a concrete room and a gate. The room's kind came from
 98    # the configuration; the gate is the entry control (lesson 10 uses it).
 99    assert rift.space is not None
100    assert rift.rift_gate is not None
101    print("room:", type(rift.space).__name__,
102          "| gate:", type(rift.rift_gate).__name__)
103
104    # Nexus is the registry - the rift can be found by id and by name.
105    assert nexus.has_rift(rift.id) is True
106    assert rift.id in nexus.list_rift_ids()
107    print("registered with nexus; rift ids:", len(nexus.list_rift_ids()))
108
109    print()
110    print("one configuration, one rift - create_rift consumes it")
111    print("presence and liveness are ALWAYS two bits, whatever they are named")
112
113
114if __name__ == "__main__":
115    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 advanced examples ยท Level guide

API contracts๏ƒ