neural/trident/reference/formal-audit.md

Formal audit contract

trident audit checks universal assertion and postcondition obligations under entry preconditions, independently for each function. It does not prove program execution or that an arbitrary witness exists. #[requires(expr)] constrains entry inputs; #[ensures(expr)] is checked independently on each terminating path with result bound to that returned scalar. U32/Bool parameter ranges are entry assumptions.

The supported formal subset is scalar Field/U32/Bool arithmetic, scalar bindings/assignments, nested if/else, early or terminal return, and explicitly modeled scalar builtins. Each branch has its own lexical environment and path predicate; only fallthrough paths execute subsequent statements. Postconditions are checked under the corresponding terminating path, including implicit tails and terminal if/else branch values. Internal path predicates use logical 0/1. Source Bool values follow the selected ABI: nox uses 0=true, Triton uses 1=true. Raw Field conditions branch on zero for nox and nonzero for Triton; assertions/contracts require exactly the selected true word (Triton Field 2 branches but does not satisfy assert). Only these two Goldilocks Boolean ABIs are currently modeled. Scalar Field literals are canonicalized modulo the prime, matching both native owners. Assertions remain obligations, never assumptions that could erase their own counterexamples.

Analysis enumerates at most 256 simultaneous paths and 4096 path/statement steps; exceeding either limit returns UNKNOWN. Constant unreachable branches are not executed; symbolic unreachable paths are excluded by their guarded obligations. Same-module ordinary scalar helpers may be inlined from their checked bodies. Calls evaluate all arguments in the caller environment before binding callee parameters. Every callee requires predicate and narrow parameter range is a caller-path obligation; every callee assertion and ensures predicate is checked on its actual selected execution path. Ensures are never assumed as summaries. The caller environment is restored after a call. Only acyclic helpers without I/O, nondeterminism, state, assembly or opaque operations are covered. Calls in contracts, generic/foreign/ambiguous definitions and recursion remain UNKNOWN. Inlining shares the4096 statement budget, permits at most64 nested calls and 256 total helper calls, and retains the256-path bound per execution frame. A shared65,536-node expression/constraint expansion budget also prevents acyclic helper duplication from growing without bound; exhaustion is UNKNOWN. Aggregates, loops, match, opaque operations and assembly remain UNKNOWN. Unsupported paths and absent obligations are never SAFE.

Static tautologies can be discharged without a solver. Random testing and bounded sampling can find counterexamples but cannot certify universal safety. With --z3, only UNSAT of a supported nonempty obligation query discharges it; SAT fails, and UNKNOWN, solver errors or a missing solver are inconclusive failures. Exit 0 means every analyzed function's obligations were discharged; exit 1 means counterexample or compilation error; exit 2 means incomplete/unsupported analysis. SMT exports reset solver state between functions to avoid shared variable IDs.

Z3 is an optional external dependency, discovered directly through native PATH entries (z3.exe on Windows). Discovery does not require a shell or which. Solver input travels through a private stdin pipe; each query retains the 10-second solver timeout and treats malformed/error replies as failures.

Graph