Skip to content

Fix deterministic inference and portable VCR storage - #100

Merged
bsbodden merged 78 commits into
mainfrom
fix/bonsai-activation
Oct 15, 2026
Merged

bsbodden merged 78 commits into
mainfrom
fix/bonsai-activation

Conversation

@bsbodden

@bsbodden bsbodden commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

Correct cold/compiled and sequential/batched inference differences with fixed activation arithmetic and preserved reduction order. The ARM 128-bit path now uses explicit SLEEF EXP/LOG recipes with matching scalar activation tails. Other supported paths retain fixed float SwiGLU arithmetic and the existing overlap handling. Upstream permissive notices are packaged with the runtime.

The branch also repairs nested executor dispatch and storage range overflow. Local VCR storage preserves logical keys with portable filesystem names, migrates legacy recordings, and preserves real durability failures. Mockito and test/JMH dependency locks are aligned with JDK 25; production dependency configurations are unchanged.

The integrated source builds the actual core JAR 19a466f8e1199b4c8476a810faccaa0f7a0e296ccedef3901eab56e321497659. All 86 class entries are byte-identical to the frozen, measured e249e91455f6800260e61d9c3d3a5e9822c7be45fabd1219d3f659dc037501c6 candidate; only META-INF/NOTICE changed to remove stale diagnostic wording. The original measured artifact and the release-review artifact have separate manifests.

Validation: the actual Gradle JAR and formatting checks pass, as do the three focused activation tests. The unchanged MFCQI gate passes at 0.722 against 0.70 after expressing the same mathematical coefficient as an exact hexadecimal float; all compiled bytes are unchanged. The combined test-only repair passes an independent full core check with 1,673 tests and 80.8861% instruction coverage against the unchanged threshold. Fresh ARM/x86 checks of that exact test set and the composed whole-model campaigns are running. The unchanged storage/VCR/test-dependency integration previously passed 371 affected tests; Windows/Linux validation passed 222 tests per platform with long-path support disabled. Those results cover their specific unchanged source, not the new activation path.

Draft: release qualification remains incomplete. Successful numerical or preflight checks do not clear the fixed task-quality, latency, allocation, startup, RSS, or statistical-precision gates. In particular, x86 small-Qwen task quality remains unresolved. The final ARM small-Qwen fixed 148-case cohort passes: candidate and published control both score 90/148, with identical labels on every case and exact native/Java control vectors. ARM 4B, Q5_1, and complete resource results remain pending. Failed experiments and raw evidence remain archived outside the production tree; no thresholds or sample counts were relaxed.

Vectors must complete its supported-platform and release gates before publication. Models and ModelJars follow only after verifying the actual upstream artifacts on Central. No cleanup release has been published.

@bsbodden bsbodden changed the title Fix reproducible SwiGLU for Bonsai native batch parity Isolate SwiGLU reproducibility; Bonsai failure remains Oct 12, 2026
@bsbodden bsbodden changed the title Isolate SwiGLU reproducibility; Bonsai failure remains Fix Bonsai Qwen35 activation determinism across native prefill paths Oct 12, 2026
@bsbodden bsbodden changed the title Fix Bonsai Qwen35 activation determinism across native prefill paths Fix Bonsai activation and BF16 full-logit determinism Oct 12, 2026
… contract

Candidate pending supported-host performance qualification. Replace the unreleased exact-exp oracle with the released 2e-6 convolution accuracy contract while preserving exact cold/hot, persistent-state and alias-order checks. Retain active SwiGLU arithmetic and remove its unreachable exp helper branch. Preserve rejected controls and measurement receipts outside the project repository.
Use a lazy fixed two-array workspace (2 KB float payload per calling thread) to isolate bit reinterpretation from the primitive polynomial loop. C2 assembly now contains packed FMA/division; the prior loop remained scalar. Defer activation only for nonoverlapping input ranges and retain published update order for overlaps and scalar suffix arithmetic. Candidate remains subject to supported-host and whole-model gates.
… loops

Separate float and integer loops with bounded raw heap copies so C2 emits packed max, scale shifts/adds and polynomial arithmetic without interpreted Vector API wrappers. Reuse three fixed 256-element arrays per thread (3 KB payload) and cached heap-segment views. Preserve the existing polynomial, exceptional-input fallback, history and alias behavior; qualification remains pending supported-host timing.
@bsbodden bsbodden changed the title Fix Bonsai activation and BF16 full-logit determinism Fix deterministic inference and portable VCR storage Oct 13, 2026
Use explicit SLEEF EXP/LOG arithmetic for the ARM 128-bit activation path, with matching scalar tails. Retain published vector grouping and alias ordering, and the fixed float SwiGLU implementation on the other supported paths. Include the upstream permissive notices.

