On this page
Read ward policy before changing it๏
Prerequisite: linking and permissions.
Conduit.policy reports the current ward policy. The policy controls contract
direction and how per-spell restrictions are applied.
The five modes are default, whitelist_all, block_all, inbound_only, and
outbound_only. Use their names or enum members; an enum's integer .value is
not its string name.
Diagnose the refusal boundary๏
The saved policy lesson checks three conditions: the frame must be dynamic, the conduit must be normal, and restrictive policy changes can be refused while contracts exist. A policy change does not silently tear down existing relationships.
Read the current relationships, end the contracts deliberately if that is the intended application operation, then apply the policy. Use the existing severing guide for the relationship's lifecycle.
The workflow in code๏
These are the core steps from the saved example. Use its complete linked script for all class definitions and setup.
1def main() -> None:
2 # Pass the mode NAME. That is the whole API - every setter in melder
3 # that takes an enum is typed Union[Enum, str] and normalizes for you.
4 print("the five modes:", list(MODES))
5 assert {policy.name for policy in md.Policies} == set(MODES)
6
7 # AND HERE IS WHY THE STRING IS THE RIGHT HABIT, not just the shorter
8 # one. Policies is built on auto(), so `.value` is an INT - reach for
9 # it to build the argument and you pass 3 instead of "block_all". The
10 # name is the string form. Use the literal and the trap disappears.
11 assert isinstance(md.Policies.block_all.value, int)
12 assert md.Policies.block_all.name == "block_all"
13 print("Policies.block_all.value is", md.Policies.block_all.value,
14 "- an int, not the mode name. pass \"block_all\" instead.")
15
16 # ------------------------------------------------------------------
17 # REFUSAL 1 - DYNAMIC MODE ONLY
18 # ------------------------------------------------------------------
19 # Each world binds its OWN class. A spell_id is the SHA256 of the
20 # class's code and neither the frame nor the binding_name is in it,
21 # so the same class bound in two frames is one spell_id and the
22 # second registration is refused process-wide. Frames isolate
23 # instances, not identity - see advanced 02.
24 automatic_book = md.Spellbook(aetheric_frame="ward-automatic")
25 automatic_book.bind(spell=Payload, existence="unique",
26 binding_name="automatic")
27 automatic_root = automatic_book.conjure(name="automatic-root")
28 try:
29 automatic_root.set_new_policy("block_all")
30 raise AssertionError("expected RuntimeError on an automatic frame")
31 except RuntimeError as error:
32 print()
33 print("automatic frame refused set_new_policy:", error)
34
35 # ------------------------------------------------------------------
36 # A DYNAMIC WORLD - now the door opens
37 # ------------------------------------------------------------------
38 book = md.Spellbook(aetheric_frame="ward-dynamic")
39 book.bind(spell=DynamicPayload, existence="unique", binding_name="dynamic")
40 book.configure_aether_frame(system_state="dynamic", disposal=None,
41 disposal_method_names=None)
42 root = book.conjure(name="ward-root")
43 print()
44 print("dynamic frame conjured")
45
46 # Plain strings, like every other enum-shaped argument in melder. The
47 # ward normalizes through EnumHelpers.convert_enum_and_check, so the
48 # mode NAME is all you ever need to pass.
49 root.set_new_policy("outbound_only")
50 print("policy -> outbound_only")
51
52 root.set_new_policy("inbound_only")
53 print("policy -> inbound_only")
54
55 root.set_new_policy("default")
56 print("policy -> default")
57
58 # ------------------------------------------------------------------
59 # REFUSAL 2 - NORMAL CONDUITS ONLY
60 # ------------------------------------------------------------------
61 lesser = root.create_lesser_conduit()
62 try:
63 lesser.set_new_policy("block_all")
64 raise AssertionError("expected RuntimeError on a lesser conduit")
65 except RuntimeError as error:
66 print()
67 print("lesser conduit refused a policy:", error)
68
69 # ------------------------------------------------------------------
70 # REFUSAL 3 - NO RETROACTIVE LOCKDOWN
71 # ------------------------------------------------------------------
72 # With no contracts yet, the restrictive modes are allowed.
73 root.set_new_policy("block_all")
74 print()
75 print("block_all accepted while the ward has no contracts")
76 root.set_new_policy("default")
77
78 # Form a contract, and the restrictive modes stop being available -
79 # melder refuses rather than severing behind your back.
80 peer_book = md.Spellbook(aetheric_frame="ward-dynamic")
81 peer = peer_book.conjure(name="ward-peer")
82 linked = root.link(peer)
83 print("linked to a peer:", linked)
84
85 for restrictive in ("block_all", "whitelist_all"):
86 try:
87 root.set_new_policy(restrictive)
88 raise AssertionError(
89 f"expected RuntimeError setting {restrictive} with contracts"
90 )
91 except RuntimeError as error:
92 print(f"{restrictive:14s} refused while contracts exist")
93
94 # The permissive/directional modes are still fine - only the two that
95 # would invalidate existing grants are gated.
96 root.set_new_policy("outbound_only")
97 print("outbound_only still accepted - it does not invalidate grants")
98
99 print()
100 print("policy governs direction AND whether per-spell checks apply")
101 print("a change that cannot be honestly applied is refused, not partial")
Runnable examples๏
Ward policies โ Advanced 16