Skip to content

refactor(perft): code-review polish for the perft rig + MCP server#95

Merged
ber4444 merged 2 commits into
mainfrom
fix/perft-review-polish
Jul 15, 2026
Merged

refactor(perft): code-review polish for the perft rig + MCP server#95
ber4444 merged 2 commits into
mainfrom
fix/perft-review-polish

Conversation

@ber4444

@ber4444 ber4444 commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Applies six code-review findings from the merged perft/MCP work (#49). No behavior change to the green gate — all fixes are correctness/robustness/clarity polish. The shipped move generator is untouched; these fixes are to the rig and the MCP adapter, not the engine.

Findings addressed

  1. Stale path in the divergence reportPerftVsStockfishTest wrote "Inspect the corresponding rule in app/src/commonMain/.../Move.kt", but the file moved to chess-core in the perft-tests migration. An agent reading build/perft-divergence.txt was pointed at a non-existent path (the exact "stale path after a module move" failure the docs hold up as the meta-lesson). Now points at chess-core/src/commonMain/.../Move.kt.
  2. render() hid a filesystem write — split DivergenceReport.render() (now pure) from a new persist(rendered); call sites persist(...) then fail(...) explicitly instead of writing to disk as a side effect of building an assertNull message.
  3. Timeout could masquerade as a divergence — on deadline/early-exit the rig (StockfishPerft) now throws instead of returning a partial divide, and the MCP adapter (StockfishDivider) reports a new DivideResult.timedOut and withholds the partial map. A slow engine can no longer look like a real mismatch.
  4. Unbounded gate subprocessrun_perft_gate now bounds gradle (15 min default / 45 min deep) via a daemon stdout drainer + waitFor(timeout) + destroyForcibly(), so a wedged build can't hang the MCP tool call (and the agent) forever.
  5. Duplicated depth cap — tool descriptions interpolate StockfishDivider.MAX_DEPTH / DEFAULT_TIMEOUT_MS instead of a separate MAX_DEPTH_CAP constant that could drift from the real clamp.
  6. Unused import — removed kotlin.io.path.pathString.

Plus a docs commit: syncs the docs/perft.md MCP tool table with the new contract (gate timeout; stockfish_divide's timedOut), and adds a Future work note on using The Grand Chess Tree's ~28k-position corpus to broaden Oracle 1.

Verification (ran locally, this branch, Stockfish present)

  • ./gradlew :perft-mcp:test --rerun-tasksgreen after a fresh recompile. Covers the description assertions that require the literals "clamped to 6" / "120s" (now produced by interpolating the real constants) and formatDivideResult.
  • ./gradlew :chess-core:desktopTest --tests "*Perft*" --rerun-tasksgreen after a fresh recompile. Oracle 2 (PerftVsStockfishTest) actually ran (2 tests, 0 skipped, 0 failures) against /opt/homebrew/bin/stockfish; no perft-divergence.txt was written, consistent with a green gate.
  • The new failure-only branches (rig-side timeout throw; render/persist split) are compile-verified and unit-covered, but not runtime-triggered by this green run — correctly, since nothing diverged or timed out.

🤖 Generated with Claude Code

ber4444 and others added 2 commits July 14, 2026 17:57
Six review findings from the merged perft/MCP work, no behavior change to the
green gate:

1. Fix stale path in the divergence report an agent reads: point at
   chess-core/src/.../Move.kt, not the pre-move app/src path.
2. Split DivergenceReport.render() (now pure) from a new persist() so producing
   the report text has no hidden filesystem side effect; call sites persist then
   fail explicitly instead of writing inside an assert message.
3. Distinguish a Stockfish timeout from a real divergence: the rig
   (StockfishPerft) now throws instead of returning a partial divide, and the MCP
   tool (StockfishDivider) reports a new DivideResult.timedOut and withholds the
   partial map so a slow engine can't masquerade as a mismatch.
4. Bound the run_perft_gate subprocess (15m default / 45m deep) with a
   background stdout drainer, so a wedged gradle can't hang the agent forever.
5. De-duplicate the depth cap / timeout: tool descriptions now interpolate
   StockfishDivider.MAX_DEPTH / DEFAULT_TIMEOUT_MS instead of a separate constant
   that could drift from the real clamp.
6. Remove unused imports (kotlin.io.path.pathString, java.io.File).

Verified: :perft-mcp:test green, :chess-core:desktopTest --tests "*Perft*" green
with Stockfish present (Oracle 2 ran).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- run_perft_gate / stockfish_divide rows now match the new contract
  (gate subprocess timeout; stockfish_divide's timedOut field + partial-
  result withholding).
- Future work: note The Grand Chess Tree's ~28k-position corpus as an
  Oracle 1 breadth extension, and why a no-divide speed counter
  (perft_cpu_2026) is the wrong tool for the localizer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ber4444
ber4444 merged commit 8040342 into main Jul 15, 2026
11 checks passed
@ber4444
ber4444 deleted the fix/perft-review-polish branch July 15, 2026 13:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant