Problem
CompiledModule / CompiledSimulation derive salsa::Update, which (via autoref specialization) falls back to the derived PartialEq for the bytecode side-channels. Those side-channels contain f64 values:
ByteCode.literals and ByteCodeContext.graphical_functions (src/simlin-engine/src/compiler/symbolic.rs)
crate::vm Specs (src/simlin-engine/src/results.rs)
NaN literals are reachable: out-of-range subscripts compile to Const(NaN). Because NaN != NaN under PartialEq, old == new can report "changed" on bit-identical output, defeating salsa's backdating for these outputs.
Why this is benign today
A cache hit is decided by the inputs' revisions, not by the output's PartialEq. The only consumer of these outputs (compile_project_incremental) is non-tracked, so an output that is never backdated costs at most one extra assemble_simulation re-exec -- never a wrong result and never a defeated cache hit.
It is also a pre-existing property of the already-tracked compile_var_fragment / PerVarBytecodes, so this change in framing does not introduce new risk.
Why it still matters
The derived PartialEq is a latent footgun: a future change that makes one of these outputs feed a tracked query would silently lose backdating on any model with NaN literals, with no compile error to flag it. Relying on "the only consumer happens to be non-tracked" is fragile.
Components affected
src/simlin-engine/src/compiler/symbolic.rs (ByteCode.literals, ByteCodeContext.graphical_functions)
src/simlin-engine/src/results.rs (crate::vm Specs)
Possible approach
Hand-write Update / PartialEq for the bytecode types using bit-pattern (f64::to_bits) float comparison, so NaN compares equal to itself and bit-identical bytecode backdates correctly.
Severity
low / cleanup.
Context
Identified during the salsa-pipeline-cleanup refactor.
Problem
CompiledModule/CompiledSimulationderivesalsa::Update, which (via autoref specialization) falls back to the derivedPartialEqfor the bytecode side-channels. Those side-channels containf64values:ByteCode.literalsandByteCodeContext.graphical_functions(src/simlin-engine/src/compiler/symbolic.rs)crate::vmSpecs(src/simlin-engine/src/results.rs)NaN literals are reachable: out-of-range subscripts compile to
Const(NaN). BecauseNaN != NaNunderPartialEq,old == newcan report "changed" on bit-identical output, defeating salsa's backdating for these outputs.Why this is benign today
A cache hit is decided by the inputs' revisions, not by the output's
PartialEq. The only consumer of these outputs (compile_project_incremental) is non-tracked, so an output that is never backdated costs at most one extraassemble_simulationre-exec -- never a wrong result and never a defeated cache hit.It is also a pre-existing property of the already-tracked
compile_var_fragment/PerVarBytecodes, so this change in framing does not introduce new risk.Why it still matters
The derived
PartialEqis a latent footgun: a future change that makes one of these outputs feed a tracked query would silently lose backdating on any model with NaN literals, with no compile error to flag it. Relying on "the only consumer happens to be non-tracked" is fragile.Components affected
src/simlin-engine/src/compiler/symbolic.rs(ByteCode.literals,ByteCodeContext.graphical_functions)src/simlin-engine/src/results.rs(crate::vmSpecs)Possible approach
Hand-write
Update/PartialEqfor the bytecode types using bit-pattern (f64::to_bits) float comparison, so NaN compares equal to itself and bit-identical bytecode backdates correctly.Severity
low / cleanup.
Context
Identified during the salsa-pipeline-cleanup refactor.