Commit Graph
189 Commits
Author SHA1 Message Date
Chris Tate a2c68beadb The ask-4 conformance corpus end to end, with the sidecar attestation and inbound-trap fixtures
- tests/harness/library-int.test.ts: all 16 reference-corpus cases as library fixtures on both emissions — send/sendU64 are profile-mapped exports with i64/u64 params, PROVE cases pin every crossed value against the Node oracle (the test process runs the same case source), the counter loop crosses 0..9 in order, REFUSE cases name obligation, slot path, and evidence
- int-returns fixture: i64/u64 returns cross as real int64_t/uint64_t (9007199254740991, -0 as 0, -7 % 3 as -1, ToUint32 max on a u64 slot)
- int-trap fixture: inbound integers past 2^53-1 deliver the structured SC4012 host-contract trap with profile teaching/remediation; in-range extremes convert exactly
- Sidecar slots: integer_slots attestation in declaration order, declared slots spelled i64 (V10 bijection validated), unproven writes refused by slot path (Msg.count, helpers.clampIdx.return), unresolvable and non-number declarations refused SC4009, teachings ride SC4022 as attributed notes
- Layer-1 differential: no Layer-1 representation exists (trivially unobservable); pinned consequence — f64-declared vs i64-declared builds cross byte-identical values
- Integer-declared helpers join libRoots so their attestation covers a compiled body, never a dead-stripped vacuity
2026-07-24 11:39:43 -05:00
Chris Tate 10696c70f8 Profile-declared i64/u64 integer slots: surface, wiring, wrappers, host-contract trap
- 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
2026-07-24 11:29:30 -05:00
Chris Tate ced8f52207 The integer-boundary inference over the lowered IR, with the reference corpus as IR-level unit tests
- library/int-infer.ts: interval+wholeness+maybeNaN+spelling domain, JS-exact transfer functions (ToInt32/ToUint32 bitwise contract, JS remainder sign, Math rounding family discharges wholeness), branch refinement on both edges (ordered comparisons exclude NaN; wholeness sharpens strict bounds), loop-header-only threshold widening with body-edge recovery
- Structured-IR fixpoint: scoped walk with join points at if/switch/try merges, per-loop header fixpoint plus a collect pass, break/continue env folding, transitive mutated-global summaries so direct calls havoc precisely
- Interprocedural v1: intraprocedural with declared-slot summaries (declared params seed their class shape; declared returns are assumed at call sites, proven at their own returns)
- numLit carries the source spelling exactly when a decimal integer literal does not round-trip f64 (the representability witness)
- All 16 reference-corpus cases pass at the IR level, the bounded counter loop proving exactly [0, 9]
2026-07-24 11:03:14 -05:00
Chris Tate f28c271784 Math.trunc and Math.ceil compile statically
- New libCalls math.trunc/math.ceil: C trunc()/ceil() are the JS operations, llvm.trunc.f64/llvm.ceil.f64 on the LLVM lane
- Joined STATIC_MATH_FNS (checked before the island table) — they are ask-4's wholeness-discharge operators, so library builds need them compiled
- Surface manifest regenerated: stdlib.math.trunc/ceil move to static
2026-07-24 10:45:01 -05:00
Chris Tate 567af934f1 Release 0.0.10 v0.0.10 2026-07-24 10:03:40 -05:00
Chris Tate c8f2bb2cbe Profiles deny surfaces by manifest id: fences, generalized teachings, and the determinism invariant
- A fences array denies manifest-identified surfaces reached by the compiled library graph: SC4008 names the id and surface with the profile's teaching as an attributed note; unreached fences leave emission byte-identical
- Fence evaluation walks the dead-stripped module IR — the same ground as the deterministic attestation, making the full-fences invariant structural
- Teachings generalize to any refusal code or manifest id; unknown or unpoliceable fence selectors refuse loudly rather than sit inert
- Teaching and remediation strings take the ratified byte constraints and the 512-byte cap everywhere
2026-07-24 09:18:32 -05:00
Chris Tate 72f01a3cea Fence ambient surfaces by manifest id: SC4008 denials, teachings on any refusal
- 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
2026-07-24 09:11:50 -05:00
Chris Tate 4564681774 The stream-ladder fixture tears its socket down deterministically
- The accepted server-side socket destroys on connection: relying on the peer's destroy to drain the server's connection count races the event loop under slow environments
2026-07-24 09:04:54 -05:00
Chris Tate 88ff8eaa60 Library links stay timer-free with the real fs.exists; the regex size arm re-bases
- fs.exists' async fire compiles out under SCR_LIB and the compile-time scan refuses the surface with the event-loop family
- The regex-free size ceiling re-bases +8KB for the engine-handle arms and validation-ladder strings
2026-07-24 08:33:32 -05:00
Chris Tate 8cb44e4345 Record order-parity baselines and the island destructuring fence for the merged train
- Baselines for the renumbered fixtures, purely additive
- iterPack loud-fences engine-held sources instead of claiming not-iterable on values Node iterates
2026-07-24 08:15:35 -05:00
Chris Tate b392ff6af0 Concurrent test-suite flavors stop sharing scratch directories
- Library, npm-static, provenance, and diagnostics suites key their cache dirs by suite flavor, so concurrent plain and sanitized runs never race ar/ranlib
- The differential oracle publish is atomic: write-tmp then rename, so a concurrent reader can't see a truncated file
- Proven with three consecutive concurrent both-flavor rounds, zero failures
2026-07-24 08:09:34 -05:00
Chris Tate a16ee028ee Keyed writes land on dynamic receivers; array destructuring walks dyn sources
- Evolving-any receivers holding checked-dynamic values take keyed writes with ToPropertyKey-exact key spelling; dyn-keyed reads gain the same key stringification
- Array destructuring over dyn sources packs via the spread walk with V8's exact non-iterable TypeError wordings
- The dyn keyed-write miss error appends the primitive's rendering, matching Node

# Conflicts:
#	packages/compiler/src/frontend/lowering/lower-exprs.ts
#	packages/compiler/src/ir/validate.ts
2026-07-24 08:09:34 -05:00
Chris Tate e4bd46c826 fs, net, dgram, tls, and stream misuse throws Node's validation ladders
- 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
2026-07-24 08:07:01 -05:00
Chris Tate c8c8b8634f Ambient roots trap whole chains; dead and nullish generic bindings lower to their runtime truth
- 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
2026-07-24 08:06:21 -05:00
Chris Tate c48a21b9ef Object.create, array entries and keys iterators, and variadic-spread Object.assign
- 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
2026-07-24 08:03:58 -05:00
Chris Tate 6a4376c9ee The string-or-object union family collapses into the checked-dynamic world
- Unions carrying an object/unknown-flavored arm beside dyn-subsumable siblings map to dyn wholesale; typeof and isArray narrowing dispatch natively
- Class instances, Maps, Sets, functions, promises, and regexes stay excluded so typed semantics never degrade; the component fence names the blocking sibling
- A dyn element makes the whole array the DOM value; element reads and writes ride the routed machinery

# Conflicts:
#	tests/harness/dyncheck.test.ts
2026-07-24 08:00:33 -05:00
Chris Tate 613d205a25 Routed operations over engine-held dyn values: keyed access, calls, method dispatch, and nullish tests
- Keyed reads and writes, dynCall, and method dispatch on engine-held values route through the engine, which runs its own prototypes JS-exact
- One generic host shim carries boxed dyn functions into engine calls over the uniform thunk signature
- Nullish coalescing and optional chains unfence for every dyn value, engine-held or not
- Mixed island-vs-DOM deepStrictEqual comparisons loud-fence instead of minting a fabricated failure
- The formatter driver's support slice runs past its flatMap wall
2026-07-24 07:59:12 -05:00
Chris Tate f4ebb76698 The checked-dynamic world gains an engine-handle kind
- SCR_DYN_JSVAL wraps a retained engine cell; scalars normalize to native kinds at the boundary, so only objects, arrays, and functions ever wrap
- typeof, truthiness, strict equality, String(), and Array.isArray/instanceof-Error narrowing route through the engine; every unarmed walker loud-fences by name
- The identity round trip: an engine value crossing into dyn and back is the same engine value, by reference
- The silent-wrong-answer fence box is unreachable from engine members; the LLVM jsMarshal dyn case now mirrors C
2026-07-24 07:58:10 -05:00
Chris Tate 1f9badf573 Key harness scratch dirs by suite flavor so concurrent plain/san runs never share build dirs
- library-mode, library-contract (cache dir plus the tmpdir npm root), and library-asyncfree now carry a plain/san path segment: both flavors run the same ordinary builds, and the nightly's concurrent both-flavor recipe raced ar/ranlib in the shared dirs ("can't open file ... lib.lib.a"); the per-build -san tag stays, it distinguishes explicitly-sanitized builds within one suite
- the same flavor split lands on npm-static's fixed npm-static-workspace dir (the two flavors even build with different sanitize flags there), provenance's shared outDir, and diagnostics' $TMPDIR/scriptc-diag scratch (some entries emit backend artifacts before failing)
- dec-oracle publishes in the differential/llvm/linux/windows lanes are now atomic (write tmp, rename): the content-keyed path is shared across flavors and lanes, and a truncate-and-rewrite could expose a torn oracle to a concurrent reader
- every other suite already keys its build dirs by a content hash that includes the flavor, and the CAS build cache folds the sanitized flags into its key, so those stay as they are
- proof: three consecutive concurrent both-flavor library-mode runs from a wiped cache all pass 45/45 with zero ar/ranlib failures, and a concurrent both-flavor run of all four library suites passes 125/125 in each flavor
2026-07-24 06:08:45 -05:00
Chris Tate 42c2725e5d Collapse string|object-family unions into the checked-dynamic representation, retiring their SC2009 fences
- mapType: a union with an 'object'/'unknown'/'{}'-flavored (dyn) arm beside only dyn-subsumable siblings — scalars, units, dynFrom-convertible records/arrays — maps to DYN wholesale; class/Map/Set/func/promise/regex arms keep their typed homes, and the SC2009 classifier now names the sibling that cannot ride the collapse instead of blaming the dyn arm.
- A dyn ELEMENT makes the whole array the DOM value (unknown[], object[], the plugins-slot (string | object)[]): the DOM array literal builds from TS annotations, .length on collapsed-array receivers is a DOM keyed read, element writes ride dyn.keySet (ARR index set/extend with undefined-hole padding), and for-of over dyn gets a pointed operation fence instead of the stale component story.
- Appendix-A repro 4 stops SC2009-fencing: an island plugins array wraps at the collapsed slot (dynFromJsval) and the element read reaches the loud keyed-read ladder until the routing lane arms it (dyncheck pin jsval-collapsed-union-slot).
- Corpus 2584/2585 differential both backends (guard ladder, option tables, unknown[] first-class; SAN clean); json-dyn snapshot repinned where the unknown[] declaration fence retires; conformance movers verified locally: discriminateObjectTypesOnly, unknownPropertiesAreAssignableToObjectUnion, unknownLikeUnionObjectFlagsNotPropagated.
- SEMANTICS 398 documents the collapse rule, the exact subsumable-arm domain, and the width/identity consequences (deep-copy entry, full-width JSON, per-site fences for non-subsumable values).
2026-07-24 02:54:47 -05:00
Chris Tate abffa3e251 Bring in the SCR_DYN_JSVAL engine-handle kind (world-unification lane 1) — the union collapse needs dyn to hold engine values 2026-07-24 02:54:26 -05:00
Chris Tate abbfcaec1a Corpus fixtures pin the ambient-trap, inert-value, and nullish-binding families
- 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
2026-07-24 02:29:56 -05:00
Chris Tate e81e4f5ab5 Ambient roots trap whole chains; dead and nullish generic bindings lower to their runtime truth
- ambientUndefVarRootOf walks calls, `new`, optional chains, assertions, instantiation expressions, and tagged templates, and accepts `declare function` and trap-binding roots: Node erases the declaration, so the root read IS the crash — lowerCall, member reads, assignments, and variable declarations lower the whole statement to the catchable ReferenceError, arguments never evaluate, and the never-initialized binding registers as a trap whose references can never run
- never-read unmappable bindings with value-only initializers and writes emit nothing: Node builds the value and drops it, so `var xs2: typeof Array;` and the write-only `var f2: { <T, U>(x: T, y: U): T }` compile instead of fencing on a type the program never consumes
- null!/as-any bindings whose types keep generic signatures (or intern empty record shapes) register no storage; generic-method calls and member reads through them compile to Node's exact TypeError, nullish-to-nullish flows to nothing, heritage-clause uses decline the family so mixin resolution keeps its fence, and checked-dynamic (`any`) bindings keep their dyn story untouched
- assertion-shaped generic arrows (`< <T>(x: T) => T >((x) => x)`) register like annotated bindings and monomorphize per call; stdlib generic members (Promise.then, Object.defineProperty) take the SC2020 lib fence, and Function.prototype.apply/call/bind on compiled function values name the direct-call spelling
- diagnostics fixtures that used `declare` to conjure unconstructible values now conjure them by cast so each fence family keeps its pin; snapshots re-recorded, the deferred checker-panic diagnostic now flushes at its first reference as designed
2026-07-24 02:29:48 -05:00
Chris Tate 346a73b7f1 Record order-parity baselines for the tls and stream ladder fixtures 2026-07-24 02:29:09 -05:00
Chris Tate b49134cdcb tls option bags and the stream misuse arms throw Node's validation ladders
- The tls server/secure-context walker validates every present typed option before the pem walk and its fences: the ciphers/passphrase/ecdhCurve string contracts, the engine trio's string-or-null-or-undefined clause, handshakeTimeout/sessionTimeout number contracts with validateInt32's exact range text, ticketKeys' view contract and exactly-48-bytes value ladder (Received renders the byte length, Node's shape), and minVersion/maxVersion's ERR_TLS_INVALID_PROTOCOL_VERSION with %j rendering. Literals carrying a validated key ride whole to the walker (JS sources), and createSecureContext gains the runtime-record form (tls.createSecureContextDyn) — a validated { cert, key } bag builds the real context.
- tls.connect validates checkServerIdentity's function contract with Node's presence semantics (a PRESENT key replaces the builtin verifier even holding undefined — the defaults spread); tls.getCACertificates walks validateString plus the documented name set before its fence.
- stream.finished/stream/promises.finished over a provably-non-stream value throw Node's isNodeStream ERR_INVALID_ARG_TYPE; socket write's two-argument encoding form implements the stream_base typecheck (write(string, 'buffer') is the synchronous "Second argument must be a buffer") with utf8 spellings as the plain write; Readable.toWeb's type option answers Node's one-of ladder.
- Unions with boxable FUNCTION arms now cross into the DOM (canConvertToDyn + both backends' union-to-dyn walkers) — the invalid-input probes iterate [1, null, () => {}, true]; scr_dyn_specific_type renders functions as Node's `function ${name}` (anonymous keeps the trailing space).
- Corpus 2581 (tls) and 2582 (stream, both backends) pin the ladders byte-identically vs Node.
2026-07-24 02:27:38 -05:00
Chris Tate 10c4613f1f net and dgram misuse throws Node's validation ladders instead of fencing
- 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.
2026-07-24 02:02:52 -05:00
Chris Tate cbb567f901 Fixtures for the jsval→DOM crossing: rows 1-3 differential, the fence ladder pinned
- 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
2026-07-24 01:59:28 -05:00
Chris Tate 096a562df6 jsval→dyn edges convert instead of fencing: the dynFromJsval crossing in both backends
- coerceToExpected's expected-dyn/actual-jsval edge, the lib-boundary jsval-into-dyn-slot fence, DOM object-literal members, and index-signature value slots all wrap through the new dynFromJsval IR node — retiring the fence-closure silent-wrong-answer box for jsval members (typeof answered "function" and .length answered 0 there; the box remains only for non-jsval unconvertibles like unboxable-signature functions and func-carrying records)
- both backends emit the wrap (scr_dyn_from_jsval, borrowed operand, +1 out, infallible), and the LLVM jsMarshal gains the missing dyn case (scr_jsval_from_dyn) so dyn→island crossings — the identity unwrap included — stop detouring through the JSON serializer
- the emitted display (sc_ds), keyed-read (sc_dyn_key_get), and iter-N walkers grow JSVAL arms in both backends: engine-routed String(), the loud keyed-read fence with the key named, and the iteration fence instead of a false not-iterable claim
- dynTest/dynHasKey route the representation-free narrowing tests through the engine (typeof object/function, Array.isArray, instanceof Error) and fence 'in' loudly; validator rules pin dynFromJsval to exactly a jsval operand and a dyn result
2026-07-24 01:59:01 -05:00
Chris Tate 2090c8807a The DOM gains the island kind: SCR_DYN_JSVAL wraps engine values by reference
- scr_dyn_from_jsval scalar-normalizes at wrap time (engine numbers/strings/booleans/null/undefined become native DOM kinds through the strict exits), so JSVAL nodes only ever hold engine objects/arrays/functions; the ops install like the promise-release hook, keeping the always-linked DOM core island-free
- typeof, truthiness, String(), and === route to the engine per use (scr_dyn_jsval_ops), the narrowing helpers (scr_dyn_isl_typeof_is/is_array/is_error) answer the engine's truth, and scr_jsval_from_dyn unwraps the SAME cell back — the identity round trip, nested members embedding by reference
- every un-armed DOM walk throws the loud "on an island value held in 'unknown' is not supported yet" ladder: keyed writes, method dispatch, calls, callback checks, 'in', spread, Object.keys/values/entries/hasOwn/assign/defineProperties, JSON.stringify/%j, structuredClone (options included), util.inspect (engine typeof named), deepStrictEqual (engine-identical answers true honestly), and dc subscription — never a silent wrong answer, never a false "is not a function"/"not iterable" claim
- assert's SameValue and strict_eq compare the ENGINE values (two wraps of one value are equal; a DOM copy is a different object, Node's answer too), and failure reports render wrapped operands as the depth-elided [island value] placeholder (the handle stance)
2026-07-24 01:58:31 -05:00
Chris Tate 7995e9b752 Order-parity baselines follow the new fixtures
- Records the ts7 preflight/order canary entries for corpus 2578-2582 and diagnostics object-create-fences; no existing entry changed
2026-07-24 01:54:23 -05:00
Chris Tate ccf0f04d4c fs misuse throws Node's validation ladders instead of fencing
- 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.
2026-07-24 01:33:36 -05:00
Chris Tate 9f422210b1 Object.create(null) lands as the null-prototype dictionary; other prototypes fence by name
- Static builds mint a DOM object flagged prototype-free: own-member walks are already Node's null-proto answers; inspect prefixes [Object: null prototype] (nested/empty/beyond-depth forms), o.toString() throws Node's "is not a function" (dyn.toString carries the source spelling), and deepStrictEqual gains the prototype gate, diff rendering included
- Under --dynamic Object.create routes through the engine's own Object.create for null and engine-held prototypes — live delegation, shadowing writes, and mutation-through-proto all Node-exact
- DOM and static-record prototypes fence with the reason instead of the design doc's own-copy stance: Object.keys/inspect/JSON answer the EMPTY own set in Node and prototype mutations show through live, which no copy answers honestly
- Element writes on plain dyn receivers ride dyn.keySet generally (the result[key] = value memo idiom; unmapped static-any receivers probe their lowered world), unblocking the dictionary's use
- Corpus 2581 (static, byte-for-byte both backends) and 2582 (@dynamic engine route); diagnostics object-create-fences pins the three named fences
- Documented residue: String()/template/join over a null-proto DOM value answer [object Object] where Node throws — the emitted String(unknown) walkers are never-throw by contract
2026-07-24 01:23:17 -05:00
Chris Tate c5a67d24f5 Lower keyed writes and array destructuring over checked-dynamic receivers
- Runtime-keyed writes on receivers that lower dyn (untyped evolving lets holding object literals, JSON.parse results, unknown slots) emit dyn.keySet — number/bool/dyn keys stringify per ToPropertyKey, values convert into the DOM with closures crossing as the callable kind — and the dyn-keyed read stringifies bool/dyn keys the same way, so an object built up through runtime keys dispatches its stored closures back out.
- Array destructuring over dyn sources packs once through the new scr_dyn_iter_pack (arrays element-by-element, strings by code point, bytes by byte) and binds positions as DOM index reads: holes, past-the-end undefined, defaults firing exactly on undefined, and nested patterns all ride it; non-iterable kinds throw V8's exact destructuring TypeError, spelled statically for identifier and identifier-callee sources, kind-worded otherwise.
- dyn.keySet's strict-mode TypeError now quotes the primitive receiver's rendering ("on number '5'"), V8's wording; rest elements over dyn sources and dyn-source defaults that cannot convert into the DOM keep honest fences.
- Fixtures 2578-2581: the warning-catcher harness shape (runtime-keyed writes of closures plus the Object.keys map arm), DOM keyed-write ops with Node's non-object-receiver TypeErrors, the destructure family with all TypeError wordings, and the island keyed write under --dynamic — byte-identical against Node through both backends, plain and sanitized.
2026-07-24 01:11:33 -05:00
Chris Tate 9097b01246 arr.entries() and arr.keys() iterate in for-of heads and seed iterator-helper chains
- Head-consumed keys()/entries() over array receivers ride the live index walk (length re-read per pass — the array iterator's contract), yielding the index or the checker's [number, T] pair; plain [i, v] heads bind straight from the reads, identifier/pattern/var heads bind the interned tuple
- Iterator-helper chains accept entries() as the source: the pair seeds the fused per-element walk, so map/filter/flatMap/take/drop and every terminal compose over [index, element] tuples unchanged
- values() keeps its existing receiver unwrap; dyn receivers keep their loud runtime fence (no dyn for-of iteration exists to ride)
- Corpus 2579 pins the for-of head shapes (liveness, holes, object patterns, let/var) and 2580 the chain matrix, byte-for-byte on both backends
2026-07-24 00:57:31 -05:00
Chris Tate 48f9854fb3 Variadic-spread Object.assign lands over checked-dynamic targets
- Object.assign(target, ...sources) packs every source into one fresh DOM array before any copying (JS's ArgumentListEvaluation: a throwing spread leaves the target untouched), then copies own enumerable keys left to right and answers the target — identity, like JS
- V8's spread TypeError texts split by position: the single-last spread keeps the optimized apply-path texts (nullish spells the expression), every other position takes the iterator-protocol texts describing the value (scr_dyn_pack_push_spread_iter)
- scr_dyn_assign's copy walk now rides the entries walk, so array/string/bytes sources contribute their index keys exactly as Object.keys lists them (two-arg form included)
- Targets: dyn values, fresh object literals (no alias exists — the DOM build is unobservable), and nullish units (Node's ToObject TypeError, catchably)
- Corpus 2578 pins the support.js shape, identity, ordering, source-kind matrix, and every error text byte-for-byte on both backends
2026-07-24 00:50:02 -05:00
Chris Tate 242ad7e117 Release 0.0.9 v0.0.9 2026-07-24 00:28:26 -05:00
Chris Tate 4d3ee3fffd Strings destructure through their iterator; stdlib globals destructure as identity tokens
- 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
2026-07-23 23:53:08 -05:00
Chris Tate 0423093a99 Node's validation ladders throw where implemented APIs were fenced
- Buffer compare/equals/constructor ladders, URLSearchParams WHATWG brand checks and arity ladders, URL.revokeObjectURL arity, and the max-listeners family answer Node's exact typed errors
- ToPrimitive string-hint coercion runs user toString/valueOf with throw propagation; assert.throws accepts expected-object variables
- Reusable always-throwing libCall shapes (error.nodeThrow, error.argTypeThrow) seed the remaining validation-ladder work
- Two emittedReadable lifecycle bugs fixed; ERR_* codes stamped across the bytes/crypto/fs range ladders

# Conflicts:
#	packages/compiler/test/ts7/baselines/order-parity.json
2026-07-23 23:37:03 -05:00
Chris Tate e56371e6cc Test scaffolding follows the new fixtures
- 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.
2026-07-23 23:05:02 -05:00
Chris Tate b06540dce6 The max-listeners argument ladders answer Node's exact errors
- Instance setMaxListeners over a non-number routes through the checked-dynamic ladder (emitter.setMaxChk): ERR_INVALID_ARG_TYPE with the rendered Received tail, the existing ERR_OUT_OF_RANGE range gate for numbers, and a well-typed dyn still applies.
- events.defaultMaxListeners is a real module property now: reads answer the process-wide default, writes (statement and expression position) validate through emitter.setDefaultMaxChk with Node's own message slot ("defaultMaxListeners"); the qualified static EventEmitter.setMaxListeners(n) shares the ladder under its "setMaxListeners" slot, and the per-target static form with a provably-non-emitter target throws ERR_INVALID_ARG_TYPE on "eventTargets".
- error.argTypeThrow joins error.nodeThrow as the generic always-throwing lowered arm whose Received tail renders at runtime.
- Corpus 2560 pins the ladders byte-identically on both backends.
2026-07-23 22:55:52 -05:00
Chris Tate a6f43649c5 URL.revokeObjectURL's arity contract and fs._toUnixTimestamp
- URL.revokeObjectURL() with no argument throws Node's ERR_MISSING_ARGS ('The "url" argument must be specified') — the check runs before any registry lookup, so the zero-argument contract is exact without blob machinery; the one-argument form and createObjectURL keep their fences.
- fs._toUnixTimestamp lowers over a DOM time value: numeric strings pass ToNumber's loose-equality gate, finite numbers pass (negatives answer now/1000, Node's shape), and everything else throws Node's exact ERR_INVALID_ARG_TYPE with the rendered Received tail.
- Corpus 2559 pins both ladders byte-identically on both backends.
2026-07-23 22:42:55 -05:00
Chris Tate ccb4cfa1ae The emittedReadable flag follows Node's emitReadable_/read() lifecycle
- emitReadable_ clears emittedReadable AFTER the 'readable' emit and only when it really fired — a listener observes true during the pass, exactly Node's readable.js.
- read() clears the flag for absent sizes too (Node's `if (n !== 0)` sees NaN there); only read(0) leaves it standing.
- Corpus 2558 pins the lifecycle byte-identically on both backends. The suite's needReadable/resumeScheduled probes remain blocked by the documented stream-tick station divergence (stream ticks drain at the next checkpoint instead of interleaving the user nextTick queue), not by flag semantics.
2026-07-23 22:34:03 -05:00
Chris Tate c82a67f823 Destructure strings through their iterator and stdlib globals as member identity tokens
- 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.
2026-07-23 22:30:58 -05:00
Chris Tate 4656cab090 Record order-parity baselines for the renumbered and new fixtures 2026-07-23 22:26:52 -05:00
Chris Tate 528ef595d4 URLSearchParams' WHATWG argument ladders answer Node's exact errors
- Method values through Function.prototype.call/apply with a receiver that is provably not a URLSearchParams throw ERR_INVALID_THIS ('Value of "this" must be of type URLSearchParams') — the brand check runs before any conversion; searchParams-typed and dyn receivers keep their existing paths.
- Too few arguments throw ERR_MISSING_ARGS with Node's per-method messages before any conversion (the WHATWG arity ladder).
- Name/value slots convert with ToPrimitive's string hint: statically-string args lower directly, symbols throw V8's 'Cannot convert a Symbol value to a string' TypeError, and every other value coerces through the DOM — a user toString/valueOf member is CALLED and its throw propagates (scr_dyn_string_coerce_js, the new dyn.toStringCoerce libCall); func-carrying records box just their toString member into a DOM carrier.
- error.nodeThrow is the new compiler-resolved Node-parity throw for always-throwing lowered arms (the global.undefRead polymorphic-result pattern), shared by these ladders and future ones.
- Corpus 2557 pins the whole surface byte-identically on both backends, including the stringifier's post-sort re-serialization.
2026-07-23 22:23:26 -05:00
Chris Tate fc1f7c212f The C lane compiles without strict aliasing: the punned object header is one effective type
- Upcasts reinterpret derived pointers as base structs, so one object's rc/vt header is legally accessed through two struct types only without TBAA
- clang -O2 elided refcount updates under the aliasing assumption, freeing objects still owned through a base-typed view; the LLVM lane emits no TBAA and was immune
- -fno-strict-aliasing lands on all three compile paths, the standard posture for refcounted-header C object systems
- The regression fixture SIGSEGVs without the flag
2026-07-23 22:22:23 -05:00
Chris Tate ad834307b1 Spread arguments land outside typed rest slots; LLVM promise.reject takes dyn reasons
- Spread calls build one fresh argument array with JS's left-to-right evaluation, on both backends and under --dynamic, with V8's exact non-iterable TypeError texts
- Fence lambdas inside rest arrows spell the hidden rest slot, curing an ICE the destructuring promotions exposed
- The LLVM promise.reject lowering admits dyn reasons, mirroring the C backend and the IR contract
2026-07-23 22:21:53 -05:00
Chris Tate f8b36d9f74 stream/promises compiles statically; out-of-scope modules refuse with named reasons
- pipeline and finished settle real promises over the existing watcher machinery, on both backends
- domain, v8, inspector, node:sqlite, and the underscore-prefixed internals each name why a compiled binary cannot provide them
- stream/web, the Console class, and dns/promises stay honest not-yets with documented paths
- The SC1010 hint gains stream/promises and the long-missing querystring
2026-07-23 22:21:31 -05:00
Chris Tate fa847e2105 DataView setters, fresh-ArrayBuffer erasure, Object.is, and the en-US Intl slice
- 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
2026-07-23 22:20:44 -05:00
Chris Tate d7aee7e36d Record width composes with hybrid shapes; index signatures carry functions, Maps, and Sets
- Hybrid records width-coerce in both directions: declared fields copy off struct slots, overflow drops or carries per the target shape
- Per-field lifts cover unknown destinations, derived-to-base upcasts, and clean function adapters, composing recursively
- The overflow store admits func, Map, and Set values; the keyed-miss trap can now describe them (a C-backend ICE fixed)
- Every remaining width and index-signature fence names its first blocking rule
2026-07-23 22:20:11 -05:00