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

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.

trust: RUNTIME  |  cost: low  |  sound: no
ORACLE

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.

trust: ORACLE  |  cost: medium (token usage)  |  sound: probabilistic
SOLVER

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.

trust: SOLVER  |  cost: medium (CPU time)  |  sound: yes (fragment-bounded)
COMPOSED

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.

trust: meet(T₁, T₂, …)  |  cost: sum of components  |  sound: conditionally
COPILOT

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.

trust: variable (depends on tools used)  |  cost: high  |  sound: tool-dependent
FORMAL_PROOF

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.

trust: FORMAL  |  cost: high (proof search)  |  sound: yes (kernel-verified)

EvidenceBundle and EvidenceItem

The \(E\) field of a judgment is an EvidenceBundle — an ordered collection of EvidenceItem objects. Each item carries:

Evidence join — combining items in a bundle
$$E_1 \sqcup E_2 \;=\; E_1 \cup E_2 \quad (\text{union, deduplicating by channel})$$ $$T(E_1 \sqcup E_2) \;=\; T(E_1) \vee T(E_2) \quad (\text{trust join = best available})$$
python
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
RUNTIMEGround atoms, arithmetic predicates, effect predicates (observable)Universal quantification over infinite domains, liveness
ORACLEAny formula expressible in natural languageGuarantees — oracle may hallucinate
SOLVERQF_LIA, QF_LRA, QF_BV, QF_UF, QF_IDL, and 8 more SMT-LIB fragmentsGeneral HOL, undecidable fragments
COMPOSEDAny formula handled by at least one constituent channelFormulas not in any constituent's jurisdiction
COPILOTAny formula (agentic planning adapts to the goal)Nothing — but trust depends on what tools are used
FORMAL_PROOFAny formula expressible in CIC / Lean 4's type theoryPropositions 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:

  1. Classify the formula — determine which SMT fragment (if any) applies, and whether the formula is purely structural, relational, or requires higher-order reasoning.
  2. Filter by jurisdiction — retain only channels whose jurisdiction covers the formula class.
  3. Apply the routing strategy — the default is Smart routing (see Solver page). Alternatives include Cheapest, Fastest, MostTrusted, and RoundRobin.
  4. Invoke in priority order — channels are called in decreasing priority; the first to return a non-NONE trust level wins, unless the all_channels flag is set.
  5. 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().

python
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)