Public Owned Data API v1

September 19, 2026 · View on GitHub

Status: implemented bounded Project-v8 API; generated packages remain unpublished and formal public promotion remains open. Release regression evidence is HOSTED GREEN under the v0.4.0 release baseline.

Audience: language users, generated-SDK consumers, tool authors, and compiler contributors.

GitHub issue #145 chose this exact profile as the candidate for a maintained, reproducible generated-package consumer route. scripts/generated-package-release.py prepares a preview bundle (deterministic README/LICENSE/checksum manifest around the compiler's own unchanged output) and dry-run-checks it; it never publishes anything. See docs/GENERATED-PACKAGE-PUBLICATION-DECISION-DRAFT-V1.md for the unapproved draft maintainer decision this prepares for.

Public Owned Data API v1 defines one additive Project profile for calling a closed set of stable-ID functions from JavaScript/TypeScript and safe Rust. It extends the existing fixed-memory byte-data mechanism with controlled owned byte results. Project Manifest v8, both generated consumer routes, the reference-interpreter lane, and their focused evidence are present in the current source tree. The v0.2.0 tag commit 5f6fb9655fdec92c57ab71615cfd7bfa8cc76051 passed the complete blocking release run, including the three-host Rust inventories and selected consumer/sanitizer jobs. This supersedes authoring-time “unrun” wording only for nonignored tests actually selected by that workflow. It does not publish either generated package, execute every separately provisioned case, or complete formal API promotion.

The profile deliberately copies every successful owned result into host-owned storage before publication. It does not expose a SEMAPRAX pointer, allocator, arena token, or provider handle to application code.

Fixed protocol identifiers

The following identifiers are exact and are not aliases:

LayerIdentifier
Project schemasemaprax.project.v8
Project profileowned-data-api.v1
Canonical API descriptorsemaprax.public-owned-data-api.v1
npm build carriersemaprax.project-npm-build.v7
npm API metadatasemaprax.owned-data-api.v1
Rust SDK manifestsemaprax.native-rust-owned-data-sdk.v1

Each identifier selects only the contract in this document. An earlier Project schema cannot select owned-data-api.v1, and Project v8 cannot select an earlier profile. Consumers must reject unknown identifiers rather than fall back to a scalar, useful-data, command, or legacy SDK route.

Canonical Project manifest

Project v8 has exactly eight assignments in this order and one terminal LF:

schema = "semaprax.project.v8"
name = "frame-payload"
version = "0.1.0"
profile = "owned-data-api.v1"
entry = "frame_payload.app"
sources = ["src/app.spx", "src/core.spx", "src/tests.spx"]
web_exports = ["frame.payload", "frame.payload-maybe", "frame.payload-result"]
tests = ["frame_payload.tests"]

The existing canonical name, Semantic Versioning, module, source-path, stable-ID, and ordering rules apply unchanged. sources contains 2–16 strictly sorted unique paths. A public API selects 1–32 strictly sorted unique web_exports stable IDs. The additive IO Cursors v1 library route also admits web_exports = [] for ordinary Project v8 libraries. It checks and executes internal entry/test closures without producing a public descriptor or public package artifact. Public artifact requests remain refused; a nonempty export selection still uses every original public API rule.

The exact bundled std.collections and std.mem no-export alias packages retain their additional source and inventory authentication and reject nonempty exports for those exact manifest shapes. Other libraries gain no intrinsic-alias authority from an empty export list. There are no command, input, or capabilities fields. Unknown, missing, extra, duplicated, or reordered assignments reject.

Project v8 enters the existing closed ProjectProfile dispatch as one distinct variant. Schema or profile text is never converted into loose feature flags from which downstream authority is inferred.

Semantic admission

Admission is derived from validated, linked HIR. Source-shaped declarations, generated metadata, target artifacts, or caller assertions are not semantic authority.

Every selected export must satisfy all of the following (the authenticated no-export std.collections package selects none):

  • it is a source-authored function with an explicit persistent @id equal to the selected web_exports identity;
  • it is monomorphic and is not the Project entry function;
  • it has 0–8 parameters, each with one exact admitted parameter type;
  • it has exactly one result with one exact admitted result type;
  • the function and every function in its transitive closure are effect-free, import-free, and contract-free;
  • the complete selected closure is acyclic; direct and mutual recursion both reject;
  • the linked executable function inventory is nonempty and contains at most the existing public-export bound of 256 functions; and
  • the closure passes the ordinary verifier, ownership checks, cleanup-plan construction, and independent cleanup-plan replay before descriptor or target generation.

All selected roots, including roots disconnected from the Project entry, are linked under one authenticated held Project snapshot. The union of their closures is checked once; a function reachable from more than one root is not duplicated or charged twice.

Admitted types

The parameter vocabulary is exactly:

  • i64
  • bool
  • borrow str
  • borrow Slice<u8>

The result vocabulary is exactly:

  • i64
  • bool
  • usize
  • Bytes
  • Option<Bytes>
  • Result<Bytes, i64>

Option and Result here are the authenticated compiler-owned variants. They are admitted only in the exact unnested forms above. Result::Err is a successful API invocation carrying a language value; it is not an adapter or host-call failure.

Borrowed arguments are invocation-bounded snapshots. Their cumulative encoded or byte length across one external call is at most 65,536 bytes. An owned byte result has an exact length in 0..=65_536; capacity-plus-one rejects before a host value becomes observable.

Exact exclusions

The public boundary rejects all of the following, even when the shape exists inside an otherwise valid SEMAPRAX program:

  • owned parameters;
  • resource parameters or results;
  • fixed arrays or any other arrays as public values;
  • borrowed results;
  • authored records;
  • authored variants;
  • nested Option or Result values;
  • Result error types other than exactly i64;
  • callbacks or callable imports;
  • async functions or async values;
  • shared values;
  • public mutation or mutable borrowed arguments;
  • multiple returned values or unit results;
  • host allocator adoption or zero-copy allocator transfer; and
  • direct raw pointer, arena-token, provider-handle, or context exposure.

The profile also grants no filesystem, process, environment, clock, random, network, thread, UI, registry, signing, or publication authority.

Canonical public API descriptor

The compiler derives one canonical descriptor from the authenticated Project revisions, Project graph digest, validated HIR, selected stable IDs, and fixed limits. Its schema is semaprax.public-owned-data-api.v1. It contains, in strict stable-ID order:

  • the Project schema, Project revision, Workspace revision, and Project graph digest;
  • every export stable ID;
  • every parameter's stable identity, source display name, ordinal, and one closed parameter-type tag;
  • one closed result-type tag for each export; and
  • the exact export, parameter, closure-function, borrowed-input, and owned-output limits.

The descriptor has deterministic canonical bytes and a domain-separated digest. Parsing is closed and bounded. Independent replay must reconstruct the same facts from the same retained Project subject and reject truncation, insertion, deletion, reordering, duplication, unknown fields or tags, changed revisions, changed graph digest, or any byte mutation.

The lower native package applies its existing nonempty, 1 MiB, terminal-LF and NUL-free byte guard before JSON parsing, including the preliminary schema lookup that selects the v8/v10 digest domain. Digest discovery and full replay share that guard; reaching the exact byte limit does not establish canonical or semantic validity. Provider-validation precedence and accepted descriptor bytes remain unchanged. The focused regressions in crates/semaprax-native-rust-owned-data-package/src/descriptor_input_tests.rs cover exact/plus-one input framing, canonical replay, domain separation and early rejection through the public builder. They are implemented.

