mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-25 00:16:23 +02:00
Add 96 tests covering the orchestrator's aggregation, provenance, routing, and explainability parsing. These verify the supervisor fan-out/fan-in lifecycle, the new RDF provenance types (Decomposition, Finding, Plan, StepResult, Synthesis), and their round-trip through the wire format. Unit tests (84): - Aggregator: register, record completion, peek, build synthesis, cleanup - Provenance triple builders: types, provenance links, goals/steps, labels - Explainability parsing: from_triples dispatch, field extraction for all new entity types, precedence over existing types - PatternBase: is_subagent detection, emit_subagent_completion message shape - Completion dispatch: detection logic, full aggregator integration flow, synthesis request not re-intercepted as completion - MetaRouter: task type identification, pattern selection, valid_patterns constraints, fallback on LLM error or unknown response Contract tests (12): - Orchestration fields on AgentRequest round-trip correctly - subagent-completion and synthesise step types in request history - Plan steps with status and dependencies - Provenance triple builder → wire format → from_triples round-trip for all five new entity types
129 lines
3.4 KiB
Python
129 lines
3.4 KiB
Python
"""
|
|
Contract tests for provenance triple wire format — verifies that triples
|
|
built by the provenance library can be parsed by the explainability API
|
|
through the wire format conversion.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from trustgraph.schema import IRI, LITERAL
|
|
|
|
from trustgraph.provenance import (
|
|
agent_decomposition_triples,
|
|
agent_finding_triples,
|
|
agent_plan_triples,
|
|
agent_step_result_triples,
|
|
agent_synthesis_triples,
|
|
)
|
|
|
|
from trustgraph.api.explainability import (
|
|
ExplainEntity,
|
|
Decomposition,
|
|
Finding,
|
|
Plan,
|
|
StepResult,
|
|
Synthesis,
|
|
wire_triples_to_tuples,
|
|
)
|
|
|
|
|
|
def _triples_to_wire(triples):
|
|
"""Convert provenance Triple objects to the wire format dicts
|
|
that the gateway/socket client would produce."""
|
|
wire = []
|
|
for t in triples:
|
|
entry = {
|
|
"s": _term_to_wire(t.s),
|
|
"p": _term_to_wire(t.p),
|
|
"o": _term_to_wire(t.o),
|
|
}
|
|
wire.append(entry)
|
|
return wire
|
|
|
|
|
|
def _term_to_wire(term):
|
|
"""Convert a Term to wire format dict."""
|
|
if term.type == IRI:
|
|
return {"t": "i", "i": term.iri}
|
|
elif term.type == LITERAL:
|
|
return {"t": "l", "v": term.value}
|
|
return {"t": "l", "v": str(term)}
|
|
|
|
|
|
def _roundtrip(triples, uri):
|
|
"""Convert triples through wire format and parse via from_triples."""
|
|
wire = _triples_to_wire(triples)
|
|
tuples = wire_triples_to_tuples(wire)
|
|
return ExplainEntity.from_triples(uri, tuples)
|
|
|
|
|
|
@pytest.mark.contract
|
|
class TestDecompositionWireFormat:
|
|
|
|
def test_roundtrip(self):
|
|
triples = agent_decomposition_triples(
|
|
"urn:decompose", "urn:session",
|
|
["What is X?", "What is Y?"],
|
|
)
|
|
entity = _roundtrip(triples, "urn:decompose")
|
|
|
|
assert isinstance(entity, Decomposition)
|
|
assert set(entity.goals) == {"What is X?", "What is Y?"}
|
|
|
|
|
|
@pytest.mark.contract
|
|
class TestFindingWireFormat:
|
|
|
|
def test_roundtrip(self):
|
|
triples = agent_finding_triples(
|
|
"urn:finding", "urn:decompose", "What is X?",
|
|
document_id="urn:doc/finding",
|
|
)
|
|
entity = _roundtrip(triples, "urn:finding")
|
|
|
|
assert isinstance(entity, Finding)
|
|
assert entity.goal == "What is X?"
|
|
assert entity.document == "urn:doc/finding"
|
|
|
|
|
|
@pytest.mark.contract
|
|
class TestPlanWireFormat:
|
|
|
|
def test_roundtrip(self):
|
|
triples = agent_plan_triples(
|
|
"urn:plan", "urn:session",
|
|
["Step 1", "Step 2", "Step 3"],
|
|
)
|
|
entity = _roundtrip(triples, "urn:plan")
|
|
|
|
assert isinstance(entity, Plan)
|
|
assert set(entity.steps) == {"Step 1", "Step 2", "Step 3"}
|
|
|
|
|
|
@pytest.mark.contract
|
|
class TestStepResultWireFormat:
|
|
|
|
def test_roundtrip(self):
|
|
triples = agent_step_result_triples(
|
|
"urn:step", "urn:plan", "Define X",
|
|
document_id="urn:doc/step",
|
|
)
|
|
entity = _roundtrip(triples, "urn:step")
|
|
|
|
assert isinstance(entity, StepResult)
|
|
assert entity.step == "Define X"
|
|
assert entity.document == "urn:doc/step"
|
|
|
|
|
|
@pytest.mark.contract
|
|
class TestSynthesisWireFormat:
|
|
|
|
def test_roundtrip(self):
|
|
triples = agent_synthesis_triples(
|
|
"urn:synthesis", "urn:previous",
|
|
document_id="urn:doc/synthesis",
|
|
)
|
|
entity = _roundtrip(triples, "urn:synthesis")
|
|
|
|
assert isinstance(entity, Synthesis)
|
|
assert entity.document == "urn:doc/synthesis"
|