Represent array holes independently from element storage with an optional runtime presence bitmap. Preserve hole state through length changes, deletion, slicing, concatenation, sorting, copying methods, iteration, serialization, and reference-counted cleanup while retaining packed-array fast paths.
Extend frontend lowering and IR validation for sparse literals, Array length construction, property-presence checks, delete, length assignment, and sparse appends. Add dense-array analysis so proven packed reads can use dedicated unchecked-presence runtime entry points in both native backends.
Add differential corpus coverage, runtime lifecycle tests, IR analysis tests, and compile fences for JavaScript fill loops that cannot prove complete initialization. Update affected binary-size expectations and align structuredClone transfer diagnostics with Node wording.
- Add native RequestInit, AbortSignal, and streaming request and response body support.
- Lower the static fetch surface through both C and LLVM without the embedded engine.
- Add differential, Node-typing, sanitizer, and regression coverage.
- Lower number-array and typed-array value iterators statically.
- Preserve stored iterator cursor and exhaustion state across loops.
- Add Node differential coverage for arrays and Uint8Array.
- Lower asynchronous ESM initialization with Node-compatible dependency ordering and caching.
- Finish top-level promises consistently across the C and LLVM runtimes.
- Add differential coverage for imports, rejection, and unsettled evaluation.
- Normalize Windows paths passed through the TS7 virtual filesystem.
- Emit and launch .exe outputs by default on Windows.
- Add targeted regressions and a Windows GitHub Actions smoke test.
Co-authored-by: Khaled Ghallab <171967089+Khaled-Ghallab@users.noreply.github.com>
- Add a strict versioned manifest and direct C ABI lowering for both backends.
- Link declared native inputs through the CLI and compiler APIs with precise diagnostics.
- Cover the ABI under plain and sanitized integration tests and document its contracts.
- The CA-store surfaces (tlsca.get/root/set) demote the determinism attestation but no fence could deny them: three AMBIENT_SURFACE_FNS rows, one per Node spelling. Split rather than folded into a single "CA store" surface — an author who denies REPLACING the trust anchors is making a different decision from one who denies reading them, and rootCertificates is a value read with no call form to hang a table row on.
- The parity test's full-fence declaration set names the new node-builtin.tls. family; surface-manifest.json regenerated.
- Order-parity baselines for the seven fixtures the two lanes added (2556-2558, 2582-2585). Pure insertions: no recorded baseline moved.
- The written-binding decline yields when the declared type has no mapping or the write's RHS roots at an ambient-undefined name
- A class extending a collection-poisoned base flushes the base's diagnostics eagerly: the heritage evaluates at module init, so deferring the compiler's own fence manufactured a silent wrong output
- trapDeclRootOf's written-binding decline now requires a mappable declared type: ordinary storage only buys anything when it compiles — an unmappable recursive call shape traded the compiling no-storage trap for a guaranteed SC2009 on a value that never exists
- bindingEverWritten skips statement-position writes whose RHS chain roots at an ambient-undefined name: that statement IS the RHS root's throw (lowerExprStatement's first claim) and never touches the target's storage, so it cannot justify the decline
- A poisoned base a top-level class extends flushes its deferred diagnostics eagerly (collectClassShape): the heritage evaluates at module init and the base's fence is the compiler's own — Node defines the base fine — so the deferred trap compiled a binary that refused at startup where Node runs; leaf and derived-only poisoned classes keep the JS deferral
- Fixtures: corpus 2632 (unmappable written trap binding) and 2633 (ambient-rooted rewrite), diagnostics js-extends-poisoned-base (the eager report names the base's real blocker), errors.test pins for both deferral edges that must NOT report eagerly; order-parity baselines recorded for the new entries
- Buffer slice and subarray become true aliasing views over the retained owner — mutating through a view was silently computing wrong bytes
- Each stream tick posts a one-to-one marker on the user tick queue, so stream emissions interleave with process.nextTick in enqueue order, Node's order by construction; the station remains for teardown
- Stream emitters model the pre-created event-key shape governing eventNames order; push honors defaultEncoding with Node's unknown-encoding errors
# Conflicts:
# packages/compiler/test/ts7/baselines/order-parity.json
- The forwarding shape — emit(event, ...args) whose rest appears only as super.emit(event, ...args) — lowers per dispatching event as a real hierarchy method, vtable-participating
- error events keep the throw-when-unhandled path through overrides; super.emit resolves to the nearest override ancestor, JS's chain
- Receivers above every override route through interned instanceOf dispatch; other emitter members and stream-rooted classes keep their fences with reasons stated
# Conflicts:
# packages/compiler/test/ts7/baselines/order-parity.json
- order-parity.json gains 2604-2607 entries (SCRIPTC_UPDATE_BASELINES re-record)
- The '.buffer' SC1090 message now names new DataView(x.buffer, ...) and Buffer.from(x.buffer, ...) as the composed positions and states the subarray-view alternative; snapshot regenerated
- Purely additive: the eight new entries (corpus 2604-2610 and the ee-emit-override diagnostics program) join baselines/order-parity.json; no existing baseline moves.
- Extract preflight's benign-cycle admission (the cheap per-edge rule plus the declaration-only init window analysis, with Tarjan SCC and cluster-verdict memos) into makeCycleAdmission; preflight's static walk and appendDynamicImportModules now judge back edges identically, so benign cycles behind dynamic import() compile as Node cache hits instead of blanket SC1016.
- appendDynamicImportModules runs once in lowerToIr before any pass constructs: the old per-constructor run minted cycle refusals into the discovery pass, whose diagnostics are discarded by design, so inadmissible import() cycles silently compiled; refusals now land on the emit pass with the same narrowed reason (binding and line, or the offending top-level statement) the static walk mints.
- SC1016 gains a registry hint naming the admitted shape and the fix; diagnostics snapshots, order-parity baselines, and the surface manifest repin with it.
- Corpus 2604 (mutual class cycle across two modules), 2605 (three-module function ring with two back edges and a function-body-only value use), 2606 (import() into an admitted mutual-recursion cycle) — all byte-identical to Node through both backends; diagnostics fixture dyn-import-cycle-tdz pins the dynamic-path TDZ refusal.
- Per-API validators in the checked-dynamic lane run Node's argument checks in Node's order, then the real operation or a rendered fence thrown after validation
- fs.exists is genuinely async including the synchronous-false wart; mkdtempSync and lchmod are real
- Destructured sub-namespace bindings resolve as their module; function-armed unions cross into the checked-dynamic world
- dgram state errors carry their ERR_SOCKET codes
# Conflicts:
# packages/compiler/test/ts7/baselines/order-parity.json
- declare-erased roots make every chain rooted there a catchable ReferenceError at first touch, exactly Node's erasure semantics
- Never-read unmappable bindings emit nothing; nullish-cast bindings answer Node's exact TypeError on member access
- Assertion-supplied generic signatures register like annotations and monomorphize per call
- Stdlib generic members take the lib fence naming the member
# Conflicts:
# packages/compiler/src/frontend/lowering/lower-stmts.ts
# packages/compiler/test/ts7/baselines/order-parity.json
- Object.create(null) is a real null-prototype dictionary: inspect, toString, and deepStrictEqual answer Node's forms; the dynamic tier routes to the engine's own Object.create for live delegation
- Object prototypes fence by name in static builds — an own-copy stance is observably wrong under Node's empty-own-set answers and live proto mutations
- entries() and keys() walk any static array live in for-of heads and iterator-helper chains
- Object.assign(target, ...sources) packs spreads with JS's evaluation order before any copy, with V8's position-dependent error texts
# Conflicts:
# packages/compiler/test/ts7/baselines/order-parity.json
# packages/runtime/src/scr_json.c
- 2578 catches the ReferenceError from ambient-rooted optional chains, generic call signatures, method chains, instantiation expressions, trap declarations, and assignment RHS roots
- 2579 pins the uncaught module-level trap: stdout up to the throw, exit 1, dead code past the unwind
- 2580 pins dead unmappable bindings, write-only bindings, and the assertion-shaped generic arrow (called on two instantiations)
- 2581 pins nullish generic bindings: the TypeError messages for null and undefined units, propagation, and nullish-to-nullish writes
- order-parity baselines re-recorded for the four new entries; byte-identical on both backends
- net.createServer with a provably-non-object argument, connect option bags (literal, computed-key, and runtime-record spellings) walking Node's Socket-constructor order — the objectMode trio's ERR_INVALID_ARG_VALUE, validatePort's ERR_SOCKET_BAD_PORT, host's string and autoSelectFamily's boolean contracts — and the autoSelectFamilyAttemptTimeout range ladder (validated and then inert, the single-dial simplification's sibling); setDefaultAutoSelectFamilyAttemptTimeout validates from 1 and keeps Node's sub-10ms floor.
- listen's and dgram.createSocket's options.signal answer validateAbortSignal's ERR_INVALID_ARG_TYPE for provably-non-AbortSignal values; plausible signals keep the fence (abort-driven close has no lowering yet).
- dgram.Socket.send replicates Node's signature shuffle over DOM arguments: slice type/bounds contracts (ERR_BUFFER_OUT_OF_BOUNDS over Buffers, subarrays, DataViews, and strings), the buffer-list per-element contract with the list as the Received tail, the unconnected port ladder with the specific-type tail and trailing period, the null/undefined-only address gate, and the connected-state ERR_SOCKET_DGRAM_IS_CONNECTED arms — a fully-validated unconnected single-payload send RUNS; callback/list/connected forms meet the post-validation fence. The dgram state errors now carry Node's ERR_SOCKET_* codes, and dgram bind/connect/close callbacks accept checked-dynamic wrappers through the dynCheck boundary.
- Corpus 2579 (net, both backends) and 2580 (dgram) pin the ladders byte-identically vs Node; order-parity baselines re-recorded.
- corpus 2578 (TS) and 2579 (JS, the JSDoc @param {object} repro shape) pin typeof/truthiness/String()/===, scalar normalization, representation-free narrowing, and the identity round trip against Node on both backends
- npm case jsval-into-dyn drives the prettier-plugins shape over a real package surface (the new plugstub fixture package: any-declared exports carrying engine functions)
- dyncheck jsval-* tests pin every loud fence (keyed read/write, member calls, 'in', destructuring, JSON.stringify, structuredClone, Object.keys, deepStrictEqual, inspect) plus the RC-clean catch-and-continue unwind under the SAN lane
- the errors.test.ts SC1101 pin flips to the now Node-exact behavior (the retired "one unbridgeable mix": the wrapped argument compiles and the unbound-this read throws Node's own TypeError); ts7 order-parity baselines record the three new fixtures
- The checked-dynamic fs.*Chk lane (JS sources) replicates Node-order argument validation over DOM values: exists/mkdtemp/readFile callback contracts, mkdtemp's prefix slot, assertEncoding on readFile/opendirSync/stream options, watchFile's path/listener pair, createReadStream/createWriteStream's options.fd and path contracts, fs.read's buffer/fd/offset/length/position ladder, and the lchmod family's cb/path/mode ladder with parseFileMode's octal-string and uint32-range arms — each throwing Node's exact ERR_INVALID_ARG_TYPE / ERR_INVALID_ARG_VALUE / ERR_OUT_OF_RANGE texts.
- A validated pass meets the honest tail: the real operation where one exists — fs.exists is REAL now (async answers through the callback, Node's synchronous-false wart for unvalidatable paths kept), mkdtempSync runs through the ladder, lchmodSync/fsPromises.lchmod apply lchmod(2) on macOS and answer Node's not-a-function / ERR_METHOD_NOT_IMPLEMENTED shapes elsewhere — or the compiler-rendered SC2020 fence thrown AFTER validation (scr_throw_lowering_fence), so Node's errors always come first.
- error.propTypeThrow joins argTypeThrow as the property-flavored always-throwing lowered arm; scr_dyn_prop_type_fail / scr_dyn_arg_value_fail / scr_num_received become shared runtime vocabulary for the remaining option-bag ladders.
- Destructured sub-namespace bindings (const { promises } = fs) resolve as the module they are, so fs.promises members reach their lowerings through that spelling.
- Corpus 2578 pins the whole surface byte-identically on both backends; order-parity baselines re-recorded for the new fixture.
- Array patterns over strings split by code points via the string-iterator machinery: positions, holes, defaults, rest, nesting, and for-of heads
- Destructured stdlib-global members bind their builtin identity tokens with Node-agreeing === identity; aliases register the twin
- Surfaced-global members like Math.max fence eagerly by name — a token would quietly degrade them
- Object patterns over strings bind length; wrapper-method extraction names the detached method
# Conflicts:
# packages/compiler/test/ts7/baselines/order-parity.json
- assert-fences drops its non-literal expected-object pin (that form lowers now through the errValue key walk — corpus 2556 pins the behavior); the diagnostics snapshot re-records.
- order-parity baselines re-record for the five new corpus fixtures.
- Array patterns over checker-typed string sources split once through %str.chars (code points, astral characters whole) and ride the array machinery — declarations, assignments, for-of heads in both declaration and expression position, and parameters; object patterns bind the wrapper's one own data property, length, with renames and dead defaults. Static builds claim exactly what staticStringPattern vets; every other string form keeps the engine gate, and --dynamic keeps the engine route wholesale.
- Object patterns over stdlib globals in JavaScript files bind MEMBER identity tokens (const { subtle } = globalThis.crypto, const { Console } = console — 27 of the node suite's 28 SC1031 first-blockers), so programs run past the destructure and each use meets its own per-site fence; globalThis members are provenance-vetted, bind the member global's own token, and register the stdlibGlobalAliasDecl twin, so surfaced members (Math) keep their receiver-keyed lowerings.
- Members of SURFACED globals (Math.max, process.env, console.log) fence eagerly by member and global name instead of degrading detached uses to quiet token reads, and IR-string sources the checker does not type as strings fence naming the checker's type, never the token's carrier.
- Corpus 2556-2558 pin the string forms and the token identity/truthiness/alias agreements under the Node oracle, byte-identical through both backends; errors.test.ts pins the surfaced-global fence and the lazy per-site token failure.
- order-parity baselines re-recorded additively: the new entries plus the 2510-2555 fixtures that landed without one.
- The DataView setter family lands end-to-end; fresh ArrayBuffers erase into zero-filled typed-array views; resizable/shared surfaces fence by name
- Object.is compiles with the spec's SameValue across every kind, including union operands
- Composed en-US Intl.NumberFormat and toLocaleString print byte-exact through the Ryu digit core's shortest-round-trip rounding, 30k-double fuzz-verified; the rest of Intl fences by name with reasons
- DurationFormat deliberately fences: Node throws V8-internal Temporal errors with embedded source paths on plain inputs
# Conflicts:
# packages/compiler/test/ts7/baselines/order-parity.json