The shared native provider-binding check also compares borrowed text rather than formatting a copy of the caller-supplied digest. It retains the exact single-binding-line predicate, including rejection of duplicate or malformed lines, without imposing a new digest grammar or changing error precedence. The same released regression module compares the old and new predicates on hostile line/digest combinations and an oversized digest mismatch.

The lower native package reader enforces parameter-identity uniqueness within each export, matching the compiler's descriptor parser. Correctly recomputing the digest does not authorize two parameter ordinals to share an identity. This shared v8/v10 rejection leaves canonical compiler-produced bytes and identifier grammars unchanged. It is a structural replay check, not independent proof of provider semantics. Implemented regressions live in tests/projections/public_api_descriptor/parameter_identity.rs and crates/semaprax-native-rust-owned-data-package/src/descriptor/tests.rs: the root cases retain real HIR and exact canonical framing while reminting duplicate-ID mutations; lower cases cover both schemas and valid parameter boundaries as well as duplicates. Structural uniqueness is per export, not a new cross-export identity rule.

The additional tests/projections/public_api_descriptor/semantic_replay.rs cases distinguish retained-HIR binding from framing and digest rejection. Each pair derives two authentic descriptors from separately checked source, first replays each against its own HIR, then cross-replays both directions using their correct digests and requires the exact retained-subject diagnostic. V8 and v10 cover parameter types, names, order and arity, scalar and owned result types; v10 additionally distinguishes Bytes from owned UTF-8. Explicit fact assertions keep these cases from degenerating into unrelated mutations.

The fixture deliberately holds synthetic revision facts constant to isolate signature replay. It does not claim an edited real Project retains its revision, that a descriptor authenticates source provenance, or that equal descriptors prove equal function behavior. Body-only and function-display-name controls preserve descriptor bytes; parameter presentation names are included facts. Parameter IDs derive from function identity and ordinal, so no independent source-authored parameter-ID mutation is claimed. These added cases are included in the v0.4.0 hosted-green regression corpus; production code, schemas and existing golden bytes remain unchanged.

This descriptor is the sole semantic API source for JavaScript bindings, TypeScript declarations, npm metadata, native provider descriptors, and the safe Rust SDK. A target may add authenticated target-layout facts, but it may not rediscover or reinterpret a source signature. If two targets require different semantic descriptors, the profile must remain inactive.

Display names are presentation only. Generated APIs are keyed by, or derive their collision-checked host identifier from, the persistent stable ID. A source display rename that preserves the stable ID must preserve descriptor meaning and the external API.

Host type mappings

SEMAPRAXTypeScriptRust
i64biginti64
boolbooleanbool
usizebigintu64
borrow strstring&str
borrow Slice<u8>Uint8Array&[u8]
BytesUint8ArrayVec<u8>
Option<Bytes>Uint8Array | nullOption<Vec<u8>>
Result<Bytes, i64>SemapraxResult<Uint8Array, bigint>Result<Vec<u8>, i64>

TypeScript uses this exact result definition:

export type SemapraxResult<T, E> =
  | { readonly ok: true; readonly value: T }
  | { readonly ok: false; readonly error: E };

JavaScript accepts only ordinary, attached, fixed-length Uint8Array byte inputs. It rejects shared, resizable, detached, differently typed, DataView, and implicitly coercible inputs. Strings are encoded as checked UTF-8. Every borrowed argument is snapshotted before public scratch is mutated, and the complete call is synchronous and non-reentrant.

For safe Rust, adapter, semantic, or host-call failure is an outer SDK error. The table's Result<Vec<u8>, i64> is the successful SEMAPRAX language value inside that outer result. Generated safe API code forbids unsafe code and exposes no raw provider handle or context.

Result representation and lifetime

The target-neutral variant discriminants are fixed:

Option: None = 0, Some = 1
Result: Ok = 0, Err = 1

Any other tag is an invariant failure before payload access. None and Err own no byte carrier. Some and Ok own exactly one active byte carrier. Inactive payload storage is never read, copied, or dropped. A tag/liveness disagreement fails before publication.

Before a generated API call returns to JavaScript or safe Rust, it must complete this sequence in order:

  1. authenticate the SEMAPRAX owned result and its active-case liveness;
  2. query and check its exact length against the authenticated carrier and the 65,536-byte output bound;
  3. allocate exact host-owned storage and copy exactly that many bytes;
  4. consume or drop the SEMAPRAX carrier exactly once;
  5. prove the invocation's provider or arena is settled, with no live result, provisional result, or cleanup obligation remaining; and
  6. only then publish the host-owned Uint8Array, Vec<u8>, null, or error branch to application code.

The host allocation is never adopted by SEMAPRAX, and SEMAPRAX allocation is never adopted by the host. Empty owned bytes still carry real ownership until settled. Failure before result publication preserves the caller-visible result slot and exposes no partial bytes. Failure after staging but before publication settles the staged owner exactly once. If exact settlement cannot be proven, the invocation fails closed and publishes no language value.

The Wasm wrapper never exposes its raw carrier. It clears or poisons temporary result storage after settlement and requires an empty arena before success. The native provider uses an opaque, provider-owned handle only inside the private FFI sibling; safe Rust queries length, copies, and settles through an internal owner guard. A separate invocation guard then proves the entire context settled through the existing context-close operation before returning any value or recoverable error, including scalars, None, and language Err. On Rust unwind the owner guard runs before the invocation guard. Uncertain owner or context settlement retains the existing fail-stop policy; no retry or later provider effect is permitted. Unknown tags or forged inactive handles never authorize length, copy, or drop operations. A panic may not cross the FFI boundary. No allocator pointer is converted directly into a Vec<u8>.

The authored v8/v9/v10 Rust correction reinitializes a proven-closed context only on the next invocation. This resets its private invocation counter, not the linked provider's nonreused handle issuer. No live result or provider obligation may cross that reset. A rejected initialization preserves its existing error and permits no further provider operation in that invocation or its cleanup; a later explicit invocation may attempt initialization again. Only a successfully initialized invocation owns a context-close obligation. Public Rust signatures, provider C and ABI, descriptors, and manifest schemas stay unchanged; generated safe/private Rust and its integrity bindings intentionally change. Hostile-provider protocol tests are implemented; this is not a safety claim against arbitrary malicious native machine code.

The subsequent native internal String correction settles String allocations that the standalone descriptor already admits inside function bodies. Provider context close cannot observe those inline allocations and is not their cleanup proof. V8/v9 provider emission now shares ordinary length-header helpers and a per-function String ledger. Full translation units with Strings, including unselected functions, intentionally change native C and dependent artifact bindings; String-free output remains exact. Public types, descriptors, schemas, v10 output, and activated Project admission are unchanged. Physical allocator and external-consumer evidence is implemented.

The authored native correction uses a 13-bit one-based slot (1..=4096) and a nonreused 51-bit issuance serial within one statically linked provider runtime. One private atomic strong compare-exchange reserves a serial without retry. Contention or permanent exhaustion rejects before owner or output publication; the caller settles its unpublished result. The issuer survives context disposal and storage reinitialization. It does not establish uniqueness across separate provider images or reloads, pointer secrecy, shared-context thread safety, or guaranteed successful progress under contention. The same private runtime correction applies to v9/v10; generated C/object/archive bytes and integrity bindings intentionally change, not public signatures or schemas.

