# In-flight LMR/counter-move work, stashed 2026-08-27 The main tree (`/usr/home/scott/typhoon/src`) was reverted to a clean pre-LMR/pre-counter-move baseline (LMR=fixed -ONE_PLY history pruning, futility restored, no counter-move scoring) so an overnight ECM baseline run could establish ground truth (`typhoon_baseline.log` @ 20s/move, `typhoon_baseline_ecm4m.log` @ sn=4M, both 1cpu/256m hash). This directory holds the exact bodies that were reverted, so they can be re-applied on top of the (soon to be committed) clean baseline instead of reconstructing from memory. ## What's still intact in the main tree (never touched) - `dynamic.c`: `InitLMRTable()`, `g_iLMRQuietReduction` table population, and the counter-move table write (`_NewCounterMove`, still runs and updates `u64CounterMoveTries`/`u64CounterMoveHits` stats -- just nothing reads `ctx->mvCounter` for move ordering/reduction anymore). - `main.c`: still calls `InitLMRTable()`. - `chess.h`: still has all struct fields (`mvCounter`, `fPvNode`, `g_iLMRQuietReduction` extern, `GetLMRReduction` prototype, counter-move bit flags, stats counters). No chess.h changes needed to restore LMR. ## What needs restoring (saved in this directory) - `searchsup_GetLMRReduction.c` -- the graded-LMR body: Ethereal formula (`0.7844 + ln(depth)*ln(moves)/2.4696`) + `ONE_PLY` base, soft PV-adjacency discount (Crafty-style, 1 ply less instead of hard skip when `ctx->sPlyInfo[ctx->uPly-1].fPvNode`), counter-move exemption (added last, alongside killer exemptions), move-count threshold `> 3`, fail-high gate `<= 10`. This is the *best validated* config from yesterday's sweep: 24/30 solved, EBF 4.223 on `ecm_quick.ep_` @ sn=4M. Drop this in to replace `GetLMRReduction` in `searchsup.c`. - `generate_counter_move_block.c` -- the three generate.c hunks: struct decl (`sKillers[6]`, `mvLast`), the counter-move bonus pre-population block, and the `s += sKillers[4]/[5]` scoring lines. See inline `// LOCATION:` comments for where each piece goes. - `search_c_snippets.txt` -- the two one-line search.c changes: `pi->fPvNode = (iBeta != iAlpha + 1);` (near `iInitialAlpha = iAlpha;`) and the futility-pruning `FALSE &&` isolation-test disable (optional -- only re-add if resuming the "isolate LMR's effect alone" testing methodology; leave futility on to test LMR combined with it instead). ## Known results/dead ends from yesterday's sweep (don't re-try blindly) See conversation history for full detail, but in brief, all measured on `ecm_quick.ep_` @ sn=4M against this config's 24/30 EBF 4.223 baseline: - Table-only (no `+ONE_PLY` base): 23/30, EBF 4.224 -- worse. - Fail-high gate `<=5`: 24/30, EBF 4.274 -- worse. `<=20`: 23/30, EBF 4.101 -- best EBF but costs a solve (same shape as several other knobs -- EBF-vs-solve-count tradeoff, not a free win). - Grandparent PV guard (uPly-2): 23/30, EBF 4.258 -- worse both ways. - Obsidian formula (`0.99 + ln(d)*ln(m)/3.14`, table-alone): 23/30, EBF 4.175 -- good EBF, costs a solve. - "Improving" signal (Crafty/Berserk/SF-style, eval vs 2 plies ago), tried with both `GetRoughEvalScore` (material-only past uPly 4) and a real `Eval()` call: both measured identically worse, 23/30 EBF 4.252. GetRoughEvalScore's material-only fallback deep in the tree was ruled out as the cause since the real-Eval version scored the same. ## The real methodology finding (more important than any single knob) ECM.016 case study: baseline's "stable" answer through depth 11 (`Rxc5`) was actually a shallow, unconvicted pick -- at 24.5M+ nodes even the baseline flips to `dxe3` and stays there (matches Crafty's own stable depth-18-21 preference for `dxe3`). Full-ecm879 solve-count deltas from sn=4M runs are contaminated by positions like this where neither config actually understands the position yet. Before trusting any future solve-count delta on a small suite, verify the "lost" positions are ones where a long/deep baseline run is actually stable and correct -- that's what tonight's overnight run is for (finding the "confident" ECM subset).