Evidence Channels
Evidence channels are the sources of justification that JuGeo consults when
building a judgment. Each channel has a defined jurisdiction, trust level,
resource profile, and federation protocol. Multiple channels can be combined
into a single EvidenceBundle.
The Six Evidence Channels
JuGeo defines six evidence channels. Each channel is a first-class object
implementing the EvidenceChannel protocol. They are ordered by
trust level, from weakest to strongest:
Runtime Testing
Generates test inputs (via property-based testing or symbolic execution) and observes that the property holds on all sampled inputs. Unsound for universally quantified properties but fast and broadly applicable. Useful as a first filter before invoking heavier channels.
LLM Oracle
Dispatches the formula and relevant code context to a language model and asks it to assess whether the property holds. The oracle produces a probabilistic confidence score. JuGeo uses structured prompting to extract a yes/no/unknown answer and a brief justification string.
SMT Solver
Encodes the formula into an SMT-LIB fragment and calls Z3 (or another registered solver). If Z3 returns UNSAT for the negation, the property is proved sound within the fragment's theory. Supports 13 SMT-LIB fragments; see the Solver page for details. Returns a proof certificate on success.
Composed Evidence
Combines evidence from two or more other channels. The composed trust is the meet (minimum) of the component trusts. Composed evidence is stronger than any single weak channel alone when multiple independent channels agree. Disagreement is flagged as an evidence conflict.
Copilot Agent
An agentic evidence channel that can invoke multiple tools iteratively to gather evidence. A Copilot agent receives the judgment goal, a budget, and a tool palette (static analyser, solver, REPL, web search), and plans a multi-step evidence-gathering strategy. Returns an EvidenceBundle produced by its tool calls.
Formal Proof
A Lean 4 or Coq proof term is type-checked by the respective kernel. This is the only unconditionally sound channel. JuGeo can either accept an existing proof term or invoke an LLM-assisted proof synthesis pipeline to attempt automated proof search. Successful proofs are stored and replayed on demand.
EvidenceBundle and EvidenceItem
The \(E\) field of a judgment is an EvidenceBundle — an ordered
collection of EvidenceItem objects. Each item carries:
channel— theChannelKindenum valuecontent— the raw evidence artifact (certificate bytes, test log, proof term, LLM transcript, …)trust— the trust level granted by this itemtimestamp— UTC time of evidence collectioncost_record— resource usage (solver ms, token count, …)metadata— channel-specific auxiliary data (e.g., solver model, oracle confidence score)
from jugeo.evidence import EvidenceBundle, EvidenceItem, ChannelKind
# Inspect an evidence bundle
result = jugeo.verify(sum_positive, property="pure")
bundle = result.judgment.evidence
print(bundle.trust) # TrustLevel.SOLVER
print(len(bundle.items)) # 1
item = bundle.items[0]
print(item.channel) # ChannelKind.SOLVER
print(item.trust) # TrustLevel.SOLVER
print(item.cost_record) # CostRecord(solver_ms=143, tokens=0)
print(item.metadata['model']) # 'z3-4.12.2'
# Combine two bundles (e.g. solver + oracle)
j_solver = jugeo.verify(sum_positive, property="pure",
channels=["SOLVER"])
j_oracle = jugeo.verify(sum_positive, property="pure",
channels=["ORACLE"])
combined_bundle = j_solver.evidence | j_oracle.evidence
print(combined_bundle.trust) # max of SOLVER, ORACLE = SOLVER
print(len(combined_bundle.items)) # 2
Channel Jurisdiction
Each channel has a jurisdiction — the set of formula kinds it can
handle. Dispatching a formula to a channel outside its jurisdiction either
raises a JurisdictionError or falls back to the next channel
in the routing order.
| Channel | Jurisdiction (formula kinds) | Cannot handle |
|---|---|---|
| RUNTIME | Ground atoms, arithmetic predicates, effect predicates (observable) | Universal quantification over infinite domains, liveness |
| ORACLE | Any formula expressible in natural language | Guarantees — oracle may hallucinate |
| SOLVER | QF_LIA, QF_LRA, QF_BV, QF_UF, QF_IDL, and 8 more SMT-LIB fragments | General HOL, undecidable fragments |
| COMPOSED | Any formula handled by at least one constituent channel | Formulas not in any constituent's jurisdiction |
| COPILOT | Any formula (agentic planning adapts to the goal) | Nothing — but trust depends on what tools are used |
| FORMAL_PROOF | Any formula expressible in CIC / Lean 4's type theory | Propositions requiring external axioms not in the kernel |
Routing
When jugeo.verify() is called without an explicit channel list,
the evidence router selects the appropriate channels automatically.
The routing algorithm:
- Classify the formula — determine which SMT fragment (if any) applies, and whether the formula is purely structural, relational, or requires higher-order reasoning.
- Filter by jurisdiction — retain only channels whose jurisdiction covers the formula class.
- Apply the routing strategy — the default is Smart routing (see Solver page). Alternatives include Cheapest, Fastest, MostTrusted, and RoundRobin.
- Invoke in priority order — channels are called in decreasing priority; the first to return a non-NONE trust level wins, unless the
all_channelsflag is set. - Assemble the bundle — all successful channel results are joined into the final
EvidenceBundle.
Federation
JuGeo supports federated evidence: evidence gathered by remote agents or on remote data can be incorporated into a local judgment via the federation protocol. A federated evidence item carries a cryptographic signature from the remote agent and is verified before being accepted.
Trust downgrade on federation. Evidence federated from an
untrusted remote agent is automatically downgraded by one trust level. Evidence
from a trusted (pre-registered) remote is accepted at face value. Trust
registration is managed via jugeo.registry.register_remote().
from jugeo.evidence.channels import (
ChannelFederation,
ChannelRouter,
EvidenceChannel,
EvidenceRequest,
EvidenceResponse,
)
request = EvidenceRequest(
coordinate="mymod.sum_positive",
proposition="function is pure",
required_kind="proposal",
fallback_channels=(EvidenceChannel.COPILOT, EvidenceChannel.HUMAN),
)
responses = [
EvidenceResponse(
request_id=request.request_id,
channel=EvidenceChannel.COPILOT,
evidence_item={"hint": "strengthen the precondition"},
trust_level="proposal",
provenance=("copilot",),
),
EvidenceResponse(
request_id=request.request_id,
channel=EvidenceChannel.HUMAN,
evidence_item={"review": "approved after audit"},
trust_level="human_attested",
provenance=("review",),
),
]
federation = ChannelFederation(ChannelRouter())
merged = federation.federate_request(request, responses)
print(merged.channel.value) # composed
print(merged.trust_level) # proposal (conservative meet)