On this page

ReleaseManagedSpell๏ƒ

Use md.ReleaseManagedSpell from the public package namespace.

Implementation source

class ReleaseManagedSpell(*args: object, **kwargs: object)[source]๏ƒ

The one way back for managed objects: a process singleton that routes an object to the pool it came from.

Purpose:

Give an object leased from an Existence.managed_spell_quantity pool back to that pool - release(obj) - without a conduit, a spell id or a pool in hand. It keys every live pool by its managed class, so the common release is one dict get by type(obj) and the pool's put_back. A class managed by several pools (two binding names, two roots, two versions of one index) is resolved on a cold path: the active version wins, and otherwise spell_id= or conduit= picks the pool.

Responsibilities:

  • release(obj, *, spell_id=None, conduit=None): give one object back (the pool runs its resets, then the object is idle for the next lease).

  • managed(obj, ...): a ManagedSpellLease whose release() or with block gives it back once.

  • release_all(objects, ...): release many; failures are raised together after every attempt.

  • describe(cls): one snapshot per pool of a class - mode, count, idle and out objects, where it lives.

  • register(pool, ...) / unregister(pool): kept by the root stores as they take and give up pools, so the registry holds exactly the pools live stores hold.

Contract:

  • A process singleton with Aether's hosted-root shape (owner ruling 2026-10-15): Aether.__init__ builds it (ReleaseManagedSpell(aether=self), last, after Nexus), Aether.cleanup cleans it right after the frames, and ReleaseManagedSpell() returns that instance. A first construction without its host refuses.

  • Releasing never goes through Aether as a verb (owner ruling 2026-10-13) and never needs a conduit.

  • Identity is not tracked (owner, 2026-10-14): an object of a managed class is trusted to come from that class's pool; nothing records which objects are out.

  • The registry borrows the pools: it never cleans or disposes one. Each belongs to its root's store.

  • A class key is the exact class object: a subclass is a class of its own, and a redefined class (a new class object) is a new key.

Owned State:

  • _pools_by_class: class -> tuple of pools. The release fast path reads it without a lock.

  • _registrations: id(pool) -> (class, id of the root whose store holds the pool), for the cold paths.

  • _lock: a leaf lock held only to publish new maps.

Both maps are replaced whole (copy-on-write) and never mutated after they are published, so a lock-free reader always sees one complete map.

Threading:

  • release on a one-pool class with no filter takes no lock: one attribute read, one dict get, then the pool's own lock-free put-back.

  • register and unregister build new maps under _lock and publish _registrations then _pools_by_class. _lock is never held with another lock and runs no user code.

  • Singleton construction and reset take the class-level _singleton_lock; Aether.__init__ builds this object under Aether._lock, so the nesting is one-way Aether -> ReleaseManagedSpell.

Performance:

Measured 2026-10-15 (CPython 3.14.7t, both GIL modes): a bound release adds about 50 ns over the pool's own put_back; the singleton call ReleaseManagedSpell() costs about 70 ns more, as Aether() does. A hot loop binds it once - release = ReleaseManagedSpell().release - and calls release(obj).

Lifecycle / Cleanup:

cleanup() is idempotent: it publishes empty maps (tombstones, so lock-free readers racing it see an empty registry rather than missing fields), keeps _lock (a register or unregister racing it takes the lock and sees it cleaned) and resets the singleton bookkeeping. After cleanup release, managed, release_all, describe and register raise the cleaned RuntimeError; unregister does nothing (it is part of teardown). _reset_singleton_for_tests() cleans the live instance and clears the bookkeeping.

Registration:

MELDER KERNEL - guarded. Created by Aether at boot; users call ReleaseManagedSpell() to reach it and never bind it as a spell.

Subsystem Context:

The managed lifetime (EPIC-2026-10-14-managed_spell_quantity): each managed spell version has a ManagedSpellQuantity pool in its owning root's Creations; a meld or an injection leases from it; this registry gives objects back; root teardown disposes what the pool holds. An ownership transfer moves a pool between stores, and the stores re-register it under its new root.

System Context:

Melder keeps the structure right - pools, this registry, the records that move with a transfer - and leaves the objects it hands out to the agents (src_architecture, "Runtime Model: Structure Is the Contract"). An object never released stays out and holds its place in a limited or queue pool until the root ends.

AGENT_ACCESS: public

AGENT_PURPOSE:

access: public. Give managed objects back: ReleaseManagedSpell().release(obj) returns an object leased from a managed_spell_quantity pool (its resets run, it is reused by the next lease); managed(obj) gives a lease for a with block; release_all(objects); describe(cls) shows each pool's mode, count and idle objects. Pass spell_id= or conduit= only when one class is managed by several pools. In a hot loop bind it once: release = ReleaseManagedSpell().release.

cleanup() → None[source]๏ƒ

Retire the registry and reset the singleton.

Contract:

  • Idempotent and one-way.

  • Publishes empty maps as tombstones, so a lock-free reader racing this cleanup sees an empty registry, and the release fast path then misses and raises the cleaned error from the cold path.

  • Keeps _lock as a tombstone: a register or unregister racing this cleanup takes it and observes _cleaned instead of a missing field.

  • Never cleans a registered pool: pools belong to their stores, which unregistered them already when Aether tears its frames down first.

  • Resets _instance and _initialized unconditionally, as Aether does: a stale instance cannot unseat a live successor, because its cleanup returns at the cleaned check above.

Threading:

