You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Strict default misses tensor flattening: matmul/relu turn a non-number element into 0 silently (#1361 follow-up) #1416
Found by the ouroboros AOT strict-mirror round (#1361). Measured on the strict-default build (main 5ccd32a content), flag unset, rc 0:
print of (matmul of [[[1, "x"]], [[1], [1]]])
print of (relu of [1, "x", -2])
[1]
[1, 0, 0]
The tensor-flattening helper (tensor_to_flat, used by matmul, relu and the other tensor builtins on list inputs) substitutes 0 for a non-number element. That is the argument-type stand-in #1361 made raise by default. The flip covered the ARG_GUARD/STRICT_REQUIRE sites and missed this one, because it is a conversion helper, not a guard. The ouroboros AOT mirrors the helper, so both tiers agree on the wrong answer.
Done when
With the flag unset, a non-number element in a list passed to any tensor builtin raises a catchable type error naming the builtin. Under EIGS_STRICT=0 the current answer is kept.
tools/strict_differential.sh gains probe rows for these (the unset-equals-strict half covers them), and they go red with the guard removed.
Every caller of the flattening helper is enumerated from the source, and the table goes here. No other conversion helper carries the same silent stand-in; the search is shown.
The ouroboros AOT mirror is updated in the same pin-bump round (file there if needed).
Runtime repair is ready in #1494 at 4501847bf31137eeb54b67cb0bab67cebfb8e24d. The caller population was derived from actual tensor_to_flat call expressions (excluding its definition and comments):
Builtin
Calls
matmul
2
matmul_at
2
matmul_bt
2
softmax
1
log_softmax
1
relu
1
leaky_relu
1
tensor_save
1
Total: 11 calls across 8 builtins. Actual targeted validation passed93/93; strict differential passed119 probes in strict/unset/opt-out modes,31 pins and255 valid mode rows. The original early-return implementation failed the nine added cases; removing either scanner arm also failed its named coverage check.
The conversion search is not clean. Reading tensor_to_flat, tensor_unary, tensor_elementwise, tensor_flatten_recursive and the byte-conversion helpers found a separate verified str_from_bytes gap and a source-only zlib_bytes_arg lead. Those are tracked in #1590; no zlib runtime result is claimed. tensor_unary/tensor_elementwise already have named ARG_GUARD paths; tensor_flatten_recursive drops unsupported values rather than inserting zero and still needs contract review.
The current ouroboros strict-default PR#262 still contains numeric-or-zero conversion in both list paths of aot_tensor_from_value (source inspection at1fa3e0296265b6b3193c9e72455f651414546043). ouroboros#263 tracks the required mirror in the pin-bump round. This issue stays open until the remaining acceptance work is reconciled.
The #1590 byte-conversion follow-up is implemented in #1616, candidate ecd0201589532ef165339440f60e325b1c9ea60f. The scoped contract is now documented: str_from_bytes and the four DEFLATE codec entry points reject consumed nonnumeric list elements under unset/explicit strict with a builtin-named, catchable type_mismatch; EIGS_STRICT=0 retains numeric-zero substitution. Text conversion stops at a numeric value whose byte conversion is NUL and does not inspect later elements; codecs consume the full list, including elements after numeric zero.
Validation records show original text regression red (9/12), candidate enrolled section 42p green in release (12/12), leak-enabled ASan/UBSan (12/12), zlib (23/23), and 24/24 independent exact-output controls. A subsequent enabled-codec calibration rebuilt the original builtins_buf.c against the same-base zlib objects: 16/23 passed, with all seven expected strict text/codec checks failing. Restoring the candidate source byte-for-byte and rebuilding returned 23/23. Full required CI and downstream acceptance remain pending. The cross-repo ownership audit itself was source-only.
AOT ownership was checked at ouroboros main 4b43ed2d248cad968bb7e50264c87c62b03c9692 and draft #2621fa3e0296265b6b3193c9e72455f651414546043. Neither has a byte-conversion specialization: generic builtin emission in aot/compile.eigs goes through aot_call_dispatch / aot_call_vm_builtin to the linked runtime builtin, and aot/build.sh derives/links the runtime sources. Consequently no separate AOT byte-helper mirror is indicated; the pin bump must include #1616 and verify forwarding behavior under unset/strict/compat modes. The standard AOT build leaves zlib disabled, so enabled-codec parity requires an explicitly matched enabled runtime/link lane; the default lane only exercises the unavailable stubs.
The distinct AOT-owned aot_tensor_from_value still has numeric-or-zero list conversion in both dimensions (main aot/aot_rt.h:1812,1822; draft :1961,1971). ouroboros #263 already owns that mirror; coordinate it with #243 and #262 rather than duplicating tracking. The current Dockerfile pin remains v0.43.0 (a6c50fba6a6250ea347a34500d6c9fa503a5c931). Mirror changes and the pin bump must land together, followed by actual byte-exact differentials and the seven-tier verdict on a clean worktree at the new pin.
This does not yet satisfy the broad “no other conversion helper” assertion: candidate f64_from_bytes still leaves nonnumeric slots as zero (src/builtins_buf.c:262–269), while tensor_flatten_recursive still skips unsupported values (src/builtins_tensor.c:367–378). Those are source-only residual contract questions; #1590 does not repair them. Keep #1416 open until those audit boundaries and the existing AOT mirror acceptance are reconciled.
Activity
InauguralPhysicist commentedon Oct 2, 2026
Runtime repair is ready in #1494 at
4501847bf31137eeb54b67cb0bab67cebfb8e24d. The caller population was derived from actual tensor_to_flat call expressions (excluding its definition and comments):Total: 11 calls across 8 builtins. Actual targeted validation passed93/93; strict differential passed119 probes in strict/unset/opt-out modes,31 pins and255 valid mode rows. The original early-return implementation failed the nine added cases; removing either scanner arm also failed its named coverage check.
The conversion search is not clean. Reading tensor_to_flat, tensor_unary, tensor_elementwise, tensor_flatten_recursive and the byte-conversion helpers found a separate verified str_from_bytes gap and a source-only zlib_bytes_arg lead. Those are tracked in #1590; no zlib runtime result is claimed. tensor_unary/tensor_elementwise already have named ARG_GUARD paths; tensor_flatten_recursive drops unsupported values rather than inserting zero and still needs contract review.
The current ouroboros strict-default PR#262 still contains numeric-or-zero conversion in both list paths of aot_tensor_from_value (source inspection at1fa3e0296265b6b3193c9e72455f651414546043). ouroboros#263 tracks the required mirror in the pin-bump round. This issue stays open until the remaining acceptance work is reconciled.
InauguralPhysicist commentedon Oct 4, 2026
The #1590 byte-conversion follow-up is implemented in #1616, candidate
ecd0201589532ef165339440f60e325b1c9ea60f. The scoped contract is now documented:str_from_bytesand the four DEFLATE codec entry points reject consumed nonnumeric list elements under unset/explicit strict with a builtin-named, catchabletype_mismatch;EIGS_STRICT=0retains numeric-zero substitution. Text conversion stops at a numeric value whose byte conversion is NUL and does not inspect later elements; codecs consume the full list, including elements after numeric zero.Validation records show original text regression red (9/12), candidate enrolled section 42p green in release (12/12), leak-enabled ASan/UBSan (12/12), zlib (23/23), and 24/24 independent exact-output controls. A subsequent enabled-codec calibration rebuilt the original
builtins_buf.cagainst the same-base zlib objects: 16/23 passed, with all seven expected strict text/codec checks failing. Restoring the candidate source byte-for-byte and rebuilding returned 23/23. Full required CI and downstream acceptance remain pending. The cross-repo ownership audit itself was source-only.AOT ownership was checked at ouroboros main
4b43ed2d248cad968bb7e50264c87c62b03c9692and draft #2621fa3e0296265b6b3193c9e72455f651414546043. Neither has a byte-conversion specialization: generic builtin emission inaot/compile.eigsgoes throughaot_call_dispatch/aot_call_vm_builtinto the linked runtime builtin, andaot/build.shderives/links the runtime sources. Consequently no separate AOT byte-helper mirror is indicated; the pin bump must include #1616 and verify forwarding behavior under unset/strict/compat modes. The standard AOT build leaves zlib disabled, so enabled-codec parity requires an explicitly matched enabled runtime/link lane; the default lane only exercises the unavailable stubs.The distinct AOT-owned
aot_tensor_from_valuestill has numeric-or-zero list conversion in both dimensions (mainaot/aot_rt.h:1812,1822; draft:1961,1971). ouroboros #263 already owns that mirror; coordinate it with #243 and #262 rather than duplicating tracking. The current Dockerfile pin remainsv0.43.0(a6c50fba6a6250ea347a34500d6c9fa503a5c931). Mirror changes and the pin bump must land together, followed by actual byte-exact differentials and the seven-tier verdict on a clean worktree at the new pin.This does not yet satisfy the broad “no other conversion helper” assertion: candidate
f64_from_bytesstill leaves nonnumeric slots as zero (src/builtins_buf.c:262–269), whiletensor_flatten_recursivestill skips unsupported values (src/builtins_tensor.c:367–378). Those are source-only residual contract questions; #1590 does not repair them. Keep #1416 open until those audit boundaries and the existing AOT mirror acceptance are reconciled.Reject nonnumeric byte-list elements in strict text and codec conversion
Reject nonnumeric byte-list elements in strict text and codec conversion
Reject nonnumeric byte-list elements in strict text and codec conversion