Problem
When a target reads the same source element through two reference sites, the reference-site IR (db/ltm_ir.rs::collect_all_reference_sites, one RefShape per site) scores each site's ceteris-paribus partial separately, and the element graph carries parallel edges (or a direct edge plus an agg-routed path). The de-subscripted scalar model -- the correctness standard for arrayed LTM (docs/reference/ltm--loops-that-matter.md section 15.4) -- has ONE link whose partial holds every read of that source live. Splitting the partial breaks the isolated-loop invariant (reference 4.1: "a loop that is the only loop acting on its stocks always has loop score +/-1", the property Appendix B rests on) and, for reducers, doubles the loop list.
D1: Bare plus FixedIndex of the same element
Oracle corpus fixed_broadcast: Region = {nyc, boston, la}; pop[Region] stock (100, 200, 300) with inflow growth; growth[r] = pop * 0.02 + pop[nyc] * spill; spill = 0.01. For element nyc the scalar partial is 0.03 dpop / 0.03 dpop = 1, and pop_nyc -> growth_nyc -> pop_nyc is the only loop on that stock, so its raw score must be +1. Simlin emits
$⁚ltm⁚link_score⁚pop→growth[nyc] = 0.02/0.03 = 2/3 (the FixedIndex read frozen), and
$⁚ltm⁚link_score⁚pop[nyc]→growth = 1/3 (the Bare read frozen).
Johnson sees one adjacency, the loop takes the Bare name (parse_link_offsets' Bare-first rule), and the isolated loop reports raw 0.6667 at every step:
edge BAD pop_nyc -> growth_nyc: scalar [1, 1, 1, 1] vs direct $⁚ltm⁚link_score⁚pop→growth[0] [0.666667, 0.666667, 0.666667, 0.666667]
loop RAW BAD r1[0] ~ r3 growth_nyc -> pop_nyc: arrayed [0.666667, ...] vs scalar [1, 1, 1, 1]
D2: a direct read plus a read inside a hoisted reducer
Corpus mean_loop: growth[r] = pop[r] * 0.02 * (1 - MEAN(pop[*]) / 1000). Element nyc, t = 1: scalar link 1.2837; Simlin's direct edge pop→growth[nyc] = 1.3405 plus the agg path pop[nyc]→$⁚ltm⁚agg⁚0 * $⁚ltm⁚agg⁚0→growth[nyc] = -0.0559 (sum 1.2846, off by the second-order cross term). The arrayed path then reports TWO loops for the one scalar loop growth_nyc -> pop_nyc (raw 1.35 and -0.057; relative 0.78 and -0.03 against a scalar relative of 0.35). Same on min_loop, max_loop, stddev_loop, share_sum, scalar_cofactor_inline, two_d and migration_matrix (every edge SPLIT row in the oracle reports). For nonlinear reducers the two halves also do not multiply to the scalar link: on migration_matrix (a 3x3 flow matrix through a reducer) the median raw loop deviation is 0.5%, the 90th percentile 12% and the maximum 4.2, because splitting a ratio's numerator and denominator between the direct and agg edges yields opposite-signed loops of 5-10x the true magnitude. The chain rule through an agg (reference 4.2) is exact only for a linear consumer with no second read (cross_agg: all 12 element links equal the product of the halves to 1e-9).
Why it matters
Silent wrong numbers on the dominance surface for shapes a modeler writes without trying (a broadcast term, a share-of-mean factor). The isolated-loop invariant is the reference's own sanity check and it fails on a three-variable model; the doubled loops and the mis-split relative scores move dominance verdicts (epic #488's no-silent-wrong-numbers invariant).
The Bare-vs-FixedIndex per-shape split is deliberate (docs/tech-debt.md entry 26: "The Bare-vs-FixedIndex per-shape split survives") and was introduced to fix the opposite failure -- a partial that left every read live, including reads of OTHER elements. The correct partial holds every read of the SAME source element live and every other read frozen; the per-shape split freezes some reads of the isolated element, which is the error here.
Fix routes
(a) Textual, medium cost: when the IR finds several sites for one (from[e], to[f]) element edge, generate one partial holding all of them live and emit ONE edge; agg-routed sites join the direct partial, and the agg node remains a hop only for edges with no direct read. Acceptance: fixed_broadcast raw loop = 1; the edge rows of mean_loop, min_loop, stddev_loop; residual second-order differences only on reducer-chain edges that keep an agg hop.
(b) The fragments plan's per-slot re-evaluation (docs/design-plans/2026-09-04-link-scores-from-fragments.md): perturb one input slot and re-evaluate the target slot, so every read of that slot is live by construction and RefShape / agg hoisting are needed only for the element graph, never for scoring. Subsumes (a) and deletes most of the textual partial builders.
The oracle
The de-subscripting oracle that finds this class (desub.py / oracle.py, with the corpus in gen_corpus.py, in the audit's scratchpad) is promoted to an integration harness by the single-mode plan (docs/design-plans/2026-09-07-ltm-single-mode.md, Phase 5: tests/integration/ltm_desubscript_oracle.rs, AC7.2). That harness is the acceptance test for either route.
Components affected
src/simlin-engine/src/db/ltm_ir.rs -- collect_all_reference_sites, ClassifiedSite (one site per read; needs a per-edge grouping)
src/simlin-engine/src/db/analysis.rs -- RefShape, emit_edges_for_reference (parallel element edges)
src/simlin-engine/src/db/ltm/link_scores.rs -- per-shape emission (emit_link_scores_for_edge), the agg-routed leg
src/simlin-engine/src/ltm_augment.rs -- build_partial_equation_shaped (holds only the matching shape live)
src/simlin-engine/src/db/ltm/loops.rs -- the Bare-first name rule that picks which split edge a loop reads
Related
Discovery context
LTM fidelity audit of 2026-09-07..09 (branches ltm-fidelity / ltm-fidelity-post), audit report B (de-subscripting oracle), finding D. Pre-existing; not a regression of that branch's commits (05e4dae, 3afd637, f5e0325, 8cbcf0c, 6a90255, 95f848f, e5319fb, e85914f).
Problem
When a target reads the same source element through two reference sites, the reference-site IR (
db/ltm_ir.rs::collect_all_reference_sites, oneRefShapeper site) scores each site's ceteris-paribus partial separately, and the element graph carries parallel edges (or a direct edge plus an agg-routed path). The de-subscripted scalar model -- the correctness standard for arrayed LTM (docs/reference/ltm--loops-that-matter.mdsection 15.4) -- has ONE link whose partial holds every read of that source live. Splitting the partial breaks the isolated-loop invariant (reference 4.1: "a loop that is the only loop acting on its stocks always has loop score +/-1", the property Appendix B rests on) and, for reducers, doubles the loop list.D1: Bare plus FixedIndex of the same element
Oracle corpus
fixed_broadcast:Region = {nyc, boston, la};pop[Region]stock (100, 200, 300) with inflowgrowth;growth[r] = pop * 0.02 + pop[nyc] * spill;spill = 0.01. For elementnycthe scalar partial is0.03 dpop / 0.03 dpop = 1, andpop_nyc -> growth_nyc -> pop_nycis the only loop on that stock, so its raw score must be +1. Simlin emits$⁚ltm⁚link_score⁚pop→growth[nyc]= 0.02/0.03 = 2/3 (the FixedIndex read frozen), and$⁚ltm⁚link_score⁚pop[nyc]→growth= 1/3 (the Bare read frozen).Johnson sees one adjacency, the loop takes the Bare name (
parse_link_offsets' Bare-first rule), and the isolated loop reports raw 0.6667 at every step:D2: a direct read plus a read inside a hoisted reducer
Corpus
mean_loop:growth[r] = pop[r] * 0.02 * (1 - MEAN(pop[*]) / 1000). Element nyc, t = 1: scalar link 1.2837; Simlin's direct edgepop→growth[nyc]= 1.3405 plus the agg pathpop[nyc]→$⁚ltm⁚agg⁚0 * $⁚ltm⁚agg⁚0→growth[nyc]= -0.0559 (sum 1.2846, off by the second-order cross term). The arrayed path then reports TWO loops for the one scalar loopgrowth_nyc -> pop_nyc(raw 1.35 and -0.057; relative 0.78 and -0.03 against a scalar relative of 0.35). Same onmin_loop,max_loop,stddev_loop,share_sum,scalar_cofactor_inline,two_dandmigration_matrix(everyedge SPLITrow in the oracle reports). For nonlinear reducers the two halves also do not multiply to the scalar link: onmigration_matrix(a 3x3 flow matrix through a reducer) the median raw loop deviation is 0.5%, the 90th percentile 12% and the maximum 4.2, because splitting a ratio's numerator and denominator between the direct and agg edges yields opposite-signed loops of 5-10x the true magnitude. The chain rule through an agg (reference 4.2) is exact only for a linear consumer with no second read (cross_agg: all 12 element links equal the product of the halves to 1e-9).Why it matters
Silent wrong numbers on the dominance surface for shapes a modeler writes without trying (a broadcast term, a share-of-mean factor). The isolated-loop invariant is the reference's own sanity check and it fails on a three-variable model; the doubled loops and the mis-split relative scores move dominance verdicts (epic #488's no-silent-wrong-numbers invariant).
The Bare-vs-FixedIndex per-shape split is deliberate (
docs/tech-debt.mdentry 26: "The Bare-vs-FixedIndex per-shape split survives") and was introduced to fix the opposite failure -- a partial that left every read live, including reads of OTHER elements. The correct partial holds every read of the SAME source element live and every other read frozen; the per-shape split freezes some reads of the isolated element, which is the error here.Fix routes
(a) Textual, medium cost: when the IR finds several sites for one
(from[e], to[f])element edge, generate one partial holding all of them live and emit ONE edge; agg-routed sites join the direct partial, and the agg node remains a hop only for edges with no direct read. Acceptance:fixed_broadcastraw loop = 1; the edge rows ofmean_loop,min_loop,stddev_loop; residual second-order differences only on reducer-chain edges that keep an agg hop.(b) The fragments plan's per-slot re-evaluation (
docs/design-plans/2026-09-04-link-scores-from-fragments.md): perturb one input slot and re-evaluate the target slot, so every read of that slot is live by construction andRefShape/ agg hoisting are needed only for the element graph, never for scoring. Subsumes (a) and deletes most of the textual partial builders.The oracle
The de-subscripting oracle that finds this class (
desub.py/oracle.py, with the corpus ingen_corpus.py, in the audit's scratchpad) is promoted to an integration harness by the single-mode plan (docs/design-plans/2026-09-07-ltm-single-mode.md, Phase 5:tests/integration/ltm_desubscript_oracle.rs, AC7.2). That harness is the acceptance test for either route.Components affected
src/simlin-engine/src/db/ltm_ir.rs--collect_all_reference_sites,ClassifiedSite(one site per read; needs a per-edge grouping)src/simlin-engine/src/db/analysis.rs--RefShape,emit_edges_for_reference(parallel element edges)src/simlin-engine/src/db/ltm/link_scores.rs-- per-shape emission (emit_link_scores_for_edge), the agg-routed legsrc/simlin-engine/src/ltm_augment.rs--build_partial_equation_shaped(holds only the matching shape live)src/simlin-engine/src/db/ltm/loops.rs-- the Bare-first name rule that picks which split edge a loop readsRelated
docs/tech-debt.mdentry 26 -- where the per-shape split is recorded as the designDiscovery context
LTM fidelity audit of 2026-09-07..09 (branches
ltm-fidelity/ltm-fidelity-post), audit report B (de-subscripting oracle), finding D. Pre-existing; not a regression of that branch's commits (05e4dae, 3afd637, f5e0325, 8cbcf0c, 6a90255, 95f848f, e5319fb, e85914f).