Summary
FunctionGemmaExportCli (0.53.0, GEMMA_GRAPH=redecode, FP32 or INT8) fails while writing gemma.safetensors:
java.lang.ClassCastException: class sk.ainet.lang.tensor.storage.BufferHandle$Floats cannot be cast to class sk.ainet.lang.tensor.storage.BufferHandle$Owned
FunctionGemmaExportHarness.writeSafetensors does val src = e.source as BufferHandle.Owned (FunctionGemmaExportHarness.kt:462 on main). With the 0.53.0 engine loader the large constants — the 262144×640 tied embedding at least — arrive as BufferHandle.Floats, not Owned. #396 fixed the same cast for the Gemma 3n harness only.
Workaround used
A shadow copy of the harness that dispatches on the handle type (Owned → bytes/offset as today, Floats → materialise little-endian f32 once) and otherwise keeps the per-trace key numbering. With it the redecode, prefill and with-past graphs export, and the arm32 build of the redecode graph is byte-identical to the host oracle on the device — so nothing else in the harness is affected.
Proposed fix
Replace the cast with a when (src) over BufferHandle subtypes (or a bytesOf(handle) helper next to the one #396 added), in all three writeSafetensors call sites (redecode, prefill, with-past).
Context. Measured on 2026-09-03 while bringing FunctionGemma-270M up as an NLU cartridge on an arm32 Android device (Android 14, armeabi-v7a-only 32-bit process, 4× ARMv8 @ 2.0 GHz, Mali GPU) with SKaiNET 0.53.0 + SKaiNET-transformers 0.53.0 from Maven Central. Harness and raw result files: a local harness (can share on request).
Summary
FunctionGemmaExportCli(0.53.0,GEMMA_GRAPH=redecode, FP32 or INT8) fails while writinggemma.safetensors:FunctionGemmaExportHarness.writeSafetensorsdoesval src = e.source as BufferHandle.Owned(FunctionGemmaExportHarness.kt:462onmain). With the 0.53.0 engine loader the large constants — the 262144×640 tied embedding at least — arrive asBufferHandle.Floats, notOwned. #396 fixed the same cast for the Gemma 3n harness only.Workaround used
A shadow copy of the harness that dispatches on the handle type (
Owned→ bytes/offset as today,Floats→ materialise little-endian f32 once) and otherwise keeps the per-trace key numbering. With it the redecode, prefill and with-past graphs export, and the arm32 build of the redecode graph is byte-identical to the host oracle on the device — so nothing else in the harness is affected.Proposed fix
Replace the cast with a
when (src)overBufferHandlesubtypes (or abytesOf(handle)helper next to the one #396 added), in all threewriteSafetensorscall sites (redecode, prefill, with-past).Context. Measured on 2026-09-03 while bringing FunctionGemma-270M up as an NLU cartridge on an arm32 Android device (Android 14,
armeabi-v7a-only 32-bit process, 4× ARMv8 @ 2.0 GHz, Mali GPU) with SKaiNET 0.53.0 + SKaiNET-transformers 0.53.0 from Maven Central. Harness and raw result files: a local harness (can share on request).