On this page
DiffEngine๏
Use md.DiffEngine from the public package namespace.
- class DiffEngine(material_resolver: Callable[[str], Dict[str, object]], *, register_defaults: bool = True)[source]๏
Strategy-dispatched derived-diff computation over custody material.
- Purpose:
Answer "what changed between these two versions" as a READ over the record: the engine resolves each version's material through an injected resolver (the MutationResearch root supplies one backed by crystallizer custody; tests supply fakes) and dispatches the comparison to a registered strategy. Nothing is stored - full-object records stay the only storage; diffs are always derived.
Contract:
material_resolver(spell_id) returns the detached material payload {"spell_id", "sources", "fingerprints"}; resolver errors propagate untouched (unknown identities stay loud).
SourceDiffStrategy (whole-module text), StructuralDiffStrategy (AST shape reports), and PartDiffStrategy (per-class/function code diffs - the agent's grain choice, owner ruling 2026-07-11) register by default; further strategies extend the family via register_strategy() (open/closed - the engine never changes to gain one).
Duplicate strategy names are refused; resolution failures name the known strategies.
Verdicts are detached payloads stamped with both identities and the strategy name.
- Threading:
Instance RLock serializes registry mutation; dispatch reads under the same lock discipline.
- Lifecycle:
Owned by its creator (the MutationResearch root or a test); cleanup() cascades into registered strategies; idempotent; lock released last.
- Registration:
MELDER KERNEL - guarded. The engine is constructed by the research root; the extension point for callers is register_strategy(), not binding an engine.
- THE RESOLVER IS INJECTED, AND THAT IS WHY THIS IS TESTABLE:
The engine never reaches into the crystallizer itself. It receives a material_resolver(spell_id) callable - the research root supplies one backed by custody, tests supply fakes - so the diff family can be exercised with synthetic material and no recorded world at all. It also means resolver errors propagate UNTOUCHED: an unknown identity stays loud rather than being softened into an empty diff.
- Subsystem Context:
The dispatcher of the spell-grain diff family in mutation_research/diff/, holding the registry that DiffStrategy implementations join. GroupDiffEngine in group_diff/ is its deliberate mirror for composition material.
- System Context:
Diffs are DERIVED, never stored: version records are full objects, and "what changed" is computed on demand. That is why the engine is open/closed - adding a grain means registering a strategy, never editing this class - and why nothing it produces is written back into the record. A verdict is an answer, not a fact the system remembers.
AGENT_ACCESS: public
- AGENT_PURPOSE:
access: public. Computes derived diffs over RECORDED custody material - never the live disk. Choose grain by strategy: source, structural, or parts. Obtain via MutationResearch.create_diff_engine().
- cleanup() None[source]๏
Cascade cleanup into registered strategies and mark cleaned.
Contract:
Idempotent; del posture (no tombstones); lock last.
- Returns:
None.
- register_strategy(strategy: DiffStrategy) None[source]๏
Register one additional diff strategy by its stable name.
- Parameters:
strategy -- Strategy instance to own.
- Raises:
TypeError -- If the object is not a DiffStrategy.
ValueError -- If the name is already registered.
- Returns:
None.
- list_strategy_names() List[str][source]๏
Return every registered strategy name, sorted.
Contract:
SORTED, so iteration order is deterministic across calls and processes.
Lists REGISTERED strategy names; a name absent here cannot be selected for a diff.
- Threading:
Reads under self._lock, so the result is a coherent snapshot.
- Lifecycle / Cleanup:
Guarded by check_cleaned().
- Raises:
RuntimeError -- If the object has been cleaned.
- Returns:
Sorted registry keys.
- Return type:
List[str]
- diff_materials(left_material: Dict[str, object], right_material: Dict[str, object], *, strategy: str = 'source') Dict[str, object][source]๏
Compute one derived diff between two pre-resolved materials.
- Purpose:
The candidate-preview entry: when one side is not (yet) a recorded identity - e.g. unbound codegen output - the caller supplies both material payloads directly and the engine only dispatches the strategy. Recorded-identity diffs should keep using diff(), which resolves through custody.
- Parameters:
left_material -- Detached material payload ({"spell_id", "sources", "fingerprints"}).
right_material -- Detached material payload of the same shape.
strategy -- Registered strategy name; "source" by default.
- Returns:
Detached verdict: left_spell_id, right_spell_id (as carried by the materials), strategy, and the strategy's result payload.
- Return type:
Dict[str, object]
- Raises:
ValueError -- If either material is not a dict.
KeyError -- If the strategy name is unknown (the error names the known strategies).
- diff(left_spell_id: str, right_spell_id: str, *, strategy: str = 'source') Dict[str, object][source]๏
Compute one derived diff between two version identities.
- Parameters:
left_spell_id -- Left version identity (binding-signature SHA256).
right_spell_id -- Right version identity.
strategy -- Registered strategy name; "source" by default.
- Returns:
Detached verdict: left_spell_id, right_spell_id, strategy, and the strategy's result payload.
- Return type:
Dict[str, object]
- Raises:
ValueError -- If either identity is empty.
KeyError -- If the strategy name is unknown (the error names the known strategies); resolver lookup failures propagate as raised.