Skip to content

ltm: loop scores through a variable-backed partial-reduce reducer reference never-emitted link-score names, stubbing to 0 #752

@bpowers

Description

@bpowers

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

  1. 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.
  2. 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".
  3. 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).
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ltmLoops that Matter (LTM) analysis subsystem

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions