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.
* Expand LLVM native output targets
- Add owned helper and runtime-pack contracts for macOS x64, Linux glibc/musl, Windows x64, and WASI.
- Generalize LLVM target selection, package validation, linker plans, and release/CI matrices.
- Document linker boundaries and add focused native-output and runtime-pack coverage.
* Pin Windows LLVM helper CI to VS 2022
The official LLVM archive needs the Visual Studio 2022 CMake generator, which is not guaranteed by windows-latest.
* Align bootstrap cache with LLVM runtime-pack builds
Use the same target-specific helper and linker identity before and after compiler loading so routed executable cache hits remain lightweight.
* Install Windows LLVM CI tools with Chocolatey
windows-2022 includes Visual Studio but not winget; use its available Chocolatey bootstrap for CMake and Ninja.
* Prevent Zig version probes from leaving runtime-pack objects
Run runtime-pack compiler version probes in a private temporary directory and remove the accidental tracked WASI a.o file.
* Use 7-Zip for Windows LLVM setup
Extract the official LLVM development archive with two-stage 7-Zip instead of Windows tar.exe, which timed out while materializing the toolchain tree.
* Define ssize_t for the MSVC runtime pack
Clang's MSVC target does not expose POSIX ssize_t through sys/types.h; define the pointer-sized runtime type without affecting MinGW.
* Build the Windows runtime pack with Zig
Use the MinGW-compatible Windows sysroot required by the runtime while retaining COFF helper output and installing Zig in the Windows native CI lane.
* Give macOS LLVM differential shard time to finish
Shard 1 passed its setup and focused contracts but was cancelled during its cold LLVM differential slice at the 20-minute job limit.
* feat(cli): expose native object link info
- add versioned, cache-independent native link metadata for program objects
- document the experimental runtime ABI and provide C-driver and Apple linker examples
- verify ABI mismatch, FFI parity, packed installs, and external linking in CI
* fix(example): validate native runtime pack identity
- Copy the CLI cache-warming postinstall script before the Docker dependency install layer
- Include the script in the restricted Docker build context
- Add regression coverage for lifecycle-script ordering and context availability
* Fence unsupported Array.from elements
- Share the backend-supported array-element contract across type mapping, callback producers, and IR validation
- Diagnose or defer unsupported Array.from mapper results before emission
- Cover the JavaScript runtime-fence path that previously crashed the C emitter
Co-authored-by: xXCrash2BomberXx <91439080+xXCrash2BomberXx@users.noreply.github.com>
* Fence unsupported array producer results
---------
Co-authored-by: xXCrash2BomberXx <91439080+xXCrash2BomberXx@users.noreply.github.com>
* Reuse reachability lowering output
- Retain reachable IR and assemble the emitted module without lowering bodies a second time
- Preserve reached-only artifact filtering, coverage remainder behavior, and add lowering phase timing
* Preserve record order in retained lowering
* Preserve record order in retained helpers
* Preserve generic lowering record order
* Recheck retained generic rest order
* Record retained lowering parity fixtures
* Preserve retained lowering failure parity
* Split volatile library identity code
- Emit build identity getters from a tiny standalone C translation unit
- Cache generated library program objects independently of volatile identity and archives
- Preserve toolchain, runtime, and translation-unit dependency invalidation coverage
* Preserve library identity during localization
* Keep library identity sources private
* Preserve library identity in public emission
* Preserve identity in kept library units
* Reuse IR across comment-only library edits
- Restore validated lowered IR when TypeScript edits change only non-semantic comments
- Rebase source locations and regenerate exact-source sidecar and build identities
- Add semantic invalidation, integrity, and real-cache coverage
* Fix semantic cache lexical validation
* Use canonical IR version in semantic cache
* Fix semantic cache lexical rebasing
* Fix semantic cache Unicode identifiers
* Optimize same-shape record spreads
- Lower TypeScript record updates through reusable clone helpers
- Outline large record clones in C and LLVM to reduce generated code
- Add ownership, IR, integer-proof, and differential coverage
* Fix cast record spread clone fallback
* fix(runtime): trust Windows root certificates
- Load default TLS roots from the Windows ROOT store.
- Link crypt32 for Windows TLS builds.
- Cover the certificate-store import in cross-build tests.
Co-authored-by: Kayakyx <Kayakyx@users.noreply.github.com>
* fix Windows CA store policy handling
* fix(runtime): cover Windows policy root stores
* fix(runtime): dedupe Windows root stores
* fix(tls): match Windows system CA stores
---------
Co-authored-by: Kayakyx <Kayakyx@users.noreply.github.com>
- Implement the Zig 0.16.0 AArch64 musl runtime and preserve compiler failure diagnostics.
- Promote the target through executable, library, localization, and documentation matrices.
- Verify both backends and the complete arm64 Alpine differential contract.
Co-authored-by: Arth Tyagi <41021374+arthtyagi@users.noreply.github.com>
`.filter(fn)` required the callback to return exactly bool. JS applies
ToBoolean to whatever the predicate answers, so `xs.filter((s) => s)` — the
idiomatic drop-the-falsy — was refused for no semantic reason.
The filter loop now wraps the call in the same toBool an `if` statement would
apply. A bool answer is unchanged and emits identical IR. A union answer
routes through its interned per-arm truthy helper, requested at the call site
where a real node exists for the diagnostic. A unit-only answer is constantly
falsy, and the call still runs for its effects.
The kinds with no native ToBoolean keep the fence: void has no value at all,
and dyn/jsval/caught truthiness needs the embedded engine.
Verified against Node: filtering strings, numbers, and a
`(string | undefined)[]` all print identically in both.
Diagnostics 100, filter corpus 9 across both
backends.
- Bump all published packages and the surface manifest to v0.0.30.
- Promote host-callback channels into the marked release notes.
- Include callback registration in cross-target ABI symbol checks.
* feat: add host-callback channels to library mode
- the profile's `callbacks` array declares named channels and
`abi.callback_register_symbol` names the one registration entry point:
`int32_t <sym>(const char *name, void (*fn)(void), void *ctx)` — 0 on
success, -1 for an unknown or NULL name, latest registration wins, a
NULL fn clears, registrations persist across init/reset. The stored
pointer's typed shape is the channel's with the opaque context first,
the panic sink's layout
- channel signatures ride the existing marshalling classes: params are
f64/bool/string/bytes plus the u8/u32/i32 plumbing classes (outbound
plumbing keeps JS's ToUint32/ToInt32, the executable FFI rule);
returns are scalar only (f64/bool/u8/u32/i32/void — a buffer return
needs an ownership contract the mode does not define). string/bytes
parameters arrive as (ptr, len) pairs borrowed for the call's duration
- compiled code reaches a channel as a signature-only ambient function
declaration whose direct calls deliver synchronously on the calling
thread; the recognition rides the FFI import machinery under a library
flavor: SC4024 refuses a call the channels cannot serve (undeclared
name or off-class signature), unused channels are legal capacity, and
callback-free profiles keep the ambient ReferenceError semantics
- calling an unregistered channel is the SC4025 runtime trap: a detected
trap through the library funnel, so the structured sink message names
the channel in its text and the entry the host called in its symbol
field, and profile teachings/remediations overlay it like the rest of
the runtime family
- registration slots are per copy of the runtime state, the sink's story:
per-archive under abi.localize_runtime (the register symbol joins the
localization keep-list), per-thread instance under
abi.instance_per_thread. The host callback must not reenter any library
entry or unwind across library frames
- both emissions produce identical behavior by construction: the slot
store/fetch lives in scr_library.c (scr_library_cb_set/_require/_ctx),
the generated TU emits the registration dispatch and typed indirect
calls, and the trap text is assembled once at export resolution
- callback-free profiles emit byte-identical program TUs and serialized
IR, and executable builds are byte-identical end to end
- conformance: the CB suite (tests/harness/library-callbacks.test.ts)
covers the acceptance stream, unregistered and pre-registration traps,
symbol exactness, teaching overlays, SC4024 refusals, capacity and
callback-free postures, the localized+thread-instanced composition
probe, and ASan reruns; profile-shape refusals join
library-profile.test.ts
* fix: preserve callback binding identity
* fix: harden library callback contracts
* fix: recognize project callback declarations
* fix: enforce host callback declarations
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: add mobile library targets for iOS and Android
- three library-mode-only triples join SCRIPTC_TARGET:
aarch64-apple-ios, aarch64-apple-ios-simulator (darwin hosts with
Xcode's iPhoneOS/iPhoneSimulator SDKs), and aarch64-linux-android
(any host with an NDK). The consuming pattern is an embedding app
linking profile-configured static archives — Xcode on the Apple side,
Gradle/NDK on the Android side — so the executable lane refuses the
triples with SC3002 and the pointer to --lib
- zig bundles no Apple or bionic libc: resolveCc discovers the sysroot
(xcrun for the selected Apple SDK; ANDROID_NDK_ROOT or the newest
ndk/<version> under the SDK root) and spells it into targetArgs,
where every cache tier already keys it. The canonical LLVM spellings
map to zig's own with the minimum-version floors pinned:
aarch64-ios.15.0[-simulator] stamps LC_BUILD_VERSION minos 15.0 into
every object, aarch64-linux-android.26 pins the bionic stub level an
embedder's minSdkVersion must meet. API 26 bionic carries everything
the library-lane units call (arc4random_buf included), so no shim TU
joins the archive
- localization follows the existing object-format rule: both iOS
platforms ride the Mach-O host-ld64 arm (ld64 reads iOS objects and
preserves platform/minos through the -r merge), Android rides the
cross-ELF arm (zig relocatable merge + in-process demotion) via the
driver's zig spelling. abi.instance_per_thread needed no per-target
work — thread-local statics compile identically on all three
- admission is a pure env/host check ahead of toolchain discovery: an
iOS triple off a darwin host and near-miss mobile spellings refuse
SC3002 with the pairing or the supported set named, in compile() and
compileLibrary() both, decorated by the profile teaching machinery
- library-multi grows the mobile lanes: M12 admission shape always
runs; SCRIPTC_IOS=1 builds localized a/b archives per target and
emission (M1 symbol exactness, ambient audit, version floor), links
probes with the Xcode clang, and EXECUTES the two-instance and
four-thread probes on a booted simulator byte-for-byte against the
desktop expectations (device-arch archives are build+link verified);
SCRIPTC_ANDROID=1 does the same through the NDK clang and an
emulator, reusing a running device or writing and booting a headless
arm64 AVD directly
- the surface manifest's coverage notes record the mobile posture (the
library-admissible surface only; no mobile claim outside it), the
profile spec and the platforms page carry the mobile matrix with the
version floors, and non-mobile builds are unchanged byte-for-byte
* fix: harden mobile target tooling
* Harden mobile target test isolation
* feat: extend runtime symbol localization to Windows hosts and cross targets
- abi.localize_runtime follows the archive's OBJECT FORMAT instead of the
build host: ELF and COFF archives localize from any supported host
(native or cross), Mach-O localization keeps the macOS host linker, and
the SC3002 fence narrows to the pairings that remain — macos targets
off darwin hosts (named in the diagnostic) and hosts outside
darwin/linux/win32
- COFF combine+demote is an in-process transform (object-localize.ts):
no linker offers a COFF relocatable mode (lld-link mirrors MSVC
link.exe; zig's COFF driver refuses multi-object merges) and
llvm-objcopy rejects symbol-scope flags for COFF, so
mergeAndLocalizeCoffObjects performs the staging archive's member
selection, the section merge, cross-object symbol resolution by index,
COMDAT deduplication, and demotion to static over the object bytes;
survivors drop the COMDAT flag so mingw .refptr stubs never
deduplicate against another archive's copies at the embedder's link,
and per-object CodeView sections stay out of the merged member (their
item indices are a per-object contract)
- cross ELF merges through `zig cc -target <triple> -r` (zig is already
the cross driver's hard requirement) and localizeElfObject demotes in
process — locals-first symbol reorder, relocation remap, COMMONs kept
global — resolving section groups the way binutils'
--force-group-allocation does; the darwin ld64 and native-linux
binutils recipes are byte-for-byte the historical ones, and darwin
hosts now admit macos cross triples through the same ld64 arm
- library-multi grows the M10/M11 cross lanes (SCRIPTC_CROSS, with
container and Windows-box execution legs, thread-instanced composition
included), runs M1/M2/M6/M7 on win32 hosts (`zig cc` probes, llvm-nm
symbol checks, CRLF-normalized probe output), and object-localize.test.ts
pins the transforms over synthesized objects in every suite
- non-localized archives are unchanged byte-for-byte
* fix: tighten runtime object localization
* fix: honor COFF COMDAT selection semantics
* test: serialize cross-target library builds
* docs: clarify Windows library link dependencies
* 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