The actual Gradle core JAR matches the frozen e249e914 candidate exactly. Core JAR, formatting, and focused activation tests pass. Whole-model qualification and the full supported-platform suites remain separate release gates.
Remove stale diagnostic wording while retaining the copyright and permissive license. All 86 class entries remain byte-identical to the frozen e249 artifact; only META-INF/NOTICE changes in the rebuilt JAR.
Use 0x1.715476p0f for the same rounded log2(e) coefficient. The long decimal digits triggered the source scanner high-entropy hexadecimal detector. The rebuilt JAR and all 86 classes are unchanged; the original MFCQI gate now passes at 0.722 against 0.70.
Use the certified source-order ARM recipe for exact gate and convolution expectations while retaining other-platform goldens and all cold/hot, history and accuracy assertions. Add direct offset, tail, alias, exceptional-value and persistent-history cases so the implementation is covered on every test host.

Only four test files change. The runtime JAR remains byte-identical to 19a466f8; independent full-core verification passed 1,673 tests with the unchanged coverage threshold.
CuVsResultDecoder negated raw cuVS distances. That preserves ordering, so search
results ranked correctly, but it put cuVS scores on a different scale from every
other IndexSpi implementation: a EUCLIDEAN result came back as -0.25 where the
rest of the library returns 0.8. Any collection score threshold therefore meant
something different the moment an application switched to a cuVS index, silently.

Each metric now produces exactly what SimilarityFunction produces, which is
checkable against that class rather than asserted:

  EUCLIDEAN           SimilarityFunction 1f/(1f + squareDistance); cuVS returns
                      squared L2, so 1f/(1f + raw).
  COSINE              SimilarityFunction (1f + cosine)/2f on a similarity in
                      [-1,1]; cuVS returns cosine DISTANCE, 1 - similarity, so
                      (2f - raw)/2f.
  DOT_PRODUCT         SimilarityFunction (1f + dot)/2f; cuVS returns the inner
                      product as-is, so (1f + raw)/2f.
  MAXIMUM_INNER_PRODUCT  delegates to SimilarityFunction.scaleMaxInnerProductScore,
                      the same function, rather than restating it.

Ordering is unchanged and the tests pin that: the same ordinal sequences assert in
both versions, so this moves the score scale and not the ranking.

Verified on CPU. CuVsResultDecoderTest is a fixture-driven unit test of the
transform and needs no GPU, which is why this is admissible while the cuVS
hardware review is still open: 0.25 -> 0.8, 1.0 -> 0.5, 4.0 -> 0.2 for squared
Euclidean, and 0.1 -> 0.95 for cosine distance. Upstream sources and the
BruteForceIndexImpl disassembly used to establish the raw directions are retained
in audit-artifacts/cuvs-java-contract-review-v1.
Every governed coordinate was re-checked against its Maven metadata and the
selections updated with the lockfiles regenerated across all twenty-eight modules.

The policy deliberately stays on stable releases rather than taking the newest
thing published: jackson-annotations holds 2.22 while 3.0-rc5 is latest, and
slf4j-api holds 2.0.20 while 2.1.0-alpha1 is latest. A release candidate and an
alpha are not upgrades for a library other people depend on.

Receipt in audit-artifacts/dependency-policy-refresh-2026-10-14/metadata-review.json
records policiesIdentical true, the policy digest, and for each coordinate the
metadata URL, its sha256, the selected and latest versions, and that the selection
is present upstream. The three per-repository lock regenerations and the policy
guard tests are logged beside it.

Compilation of main and test sources passes, spotlessCheck passes, and the policy
guard tests pass locally.
…ssion

The candidate replaced the released vector EXP intrinsic with per-lane
StrictMath.exp so activations survive HotSpot intrinsification. Run 38596566492
measured what that cost on x86: JEVBench 76/120 released against 75/120
candidate, a per-dataset loss that an improved SNIPS 14->15 does not waive. ARM
passed 74->75 and 15/15.

x86 therefore returns to the released arithmetic exactly. The three affected
non-ARM method bodies -- swiGlu, sigmoidAndScaledSoftplus and
causalDepthwiseConv1dSilu -- are now byte-identical to origin/main, checked by
brace-matched extraction and string comparison rather than by eye. ARM keeps
PublishedArmActivations and its measured gain. No other accepted repair is
touched.

Removing that route made a cascade of candidate-only code unreachable, and the
working agreement does not allow leaving it:

  ReproducibleActivationExp        1 reference -> 0
  activationExp, activationLog     private helpers, only their own declarations
  applyConvolutionSilu             private delegator, no callers
  ReproducibleConvolutionSilu      used only by that delegator; absent from main

Three new tests went with their subjects: FallbackSwiGluContractTest,
ConvolutionSiluContractTest and ConvolutionPolynomialAccuracyTest. The second of
those is why this is a deletion and not a retarget -- it asserts raw float bits
against a reference built on StrictMath.exp, and no scalar Java reference can
reproduce the VectorOperators.EXP intrinsic bit for bit. That impossibility is
the reason the reproducible implementation existed at all.
ArmActivationReference is retained; the two ARM tests still use it.

Verified before deleting: the accepted SwiGLU forward-overlap repair is not in
the restored bodies. Commit 1ff05e1 touched only ReproducibleActivationExp and
its test, never PanamaVectorUtilSupport, so that defect and its fix leave
together and the released path is unchanged.

