Adapter Hooks (Legal / Medical)¶
Goal: keep domain logic thin and explicit. Adapters may enrich signals, but the Basis5 geometry remains the source of phase dynamics.
Locations¶
src/engine/adapters/
base.py # shared types/helpers (already present)
legal.py # thin legal shim
medical.py # thin medical shim
Interfaces¶
Each adapter can expose some/all of the following optional callables. The pipeline probes them with raising=False
and proceeds if missing.
# legal.py
def cf_analyze(expr: str) -> dict | None:
"""Optional. Counterfactual analysis (used as an enrichment field)."""
# medical.py
def dm_classify(expr: str) -> str | None:
"""Optional. Divergence/clinical risk classification: e.g. 'low' | 'hi-risk'. """
def ner_extract(expr: str) -> list[dict] | None:
"""Optional. Simple NER results: [{"text": "1"}, ...]."""
Example stubs (safe defaults)¶
# src/engine/adapters/legal.py
def cf_analyze(expr: str):
if "->" in expr or "IMPLIES" in expr:
return {"counterfactual": True}
return None
# src/engine/adapters/medical.py
def dm_classify(expr: str):
return "low"
def ner_extract(expr: str):
return []
How the pipeline uses them¶
- After prenorm and before detect, the pipeline builds
enrichment
and includes any adapter outputs under stable keys: - Legal: enrichment['counterfactual'] = {...} when present
- Medical: enrichment['risk'] = 'low'|'hi-risk', enrichment['ner'] = [...]
- Additionally, enrichment carries basis5_witness projected from the normalized expression.
Resulting provenance detect event (excerpt):
{
"kind": "detect",
"phase_after": "JAM",
"details": {
"enrichment": {
"domain": "legal",
"pattern": "1 -> 0",
"tags": ["implication","boolean"],
"basis5_witness": {"jam":1,"detach":1,"mp":1},
"counterfactual": {"flag": "cf-ok"}
}
}
}
Adapters remain non-authoritative: they annotate, they do not steer phases.