Scoped local execution of public_native_rust_owned_data_sdk_v1 on Linux AArch64/Rust 1.88/Clang 14 passes nine selected tests: seven provider/SDK tests and two target-management support checks. The native probes exercise hostile handles, all 4,096 slots, context reincarnation, serial exhaustion and contention, and separate thread-confined contexts at O0/O2; the provider/issuer probes also run the Linux O2 sanitizer lane. The UTF-8 rejection probe runs at O0/O2. The nested offline Cargo package-consumer test is explicitly excluded. The Windows path-budget support check is a model, not Windows execution. These results do not establish shared-context safety, full native support, hosted promotion or physical allocator settlement for internal Strings.

The authored v8/v9/v10 JavaScript correction admits the entire argument tuple, including exact bounded UTF-8 lengths, before payload snapshot allocation. Captured intrinsic view checks reject detached/shared/resizable and wrong-brand inputs without invoking caller constructor/species hooks. All snapshots still precede Wasm scratch writes and arena entry. Module-byte inputs have their separate 16 MiB admission bound before copy/hash. Explicit v9/v10 routing now reuses the byte-identical v8 input helper; v8 JavaScript remains unchanged by that extension. V9/v10 JavaScript and dependent artifact bindings intentionally change, not descriptors, Wasm, or TypeScript declarations. Their record-field authentication, scalar validation, and consume-before-UTF-8-decoding rules remain in force. Real-package hostile-input regressions are release-tested, not promotion evidence; their owner is tests/project/owned_input_admission.rs, alongside the preserved v8 renderer known answers.

The Node evidence requires actual shared and resizable buffers plus transfer support; missing prerequisites fail the selected gate rather than omit cases. Buffer construction and capability checks happen outside rejection assertions. The direct-Bytes fixture and shared v8/v9/v10 input-admission fixture require the actual facade's TypeError and fixed-input diagnostic, followed by healthy same-instance calls. An assertion that a forbidden input was accepted must not be swallowed by a capability-detection catch. The direct/variant v8 and UTF-8 consumer tests also require Node execution instead of returning success when Node cannot start. These evidence corrections are included in the v0.4.0 hosted-green regression corpus; generated runtime bytes, schemas, and support status are unchanged.

The subsequent owned npm invocation correction reserves busy state before preflight and distinguishes reusable input rejection from post-entry uncertainty. Only a locally authenticated checked-status error may recover after settlement. Caught reentry, malformed output and unexpected host exceptions poison the instance even with an empty arena; the first thrown value is preserved without truthiness checks. This correction intentionally changes v8/v9/v10 JavaScript and its dependent integrity bindings, including the bounded-renderer known answers. Historical unselected renderers, Wasm, descriptors, declarations and v1-v7 artifacts remain unchanged. Its separate real-package failure matrix has scoped local execution evidence recorded in that contract; it does not promote the entire public profile.

Generated artifacts and carriers

The npm output inventory is exactly:

  1. app.wasm
  2. semaprax.js
  3. semaprax.bindings.js
  4. semaprax.bindings.d.ts
  5. semaprax.api.json
  6. package.json

semaprax.api.json uses semaprax.owned-data-api.v1 and binds the canonical API descriptor, Wasm digest, fixed limits, exact target call shapes, ordered artifact inventory, and owned-result settlement policy. The surrounding context-bound npm build carrier uses semaprax.project-npm-build.v7 and binds the retained Project subject plus the exact ordered artifacts, bytes, digests, and payload digest. Inspection or replay proves consistency only; neither the metadata nor carrier grants build or publication authority.

Filesystem materialization uses the shared Unix npm publication boundary: final parent binding compares held/reopened filesystem identities as well as canonical path text. Same-path parent replacement must not turn a package retained in a displaced directory into reported success. The admitted release regressions are HOSTED GREEN; no Windows routing change or atomic-publication claim follows.

The separately approved Windows owned npm publication change routes Project v8–v10 npm/Web filesystem effects through semaprax-full and the existing held-handle platform authority. Standalone Windows publication rejects before output effects; inline carriers and generated bytes are unchanged. The private route requires an existing parent and an admitted ASCII output leaf. Its source-drift, no-clobber and settlement evidence is implemented.

The owned-data Rust package uses manifest semaprax.native-rust-owned-data-sdk.v1. It binds the same canonical API descriptor and exact generated package/provider inventories. It is distinct from, and does not reinterpret, the existing scalar Rust SDK manifest. The safe package must build locked and offline without repository source or a workspace dependency. Unsafe FFI remains quarantined outside the root semaprax crate and outside the generated safe API.

The lower builder shares the scalar SDK's compiled-ABI admission: five supported GNU/Linux, Apple/macOS, and x86-64 MSVC/Windows target identities, without substituting another libc or ABI. Unsupported targets retain the existing tool error before staging; v8/v9/v10 descriptors and supported-target package bytes are unchanged by this selection rule.

Generated Cargo build-script path boundary

The shared private build-script renderer for v8, v9, and v10 validates CARGO_MANIFEST_DIR before printing any Cargo instruction. After the existing target-mismatch check, it requires a present Unicode path containing neither CR nor LF. It does not canonicalize, require existence, or reject spaces and other ordinary Unicode characters. Accepted paths retain the exact three archive-change, native-search, and static-link instructions in their original order. This follows Cargo's line-oriented build-script output contract: a path must not introduce another instruction line.

This correction intentionally changes generated build.rs bytes and their manifest integrity bindings, including standalone owned-data evidence packages. It does not change descriptors, provider C/archive bytes, generated safe/FFI Rust, public signatures, package schemas, or the existing scalar SDK. Missing, non-Unicode, and CR/LF paths fail before any stdout; target mismatch retains precedence and its original message.

The lower package's build_script::tests renders both families for all five target identities and authors standalone build-script subprocess checks for the current host. The two executables are reused across valid-path, CR/LF, missing-variable, target-precedence, and platform-specific non-Unicode cases. The implemented release regression corpus is HOSTED GREEN. They test the generated instruction boundary, not Cargo's downstream execution, archive linking, pathname authority, or a build sandbox; the separate real package consumers remain required.

Focused gate (reproducible regression selector):

cargo test --locked -p semaprax-native-rust-owned-data-package build_script::tests

Safe Rust thread-confinement gate

The generated NativeRustOwnedDataSdk remains !Send and !Sync; owning a copied host result does not grant permission to move or share its provider context across threads. The compile-only lower-package test tests::auto_traits::generated_owned_sdks_reject_send_and_sync_in_external_safe_consumers protects this existing boundary for standalone v8, Project v8, v9 and v10.

Each case replays its canonical descriptor fixture and compiles the actual generated SDK and private FFI into a separate metadata crate. A healthy external consumer with #![forbid(unsafe_code)] must compile before separate concrete Send and Sync assertions are checked. Rejections must carry E0277 at the intended SDK assertion, with the requested trait and SDK identified by compiler diagnostic facts; a missing dependency, syntax failure or arbitrary nonzero exit is not evidence. The private FFI is not included beneath the consumer's unsafe prohibition. No provider or linker is invoked, and these descriptor fixtures are not evidence of root-owned HIR admission.

The gate contains four healthy consumers and eight negative consumers. It adds no unsafe implementation, dependency, public type or runtime behavior; compile-time confinement is not runtime reentrancy, lifecycle, provider-thread safety or minimum-version validation. All four profiles pass their healthy and negative consumers locally on Linux AArch64/Rust 1.88 and macOS AArch64/Rust 1.98. Strict lower-package library/test Clippy also passes on macOS. The separate generated-SDK Rust 1.85.1 checks below extend compiler evidence without claiming Windows execution.

Focused command:

cargo test --locked --offline -p semaprax-native-rust-owned-data-package --lib auto_traits

Descriptor-selected private Rust helpers

