mixle.system.registry module¶
Registry – a local directory + index of fitted task models, queryable by capability and fingerprint.
The registry is the local library catalog that orchestrators, routers, capture
flows, and accumulation workflows can read from or write into. Deliberately a
directory plus a JSON index, not a server: every entry is a saved
TaskModel, CalibratedTaskModel, or an IC-1
Posterior-conforming field-posterior artifact directory (see mixle.task.artifact for the
first two; the third is written/read through mixle_pde.io.artifacts – IC-2 – lazily imported so
this module never hard-depends on the mixle_pde plugin). A small index record names each entry’s
capabilities, task fingerprint (task_fingerprint()), and capture profile.
find_for answers “do I already have something for this task”; tier_stack turns a matching
capability into an ascending-cost tier list – the shape Router consumes
directly (Router(tiers=stack)), with the frontier appended last as the router’s own fallback tier.
- class Registry(dir)[source]
Bases:
objectA
dir-backed catalog of registered models:registerwrites an artifact + index entry;find_for/tier_stackquery it. Re-opening the samedirin a fresh process sees every entry.- Parameters:
dir (str)
- register(model, *, capabilities, fingerprint=None, profile=None, cost=0.0, entry_id=None)[source]
Save
model’s artifact underdirand add its index entry; return the entry.modelis a fittedTaskModel, aCalibratedTaskModel, or amixle_pdefield posterior (a “field_posterior” kind, IC-2) – the three artifact-saveable model kinds.capabilitiesnames what this model answers (matched byfind_for());fingerprintis typicallytask_fingerprint()’s vector for the training data;profileis free-form (e.g. acapture_profile()dict);costis the per-request cost used to ordertier_stack(). An explicitentry_idthat already exists (in the index or as an artifact directory) raises rather than duplicating the index row and silently overwriting the artifact; auto-generated ids scan past taken ones.entry_idmust be a single safe path component (_safe_entry_id()): an unvalidated value such as"../escaped"would otherwise write the artifact outsidedirinstead of inside it.Every field of the index row is validated (by constructing the
RegistryEntry) BEFORE the id is claimed or the artifact written, so a rejected argument leaves the registry byte-for-byte unchanged and the id free to retry – see the comment at that construction (MXR-080-1902).Allocating an id and persisting the index is a read-modify-write over the on-disk index: two
Registryinstances opened on the samedir(or two threads/processes sharing one) each cache their ownself._entriessnapshot from construction time and otherwise never refresh it, so one instance’sregistercan silently overwrite another’s already-persisted index row when it writes back its own stale-plus-one view – even when the two calls pick different, non-colliding entry ids. Fixed by serializing id-allocation-through-index-write with anfcntl.flockon a lock file at the registry root, re-reading the on-disk index fresh under the lock rather than trusting the cached snapshot. An independent claim-file guard (O_CREAT | O_EXCL) additionally protects the artifact write itself, belt-and-suspenders alongside the lock, mirroringmixle.inference.production.registry.Registry.register()’s fix for the same class of bug.
- load(entry_id)[source]
Reload a registered model by
entry_id(round-trips through the artifact on disk).Always resolves through
_get()against the registry’s own validated state – never a record a caller was handed byfind_for()and may have altered.
- find_for(query, *, top_k=None)[source]
Entries matching
query: a capability name (str, containment match) or a task fingerprint vector (array-like of floats, nearest-neighbor match).top_kcaps how many are returned – every capability match by default, or the single nearest fingerprint match by default.Returns defensive copies: the results are a view of the catalog, not handles onto it, so altering one cannot silently rewrite where a later
load()reads from or which entries a later query matches (registration is the only way to change the catalog).An entry whose fingerprint does not share the query’s dimension is skipped individually rather than aborting the whole search: one length-3 record used to make every two-dimensional query raise a broadcasting
ValueError, hiding every healthy entry behind one incompatible one.
- tier_stack(task, *, frontier, costs=None, names=None)[source]
Ascending-cost
(name, model, cost)tiers for capabilitytask,frontierappended last.Matching entries are loaded (
load()) and ordered by their effective cost – thecostsoverride when given, else the registered per-entry cost. The result is exactly the shapeRoutertakes astiers=: each non-final tier exposesdecide(x), the final tier is the callablefrontierfallback.costs(one entry per matching solution in registered-cost order, plus one forfrontier, mirroringfrom_solutions()) overrides the registered per-entry costs when given.
- class RegistryEntry(entry_id, path, kind, capabilities=<factory>, fingerprint=None, profile=<factory>, cost=0.0)[source]
Bases:
objectOne catalog record: where the artifact lives, what it’s registered under, and how much it costs to run.
Frozen, and validated on construction. A durable catalog record is a persisted fact, not a scratch object:
Registry.find_for()used to hand out the very objects stored inRegistry._entries, so rebinding a lookup result’spathsilently redirected the nextRegistry.load()and clearing itscapabilitiesremoved it from later matching – all without any registry mutation API, validation, persistence, or receipt. Lookups now return defensive copies (seecopy()), and a rebinding attempt raises instead of quietly rewriting routing.- Parameters:
- copy()[source]
A defensive copy: mutating its containers cannot reach the registry’s own state.
- Return type:
RegistryEntry
- to_dict()[source]
Serialize the registry entry into JSON-compatible fields.
- classmethod from_dict(d)[source]
Create a registry entry from a JSON index record.
The index is untrusted persisted input, not a trusted in-process value:
entry_id,kind,fingerprintandcostare validated here exactly as they are onRegistry.register()(seeRegistry._read_index(), which additionally re-derivespathfrom the registry root rather than trusting the serialized one).