orthonym.assembly.memo#
Note
Internal API. Names and behaviour may change between releases.
Scoped-per-call memoization infrastructure (M1, Levers C1 + E).
A byte-identity-preserving cache whose lifetime is exactly ONE top-level naming
call. The engine re-names the same substituent fragments many times inside one
molecule – the dispatch cascade, the _retry_cascade_on_gate_rejection
re-entries and the recursive Tier-4 cascade all re-derive the same fragment
prefixes – so a per-call cache removes that redundant work without changing any
emitted name. See internal notes Part 2.
Design invariants (each is load-bearing for the 0-wrong / byte-identity contract):
Scope is per top-level call. A
contextvars.ContextVarholds the cache dict; it is created at the outermost naming entry and torn down on exit, so cross-molecule staleness, tier drift and env-flag changes are structurally impossible and memory stays bounded.Fail-open, never fail-wrong. With no active scope (or
ORTHONYM_MEMO=off) every call recomputes. A cache MISS can never corrupt output; only a false HIT could, and that is exactly what a COMPLETE key andverifymode prevent.``verify`` mode is the continuous completeness check. It always recomputes and raises:class:MemoMismatch the instant a stored value disagrees with a fresh one for the same key – turning an incomplete key into a loud failure rather than a silent wrong name.
Dependency-light on purpose (contextvars + os only).
- orthonym.assembly.memo.verify_mismatch_count()#
Number of verify-mode same-key-different-result events since the last reset.
- orthonym.assembly.memo.reset_verify_mismatches()#
Clear the verify-mode mismatch log (call before a validation corpus run).
- orthonym.assembly.memo.pin_promotion_var = <ContextVar name='orthonym_pin_promotion' default=False>#
True while the default (PIN) tier re-names a molecule it could not name, with the best-effort ring-substituent producers admitted under the PIN-vocabulary guard (
rules.pin_vocabulary.promote_at_pin_tier;Orthonym.name). Values computed in that re-run can differ from the first run’s for the same key, so every cache below keys them apart: neither run is ever served the other’s value, and the first run stays byte-identical to the engine without the re-run.
- orthonym.assembly.memo.prefixes_apart_var = <ContextVar name='orthonym_prefixes_apart' default=False>#
True while an isotope-labelled molecule’s skeleton is named with its identical N- and C-prefixes cited apart (
composition_primitives. identical_prefixes_cited_apart). Its values differ from the grouped run’s for the same key, so the caches below key them apart, as for the promotion re-run.
- exception orthonym.assembly.memo.MemoMismatch(namespace, key, stored, fresh)#
Bases:
ExceptionRaised in
verifymode when a cached result disagrees with a fresh recompute for the same key – i.e. the cache key is INCOMPLETE and a hit would have shipped a wrong name. Carries the offending namespace/key and both values so the missing key component can be identified.
- orthonym.assembly.memo.push_scope()#
Open a memo scope for this (and nested) calls, unless one is already open.
Returns a ContextVar token when THIS call created the scope (the caller owns teardown and must pass the token to:func:pop_scope), or
Nonewhen a scope already existed (a nested re-entry – it shares the outer cache and must NOT reset it).
- orthonym.assembly.memo.pop_scope(token)#
Tear down the scope created by the matching:func:push_scope. A
Nonetoken (nested re-entry) is a no-op, so only the outermost frame tears down.
- orthonym.assembly.memo.push_sandbox()#
Open a throwaway COPY of the current scope for a speculative computation.
Reads still hit what the enclosing scope already holds; writes land in the copy and are discarded by:func:pop_sandbox, so the enclosing naming can never be served a value the speculation computed in its own context. With no scope open, nothing changes (no caching, as before). Always returns a token for:func:pop_sandbox.
- orthonym.assembly.memo.pop_sandbox(token)#
Discard the sandbox opened by the matching:func:push_sandbox.
- orthonym.assembly.memo.side_get(namespace, key)#
Return the scope-bound side value for
(namespace, key), orNone.
- orthonym.assembly.memo.side_put(namespace, key, value)#
Store a scope-bound side value for
(namespace, key)(no verify compare). A no-op with no active scope (fail-open: no scope -> no hit -> no replay).
- orthonym.assembly.memo.process_cache_stats()#
{"size", "maxsize", "hits", "misses"}for the process-wide pure cache.
- orthonym.assembly.memo.clear_process_cache()#
Drop every process-wide entry (tests; a worker that changes engine flags).
- orthonym.assembly.memo.pure_cache_or_compute(namespace, key, compute_fn)#
Memoise a value that is a pure function of
keyfor the LIFE OF THE PROCESS.Same contract as:func:cache_or_compute except that the entry outlives the naming scope. Bounded LRU (
ORTHONYM_PROCESS_CACHEentries, default 20,000;0disables).ORTHONYM_MEMO=off/verifybypass it exactly as they bypass the scope cache. The caller guarantees the key determines the value.
- orthonym.assembly.memo.cache_or_compute(namespace, key, compute_fn)#
Return the memoized value for
(namespace, key), computing it viacompute_fnon a miss.ORTHONYM_MEMO=offOR no active scope -> alwayscompute_fn(fail-open; never caches).on-> return the cached value if present, else compute + store + return.verify-> ALWAYS recompute; if a value is already stored for the key and differs, raise:class:MemoMismatch; then store + return the fresh value.