The private FFI renderer emits result-owner declarations only when an admitted selected result uses them. Scalar-only standalone/v8/v10 selections omit Handle, RawCall, owner extern declarations, copying/discard methods and the owner guard. Context initialization, thread confinement, invocation guards, checked close and reinitialization remain unconditional. Scalar results still cannot escape an unsettled provider context.

Every v8/v10 owned result retains the discard path for malformed successful carriers. Flat v9 always needs copying and its owner guard, but emits discard only when any selected record contains a Bool field: an invalid successful Bool must drop that record's live owner before reporting adapter rejection. A Bool parameter alone does not require this result-cleanup path.

This corrects unconditional unused helper emission, not a compiler warning policy. No lint is suppressed and no valid descriptor is rejected. Generated private FFI and dependent manifest bindings intentionally change for scalar-only standalone/v8/v10 and Bool-free v9 selections. Public Rust types, descriptors, provider C/archive bytes, ABI, schemas and capacity limits are unchanged. Previously used helpers preserve their exact emitted bytes.

tests::strict_sources checks all three scalar result kinds in standalone v8, Project v8 and Project v10: nine separately replayed SDKs and nine external safe consumers compile metadata with -D warnings. The four-profile thread-confinement gate also denies warnings in generated SDK and consumer compilation. The flat descriptor regression includes a Bool in only the later export; the existing hostile ABI-double gate still checks malformed-Bool owner disposal and checked context closure at O0/O2. These are compiler/protocol checks, not provider proof.

All 49 lower-package library tests pass locally on Linux AArch64/Rust 1.88 and macOS AArch64/Rust 1.98; strict lower library/test Clippy passes on macOS. The same Rust-1.88-built harness also passes all 49 cases in the cached Linux Rust 1.85.1 image, where fresh generated SDK, external metadata consumer and hostile ABI-double subprocess compilations use that older compiler. The harness itself is not built by Rust 1.85.1; this does not lower the repository MSRV.

Actual Linux AArch64 v8/v9 mixed-borrow packages generated by Rust 1.88/Clang 14 also pass locked/offline Cargo consumers under Rust/Cargo 1.85.1, with RUSTFLAGS=-Dwarnings. Before this correction the identical strict v9 consumer failed on unused discard; after regeneration both consumers pass. The twenty-file handoff contains only the two seven-file SDKs and each consumer's manifest, lockfile and source; inventories and hashes match before and after read-only consumption. Comparing before/after publications, only v9 private FFI and its manifest binding differ; all v8 files and both provider archives match. The older image does not build the repository or invoke SEMAPRAX. This is Rust 1.85.1 evidence, not exact 1.85.0, repository MSRV, Windows or hosted evidence.

Raw Wasm call boundary

The raw Wasm owned-result call shape is profile-specific:

(parameters..., result_out: i32) -> status: i32

The adapter validates alignment and the complete result-out range before semantic execution. It writes one authenticated carrier only after semantic success and cleanup-plan result publication. Status and out-of-band adapter failure remain distinct from a successful language Result::Err.

The authored raw-Wasm correction excludes the complete reachable private shadow-stack interval, not merely the wrapper's temporary output. The shared validated-HIR call index and the actual lowerer's frame sizes derive the maximum simultaneous call-path extent for selected exports only. Missing, cyclic, overflowing, or over-capacity selected extents reject; unrelated declarations do not change this admission. Full and partial overlap guards run before UTF-8 imports or semantic execution and preserve the fixed borrowed and public-result scratch reservation. This shared v8/v9/v10 correction intentionally changes their Wasm bytes and dependent artifact bindings, without changing descriptors, public call signatures, or v1-v7 artifacts. Its real-engine poison, nested-helper, settlement, and re-entry regressions are implemented.

Compatibility

The shared checked usize multiplication correction is an explicit correctness exception to the artifact-byte preservation below: Wasm modules emitting this operation and their derived integrity bindings change across affected profiles, not just v8. It restores multiplication by zero and preserves genuine overflow cleanup; schemas, source semantics, descriptors and native code are unchanged. Its cross-target regressions are included in the v0.4.0 hosted-green regression corpus.

Project v8 and every protocol above are additive. Project v1–v7 parsing, diagnostic selection, canonical manifest bytes, linked meaning, generated artifacts, npm carrier schemas and bytes, Rust SDK v1 schemas and bytes, scalar Web exports, command packages, and target known answers must remain unchanged.

The v8 implementation must be reachability- and profile-gated. When Project v8 is absent, it emits no owned-data descriptor, metadata, helper, arena/provider operation, target branch, artifact, or runtime state. Earlier schemas reject the new profile, and v8 rejects all earlier profile names. There is no migration that silently rewrites an earlier manifest as v8.

Stable-ID display rename compatibility requires the same selected identity, signature, descriptor semantics, host API identity, and generated consumer behavior before and after rename. A signature, ownership, effect, contract, import, or stable-ID change is not a display rename and must reject or produce a separately reviewed compatibility change.

Completion gates

This implementation may be described as locally evidenced only when all applicable gates below pass at the same commit. Completion-matrix or public promotion additionally requires the exact hosted gate in item 12. Authored but unexecuted repository tests do not satisfy either condition.

  1. Parser and canonical manifest: exact v8 assignment/order/LF/profile acceptance; every malformed, capacity, ordering, schema/profile-confusion, source-count, and export-count rejection; byte-for-byte v1–v7 manifest and diagnostic preservation.
  2. HIR admission: success for every admitted parameter/result type and their mixed 0–8-parameter signatures; rejection of every exact exclusion; stable-ID selection, non-entry, monomorphic, effect/import/contract-free, acyclic closure, 256-function bound, and hostile-HIR validation.
  3. Descriptor replay: canonical bytes and digest; zero-export rejection; one and 32 exports; zero, one, and 8 parameters; strict ordering and uniqueness; display rename; revision/graph binding; independent replay; byte mutation, truncation, insertion, deletion, foreign-subject, unknown-tag, and budget rejection; one descriptor driving every target generator.
  4. Interpreter/native/Wasm equivalence: the same source corpus produces equal scalar, byte, Option, and language-Result values and normalized failures through interpreter, native O0/O2, and Core-Wasm, including empty, embedded-NUL, invalid-UTF-8, 0xff, None, Some, Ok, and minimum/zero/ maximum Err(i64) cases.
  5. JavaScript and TypeScript consumption: compiler-free installed package use; exact declarations and result union; stable-ID access; string and byte input validation; snapshot isolation; repeated calls; digest and metadata authentication; ordinary fresh Uint8Array results; no raw carrier access; locked offline pack/install.
  6. Safe Rust consumption: exact descriptor/manifest replay; generated API with unsafe forbidden; locked offline external consumer; exact Vec<u8>, Option, inner language Result, and outer call-error behavior; no raw handle/context; panic containment; O0/O2 equality.
  7. Hostile carriers: malformed Wasm/provider/artifact digest; invalid or unaligned result pointer; zero, stale, foreign, or duplicate handle/token; wrong length; invalid tag; inactive forged payload; tag/liveness mismatch; wrong destination length; double consume/drop; provider copy/drop failure; arena/provider non-settlement; tampered re-digested metadata.
  8. Cleanup exactness: independent cleanup-plan replay and target traces for success, pre-publication failure, post-staging failure, inactive cases, postcondition failure, copy failure, settlement failure, repeated entry, token/handle rotation, first-failure stickiness, exact-once active-owner settlement, and no partial result publication.
  9. Stable-ID display rename: a multi-module fixture is built and consumed before and after a display-only rename; Project graph facts, canonical API identity, npm and Rust method identity, and consumer behavior remain bound to the unchanged stable ID, while presentation facts may change.
  10. Capacity boundaries: minus-one, exact, and plus-one cases for 32 exports, 8 parameters, 256 linked functions, 65,536 cumulative borrowed input bytes, 65,536 owned output bytes, every descriptor/carrier byte budget, Wasm result storage, native destination length, and handle/arena capacity.
  11. Compatibility preservation: known-answer bytes for every Project v1–v7 manifest, existing npm carrier, scalar and useful-data Web artifact, command package, and scalar Rust SDK remain exact; profile-absent builds contain no v8 runtime or metadata; all earlier mismatch diagnostics remain stable.
  12. Cross-platform hosted promotion: all focused gates, hostile tests, external JS/TypeScript and Rust consumers, native O0/O2, browser execution, sanitizers, deterministic inventories, and compatibility KATs pass on one exact commit in blocking Linux, macOS, and Windows jobs, with every claimed browser/runtime and minimum-Rust-version lane named by the release gate. Skipped, cancelled, diagnostic-only, retried, or allowed-failure jobs do not count.

