On this page
- Spell
SpellSpell.cleanup()Spell.resolvableSpell.managed_spell_modeSpell.managed_spell_limitSpell.managed_spell_timeout_secondsSpell.managed_spell_reset_methodsSpell.binding_hashSpell.emit_cache()Spell.emit_cache_file()Spell.keySpell.is_existing_creationSpell.is_class_spellSpell.is_method_spellSpell.is_lambda_spellSpell.has_existing_objectSpell.owner_conduit_infoSpell.requirementsSpell.symbolic_graphSpell.resolution_frameSpell.validation_result_phase4Spell.validation_result_phase6Spell.validatedSpell.is_brokenSpell.invalidate_spell()Spell.system_stateSpell.mutation_overrideSpell.has_mutation_overrideSpell.apply_mutation_override()Spell.clear_mutation_override()
Spell๏
Use md.Spell from the public package namespace.
- class Spell(spell: Any, spell_index: SpellIndex, spellframe: Any | None, binding_name: str | None, spell_name: str, existence: Existence, spell_type: SpellType, spell_id: str, permissions: Permissions, aetheric_frame: str, spellbook: Spellbook, profile: Any | None = None, existing_object: object | None = None, disposal_method_names: list[str] | None = None, *args: Any, resolvable: bool = True, spellframe_kind: SpellframeKind = SpellframeKind.none, implemented_protocols: tuple[type, ...] = (), managed_spell_mode: ManagedSpellMode | None = None, managed_spell_limit: int | None = None, managed_spell_timeout_seconds: float | None = None, managed_spell_reset_methods: tuple[str, ...] = (), **kwargs: Any)[source]๏
Internal
Represents one registered spell inside the Melder runtime.
A Spell is the canonical bind-time runtime record for one class, function, lambda, or existing object registration. It keeps the spell's structural identity, lifecycle policy, access policy, reflective profile, build-time artifacts, spell-local runtime helpers, and ownership metadata together so the rest of Melder can reason about one stable object instead of a loose bundle of values.
Contract:
Wraps exactly one registered spell target plus its SpellIndex, the index that organizes this spell with the other members and selects one.
Owns spell-local mutable runtime state such as hooks, dependency/build artifacts, the spell-owned CreationContextFactory, the spell-owned CreationContext, execution-plan dispatch-route metadata, and mutation overlays.
Does not validate bind-time inputs by itself; upstream bind/examiner stages are expected to hand it already-validated configuration.
Uses an internal RLock to guard multi-field configuration and cleanup transitions.
Becomes unusable after cleanup() completes; later live-object methods are expected to fail through check_cleaned().
Disposal metadata is established once at bind. The ordered list, presence flag, and binding hash describe that same policy. Post-creation mutation is unsupported; this class adds no copying or mutation guards.
Resolution capability is fixed per bound version and exposed by the read-only resolvable property, independently of activity and compilation state.
The managed options of an Existence.managed_spell_quantity binding (mode, limit, queue timeout, reset method names) are fixed per bound version the same way, as Bind normalized them, and exposed by read-only properties; they are part of the binding manifest, never of the spell_id.
binding_manifest records how this version is bound - its address, spellframe and kind, existence, disposal order, resolvable and managed settings - with its own SHA256, binding_hash. Built once at construction from the same arguments and kept after cleanup, like spell_id: what a spell IS is its spell_id, how it is kept is its binding (EPIC-2026-10-18-spell_identity_is_the_code).
Core Responsibilities:
Holds an immutable reference to the object (function/class/instance) it represents.
Tracks configuration data: type, binding profile (if attached), spellframe, ownership, and hooks.
Defines dependency DAGs for invocation and construction (via external DAG / resolution pipelines).
Manages permission control via the Permissions enum.
Enables hook-based lifecycle support (pre, activation, post).
Acts as a source of truth for spell identity and access.
Stores bind-time resolved disposal metadata (matched method names + boolean flag).
Tracks whether runtime resolution is still required before the first context build.
Caches the Phase 11 execution-plan dispatch-route hint used by current runtime path selection.
Permissions (Permissions enum):
read: Allows other conduits to use the spell as-is, but not modify or recreate it.
create: Allows other conduits to instantiate or construct new versions.
block: Prevents external access. Internal owner-conduit access is still allowed.
Key Concepts:
Each spell has a SHA256 spell_id: the digest of the registered object's code (SpellCodeDigest) and nothing from the bind call. How it is bound is its binding_manifest, hashed apart as binding_hash.
spellframe is the category half of the address: a string category or a Protocol contract. spellframe_kind records which (or none for a bare binding) and implemented_protocols the Protocol bind checked the spell against, so Phase 3 never infers a meaning from the frame's name.
Spells may be cleaned (cleanup()), after which modification is disallowed.
Dependency graphs and resolution profiles are produced by the Resolution / Meld pipeline, not by this class directly.
Permissions are enforced during conduit contract evaluation.
- Parameters:
spell (Any) -- The actual object to register (function, class, lambda, or existing instance).
spell_index (SpellIndex) -- The SpellIndex this spell is organized under; the index selects one member version as active.
spellframe (Optional[Any]) -- Frame context (usually a Protocol, class, or string) to scope the spell's identity.
binding_name (Optional[str]) -- The logical name this spell is bound to (e.g., "database", "engine"). Normalized as part of the internal key via SpellInputUtils. Maybe None for unnamed/default bindings.
spell_name (str) -- The actual internal name of the object or callable (for display/debugging).
existence (Existence) -- The spell's lifecycle policy (unique, shared, etc.).
spell_type (SpellType) -- Indicates if the spell is a class, method, lambda, or existing creation, and whether it participates in spellframes and/or binding names.
spell_id (str) -- The SHA256 of the registered object's code (SpellCodeDigest); nothing from the bind call enters it.
permissions (Permissions) -- Defines access control level for borrowing, invoking, or recreating this spell.
aetheric_frame (str) -- Logical Aether frame / namespace this spell was registered under.
profile (Optional[Any]) --
Optional reflective profile associated with this spell.
Currently:
The Bind pipeline finishes by attaching a combined general or detailed spell profile here.
Those combined profiles still expose the underlying binding and resolution artifacts for downstream consumers.
Legacy usage expecting raw profile types should treat this field as an opaque introspection artifact and normalize it first.
existing_object (Optional[object]) -- Optional pre-instantiated object to attach to the spell (EXISTING_CREATION* types). For factory-like spells (class/method/lambda), this is usually None.
spellbook (Spellbook) -- Back-reference to the owning Spellbook. This is a required live-owner contract used for internal coordination, graph wiring, diagnostics, and spell-system-state attachment.
kwargs (args and) -- Arbitrary tags and metadata for internal use or future extensions.
Threading / Concurrency:
'_Lock' guards internal multi-field mutation.
Spell-owned runtime context publication uses _creation_context_switch so only one builder wins publication at a time.
Higher-level conduit/spellbook orchestration still owns system-level concurrency decisions; this class only protects its own local state.
Lifecycle / Cleanup:
Spell owns its spell compiler artifact foundation, spell-owned CreationContextFactory, spell-owned CreationContext, hook lists, dependency/build artifacts and cached execution-plan dispatch-route metadata.
Conduit ownership can be restamped later, which invalidates the spell-owned CreationContext and rebuilds the spell-owned factory.
cleanup() is deterministic, best-effort for owned child cleanup, and clears references to prevent reuse-after-clean.
- Registration:
MELDER KERNEL - guarded (internal manifest). Melder constructs every Spell during Bind; a user never asks Melder to inject one, so bind(Spell) is the category error the guard refuses. access=public is deliberate and orthogonal to the guard: agents RECEIVE spells from bind() and from viewer/examination surfaces and read their identity, existence, and permissions - they simply do not construct or re-bind them.
- Subsystem Context:
The unit of currency of the spellbook subsystem. Bind produces one Spell (paired with the SpellIndex that organizes it) from a user target; Spellbook registers it into its owned/contracted maps and spell-id caches and registers its SpellIndex into SpellSystemStates. Downstream, the SpellCompiler keys every phase artifact on this spell (by spell_index.selected_spell_id) and Meld reads it to choose reuse-vs-construct. It hands structural identity to SpellIndex, build/plan artifacts to the SpellCompiler, and its Permissions to ConduitWard contract evaluation.
- System Context:
Lives in the Spellbook layer of the DGR boot order (Aether|AetherUtilitySystem -> Crystallizer -> MutationResearch -> Nexus -> AethericFrame -> Spellbook -> Conduit|Ward). Created at bind time - after a frame exists, before conjure - and is the object every later layer operates on per-spell: SpellCompiler phases 1-11, SpellSystemStates validity, ChangeControl dirty-root gating, and Meld resolution into live instances via Creations. It sits between the Spellbook that owns it and the Conduit/Meld layer that resolves it.
Notes
This class is never used directly by users. It is created during bind() and registered into the Spellbook and Aether.
Internal mutation after cleaning is disallowed.
Dependency graphs, resolution frames, and resolution profiles are produced by the Resolution / Meld layer; Spell itself does not execute resolution.
AGENT_ACCESS: public
- AGENT_PURPOSE:
access: public. One registered binding: identity, existence, permissions, spellframe, hooks. You receive spells from bind and from viewer surfaces; you do not construct them.
- cleanup() None[source]๏
Release the spell-owned runtime state and permanently retire this Spell.
- Purpose:
Deterministically tear down the spell-local runtime surface so later code cannot keep using stale build artifacts, runtime contexts, or owner references after the spell leaves service.
Contract:
Idempotent: repeated calls become no-ops after _cleaned flips.
Thread-safe: acquires _lock, re-checks _cleaned, and then performs teardown under the guarded section.
A direct call on a live spell - one its Spellbook is not driving (_spellbook_cleanup unset) - removes the spell through Spellbook.cleanup_and_remove_spell, which takes it off every registry and then calls back here for the local teardown. That removal runs outside _lock, under this spell's _removal_lock (created by the first direct call), so a second direct call waits for it and then returns.
Best-effort child cleanup: owned child cleanup failures are swallowed so teardown still reaches the final cleared state.
Clears hooks, metadata, dependency/build artifacts, execution-plan metrics, spell-owned factory/context state, conduit ownership state, spellbook references, and reflective profile state.
Sets _cleaned before the guarded section exits. _lock is kept, not deleted with the other fields, so a lock-guarded reader such as _spell_index_unless_cleaned can still take it on a cleaned spell. _removal_lock is deleted with the other fields; a direct call waiting on it holds its own reference.
Deletes the disposal-name reference without clearing its list; creation entries may still retain that established metadata.
Keeps the identity data readable: spell_id, the address (key), the spellframe and its kind, and binding_manifest / binding_hash.
- Threading:
The Book removal takes the Spellbook lock, frame locks and the Nexus record, while Book teardown (Spellbook._cleanup_spells, also reached from root and frame teardown) and conjure's ownership stamping (define_conduit_into_spells) take this spell's _lock under the Spellbook lock. Holding _lock across the removal hung both threads when they met (before 0.2.8233); now _lock covers only the decision (_direct_removal_route) and the local teardown. Nothing else in Melder takes _removal_lock, so it closes no lock-order cycle; a caller holding this spell's lock (with spell:) or another Melder lock around a direct call brings the old order back. A direct call racing its Book's teardown returns when the teardown cleaned the spell first, or raises the Book's cleaned RuntimeError; it does not hang. (direct_spell_cleanup_lock_order, 0.2.8233)
Runtime resolution and instance lifecycle remain owned by the Resolution / Meld layer, not by this class.
- Returns:
None.
- Raises:
RuntimeError -- On a direct call, from Spellbook.cleanup_and_remove_spell: the spell is not its Book's current active version (a parked version, for one); it is the active version of an index that also holds parked versions (nothing changes: notch the index to one of them, dispose them with cleanup_spell, or move them out with remove_from_spell_index first); or the Book has been cleaned and did not clean this spell.
- property resolvable: bool๏
Return this bound version's immutable resolution capability.
- Contract:
Default True is established at bind. The value is independent of index selection, permissions, existence, and current compilation validity. No live setter is provided; changing capability requires another binding.
- Returns:
Whether this version is declared available for runtime resolution.
- Return type:
bool
- Raises:
RuntimeError -- If this Spell has been cleaned.
- property managed_spell_mode: ManagedSpellMode | None๏
Return the pool policy of this managed version.
- Contract:
Set once at bind (default elastic for a managed binding) and part of the binding manifest, not the spell_id. No live setter; changing it takes another binding.
- Returns:
The mode, or None when the spell is not Existence.managed_spell_quantity.
- Return type:
Optional[ManagedSpellMode]
- Raises:
RuntimeError -- If this Spell has been cleaned.
- property managed_spell_limit: int | None๏
Return the limit of this managed version.
- Contract:
elastic: the most idle objects its pool keeps (default 256). limited_quantity and queue: the most objects alive at once, idle plus out. Set once at bind and part of the binding manifest, not the spell_id.
- Returns:
The limit, or None when the spell is not managed.
- Return type:
Optional[int]
- Raises:
RuntimeError -- If this Spell has been cleaned.
- property managed_spell_timeout_seconds: float | None๏
Return how long a queue lease of this version waits for a release.
- Contract:
Set once at bind for the queue mode and part of the binding manifest, not the spell_id; always None for elastic and limited_quantity, which never wait.
- Returns:
Seconds, or None.
- Return type:
Optional[float]
- Raises:
RuntimeError -- If this Spell has been cleaned.
- property managed_spell_reset_methods: tuple[str, ...]๏
Return the reset method names of this managed version.
- Contract:
Zero-argument methods of the class, run in this order on every release before the object is leased again. Set once at bind and part of the binding manifest, not the spell_id.
- Returns:
The names; empty when none were named or the spell is not managed.
- Return type:
tuple[str, ...]
- Raises:
RuntimeError -- If this Spell has been cleaned.
- property binding_hash: str๏
Return the SHA256 of this version's binding manifest.
- Contract:
How this version is bound - address, spellframe and kind, existence, disposal order, resolvable and managed settings - hashed apart from its code (spell_id). Equal bind arguments give equal hashes in every process; a change of any of them gives another. Readable after cleanup, like spell_id (binding_manifest is a value record).
- Returns:
64 hex characters (binding_manifest.binding_hash).
- Return type:
str
- emit_cache() bool[source]๏
Public API
Emit this spell's current cache payload through its owning Spellbook.
- Purpose:
Provide one spell-facing cache export entrypoint without moving cache ownership or file mutation into CreationContext.
Contract:
Returns early when spell-level cache policy is disabled.
Delegates the real cache update to the owning Spellbook.
Requires the spell to still have a live owning Spellbook.
- Returns:
True when the spell emitted a cache payload, otherwise False.
- Return type:
bool
- Raises:
RuntimeError -- If the spell no longer has an owning Spellbook.
- emit_cache_file() bool[source]๏
Public API
Emit the Spellbook-owned cache file for this spell's current cache state.
- Purpose:
Provide one spell-facing entrypoint for saving the current Spellbook-owned in-memory cache state to disk.
Contract:
Returns early when spell-level cache policy is disabled.
Delegates the real file emit to the owning Spellbook, which writes only when cache was staged since its last save.
Requires the spell to still have a live owning Spellbook.
A save the operating system refuses (a read-only cache folder, a full disk, or on Windows a bundle another handle holds open) does not raise: the Spellbook's cache utility logs it, the staged cache stays in memory for the next save, and this call returns False.
- Returns:
True when the Spellbook cache file was written; False when caching is off, nothing was staged since the last save, or the save was refused.
- Return type:
bool
- Raises:
RuntimeError -- If the spell no longer has an owning Spellbook.
- property key: tuple[str, str]๏
Internal
Return the canonical (frame_key, binding_key) lookup tuple.
Contract:
Always reflects the bind-time normalized key produced by SpellInputUtils.make_spell_key_from_parts(...).
Read-only at the Spell layer; callers must not mutate key semantics after bind time.
- Returns:
Canonical Spellbook dictionary key for this spell.
- Return type:
tuple[str, str]
- property is_existing_creation: bool๏
Whether this spell represents an existing, pre-created object.
Contract:
Derived ONCE from spell_type during __init__ and never recomputed; it is a bind-time fact, not runtime state.
Part of a strict four-way partition with is_class_spell, is_method_spell and is_lambda_spell: the four families cover all 14 SpellType members with no overlap, so for any spell EXACTLY ONE of them is True. Branching on all four without a fallback is safe and total.
Answers "did the user hand us the object?", which is distinct from has_existing_object - that one asks whether the object is still attached right now.
- Threading:
Unsynchronized read of an immutable bool; safe from any thread.
- Returns:
True only for EXISTING_CREATION* spell types.
- Return type:
bool
- property is_class_spell: bool๏
Whether this spell represents a class-backed factory registration.
Contract:
Derived ONCE from spell_type during __init__; bind-time fact.
Covers the four SPELL* members. This is the FACTORY family: melding constructs an instance per the spell's Existence policy, as opposed to is_existing_creation where the instance already exists.
Exactly one of the four family flags is True for any spell (see is_existing_creation for the full partition).
- Threading:
Unsynchronized read of an immutable bool; safe from any thread.
- Returns:
True only for SPELL* spell types.
- Return type:
bool
- property is_method_spell: bool๏
Whether this spell represents a non-lambda method or function registration.
Contract:
Derived ONCE from spell_type during __init__; bind-time fact.
Covers the four named METHOD* members and EXCLUDES the three LAMBDA_METHOD* members, which report through is_lambda_spell. The split exists because a lambda has no stable qualname to bind against, so lambda variants always carry a binding name or spellframe.
Exactly one of the four family flags is True for any spell (see is_existing_creation for the full partition).
- Threading:
Unsynchronized read of an immutable bool; safe from any thread.
- Returns:
True only for non-lambda METHOD* spell types.
- Return type:
bool
- property is_lambda_spell: bool๏
Whether this spell represents one of the lambda-backed method spell variants.
Contract:
Derived ONCE from spell_type during __init__; bind-time fact.
Covers the three LAMBDA_METHOD* members. Every one of them carries a binding name, a spellframe, or both - there is no bare LAMBDA_METHOD member, because an anonymous function supplies no usable identity of its own to bind against.
Exactly one of the four family flags is True for any spell (see is_existing_creation for the full partition).
- Threading:
Unsynchronized read of an immutable bool; safe from any thread.
- Returns:
True only for lambda METHOD* spell types.
- Return type:
bool
- property has_existing_object: bool๏
Whether this spell currently holds a concrete user-provided object.
Contract:
Meaningful only for EXISTING_CREATION* spell types.
Returns False for factory-style spell types even if they later create runtime instances through conduits.
- Returns:
True when user_created_object is currently attached.
- Return type:
bool
- property owner_conduit_info: tuple[str | None, str | None]๏
Return the current conduit ownership tuple for this spell.
Contract:
Both halves start None and are populated together when the owning conduit stamps ownership, which happens after conjure - never at bind time. (None, None) therefore means "not yet owned", not "error".
The name half is a convenience label and may be None even once the id is set, for conduits created without an explicit name.
- Threading:
Reads the two attributes separately WITHOUT holding self._lock, so the pair is not snapshotted atomically. A read racing an ownership stamp can observe a mixed tuple (new id, stale name). Callers that need a coherent pair must hold the spell lock via the with spell: context manager.
- Returns:
(owner_conduit_id, owner_conduit_name) when ownership has been stamped, otherwise (None, None).
- Return type:
tuple[Optional[str], Optional[str]]
- property requirements: SpellRequirements | None๏
Phase 1 artifact for this spell, if it has been computed.
This is populated by the compiler artifact during structural phase execution.
Contract:
PHASE-GATED PROBE. None means Phase 1 has not produced this artifact yet - either the structural phases have not run, or the artifact was invalidated and reset. It is never an error value, so this property does not raise for an un-run phase.
A read-through onto the spell-owned SpellCompilerArtifact. The Spell is the public face of that artifact; the artifact itself is internal.
The returned object is live, not a copy. A subsequent recompilation can replace or mutate it underneath the caller.
- Threading:
Unsynchronized read-through; a snapshot of a reference that compilation can swap concurrently.
- Returns:
- Phase 1 requirements, or None before the
structural phases have run for this spell.
- Return type:
Optional[SpellRequirements]
- property symbolic_graph: SpellSymbolicGraph | None๏
Phase 2 symbolic graph for this spell, if it has been computed.
This is populated by the compiler artifact during structural phase execution.
Contract:
PHASE-GATED PROBE; None means Phase 2 has not produced this artifact yet, or it was reset by an invalidation. Not an error.
Phase 2 consumes Phase 1, so a non-None graph implies requirements was populated at the time the graph was built - but not that it is still populated now, since invalidation can clear artifacts independently.
Read-through onto the spell-owned SpellCompilerArtifact; returns the live object, not a copy.
- Threading:
Unsynchronized read-through; snapshot only.
- Returns:
- The Phase 2 symbolic graph, or None before
Phase 2 has run.
- Return type:
Optional[SpellSymbolicGraph]
- property resolution_frame: Any๏
Phase 3 local resolution frame / DAG for this spell, if it has been computed.
This is populated by the compiler artifact during structural phase execution. Concrete type is intentionally opaque here; callers should treat it as an internal resolution artifact.
Contract:
PHASE-GATED PROBE; None means Phase 3 has not produced this artifact yet, or it was reset. Not an error.
The Any return type is DELIBERATE, not missing typing. The concrete resolution/DAG type is internal and free to change; treat the value as an opaque handle to pass back into melder, and do not branch on its structure.
Read-through onto the spell-owned SpellCompilerArtifact; returns the live object, not a copy.
- Threading:
Unsynchronized read-through; snapshot only.
- Returns:
The Phase 3 resolution frame, or None before Phase 3 has run.
- Return type:
Any
- property validation_result_phase4: SpellValidationResult | None๏
Phase 4 validation result for this spell, if it has been computed.
This is populated by the compiler artifact during structural phase execution.
Contract:
THIS IS THE DISCRIMINATOR for the validated / is_broken booleans. Those two are False both before Phase 4 runs and after a failing verdict; this property is None in the first case and non-None in the second, so it is the only way to tell "not checked" from "checked".
STRUCTURAL verdict only - it judges the spell in isolation. Conduit-scoped judgement lives in validation_result_phase6, and a spell can pass Phase 4 and still fail Phase 6.
Read-through onto the spell-owned SpellCompilerArtifact; returns the live object, not a copy.
- Threading:
Unsynchronized read-through; snapshot only.
- Returns:
- The structural (Phase 4) verdict, or None
if Phase 4 has not run for this spell.
- Return type:
Optional[SpellValidationResult]
- property validation_result_phase6: SpellSystemValidationState | None๏
Phase 6 validation result for this spell, if it has been computed.
This is populated by the compiler artifact during conduit-scoped validation.
Contract:
CONDUIT-SCOPED verdict, unlike the structural Phase 4 result. None here is expected for a bound-but-never-conjured spell, because Phase 6 runs as part of conduit-scoped validation rather than at bind time.
Passing Phase 4 does not imply Phase 6 will pass: a spell can be structurally sound and still be unsatisfiable in the conduit it is asked to live in (missing dependency, permission refusal).
None is not an error and this property does not raise.
Read-through onto the spell-owned SpellCompilerArtifact; returns the live object, not a copy.
- Threading:
Unsynchronized read-through; snapshot only.
- Returns:
- The system (Phase 6) verdict, or None
if Phase 6 has not run for this conduit.
- Return type:
Optional[SpellSystemValidationState]
- property validated: bool๏
Whether Phase 4 validation currently considers this spell valid.
Contract:
False IS AMBIGUOUS. It means either "Phase 4 has not run" or "Phase 4 ran and the spell did not pass". The flag alone cannot distinguish them, because it is initialized False and is reset to False whenever the artifact is invalidated.
To tell the two apart, read validation_result_phase4: None means the phase has not produced a verdict; a non-None result means the verdict is real and validated reflects it.
Never raises for an un-run phase; absence is reported as False, not as an error.
- Threading:
Unsynchronized read of the compiler artifact's flag. It is a snapshot; a concurrent revalidation can flip it immediately after this returns.
- Returns:
False until Phase 4 validation has populated the compiler artifact.
- Return type:
bool
- property is_broken: bool๏
Whether validation currently classifies this spell as broken or unsafe.
Contract:
False IS AMBIGUOUS in the same way as validated: it is the initial value AND the reset value, so an unvalidated spell and a validated-healthy spell both report False.
is_broken is NOT the negation of validated. A spell that has never been validated reports validated=False AND is_broken=False simultaneously. Do not treat not is_broken as "safe to use".
The honest health check is: validation_result_phase4 is not None (a verdict exists) AND validated (the verdict passed).
- Threading:
Unsynchronized read of the compiler artifact's flag; a snapshot only.
- Returns:
False until Phase 4 validation has populated the compiler artifact.
- Return type:
bool
- invalidate_spell(change_reason: SpellStateChangeReason | None = None) None[source]๏
Invalidate this spell for a full next-meld rebuild.
- Purpose:
Provide one spell-local helper for the common "this spell is no longer trustworthy; rebuild it on the next meld" path. This method is the spell-owned convenience wrapper over two different invalidation layers:
spell-local runtime invalidation
clear the cached CreationContext
force deferred runtime resolution to run again
control-plane invalidation of its SpellIndex
mark its SpellIndex structurally gated in SpellSystemStates
Contract:
Safe to call multiple times on a live spell.
Requires the spell to be attached to a dynamic runtime environment.
Clears the spell-owned CreationContext so the cached runtime dispatch state cannot survive a structural invalidation.
Sets resolution_complete=False and resolution_required=True so the next meld re-enters the deferred runtime plan path after structural validation succeeds.
Uses SpellSystemStates.mark_structural_change(...) when the control-plane registry is available.
Defaults the reason to SpellStateChangeReason.structure_changed when callers do not supply a more specific reason.
Intentionally does not use transfer-only hard-disable semantics; this helper models the recoverable post-change posture rather than the unsafe mid-transfer posture.
- Parameters:
change_reason -- Optional structural change reason to record in its SpellIndex's state. When omitted, the helper uses SpellStateChangeReason.structure_changed.
- Returns:
None.
- Raises:
RuntimeError -- If the spell has already been cleaned, or if the spell is not attached to a dynamic runtime environment.
- property system_state: SpellSystemState | None๏
Return the SpellSystemState instance associated with this spell's SpellIndex.
This is a read-mostly view into the change-control and validation state tracked by SpellSystemStates.
Contract:
Mutation and contract operations can ask for the current state of its SpellIndex.
Higher-level dev-ops and validation pipelines can inspect this value while orchestrating Phase 1-7 revalidation.
Returns None when SpellSystemStates are unavailable or the SpellIndex is not currently tracked.
- Returns:
The state object for this spell's SpellIndex, if available.
- Return type:
Optional[SpellSystemState]
- property mutation_override: dict๏
Current persistent default override payload for this spell.
This payload is pre-normalized into the same override-map shape that meld-time runtime overrides use. It is conceptually separate from the caller-supplied spell_override argument passed into meld(...):
meld spell_override -> one-call runtime override payload
Spell.mutation_override -> persistent default override payload stored on the spell itself
Contract:
None is the ONLY inactive sentinel. An empty dict is never stored: apply_mutation_override({}) normalizes to None, so a caller testing == {} will never match. Test is None, or use has_mutation_override.
Positional payloads are normalized into {"__args__": [...]}.
EMPTY POSITIONAL IS NOT EMPTY. apply_mutation_override([]) stores {"__args__": []}, which is a non-empty dict and therefore reports has_mutation_override == True. Empty dict and empty list are deliberately NOT symmetric: {} clears, [] installs a positional override of zero arguments.
Keyword payloads are copied into a fresh dict so later meld calls do not depend on caller-owned containers.
Note
The declared return annotation is dict, but this property returns Optional[dict[str, Any]] - None is the normal inactive value. Trust the Returns block below over the signature.
- Returns:
The normalized persistent default override payload currently attached to this spell, or None when no default payload is active.
- Return type:
Optional[dict[str, Any]]
- property has_mutation_override: bool๏
Whether this spell currently has a non-empty mutation overlay.
This is a convenience for Dynamic or AI-native flows that want a quick check before doing more expensive revalidation or graph rebuilds.
Contract:
Truthiness test over the stored payload, so it is False exactly when the payload is None.
Reports True for a zero-argument POSITIONAL override, because [] normalizes to {"__args__": []} which is a non-empty dict. apply_mutation_override([]) therefore leaves this True while apply_mutation_override({}) leaves it False.
Unlike apply_mutation_override / clear_mutation_override, this does NOT require a dynamic environment and does not raise; it is safe to probe on any live spell.
- Threading:
Unsynchronized single-attribute read.
- Returns:
True when the current overlay payload is non-empty.
- Return type:
bool
- apply_mutation_override(override: dict | list | tuple | None) None[source]๏
Apply or replace the persistent default override payload for this spell.
Contract:
Requires the spell to be attached to a dynamic runtime environment.
Normalizes the payload into the same runtime override-map shape that meld-time caller overrides use.
Stores only the normalized runtime payload shape on the spell.
Does not invalidate the spell, clear CreationContext, or mark structural change state.
Treats None and empty dict payloads as "no active default override payload."
- Parameters:
override --
New persistent default override payload. Supported shapes match meld-time override payloads:
dict for targeted keyword-style overrides
list / tuple for root positional overrides
None to clear the default payload
- Returns:
None.
- Raises:
RuntimeError -- If the spell is not attached to a dynamic runtime environment.
TypeError -- If override is not one of the supported override payload shapes.
- clear_mutation_override() None[source]๏
Clear any active persistent default override payload for this spell.
Contract:
Requires the spell to be attached to a dynamic runtime environment.
Resets the stored payload back to None.
Does not invalidate the spell or rebuild runtime shape.
- Returns:
None.
- Raises:
RuntimeError -- If the spell is not attached to a dynamic runtime environment.