js: the reads round — flat round_trip 1.21x, derived read 2.01 -> 2.89 M msg/s; 318% -> 262% of generated C++ - #244
Merged
Merged
Conversation
|
All contributors have signed the CAA. Thank you. |
gafferongames
force-pushed
the
js-reads-round
branch
from
September 1, 2026 15:30
ee8ad87 to
7f2dc53
Compare
The flat tier's read side reloaded a 64-bit window per field. One window carries exactly 32 valid bits from the cursor, so consecutive fields whose widths sum to 32 or less all extract from the SAME `out` at literal RELATIVE shifts — static even where the absolute cursor is dynamic, which is what reaches the loop bodies. On bench_mixed the stats element goes 2 loads to 1 and the entity element 14 to 5. While a window is open the cursor lags by the bits already served, so pf — the single emission choke point — settles it before any text that names br or that opens or closes a scope. The one exception is the value-refusal guard, which carries braces but only tests v/bg and only returns false: it cannot read the cursor and cannot fall through with the window stale, and it panics if its condition names br. A window also never joins across an indent change. Paired instrument, single-path runs, arm rotation, max of 7 rounds, three invocations each: read 1.3151/1.3168/1.3152 against a +/-0.9% A/A null, round_trip 1.1765/1.1779/1.1808 against +/-0.3%, write 0.9986 (untouched). Negative control: with the relative shift off by one bit, test/js prints 93 FAILED lines and exits 1. Differential against origin/main's readers over the pinned corpus, its mutations and random buffers: 820,160 cases per mode, zero divergences in verdict, fields and cross read-back, both NODE_ENV modes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A fresh profile of the post-chunking floor put the largest single line at `value.Flux = -2^100n + bg` (11.1% of read ticks), with the two 128-bit assemblies at 7.1%. A 128-bit-domain BigInt op is multi-digit and allocating, and the shape cost a second getBigUint64, a shift by 64, an or, a BigInt comparison and a BigInt add. When a wide field is over 64 bits and its high half is at most 53 bits, that half is an exact Number. The range refusal then splits across the halves — numeric on the high, the low comparison only on the exact boundary — the offset is a numeric add, and exactly one signed 64-bit BigInt comes out of the scratch. Conditions, all checked in the emitter: bits in (64, 117]; min a nonzero multiple of 2^64, so the offset touches only the high half and the low 64 bits pass through with no borrow; min's high half and the adjusted high half both inside 2^53. Every other wide shape keeps the general path. The high word is `(nw - nl) / 4294967296` with `nl = nw >>> 0`, not a rounding function of nw / 2^32: `nw - nl` is an exact multiple of 2^32, so the division is exact and no rounding mode enters the argument. read 1.0781 / 1.0766 / 1.0742 against a +/-0.9% null, round_trip 1.0444 / 1.0430 / 1.0443 against +/-0.3%. Cumulative for the branch against origin/main: read 1.4199 / 1.4175 / 1.4185, round_trip 1.2250 / 1.2286 / 1.2305. The negative control found a hole in the oracles. With the high word taken as Math.trunc(nw / 2^32) — wrong exactly when the adjusted high half is negative and not a multiple of 2^32 — test/js stayed green AND the buffer-mutation differential stayed green across 189,120 cases: BenchMixed's header carries a pinned magic constant, so no random or bit-flipped buffer ever reaches a field, and the corpus's own Flux values all sit above zero. Seeded INSTANCE mutation reaches it: perturb one leaf of a decoded instance across its own domain, re-encode through the untouched writer, run both readers. One leaf at a time is load-bearing — the checked writer refuses a whole instance for any single out-of-contract field. On that oracle the trunc control goes red at once on BenchMixed.Flux, and a direct probe of the band shows 7 of 11 values decoding wrong. Restored: green. Both oracles, both NODE_ENV modes, against origin/main's readers: 152,000 single-leaf instance mutations and 263,360 buffer cases per mode, zero divergences. Nine-leg make test green; testdata/wire untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…l named Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The attribution paragraph quoted 1.0248x for "the emitter lands nothing on family bits" — computed from the two bitpacker write rows the same document declares INVALID at 47.7% and 49.3% spread. §2.3 is absolute: an invalid row does not become usable by being cited for a small effect rather than a large one. The figure is gone; the claim rests on the mechanism (the generated flat tier imports nothing) and on the paired leg's own valid bitpacker row. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gafferongames
force-pushed
the
js-reads-round
branch
from
September 1, 2026 16:10
c6cc29f to
99b5929
Compare
gafferongames
marked this pull request as ready for review
September 1, 2026 16:12
Contributor
Author
|
Adversarially reviewed as a pair with serialize.js#11: mechanical audit of all 852 window extractions across 114 generated read functions (zero violations), the brace-lock proven load-bearing by sabotage, the L2 number-domain boundary probed at every edge with the oracle asymmetry reproduced exactly (buffer oracle blind, instance oracle red — the round's own finding), an independent 160k-case pair differential at zero divergence with all 240 write functions proven structurally untouched, and every number recomputed to four decimals including the published A/A nulls. Verdict: MERGE. |
This was referenced Sep 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The READS round for generated JavaScript — the follow-on schema#237 named
("read-side window chunking"), plus the lever the fresh profile found under it.
Its runtime twin is mas-bandwidth/serialize.js#11; the two PRs
pair (see "Pairing" below).
Headline (
bench/run.sh --only js, the FULL leg — 1 warmup + 7 measuredruns per §2.1, not
--quick— before and after in one sitting,bench_mixed,family
gen, codecflat,checks=contract, corpus6b213fbfa1a03a99, maxrates per §2.2):
Against generated C++ at the same
corpus_id: 318.2% → 262.4% on thissitting's ledger denominator (
cpp bench_mixed round_tripmax 3,579,797 from2026-09-01-sitting3), or 312.1% → 257.4% on the LOCKed sitting-2 reference(3,512,100, untouched by this round). The before leg reproduces the standing
ledger row to 0.02% (1,125,162 vs 1,124,935). Derived read 2.01 → 2.89 M
msg/s. Measurement CSVs live outside
bench/results/(scratch, per theround's rules);
ROUND-LOG.mdcarries their paths and every row verbatim.1. The instrument first — A/A NULL before any number
A paired instrument times ONE path per invocation over two arms loaded as
separate ES modules, each arm's timing loop built from its own source text so
the two never share a SharedFunctionInfo or a feedback vector; arm order
rotates by round parity; the statistic is the max of 7 rounds. Every pair run
gates first: both arms decode all 64 variants, agree field-for-field, and
re-encode byte-identically — non-equivalent arms are never timed.
The write path carries a consistent ~0.6% bias to arm A across all three
invocations, so a write claim on this instrument would need ~2%. This round
makes none. Corroboration that the instrument measures the shipped thing:
its pure-read arm at
origin/mainprints 2.00 M msg/s — #237's derived-readfigure, from a different harness.
2. MEASURE FIRST — where read time actually was
node --profandnode --cpu-profover a pure read loop, 4M iterations,production mode, node 26.7, M2: 78.9% inside
ReadBenchMixedFlatitself,19.0% in V8 runtime calls made from it (BigInt traffic; macOS renders them
as one bogus nearest-symbol, exactly as #237 recorded), GC 3.2–3.8%. Line
ticks put ~30% in the
Statsloop (two full window loads per 18-bit element,80 elements per message) and 14 window loads per entity. The named candidate
is where the time is.
3. The levers
L1 — read-side window chunking. One 64-bit pair load carries exactly 32
valid bits from the cursor, so consecutive fields whose widths sum to ≤ 32 all
extract from the SAME
outat literal RELATIVE shifts — static even where theabsolute cursor is dynamic, which is what reaches the loop bodies. The stats
element goes 2 loads → 1, the entity element 14 → 5. Prototyped first as a
transformer over the generated file (ceiling: read 1.29x) before any emitter
work. read 1.3151 / 1.3168 / 1.3152 (null ±0.9%), round_trip 1.1765 /
1.1779 / 1.1808 (null ±0.3%), write 0.9986.
Safety by construction, not inspection: while a window is open the cursor
brLAGS by the bits already served, so
pf— the single emission choke point —settles the window before any text that names
bror that opens or closes ascope. The one deliberate exception is the value-refusal guard, which carries
braces but only tests
v/bgand onlyreturn falses: it cannot read thecursor and cannot fall through with the window stale, and it panics if its
condition names
br. A second lock: a window never joins across an indentchange.
L2 — wide offset fields decoded in the number domain. A fresh profile of
the post-L1 floor put the largest single line at
value.Flux = -2^100n + bg(11.1%). When a wide field is over 64 bits and its high half is ≤ 53 bits,
that half is an exact Number: the range refusal splits across the halves, the
offset is a numeric add, and exactly one signed 64-bit BigInt comes out of the
scratch. Conditions, all checked in the emitter: bits in (64, 117];
minanonzero multiple of 2^64 (so the offset touches only the high half, no
borrow);
min's high half and the adjusted high half both inside 2^53. Everyother wide shape keeps the general path — extending it is a named follow-on.
The high word is
(nw - nl) / 4294967296withnl = nw >>> 0, not a roundingfunction of
nw / 2^32:nw - nlis an exact multiple of 2^32, so norounding mode enters the argument at all. read 1.0781 / 1.0766 / 1.0742,
round_trip 1.0444 / 1.0430 / 1.0443.
Refused by measurement
one the byte index has advanced by exactly 4, so the previous
whiIS thenew
wloands2is unchanged: one move and one load instead of two loads.Prototyped, 20 windows carried, wire gate 64/64 byte-identical. 1.0060,
1.0123, 1.0039 against a ±0.9% null — two of three inside it. After L1 the
read path is not load-bound.
e0.Damage = BigInt(v): a frozen 256-entry array indexed instead ofconstructed. 0.9718, 0.9709, 0.9706 — measurably SLOWER. V8's
BigInt(smallNumber)beats a heap-array load of a shared BigInt; the tablelever does not transfer from the BEAM to V8.
bg > Rncomparisons removed outright — 1.0083, 1.0060, inside the null. A BigInt
comparison allocates nothing. Folded into L2 where it is free; never pursued
alone.
WorldTime, raw range 2×10^12,well inside 2^53): ceiling with the refusal AND the add removed outright —
0.9953, 0.9995, inside the null. Only the 128-bit domain pays, which is
why L2 is gated at
bits > 64and not at "fits in 2^53".4. Discipline — and one finding about the gates themselves
make testgreen;testdata/wireuntouched(the re-pin commits touch SOURCE goldens only); both NODE_ENV modes;
corpus_id 6b213fbfa1a03a99on every leg.test/jsprints 93 FAILED lines and exits 1. Restored, green, regeneratedtree byte-identical.
part of the work. With the high word taken as
Math.trunc(nw / 2^32)—wrong exactly when the adjusted high half is negative and not a multiple of
2^32 —
test/jsstayed green AND the buffer-mutation differential stayedgreen across 189,120 cases. Neither can reach that band:
BenchMixed'sheader carries a pinned magic constant, so no random or bit-flipped buffer
reaches a field at all, and the corpus's own
Fluxvalues all sit abovezero. Seeded INSTANCE mutation reaches it — decode a pinned instance,
perturb ONE leaf across its own domain, re-encode through the writer this
round does not touch, run both readers. One leaf at a time is the
load-bearing detail: the checked writer refuses a whole instance for any
single out-of-contract field, so mutating everything at once produces
refusals and the deep domains never encode. On that oracle the control goes
red at once on
BenchMixed.Flux, and a direct probe of the band shows 7 of11 values decoding wrong.
origin/main's readers:820,160 buffer cases and 152,000 single-leaf instance mutations per mode,
zero divergences in verdict, fields (bit-exact, so −0 and NaN payloads
count) and cross read-back.
is not deterministic across module instances: an A/A null (origin/main vs a
byte-identical copy) printed 3 re-encode divergences in one invocation and 0
in the next, always at float NaN sites — V8 does not promise to preserve a
NaN's payload as a JS number travels through heap numbers, unboxed double
fields and DataView stores. The leg now SKIPS NaN-bearing values and says
how many, and with that exclusion the A/A null is a deterministic zero
across three consecutive invocations. That is what makes the branch's zero
mean anything.
printed the
bitpackerwrite row at 47.7% and 49.3% spread — over §2.3's40% INVALID threshold — so no ratio is taken from them, and the 1.16x that
arithmetic would give is NOT published here.
same instrument.
ROUND-LOG.mdis the round's ledger.go vet, golangci-lint (0 issues), modernize, shapegate — all clean locally.
bench/LOCKuntouched: nothing underinternal/codegen/{c,cpp}orgenerated/{c,cpp,c-ludicrous}moved.5. Pairing
The generated flat tier imports nothing, so the two halves do not overlap and
the certification pair shows it: the runtime lever adds nothing to
round_trip(1.2126x emitter-only, 1.2123x paired), and the emitter landsnothing on family
bits— no figure is quoted for that last claim, becausethe only rows that could produce one are the two this PR declares INVALID at
47.7%/49.3% spread, and §2.3 is absolute: an invalid row does not become
usable by being cited for a small effect rather than a large one. The claim
rests on the mechanism and on the paired leg's valid bitpacker row. schema's
test/js,test/js-ludicrous(both modes)and the bench leg all run green against the serialize.js branch through the
§3.5
SERIALIZE_JSoverride.6. Follow-ons, named not done
SERIALIZE_JS_TAG: v1.1.0. Bumpingit after BitWriter: single-word 32-bit staging — family bits 1.18x, writeBytes 1.37x serialize.js#11 lands is a separate change; nothing
in this PR depends on it.
RealPacket. Themagic-header blind spot this round found in
BenchMixedis a CLASS, andRealWorldFlatis in it: over 400 random buffers the random-buffer oracleaccepts
RealPacket0 times, exactly as it acceptsBenchMixed0 andBenchPacket0 — a pinned header constant refuses every one before a fieldis read. To be precise about what that does and does not leave uncovered:
single-leaf instance mutation already reaches
RealPacket— it took 611encoded mutations at 2 seeds and ~1,500 at the 5 this round ran, and it is
under the same zero-divergence result as everything else. What is thin is
its SEED SET: only 1 of the 24 pinned buffers decodes as a
RealPacket, sothe whole mutation walk starts from a single point, where
BenchMixedgets2 and the shallow shapes get 23. Widening that seed set (or pinning a second
RealPacketinstance) is the actual work, and it is worth doing for theclass rather than for this shape.
🤖 Generated with Claude Code