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
The synthetic aggregate node that LTM hoists for an inlined reducer of the shape SUM(arrayed[*] * scalar)with a scalar target fails fragment compilation, so it is silently stubbed to a constant 0 (with an AssemblyWarning from model_ltm_fragment_diagnostics). Every link and loop score that routes through that agg is then wrong.
Repro shape (from the characterization fixture):
pop[region] -- an arrayed stock
scale = 0.001 * total + 0.01 -- a scalar aux feeding back from the scalar stock total
grow = 1 + SUM(pop[*] * scale) -- a scalar flow; SUM(pop[*] * scale) is a sub-expression (the 1 + keeps it from being a whole-RHS, variable-backed agg), so it is hoisted into a synthetic $⁚ltm⁚agg⁚0
With LTM enabled the model compiles and simulates, but the hoisted $⁚ltm⁚agg⁚0 node's own equation is rejected by the fragment compiler: compile_ltm_equation_fragment returns a result with flow_bytecodes: None, assemble_module drops the fragment, and the agg keeps its layout slot with no bytecode writing it -- it reads a constant 0 at runtime instead of SUM(pop[*] * scale). model_ltm_fragment_diagnostics (src/simlin-engine/src/db/ltm/compile.rs, ~line 1147) emits the "failed to compile; ... evaluates to a constant 0" Warning, so the degradation is visible in diagnostics, but the scores are still silently wrong numerically.
The arrayed-target twin of the same expression compiles fine -- this is specific to the scalar-target shape (a scalar variable whose equation embeds a reducer over an arrayed dep multiplied by a scalar feeder).
Why it matters
Medium. This is a quiet LTM correctness gap for scalar-target reducer loops -- a common, perfectly legal model shape (total_flow = base + SUM(arr[*] * coeff)). The agg's runtime value is 0, so:
the source→agg link scores (pop[d] → $⁚ltm⁚agg⁚0) and the agg→target link score ($⁚ltm⁚agg⁚0 → grow) are degraded, and
every loop score whose chain passes through the agg is wrong.
A Warning is emitted (and per GH #466 it may not even reach the FFI diagnostics surface by default), but nothing in the numeric output flags the corruption.
Components affected
src/simlin-engine/src/ltm_agg.rs -- enumerate_agg_nodes (~line 308) and the agg equation construction: the emitted agg equation for the scalar-target SUM(arrayed[*] * scalar) shape is what the compiler rejects
src/simlin-engine/src/db/ltm/compile.rs -- compile_ltm_synthetic_fragment / compile_ltm_equation_fragment (the fragment-compile path that fails) and model_ltm_fragment_diagnostics (~line 1147, the Warning that makes the stub visible)
Possible approaches
Root-cause why the scalar-target agg equation fails fragment lowering while the arrayed-target twin succeeds (likely a dimension/typing mismatch in how the emitted agg equation or its dependency stubs are shaped when the hoisting target is scalar), and fix the agg equation construction in ltm_agg.rs (or the fragment dep-stub shaping in db/ltm/compile.rs) so the fragment compiles.
Once the agg computes, note that the pure-scalar loop total → scale → grow → total still won't route through it: build_loops_from_tiered materializes a PureScalar fast-path cycle straight from the variable-level circuit, linking scale → grow directly (gap editor overlay #2 in the characterization test's doc comment) -- closing that routing gap is adjacent follow-on work.
Existing test coverage
A characterization test documenting both gaps exists: scalar_feeder_scalar_target_loop_compiles_and_is_well_formed in src/simlin-engine/tests/integration/ltm_array_agg.rs (see its doc comment, which enumerates this issue as gap #1). It pins compile/simulate well-formedness (finite scores, loop enumerated) without asserting the currently-zero values, so closing this gap will not break it -- but a fix should tighten it to assert a non-zero agg value/score.
Discovery context
Identified during work on GH #533 (branch ltm-bug-batch, commit 189e7d0). Both gaps behave identically with and without #533's element-graph fast-path fix -- the element edge that fix adds is never consumed downstream here -- so this is pre-existing, independent breakage.
Tracking
Part of LTM tracking epic #488. Related to but distinct from: #533 (element-graph both-scalar fast path bypassing ThroughAgg routing -- the element edge, not the agg node's value), #525 (link-score partial equation fails to compile for partially-iterated subscripts -- a different synthetic-equation family), #514/#534 (whether a reducer gets hoisted at all -- here the hoist succeeds, the hoisted node's equation doesn't compile), #546/#548 (closed: other causes of synthetic fragments stubbing to 0).
Summary
The synthetic aggregate node that LTM hoists for an inlined reducer of the shape
SUM(arrayed[*] * scalar)with a scalar target fails fragment compilation, so it is silently stubbed to a constant0(with anAssemblyWarningfrommodel_ltm_fragment_diagnostics). Every link and loop score that routes through that agg is then wrong.Repro shape (from the characterization fixture):
pop[region]-- an arrayed stockscale = 0.001 * total + 0.01-- a scalar aux feeding back from the scalar stocktotalgrow = 1 + SUM(pop[*] * scale)-- a scalar flow;SUM(pop[*] * scale)is a sub-expression (the1 +keeps it from being a whole-RHS, variable-backed agg), so it is hoisted into a synthetic$⁚ltm⁚agg⁚0With LTM enabled the model compiles and simulates, but the hoisted
$⁚ltm⁚agg⁚0node's own equation is rejected by the fragment compiler:compile_ltm_equation_fragmentreturns a result withflow_bytecodes: None,assemble_moduledrops the fragment, and the agg keeps its layout slot with no bytecode writing it -- it reads a constant0at runtime instead ofSUM(pop[*] * scale).model_ltm_fragment_diagnostics(src/simlin-engine/src/db/ltm/compile.rs, ~line 1147) emits the "failed to compile; ... evaluates to a constant 0"Warning, so the degradation is visible in diagnostics, but the scores are still silently wrong numerically.The arrayed-target twin of the same expression compiles fine -- this is specific to the scalar-target shape (a scalar variable whose equation embeds a reducer over an arrayed dep multiplied by a scalar feeder).
Why it matters
Medium. This is a quiet LTM correctness gap for scalar-target reducer loops -- a common, perfectly legal model shape (
total_flow = base + SUM(arr[*] * coeff)). The agg's runtime value is0, so:pop[d] → $⁚ltm⁚agg⁚0) and the agg→target link score ($⁚ltm⁚agg⁚0 → grow) are degraded, andA
Warningis emitted (and per GH #466 it may not even reach the FFI diagnostics surface by default), but nothing in the numeric output flags the corruption.Components affected
src/simlin-engine/src/ltm_agg.rs--enumerate_agg_nodes(~line 308) and the agg equation construction: the emitted agg equation for the scalar-targetSUM(arrayed[*] * scalar)shape is what the compiler rejectssrc/simlin-engine/src/db/ltm/compile.rs--compile_ltm_synthetic_fragment/compile_ltm_equation_fragment(the fragment-compile path that fails) andmodel_ltm_fragment_diagnostics(~line 1147, the Warning that makes the stub visible)Possible approaches
ltm_agg.rs(or the fragment dep-stub shaping indb/ltm/compile.rs) so the fragment compiles.total → scale → grow → totalstill won't route through it:build_loops_from_tieredmaterializes aPureScalarfast-path cycle straight from the variable-level circuit, linkingscale → growdirectly (gap editor overlay #2 in the characterization test's doc comment) -- closing that routing gap is adjacent follow-on work.Existing test coverage
A characterization test documenting both gaps exists:
scalar_feeder_scalar_target_loop_compiles_and_is_well_formedinsrc/simlin-engine/tests/integration/ltm_array_agg.rs(see its doc comment, which enumerates this issue as gap #1). It pins compile/simulate well-formedness (finite scores, loop enumerated) without asserting the currently-zero values, so closing this gap will not break it -- but a fix should tighten it to assert a non-zero agg value/score.Discovery context
Identified during work on GH #533 (branch
ltm-bug-batch, commit 189e7d0). Both gaps behave identically with and without #533's element-graph fast-path fix -- the element edge that fix adds is never consumed downstream here -- so this is pre-existing, independent breakage.Tracking
Part of LTM tracking epic #488. Related to but distinct from: #533 (element-graph both-scalar fast path bypassing ThroughAgg routing -- the element edge, not the agg node's value), #525 (link-score partial equation fails to compile for partially-iterated subscripts -- a different synthetic-equation family), #514/#534 (whether a reducer gets hoisted at all -- here the hoist succeeds, the hoisted node's equation doesn't compile), #546/#548 (closed: other causes of synthetic fragments stubbing to 0).