- Emit callable Wasm reactors with explicit exports, host callbacks, and independent instance memory.
- Compile three.js scene and geometry workloads into Wasm without an embedded JavaScript engine.
- Document initialization, memory ownership, and external browser hosting.
- Run production scope and closure capture logic with native TypeScript 7 symbols.
- Give lowering caches explicit pass ownership and stable symbol identities.
- Support reference collection arrays and optional Set seeds on both native backends.
* feat(compiler): lower Date.parse through native parser
* feat(compiler): support exit status writes and URL getters
* chore(compat): regenerate static support after upstream changes
* test: update URL fence hint snapshot
* test: record new corpus entries for TS7 parity
* test: record upstream lstat parity entry
* 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
* Support Date instance lowering
- Lower read-only Date values and constructors through the C and LLVM backends.
- Add portable calendar helpers, differential coverage, and documented surface contracts.
- Fence unsupported mutation, identity, locale, and component-constructor forms.
Co-authored-by: sensei-woo <sensei-woo@users.noreply.github.com>
* Fix Date exception and timezone semantics
* fix: harden Date lowering edge cases
* fix Date lowering edge cases
* Fix Date union fences and offset clipping
---------
Co-authored-by: sensei-woo <sensei-woo@users.noreply.github.com>
- Track whether subscriptions_export is explicitly declared and reject dangling names at the profile.
- Preserve optional omission semantics and cover both paths with contract regressions.
- An interval-and-wholeness inference over the lowered IR proves integrality and range for every value reaching a declared i64/u64 slot, with loop-header widening precise enough that the bounded counter loop proves its exact range
- Refusals carry the slot path, the failed obligation with evidence, and the author's concrete fix as SC4021, SC4022, and SC4023
- Declared slots are both obligation and assumption: call sites check arguments, callee bodies assume their classes; integer returns emit exact machine-integer wrappers and inbound params trap through the structured host-contract family
- Math.trunc and Math.ceil compile statically
# Conflicts:
# packages/compiler/src/library/profile.ts
- process.resourceUsage, cpuUsage/threadCpuUsage, constrainedMemory, and the stdio isTTY/columns reads are live ambient state the attestation attested past; their spellings now demote deterministic (flipped attestations are corrections), and each family projects a node-builtin.process.* manifest entry with a reach-witnessing detector, so the §4 invariant holds by construction.
- The dead process.memoryUsage prefix is gone from the scan table, replaced by a comment saying why nothing can match it (no lowering spells it) and what a future lowering owes the table and the projection.
- The parity test covers the new prefixes through the existing node-builtin.process. family fence; the resolve test pins the new ids in the family sweep, and a K14 case pins the teeth end to end: process.stdout.isTTY under the full-fence profile refuses SC4008 naming node-builtin.process.isTTY, both emissions.
- surface-manifest.json regenerated (6 new entries, 342 total).
- LIB_PARAM_CLASSES/LIB_RETURN_CLASSES grow i64/u64 (the prove-or-refuse pair); u8/u32/i32 stay param-only with the message updated to point at the landed machinery
- sidecar.integer_slots declares contract slots by sidecar path (Msg.count, Point.x, helpers.f.params[0], helpers.f.return); the projection spells each declared slot i64 (the frozen format-1 vocabulary — u64 is the stricter compile-time obligation over the same wire spelling), refuses non-number or unresolvable paths, and emits integer_slots as the resolved-decision attestation in declaration order
- compileLibrary runs the integer-boundary inference over export-map and sidecar-declared slots and refuses SC4021 (representability) / SC4022 (wholeness) / SC4023 (range), each carrying slot path, failed obligation with evidence, and the author's fix; u8/u32/i32 plumbing classes seed parameter shapes for free precision
- Both emitters grow i64/u64 wrappers: inbound params range-check through scr_library_i64_in/u64_in (the SC4012 host-contract trap — silent rounding past 2^53 is a coercion the author never wrote), returns convert exactly under the discharged proof
- Profile-loader suite pins the new surface; the pre-ask-4 pins updated
- The ask-5 keys (fences/teachings/remediations) at the profile root refuse SC4001 with a pointer to their determinism.* home; every other unknown root key refuses with the standard unknown-field wording.
- The root goes strict everywhere, not just for the three ask-5 names: profiles pin per compiler release, so an unknown root key is a typo or a misplaced section (a misspelled sidecar would silently drop the contract), never forward-compat surface. All fixture and harness profiles load unchanged under the strict root.
- The check runs after the profile_format gate so a future format still refuses as the wrong format, and the interior of determinism keeps its reserved-and-ignored surface beyond the three ask-5 keys, both pinned by tests.
- The determinism attestation demoted on Date/perf_hooks/process libCalls that had no manifest entry, so the ask-5 §4 invariant (compiles under full fences => deterministic) could not be stated and the spec's own worked-example prefix stdlib.date. refused as unknown; AMBIENT_SURFACE_FNS now projects those families as permanent manifest ids (stdlib.date.*, node-builtin.perf_hooks.performance.now, node-builtin.process.*) with reach-witnessing detectors.
- BUILTIN_MODULE_FN_ALIASES folds the special-cased alternate spellings into their member detectors: the fs Buffer/fd/options/withFileTypes/watch-listener variants, the JS-ladder mkdtempSyncChk and lchmodSyncChk, crypto's composed randomBytesToString, and os.userInfo's userHomedir/userShell scalars.
- A parity test holds the two scans together over the exhaustive IrLibFn registry: every spelling LIB_NONDETERMINISTIC_PREFIXES demotes on must be deniable through a manifest-id fence, with the library-mode-refused and validate-then-fence residue pinned by name with reasons.
- The §4 invariant fixture and K14's worked fences now cover every attestation-known family, and a new K14 case pins the teeth: Date.now / process.env reads under the full-fence profile refuse SC4008 naming the entry instead of attesting deterministic: false post hoc.
- Sampling probes cover the new static entries (Date.now, process.pid, performance.now); surface-manifest.json regenerated (18 new entries, 336 total).
- Profile fences (determinism.fences) resolve at load against this release's surface manifest: exactly one of id/prefix, unknown selectors and unpoliceable static entries refuse SC4001 loudly (ratified strictness), folded constants exempt under a prefix only
- A fenced static surface reached by the compiled library graph refuses SC4008 at the reaching construct, over the same dead-stripped module IR the deterministic attestation reads; unreached fences emit byte-identical code
- The SC4004/SC4005 teaching rider generalizes: one decoration pass attaches profile text to any library refusal by code, manifest id, or fence coverage, rendered as a visibly-attributed note line the renderer prints after the hint
- Teaching/remediation strings now refuse every control byte below 0x20 except newline and cap at 512 UTF-8 bytes; fence remediations feed profileRemediation through covered entry codes
- K14 fence conformance on both emissions, fence-family SC4001 exact-path tests, and the ask-5 §4 pin: the full-fence worked-example profile compiles and attests deterministic: true
- Trap messages assemble as 0x01 text 0x1F code 0x1F symbol with an optional remediation field, built once at export resolution so both backends emit identical bytes
- Thrown messages already leading with the marker pass to the sink verbatim through a length-delimited funnel entry
- Profiles refuse teaching and remediation strings containing the reserved bytes; embedder codes validate only as clean tokens
- A conformance fixture parses the structured bytes with the ten-line host rule and pins printable-first-byte on baseline messages
# Conflicts:
# packages/compiler/src/diagnostics/diagnostic.ts
- A library-mode trap that carries a diagnostic code and/or the trapping symbol is assembled as 0x01 text 0x1F code 0x1F symbol [0x1F remediation]: the teaching text leads so plain-text hosts degrade gracefully, the whole remediation field is absent when the profile supplies none, and the frozen sink signature is untouched — all structure lives in the message bytes. The compiler assembles the buffer once at export resolution (library/trap-teaching.ts), both backends emit the same bytes, and the runtime funnel carries them opaque; the first wired site is the inbound-bytes host-contract trap (new runtime code SC4010), naming the trapping export's C symbol.
- The profile's determinism riders now feed the encoding: teachings gains a remediations sibling, both keyed by code, with keys validated only as tokens free of the reserved bytes (SC space stays the compiler registry's; embedder codes are embedder-prefixed) and values refused at load (SC4001) when they contain 0x01 or 0x1F.
- The escaped-exception renderer honors the verbatim rule: a thrown string or Error message that already begins with 0x01 reaches the sink byte-for-byte — no "Uncaught " prefix, no added newline — which is how facade-authored structured teachings ride the throw channel; everything else keeps the baseline shape, whose printable first byte is what makes the marker unambiguous.
- New K11 conformance fixture (tests/library-mode/teach) drives all of it through a real C host on both emissions: exact structured byte layout via the spec's parse rule, verbatim 0x01-led throws (Error and string), and the printable-first-byte pin on baseline trap and throw messages; library-profile tests cover the remediations round-trip and the reserved-byte refusals.
- The executable lane is untouched: every change sits behind SCR_LIB or the library emission path, verified by byte-identical executable binaries on both backends before and after.
- profile.sidecar declares the echoed constants (wire/abi/snapshot), the identity-getter symbols, the model/msg designations, and the profile-selected "module-graph" source-hash contract; presence turns contract emission on
- wyhash.ts implements wyhash-64 final_version_3 (BigInt, vector-pinned) with the length-prefixed framing the schema's build_id definition requires
- the profile's exact bytes ride the resolved LibraryProfile (build_id input 2), getter symbols join the pairwise-distinct claim set, and unknown fields inside the section refuse as SC4001