Surface → Core-N0 T2 Contract
Status: T2A implemented and validated
Architecture decision:
ADR-0011
Core profile: P1V0
1. Claim
For a T2A-admitted Surface kernel K, typed input manifest M, exact dynamic
input vector x, and sufficient Core evaluation budget:
normalize(eval_Surface(K, bind(M, x)).result)
=
normalize(eval_Core(verify(elaborate_T2A(K, M)), x).result)
The relation covers successful returned scalar values. Elaboration rejection, input binding rejection, and Core evaluation-budget exhaustion are distinct typed failure domains and are not equated with bridge-interpreter errors. Runtime log events created by the bridge’s assignment implementation are not Core effects and are outside this pure-kernel relation.
2. Request
An elaboration request contains:
statements
ordered inputs: [(name, Bool | I64 | F64)...]
result variable name
max_source_steps
max_core_nodes
Input names must be non-empty and unique. The result must exist on every syntactic path, including a branch whose condition is a literal, and have one scalar type.
Binding requires exactly the manifest arity, order, and scalar tag. I64 is
never coerced to F64, nor vice versa.
3. Admitted Surface
Statements:
name = expression
if bool_expression
statements
else
statements
end
Expressions:
Bool literal
numeric literal
input or local variable
F64 expression + F64 expression
F64 expression - F64 expression
Assignments create new immutable Core locals. Reassignment is admitted only when the scalar type is unchanged on that path.
The parser represents a negative source literal as a unary expression, so it
is rejected in T2A even though a negative Number(f64) constructed directly
in the AST can be classified by the numeric boundary rule.
4. Explicit exclusions
T2A rejects:
Rite,Unsafe, function definitions, calls, and closures;- expression statements, loops,
Each,While, andReturn; - actions, imports, IO, FFI, and unsafe memory;
- text, bytes, lists, maps, fields, and indexing;
- integer or mixed numeric arithmetic;
- multiplication, division, modulo, bitwise operations, and shifts;
- equality, relational comparison, boolean operators, and unary operators;
- annotations that T2A does not understand;
- unbound names, type-changing reassignment, or path-dependent result types.
Rejection is a typed elaboration error with a structural path and a source span
when the Surface AST provides one. It never invokes the AST interpreter, VM,
trace JIT, or an Any fallback.
5. Scalar observation
Differential evidence compares this normalized domain:
Bool → exact boolean
I64 → exact signed 64-bit value
F64 → exact IEEE-754 bits
all NaNs → 0x7ff8000000000000
Non-NaN F64 bits are preserved, including the sign of zero. T2A currently
compares bridge and Core execution in the same process and host floating-point
environment. It does not yet claim cross-target reproducibility under altered
rounding modes, FTZ, or DAZ behavior.
6. Canonical form and determinism
- Input order fixes parameter IDs.
- Source traversal is left-to-right.
- Output contains exactly one pure
P1V0function with ID 0 and no region parameters. - Parameters receive locals
0..Nin manifest order; all later local IDs increase monotonically across the whole artifact. - Every Surface assignment becomes a
letwithRValue::Use; every nestedF64operation becomes its own preceding ANFlet. - There is no constant folding in T2A.
- The
thenbranch is fully elaborated before theelsebranch, using one global local-ID allocator and separate cloned environments. - The remaining continuation is duplicated into both branches.
- Core sealing uses Semantic Encoding v1.
- Sufficient budget values do not affect the emitted Core or semantic hash.
Surface variable spelling is not encoded after alpha-renaming into Core local IDs.
The locked vector for $result = $x + $y with ordered F64 inputs x, y is:
source_steps = 4
core_nodes = 3
semantic_hash = 52ee627ea5c1685d00d88b6bcbc0947a4c44ff539ad6685349135f67b4d0b468
7. Budgets and safety caps
max_source_steps bounds visited statement/expression nodes, including visits
caused by continuation duplication.
max_core_nodes bounds emitted let, if, and return terms.
T2A also enforces non-configurable safety caps:
inputs ≤ 256
source_steps ≤ 256
core_nodes ≤ 256
Zero or exhausted source and Core budgets have distinct error codes and fail before an artifact is returned. A request above a cap is rejected before lowering, and a partial artifact is never sealed or evaluated.
8. Admission path
Surface AST + typed manifest
→ T2A validation
→ deterministic ANF elaboration
→ Core artifact sealing
→ independent Core verifier
→ VerifiedArtifact
→ canonical Core interpreter
The elaborator cannot construct a successful report unless the independent Core verifier accepts the sealed artifact.
9. Evidence
T2A requires:
- positive scalar/assignment/branch cases;
- both dynamic branch directions;
- validation of unsupported constructs in both syntactic branches, even when one condition is statically known;
- repeated elaboration and fixed-vector hash stability;
- numeric edge values admitted by the profile;
- exact input arity/tag rejection without numeric coercion;
- Surface bridge ↔ Core differential cases;
- unbound, type mismatch, missing result on one branch, unsupported construct, and exact-minus-one/zero budget negatives;
- a source-boundary test proving the Core semantic nucleus still imports no
Surface AST, runtime, VM, or
egg, including future Rust source files added undersrc/core.
10. Definition of done
T2A is complete when the implementation and evidence above pass the full workspace test, strict lint, formatting, governance, and documentation-link gates. Completion of T2A does not complete Roadmap Stage 1 or admit function elaboration.