Stockfish-PVS v2
How it works
Step by step: (1) the context suffix is hashed with SplitMix64 Zobrist keys (`zhash`) separately for 5-, 4- and 3-grams. (2) During rollout, `ngram-map.cpp` queries `StockfishDrafter::query()`/`probe5/4/3`, resolving 1-ply horizon choices and disambiguating conflicting in-context suffix matches. (3) On every subsequent forward pass, `observe()` compares the remembered draft (`last_draft`) against the tokens actually committed. (4) An accepted token (`actual == drafted`) increments `wins` in `tt5/tt4/tt3` and boosts `history` via the History Gravity formula (`h += bonus - h * |bonus| / 512`, +128). (5) A rejected token (`actual != drafted`) records the proposed token as `refuted_move` (killer/refutation), promotes the actual token to `best_move`, and penalizes the entry (-128 to -224). (6) Extending the horizon to M=7 (batch = 8 tokens) is activated only for "singular" paths — when `true_consensus_hits >= 2`, a macro-codebook chain fires, or a singular cascade match plus a Zobrist-TT lock occurs — and every extended token must be confirmed by RouteCrack or the Zobrist TT and remain unrefuted.
Problem solved
On a CPU running a Sparse MoE + hybrid Mamba-2 model, every wasted draft token costs an extra ~0.30×T1 (the marginal MoE expert-routing cost out of DDR5), and every rejection forces a costly Mamba-2 recurrent-state rollback (~18.4 MB). Static predictors trained on the same corpus make correlated errors, so unconditionally extending the draft horizon (e.g. M=5→7) sharply lowers precision. Stockfish-PVS v2 supplies an orthogonal, session-derived verification signal that lets drafts be pruned safely and the horizon extended only when the path is "singular".
Components
Three tables of 4,096 entries × 16 B (64 KB each, 192 KB total in the rc_stockfish.h header), indexed by Zobrist keys for 5-, 4- and 3-gram suffixes. Each entry (SFTTBucket) stores key32, best_move, refuted_move, history, wins and total.
64-bit hashing of the context suffix via SplitMix64; the upper 32 bits serve as key32 and the lower bits as the table index (TT_MASK). Lockless identification of the context state.
Move-history score update: h += bonus - h * |bonus| / 512, bounding history in [-512, +512] without saturation and penalizing static predictions previously refuted by the target model.
Every rejected draft is recorded as refuted_move, while the actual token committed by the target model is promoted as best_move. Acts as an immediate refutation filter on in-context matches.
Inspired by Stockfish singular extensions, extends the draft horizon to M=7 (batch = 8 tokens) only for "singular" paths (true_consensus_hits >= 2, a macro chain, or a singular cascade + Zobrist lock), requiring each extended token to be confirmed.
Per ARCHITECTURE.md, the full StockfishDrafter design includes Principal Variation Search with late move reductions (LMR) over token candidates. Note: the published rc_stockfish.h header implements a leaner subset (Zobrist tables + History Gravity + killer/refutation); PVS/LMR are described in the architecture documentation.
Per ARCHITECTURE.md and the technique catalog (#93 countermove table prev2→replacement, #94 2-ply continuation history), the full design includes a 1 MB countermove table and a 256 KB continuation-history table. Note: these components are not present in the published rc_stockfish.h header and are documented in the architecture description.
When the cascade’s primary candidate (ent.pred[0]) is refuted or uncertain, secondary candidates (pred[1..3]) are promoted if they are simultaneously the verified best_move in the session Zobrist TT and backed by the trie/PPM — giving a signal orthogonal to correlated static predictors.
Implementation
Hyperparameters (configurable axes)
Maximum draft length in tokens; M=7 means a batch of 8 tokens. Flag --spec-ngram-simple-size-m.
Entries per single transposition table (TT_ENTRIES), a power of two for index masking.
History-score range and gravity divisor in the formula h += bonus - h * |bonus| / 512.
Computational complexity
Time complexity: O(1). Space complexity: O(1).
Hardware requirements
Designed for draftless CPU speculative decoding (Zen 5, AMD Ryzen 9 9955HX). The tables (192 KB) are fully resident in a core’s private L2 and do not pollute the shared L3 or the KV/Mamba-2 states.