Skip to content

ltm-finding: discovery mode silently drops ALL cross-element (cross-agg) reducer loops #696

Description

@bpowers

Summary

LTM discovery mode (the strongest-path heuristic in src/simlin-engine/src/ltm_finding.rs) silently drops every cross-element feedback loop that traverses a hoisted reducer (a synthetic \$⁚ltm⁚agg⁚{n} aggregate node) more than once -- e.g. pop[a] → agg → pop[b] → agg → pop[a]. Discovery returns only the single-petal (same-element-through-agg) loops; the genuinely cross-element ones never appear, with no diagnostic.

The recovery routine that materializes these loops, recover_cross_agg_loops (src/simlin-engine/src/db/ltm/loops.rs, the petal-stitcher; call site ~line 1056), runs only on the exhaustive Johnson path via build_element_level_loops. Discovery has its own per-timestep strongest-path DFS (ltm_finding.rs) and never feeds recover_cross_agg_loops.

Root cause

A cross-agg loop visits the agg node more than once, so it is not an elementary circuit in the element graph. Discovery's DFS maintains a visiting set (ltm_finding.rs:341, checked at :395, inserted at :411) that forbids revisiting any node on the current path -- including the agg node. So these loops are structurally unreachable by the search: the DFS can never construct a path that returns to agg a second time. This is orthogonal to the cap/under-enumeration in the exhaustive recovery (#515) -- in discovery the recovery never runs at all, so even the loops that #515's MAX_AGG_PETALS=8 would have produced are absent.

Empirical repro

A reducer-in-feedback model growth[r] = SUM(pop[*]) * 0.05 over 3 elements:

  • Exhaustive mode emits 7 loop scores: 3 single-petal + 3 disjoint-pair + 1 triple.
  • Discovery mode returns only the 3 single-petal loops.

All link scores are present and non-zero in both modes (pop[e] → agg = 0.333, agg → growth[e] = 1.0) -- the cross-element loops are not zeroed out, they are simply never reached by the search.

Why it matters (worst exactly where it bites)

The failure case overlaps the auto-flip condition. A reducer-in-feedback model over a large dimension trips MAX_LTM_SCC_NODES and auto-flips from exhaustive Johnson to discovery -- and at that moment loses its cross-element reducer loops, silently. The model author sees a loop list that looks complete but is missing an entire class of loops, with no truncated-style signal. This is a correctness/completeness gap, distinct from the discovery performance issues (#647, #540) and from the recovery cap (#515) and polarity (#516) issues, all of which assume the loops at least get enumerated.

Misleading design doc

docs/design/ltm--loops-that-matter.md, "Discovery Mode" step 4 (lines 1214-1215), claims:

Discovered element-level loops are grouped and classified identically to exhaustive mode via build_element_level_loops; the synthetic agg nodes are [...]

This is misleading: discovery has its own DFS and never feeds recover_cross_agg_loops, so it does not classify identically -- it cannot recover cross-agg loops at all. The doc should be corrected regardless of which code fix is chosen.

Possible approaches

  • (a) Post-process discovery results: stitch the discovered single-petal loops through their shared agg nodes by reusing recover_cross_agg_loops after the per-timestep DFS, so discovery gets the same cross-agg recovery the exhaustive path has.
  • (b) Bounded agg-node revisit in the DFS: permit the visiting guard to allow a bounded number of revisits specifically for agg nodes, so cross-agg loops become reachable by the search itself.
  • Either way: fix the design-doc claim, and consider emitting a diagnostic when cross-agg recovery is skipped/unavailable in discovery mode.

Components affected

  • src/simlin-engine/src/ltm_finding.rs (discovery DFS, the visiting set at :341/:395/:411)
  • src/simlin-engine/src/db/ltm/loops.rs (recover_cross_agg_loops, exhaustive-only)
  • docs/design/ltm--loops-that-matter.md (Discovery Mode step 4, lines 1214-1215)

Relationship to existing tracking

Discovery context

Identified during an LTM deep review while cross-checking discovery vs exhaustive loop output on a reducer-in-feedback fixture. Part of LTM tracking epic #488.

Activity

  1. added
    ltmLoops that Matter (LTM) analysis subsystem
    on Jun 3, 2026
  2. bpowers commented on Jun 8, 2026

    @bpowers
    OwnerAuthor

    Fixed by PR #705 (merged, commit 26a641e), verified present on main:

    Closing as resolved. (FFI surfacing of the #696 truncation flag remains tracked as #701.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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