The v0.2.0 tag contains the Project v8 implementation behind its exact manifest/profile and CLI routes, and the tag workflow executed its nonignored regression inventory. That does not satisfy every separately provisioned part of the twelve-gate contract or make either generated package a published, supported SDK. Formal completion-matrix promotion therefore remains an explicit decision after the remaining gates.

The frame-payload product's authored binding fixtures now reopen each real baseline/display-renamed Project revision and replay the exact descriptor from both generated packages against that subject. They compare regenerated npm artifacts and independently reconstruct the native manifest's canonical inventory and descriptor/provider-source bindings from reopened bytes. This is a test-specific manifest observation, not a newly exposed package verifier or an independent proof of the archive's machine-code semantics.

The lower native package builder preserves the safe platform facade's archive settlement state before projecting its existing publication error. An Uncertain failure stops before owned-stage discard, later authority rechecks, or outer package publication. The inert stage remains for reconciliation; ordinary held handles are still released. Settled failures retain exact-inventory cleanup and sticky primary-error precedence. This shared boundary also serves the additive v9/v10 packages. Private regressions inject closed archive failures and exercise real held-stage inventory preservation, including foreign bytes. Their release coverage is HOSTED GREEN, but injected archive failures do not prove physical archiver settlement or process quiescence.

The seven-file outer package has the same one-way publication boundary: exact-inventory cleanup is available only during preparation. Starting settle_for_publish consumes that cleanup authority, including when settlement, rename, or a later path/replay check fails. Failures retain the inert or published tree for reconciliation; moving a published tree back to its former staging name cannot restore deletion authority. Private held-filesystem regressions cover preparation cleanup, retained post-transition stages, a real no-clobber collision, and Unix post-rename displacement back to the stage name. Their release coverage is HOSTED GREEN without establishing hostile same-principal isolation or permanent pathname binding.

The same retained HIR supplies the interpreter and native O0/O2 corpus checks. A separate raw-Wasm ABI observer uses the unchanged production arena/core templates, observes actual mint/drop/copy-out and empty settlement, and checks alignment rejection before imports with preserved poisoned output. It is an independent consumer, not an independent arena implementation or a complete internal destruction trace. These frame-product lanes passed locally on macOS arm64 with Rust 1.98, Apple Clang 21 and Node 24.3, including the actual baseline/display-renamed Project npm and locked/offline Rust consumers.

The frame-payload native corpus additionally has a separate allocator-observed O0/O2 lane, alongside the unchanged plain-provider lane. The test wraps the exact generated provider with the existing calibrated allocator observer and checks each call: nonempty payload allocation and release, empty-owner free(NULL), allocation-free inactive None/Err, exact copy-out, and stale drop rejection without another free. Both live-pointer and provider-slot inventories must be empty between calls. Existing callers select the isolated module and both authenticated baseline/display-renamed Project subjects. The observer and its static context are private fixtures, not generated hooks or public ABI. These checks passed in the same local macOS frame-product run; successful handle-drop statuses alone are not physical deallocation evidence, and this lane does not replace sanitizers, OOM handling, or the separate generated Rust consumer.

The explicitly selected native_execution sanitizer gate reuses those exact plain-provider and allocator-observed C corpora at O0/O2 for the isolated module and both retained Project subjects. It requires an absolute SEMAPRAX_FRAME_SANITIZER_CLANG, enables ASan and UBSan with recovery disabled, and rejects missing compile-time instrumentation. Independent use-after-free and signed-overflow controls must fail with their sanitizer diagnostics at both optimization levels before the 12 product executables may pass. It does not modify the ordinary compiler flags, provider bytes, or corpus expectations.

SEMAPRAX_FRAME_SANITIZER_CLANG=/absolute/path/to/clang cargo test --locked --offline -p semaprax --test frame_payload_product_v1 native_execution::isolated_and_retained_project_corpora_pass_asan_and_ubsan_at_o0_and_o2 -- --ignored --exact

Provision the selected compiler's headers and sanitizer runtimes. Direct Apple Clang also needs the installed macOS SDK selected through SDKROOT. This gate is not sanitizer coverage of every source program, Rust allocation, or public SDK build, and cannot promote a platform without its other required gates.

The selected gate passed locally on macOS arm64 with Rust 1.98/Apple Clang 21 and on Linux arm64 kernel 6.12.72 with Rust 1.88/Clang 14.0.6. Linux execution used an offline Docker container with all capabilities dropped and read-only source/registry mounts. The four calibration failures were expected controls; all 12 product executables succeeded. Linux compilation also emitted an existing unused-constant warning in the standalone String emitter; no clean Linux lint or complete quality-gate result is claimed here.

The separate frame-format supplement in tests/frame_payload_product_v1/adversarial.json retains the existing corpus schema without changing any of the three committed nine-case corpora. Its 72 rows cover every bit of the four-byte declared length, valid power-of-two payload sizes, all incomplete header lengths with good and bad magic prefixes, complete-header magic/error precedence, and unsigned 32-bit declaration edges. Expected validity and errors are literal fixture facts, checked by a separate host-side inventory oracle rather than by the SEMAPRAX decoder. In particular, ignoring either upper length byte must no longer pass the conformance corpus.

The original native/raw-Wasm checkpoints run before the supplement. The 72 additional cases make 160 calls with 48 nonempty owned results, and reuse the existing native executables and raw-Wasm instance. Actual baseline and renamed Project subjects also use the same published npm/Rust packages and unchanged external consumer source. The additional Rust consumer has a fresh source/input path and shares only the compilation cache, avoiding reliance on timestamps for an in-place include_str! input change. The provisioned Chromium fixture passes the test-owned supplement to the unchanged same-origin corpus runner after checking the original host-served corpus; it does not require a changed host corpus or claim authentication of Project source derivation. The local macOS frame-product run passed these additional interpreter/native/Wasm/npm/Rust checks. A separate local Chromium run with Playwright 1.62.0 passed both packages' nine canonical and 72 supplemental cases; pinned served bytes were unchanged afterward. These are not Windows or hosted promotion results.

The provisioned private toolchain gate project_owned_tuple_sdk_v1 adds real published v8/v9 Rust consumers for one borrowed UTF-8 string plus two borrowed byte slices. It checks cumulative 65,535/65,536/65,537-byte tuples, Unicode byte length rather than character count, unused arguments, and v8 inactive None/Err branches. Accepted cases include maximum Some/Ok outputs; rejections are followed by successful calls on the same SDK object. Separate objects, input/output mutation, and retained outputs after object drop check host-owned copies. Each seven-file package is reopened against its canonical descriptor and regenerated provider binding before the locked/offline consumer runs. The gate is ignored by default and must be explicitly selected after tool provisioning; scoped local results are recorded below:

cargo test --locked -p semaprax-toolchain --test project_owned_tuple_sdk_v1 -- --ignored

This is consumer-level capacity and ownership evidence, not an invocation-entry counter, allocation trace, or proof of persistent native-context reuse. It does not replace the separate sanitizer, browser, or exact-head promotion gates.

The npm counterpart tests/project/owned_tuple_npm.rs derives both real Project subjects and reopens each six-file publication against its verified inline carrier and descriptor. Its Node consumer spells the same tuple corpus independently, checks exact variant/record results, and retains independent copies across two runtime objects. A test-only wrapper counts entry into the actual selected Wasm exports: accepted calls calibrate one entry, and rejected tuples must leave the count unchanged before a successful recovery call. This observes JavaScript preflight before selected-export entry, not Wasm-internal allocation, native-context lifetime, browser execution, or TypeScript checking. The scoped local descriptor/lifecycle batch records this fixture's Linux and macOS execution in Owned npm invocation.

tests/native/owned_tuple_admission.rs uses the same authenticated Project subjects to generate the actual native v8/v9 providers. Its separate C fixture observes the provider's existing post-validation invocation counter, owner slots, issuance serial, and instrumented malloc/calloc/free call counts. Successful calls calibrate entry and allocation observations; oversized tuples and malformed UTF-8 must preserve output sentinels and context bytes without entry, allocation calls, or ownership changes, including inactive v8 branches. Recovery uses the same physical context. Empty active Bytes results still own a handle; their drop observes free(NULL) without a payload allocation. This test-only allocator instrumentation is not a public ABI, an OOM-recovery proof, or a sanitizer substitute.

The native tuple test passes all four v8/v9 O0/O2 executables on Linux AArch64/Rust 1.88/Clang 14 and macOS AArch64/Rust 1.98/Apple Clang 21. On those same hosts, the explicitly selected Rust consumer gate passes actual v8/v9 publication, exact seven-file reopening and both locked/offline consumers. Linux publication uses the container's /tmp tmpfs and the held /usr/bin/aarch64-linux-gnu-ar; macOS requires /usr/bin/libtool, as frozen by the native archive contract. A first macOS invocation selecting ar correctly rejected with SPX-I234 before package publication; the provisioned libtool invocation passed without changing admission.

The lower package's three close-selected unit tests also pass on both hosts, including generated v8/v10 and flat-record boundary consumers at O0/O2 and the deliberately broken-close calibration. Their hostile provider is a Rust ABI double, not the real C provider or a proof of panic traversal across C. All subprocess gates run under external deadlines; Linux also has container resource/network confinement. The separate strict Rust 1.85.1 package handoff is recorded above. The exact v0.2.0 tag matrix at 5f6fb9655fdec92c57ab71615cfd7bfa8cc76051 supplies current hosted, cross-platform nonignored regression coverage; see the release evidence. Exact Rust 1.85.0, every opt-in sanitizer/tuple corpus, generated-crate registry publication, and formal public profile support remain separate. No public support promotion follows from the prerelease.

The same lower-package boundary harness additionally covers joint host unwind and finalizer failure. Modes 28 and 29 inject a Rust panic immediately after the private owner guard is armed, outside every extern "C" call. The ABI double records and flushes the actual std::thread::panicking() state inside the owner/context finalizers. An owner-drop failure must end after that one drop; a context-close failure after successful owner drop must end after that one close. Exact ordered transcripts forbid length/copy, repeated cleanup, reinitialization, caught-call completion, or outward publication. The healthy unwind case remains mandatory, and every harness/control explicitly compiles with panic=unwind at O0 and O2.

Independent generated-test-file controls suppress only one finalizer's abort response at a time. Ignoring owner-drop uncertainty reaches the still-checked context close and must fail the same oracle for a forbidden later effect; ignoring context-close failure reaches the flushed caller-completion witness and must fail that oracle even when the harness subsequently panics. The original ordinary-error broken-close control remains. A separate pure mutation test rejects missing, duplicated, reordered and extra transcript events. This is generated Rust/ABI-double protocol evidence, not real C-provider cleanup, physical allocator accounting, panic traversal across FFI, OOM recovery, panic=abort recovery, or protection against hostile native machine code.

Historical scoped validation of that joint-failure batch passed all 50 lower-package unit tests on Linux AArch64/Rust 1.88 and macOS AArch64/Rust 1.98. The two new modes run across five owned result shapes (Bytes, Option<Bytes>, Result<Bytes, i64>, UTF-8, and the flat record), at both optimization levels: twenty joint-failure invocations per host, with four additional broken-finalizer control invocations. The same Rust-1.88-built test executable also passes all 50 tests inside the cached Linux Rust 1.85.1 environment, compiling and executing fresh generated SDK and control crates there. This is not a Rust-1.85 build of the root compiler, exact Rust 1.85.0 evidence, or a real C-provider MSRV gate. All runs have external deadlines; the Linux environments have no network, read-only input mounts, and bounded resources. Scoped macOS package Clippy and the two documentation tests pass. The existing frame-product suite also passes on both hosts after retaining its exact original browser provisioning command and adding an independently pinned variant command: nine tests pass, while the three explicitly provisioned TypeScript/sanitizer/npm-installation tests were not selected. Those counts do not describe Windows or unselected gates. The implemented release corpus has the current hosted-green baseline; historical executions retain their actual selected scope.

The complete existing project_v8_npm_and_rust_routes_run_the_same_corpus_before_and_after_display_rename frame-product gate also passes on Linux AArch64/Rust 1.88/Clang 14/Node 24.3 at held parent f725377. It binds actual npm and Rust publications to their retained descriptors/providers and executes the baseline/renamed nine-case corpus and 72-case supplement across interpreter, native O0/O2, raw Wasm and consumers. This direct-consumer run is not npm installation, TypeScript, browser or current-hosted-head evidence.

A separate explicit handoff gate now authenticates those same baseline and display-renamed products with the current Linux AArch64/Rust 1.88 compiler, copies only the two verified seven-file SDKs and four unchanged four-file consumers into a fixed 30-file transfer inventory, and rechecks every source and transferred byte. An independent compiler-free Linux AArch64 environment then passes all four canonical/supplemental consumers under Rust/Cargo 1.85.1 with --locked --offline, a read-only handoff and registry, no checkout mount, no network and a fresh target. The four stdout markers are exact, stderr is empty, and all 30 files remain byte-identical afterward. The publisher still runs on its authenticated native scratch filesystem; transfer uses create_new only after product verification, avoiding unsupported bind-mount publication semantics without weakening publication checks. This is local generated-package and consumer evidence, not a Rust-1.85 compiler build, exact Rust 1.85.0, Windows, hosted, published-SDK or repository-MSRV evidence.