vectors-core: 2003 tests pass, compilation and spotlessCheck clean.

What this defers, stated rather than buried: x86 activations no longer carry the
cold/hot determinism guarantee that main already ships for the F32, Q4K, Q5K,
Q6K and Q8 matmul paths. ActivationColdHotTest passes locally on ARM at 128 and
256 bits; x86 is the architecture in question and CI decides it. Closing that gap
needs an exp that is both deterministic and bit-compatible with the warmed JDK
AVX2 recipe. One exists and is numerically proven over 4,194,304 inputs, but it
is GPLv2-derived and barred from this runtime, and selecting a different
permissive approximation because it restores the label would be tuning to the
gate.
…s it

CI found both determinism tests failing after x86 returned to the released
arithmetic, and one of them in a place I had not predicted:

  ActivationColdHotTest          failed on x86, as expected
  BonsaiActivationSequenceTest   failed on x86 AND arm64, at every width ceiling

The arm64 failure is correct behaviour, not a second defect.
USE_PUBLISHED_ARM_ACTIVATIONS requires aarch64 AND a 128-bit float species, so
aarch64 at 64, 256 and 512 bits runs the released vector EXP intrinsic exactly as
x86 does. The activation cold/hot contract therefore survives only on the
published aarch64 128-bit route, and that is where these tests now run: an
arch assumption plus the 128-bit rows only.

I am scoping rather than relaxing. The assertions are unchanged and still exact;
they simply no longer claim to cover configurations where the shipped arithmetic
cannot satisfy them. Deleting them would discard real ARM coverage, and loosening
the comparison would convert a measurable contract into a vague one.

Each test carries the reason inline so the next reader does not have to
reconstruct it: the StrictMath substitution that made activations deterministic
everywhere cost measured x86 task quality (run 38596566492, JEVBench 76/120
against 75/120), a user-visible loss that is not acceptable; and the only exp
proven both deterministic and bit-compatible with the warmed JDK AVX2 recipe is
GPLv2-derived and barred from this runtime.

Activations are consequently the one path lacking the cold/hot guarantee that the
F32, Q4K, Q5K, Q6K and Q8 matmul paths already ship. That is written into the
tests and into RELEASE-TODO.md rather than left for CI to rediscover.

Both tests pass on this aarch64 host; spotlessCheck and test compilation clean.
…f waiting

SwiGluColdHotTest asserts the same activation determinism contract and fails for
the same reason on every configuration that runs the released vector EXP
intrinsic. It is now scoped like ActivationColdHotTest and
BonsaiActivationSequenceTest: aarch64 only, 128 bits only.

I should have found it in the previous commit. I scoped the two tests CI happened
to report and did not sweep for the rest of the class, which is the same
fix-N-minus-one mistake twice in one change. This time the set was enumerated
mechanically rather than discovered one CI run at a time: of the newly added
cold/hot tests, ActivationColdHotProbe, BonsaiActivationSequenceProbe,
SwiGluColdHotProbe and SwiGluColdHotTest drive swiGlu, sigmoidAndScaledSoftplus
or causalDepthwiseConv1dSilu; BFloat16MatrixColdHotTest and its probe drive none
and are correctly left alone. The probes need no assumption of their own because
the scoped tests decide whether they fork at all.

The pre-existing F32, Q4K, Q5K, Q6K and Q8 cold/hot tests are untouched and still
run everywhere. Only the activation contract is narrowed, and only to the route
that can satisfy it.

Local: compilation, spotlessCheck and all four cold/hot tests pass on aarch64.
The changelog is user-facing, and two entries would have shipped as false claims.

The SwiGLU overlapping-output entry described a repair that lived entirely inside
ReproducibleActivationExp. That class is gone, so the defect and its fix left
together and the released path never had either. The entry is removed rather than
reworded; there is nothing in this release it describes.

The JIT-stability entry claimed SwiGLU, recurrent gates and convolution/SiLU are
numerically stable across compilation, without qualification. That now holds only
where USE_PUBLISHED_ARM_ACTIVATIONS does -- aarch64 with a 128-bit float species,
which is the exact condition in the source, not a paraphrase of it. Everywhere
else activation arithmetic is unchanged from 0.1.29 and keeps the platform vector
exponential.

The entry now says both halves: the guarantee where it exists, and plainly that
output is identical to the previous release elsewhere and the cold/hot activation
guarantee does not extend there. It also records why -- the deterministic
substitute was implemented, measured, and cost x86 task quality on a fixed
148-case comparison (JEVBench 76/120 against 75/120) -- and notes that the
quantized and F32 matrix paths keep their cold/hot guarantees on all targets, so a
reader does not infer a broader loss than occurred.

Both figures and the route condition were checked against
audit-artifacts/qwen-released-distribution-quality-v1/RESULTS.md and the source
guard rather than written from memory. The rest of the 0.1.30 section was swept
for other claims describing removed code; there are none.
@bsbodden
bsbodden marked this pull request as ready for review October 15, 2026 00:35
@bsbodden
bsbodden merged commit a672c4d into main Oct 15, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant