Summary
A loop score through a variable-backed partial-reduce reducer (is_synthetic == false -- the variable itself is the agg) references link-score names that are never emitted, so the loop-score fragments fail fragment compile (Assembly Warnings) and are silently stubbed to constant 0.
Fixture shape
D1 = {a, b}, D2 = {x, y}
matrix[D1,D2] = stock[D1] * 0.1
stock[D1] (fed by inflow)
inflow[D1] = SUM(matrix[D1,*]) -- the WHOLE RHS: a variable-backed agg
A feedback loop closed through the D1 stock that broadcasts into the D1 x D2 matrix.
Mechanism
- Variable-backed aggs do not get read-slice-driven element edges -- per the
src/simlin-engine/src/ltm_agg.rs module docs, the element-graph reroute and the link-score emitter both filter to is_synthetic aggs, and "Variable-backed aggs still take the conservative cross-product in the element graph." So the element graph contains phantom matrix[a,x] -> inflow[b] cross-element edges.
- The cross-element loop-score equations built over those edges reference
"$⁚ltm⁚link_score⁚matrix[a,x]→inflow"[b] (subscripted per-element form) and the bare A2A "$⁚ltm⁚link_score⁚matrix→inflow".
- But the only link scores actually emitted for a variable-backed partial reduce are the per-
(row, slot) scalars matrix[a,x]→inflow[a] from try_cross_dimensional_link_scores (src/simlin-engine/src/ltm_augment.rs).
- The referencing loop-score fragments therefore fail to compile,
assemble_module drops them, and each loop score keeps its layout slot reading constant 0 -- visible only as Assembly Warnings in diagnostics.
Verified pre-existing: identical behavior at the parent of the #528 fix on branch ltm-core-batch (commit bce4aa4c); not a regression of that branch's work.
Why it matters
Medium. Silent zero loop scores for cross-element loops through a whole-RHS partial reducer -- row_total[D1] = SUM(matrix[D1,*]) as an entire equation is a common Vensim shape. The model compiles and simulates; the degradation is only visible if the user inspects diagnostics.
Components affected
src/simlin-engine/src/ltm_agg.rs -- variable-backed aggs (is_synthetic == false) excluded from the read-slice-driven element-graph reroute, leaving the conservative cross-product in place
src/simlin-engine/src/db/ltm/loops.rs / loop-score equation construction -- composes link-score names (bare A2A + subscripted per-element) that the partial-reduce emitter never produces
src/simlin-engine/src/ltm_augment.rs -- try_cross_dimensional_link_scores emits only the per-(row, slot) scalar forms
Possible approaches
- Give variable-backed partial reducers read-slice-driven element edges like synthetic aggs (retiring the conservative cross-product for them), so the phantom cross-element edges -- and the loop-score equations over them -- never arise; or
- Teach the loop-score name resolution the per-
(row, slot) scalar forms that try_cross_dimensional_link_scores actually emits, so the cross-element loop-score equations reference names that exist.
Existing test coverage
build_model_with_failing_ltm_fragment in src/simlin-engine/src/db/ltm_unified_tests.rs is exactly this fixture -- it is the positive fixture for the fragment-diagnostics tests (the #547 test-debt subject), deliberately leaning on this genuinely-unfixed bug. Its doc comment (rewritten in bce4aa4c; it previously mis-attributed the failure to #528) describes this gap accurately. Whoever fixes this issue must replace that fixture (or land the #547-style injection hook) so the diagnostics tests keep a real positive case.
Related
Discovery context
Root-caused during GH #528 work on branch ltm-core-batch (commit bce4aa4c), while disentangling why build_model_with_failing_ltm_fragment still fails after the #528 fix.
Summary
A loop score through a variable-backed partial-reduce reducer (
is_synthetic == false-- the variable itself is the agg) references link-score names that are never emitted, so the loop-score fragments fail fragment compile (AssemblyWarnings) and are silently stubbed to constant0.Fixture shape
A feedback loop closed through the
D1stock that broadcasts into theD1 x D2matrix.Mechanism
src/simlin-engine/src/ltm_agg.rsmodule docs, the element-graph reroute and the link-score emitter both filter tois_syntheticaggs, and "Variable-backed aggs still take the conservative cross-product in the element graph." So the element graph contains phantommatrix[a,x] -> inflow[b]cross-element edges."$⁚ltm⁚link_score⁚matrix[a,x]→inflow"[b](subscripted per-element form) and the bare A2A"$⁚ltm⁚link_score⁚matrix→inflow".(row, slot)scalarsmatrix[a,x]→inflow[a]fromtry_cross_dimensional_link_scores(src/simlin-engine/src/ltm_augment.rs).assemble_moduledrops them, and each loop score keeps its layout slot reading constant0-- visible only as AssemblyWarnings in diagnostics.Verified pre-existing: identical behavior at the parent of the #528 fix on branch
ltm-core-batch(commitbce4aa4c); not a regression of that branch's work.Why it matters
Medium. Silent zero loop scores for cross-element loops through a whole-RHS partial reducer --
row_total[D1] = SUM(matrix[D1,*])as an entire equation is a common Vensim shape. The model compiles and simulates; the degradation is only visible if the user inspects diagnostics.Components affected
src/simlin-engine/src/ltm_agg.rs-- variable-backed aggs (is_synthetic == false) excluded from the read-slice-driven element-graph reroute, leaving the conservative cross-product in placesrc/simlin-engine/src/db/ltm/loops.rs/ loop-score equation construction -- composes link-score names (bare A2A + subscripted per-element) that the partial-reduce emitter never producessrc/simlin-engine/src/ltm_augment.rs--try_cross_dimensional_link_scoresemits only the per-(row, slot)scalar formsPossible approaches
(row, slot)scalar forms thattry_cross_dimensional_link_scoresactually emits, so the cross-element loop-score equations reference names that exist.Existing test coverage
build_model_with_failing_ltm_fragmentinsrc/simlin-engine/src/db/ltm_unified_tests.rsis exactly this fixture -- it is the positive fixture for the fragment-diagnostics tests (the #547 test-debt subject), deliberately leaning on this genuinely-unfixed bug. Its doc comment (rewritten inbce4aa4c; it previously mis-attributed the failure to #528) describes this gap accurately. Whoever fixes this issue must replace that fixture (or land the #547-style injection hook) so the diagnostics tests keep a real positive case.Related
combined_read_slicedeclines the hoist; here no hoist is involved at all)Discovery context
Root-caused during GH #528 work on branch
ltm-core-batch(commitbce4aa4c), while disentangling whybuild_model_with_failing_ltm_fragmentstill fails after the #528 fix.