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
BLOCKEDresults. An engine that misses the deadline is recorded inverification_chainas aBLOCKEDEngineResultwith the timeout in itserrorfield (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
BLOCKEDresult 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
BLOCKEDengine result caps the consensus atUNVERIFIABLE. - 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 dedicatedEngineResult entry rather than silently dropping it. This ensures that:
- The failure is visible in the
resultsarray returned to the caller - Aggregate confidence scores account for the failed engine
- The error is logged via
logger.exceptionfor post-mortem debugging
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.
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, includingfrom ... import os as safealiasing. - 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, theexec*/spawn*families,fork) are blocked as bare names and as attribute targets, which also stopsimportlib.import_module("os")-style indirection.
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 aVERIFIED status from disagreement:
- All engines return
BLOCKED→ the consensus result isBLOCKED. - Any single engine returns
BLOCKED(but not all) → the consensus result is capped atUNVERIFIABLE(fail-closed — a partial block preventsVERIFIED). - Any engine returns
UNVERIFIABLE→ the consensus result isUNVERIFIABLE. - Only unanimous
VERIFIEDengine outcomes can produce aVERIFIEDconsensus. - Math-query translation failures fail closed — the engine raises rather than fabricating a numeric answer from a regex or decimal guess.
status field on each EngineResult in the aggregated result.
Sub-engine status contract
Not every sub-engine that runs under consensus can emitVERIFIED. 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 aConsensusResult 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:
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.