Found by the phugoid consumer at rung 3, 2026-08-25, eigenscript v0.41.0. Ledger entry: phugoid GAPS.md G6. Filed late — G6 was the one entry in that ledger recorded without an upstream issue, which its own opening rule forbids.
Summary
lib/linalg.eigs's solve_linear returns null when the system is singular. It does not raise, and the null carries no information about which system failed. Callers that index the result get cannot index null at a site that can be far from the cause.
Reproduction
A 3x3 with a zero row:
load_file of "lib/linalg.eigs"
r is linalg.solve_linear of [[[1.0, 2.0, 3.0], [0.0, 0.0, 0.0], [4.0, 5.0, 6.0]], [1.0, 2.0, 3.0]]
print of f"result: {r}"
print of f"r[0] -> "
print of r[0]
result: null, exit 0 from the first two prints, then cannot index null.
How it presented
Building a planted-fault matrix for a trim solver, one plant zeroed the aircraft's control derivatives. That makes the delta-e column of the trim Jacobian identically zero, so the Newton step is singular. The observed failure was cannot index null inside trim_solve, several frames from the plant, with nothing naming the singular system. The plant was rewritten to avoid the crash — the consumer's own workaround — and the gap recorded rather than silently absorbed.
The consumer-side robustness bug (indexing an unchecked result) is the consumer's to fix. What is upstream is that a linear solver signals "no solution" the same way a dictionary signals "no such key", so no caller can distinguish them without a shape check it should not need to write.
What would resolve it
Either raising on a singular system, or returning a discriminated result the caller can test ({"ok": 0, "reason": ...}) as the estimator modules in this ecosystem already do. Related policy: the fail-soft reform track (#971/#975) owns whether the answer here is "raise" or "structured refusal"; this issue is a concrete instance for that decision rather than a request for a particular one.
Note the same family sits one level down: a missing dict field also returns null silently (phugoid GAPS.md W4), which is what makes the null from this function indistinguishable from a typo at the call site.
Found by the
phugoidconsumer at rung 3, 2026-08-25,eigenscriptv0.41.0. Ledger entry: phugoid GAPS.md G6. Filed late — G6 was the one entry in that ledger recorded without an upstream issue, which its own opening rule forbids.Summary
lib/linalg.eigs'ssolve_linearreturnsnullwhen the system is singular. It does not raise, and the null carries no information about which system failed. Callers that index the result getcannot index nullat a site that can be far from the cause.Reproduction
A 3x3 with a zero row:
result: null, exit 0 from the first two prints, thencannot index null.How it presented
Building a planted-fault matrix for a trim solver, one plant zeroed the aircraft's control derivatives. That makes the delta-e column of the trim Jacobian identically zero, so the Newton step is singular. The observed failure was
cannot index nullinsidetrim_solve, several frames from the plant, with nothing naming the singular system. The plant was rewritten to avoid the crash — the consumer's own workaround — and the gap recorded rather than silently absorbed.The consumer-side robustness bug (indexing an unchecked result) is the consumer's to fix. What is upstream is that a linear solver signals "no solution" the same way a dictionary signals "no such key", so no caller can distinguish them without a shape check it should not need to write.
What would resolve it
Either raising on a singular system, or returning a discriminated result the caller can test (
{"ok": 0, "reason": ...}) as the estimator modules in this ecosystem already do. Related policy: the fail-soft reform track (#971/#975) owns whether the answer here is "raise" or "structured refusal"; this issue is a concrete instance for that decision rather than a request for a particular one.Note the same family sits one level down: a missing dict field also returns null silently (phugoid GAPS.md W4), which is what makes the null from this function indistinguishable from a typo at the call site.