Unified inference audit
gestaltdb.inference.explain_inference joins explicitly tagged model-output
claims with the existing historical logical explanation graph. This read-only
adapter returns a detached InferenceExplanation with deterministic
to_json(), copy-returning to_dict() and script-free as_html().
It does not run a model, request network resources, or change rule semantics.
Model outputs are assertions, not proofs
Tag model outputs with provenance['model_output'] containing explicit
model_id and model_version strings. Optional training-data identifiers,
feature snapshot identifiers or calibration notes can be stored alongside
them. These fields are caller assertions, not authenticated model lineage.
No association is guessed from confidence, agent names, or predicates.
Confidence remains a score on an assertion. A deterministic rule consuming a prediction proves only what follows assuming that assertion. It does not prove the prediction correct, propagate probabilities, or explain the model’s internal decisions. This export is an audit record, not independent proof verification or a regulatory-compliance certificate.
Runnable model-to-proof example
This example requires the lmdb extra and closes the database explicitly.
The prediction could come from a GNN; the example deliberately uses a fixed
score rather than requiring a training framework.
from pathlib import Path
from tempfile import TemporaryDirectory
from gestaltdb.graphdb import GraphDB
from gestaltdb.inference import explain_inference
with TemporaryDirectory() as directory:
graph = GraphDB.create(Path(directory) / "db", backend="lmdb", serializer="json")
try:
prediction = graph.assert_claim(
subject="supplier-1", predicate="PREDICTED_RISK", object="high",
polarity="positive", agent="gnn-risk", confidence=0.8, valid=(0, 100),
provenance={"model_output": {
"model_id": "supplier-risk-gnn", "model_version": "weights-7"}},
)
graph.create_rule(
"review-predictions", when=[("?s", "PREDICTED_RISK", "high")],
then=("?s", "REQUIRES_REVIEW", "yes"),
)
graph.run_rules(as_of=10)
conclusion = next(graph.iter_claims_as_of(
valid_time=10, subject="supplier-1", predicate="REQUIRES_REVIEW"))
report = explain_inference(graph, conclusion.logical_id, valid_time=10)
assert any(node["kind"] == "model_output" for node in report.to_dict()["nodes"])
Path(directory, "audit.json").write_text(report.to_json(), encoding="utf-8")
Path(directory, "audit.html").write_text(report.as_html(), encoding="utf-8")
finally:
graph.close()
Identity, alternatives and bounds
Format-v1 exports carry the root logical claim/version IDs, requested valid
time, resolved system time, exact claim/rule versions, validity, commit ID and
ordinal, payload hashes, scores and provenance. Alternative justifications
retain their ordered premise-version groups per conclusion. They are not
collapsed through shared rule nodes; recursive evidence may be a finite graph,
not a tree. Rules using closed-world negation also export absence nodes and
per-support absences lists. These record absence checks at the evaluation
horizon; they are not claim versions, negative facts or independent proof that
the closed-world declaration was justified. Evidence is untrusted data and can contain sensitive metadata;
review it before sharing. JSON serialization does not authenticate the report.
max_depth and max_nodes use the existing explain_claim traversal
bounds. Missing/depth-limited evidence sets truncated=true; incomplete
justifications are omitted, never presented as proofs. Additional max_edges
and max_bytes bound the exported justification links and serialized JSON;
overflow raises RuleEvaluationLimitError without an artifact. These are
export bounds, not a guarantee of bounded backend reads or serializer memory.
HTML escaping prevents metadata from becoming executable markup.
Absent or retracted roots return None. Pass system_time to inspect an
older visible root. Exact premise versions remain historical even if corrected
later. export_inference also accepts an existing ClaimExplanation;
it does not authenticate manually constructed values.