Commit Graph
7140 Commits
Author SHA1 Message Date
Shawn XuandJoost VandeVondele d91c7f6eac Update main network to nn-0ee0657fb25e.nnue
Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 26976 W: 7185 L: 6883 D: 12908
Ptnml(0-2): 89, 3058, 6895, 3354, 92
https://tests.stockfishchess.org/tests/view/6a46dd46f97ff95f78795707

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 101394 W: 26460 L: 26009 D: 48925
Ptnml(0-2): 74, 10871, 28367, 11300, 85
https://tests.stockfishchess.org/tests/view/6a46eff2f97ff95f7879573b

fixes a potential overflow when rescaling network evals.

nettest: vondele/nettest#403

closes https://github.com/official-stockfish/Stockfish/pull/6944

Bench: 2752030
2026-07-03 20:19:10 +02:00
e33bb26ee7 Update nnue-architecture to SFNNv15
Updating nnue to a new architecture including a newly trained net using recipe https://github.com/vondele/nettest/pull/395 and trainer https://github.com/official-stockfish/nnue-pytorch/pull/480.

The recipe contains many small improvements additionally the newly relabled data. Thus this is a combined effort.

Passed STC
https://tests.stockfishchess.org/tests/view/6a429fd8f97ff95f78795110
```
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 25312 W: 6725 L: 6422 D: 12165
Ptnml(0-2): 78, 2915, 6397, 3158, 108
```

Passed LTC
https://tests.stockfishchess.org/tests/view/6a434c4cf97ff95f78795235
```
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 32814 W: 8655 L: 8345 D: 15814
Ptnml(0-2): 17, 3469, 9132, 3765, 24
```

closes https://github.com/official-stockfish/Stockfish/pull/6938

Bench: 2639962

Co-authored-by: anematode <anematode@users.noreply.github.com>
Co-authored-by: Joost VandeVondele <vondele@users.noreply.github.com>
Co-authored-by: xu-shawn <xu-shawn@users.noreply.github.com>
2026-07-03 20:07:49 +02:00
yl25946andJoost VandeVondele 6088838797 Yeet psqt weights
Simplifying the ratio in the eval between the psqt and the positional eval to a basic addition

Passed Nonreg STC:
https://tests.stockfishchess.org/tests/view/6a3eaac63036e45021aeb937
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 207392 W: 53521 L: 53489 D: 100382
Ptnml(0-2): 585, 24412, 53748, 24288, 663

Passed Nonreg LTC:
https://tests.stockfishchess.org/tests/view/6a423666f97ff95f7879508e
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 27198 W: 7200 L: 6989 D: 13009
Ptnml(0-2): 12, 2794, 7779, 2999, 15

closes https://github.com/official-stockfish/Stockfish/pull/6934

Bench: 2067208
2026-06-30 06:22:29 +02:00
Shawn XuandJoost VandeVondele 4488343cf6 Update main network to nn-af1339a6dea3.nnue
This network is trained by adding the following binpacks, relabeled by @vondele and totaling 74B positions, to the distillation fine-tuning stage:
```
  - vondele/from_kaggle_1_relabel/leela96-filt-v2.min.split_0.relabel-BT4-tf13tune.binpack
  - vondele/from_kaggle_1_relabel/leela96-filt-v2.min.split_1.relabel-BT4-tf13tune.binpack
  - vondele/from_kaggle_1_relabel/leela96-filt-v2.min.split_2.relabel-BT4-tf13tune.binpack
  - vondele/from_kaggle_1_relabel/leela96-filt-v2.min.split_3.relabel-BT4-tf13tune.binpack
  - vondele/from_kaggle_1_relabel/leela96-filt-v2.min.split_4.relabel-BT4-tf13tune.binpack
  - vondele/from_kaggle_2_relabel/T60T70wIsRightFarseerT60T74T75T76.split_0.relabel-BT4-tf13tune.binpack
  - vondele/from_kaggle_2_relabel/T60T70wIsRightFarseerT60T74T75T76.split_1.relabel-BT4-tf13tune.binpack
  - vondele/from_kaggle_2_relabel/T60T70wIsRightFarseerT60T74T75T76.split_2.relabel-BT4-tf13tune.binpack
  - vondele/from_kaggle_2_relabel/T60T70wIsRightFarseerT60T74T75T76.split_3.relabel-BT4-tf13tune.binpack
  - vondele/from_kaggle_2_relabel/T60T70wIsRightFarseerT60T74T75T76.split_4.relabel-BT4-tf13tune.binpack
```

The relabeling effort has been completed during the testing of this patch, and a full training run is on the way. Thanks to @vondele, @anematode, @Disservin, @yl25946, and all who've contributed to the process.

Passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 24512 W: 6500 L: 6201 D: 11811
Ptnml(0-2): 69, 2772, 6300, 3021, 94
https://tests.stockfishchess.org/tests/view/6a40b7083036e45021aebbd6

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 15708 W: 4232 L: 3960 D: 7516
Ptnml(0-2): 8, 1572, 4420, 1848, 6
https://tests.stockfishchess.org/tests/view/6a413d293036e45021aebc84

nettest PR: https://github.com/vondele/nettest/pull/388

closes https://github.com/official-stockfish/Stockfish/pull/6932

Bench: 2102535

Co-authored-by: Joost VandeVondele <Joost.VandeVondele@gmail.com>
2026-06-29 06:32:19 +02:00
Shawn XuandDisservin 9d2ba2bed5 Update main network to nn-1b6a82263149.nnue
Add `test80-2024-01-jan-2tb7p.min-v2.v6.relabel.binpack` to the distillation fine tuning stage, an additional 3.5B (2.9B non-skipped) positions.

nettest PR: https://github.com/vondele/nettest/pull/375

