Skip to main content
The Consensus Engine orchestrates multiple verification engines for high-confidence results with fault tolerance.
Changed in v4.0.4: Python code verification within consensus now runs exclusively through the secure Docker executor (SecureCodeExecutor). If the Docker sandbox is unavailable, consensus returns a blocked_secure_execution status and the API responds with HTTP 503.

Features

  • Async parallel execution — Run engines concurrently
  • Circuit breaker — Auto-disable failing engines
  • Engine health monitoring — Track reliability
  • Weighted consensus — Consider engine reliability
  • Secure code execution — Python engine runs through the Docker sandbox only

Usage

Verification modes

The high and maximum modes include the Python engine, which requires the secure Docker sandbox. If Docker is unavailable, these modes return blocked_secure_execution instead of falling back to in-process execution.
The Python engine in high and maximum modes requires Docker. If the secure Docker sandbox is unavailable, consensus verification returns HTTP 503 instead of falling back to in-process code execution.

Async execution

Circuit breaker

When an engine fails repeatedly, it’s automatically disabled:

Execution deadlines and partial results

Consensus verification runs under a single 30-second aggregate deadline that covers all engines. No engine call can hold a request open indefinitely, and /verify/consensus never hangs or returns HTTP 500 because one engine stalled. How the deadline applies:
  • One aggregate budget, not per-engine stacking. All selected engines share the same 30-second wall clock. Sequential per-engine waits cannot accumulate beyond it.
  • Timed-out engines become explicit BLOCKED results. An engine that misses the deadline is recorded in verification_chain as a BLOCKED EngineResult with the timeout in its error field (for example, "Engine timed out after 30s"). The failure is also recorded with the circuit breaker.
  • Circuit-open engines are recorded too. An engine skipped because its circuit breaker is open appears as a BLOCKED result rather than being silently dropped.
  • Partial results still aggregate. Engines that finished within the deadline contribute normally. The consensus verdict is computed from the results that arrived, with the fail-closed status propagation rules applied — a BLOCKED engine result caps the consensus at UNVERIFIABLE.
  • Off the event loop. Engine execution runs in a dedicated per-call executor, so a slow consensus request degrades only itself, not other API traffic.
A consensus response that includes timed-out engines is a valid partial result, not an error. Check verification_chain to see which engines contributed and treat the aggregate status as authoritative.

Async failure handling

When an unexpected error occurs during async engine aggregation, the Consensus Engine records the failure as a dedicated EngineResult entry rather than silently dropping it. This ensures that:
  • The failure is visible in the results array returned to the caller
  • Aggregate confidence scores account for the failed engine
  • The error is logged via logger.exception for post-mortem debugging
The recorded result uses engine_name: "consensus_orchestrator", method: "async_aggregation", success: false, and includes the error message in the error field.

Secure execution gates

Before any Python code runs in the Docker sandbox, two validation layers apply. Both fail closed: a rejected input returns a security error instead of executing.

Single-expression gate on translated math

When consensus translates a natural-language math query, the translated expression is interpolated into the generated verification code. The translator therefore enforces that the output is exactly one Python expression:
  • The expression must parse with ast.parse(..., mode="eval"). Multi-statement input, semicolon chains, assignments, imports, and multi-line newline smuggling all fail by construction.
  • Expressions longer than 500 characters are rejected before parsing, so deeply nested adversarial input never reaches the parser.
  • The existing character-set and denylist checks remain as defense in depth.
Bracketed multi-line expressions (a single expression wrapped in parentheses across lines) still pass. Anything that is not one expression does not.

Module-indirection blocklist on executed code

The pre-execution AST check on sandboxed Python code inspects every dotted segment, not just the first:
  • Imports of OS, process, and reflection modules (os, sys, subprocess, socket, posix, nt, importlib, ctypes, builtins, and network clients) are blocked wherever the module name appears in the import path, including from ... import os as safe aliasing.
  • Attribute chains are blocked when any segment names a dangerous module, so package-internal re-exports (reaching the OS module through pandas or numpy internals) are caught even though the chain is rooted at an innocuous alias.
  • OS-primitive calls (system, popen, import_module, the exec*/spawn* families, fork) are blocked as bare names and as attribute targets, which also stops importlib.import_module("os")-style indirection.
Legitimate pandas and numpy verification code at the public API surface (np.linalg.norm, pd.Timestamp.now) is unaffected.

Engine selection

The consensus engine automatically selects which engines to run based on the verification mode:
The fact engine is excluded from automatic engine selection. Fact verification requires external context, and including it in consensus without that context would create self-referential verification loops. If fact verification is invoked during consensus, it returns an error indicating that external context is required.

Consensus calculation

The engine uses weighted voting: Final confidence = weighted average of agreeing engines.

Agreement statuses

Status propagation

Consensus is a status-preserving aggregator, not a proof engine. Per the 3-tier engine classification, consensus never invents a VERIFIED status from disagreement:
  • All engines return BLOCKED → the consensus result is BLOCKED.
  • Any single engine returns BLOCKED (but not all) → the consensus result is capped at UNVERIFIABLE (fail-closed — a partial block prevents VERIFIED).
  • Any engine returns UNVERIFIABLE → the consensus result is UNVERIFIABLE.
  • Only unanimous VERIFIED engine outcomes can produce a VERIFIED consensus.
  • Math-query translation failures fail closed — the engine raises rather than fabricating a numeric answer from a regex or decimal guess.
Individual engine outcomes are exposed via the status field on each EngineResult in the aggregated result.

Sub-engine status contract

Not every sub-engine that runs under consensus can emit VERIFIED. The table below makes the fail-closed contract explicit — these engines never contribute a VERIFIED vote, even on a successful computation, so their output stays advisory: This mirrors the existing Fact engine heuristic contract: a TF-IDF SUPPORTED verdict is capped at UNVERIFIABLE because heuristic support is not a proof. Because a VERIFIED consensus requires every contributing engine to have emitted VERIFIED, a query answered only by Stats or code execution can never reach VERIFIED — it stops at UNVERIFIABLE with the computed value carried through as advisory data.

ConsensusResult

Async and sync consensus verification both return a ConsensusResult dataclass that carries the aggregated verdict along with per-engine detail:
status is now a DiagnosticStatus enum rather than a bare string. Code that compared result.status == "VERIFIED" should use result.status is DiagnosticStatus.VERIFIED or check result.status.value for the string form.

.to_diagnostic_result()

ConsensusResult converts cleanly to a DiagnosticResult using the stored verified_evidence, so downstream attestation hashes bind to the exact evidence used to reach agreement:
The conversion is fail-closed: a VERIFIED ConsensusResult that is missing verified_evidence is downgraded to UNVERIFIABLE rather than emitting a weaker proof. This is why the /verify/consensus endpoint’s meets_requirement flag is true only when consensus is VERIFIED at the trust boundary and confidence meets the requested threshold — confidence alone is never sufficient.