ADR-0024: R0-B Evidence-Gated Static Evaluation

Status: accepted
Date: 2026-07-26

Context

R0-A admits canonical static values and dynamic holes under a verified B0 certificate. R0-B must begin executing static work without reusing bridge runtime values, speculatively running denied operations, or coupling evaluation correctness to the future Residual Core generator.

B0 evidence records two independent properties for every canonical node:

binding time: Static | Dynamic
static-evaluation eligibility: EligiblePure | Denied

Static alone is not permission to execute. Checked arithmetic and array indexing can be static while still producing an observable typed error, so B0 marks them Denied.

Options considered

OptionBenefitCost
Reuse the canonical bridge interpreter and CoreValueBroad semantics already existExecutes through host-oriented values and an API that permits effects
Fold constants directly while emitting Residual CoreFewer intermediate APIsCouples evaluation, code generation, and proof failures
Execute any node classified StaticMaximizes early foldingConfuses dependency with permission and can trigger typed effects
Dedicated evaluator gated by both B0 dimensionsSmall independent trust boundary with explicit refusalInitially supports less than the full P1V0 language

Decision

Implement a dedicated evaluator over SpecializationValue. It may be entered only with ValidatedSpecializationRequest, which retains the exact verified source artifact and B0 certificate.

Every term, rvalue, and operand is checked against the exact B0 node identity before execution:

Static + EligiblePure → consume one step, then execute
Dynamic              → ResidualRequired(DynamicDependency)
Static + Denied       → ResidualRequired(DeniedByCertificate)
missing/wrong evidence → fail closed

R0-B is split into bounded packages:

PackageBoundary
R0-B1Intraprocedural all-or-frontier evaluation, exact executed-node trace, no calls
R0-B2Interprocedural calls, tail calls, recursion, and mixed static-fact frontiers

R0-B1 supports verified P1V0 let, static if, static case, return, use, tuple, projection, sum construction, wrapping/saturating integer arithmetic, floating addition/subtraction, integer comparisons, and ArrayLenF64.

Direct calls and tail calls return ResidualRequired(InterproceduralDeferred). Checked integer arithmetic and ArrayGetF64 never execute in R0-B1 because their typed errors are observable. References, closures, handlers, operations, allocation, and mutation remain outside P1V0 and fail closed if reached.

The step budget counts each authorized canonical term, rvalue, and operand immediately before execution. Exhaustion returns a typed error and no StaticEvaluation artifact. Successful and residual outcomes include the request hash, exact step usage, and deterministic ordered executed-node trace.

Rationale

  • A separate evaluator keeps specialization semantics free of Arc, logical references, handlers, and bridge runtime representation.
  • Checking evidence at every node prevents a root-level permission check from becoming ambient authority.
  • All-or-frontier behavior establishes effect safety and deterministic budget semantics before mixed residualization adds control complexity.
  • Deferring calls avoids host-stack recursion and forces R0-B2 to define an explicit continuation machine.

Trade-offs

  • R0-B1 residualizes programs whose safe selected path could theoretically be evaluated when B0 conservatively denies the whole root.
  • Unused dynamic entry parameters are allowed only when the executed nodes remain independently certified static.
  • Direct and tail calls are deferred even when B0 certifies them pure.
  • Node lookup and trace storage add bridge-time overhead.

These costs are accepted because R0-B1 is a semantic/evidence gate, not the performance implementation or final partial evaluator.

Consequences

Positive: R0-B2 and R0-C gain a small, deterministic, effect-free execution kernel whose refusals are explicit and testable.

Negative: completing R0-B1 does not complete R0-B and produces no Residual Core.

Mitigation: R0-B2 must use an explicit continuation machine, preserve the same per-node authority checks, and retain fail-closed exhaustion.

Revisit trigger

Any capability to execute a Denied node, produce a typed effect at specialization time, admit another Core profile, or change step accounting requires a superseding ADR and policy version.