The provisioned Owned Data Browser v1 fixture imports two actual generated packages in the existing three browser projects, with mandatory distinct same-origin URLs and an exact twelve-artifact request inventory. The original four-export direct-Bytes Project is unchanged. A separate two-export Project stages Bytes before Option/Result selection, preserving the existing G410 combined-module and G172 owned-return import boundaries. Separate compiler-side carrier tests bind both fixtures' signatures and verify unconditional variant staging in typed HIR. Browser cases cover capacity, nonzero-offset views, calibrated shrinking/regrowing resizable views, exact hostile-input diagnostics, retained copy independence, both Wasm authentication failures before instantiation, and same-instance recovery. The variant facade executes 96 active/inactive/recovery calls plus four oversized rejection/recovery pairs. Required shared/resizable/transfer features fail closed when unavailable. Both compiler tests pass locally on Linux Rust 1.88 and macOS Rust 1.98. Actual CLI publications passed a local Chromium-only run with cached Playwright 1.62.0 and Chromium 151.0.7922.34, using unchanged test/config copies and retained input bytes. That is not the pinned Playwright 1.55.0 three-browser gate, whose separately provisioned execution cannot be inferred from this local witness. Firefox/WebKit breadth, raw-carrier faults and physical cleanup traces retain their own selected-gate requirements. The implemented release corpus has the current hosted-green baseline. No production, schema, dependency or support-status changes follow from extending this evidence fixture.

Offline installed-package gate

tests/frame_payload_product_v1/npm_installation.rs adds an explicitly provisioned v8 gate for both baseline and display-renamed frame projects. It publishes the real six-file package, checks it against the retained verified inline carrier, and runs offline npm pack. An independent SHA-512 of the actual tarball must match both the pack report and the local dependency's integrity in a closed, two-package-row lockfile before offline npm ci. The lockfile must remain unchanged and all six installed files must equal the retained compiler artifacts.

The consumer imports the installed package by name, resolves its exported Wasm and metadata assets, and runs the unchanged nine-case corpus and 72-case supplement. Strict TypeScript accepts the same package-name import and rejects wrong argument types and unguarded Result access. Provision NODE as an absolute Node executable, NPM_CLI as an absolute npm-cli.js, and TSC_CLI as an absolute TypeScript 5.8.3 tsc.js; invoking both JavaScript tools through Node avoids platform-specific command shims. The existing full-toolchain build prerequisites also apply, including Windows native Cargo/linker provisioning.

cargo test --locked -p semaprax --test frame_payload_product_v1 npm_installation::installed_owned_npm_package_resolves_and_runs_without_compiler -- --ignored --exact

Missing tools fail this selected gate instead of skipping it. Installation and consumption follow package generation without invoking SEMAPRAX or a native compiler; TypeScript is used separately for declaration checking. Offline npm flags, disabled lifecycle scripts, private cache and cleared npm configuration are not OS-level network confinement. This gate passed locally on macOS arm64 with Node 24.3, npm 11.4.2 and TypeScript 5.8.3, for both display names. The separate direct-consumer strict TypeScript gate also passed. The gates cover v8 only and do not establish registry publication or hosted promotion.

Authored same-source Result-extrema gates

tests/support/owned_result_product.rs supplies one canonical two-source v8 Project to the interpreter/native/npm fixture and the private Rust SDK fixture. Its single stable-ID export returns Err(0), Err(i64::MIN) and Err(i64::MAX) for three input lengths, successful copied Bytes for two others, and a genuine division failure after staging Bytes for a sixth. The extrema stay exact integers; JavaScript expectations use decimal strings converted to BigInt, never JSON numbers.

tests/project/owned_result_extrema.rs checks the retained Project HIR in the reference interpreter, actual native providers at O0/O2, and the real six-file npm publication. The native and raw-Wasm observations distinguish successful Err status/tag/payload bits from invocation failure, calibrate real owner allocation/consumption, and require untouched failure outputs and recovery on the same native context or Wasm instance. Native language failure is normalized to status 1; the interpreter and raw Wasm retain division status 4. Interpreter cleanup events describe boundary copy-out, not a physical allocator trace. Provision Clang and Node plus the existing full-toolchain prerequisites for Windows npm publication:

cargo test --locked -p semaprax --test project owned_result_extrema::same_source_result_extrema_match_interpreter_native_and_npm -- --exact

crates/semaprax-toolchain/tests/project_owned_result_extrema_sdk_v1.rs publishes the same source through the real Rust builder and reopens all seven files. It checks the retained descriptor, all parsed manifest facts, inventory hashes and regenerated provider-source binding before running a separately locked/offline, unsafe-forbidden Rust consumer. That consumer distinguishes Ok(Err(...)) from an outer CallError::SemanticFailure, reuses two SDK objects, and retains independent output vectors after both objects are dropped. This is not a new package verifier or evidence that an SDK object retains one physical native context. Provision absolute CLANG and SEMAPRAX_ARCHIVER, native Cargo, and the existing Windows MSVC environment:

cargo test --locked -p semaprax-toolchain --test project_owned_result_extrema_sdk_v1 provisioned_result_extrema_publish_and_run -- --ignored --exact

Both gates passed locally on macOS arm64 with Rust 1.98, Apple Clang 21 and Node 24.3, including the explicitly selected, locked/offline Rust SDK consumer. They add no production ABI, schema, artifact or completion-status change and do not replace sanitizer or exact-head hosted evidence. The interpreter/native/npm gate additionally passes on Linux AArch64 with Rust 1.88, Clang 14 and Node 24.3 at held parent f5cdcc7; that run did not execute this Result-extrema Rust SDK consumer.

Initialized-owner inactive results

The shared tests/support/owned_inactive_product.rs preserves the exact earlier inactive-cleanup Project, canonical source/Graph round-trip and manifest. Both exports initialize Bytes before returning either an active owned value or successful None/Err(-7). This differs from frame/extrema fixtures whose inactive constructors allocate nothing.

tests/project_owned_inactive_cleanup_v1 now derives the actual native provider from the same retained Project and descriptor as its unchanged npm consumer. The native companion wraps that exact provider with the independently calibrated allocator observer, then executes O0/O2 with strict C warnings. Its 96 calls cover both variants and empty, binary/invalid-UTF8, 65,535 and 65,536-byte inputs, with active/inactive/three-byte recovery sequences on one physical context. Immediately after an inactive call returns, before host len/copy/drop or context close, its allocation must already be freed, its pointer and slot inventories must be empty, and no public handle may have been issued. Empty Bytes separately requires one free(NULL) call, not a fictitious payload allocation.

Active controls retain exactly one handle, preserve copied bytes and the output canary, settle once, and reject a second drop without another free. The corpus requires 64 active results, 32 inactive results, 80 physical allocations and 96 finalizer calls; final context closure must add no allocation or free. These observations prove caller-visible settlement timing for this source, not every intermediate store, OOM behavior or sanitizer coverage.

The private toolchain's project_owned_inactive_cleanup_sdk_v1 separately publishes that same Project as a real seven-file Rust package. The existing tuple package's exact inventory/manifest oracle is shared without changing its facts or format. Descriptor and regenerated provider-source bindings are checked before a locked/offline, unsafe-forbidden consumer makes 192 calls using two SDK objects. It distinguishes successful None/Err(-7) from outer call failure, checks exact active/recovery bytes, and retains 128 independent outputs through input mutation and SDK destruction. Package and source bytes are reopened after consumption. This safe consumer is not itself an allocator trace or proof that one SDK object retains a single physical provider context.

Focused gates (external deadlines/resource bounds remain required):

cargo test --locked --offline -p semaprax --test project owned_inactive_cleanup::
cargo test --locked --offline -p semaprax-toolchain --test project_owned_inactive_cleanup_sdk_v1 provisioned_inactive_cleanup_publish_and_run -- --ignored --exact

The first gate requires Node and Clang; the explicitly selected SDK gate requires absolute CLANG and SEMAPRAX_ARCHIVER, native Cargo and the existing Windows MSVC prerequisites. It must not be counted when left ignored. No source language, runtime, descriptor, ABI, generated artifact or public-support change follows from these test-only additions.

The native/npm gate and explicitly selected new SDK gate pass locally on Linux AArch64/Rust 1.88/Clang 14/Node 24.3 and macOS AArch64/Rust 1.98/Apple Clang 21/Node 24.3. The existing v8/v9 tuple SDK gate also passes on both hosts after the shared-oracle extraction. Scoped root/compiler and changed-toolchain-test Clippy passes on macOS. This batch does not execute the new source on Windows, Rust 1.85, real browsers or sanitizers, and does not run the full quality profile or exact-head hosted promotion. In particular, the single-Slice owned-data interpreter gate used by that earlier fixture did not accept its additional Bool parameter. The later retained-Project evaluator below closes that reference-lane gap without changing the original single-Slice entry point or its diagnostics.

Mixed-parameter arity gates

tests/support/owned_mixed_arity_product.rs supplies one canonical v8 Project with nine selected exports, covering every arity from zero through eight. The parameter prefix repeats i64, bool, borrow str, and borrow Slice<u8>; distinct scalar values and borrowed lengths distinguish both positions of each repeated type. Each export returns owned ok or bad bytes according to its present arguments. Result bytes are copied from named local fixed arrays, preserving the language's exact storage-place requirement for borrowed views. Consumer literals are independent of the source predicates.

ProjectRevision::evaluate_public_api_v1 is the authority-free reference lane for this complete v8 signature surface. It independently replays the retained canonical descriptor, requires exact selected-export membership, and validates argument count, type and order before calling the crate-private HIR evaluator. The evaluator admits only the four v8 parameter types and six v8 result types, requires an explicit stable identity and a bounded effect-free, contract-free, acyclic closure, and snapshots borrowed UTF-8 and byte slices before starting the fixed-stack worker. UTF-8 contributes its encoded byte length to the same 65,536-byte cumulative borrowed-input limit. Active Bytes payloads use the existing authenticated copy-out and settlement path; scalar and inactive variant results create no cleanup event. The retained descriptor, rather than caller-supplied metadata or discoverable HIR membership, remains the export authority.

tests/project/owned_mixed_arity_interpreter.rs executes arities zero through eight, repeated same-type position swaps, all four argument and six result shapes, scalar/error extrema, None/Some, Ok/Err, language failure and exact active-owner cleanup. It also checks cumulative UTF-8-plus-slice sizes of 65,535, 65,536 and 65,537 bytes, exact wrong-count/type/order diagnostics, and an explicit retained function that is absent from the selected descriptor. The four focused cases pass locally on macOS arm64; this is not cross-backend, Windows, minimum-Rust, hosted or support-promotion evidence.

The descriptor fixture tests/projections/public_api_descriptor/mixed_arity.rs checks exact parameter order, names, identities, ordinals, result types and replay, including separate seven/eight-parameter selections. A selected ninth parameter must yield the exact SPX-J113 arity diagnostic. The real nine-parameter Project must reject before exposing an authenticated callback and preserve its input files. This callback check is not a physical tool-execution counter.

tests/project/owned_mixed_arity.rs retains the same Project descriptor for actual native providers at O0/O2 and a verified, published six-file npm package. Independent C and Node consumers exercise every arity, wrong-value controls for each present position, same-type argument swaps and healthy recovery. The native fixture separately observes owned allocation/copy/drop and empty context slots; Node checks host-copy independence across runtime objects. These tests establish only their observed argument positions and lengths when executed, not general evaluation order, complete borrowed-content equivalence or browser support.

The private toolchain's project_owned_mixed_arity_sdk_v1 gate publishes the same Project through the real Rust builder, reopens the exact seven-file package and binds its descriptor and provider source. An unsafe-forbidden, locked/offline external consumer calls all nine methods, checks each eight-argument mutation and recovery, and retains independent outputs across two SDK objects and after their disposal. SDK object reuse is not proof of one persistent native context.

Focused gates:

cargo test --locked -p semaprax --test projections public_api_descriptor::mixed_arity
cargo test --locked -p semaprax --test project owned_mixed_arity_interpreter::
cargo test --locked -p semaprax --test project owned_mixed_arity::
cargo test --locked -p semaprax-toolchain --test project_owned_mixed_arity_sdk_v1 provisioned_mixed_arity_publish_and_run -- --ignored --exact

All three gates passed locally on macOS arm64 with Rust 1.98, Apple Clang 21 and Node 24.3 after correcting the fixture's invalid string-literal byte view. The complete descriptor test binary passed all 15 tests; the native/npm and explicitly selected Rust SDK gates each passed their product test. This is local evidence, not Windows, minimum-Rust, browser, sanitizer or hosted validation. A later root native/npm run also passes on Linux AArch64/Rust 1.88, Clang 14 and Node 24.3 at held parent f5cdcc7; that execution did not include the mixed-arity Rust SDK consumer.

Native/npm execution requires Clang and Node, plus the existing full-toolchain prerequisites for Windows npm publication. The selected Rust gate requires absolute CLANG and SEMAPRAX_ARCHIVER, native Cargo and the existing Windows MSVC environment. Missing prerequisites fail; no test silently skips. These fixtures leave bounded temporary evidence trees for inspection. They do not change production code, generated artifacts, schemas or completion status, and do not replace strict TypeScript, installed-package, sanitizer or exact-head hosted gates.

Authentic descriptor capacity regressions

The export-count regression in tests/projections/public_api_descriptor.rs resolves 33 real export declarations. Selections of 31 and 32 derive and replay; selecting all 33 requires SPX-J113 with the exact export-count diagnostic. The previous negative selected a nonexistent extra identity, which could conceal a broken count guard behind a different rejection.

The companion tests/projections/public_api_descriptor/limits.rs changes each of the six literal wire limits by minus one and plus one, independently for v8 and v10. All 24 submissions retain canonical member order and have freshly recomputed, profile-specific digests. Healthy self-replay brackets the mutations; rejection must identify invalid limits rather than a stale digest or unrelated subject. These are descriptor validation checks, not execution at the runtime capacities. All 16 descriptor tests pass in the scoped local batch on macOS/Rust 1.98 and Linux/Rust 1.88; the exact counts remain historical and formal public promotion is separate from the current hosted-green release baseline.

Owned-output capacity evidence boundary

The current admitted byte-operation vocabulary has no concatenation or growth operation: bytes_copy preserves the source extent, ranges cannot enlarge it, and admitted external or fixed-array roots are bounded by 65,536 bytes. The selected v10 closure also rejects compiler-owned String intrinsics. This audit establishes no admitted source construction of a 65,537-byte owned result.

Keep the three observations separate: a real compiled copy can return 65,536 bytes; a 65,537-byte borrowed input rejects before entry; and a test-mutated 65,537-byte output carrier rejects after entry and poisons the facade. The last observation in project_owned_failure_fsm_v1/result.mjs exercises the real decoder, not compiler production of an oversized value. None of these labels relaxes the output bound or grants the full capacity/promotion gate.

Nonclaims

Public Owned Data API v1 does not claim public records or authored variants, nested algebraic data, resources, owned inputs, borrowed outputs, owned UTF-8 strings, mutable/shared values, multiple returns, general generics, lifetime inference, zero-copy transfer, allocator interoperability, callbacks, imports, effects, contracts, async, reentrancy, threads, shared memory, memory growth, WIT/Component Model support, C/C++/Swift/Kotlin bindings, native executable support for Project v8, package resolution, registry publication, signing, provenance, or general public aggregate ABI stability.