* feat: ship the self-hosted native scriptc CLI
- Run the shared compiler and CLI natively, including library builds and compile-time evaluation.
- Install native platform packages and ship relocatable standalone distributions.
- Preserve program semantics and reuse validated build artifacts for fast rebuilds.
* fix: complete native CLI integration and validation
- Preserve library diagnostics and run recursive compiler work on the main stack.
- Restore packaged helper permissions and exercise native npm and Wasm library builds.
- Recover interrupted Sandbox status probes within the original command deadline.
- Remove C emission, debugging options, and automatic backend fallback.
- Complete LLVM lowering and native bootstrap coverage across supported targets.
- Link executables and libraries with precompiled C runtime packs, including iOS and Android.
- Extend native FFI with additional scalar widths and writable byte spans.
- Compile stored text codecs and supported bundled module patterns without a JavaScript engine.
- Document supported limits.
- Pin GNU runtime packs to glibc 2.36 Zig targets and reject incompatible imports.
- Provision verified Zig builds and exercise published artifacts on Debian Bookworm.
Fixes#349
Co-authored-by: Cruel <383999+Cruel@users.noreply.github.com>
Build the Linux LLVM helper and runtime pack before running both test lanes, and align native cache contracts with the current target policy. Full managed Sandbox gate passed.
* Warn on non-null assertions
- Surface non-null assertions during linting without making them blocking.
- Preserve existing assertion sites for opportunistic cleanup.
* Classify internal compiler errors
- Export InternalCompilerError and migrate compiler invariant throws without changing messages.
- Rename the native cache test to match cc.ts and update test scheduling references.
- Document test placement by unit, package integration, and cross-package scope.
* Fix internal compiler error classification
What we did:
- Add the compiler and runtime support required to build the real Portless CLI as a fully static native binary and run its proxy, alias, framework, parallel-registration, and process-cleanup workflows without Node.
- Support Portless's dual HTTP/1.1 and HTTP/2 secure-server graph, including ALPN dispatch, shared request/connect listeners, HTTP/2 CONNECT responses, enableConnectProtocol settings, req.stream access, session errors, and the required ownership and lifecycle handling.
- Lower Portless's indexed absence probes, strict indexed comparisons, optional chains, server options, and container patterns. Preserve Node-style self-reexecution and correctly frame forwarded chunked responses.
- Add focused corpus and server differentials plus an isolated-copy acceptance harness that builds and exercises the pinned Portless checkout in plain and sanitized modes without modifying the external checkout.
- Validate the static binary against Portless's official e2e suite: all 13 files and 16 tests pass.
What we decided was out of scope:
- Broader HTTP/2 client policy, lifecycle compatibility, protocol validation, listener overloads, and unrelated HTTP/2 completeness.
- General runtime-optional soundness beyond the Portless paths. Making that mechanism generally sound requires function-scoped tracking so reused local IDs cannot leak optional state between functions, assignment-aware tracking so writing a definitely present value clears hidden undefined state, and correct preservation across generators, modules, and finally blocks. That larger cross-cutting change remains a dedicated follow-up.
- Removing the self-reexecution heuristic's inherent ambiguity. A direct invocation whose first user argument canonically names the executable is currently treated as Node's repeated script slot and collapsed. An explicit native reexec marker can address that in future work.
* feat: support thread-instanced library state
- Add the abi.instance_per_thread profile field: the archive's TUs compile
with -DSCR_THREAD_INSTANCES, and the SCR_TL qualifier in scr_runtime.h
moves every runtime unit's mutable statics into thread-local storage;
both backends emit the program TU's module globals, run-once guards, and
lazily-compiled regex literal caches thread-local to match
- ONE linked archive then serves one independent instance per embedder
thread through the unchanged entry family: a thread registers its sink
and calls the init entry, and owns its own collector, result arena,
poison flag, and program state — a trap poisons only the instance it
fired in while sibling threads' instances keep answering
- Document the contract beside the profile spec: one instance per thread,
selected implicitly by the calling thread; instance lifetime is the
thread's lifetime; the never-entered-from-two-threads rule is unchanged;
independent of and composable with abi.localize_runtime
- Immutable interned data (string literals, unit arms, template arrays,
vtables) stays shared — Darwin ASan's image-registration common
included, keeping the one-registration-per-image discipline; the
exception cell's current pointer resolves a NULL sentinel in this mode
because a thread-local address is not a constant initializer
- Add the four-thread acceptance probe (distinct per-thread workloads,
concurrent instance-local inits, per-instance collects, a trap delivered
to its own thread's sink exactly once), the composition probe pairing a
thread-instanced localized archive with a second different-prefix
localized archive, an explicit ASan rerun beside the suite-flavor
sanitized builds, and profile-shape coverage; schedule the new lane
contracts beside M1/M2
- Non-opted builds are byte-for-byte unchanged: the qualifier expands to
nothing outside -DSCR_LIB -DSCR_THREAD_INSTANCES (verified object-level
over every touched runtime TU in both default and library flavors)
* fix: keep sanitized runtime-localized archives linkable on ELF
ASan's instrumented globals ride ELF section groups; archives built from
shared runtime objects carry groups with REPEATED signatures, so a process
linking two runtime-localized sanitized archives kept one archive's group
and discarded the other's — whose now-local references then dangled at the
embedder's link. Resolving the groups into the combined relocatable member
(ld -r --force-group-allocation) keeps every archive's copies; the
localization step then demotes them per archive exactly like unsanitized
state. Plain builds carry no section groups, so the flag is inert there.
With the groups resolved, ELF surfaces the same deliberate exception
Mach-O already documented: the image-wide registration guard COMMON stays
shared so the final image registers its ASan globals exactly once — M1/M7
now pin that spelling on both platforms. The explicit ASan pairing (M8)
additionally points Linux LSan away from contractually thread-lifetime
instance state, exactly as the sanitized suite lanes do.
* fix: isolate inspect state per thread
* fix(runtime): share uptime anchor across threads
* feat: support multi-instance library mode via runtime symbol localization
- Add the abi.localize_runtime profile field: the archive build combines the
program object with exactly the runtime/vendor members it reaches and
demotes every external definition except the profile-declared symbols to a
local symbol (darwin: one ld -r pass with -exported_symbols_list; linux:
ld -r then objcopy --keep-global-symbols)
- N archives built under pairwise-distinct prefixes now link into one process
with no symbol collisions and no shared mutable runtime state: each
instance owns a private copy of the allocator, collector, result arena, and
panic sink, so sinks register per instance and a trap poisons only the
instance it fired in
- Document the embedder contract beside the profile spec: one thread per
instance (an instance is never entered from two threads), and values cross
instances only through the embedder's own byte/record marshalling
- Refuse cross-target localized builds with SC3002 (the step runs the host
toolchain's ld/objcopy over host-format objects); absent or false keeps the
classic single-archive artifact byte-for-byte
- Add the two-instance acceptance probe (two archives, two embedder threads,
independent collects, a trap delivered to its own sink exactly once while
the other instance keeps answering) plus symbol-exactness, profile-shape,
and target-posture suites, and schedule the artifact contracts on the gate
host
* fix: tighten runtime localization validation
* fix: harden localized library publication
* Restore sandbox test performance
- Re-enable secure native compiler caching for repo-local test artifacts.
- Isolate strict cache coverage while keeping it off the sandbox critical path.
* fix: respect sandbox test runtime limits
- Run host artifact and ASan contracts on supported platforms with a Sandbox fallback.
- Clear image-seeded workspace files before extracting the dirty worktree.
- Pin current Linux artifact size classes and regression coverage.
- Retain representative Darwin kqueue coverage in the default gate.
- Schedule native runtime tests by host and make Linux clang invocations portable.
- Resolve canonical OCI manifest digests for direct and indexed images.
- Shard portable coverage across 16 sandboxes while retaining focused Darwin contracts.
- Run invariant suites once and keep differential and sanitizer-sensitive coverage in both lanes.
- Harden sandbox transport, exit-status parsing, and Linux runtime test portability.
- Add a custom Node 24 test image with tenant-neutral VCR configuration.
- Shard differential suites across disposable Sandboxes while preserving host-specific coverage.
- Load local agent credentials safely and document the validation workflow.