Offline experiment · detector ai-workspace/game-story-prod-review/regen/positional-detect.mjs · chess.js only, no engine call, no Python change · 2026-09-04
Can plain board rules (passed pawn, king cover, open file, trapped piece...) explain the 58 pending moments? Result: about a third, not all.
1. What I built
A Node script reads each pending moment: the position before the move, the move played, the better move, and the engine's 6-ply line after each. It computes board facts for both sides at each ply of both lines, and fires a rule when the played line is worse on a fact and the move that caused it is the played move or the reply. Fuzzy facts (piece mobility, checks available, attackers near the king) are kept apart as weak signals.
| Rule | In words | Primary hits |
|---|---|---|
perpetual-check-missed | A draw by perpetual check was there | 3 |
piece-trapped | A piece is attacked and has no safe square | 3 |
piece-pinned | A piece is pinned | 2 |
forced-queen-trade | The reply forces a queen trade | 0 |
forced-rook-trade | The reply forces a rook trade | 0 |
needless-trade | The move trades off a good piece for nothing | 0 |
king-walks-from-cover | The king walks away from its pawn cover | 1 |
king-to-center | The king walks into the open | 1 |
king-cover-lost | A pawn in front of the king is gone | 1 |
passed-pawn-for-them | The move gives them a passed pawn | 1 |
passed-pawn-lost | The better move made a passed pawn | 1 |
their-passer-advances | Their passed pawn runs | 1 |
best-was-rook-to-open-file | The better move puts a rook on the open file | 7 |
rook-leaves-open-file | The rook leaves the open file | 2 |
their-rook-takes-file-or-7th | Their rook takes the open file or the 7th rank | 1 |
piece-hanging | A piece is attacked and must move (tempo) | 4 |
knight-to-rim | The knight goes to the edge | 1 |
pawn-structure | The move makes doubled or isolated pawns | 0 |
their-outpost | Their piece gets an outpost | 0 |
pawn-attacked-more-than-defended | A pawn has more attackers than defenders | 5 |
makes-way | The better move clears a square for the next move | 4 |
king-under-attack | More attackers near the king (fuzzy) | 1 |
more-checks-on-me | They get many more checks (fuzzy) | 1 |
less-active | Your pieces have far fewer moves (fuzzy) | 4 |
2. The numbers
A rule that fires is not a rule that is right. I checked 14 of the concrete hits by hand on the board. 11 of 14 name the real reason or a fair part of it. 3 name a side fact and miss the real reason.
So the honest estimate is: the concrete rules give a true, simple sentence for about 30 of the 58 moments. Of those, some already appear in today's story as a fact appendix (for example "It gives them a passed pawn on c3"). The other 28 need something else: a forcing line the story rejects today, the threat search, or a reason no board rule can name.
3. Where the wrong hits come from
The wrong hits share one shape: the rule sees a true fact that is not the point. A king-cover rule fires on a pawn push far from any danger. A hanging-rook rule fires when the real story is a rook trade into a pawn ending. A knight-guard rule fires when the real miss is a mating attack. Board rules cannot rank facts by importance. The engine score says how bad the move is, but not why.
Two wrong hits pointed at rules I did not have. Both are now in the script and both are Node-only: a perpetual check that was there (the better move gives check after check, or the line repeats, and the score is level), and a reply that forces a queen or rook trade into a lost ending.
4. Every pending moment
| Case | Side | Played | Better | Drop | Primary rule | Detail | Other hits | Hand check |
|---|---|---|---|---|---|---|---|---|
1b858313:31positional-gives-material | w | Qd4 | Qc4 | 520 | A piece is attacked and has no safe square | piece-trapped@2 qd4 after Qe5+ | piece-hanging@2, forced-queen-trade@4 | right Qe5+ forces the queen trade into a lost pawn ending. |
43b0c5fa:16positional-no-material | b | a4 | Rg7 | 130 | nothing fires | |||
43b0c5fa:27lines-too-short | w | d7 | Qe6 | 100 | A pawn in front of the king is gone | king-cover-lost@1 shield 0 vs 1 after d7 | pawn-attacked-more-than-defended@2 | wrong The pawn push is far from any danger. The real point is the a-pawn run after Qe6. |
43b0c5fa:30positional-gives-material | b | Qf3+ | Rg3+ | 114 | nothing fires | |||
1ee86237:9positional-gives-material | w | Qxa4 | Ng5 | - | nothing fires | |||
ce5469b0:2positional-no-material | b | Rb5 | Rbd8 | 113 | The better move puts a rook on the open file | best-was-rook-to-open-file@1 Rbd8 | their-rook-takes-file-or-7th@2 | right Rbd8 doubles rooks on the d-file. Rb5 lets their rook swing to f2. |
aaf8f107:4last-move-no-reply | b | Rc7 | Rfe8 | 109 | The better move puts a rook on the open file | best-was-rook-to-open-file@1 Rfe8 | rook-leaves-open-file@1 | |
8d0b0f46:7last-move-no-reply | w | Bf4 | Nh5 | 187 | Your pieces have far fewer moves (fuzzy) | less-active@2 mob 31-43 vs 40-44 material changes in the line at ply 6 | ||
67088156:6positional-no-material | b | d3 | Rac8 | 140 | The better move puts a rook on the open file | best-was-rook-to-open-file@1 Rac8 | pawn-attacked-more-than-defended@1 | right Rac8 takes the open c-file. |
67088156:12positional-gives-material | b | Kh8 | Kxh7 | 248 | Your pieces have far fewer moves (fuzzy) | less-active@1 mob 56-34 vs 57-27 material changes in the line at ply 1 | more-checks-on-me@2 | |
9f68fbe5:1positional-gives-material | w | Qh4 | Qg3 | 226 | The better move clears a square for the next move | makes-way@1 Qg3 clears f2 for Rxf8+ material changes in the line at ply 3 | passed-pawn-for-them@2, their-passer-advances@2, piece-hanging@2 | right f4 hits the bishop with tempo. The story already says it. |
9f68fbe5:7last-move-no-reply | w | Bh6 | Kf2 | 485 | A piece is attacked and has no safe square | piece-trapped@2 bh6 after Qg4+ material changes in the line at ply 5 | piece-hanging@2 | |
4661effb:14positional-no-material | b | Bxd4 | Qa2+ | 140 | A piece is pinned | piece-pinned@1 bd4>q after Bxd4 | makes-way@1, less-active@1, more-checks-on-me@2 | |
4661effb:46positional-gives-material | b | Qb2+ | Bxg3+ | 211 | A piece is attacked and must move (tempo) | piece-hanging@2 bd6 after Kh1 material changes in the line at ply 1 | ||
4661effb:49positional-no-material | w | Qc5+ | Qc4+ | 317 | The better move clears a square for the next move | makes-way@1 Qc4+ clears d5 for Qg8+ | piece-hanging@2 | wrong The knight guard is a side point. The real miss is the mating attack after Qc4+. |
4661effb:50last-move-no-reply | b | Kd8 | Kb8 | 251 | The king walks away from its pawn cover | king-walks-from-cover@1 shield 0 vs 1 | king-to-center@1, piece-trapped@2, more-checks-on-me@2, less-active@2 | |
60a3b89d:2positional-gives-material | b | Bxf3 | e5 | 103 | The better move clears a square for the next move | makes-way@1 e5 clears e6 for Qg4+ | needless-trade@2 | right Bxf3 trades off the strong bishop for nothing (needless trade). The hanging rule alone was wrong. |
b8eb8d2e:4positional-gives-material | b | g5 | Rb8 | 129 | The better move puts a rook on the open file | best-was-rook-to-open-file@1 Rb8 material changes in the line at ply 2 | more-checks-on-me@1, less-active@1, passed-pawn-for-them@2 | |
1eb7a1d5:10positional-no-material | b | Rd8 | Kg8 | 122 | Their passed pawn runs | their-passer-advances@2 a5 | right The a-pawn runs. The story already says it. | |
1eb7a1d5:12positional-no-material | b | Ra8 | Rb8 | 103 | The rook leaves the open file | rook-leaves-open-file@1 Ra8 | ||
1eb7a1d5:15positional-gives-material | w | Re7 | a7 | 121 | The rook leaves the open file | rook-leaves-open-file@1 Re7 | piece-hanging@2, less-active@2 | |
bead1460:5positional-no-material | w | Qf4 | Bxf7+ | 208 | Your pieces have far fewer moves (fuzzy) | less-active@1 mob 45-38 vs 39-1 material changes in the line at ply 1 | ||
bead1460:11positional-gives-material | w | Qxh5 | Qe5+ | 300 | A pawn has more attackers than defenders | pawn-attacked-more-than-defended@1 pe4 after Qxh5 material changes in the line at ply 4 | makes-way@1, less-active@1, passed-pawn-for-them@2 | |
7cda97b2:1positional-no-material | w | b3 | Re4 | 180 | The move gives them a passed pawn | passed-pawn-for-them@2 c3 vs - after c3 material changes in the line at ply 3 | their-passer-advances@2 | right c3 makes a passed pawn. The story already says it. |
f55d277e:23last-move-no-reply | w | Kg1 | Re8+ | 133 | The better move puts a rook on the open file | best-was-rook-to-open-file@1 Re8+ material changes in the line at ply 5 | less-active@1 | |
94a9fa9c:1positional-no-material | w | Ne5+ | Qd5+ | 194 | A pawn has more attackers than defenders | pawn-attacked-more-than-defended@2 pd4 after Bxe5 material changes in the line at ply 2 | ||
32f1cb86:1positional-no-material | w | Rc2 | Qe4 | 175 | A piece is attacked and must move (tempo) | piece-hanging@2 qf4 after Nd5 | ||
32f1cb86:5last-move-no-reply | w | Rcb2 | Rxb7+ | 329 | A draw by perpetual check was there | perpetual-check-missed@1 best line gives 12 checks in a row, repeats 5 material changes in the line at ply 1 | rook-leaves-open-file@1, less-active@1 | |
bd4f3950:13positional-no-material | w | Qh3+ | Qe7 | 141 | A pawn has more attackers than defenders | pawn-attacked-more-than-defended@2 pe5 after Kg7 | less-active@2 | |
fd99145d:19positional-gives-material | w | Nh5 | Ne4 | 152 | The knight goes to the edge | knight-to-rim@1 Nh5 material changes in the line at ply 5 | right The knight goes to the edge. Ne4 goes to the centre. | |
1962fb77:4positional-gives-material | b | c3 | d3+ | 125 | A piece is attacked and must move (tempo) | piece-hanging@2 qc5 after Qa3 material changes in the line at ply 5 | less-active@1, forced-queen-trade@4 | |
272bfb10:2positional-gives-material | b | R7g5 | Qd5+ | 294 | A pawn has more attackers than defenders | pawn-attacked-more-than-defended@1 pf6 after R7g5 material changes in the line at ply 2 | more-checks-on-me@1, less-active@1, piece-trapped@2, passed-pawn-lost@3 | |
a3bbe4cb:25positional-gives-material | w | Rd2+ | c6+ | 127 | A piece is attacked and must move (tempo) | piece-hanging@2 rd2 after Ke7 | forced-rook-trade@4 | wrong Rd2+ trades rooks into a pawn ending. The rule names a hanging rook instead. |
a3bbe4cb:33positional-gives-material | w | h4 | Kg3 | 103 | nothing fires | |||
22d12591:9positional-no-material | w | Nc2 | Qxc5 | 110 | nothing fires | material changes in the line at ply 1 | ||
22d12591:14positional-no-material | b | Qd7+ | Qe2+ | 213 | nothing fires | material changes in the line at ply 3 | ||
6f76c4ae:26positional-no-material | b | Qg5 | Qd7 | 623 | They get many more checks (fuzzy) | more-checks-on-me@2 10 vs 1 | less-active@2 | |
6f76c4ae:27positional-no-material | w | Qa7+ | Qd3+ | 426 | nothing fires | |||
6f76c4ae:28positional-no-material | b | Kg6 | Kh6 | 621 | A draw by perpetual check was there | perpetual-check-missed@1 best line gives 6 checks in a row, repeats 2 material changes in the line at ply 4 | piece-trapped@2, piece-pinned@2, less-active@2 | |
6f76c4ae:32last-move-no-reply | b | Qf6 | Kh5 | 609 | A piece is pinned | piece-pinned@1 qf6>k after Qf6 material changes in the line at ply 2 | less-active@1, king-under-attack@2, more-checks-on-me@2, forced-queen-trade@4 | |
db8a2113:15positional-no-material | w | gxf4 | Qc7+ | 292 | A draw by perpetual check was there | perpetual-check-missed@1 best line gives 12 checks in a row, repeats 3 | pawn-structure@1, less-active@1, pawn-attacked-more-than-defended@2, more-checks-on-me@2 | right Qc7+ was a perpetual check, a draw in a lost position. The pawn-structure hit alone was wrong. |
43af0bc8:6last-move-no-reply | b | Kf7 | Kg8 | 102 | The king walks into the open | king-to-center@1 Kf7 material changes in the line at ply 5 | piece-trapped@2, more-checks-on-me@2 | |
977851fe:11positional-no-material | w | Rh5+ | Re5 | 100 | The better move puts a rook on the open file | best-was-rook-to-open-file@1 Re5 | rook-leaves-open-file@1, their-rook-takes-file-or-7th@2 | |
c41cdcae:6last-move-no-reply | b | Re7 | Rf8 | 194 | Their rook takes the open file or the 7th rank | their-rook-takes-file-or-7th@2 Rc1 | plausible Rc1 takes the open c-file and later hits the queen from c4. | |
2a899703:4positional-gives-material | b | Qh3+ | Rxf4 | 126 | nothing fires | material changes in the line at ply 1 | ||
4fd0f10c:5positional-no-material | w | Nxd3 | Rxd3 | 112 | The better move clears a square for the next move | makes-way@1 Rxd3 clears d2 for Rxd3 | ||
f1bb4037:5positional-gives-material | w | b7 | Nxf7 | 128 | nothing fires | material changes in the line at ply 1 | right Be5 hits the queen. The story already says it. | |
9744412f:18positional-no-material | b | Kh6 | Qd6 | 238 | nothing fires | |||
c7dbddd0:9last-move-no-reply | w | Qc7 | Qd6 | 107 | nothing fires | material changes in the line at ply 3 | ||
35b8cf0e:2positional-gives-material | b | Qh7 | Qc6 | 221 | nothing fires | material changes in the line at ply 2 | ||
a76b4a7b:7positional-no-material | w | Qd7 | Qa4 | 247 | The better move made a passed pawn | passed-pawn-lost@3 best line makes a2 with Qa4 Re6 Qxa6 material changes in the line at ply 3 | more-checks-on-me@2 | |
a76b4a7b:11positional-no-material | w | Qd2 | Qd4 | 351 | Your pieces have far fewer moves (fuzzy) | less-active@1 mob 24-21 vs 27-15 material changes in the line at ply 5 | more-checks-on-me@2 | |
e8fe4db8:23positional-no-material | w | Qg7+ | Re1+ | 144 | The better move puts a rook on the open file | best-was-rook-to-open-file@1 Re1+ | pawn-attacked-more-than-defended@2 | |
f2a38c62:6positional-gives-material | b | Qf7 | Qd6 | 236 | nothing fires | material changes in the line at ply 3 | ||
da9088aa:2positional-no-material | b | Ne7 | Qc7 | 253 | A piece is attacked and has no safe square | piece-trapped@1 ne7 after Ne7 material changes in the line at ply 4 | piece-pinned@2 | |
da9088aa:10last-move-no-reply | b | Kg6 | Kh6 | 112 | More attackers near the king (fuzzy) | king-under-attack@1 zone attacks 6 vs 3 | more-checks-on-me@2 | |
ac42ef5a:6positional-gives-material | b | Bf6 | Bxg3 | 110 | nothing fires | material changes in the line at ply 1 | ||
ac42ef5a:12positional-no-material | b | g6 | Bd4 | 151 | A pawn has more attackers than defenders | pawn-attacked-more-than-defended@1 pg6 after g6 | makes-way@1 |
5. What I would do
Ship the rules that were right every time I checked them, each as one fixed sentence, only when the engine line agrees (the rule's move is in the line):
- Rook to the open file. "The rook belongs on the open c-file (Rac8)."
- Piece attacked with tempo. "After (f4) your bishop is attacked and has to move."
- Trapped or pinned piece. "Your bishop on h6 has no safe square."
- Passed pawn made or lost. "It gives them a passed pawn on c3."
- Knight to the edge. "The knight goes to the edge. (Ne4) puts it in the centre."
- Perpetual check missed. "(Qc7+) starts a perpetual check. The game was a draw."
- Forced trade into a lost ending. "(Qe5+) forces the queen trade. The pawn ending is lost."
Do not ship the fuzzy rules (mobility, checks, king-zone attackers). They fire often and name nothing a reader can see.
Expected effect: a true, simple sentence for about 30 of the 58 pending moments, with zero engine time. The other 28 stay as they are unless the threat search comes back for the 21 sharp-threat cases, which overlap with these in part.