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
docs: full verification pass of ltm--loops-that-matter.md against the LTM code (build_partial_equation is gone; recompute passage describes the adapter, not ModuleOverrideCache; module-role taxonomy is prose-only) #1049
docs/design/ltm--loops-that-matter.md (2,188 lines) is the LTM implementation design doc that docs/README.md, docs/architecture.md, src/simlin-engine/CLAUDE.md and the engine's own auto-switch warning text (db/ltm/mod.rs, "see docs/design/ltm--loops-that-matter.md for the two-tier strategy") all point at. The repo rule is that docs are evergreen and true of the tree.
The documentation chunk of the compiler-unification-v2 branch (PR #1040, commit 78d0195a) rewrote and verified the describer sections against the code: the db/ltm/ module table, the RefShape variants including PerElement, compute_read_slice, node identity as the spelled reducer, BareSpelling, occurrence_realizes_shape, and the residual carve-outs as the code's current declines. The rest of the document -- the two-modes, module-classification, module-boundary / composite, polarity, post-simulation discovery, array, pinned-loop and test-coverage sections -- still describes the machinery as of 2026-05/06 and was NOT verified name-by-name or claim-by-claim against the current tree. That verification is its own chunk, and this issue tracks it.
Line numbers below are as of 78d0195a.
Concrete evidence (spot checks, not a full pass)
Stale name (absent from the tree):
build_partial_equation (lines 368 and 2093). Nothing in src/ is named that. The builders are build_partial_equation_shaped (src/simlin-engine/src/ltm_augment.rs:1051) and build_partial_equation_shaped_with_live_ref (:1102). Line 368 attributes the module-ref-aware normalize_module_ref() behaviour to the old name; line 2093 lists it under Test Coverage.
Names that exist but whose surrounding prose has drifted (this is why a name-existence sweep is not sufficient):
recompute_module_input_edge_series (lines 496, 552, 582). The function exists (src/simlin-engine/src/ltm_finding.rs:2168), but its own rustdoc now calls it "the links-slice ADAPTER kept for call sites (and tests) that still hold a Link sequence ... Production no longer calls this directly for a sequential edge -- see ModuleOverrideCache::series". The engine is recompute_module_input_edge_series_for (:2036), memoized by ModuleOverrideCache (:2235). The doc has zero mentions of ModuleOverrideCache or the _for variant, so "This is recompute_module_input_edge_series in ltm_finding.rs" (line 552) and the subscript-stripping attribution (line 582) describe the adapter, not the production path.
"Module Classification" (lines 426-440) states that "Modules fall into three LTM roles: Infrastructure, DynamicModule, Passthrough" as if it were a code-level taxonomy. DynamicModule occurs in the tree only inside comments (ltm_finding.rs:2049, ltm/graph.rs:462, db/ltm_module_tests.rs:415); Infrastructure and Passthrough occur nowhere in ltm/graph.rs, ltm_finding.rs or db/ltm/mod.rs. Whether the three-role prose still matches how model_ltm_variables / modules_carry_state actually decide is unverified.
Checked and found consistent (so the pass does not have to re-litigate these):
The path0 / path1 worked example (lines 475-477) is illustrative, not an identifier. Its claim -- >= first-index tie-break picks the earlier pathway when magnitudes tie -- matches the discovery recompute's let keep_earlier = slot.abs() >= candidate.abs(); in ltm_finding.rs. The emitted composite equation's textual form was not checked.
All seven file paths named in section headings exist (ltm/graph.rs, ltm/types.rs, ltm/partitions.rs, ltm_finding.rs, ltm_finding_enum.rs, ltm_finding_fallback.rs, tests/integration/simulate_ltm.rs), and FoundLoop, CausalGraph, Link, Loop, CyclePartitions are defined where the headings say.
Changelog-style narration (the evergreen rule in the root CLAUDE.md forbids it; the V10 narration rg used a narrower pattern and did not match these): 10 lines, e.g. line 438 "now fires only for", line 600 "Before this fix, discovery read the composite's offset", line 843 "the exhaustive path now uses the all-slots reading", line 588 "This defense is LIVE, not latent, since GH #716 closed", and PR review-comment IDs (r3353459409, r3353597299, r3353097150, r3353758167) at lines 489, 492, 543, 586. GH issue numbers are fine as pointers; review-comment IDs and "before/now" framing are not.
Bounded sweep result (the floor the pass starts from)
Extracting every backticked snake_case / CamelCase identifier from the doc gives 285 distinct names; 278 resolve via rg -F -w in src/simlin-engine/{src,tests}. Of the 7 that do not, 5 are libsimlin / pysimlin surface names present elsewhere in src/ (get_loops, simlin_analyze_discover_loops, simlin_analyze_get_loop_element_count, SimlinDiscoveredPartition, SimlinModel), 1 is an example variable (x_rate), and 1 is genuinely stale (build_partial_equation, item 1). Items 2 and 3 pass this sweep, which is the point: name existence is necessary, not sufficient.
The doc is the designated entry point for LTM (four in-repo pointers, including a runtime warning string). A reader who follows item 2 to recompute_module_input_edge_series lands on the adapter and would reasonably conclude production strips subscripts there; the cache is where the production decision lives.
scripts/check-docs.py validates path references but deliberately blanks inline code spans, so no gate covers backticked identifiers or backticked .rs names in docs/design/. Drift here is invisible to CI and to review (reviewers check code against the doc's claim, not the claim against the tree).
docs/design/ltm--loops-that-matter.md against src/simlin-engine/src/db/ltm/, src/simlin-engine/src/db/ltm_ir.rs, src/simlin-engine/src/ltm_*.rs (ltm_augment*.rs, ltm_finding*.rs, ltm_agg.rs), src/simlin-engine/src/ltm/, src/simlin-engine/src/analysis.rs.
Possible approach
Doc-only chunk, its own PR (no .rs changes expected):
Section by section (Two Modes ~96-158; Cycle Partitions 159-196; Synthetic Variables / Naming 197-283; Link Score Equations 284-418; Module Boundary Handling 419-688; Polarity 689-844; Post-Simulation Discovery 845-1269; Array Support 1270-1843; Pinned Loops 1844-1910; Limitations / Divergences 1911-2079; Test Coverage 2080-2181): for every backticked name run rg -F -w; for every behavioural claim name the function or the test that pins it, or rewrite the claim to what the code does.
Fix items 1-3 above; add ModuleOverrideCache / recompute_module_input_edge_series_for to the discovery-recompute passage; restate the module-role paragraph in terms of the actual decision points (model_ltm_variables, modules_carry_state, find_model_output_ports, the pathway map) rather than a named taxonomy the code does not have.
Re-run the Test Coverage section's test names against #[test] fn definitions (they are in the 278 that resolve today, but check they still test what the bullets say).
Optional prevention, stated as a necessary-condition gate only: extend scripts/check-docs.py (or add a sibling) so every backticked snake_case identifier in docs/design/*.md must resolve with rg -w somewhere in src/. It would have caught item 1 and would not catch items 2-3; say so in the check's docstring.
Discovery context
Out-of-scope discovery of the V10 documentation chunk on the compiler-unification-v2 branch (PR #1040, commit 78d0195a "doc: engine map, ledger and evergreen design docs"). Related tracking: epic #488 (LTM); tech-debt #61 (CLAUDE.md evergreen rule). No open issue covered this (searched "ltm--loops-that-matter.md", "LTM design doc", "docs stale", "loops-that-matter").
Problem
docs/design/ltm--loops-that-matter.md(2,188 lines) is the LTM implementation design doc thatdocs/README.md,docs/architecture.md,src/simlin-engine/CLAUDE.mdand the engine's own auto-switch warning text (db/ltm/mod.rs, "see docs/design/ltm--loops-that-matter.md for the two-tier strategy") all point at. The repo rule is that docs are evergreen and true of the tree.The documentation chunk of the compiler-unification-v2 branch (PR #1040, commit
78d0195a) rewrote and verified the describer sections against the code: thedb/ltm/module table, theRefShapevariants includingPerElement,compute_read_slice, node identity as the spelled reducer,BareSpelling,occurrence_realizes_shape, and the residual carve-outs as the code's current declines. The rest of the document -- the two-modes, module-classification, module-boundary / composite, polarity, post-simulation discovery, array, pinned-loop and test-coverage sections -- still describes the machinery as of 2026-05/06 and was NOT verified name-by-name or claim-by-claim against the current tree. That verification is its own chunk, and this issue tracks it.Line numbers below are as of
78d0195a.Concrete evidence (spot checks, not a full pass)
Stale name (absent from the tree):
build_partial_equation(lines 368 and 2093). Nothing insrc/is named that. The builders arebuild_partial_equation_shaped(src/simlin-engine/src/ltm_augment.rs:1051) andbuild_partial_equation_shaped_with_live_ref(:1102). Line 368 attributes the module-ref-awarenormalize_module_ref()behaviour to the old name; line 2093 lists it under Test Coverage.Names that exist but whose surrounding prose has drifted (this is why a name-existence sweep is not sufficient):
recompute_module_input_edge_series(lines 496, 552, 582). The function exists (src/simlin-engine/src/ltm_finding.rs:2168), but its own rustdoc now calls it "the links-slice ADAPTER kept for call sites (and tests) that still hold aLinksequence ... Production no longer calls this directly for a sequential edge -- seeModuleOverrideCache::series". The engine isrecompute_module_input_edge_series_for(:2036), memoized byModuleOverrideCache(:2235). The doc has zero mentions ofModuleOverrideCacheor the_forvariant, so "This isrecompute_module_input_edge_seriesinltm_finding.rs" (line 552) and the subscript-stripping attribution (line 582) describe the adapter, not the production path."Module Classification" (lines 426-440) states that "Modules fall into three LTM roles: Infrastructure, DynamicModule, Passthrough" as if it were a code-level taxonomy.
DynamicModuleoccurs in the tree only inside comments (ltm_finding.rs:2049,ltm/graph.rs:462,db/ltm_module_tests.rs:415);InfrastructureandPassthroughoccur nowhere inltm/graph.rs,ltm_finding.rsordb/ltm/mod.rs. Whether the three-role prose still matches howmodel_ltm_variables/modules_carry_stateactually decide is unverified.Checked and found consistent (so the pass does not have to re-litigate these):
path0/path1worked example (lines 475-477) is illustrative, not an identifier. Its claim -->=first-index tie-break picks the earlier pathway when magnitudes tie -- matches the discovery recompute'slet keep_earlier = slot.abs() >= candidate.abs();inltm_finding.rs. The emitted composite equation's textual form was not checked.ltm/graph.rs,ltm/types.rs,ltm/partitions.rs,ltm_finding.rs,ltm_finding_enum.rs,ltm_finding_fallback.rs,tests/integration/simulate_ltm.rs), andFoundLoop,CausalGraph,Link,Loop,CyclePartitionsare defined where the headings say.Changelog-style narration (the evergreen rule in the root
CLAUDE.mdforbids it; the V10 narrationrgused a narrower pattern and did not match these): 10 lines, e.g. line 438 "now fires only for", line 600 "Before this fix, discovery read the composite's offset", line 843 "the exhaustive path now uses the all-slots reading", line 588 "This defense is LIVE, not latent, since GH #716 closed", and PR review-comment IDs (r3353459409,r3353597299,r3353097150,r3353758167) at lines 489, 492, 543, 586. GH issue numbers are fine as pointers; review-comment IDs and "before/now" framing are not.Bounded sweep result (the floor the pass starts from)
Extracting every backticked snake_case / CamelCase identifier from the doc gives 285 distinct names; 278 resolve via
rg -F -winsrc/simlin-engine/{src,tests}. Of the 7 that do not, 5 are libsimlin / pysimlin surface names present elsewhere insrc/(get_loops,simlin_analyze_discover_loops,simlin_analyze_get_loop_element_count,SimlinDiscoveredPartition,SimlinModel), 1 is an example variable (x_rate), and 1 is genuinely stale (build_partial_equation, item 1). Items 2 and 3 pass this sweep, which is the point: name existence is necessary, not sufficient.Measurement (name existence only):
Why it matters
recompute_module_input_edge_serieslands on the adapter and would reasonably conclude production strips subscripts there; the cache is where the production decision lives.scripts/check-docs.pyvalidates path references but deliberately blanks inline code spans, so no gate covers backticked identifiers or backticked.rsnames indocs/design/. Drift here is invisible to CI and to review (reviewers check code against the doc's claim, not the claim against the tree).Affected
docs/design/ltm--loops-that-matter.mdagainstsrc/simlin-engine/src/db/ltm/,src/simlin-engine/src/db/ltm_ir.rs,src/simlin-engine/src/ltm_*.rs(ltm_augment*.rs,ltm_finding*.rs,ltm_agg.rs),src/simlin-engine/src/ltm/,src/simlin-engine/src/analysis.rs.Possible approach
Doc-only chunk, its own PR (no
.rschanges expected):rg -F -w; for every behavioural claim name the function or the test that pins it, or rewrite the claim to what the code does.ModuleOverrideCache/recompute_module_input_edge_series_forto the discovery-recompute passage; restate the module-role paragraph in terms of the actual decision points (model_ltm_variables,modules_carry_state,find_model_output_ports, the pathway map) rather than a named taxonomy the code does not have.compute_module_link_overridesdoes the same" instead of "This defense is LIVE ... since GH ltm: scalar module output feeding an arrayed reader emits a single scalar constant-0 link score, dropping all arrayed loops through modules #716 closed"); drop the review-comment IDs.#[test] fndefinitions (they are in the 278 that resolve today, but check they still test what the bullets say).scripts/check-docs.py(or add a sibling) so every backticked snake_case identifier indocs/design/*.mdmust resolve withrg -wsomewhere insrc/. It would have caught item 1 and would not catch items 2-3; say so in the check's docstring.Discovery context
Out-of-scope discovery of the V10 documentation chunk on the compiler-unification-v2 branch (PR #1040, commit
78d0195a"doc: engine map, ledger and evergreen design docs"). Related tracking: epic #488 (LTM); tech-debt #61 (CLAUDE.md evergreen rule). No open issue covered this (searched "ltm--loops-that-matter.md", "LTM design doc", "docs stale", "loops-that-matter").