# CL cache-lab sweep & rebuild matrix (S0-S7) Task: Z5NOPD (epic KIMRKS) — 369-line corpus sweep of the instrumented CL-table cache strategies, every solve byte-compared against the full-rebuild reference. ## How the cache layer works (high level) Reference for reading the matrix. The cache-less reference solve (`int_solve_cl_path`) rebuilds two derived tables per hop on every solve: 1. **Crossing table** — one entry per range; each entry carries the accumulated integer `(gross_input, output)` crossing amounts as the walk moves through successive ranges. The active-set Möbius walk consumes it to jump across already-crossed ranges. The entries are cumulative, so they can be stored as per-range *segments* (diffs) and re-summed cheaply. 2. **Word profiles** (`ClProfileTable`) — one optional profile per range, built only for "dense" ranges spanning ≥ `WORD_PROFILE_THRESHOLD` 256-tick word boundaries. It is a piecewise bucket curve that lets the solver and profit envelope skip straight to the next meaningful boundary. Deriving both from a live sequence is the dominant per-solve cost when uncached (see `docs/hotpath-crossing-cache-verification.md`). The seam: every call passes the hop sequences plus a `CacheEvent` (`Fresh` | `PriceMove` | `Liquidity` | `TickCross` | `Restore`) to `strategy.refill(seqs, event)`, which returns one prepared `(crossing, profile)` pair per hop, consumed by `int_solve_cl_path_cached`. Each strategy answers one question per hop: *can I serve the solver a correct table cheaper than rebuilding?* Correctness is exact — every epoch's solution must be byte-identical to the S0 full-rebuild reference; any divergence is a failure, not a tolerance band. - **Memo** (S1 fused epoch, S5 probe): key = (hop index, full state key). Hit → clone two `Arc`s in O(1); miss → rebuild both tables and store. "Fused" = crossing table and profile table are invalidated as one unit. S5 adds first-sight bookkeeping (`sequence_rebuilds`) on top of the same memo. - **Patch** (S2 price overlay): on a price-only move with structure unchanged, recompute only the new price's effect at range 1 and propagate that delta across all subsequent prefix entries; rebuild just range 0's profile. - **Segment** (S3 prefix, S4 dirty-suffix): store per-range crossing segments instead of prefix sums; on `PriceMove` recompute only segment 0 and re-sum the table O(n) (S4 extends this to `Liquidity` by resegmenting just the jittered range). - **Split** (S6 profile, S7 composite): cache crossings and profiles at different granularities — crossings keyed by full state, profiles keyed per-range by ending-range identity — so a price-only move reuses most profile tables. S7 combines S4-style segment crossings with S6-style split profiles. **Why S1 wins.** The patch/segment family looks cheaper in theory and leads the small CI pin (6 price-only rebuilds vs S1's 26), but under the deep corpus its validity guards trip often — caches carry segments across different pool states and any shape mismatch forces a full rebuild anyway (198 price-only rebuilds vs S1's 89; 817 vs 214 total crossing builds). S6 touched profiles 173,019 times vs S1's 214. The fused-epoch memo is the smallest cache that stays exact on the real stream: deterministic O(1) hit or clean full rebuild, no partial-state corruption risk. ## Method - Harness: `rust/crates/engine/degenbot-solvers/examples/cl_cache_lab.rs`, replaying `rust/crates/engine/degenbot-solvers/tests/fixtures/heavy_cl_solve_captures.jsonl` (420 corpus lines) as deterministic pool-state transition commands. - Strategies refill crossing tables + word profiles through the same production builders and solve through the production `int_solve_cl_path_cached` entry; no parallel implementation (measurement is of the real code path). - Each path's transition stream is seeded from `(path_id, line_index)`; event classes are sampled price-only 2/5, liquidity 1/5, tick-cross 1/5, restore 1/5. - Counters: `crossing_tables` / `profile_tables` = tables built, `sequence_rebuilds` = full (crossing+profile) hop rebuilds, `partial_rebuilds` = segment/profile patches, `solves` = epochs solved. - Exactness: every strategy's byte-identical output vs the S0 full-rebuild reference is required at every epoch. The harness prints the total-divergences line only at normal completion and exits 1 on any divergence; all runs below completed with 0 divergences and no DIVERGENCE lines, so every run exited 0. ## 1. 369-line corpus sweep (the deliverable run) `DRCLAB_MAX_PATHS=369 DRCLAB_TRANS=2` → 369 paths x 2 transitions = 738 epochs. Wall clock **9 min 0 s** (file birth 10:25:30Z to final write 10:34:30Z, including process start). A second capture of the same run is byte-identical (deterministic transition streams). Validation-gate invocation: ``` DRCLAB_MAX_PATHS=369 DRCLAB_TRANS=2 cargo run -q -p degenbot-solvers --manifest-path rust/Cargo.toml --example cl_cache_lab -- rust/crates/engine/degenbot-solvers/tests/fixtures/heavy_cl_solve_captures.jsonl ``` ### Table A — class rebuild deltas, 369x2 sweep (crossing tables built) | Strategy | price-only | liquidity | tick-cross | restore | |---|---:|---:|---:|---:| | S0_full_rebuild | 268 | 157 | 155 | 158 | | S1_fused_epoch | **89** | **60** | **39** | **26** | | S2_price_overlay_patch | 198 | 210 | 222 | 187 | | S3_segment_prefix | 198 | 210 | 222 | 187 | | S4_dirty_suffix_segments | 198 | 121 | 222 | 187 | | S5_seq_memo_probe | **89** | **60** | **39** | **26** | | S6_profile_split | **89** | **60** | **39** | **26** | | S7_composite_split | 198 | 121 | 222 | 187 | ### Table B — cumulative counters, 369x2 sweep | Strategy | crossing | profiles | seq_rebuilds | partial | solves | |---|---:|---:|---:|---:|---:| | S0_full_rebuild | 738 | 738 | 0 | 0 | 738 | | S1_fused_epoch | 214 | 214 | 214 | 0 | 738 | | S2_price_overlay_patch | 817 | 817 | 0 | 160 | 738 | | S3_segment_prefix | 817 | 817 | 0 | 160 | 738 | | S4_dirty_suffix_segments | 728 | 728 | 0 | 249 | 738 | | S5_seq_memo_probe | 214 | 214 | 977 | 0 | 738 | | S6_profile_split | 214 | 173,019 | 0 | 0 | 738 | | S7_composite_split | 728 | 173,019 | 0 | 249 | 738 | **Total divergences: 0** (all 8 strategies, all 738 epochs). ## 2. CI pin (12 paths x 6 transitions = 72 epochs) Authoritative pin data from the pre-sweep run of the first 12 corpus lines. ### Table C — class rebuild deltas, CI pin | Strategy | price-only | liquidity | tick-cross | restore | |---|---:|---:|---:|---:| | S0_full_rebuild | 32 | 16 | 10 | 14 | | S1_fused_epoch | 26 | 14 | 6 | 3 | | S2_price_overlay_patch | **6** | 21 | 10 | 20 | | S3_segment_prefix | **6** | 21 | 10 | 20 | | S4_dirty_suffix_segments | **6** | 9 | 10 | 20 | | S5_seq_memo_probe | 26 | 14 | 6 | 3 | | S6_profile_split | 26 | 14 | 6 | 3 | | S7_composite_split | **6** | 9 | 10 | 20 | ### Table D — cumulative counters, CI pin | Strategy | crossing | profiles | seq_rebuilds | partial | solves | |---|---:|---:|---:|---:|---:| | S0_full_rebuild | 72 | 72 | 0 | 0 | 72 | | S1_fused_epoch | 49 | 49 | 49 | 0 | 72 | | S2_price_overlay_patch | 57 | 57 | 0 | 29 | 72 | | S3_segment_prefix | 57 | 57 | 0 | 29 | 72 | | S4_dirty_suffix_segments | 45 | 45 | 0 | 41 | 72 | | S5_seq_memo_probe | 49 | 49 | 86 | 0 | 72 | | S6_profile_split | 49 | 9,135 | 0 | 0 | 72 | | S7_composite_split | 45 | 9,135 | 0 | 41 | 72 | **Total divergences: 0.** ## 3. Prefix probe (12 paths x 2 transitions = 24 epochs) The exact first-2-transitions prefix of the CI-pin paths, run as a decomposition check during this task. ### Table E — class rebuild deltas, 12x2 prefix probe | Strategy | price-only | liquidity | tick-cross | restore | |---|---:|---:|---:|---:| | S0_full_rebuild | 8 | 5 | 4 | 7 | | S1_fused_epoch | 9 | 6 | 4 | 3 | | S2_price_overlay_patch | **5** | 7 | 4 | 9 | | S3_segment_prefix | **5** | 7 | 4 | 9 | | S4_dirty_suffix_segments | **5** | 6 | 4 | 9 | | S5_seq_memo_probe | 9 | 6 | 4 | 3 | | S6_profile_split | 9 | 6 | 4 | 3 | | S7_composite_split | **5** | 6 | 4 | 9 | Cumulative counters (12x2): S0 24/24/0/0, S1 22/22/22/0, S2 25/25/0/5, S3 25/25/0/5, S4 24/24/0/6, S5 22/22/30/0, S6 22/6,697/0/0, S7 24/6,697/0/6 — each at solves=24. **Total divergences: 0.** ## 4. Reading the numbers - Internal consistency: in every run, each strategy's class-delta row sums exactly to its `crossing_tables` counter (Table A rows sum to Table B `crossing`; same for the two pin sets). The lab's accounting is coherent. - **Corpus-tail decomposition.** Subtracting the 12x2 prefix probe from the 369x2 sweep locks the remaining 714 epochs (paths 12..368): price-only crossing builds there are S1/S5/S6 **80**, S2/S3/S4/S7 **193**, S0 **260**. The overlay/segment family wins the pin sets (5-6 price-only rebuilds vs 9-26 for the memo family) but degrades ~2.4x deeper into the corpus (817 vs 214 total crossing builds), where per-hop caches carrying foreign segments across paths make its patch guard fail and rebuild. - S6_profile_split builds 173,019 profile tables for 214 crossing tables on the sweep (and 9,135/6,697 on the pin sets) — a per-solve profile construction storm, the dominant cost anywhere it runs. - S5_seq_memo_probe's class-delta matrix is identical to S1's, but its `sequence_rebuilds` counter is 977 vs S1's 214 (and 86 vs 49 on the CI pin) — strictly more rebuild work for identical reuse behaviour. ## 5. Recommendation **Promote S1_fused_epoch.** On the 369-line corpus sweep S1 ties S5 and S6 for the fewest price-only rebuilds (89 vs S0 268 and the overlay/segment family's 198) with 0 divergences everywhere, and among the tied three S1 has the lowest total rebuild work: 214 crossing + 214 profile + 214 sequence rebuilds, versus S5's 977 sequence rebuilds and the 173,019-profile storm of S6. The same break holds on the CI pin (seq_rebuilds 49 vs 86, profiles 49 vs 9,135), and S1 is the incumbent already landed in production (the `hp_cl_solve_final2.json` comparator), so promotion carries no new-cache semantics risk — the fused memo is the robust choice at corpus depth. ## 6. Gaps / next step - The harness does not emit per-path timestamps, so per-path wall medians/p95 cannot be reported factually from this data; the sweep wall is 9m0s for 738 epochs. Latency evidence is the job of the next task's hotpath run (KGXFT7) against `logs/hp_cl_solve_final2.json`. - No fixture or corpus changes: the profit-envelope test still checks only the first 12 full goldens as intended.