Passed STC (vs #6924):
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 57952 W: 15000 L: 14656 D: 28296
Ptnml(0-2): 164, 6651, 15003, 6993, 165
https://tests.stockfishchess.org/tests/view/6a3cca103036e45021aeb6f8

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 81456 W: 21265 L: 20858 D: 39333
Ptnml(0-2): 52, 8630, 22958, 9035, 53
https://tests.stockfishchess.org/tests/view/6a3dbe203036e45021aeb828

closes https://github.com/official-stockfish/Stockfish/pull/6929

Bench: 2703604
2026-06-27 15:30:39 +02:00
DavidandDisservin feb932533d Update bug report template
closes https://github.com/official-stockfish/Stockfish/pull/6926

No functional change
2026-06-27 15:30:23 +02:00
FauziAkramandJoost VandeVondele 47575ebd8b Deduplicating Color-Specific Piece Validation
Deduplicating Color-Specific Piece Validation.

The validation checks for the number of pawns and additional promoted pieces are duplicated for WHITE and BLACK. We can combine this logic into a single range-based for loop over both colors.

closes https://github.com/official-stockfish/Stockfish/pull/6922

No functional change
2026-06-25 13:11:17 +02:00
Daniel MonroeandJoost VandeVondele 3c858c19e6 Two small simplifications
Passed simplification STC
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 206368 W: 52592 L: 52560 D: 101216
Ptnml(0-2): 537, 24201, 53669, 24247, 530
https://tests.stockfishchess.org/tests/view/6a2c5ab00d5d4b19d0805326

Passed simplification LTC
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 109944 W: 27839 L: 27709 D: 54396
Ptnml(0-2): 61, 11938, 30844, 12068, 61
https://tests.stockfishchess.org/tests/view/6a2dc6e70d5d4b19d08053aa

closes https://github.com/official-stockfish/Stockfish/pull/6913

Bench: 2767133
2026-06-25 13:10:08 +02:00
zungurandJoost VandeVondele 782852b26a Clear capturedPiece in do_null_move
do_null_move copies the whole StateInfo from the previous state, which leaves capturedPiece holding the piece captured by the last real move, so inside the null-move subtree captured_piece() reports a stale capture. The priorCapture consumers in search are all guarded by prevSq != SQ_NONE or (ss-1)->currentMove.is_ok(), which are false at the null-move child, but the stalemate verification gate in qsearch reads captured_piece() unguarded and can be spuriously triggered by the stale value.

Clear the field, since a null move captures nothing.

Passed non-regression STC:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 82784 W: 21172 L: 21011 D: 40601
Ptnml(0-2): 194, 8976, 22923, 9073, 226
https://tests.stockfishchess.org/tests/view/6a2b5b356b4aa63ddbf31518

Passed non-regression LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 118134 W: 30007 L: 29891 D: 58236
Ptnml(0-2): 66, 11856, 35108, 11970, 67
https://tests.stockfishchess.org/tests/view/6a2c4c9c0d5d4b19d0805301

closes https://github.com/official-stockfish/Stockfish/pull/6910

No functional change
2026-06-25 13:09:32 +02:00
zungurandJoost VandeVondele 5b87bc48cd Remove unused search-layer APIs
The following have zero call sites repo-wide:

    SearchManager:🆔 never read or written (also never initialized, nor was it ever used).
    Search::Worker::elapsed_time(): never called. PV output uses tm.elapsed_time() (TimeManager) directly. (removed callers on 25361e5)
    MovePicker::begin()/end(): unused private accessors. (removed callers on 8c2d21f)

closes https://github.com/official-stockfish/Stockfish/pull/6909

No functional change
2026-06-25 13:09:03 +02:00
FauziAkramandJoost VandeVondele 1ece3c030d Simplify Evasion Logic
When the king is in check, a pseudo-legal move must be a valid evasion. Instead of duplicating the checking rules for king and non-king moves, we can leverage the existing MoveList<EVASIONS> class.

Passed non-reg STC:
LLR: 2.98 (-2.94,2.94) <-1.75,0.25>
Total: 187360 W: 47579 L: 47524 D: 92257
Ptnml(0-2): 418, 20266, 52263, 20309, 424
https://tests.stockfishchess.org/tests/view/6a28aa5b7c758d82accea13c

closes https://github.com/official-stockfish/Stockfish/pull/6902

No functional change
2026-06-25 13:07:50 +02:00
9fcd47a717 Update main network to nn-f8a759c05f9f.nnue
This network is further trained on a new BT4 distillation stage, fine tuning on ~2 billion positions relabeled with the value head output of `BT4-tf13tune.pb.gz`. The dataset can be found at https://huggingface.co/datasets/xushawn/test80-bt4-relabel. A modified branch of lc0 was used to derive this data: https://github.com/xu-shawn/lc0/tree/relabel_dual_stream_test

2 billion positions represent a tiny subset of the total training data, and BT4 relabeling is inherently computationally expensive. I expect a lot more gains as more data are relabeled, but it will likely require coordinated community effort. Everyone is welcome to contribute, and yl25946 has made a spreadsheet to track progress: https://docs.google.com/spreadsheets/d/1yanofhusEzDg8ZnurAw799ikoTY6GcqsNMYfpswOIbw/edit.

Special thanks to Viren6, who performed policy/value distillation experiments on Monty, and created the lc0 distillation fork that the current relabeler is based on; yl25946 for proposing the idea of large network distillations back in February 2025, running distillation experiments on the HL4096 network, and working on fine tuning attempts; vondele for nettest and suggesting the fine-tuning approach; and many others on the knowledge distillation thread in the SF Discord #ideas channel.

nettest PR: https://github.com/vondele/nettest/pull/369

Ongoing STC:
 LLR: -0.01 (-2.94,2.94) <0.00,2.00>
Total: 72224 W: 18891 L: 18784 D: 34549
Ptnml(0-2): 336, 8437, 18332, 8798, 209
https://tests.stockfishchess.org/tests/view/6a3ae7913036e45021aeb4a0

Passed LTC:
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 25110 W: 6566 L: 6288 D: 12256
Ptnml(0-2): 27, 2625, 6957, 2935, 11
https://tests.stockfishchess.org/tests/view/6a3b73513036e45021aeb51e

Passed VLTC:
 LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 18544 W: 4924 L: 4658 D: 8962
Ptnml(0-2): 5, 1730, 5533, 2002, 2
https://tests.stockfishchess.org/tests/view/6a3bbe233036e45021aeb56e

closes https://github.com/official-stockfish/Stockfish/pull/6924

Bench: 2710209

Co-authored-by: Li Ying <121075683+yl25946@users.noreply.github.com>
Co-authored-by: Viren6 <94880762+Viren6@users.noreply.github.com>
2026-06-25 13:06:10 +02:00
Michael ChalyandJoost VandeVondele d64835051e Do more aggressive probCut when improving.
If improving is true reduce depth of probCut search by 1.
Passed STC:
https://tests.stockfishchess.org/tests/view/6a2a6ceb17167cbe7100a909
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 119136 W: 30591 L: 30158 D: 58387
Ptnml(0-2): 323, 13831, 30845, 14228, 341
Passed LTC:
https://tests.stockfishchess.org/tests/view/6a2d65a40d5d4b19d080537f
LLR: 2.96 (-2.94,2.94) <0.50,2.50>
Total: 186552 W: 47377 L: 46755 D: 92420
Ptnml(0-2): 89, 20047, 52395, 20643, 102

closes https://github.com/official-stockfish/Stockfish/pull/6914

Bench: 2422062
2026-06-25 13:04:20 +02:00
Dalton HanawayandJoost VandeVondele 6f97594eda prefetch the TT entry as soon as the move is known
Worker::do_move computes the successor hash key via the new
Position::key_after(m) and prefetches the TT entry one full do_move
earlier than the existing prefetch in Position::do_move. key_after does
not model castling, en passant or promotion keys exactly; for rare
moves the prefetch lands on an unused line.

`key_after` has been around since 2014 (https://github.com/official-stockfish/Stockfish/commit/82d065b0) and was removed in (https://github.com/official-stockfish/Stockfish/pull/5770). Adding back `prefetch_key` helps in common, normal moves at the cost of extra compute.

Speedup (PGO vs PGO, interleaved paired bench, n=48 pairs, Apple M2
Pro / apple-silicon): +0.69% [0.47, 0.91]

Passed STC:
https://tests.stockfishchess.org/tests/view/6a291f8d7c758d82accea17f
LLR: 4.24 (-2.94,2.94) <0.00,2.00>
Total: 473504 W: 121250 L: 120228 D: 232026
Ptnml(0-2): 1112, 51137, 131251, 52121, 1131

No functional change

closes https://github.com/official-stockfish/Stockfish/pull/6911

No functional change
2026-06-25 13:03:44 +02:00
anematodeandJoost VandeVondele 31e89adf70 [RfC] Make CI faster
We can straightforwardly parallelize the `check_universal.sh` script, which takes quite a bit of time for the x86 builds.

closes https://github.com/official-stockfish/Stockfish/pull/6919

No functional change
2026-06-25 13:03:07 +02:00
Robert Nurnberg @ elitebookandDisservin 74a0a73715 Final fix for MultiPV mate PV corner cases
This PR fixes the remaining corner cases in the treatment of MultiPV
mated-in PVs, as well as an oversight in #6886. See the discussion in

In particular:
1. `previousScore` and `previousPV` can only be trusted, if that
   rootmove was indeed fully searched in the previous iteration.
2. A move beyond `pvIdx` (that was hence not fully searched) may have an
   exact loss score that cannot be trusted. So if a MultiPV search gets
   aborted while searching `pvIdx`, we mark all the following loss
   scores as bounds.
3. The forgotten mate logic also got broken in #6886, because the
   `previousPV` of the forgotten mate's bestmove can only be trusted if
   that move was fully searched in the previous iteration, something
   that is not guaranteed. So we now store both `lastBestMoveScore` and
   `lastBestMovePV`.

Here some scenarios for MultiPV = 8 that explain how master was broken:
1. Move A with an inexact mated-in-2 score from the previous iteration
   (so outside the top8 moves) gets flushed into the top8 moves for the
   current iteration, because the previous top8 move B is now scored as
   a mated-in-1. Hence we cannot trust `previousScore` or `previousPV`
   for move A, if the search gets aborted while it is being searched.
2. In the scenario above, move B has `Score != -VALUE_INFINITE` and a
   mated-in-1 score, which cannot be trusted as it was not fully
   searched.
3. Iteration N has bestmove A with mated-in-10, which gets recorded in
   `lastBestMoveScore` (renamed from `lastIterationScore`). Iteration 11
   forgets the mate and has bestmove B with a cp score, move A may have
   an incomplete PV, and may even have a non-mate score. Iteration 12
   gets aborted, and in trying to remember the forgotten mate, master
   recovers the `previousScore` and `previousPV` of move A, which may be
   neither mate nor complete.

Passed STC non-reg:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 69728 W: 17748 L: 17573 D: 34407
Ptnml(0-2): 143, 7571, 19274, 7720, 156
https://tests.stockfishchess.org/tests/view/6a2c40c60d5d4b19d08052f2

closes https://github.com/official-stockfish/Stockfish/pull/6906

No functional change
2026-06-14 09:58:13 +02:00
anematodeandDisservin f9b002cf7d Share continuation history between threads
Passed 8th 5+0.05 https://tests.stockfishchess.org/tests/view/6a0bfdb46524d21ee79b879b
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 23472 W: 6103 L: 5823 D: 11546
Ptnml(0-2): 26, 2501, 6403, 2779, 27

Passed 8th 20+0.2 https://tests.stockfishchess.org/tests/view/6a0c87196524d21ee79b885c
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 44692 W: 11640 L: 11319 D: 21733
Ptnml(0-2): 12, 4418, 13169, 4731, 16

Passed 16th 5+0.05 https://tests.stockfishchess.org/tests/view/6a20533f818cacc1db0ad32b
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 14720 W: 3910 L: 3642 D: 7168
Ptnml(0-2): 6, 1434, 4223, 1680, 17

Passed 64th 10+0.1 https://tests.stockfishchess.org/tests/view/6a20ae8e818cacc1db0ad369

LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 34096 W: 8889 L: 8607 D: 16600
Ptnml(0-2): 4, 2974, 10808, 3260, 2

Continuation history is fixed size so there's a much more false sharing and a larger speed loss here at high thread counts, unfortunately.

vondele's machine, 4x70

```
==== master ====
Average (over 3):  294528128
==== shared-conthist ====
Average (over 3):  282364217 (~4% slowdown)
```

my machine, 8x32
```
Nodes/second               : 243157385
Nodes/second               : 228374554 (~6% slowdown)
```

Evidently it still gains at 64th, but a few followup ideas to try get the speed back:
- Add padding in `PieceToHistory` stats so there's less false sharing.
- Subdivide continuation history more finely than shared correction history.
- Scramble the `PieceToHistory` indexing so there's less false sharing

closes https://github.com/official-stockfish/Stockfish/pull/6905

No functional change
2026-06-14 09:58:13 +02:00
zungurandDisservin f9beec5fa5 Reuse computed ray bitboard in update_piece_threats
Reuse the already-computed ray instead of calling ray_pass_bb a second time with identical arguments.

closes https://github.com/official-stockfish/Stockfish/pull/6899

No functional change
2026-06-14 09:58:13 +02:00
zungurandDisservin ed8e35d759 Remove unused code from the post NNUE accumulator merge
After merging the HalfKA and Threats accumulators (7c7fe322) and the
subsequent removal of the double-incremental/fused update, a number of
NNUE helpers and fields became unreachable. Each was verified to have
zero callers/readers across the source tree:

- FusedUpdateData logic in FullThreats: the fused-update branch of
  append_changed_indices and the FusedUpdateData parameter are unused;
  the accumulator update no longer passes fused data.
- FullThreats::requires_refresh: never called. The live king-bucket
  refresh check is HalfKAv2_hm::requires_refresh (PSQFeatureSet), used
  in nnue_accumulator.
- HalfKAv2_hm::append_active_indices: never called. The live
  active-index builder is FullThreats::append_active_indices
  (ThreatFeatureSet).
- DirtyThreats::us, prevKsq and ksq: written in do_move but only read by
  the now-removed FullThreats::requires_refresh. Removing them also
  drops three stores from the do_move path.
- Unused feature Name constants and the unused FtOneVal / HiddenMaxVal
  constants in nnue_common.h.
- Two stale feature-header banner comments.

closes https://github.com/official-stockfish/Stockfish/pull/6898

No functional change
2026-06-14 09:58:13 +02:00
Disservin 6e4e03fd28 Replace Remaining Types
Somehow a few size_t slipped through https://github.com/official-stockfish/Stockfish/pull/6874

closes https://github.com/official-stockfish/Stockfish/pull/6897

No functional change
2026-06-14 09:58:13 +02:00
Disservin 718a001e6a Fixup RelaxedAtomic operator Types
As pointed out in
https://github.com/official-stockfish/Stockfish/commit/0111d11e2356147bad21c1f890b271a30d10a580#r188197707,
the parameter type should be `T` not `int`

closes https://github.com/official-stockfish/Stockfish/pull/6896

No functional change
2026-06-14 09:58:13 +02:00
Joost VandeVondeleandDisservin 0dc19b61ae More stable matetrack CI
This version handles aborting engine processes more gracefully. This
also test the engine prior to use, as the process is nevertheless not
fully robust.

closes https://github.com/official-stockfish/Stockfish/pull/6893

No functional change
2026-06-14 09:58:05 +02:00
anematodeandJoost VandeVondele 86f1df7134 Fix material key computation error
Fixes an error introduced in 278a755fb5 https://github.com/official-stockfish/Stockfish/pull/6891

Also enables more checking in debug builds

closes https://github.com/official-stockfish/Stockfish/pull/6894

No functional change
2026-06-10 23:01:50 +02:00
zungurandJoost VandeVondele 5595cb20ea Fix FEN validation of pawns on first or eighth rank
The FEN validation check intended to reject pawns on the first or eighth rank uses the `Rank` enum values in a bitwise OR operation:

`if (pieces(PAWN) & (RANK_1 | RANK_8))`

`RANK_1 | RANK_8` evaluates to the integer `0 | 7 == 7` instead of a bitboard, so the expression only tests squares A1, B1 and C1. As a result, unsupported positions with pawns elsewhere on the first or eighth rank are silently accepted. For instance, `position fen 3P3k/8/8/8/8/8/8/3K4 w - - 0 1` is accepted even though the pawn on d8 makes the position unsupported.

Use the `Rank1BB | Rank8BB` bitboard constants so any pawn on the first or eighth rank are correctly rejected.

closes https://github.com/official-stockfish/Stockfish/pull/6887

No functional change
2026-06-10 12:44:57 +02:00
Robert Nurnberg @ elitebookandJoost VandeVondele 7b37032885 Stop searching if we cannot find a better move
In a recent CCC event, Stockfish (probably through no fault of its own), lost some games on time when it was winning and when it had already found the move that delivers checkmate.

This patch stops the search when TM is active, and when mainthread can be certain that it is impossible to find a better move. That is if (i) it has found mate-in-1, (ii) it has found a mate-in-2 or (iii) it has found a mated-in-1.

patch:
```
position fen 5K2/8/2qk4/2nPp3/3r4/6B1/B7/3R4 w - e6
go wtime 100000000 winc 100000000
info string Available processors: 0-7
info string Using 1 thread
info string NNUE evaluation using nn-71d6d32cb962.nnue (106MiB, (83248, 1024, 31, 32, 1))
info string Network replica 1: Shared memory.
info depth 1 seldepth 3 multipv 1 score mate 1 nodes 30 nps 30000 hashfull 0 tbhits 0 time 1 pv d5e6
bestmove d5e6
```

master:
```
position fen 5K2/8/2qk4/2nPp3/3r4/6B1/B7/3R4 w - e6
go wtime 100000000 winc 100000000
info string Available processors: 0-7
info string Using 1 thread
info string NNUE evaluation using nn-71d6d32cb962.nnue (106MiB, (83248, 1024, 31, 32, 1))
info string Network replica 1: Shared memory.
info depth 1 seldepth 3 multipv 1 score mate 1 nodes 30 nps 15000 hashfull 0 tbhits 0 time 2 pv d5e6
<snip>
info depth 245 seldepth 2 multipv 1 score mate 1 nodes 5886 nps 367875 hashfull 0 tbhits 0 time 16 pv d5e6
bestmove d5e6
```

Note: In MultiPV analysis (extremely rare with TM active), we take the point of view that the user would like to continue to search until none of the PVs can be improved anymore. This means we only stop if the worst searched line is at least a mate-in-2, or if the best searched line is a mated-in-1.

closes https://github.com/official-stockfish/Stockfish/pull/6879

No functional change
2026-06-10 12:42:01 +02:00
Carlos EsparzaandJoost VandeVondele 278a755fb5 Reorder operations in do_move
Passed STC
 https://tests.stockfishchess.org/tests/view/6a2682ce351b79f679cc47c5
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 57248 W: 14730 L: 14399 D: 28119
Ptnml(0-2): 145, 6159, 15698, 6464, 158

Reordering operations in `do_move` allows us to effectively prefetch the TT entry earlier, since the piece moving helpers don't actually modify the position key.  I suspect that with threat inputs, `put_piece` and friends got a lot more expensive, and so this helps us a lot.

vondele's machine:

==== master ====
1 Nodes/second : 294311526
2 Nodes/second : 297068312
3 Nodes/second : 297418763
Average (over 3):  296266200
==== pfearly ====
1 Nodes/second : 303986449
2 Nodes/second : 304221719
3 Nodes/second : 305302969
Average (over 3):  304503712 (+2.78%)

Locally, `bench`:

Result of 200 runs
speedup         = +0.0158
P(speedup > 0) =  1.0000

As expected it helps even more in a large-hash, NUMA setting.

closes https://github.com/official-stockfish/Stockfish/pull/6891

No functional change
2026-06-10 12:37:12 +02:00
anematodeandJoost VandeVondele 7c7fe322ea Merge HalfKA and Threats accumulators
Passed STC (https://tests.stockfishchess.org/tests/view/6a2893ad7c758d82accea129):
LLR: 3.20 (-2.94,2.94) <0.00,2.00>
Total: 23328 W: 6145 L: 5838 D: 11345
Ptnml(0-2): 50, 2463, 6346, 2740, 65

Instead of repeatedly doing the sum HalfKA + threats at the end, it's profitable to simply store one accumulator per side that combines them. This also avoids an extra/load store of an accumulator, and halves the cache footprint of the accumulators.

For full refreshes, we always compute both halfka and threats simultaneously. Any threat full refresh is always a halfka refresh because it occurs when the king crosses the center line, while halfka refreshes are required for ANY king move, so we don't need a separate detection path for threats.

I get about a 2.5% speedup locally with this, but I'd appreciate other ppl's measurements.

closes https://github.com/official-stockfish/Stockfish/pull/6890

No functional change
2026-06-10 08:40:26 +02:00
anematodeandJoost VandeVondele 0111d11e23 Add ability to disable performance-sensitive relaxed atomic operations at compile time
Adds a `RelaxedAtomic`  wrapper around either `T` or `std::atomic<T>` and `USE_SLOPPY_ATOMICS` preprocessor define. The intent of this flag is to allow easy disabling of atomics on WASM, where even relaxed atomics are expensive because all atomics have `seq_cst` semantics.

Passed non regression STC
LLR: 2.99 (-2.94,2.94) <-1.75,0.25>
Total: 50624 W: 12976 L: 12776 D: 24872
Ptnml(0-2): 112, 5445, 14005, 5631, 119
https://tests.stockfishchess.org/tests/view/6a1f690e818cacc1db0ad2c7

Passed non-regression STC SMP
 LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 163696 W: 41514 L: 41438 D: 80744
Ptnml(0-2): 162, 18272, 44904, 18348, 162
https://tests.stockfishchess.org/tests/view/6a21fb97351b79f679cc44b3

Using this class for the TT also allows us to remove the TSAN suppressions, since the UB is fixed.

closes https://github.com/official-stockfish/Stockfish/pull/6877

No functional change
2026-06-09 21:52:29 +02:00
Abdul KhanandJoost VandeVondele 415ff793a0 Fix test harness timeout enforcement
Fixes #6881.

`timeout_decorator()` used a `ThreadPoolExecutor` context manager around blocking output waits. When `future.result(timeout=...)` timed out, leaving the context manager still waited for the worker thread to finish, so a blocked stdout read could keep the instrumented tests hanging past the configured timeout.

This change removes that executor wrapper for interactive Stockfish output waits. The harness now drains process output on a daemon reader thread, queues received lines, and applies the deadline directly while waiting for the next queued line. `TimeoutException` also initializes the base exception message so failures show useful text.

Validation:
- `python3 -m py_compile tests/testing.py tests/instrumented.py`
- local timeout smoke test: a 0.2s no-output wait raises in ~0.204s
- Stockfish smoke test: startup/`uciok` read succeeds, deliberate no-output wait raises in ~0.205s, engine exits 0
- `make -C src -j4 build`
- `../tests/signature.sh` -> `2814421`

closes https://github.com/official-stockfish/Stockfish/pull/6882

No functional change
2026-06-09 19:38:00 +02:00
Robert Nurnberg @ elitebookandJoost VandeVondele 1eff8b0389 Guarantee complete mate PVs in multiPV analysis
This PR introduces the additional `RootMove` attribute `previousPV` so that scores and PVs we send to the GUI in MultiPV analysis always match. This allows us in particular to extend our guarantee of exact mate (and TB win/loss) scores having a complete PV (leading to checkmate in the correct number of plies) to all PV lines. Recall that master fails here, since partially searched root moves may send to the GUI the previous score with the current/modified PV. See #6784.

The PR also uses the new attribute to extend the followPV logic to the analysis of sidelines, building on the idea in #6813 by @joergoster.

Passed non-reg STC:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 166880 W: 42357 L: 42282 D: 82241
Ptnml(0-2): 394, 18685, 45177, 18820, 364
https://tests.stockfishchess.org/tests/view/6a0dea55818cacc1db0abb6a

Failed non-reg LTC:
LLR: -2.97 (-2.94,2.94) <-1.75,0.25>
Total: 890520 W: 224168 L: 225282 D: 441070
Ptnml(0-2): 390, 91902, 261789, 90790, 389
https://tests.stockfishchess.org/tests/view/6a1143ad818cacc1db0ac14c

Opening as draft for discussion on how to proceed. In SinglePV analysis, the patch is completely nonfunctional. But it is maybe a (small?) slowdown because of the increased size of `RootMove`. I am not sure if there as an elegant way to enrich the class only for MultiPV analysis (but the switch can happen at any time through the UCI interface), or to mitigate the speed penalty in some other way.

A local speedup test shows only a small slowdown on my system (but still high error bars):
```
sf_base =  1156928 +/-   1459 (95%)
sf_test =  1155885 +/-   1283 (95%)
diff    =    -1043 +/-   1777 (95%)
speedup = -0.09021% +/- 0.154% (95%)
```

The PR also adds the new MultiPV mate PV correctness check to the CI.

closes https://github.com/official-stockfish/Stockfish/pull/6886

No functional change
2026-06-09 19:36:14 +02:00
anematodeandJoost VandeVondele 8e711c29fe Add wasm32 and wasm32-relaxed-simd targets, and light optimizations
Lichess maintains some patches on top of SF dev to get it working with Emscripten. This PR moves some of these patches into SF and adds WASM to CI. It also adds a few changes in places where the x86 intrinsics don't cleanly map onto WebAssembly SIMD instructions; otherwise, we use Emscripten's x86 compatibility layer and take SSE4.1 code paths.

Summary of the compatibility changes:

- Define `wasm32` and `wasm32-relaxed-simd` targets.
    - We don't support wasm without SIMD; it'd be a waste of time.
- Add option to disable TBs
    - This is required because `tbprobe.cpp` pulls in `mmap`. This option can be used on any target, of course, but it's only enabled by default for wasm.
- Add compilation job + test to CI

And the changes for performance:

- Disable atomics for shared history on wasm
    - Atomics are always `seq_cst` there, which can be quite slow (even on the x86, stores are locked `xchg [mem], reg`)
- Add SSE code path to `get_changed_pieces`, modeled after the AVX2 path
- `_mm_mulhi_epi16` has a complicated emulation sequence, so for the pairwise multiplication, use an approach similar to the NEON impl.
- __int128 is gets lowered to runtime functions on wasm, so use the fallback impl for `mul_hi64`
- V8 does a poor job with the NNZ finding, so use a slightly different sequence there
- Add relaxed simd support for `m128_dpbusd`.

Some local perf figures (single-threaded speedtest):

```
wasm
Nodes/second               : 902523
sse4.1
Nodes/second               : 1155380
avx512icl
Nodes/second               : 1676184
```

Further avenues to explore:
- Optimize for performance under V8's experimental AVX revectorizer (Currently it's about +10% in my testing, but could definittely be more)
- Branch hinting. For example, run bench while collecting branch frequency info, then inject it late in the WASM compilation pipeline. I tried this locally and it didn't help much, but maybe I'm missing something.
- PGO. Gives +1.5% NPS locally, but hard to integrate with WASM compilation wrokflows

closes https://github.com/official-stockfish/Stockfish/pull/6875

No functional change
2026-06-09 19:35:05 +02:00
DisservinandJoost VandeVondele dd3e1c4a50 Consistent Integer Types
example of using, to avoid mixed usage of std::uint/std::int and uint/int...
```cpp
using u64 = std::uint64_t;
using u32 = std::uint32_t;
using u16 = std::uint16_t;
using u8  = std::uint8_t;

using i64 = std::int64_t;
using i32 = std::int32_t;
using i16 = std::int16_t;
using i8  = std::int8_t;

using usize = std::size_t;
using isize = std::ptrdiff_t;

#if defined(__GNUC__) && defined(IS_64BIT)
__extension__ using u128 = unsigned __int128;
__extension__ using i128 = signed __int128;
#endif
```

closes https://github.com/official-stockfish/Stockfish/pull/6874

No functional change
2026-06-08 19:54:33 +02:00
FauziAkramandJoost VandeVondele e4a635486a Simplify margin formula
Passed STC non-reg:
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 46944 W: 11934 L: 11730 D: 23280
Ptnml(0-2): 95, 5403, 12273, 5605, 96
https://tests.stockfishchess.org/tests/view/6a0b018d6524d21ee79b8680

Passed LTC non-reg:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 535980 W: 135398 L: 135702 D: 264880
Ptnml(0-2): 241, 58385, 151023, 58119, 222
https://tests.stockfishchess.org/tests/view/6a0c3ab86524d21ee79b87f2

Passed VLTC non-reg:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 126632 W: 32068 L: 31961 D: 62603
Ptnml(0-2): 14, 12466, 38244, 12583, 9
https://tests.stockfishchess.org/tests/view/6a1ac130818cacc1db0ad03c

closes https://github.com/official-stockfish/Stockfish/pull/6880

Bench: 3493826
2026-06-06 10:15:00 +02:00
dav1312andJoost VandeVondele 92fe6b6f4c Simplify RankAttacks initialization
Simplify by replacing the manual ray-casting loop with a single call to the canonical sliding_attack() helper.

closes https://github.com/official-stockfish/Stockfish/pull/6869

No functional change
2026-06-06 10:13:46 +02:00
AdrianandJoost VandeVondele 73826352d4 Simplify quiet history update expression
This patch simplifies the quiet history update expression in search.cpp.

The change is behaviour‑identical and removes unnecessary complexity from
the update_quiet_histories call.

Passed STC (non‑regression):
https://tests.stockfishchess.org/tests/view/6a14367b818cacc1db0ac7c3
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 52224 W: 13338 L: 13135 D: 25751
Ptnml(0-2): 118, 6065, 13557, 6240, 132

Passed LTC (non‑regression):
https://tests.stockfishchess.org/tests/view/6a155046818cacc1db0ac94d
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 136812 W: 34689 L: 34586 D: 67537
Ptnml(0-2): 51, 14770, 38668, 14859, 58

Both STC and LTC passed. Patch rebased to latest master.

closes https://github.com/official-stockfish/Stockfish/pull/6863

Bench: 2549662
2026-06-06 10:12:36 +02:00
DubslowandJoost VandeVondele db11ca42d5 Guard tt depth edits from racy underflows
Two recent patches, involving editing TTEs, introduced potential racy underflows. Guarding against these doesn't appear to gain elo but does improve sanity.

fixes https://github.com/official-stockfish/Stockfish/issues/6847

STC: https://tests.stockfishchess.org/tests/view/6a1c8c4b818cacc1db0ad158
LLR: 3.85 (-2.94,2.94) <-1.75,0.25>
Total: 125984 W: 32248 L: 32055 D: 61681
Ptnml(0-2): 292, 13678, 34866, 13857, 299

SMP STC: https://tests.stockfishchess.org/tests/view/6a1fb2ba818cacc1db0ad2e2
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 104272 W: 26524 L: 26385 D: 51363
Ptnml(0-2): 103, 11650, 28494, 11783, 106

closes https://github.com/official-stockfish/Stockfish/pull/6883

No functional change
2026-06-06 10:08:26 +02:00
Stefan GeschwentnerandJoost VandeVondele 645b636dfa Tweak best move history updates.
If not at an PV node, scale history bonus for the found best move up proportionally to the count of the other moves searched.

Passed STC:
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 219712 W: 56104 L: 55525 D: 108083
Ptnml(0-2): 565, 25482, 57188, 26051, 570
https://tests.stockfishchess.org/tests/view/6a1306fb818cacc1db0ac5b7

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 53988 W: 13851 L: 13498 D: 26639
Ptnml(0-2): 22, 5779, 15051, 6108, 34
https://tests.stockfishchess.org/tests/view/6a1b557e818cacc1db0ad0b8

closes https://github.com/official-stockfish/Stockfish/pull/6871

Bench: 2935474
2026-06-06 10:05:50 +02:00
Niklas FiekasandJoost VandeVondele 9eb836b3b5 Compute simplified HQ r/rr at runtime
Hyperbola Quintessence works out without the "... * 2" in r and rr. This then is cheap enough to compute at runtime, instead of looking it up, for a minor speedup.

Passed apple-silicon|armv8|loongarch64 STC:
https://tests.stockfishchess.org/tests/view/6a15f031818cacc1db0aca49
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 410208 W: 104369 L: 103556 D: 202283
Ptnml(0-2): 758, 43951, 114883, 44744, 768

Verified attacks_bb<ROOK>() and attacks_bb<BISHOP>() assembly remains unchanged on x86 (gcc 16.1.1).

closes https://github.com/official-stockfish/Stockfish/pull/6870

No functional change
2026-06-06 10:04:39 +02:00
anematodeandJoost VandeVondele db6cba47d6 More loongarch optimizations
Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 113120 W: 29094 L: 28674 D: 55352
Ptnml(0-2): 362, 12619, 30248, 12899, 432
https://tests.stockfishchess.org/tests/view/6a1486f7818cacc1db0ac832

closes https://github.com/official-stockfish/Stockfish/pull/6862

No functional change
2026-06-06 10:03:25 +02:00
BerektassulyandJoost VandeVondele 8416ccafff fix Makefile universal build selection
and remove armv8 left-over

closes https://github.com/official-stockfish/Stockfish/pull/6876

No functional change
2026-06-06 10:01:37 +02:00
CiekceandJoost VandeVondele 0c1001c93e Disable PEXT on AMD Excavator CPUs
Excavator also supports BMI2, where it has the same microcoded performance implications as on Zen pre-3.

closes https://github.com/official-stockfish/Stockfish/pull/6868

No functional change
2026-06-06 09:58:43 +02:00
Joost VandeVondele 91045b2ff6 [CI] Update SDE action
more robust and efficient installation process.
Thanks @ppetrovt

closes https://github.com/official-stockfish/Stockfish/pull/6885

No functional change
2026-06-06 09:57:45 +02:00
FauziAkramandJoost VandeVondele b1053e60b7 Simplify Internal Iterative Reductions (IIR) Condition
Passed STC non-reg:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 75840 W: 19367 L: 19192 D: 37281
Ptnml(0-2): 186, 8837, 19710, 8990, 197
https://tests.stockfishchess.org/tests/view/6a0b02ba6524d21ee79b8685

Passed LTC non-reg:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 166920 W: 42039 L: 41967 D: 82914
Ptnml(0-2): 78, 18155, 46919, 18233, 75
https://tests.stockfishchess.org/tests/view/6a0c98fb6524d21ee79b8875

Passed VTC non-reg:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 46390 W: 11914 L: 11729 D: 22747
Ptnml(0-2): 8, 4543, 13911, 4722, 11
https://tests.stockfishchess.org/tests/view/6a143877818cacc1db0ac7c5

closes https://github.com/official-stockfish/Stockfish/pull/6861

Bench: 2814421
2026-05-29 19:06:38 +02:00
8cbca11a53 macOS universal binary, take 2
- Add new target `macos-lipo`.
   - Created by compiling a universal x86 binary (no PGO) and a standard Apple silicon binary (with PGO), then combining them into a Mach-O fat binary
   - To keep only one copy of the net, we add custom loading logic in the x86 section. The executable reads its own path and mmaps the net that's in the ARM section.
       - The offset and size (from the executable base) of the mapping is injected after compilation in `patch_x86_slice.sh`
   - avx512 on macOS isn't advertised in the xcr0 register by default. The simple solution I came up with is to execute a dummy AVX512 instruction, which sets up the register, before calling `__builtin_cpu_init`.

Some housekeeping as well:
- Rename `armv8-universal` -> `arm64-universal`.
- Add standard copyright headers to the files we've added recently.

Potential follow-ups:
- Disservin's Makefile cleanup
- Alternative ideas for the net loading. In particular, this will error out if the user strips the binary (since that'll invalidate the offset).

closes https://github.com/official-stockfish/Stockfish/pull/6860

No functional change

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-29 19:05:53 +02:00
Ryan HirschandJoost VandeVondele 24a551899e Speed up feature transform on neon
STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 109344 W: 27919 L: 27520 D: 53905
Ptnml(0-2): 200, 11718, 30434, 12123, 197
https://tests.stockfishchess.org/tests/view/6a123ed0818cacc1db0ac39e

Updated to anematode’s suggestion - apparently clang already optimized it to this.

Apple M1

Result of 100 runs
base (...kfish.master) = 1307276 +/- 10930
test (./stockfish ) = 1320940 +/- 11279
diff = +13664 +/- 2223

speedup = +0.0105
P(speedup > 0) = 1.0000

closes https://github.com/official-stockfish/Stockfish/pull/6855

No functional change
2026-05-29 19:05:08 +02:00
TonyandJoost VandeVondele 313ea4ab04 Update main network to nn-71d6d32cb962.nnue
Using a net trained with Quantization Aware Training (QAT)

See:
- https://github.com/official-stockfish/nnue-pytorch/pull/477
- https://github.com/vondele/nettest/pull/346

CHANGES: To allow QAT some small changes had to be made.
- Quant scheme now only uses perfect power of two scales for anything but the very last output.
- Final output conversion happens in int64 to completely eliminate the chance of overflows.

REFACTORING: Some small refactoring was done to improve maintainability.
- Different weight scales are supported for different layers 64 or 128 instead of only 64).
- Changed order of weight segments in ft weights to simplify serialization.

Passed STC
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 23904 W: 6271 L: 5970 D: 11663
Ptnml(0-2): 87, 2742, 5995, 3039, 89
https://tests.stockfishchess.org/tests/view/6a0f6911818cacc1db0abdea

Passed LTC
LLR: 3.01 (-2.94,2.94) <0.50,2.50>
Total: 82950 W: 21276 L: 20857 D: 40817
Ptnml(0-2): 50, 8976, 23015, 9373, 61
https://tests.stockfishchess.org/tests/view/6a0fe40d818cacc1db0abe88

closes https://github.com/official-stockfish/Stockfish/pull/6856

Bench: 3003571

Co-authored-by: Joost VandeVondele <Joost.VandeVondele@gmail.com>
2026-05-27 07:06:17 +02:00
anematodeandJoost VandeVondele 564f9f9c85 Fix sloppy L3 cache detection code
Fixes https://github.com/official-stockfish/Stockfish/issues/6857

Many thanks to Andrew for the repro

closes https://github.com/official-stockfish/Stockfish/pull/6858

No functional change
2026-05-27 07:05:56 +02:00
anematodeandJoost VandeVondele 77a8f6ccf3 HQ attacks for AVX2
passed STC (https://tests.stockfishchess.org/tests/view/6a1157dc818cacc1db0ac172):

LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 29792 W: 7759 L: 7465 D: 14568
Ptnml(0-2): 75, 3206, 8033, 3514, 68

Also passed STC after cleanups https://tests.stockfishchess.org/tests/view/6a121beb818cacc1db0ac35e

vondele's local test:

Result of 100 runs
base (./stockfish.master       ) =    1136025  +/- 2816
test (./stockfish.patch2       ) =    1171370  +/- 2848
diff                             =     +35346  +/- 3275

speedup        = +0.0311
P(speedup > 0) =  1.0000

Basically we just do hyperbola quintessence in parallel. AVX2 doesn't have efficient bit reversal so we only do it for file and bishop attacks, then do rank attacks separately with a lookup table. This LUT is much smaller which is why this seems to be faster than standard magics.

closes https://github.com/official-stockfish/Stockfish/pull/6845

No functional change
2026-05-25 11:20:24 +02:00
Joost VandeVondele 41f3557db9 Further binary releases fixes
* .tar -> .tar.gz: save a few more MB in distribution.
* drop android armv7 without NEON support: there should be almost no devices around that do not support this.

closes https://github.com/official-stockfish/Stockfish/pull/6850

No functional change
2026-05-25 11:20:01 +02:00
anematodeandJoost VandeVondele 05f48577e1 Fix partial MADV_POPULATE_WRITE
Potentially fixes https://github.com/official-stockfish/Stockfish/issues/6846

I'm not a Linux guru but here's my understanding of what's going on, from looking at strace logs.

If `/dev/shm` is undersized or too full, `MADV_POPULATE_WRITE` can partially fault in the pages and then return an error. The crash then happens in the second process, on the first read to `header_ptr_->initialized`. There's a TOCTOU between when the region is attachable (the second process can see it in `/dev/shm`) and when we can actually safely read from it. The SIGBUS happens because `/dev/shm` is so full from partially faulted pages that we can't even fault in a single additional page.

This didn't happen before because a failed `posix_fallocate` *rolls back any faulted pages*. Then the second process faults in one page (which succeeds), reads a `0` from `header_ptr_->initialized`, declares the region invalid, and continues to try (and fail) to set up its own region.

There's still a problem here, methinks, if the process gets killed/interrupted between the failed `madvise` and the `ftruncate`. I think a more robust approach is to create the file anonymously first (to prevent other processes from attaching to it), then `linkat` to publish it atomically, but that would be more implementation work. (Could create a follow-up issue for that as an nice first issue for new contribs?)

closes https://github.com/official-stockfish/Stockfish/pull/6852

No functional change
2026-05-25 11:19:40 +02:00