Internal String Interpreter v1
September 10, 2026 ยท View on GitHub
Status: implemented bounded profile; HOSTED GREEN under the v0.4.0 release baseline. Historical local, authoring-time, ignored, device/simulator, or separately provisioned evidence below retains its narrower scope; public promotion, registry publication and broader product completion remain separately gated.
Audience: language users, compiler contributors, and conformance reviewers.
Explicit entry point
semaprax interpret-strings <file> --function <name|stable-id> [--arg literal]... [--max-bytes N]
The additive library module is semaprax::interpreter::internal_strings, with
interpret, verify_envelope, and verify_envelope_against_source functions
using the same signatures as their ordinary interpreter
counterparts. InterpreterOptions and Interpretation are reused unchanged.
The command shares the existing option parser and exit-code convention:
returned value is 0, language/capacity failure is 1, and usage failure is 2.
The API returns no terminal LF; the CLI appends one.
The existing interpret command/API, source-report verifier, Project entry and
test execution, prepared Project interpreter, source traces, stdout, command,
and owned-data evaluators do not opt in. Their admission, wire bytes, and
diagnostics remain unchanged. In particular, ordinary interpretation still
rejects an internal String-signature callee with SPX-F102.
Admission and evaluation
The selected external function retains the existing explicit-ID, monomorphic, effect-free scalar-result boundary. Arguments remain the existing direct scalar or invocation-borrowed text/byte literals. No owned String argument or result is added to the command or report grammar.
Only the transitive internal function inventory is widened: alongside its
previously admitted signatures, it admits direct string parameters with
the ordinary by-value declaration mode and direct string results. Explicit
identities, effect exclusion, monomorphism, and every existing expression
admission check remain required. This is not generic, aggregate-String,
mutable-borrow, import, unsafe, or effectful-call support.
The ordinary verifier and validated HIR remain the source of meaning. The existing evaluator already represents String values as Rust-owned UTF-8; there is no second String execution engine. Place reads clone, arguments evaluate left to right into an invocation-owned vector, and the complete vector enters the callee frame. Rust ownership releases frames and temporaries on normal return, late-argument failure, failed pre/postconditions, fuel exhaustion, and depth refusal. Failed postconditions do not publish a provisional result. No CleanupPlan transition, target runtime, or allocator transfer is added by this admission policy.
String lengths include embedded NUL, and scalar counts count U+0000 as one scalar. Arithmetic and contract failures retain the compiler's normalized status and first-failure selection. Existing step charges, recursion ceiling, and fixed-stack evaluation thread are unchanged.
Distinct report identity
Both the outer object and its payload use exactly:
semaprax.interpret.internal-strings.v1
Payload digest domain:
semaprax.interpret.internal-strings.payload.v1\0
The digest framing remains SHA-256(domain || little_endian_u64(length) || exact_payload_bytes) with sha256: and 64 lowercase hex digits. Source
digests retain the existing semaprax.interpret.source.v1\0 domain. This is
a directly rendered report for the selected profile, not a legacy execution
envelope wrapped or relabeled after evaluation.
Outer member order is schema, digest, bytes, payload. Payload member order
is schema, source, function, arguments, limits, fuel, outcome, nonclaims.
The nested member order, external value grammar, normalized-status grammar,
outcome kinds, and six ordered nonclaims are inherited from Interpreter v1.
The distinct schema and digest domain select the new profile; there is no
implicit fallback between the two verifiers.
Bounds and replay
The new route validates options before source evaluation. Source acquisition
and final drift checks are bounded to 16 MiB through the existing authenticated
source-snapshot helpers. Source-bound verification also bounds its source read.
Envelope input is capped at 16 MiB before JSON parsing, and must additionally
fit its embedded limits.max_bytes. The existing option range is 1 KiB through
16 MiB, default 64 KiB. The library step-budget range remains 1 through
100,000,000, default 1,000,000; the call-depth ceiling remains 256.
Generation has a separately bounded serialization-work allowance and checks
the exact final envelope length against max_bytes; exact capacity succeeds
and one byte less fails without truncation. The legacy renderer's accounting
is unchanged.
The new verifier requires canonical encoding, exact member sets and order,
and exact schema/domain bindings. Duplicate members, alternative escaping,
whitespace variants, unknown keys, re-signed malformed values/statuses, and
contradictory fuel/outcome facts reject. Fuel exhaustion is true exactly when
the outcome kind is fuel_exhausted. Source binding detects drift, but does
not independently re-execute the program, authenticate provenance, or prove
that a submitted outcome was obtained by execution.
The existing diagnostic families are reused: SPX-F101 options, SPX-F102
admission, SPX-F103 arguments, SPX-F104 generation bounds, SPX-F105
evaluation guards, and SPX-F106 replay/source-binding rejection. Shared
source I/O and final-drift diagnostics remain available on generation.
Evidence and nonclaims
Authored evidence covers String forwarding and return, clones, empty/NUL and multibyte values, nested/mixed arguments, contracts, sticky failure, late argument failure, depth/fuel limits, subsequent calls, and scalar legacy fuel/output preservation. Native O0/O2 and ordinary Core-Wasm comparisons use the actual source and raw target emitters, not the frozen public scalar-export package profile, which still excludes String closures.
The report tests cover deterministic generation, source drift, exact output capacity, input bounds, canonical and re-signed hostile envelopes, profile cross-pair rejection, unchanged external String rejection, frozen effect/import/generic/unsafe rejection, and CLI behavior. Executed selections and their limits are recorded in the local validation record. This is partial local evidence, not completion of the cross-platform, full-profile, or hosted gates, and does not imply interpreter sanitizer evidence.
The focused gates are:
cargo test --lib interpreter::internal_strings::tests
cargo test --test interpreter_internal_strings_v1
cargo test --test interpreter_v1
cargo test --test native string_settlement::
The new integration fixture is split between
tests/interpreter_internal_strings_v1.rs and its source.spx, protocol.rs,
support.rs, and probe.mjs children. Its parity gate requires installed
Clang and Node; neither is downloaded or silently skipped. Existing legacy
and native String gates remain necessary preservation evidence. These
commands document required checks; the linked record, not this list, identifies
which selections have executed.
Fuel bounds evaluated work, not String byte growth or peak heap allocation. Source/output caps are not an execution-memory sandbox. Allocator failure, foreign unwind, cancellation, target finalizers, and signal recovery do not gain new guarantees. Wasm String value parity is not physical Wasm settlement. No Project/Transport widening, debugger, persistent cache, JIT, native code execution, filesystem mutation, network, or publication authority is added.