On this page
Two knobs and a terminator per rung๏
๐ต Expert ยท Lesson 06
THE LAST TWO PUBLIC NAMES, and what they say about the whole configuration story the curriculum has been tracking since advanced 07.
MutationResearchConfiguration has exactly TWO knobs: with_unrestricted_module_mutations(enabled) with_lane_type_enforcement(enabled)
Two. That is the entire configurable surface of a subsystem with 49 public methods, and the smallness is the point - the research plane records what happened; it does not need a policy engine to do it. Compare AethericFrameConfiguration's fourteen (advanced 05): a frame is a WORLD and needs a law book. A research set is a LEDGER and needs almost nothing.
WHAT THE TWO KNOBS ACTUALLY GOVERN unrestricted_module_mutations - whether the plane will record mutations that reach outside a spell's own module. Off is the conservative posture. lane_type_enforcement - whether LaneType (expert 03) is a RULE or a LABEL. You met this on the ResearchSet as a live setter; here is where the default comes from. That second one is worth noticing: the SAME switch exists in two places, at two scopes. The configuration sets the default for new sets; ResearchSet.set_lane_type_enforcement overrides it per set. A knob at both scopes is a deliberate answer to "is this a house rule or a per-experiment choice" - melder says both.
AND THE BUILDER CLOSES THE CONFIGURATION ARC. Advanced 17 measured nine public configuration objects carrying FIVE different terminator sets. This builder is the most generous shape in that table, tied with the crystallizer's:
build() hand me the configuration finalize() ...frozen activate() ...and in force
ONE TERMINATOR PER RUNG. You choose where to get off the ladder, instead of always landing on rung one and climbing manually the way AetherConfigurationBuilder makes you.
THE LADDER, ONE LAST TIME (and this is the fourth subsystem): Aether caller activates the config (advanced 07) Crystallizer caller activates the config (advanced 17) MutationResearch caller activates the config (here) Nexus activate() finalizes it FOR you (advanced 08) Three to one. Caller-driven activation is the house rule and Nexus is the exception - which is worth knowing before you meet a fifth subsystem and have to guess.
AND THE FOURTH ROOT HAS CAUGHT UP. Nexus was once the one root of four with NO builder at all - its callers built the configuration by hand while every other root handed one over. It now carries the same three exits, so the generosity table above is no longer lopsided. What has NOT changed is the two-bits rule: the builder's activate() marks the CONFIGURATION active, and you must still pass it to Nexus.activate(...). Two objects, two bits.
THE EXITS ARE ONE-SHOT, WHICH IS THE POINT OF A BUILDER. Each exit TRANSFERS OWNERSHIP and consumes the builder; a second exit raises. That is what makes a builder different from a config you keep poking - there is exactly one owner at each step, and the handoff is the moment ownership moves.
AND build() EARNS ITS PLACE ON THIS ROOT. The builder mirrors only the one knob almost everyone sets; the configuration carries a far wider with_* surface (frame allow/deny lists, tokens, nested rift policy). build() is the exit that hands you back something still MUTABLE so you can reach the rest. A frozen-only builder would have made the wide surface unreachable through it.
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/06_two_knobs_and_a_terminator_per_rung.py
py -3.14t UX_and_AIX_experiences/04_expert/06_two_knobs_and_a_terminator_per_rung.py
Public surface๏
md.MutationResearchConfiguration, md.MutationResearchConfigurationBuilder, md.NexusConfiguration, md.NexusConfigurationBuilder
Code๏
1"""
2TIER: expert (06)
3GOAL: THE LAST TWO PUBLIC NAMES, and what they say about the whole
4 configuration story the curriculum has been tracking since
5 advanced 07.
6
7 MutationResearchConfiguration has exactly TWO knobs:
8 with_unrestricted_module_mutations(enabled)
9 with_lane_type_enforcement(enabled)
10
11 Two. That is the entire configurable surface of a subsystem with 49
12 public methods, and the smallness is the point - the research plane
13 records what happened; it does not need a policy engine to do it.
14 Compare AethericFrameConfiguration's fourteen (advanced 05): a
15 frame is a WORLD and needs a law book. A research set is a LEDGER
16 and needs almost nothing.
17
18 WHAT THE TWO KNOBS ACTUALLY GOVERN
19 unrestricted_module_mutations - whether the plane will record
20 mutations that reach outside a spell's own module. Off is the
21 conservative posture.
22 lane_type_enforcement - whether LaneType (expert 03) is a RULE or
23 a LABEL. You met this on the ResearchSet as a live setter; here
24 is where the default comes from.
25 That second one is worth noticing: the SAME switch exists in two
26 places, at two scopes. The configuration sets the default for new
27 sets; ResearchSet.set_lane_type_enforcement overrides it per set.
28 A knob at both scopes is a deliberate answer to "is this a
29 house rule or a per-experiment choice" - melder says both.
30
31 AND THE BUILDER CLOSES THE CONFIGURATION ARC.
32 Advanced 17 measured nine public configuration objects carrying
33 FIVE different terminator sets. This builder is the most generous
34 shape in that table, tied with the crystallizer's:
35
36 build() hand me the configuration
37 finalize() ...frozen
38 activate() ...and in force
39
40 ONE TERMINATOR PER RUNG. You choose where to get off the ladder,
41 instead of always landing on rung one and climbing manually the way
42 AetherConfigurationBuilder makes you.
43
44 THE LADDER, ONE LAST TIME (and this is the fourth subsystem):
45 Aether caller activates the config (advanced 07)
46 Crystallizer caller activates the config (advanced 17)
47 MutationResearch caller activates the config (here)
48 Nexus activate() finalizes it FOR you (advanced 08)
49 Three to one. Caller-driven activation is the house rule and Nexus
50 is the exception - which is worth knowing before you meet a fifth
51 subsystem and have to guess.
52
53 AND THE FOURTH ROOT HAS CAUGHT UP. Nexus was once the one root of
54 four with NO builder at all - its callers built the configuration
55 by hand while every other root handed one over. It now carries the
56 same three exits, so the generosity table above is no longer
57 lopsided. What has NOT changed is the two-bits rule: the builder's
58 `activate()` marks the CONFIGURATION active, and you must still
59 pass it to `Nexus.activate(...)`. Two objects, two bits.
60
61 THE EXITS ARE ONE-SHOT, WHICH IS THE POINT OF A BUILDER.
62 Each exit TRANSFERS OWNERSHIP and consumes the builder; a second
63 exit raises. That is what makes a builder different from a config
64 you keep poking - there is exactly one owner at each step, and the
65 handoff is the moment ownership moves.
66
67 AND `build()` EARNS ITS PLACE ON THIS ROOT. The builder mirrors
68 only the one knob almost everyone sets; the configuration carries a
69 far wider `with_*` surface (frame allow/deny lists, tokens, nested
70 rift policy). `build()` is the exit that hands you back something
71 still MUTABLE so you can reach the rest. A frozen-only builder
72 would have made the wide surface unreachable through it.
73SURFACE EXERCISED: md.MutationResearchConfiguration,
74 md.MutationResearchConfigurationBuilder,
75 md.NexusConfiguration, md.NexusConfigurationBuilder
76VERIFY: RUN GREEN 2026-08-03 on the owner's 3.14t harness; the Nexus
77 builder section added 2026-08-04 and not yet run.
78"""
79import melder as md
80
81
82def main() -> None:
83 # TWO KNOBS. That is the whole configurable surface.
84 knobs = ("with_unrestricted_module_mutations", "with_lane_type_enforcement")
85 for knob in knobs:
86 assert hasattr(md.MutationResearchConfiguration, knob), knob
87 assert hasattr(md.MutationResearchConfigurationBuilder, knob), knob
88 print("configurable surface:", len(knobs), "knobs")
89 for knob in knobs:
90 print(" ", knob)
91
92 # For contrast - the frame's law book, from advanced 05.
93 print()
94 print("AethericFrameConfiguration carries 14. A frame is a WORLD.")
95 print("A research set is a LEDGER - it needs almost nothing.")
96
97 # THE CONFIG'S OWN LADDER. finalize seals, activate enables, and they
98 # are two bits (advanced 07's headline, still true four subsystems on).
99 config = md.MutationResearchConfiguration()
100 config.with_defaults()
101 assert config.activated is False
102 config.finalize()
103 assert config.activated is False, "finalize seals; it does not enable"
104 config.activate()
105 assert config.activated is True
106 print()
107 print("config ladder: with_defaults -> finalize (sealed) -> activate (in force)")
108
109 # THE BUILDER: ONE TERMINATOR PER RUNG. Take each exit and look at
110 # what it hands back - that is what proves the rungs are different,
111 # where checking the three names exist would only prove they exist.
112 print()
113 print("builder terminators, each one actually taken:")
114
115 built = md.MutationResearchConfigurationBuilder().with_defaults().build()
116 assert isinstance(built, md.MutationResearchConfiguration)
117 assert built.frozen is False and built.activated is False
118 print(" build() -> mutable | frozen:", built.frozen,
119 "activated:", built.activated)
120
121 sealed = (md.MutationResearchConfigurationBuilder()
122 .with_defaults().finalize())
123 assert sealed.frozen is True and sealed.activated is False, (
124 "finalize FREEZES without activating - that is its own rung"
125 )
126 print(" finalize() -> frozen | frozen:", sealed.frozen,
127 "activated:", sealed.activated)
128
129 ready = (md.MutationResearchConfigurationBuilder()
130 .with_defaults().activate())
131 assert isinstance(ready, md.MutationResearchConfiguration)
132 assert ready.frozen is True and ready.activated is True
133 print(" activate() -> in force | frozen:", ready.frozen,
134 "activated:", ready.activated)
135 print(" three exits, three DIFFERENT states - no manual rung 2")
136
137 # THE CONTRAST THAT MAKES THE POINT. Aether's builder offers ONE exit
138 # and leaves the rest to you.
139 assert not hasattr(md.AetherConfigurationBuilder, "activate")
140 print()
141 print("AetherConfigurationBuilder offers build() only - rung 2 is yours")
142 print("same pattern, different generosity. that divergence is real.")
143
144 # THE FOURTH ROOT CAUGHT UP. Nexus once had no builder at all; it now
145 # carries the same three exits, and each is taken here for the same
146 # reason as above - the states differ, so show the states.
147 nexus_built = md.NexusConfigurationBuilder().with_defaults().build()
148 assert nexus_built.frozen is False
149 nexus_sealed = md.NexusConfigurationBuilder().with_defaults().finalize()
150 assert nexus_sealed.frozen is True and nexus_sealed.activated is False
151 print()
152 print("NexusConfigurationBuilder takes the same three exits:")
153 print(" build() frozen:", nexus_built.frozen,
154 "| finalize() frozen:", nexus_sealed.frozen,
155 "activated:", nexus_sealed.activated)
156 print(" the root that once had NO builder now matches the table")
157
158 # BUILD() HANDS BACK SOMETHING STILL MUTABLE - and on this root that
159 # is the whole reason it exists. The builder mirrors one knob; the
160 # configuration carries the wide surface, so you need a mutable exit.
161 assert hasattr(md.NexusConfigurationBuilder, "with_rift_creation_enabled")
162 assert not hasattr(md.NexusConfigurationBuilder,
163 "with_allowed_target_frame_names")
164 assert hasattr(md.NexusConfiguration, "with_allowed_target_frame_names")
165 print(" builder mirrors with_rift_creation_enabled, NOT the frame lists")
166 print(" -> build() is the exit that keeps the wide surface reachable")
167
168 builder = md.NexusConfigurationBuilder()
169 builder.with_defaults().with_rift_creation_enabled(True)
170 handed_over = builder.build()
171 assert isinstance(handed_over, md.NexusConfiguration)
172 assert handed_over.frozen is False, "build() hands back a MUTABLE config"
173 handed_over.with_allowed_target_frame_names(["some-frame"])
174 print(" build() -> mutable, and the wide surface still applies")
175
176 # ONE-SHOT: the exit TRANSFERS OWNERSHIP and consumes the builder.
177 try:
178 builder.build()
179 raise AssertionError("expected the builder to be consumed")
180 except RuntimeError as consumed:
181 print(" second build() REFUSED:", str(consumed)[:58])
182 print(" one owner at each step - the handoff is ownership moving")
183
184 # THE TWO BITS SURVIVE. A builder that activates the CONFIG has still
185 # not turned the Nexus on; that is a separate call on the root.
186 ready = md.NexusConfigurationBuilder().with_defaults().activate()
187 assert ready.activated is True
188 print(" builder.activate() -> config activated, Nexus still OFF")
189 print(" two objects, two bits - the rule did not bend for the builder")
190
191 # THE SAME SWITCH AT TWO SCOPES. Configuration sets the default;
192 # ResearchSet overrides per set.
193 assert hasattr(md.MutationResearchConfiguration, "with_lane_type_enforcement")
194 assert hasattr(md.ResearchSet, "set_lane_type_enforcement")
195 print()
196 print("lane_type_enforcement lives at BOTH scopes:")
197 print(" configuration -> the default for new sets")
198 print(" ResearchSet -> the override for one set")
199 print("house rule AND per-experiment choice - melder ships both")
200
201 print()
202 print("caller-driven activation is the house rule, 3 subsystems to 1")
203 print("two knobs is not a gap - a ledger does not need a policy engine")
204
205
206if __name__ == "__main__":
207 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.