Takes _lock to retire the maps, then _singleton_lock to reset the bookkeeping; never both at once.

Returns:

None.

register(pool: ManagedSpellQuantity, *, root_conduit_id: str) → None[source]๏ƒ

Internal

Make a pool routable: called by a root store when it takes a pool (ensure at an owner stamp, a restore).

Contract:

  • Keys the pool by its managed class (pool.managed_class) and records the root whose store holds it.

  • Idempotent: the same pool, class and root register once. The same pool under a new root (a restore into another root) only moves its root; under a new class (a rebind that brought another class object) it moves to that class.

  • Publishes new maps; never mutates a published one.

Parameters:
  • pool -- A live pool held by the calling store.

  • root_conduit_id -- Id of the root conduit whose store holds the pool now.

Raises:

RuntimeError -- If the registry or the pool has been cleaned.

Threading:

Takes the leaf _lock to read and publish; no user code runs under it.

Returns:

None.

unregister(pool: ManagedSpellQuantity) → None[source]๏ƒ

Internal

Forget a pool: called by a store when it gives the pool up (extract, a restore replacing it, its cleanup).

Contract:

  • Idempotent: an unregistered pool, or a second call, does nothing.

  • Does nothing on a cleaned registry: unregistering is part of teardown, and a registry already gone has nothing to forget.

  • The pool's class stays routable while it has other pools; a class with none left leaves the registry.

Parameters:

pool -- The pool the calling store gives up.

Threading:

Takes the leaf _lock to read and publish; no user code runs under it.

Returns:

None.

release(obj: object, *, spell_id: str | None = None, conduit: Conduit | None = None) → None[source]๏ƒ

Give one leased object back to its pool.

Purpose:

The common hand-back. With one pool for the object's class and no filter it is one dict get and the pool's put_back; otherwise the cold resolver picks the pool.

Contract:

  • The pool runs its reset methods in order, then the object is idle for the next lease; an elastic pool above its baseline may trim its oldest idle objects (disposed outside every lock).

  • Several pools for the class: spell_id keeps the pool of that version, conduit the pools held by its root (a root or one of its lessers names that root); when more than one remains, the pools whose version is the one its index selects are preferred; exactly one must remain.

  • Trusted, never checked: the object is assumed to be one this pool leased.

Parameters:
  • obj -- An object leased from a managed spell's pool.

  • spell_id -- Optional spell_id picking one pool.

  • conduit -- Optional root conduit, or a lesser of it, picking the pools that root holds.

Raises:
  • ValueError -- The class is managed by no live pool, the filters match none, or several remain.

  • TypeError -- spell_id is not a str, or conduit is not a Conduit.

  • RuntimeError -- The registry or the given conduit was cleaned, or the pool was torn down with its root (the object is then the caller's to dispose).

  • Exception -- What a reset raised, after the pool destroyed the object.

  • ExceptionGroup -- A raising reset whose disposal failed too, or an elastic trim's disposal failures.

Threading:

The fast path takes no lock. Safe from any thread.

Returns:

None.

managed(obj: ManagedObjectT, *, spell_id: str | None = None, conduit: Conduit | None = None) → ManagedSpellLease[ManagedObjectT][source]๏ƒ

Return a lease that gives one leased object back once, by release() or at the end of a with block.

Contract:

  • The pool is resolved now, exactly as release resolves it; the lease then needs no lookup.

  • with ReleaseManagedSpell().managed(obj) as o: releases o when the block ends, whether or not it raised, and never suppresses the block's exception.

Parameters:
  • obj -- An object leased from a managed spell's pool.

  • spell_id -- Optional spell_id picking one pool.

  • conduit -- Optional root conduit, or a lesser of it, picking the pools that root holds.

Raises:

ValueError, TypeError, RuntimeError -- As release raises them while resolving the pool.

Returns:

The lease over obj and its pool.

Return type:

ManagedSpellLease

release_all(objects: Iterable[object], *, spell_id: str | None = None, conduit: Conduit | None = None) → None[source]๏ƒ

Give many leased objects back, attempting every one.

Contract:

  • Each object is released as release(obj, spell_id=..., conduit=...) would; a failure does not stop the rest.

  • Every failure is raised together afterwards, in object order, as one ExceptionGroup.

Parameters:
  • objects -- The leased objects (any iterable, consumed once).

  • spell_id -- Optional spell_id picking one pool for every object.

  • conduit -- Optional root conduit, or a lesser of it, picking the pools that root holds.

Raises:
  • RuntimeError -- If the registry has been cleaned (nothing is released).

  • ExceptionGroup -- "Errors occurred releasing <n> of <m> managed objects", after every object was attempted.

Returns:

None.

describe(cls: type) → Tuple[Dict[str, Any], ...][source]๏ƒ

Return one snapshot per live pool of a managed class.

Contract:

  • Each entry is the pool's own describe() (mode, limit, timeout, count, idle and out counts, retention, spell identity, children recorded) plus holding_conduit_id (the root whose store holds the pool now) and active_version (whether its version is the one its index selects).

  • Entries follow registration order; a class with no pool answers ().

  • A read: it creates, registers and changes nothing.

Parameters:

cls -- The managed class.

Raises:
  • TypeError -- If cls is not a class.

  • RuntimeError -- If the registry has been cleaned, or a pool was torn down with its root while it was being described.

Returns:

The snapshots.

Return type:

Tuple[Dict[str, Any], ...]

Topic reference ยท Full contents