Releases: osick/helpmate-tablebase
Release list
v0.20.0
What's Changed
- tools: cross the DEEPEST showcase with a database of published helpmates by @osick in #30
- docs: 26 DEEPEST problems are published -- author and source added, 16 unpublished siblings by @osick in #31
- docs: grade every DEEPEST problem, swap weak unpublished positions, published-by column by @osick in #32
- docs(build): venvs, and why pipx install ./src/packages/api fails by @osick in #33
- Per-material pages, deepest duals, and a corpus-wide theme index by @osick in #34
- The generated pages had no stylesheet at all by @osick in #35
- Say plainly that these positions were enumerated, not composed by @osick in #36
- Collapse the theme index: 37,000px to 1,900px by @osick in #38
- (chore) Update/extend setup docs by @T31M in #42
- Themes: indian, maslar, maslar:black-white (registry 30 → 33) by @osick in #44
- Release 0.20.0: T31M's fifteen KRB tables, corpus 302 → 317 by @osick in #46
New Contributors
Full Changelog: v0.19.0...v0.20.0
v0.19.0
What's Changed
- corpus 302 tables; site puzzles with themes and a Theme filter, 1071 puzzles by @osick in #27
- docs: DEEPEST as problem cards -- SVG diagrams, numbers, solve link, themes by @osick in #28
- release 0.19.0: commit docs/DEEPEST.pdf, attach it to releases by @osick in #29
Full Changelog: v0.18.1...v0.19.0
v0.18.1
What's Changed
- mine: --jsonl and save FILE.jsonl -- JSON Lines with header, streamed records and footer (0.18.1) by @osick in #26
Full Changelog: v0.18.0...v0.18.1
v0.18.0
What's Changed
- mine: --json, --themes, --solutions, --max infinity and an --interactive shell (0.18.0) by @osick in #25
Full Changelog: v0.17.0...v0.18.0
v0.17.0
What's Changed
- Dashboard UX round 2 and 3: no modes, banded moves, puzzles, motif docs by @osick in #11
- Search off by default, per-origin CORS, and a connection limit (v0.14.0) by @osick in #12
- Dashboard polish: pinned chrome, lifted board, About/Technique/Privacy by @osick in #13
- Front-page README, tablebase contribution guide, and helpmate-tables --create-pr by @osick in #14
- Batch HF pushes into chunked commits (fixes 429 rate-limit failure) by @osick in #15
- Release 0.16.0 by @osick in #16
- docs: the deepest sound problem in every material class by @osick in #17
- docs: corpus at 300 tables, 14 of 645 six-piece classes by @osick in #18
- tools: block-level integrity check for compressed tables; one repo name by @osick in #19
- docs: the technical post, for people who already know Syzygy by @osick in #20
- feat(site): a static showcase on GitHub Pages by @osick in #21
- fix(site): track site/js/lib, hidden by the Python lib/ ignore rule by @osick in #22
- Add six new themes and first parametric theme; registry 24→30 by @osick in #23
Full Changelog: v0.11.0...v0.17.0
v0.11.0 — dashboard UX: rail and readout
Every screen is now a grey rail — what you manipulate — beside a white readout — what the tables say.
This release also carries v0.10.0, which was merged to main and superseded within the same session and so has a tag but no separate release.
Added
- Drag-and-drop position editing. Drag a piece from the palette onto a square, drag pieces around the board in the new Arrange mode, or drag one off the edge to remove it. Click-to-place is unchanged and remains the keyboard path. Edit mode gained a visible Done — evaluate.
- The explorer shows the table a position came from, in a band below the board and the move list.
- Materials lands on "All tables" — the whole corpus at once, including the 67 materials that contain no helpmate at all and the seven generator versions that built the rest. The table list scrolls inside its rail, filters on substring, and groups by piece count.
- Search has a Stop button and shows elapsed time against the server's own budget. Stop is honest about its limits: the scan runs in a thread pool, so abandoning the response does not free the worker.
GET /v1/statsreturns a corpus aggregate./v1/probeand/v1/movesreport thematerialwhose table answered — the mirrored one when colours were flipped./v1/healthreportsmine_timeout.
Fixed
- The board overlapped the move list between 860px and ~1150px, sized from the viewport while its column was sized from the grid.
- A material with no helpmate reported "longest mate h#127.5" — the stored
DTM_UNSOLVABLEsentinel divided by two. 67 of 295 tables were affected. - A timed-out search reported "0 position(s) (truncated — raise max results for more)" — advice that could not help, about a scan that never finished.
- The Materials page rendered 12,005px tall.
- An edited position never reached the URL: a copied link reopened the pre-edit position, Back could not undo, and switching panels discarded the edit.
- Typing in the Materials filter with no tables installed threw on every keystroke and permanently killed the filter — the first-run state of a fresh install.
- A truncated sidecar returned 500 from
/v1/statsand/v1/materials, contradicting the documented tolerance. An interrupted generation run produces exactly that. materialcould name a table that cannot exist on unsolvable mirrored positions./v1/statsparsed every sidecar before checking its own cache.make test-apitested a stale site-packages copy, so a regression in existing behaviour could pass silently;make lintskipped new unstaged JavaScript.
Known limits
- An uncommitted edit is still discarded by switching panels; Done — evaluate is the commit gesture.
SIGTERMdoes not stop a runningminescan and its timeout is non-deterministic under load, because the pool worker outlives its HTTP response. Concurrency work is next.- Touch-drag is verified under emulation, not on a physical device.
What's Changed
- Dashboard UX: rail and readout, drag-and-drop editing, corpus statistics (v0.11.0) by @osick in #9
- Bring the dashboard UX pass (v0.11.0) to main by @osick in #10
Full Changelog: v0.10.0...v0.11.0
v0.10.0
What's Changed
Full Changelog: v0.9.1...v0.10.0
v0.9.1 — set-play corrected
A semantics fix to a theme released in 0.9.0, and a native install path for the CLI binary.
set-play was nearly vacuous — and reported the opposite of set play
0.9.0 defined it as "the same position with the other side to move is solvable". That matched 423 of 580 KQvk --dtm 2 positions (72.9%). A filter that keeps three positions in four is not a filter.
It also conflated two opposite things. Parity forces the sibling position to be at D−1 or D+1, where D is this position's distance:
D−1 — the mate is already there; the side to move merely delays it. This is set play:
8/8/8/8/8/8/8/k1KQ4 b → dtm=2 (h#1) Ka2 Qa4#
8/8/8/8/8/8/8/k1KQ4 w → dtm=1 (h#0.5) Qa4#
D+1 — flipping the side to move makes the mate longer. This was reported too:
8/8/8/8/8/8/k7/2K1Q3 b → dtm=2 (h#1) Ka1 Qa5#
8/8/8/8/8/8/k7/2K1Q3 w → dtm=3 (h#1.5) Kc2 Ka3 Qa5# (28 solutions)
set-play now requires the sibling solvable at exactly D−1: 423 → 183 hits, 72.9% → 31.6%.
This changes behaviour for anyone using 0.9.0's set-play — you will get fewer positions, specifically the 240 per that query where flipping the side to move lengthened the mate. The looser "any shorter distance" reading is the glossary's separate Short set play, not implemented.
ThemeInput gained the position's own ValuePair, since the detector previously could not see D at all.
The guard that nearly wasn't
Both sentinel guards are load-bearing, and one only proved so under mutation testing: dropping value.dtm <= DTM_MAX survived the first run, because at DTM_UNSET (253) with a sibling at DTM_MAX (252), 252 + 1 == 253 holds by coincidence — an unsolvable position would have reported set-play. A boundary test for that exact pair now kills it, and review confirmed it is the only such coincidence in the sentinel range.
make install-bin
Install the CLI binary alone, no Python — for a system package, a container layer, or a machine with no Python:
sudo make install-bin # /usr/local/bin/helpmate (GNU default)
make install-bin PREFIX=$HOME/.local # rootless
make install-bin DESTDIR=/tmp/stage # package staging
make uninstall-binA thin wrapper over cmake --install, which already worked but was undocumented. No bespoke install script, which would be a second source of truth against the build.
Verification
Catch2 3,867,064 assertions / 213 cases; ctest 275/275; lint, typecheck, format-check clean; api 85, bindings 17, web 38+16, repo 14, jstest 38.
The KPvk integration test was re-measured rather than relaxed (57 → 23 hits), and its per-hit check strengthened from "the flipped position is solvable" to "probes to exactly D−1" — the weaker assertion is what let the original bug through.
Upgrade note: no table format change. Existing tables read exactly as before.
What's Changed
Full Changelog: v0.9.0...v0.9.1
v0.9.0 — theme detection round 2
Six new composition themes, and the structural change that lets two of them exist.
needs — the actual deliverable
A theme detector now receives a ThemeInput (the diagram, the sibling side-to-move plane's value, the solutions) instead of a bare Solution, and each declares needs: Position, Plane or Solutions.
mine previously enumerated a position's optimal solutions for every theme filter. Enumeration is impossible for positions whose stored solution count saturates at 255 — those were skipped and counted, so a theme query silently never saw them. mine now enumerates only when a requested theme actually needs the solutions.
So a Needs::Plane theme answers on saturated positions. Measured: --theme set-play reports 0 skipped where --theme model on the identical query skips 19.
This is a capability difference, not a speed-up, and the docs say so. An earlier draft claimed diagram-only themes would run at "scan speed" — withdrawn. Evaluating one requires materialising the position, so its floor is decode speed: 51 s → 26 s on KRvkbn --dtm 8 (31.5M candidates) once fen construction was made lazy, against >100 hours to enumerate the same candidates.
New themes
set-play, kniest, zajic, phoenix, schnoebelen, pendulum. Registry 16 → 22. helpmate themes now prints each theme's needs, as do /v1/themes and helpmate.themes().
set-play is cheap for a reason specific to this project: a cell index is independent of side to move, so the sibling plane's value is the same cell in the other plane — one extra byte from a read the scan already performs.
homebase was designed, implemented, reviewed — and cut
It shipped through nine tasks before the whole-branch review removed it. It cannot be meaningfully mined, and not merely because the canonical index confines the White king to files a–d. A tablebase cell stores an equivalence class, and homebase is not invariant under the symmetry group the index quotients by — the file mirror maps king e↔d and queen d↔e. The question is ill-posed, not just unanswerable.
All 22 remaining themes were tested for invariance across 525 transform pairs; none is affected. The spec now records the constraint: a Needs::Position theme must be invariant under the index's symmetry group.
Also
/v1/probe?themes=true and the Python bindings now disclose solution-set truncation, which previously only the CLI did — two mirror-image FENs could return different theme lists at count=255.
Verification
Catch2 3,867,093 assertions / 208 cases; ctest 270/270; lint, typecheck and format-check clean; api 85, bindings 17, web 16, repo 14, JS 38. Every worked example in the README, docs/USAGE.md and CHANGELOG.md was reproduced byte-for-byte against a real 30 GB corpus.
Upgrade note: no table format change. Existing v1/v2/v3 tables read exactly as before; no corpus reconversion is needed.
What's Changed
Full Changelog: v0.8.2...v0.9.0
v0.8.2 — faster mining on compressed tables, corpus-wide stats
Two rungs in one release. 0.8.1 was merged but never tagged, so it ships here too; the changelog records each under its own version.
Mining a compressed table is no longer several times slower (0.8.1)
Measured on a real 462 MiB KRvkbn (70.8 MiB compressed), taskset -c 0-3, warm:
| workload | before | after |
|---|---|---|
| full plane scan | 14.2x raw | 2.3x raw |
solution enumeration (--theme model) |
11.8x raw | 1.14x raw |
single warm probe |
1.09x raw | unchanged |
Two independent causes, neither of them block size — which the v0.7.5 experiment had suspected and correctly acquitted, then stopped at.
- The plane scan read one byte per block-cache call. Each
get()on a compressed table takes the cache mutex and copies a single byte; over a whole plane that, not the decompression, was the cost — decompressing both planes is only ~0.2 s of the 9.06 s the scan took. NewTableReader::read_values()pays one lock and one memcpy per block touched. - The block cache was smaller than the enumeration working set. Theme and shape queries probe at effectively random indices, and with the 4 MB budget nearly every probe paid a full block decompression for one byte. The budget is now 64 MB, capped per table at its own logical size. It is a ceiling, not a reservation — that run peaked at 62 MB RSS in total.
The ~6.5x figure documented since v0.7.5 is withdrawn: its benchmark exits as soon as it has 20000 hits and never scans the plane, understating the real cost by 3x.
helpmate stats summarises a whole table directory (0.8.2)
helpmate stats --tables DIR, with no MATERIAL, reports what is on disk and what is in it — formats, sizes, the whole-corpus compression ratio, the cell breakdown, the deepest mate, the largest tables. Covers the roadmap's helpmate list <dir> item.
tools/compress-corpus.sh
Converts a directory of raw tables into compressed ones in a different directory; compact --compress only works in place. One table at a time, source only read, nothing deleted, and it will not even open a table written in the last hour so an active generation run is never disturbed.
Verification
ctest 244/244, Catch2 3,866,730 assertions / 183 cases, lint / typecheck / format-check clean, api 83, bindings 15, web 15, repo 14, JS 36. mine output is byte-identical between raw and compressed tables for --dtm/--count, --starts and --theme, and row counts match the generator's own uniqueness histogram.
Upgrade note: no format change. Existing v1/v2/v3 tables are read exactly as before, and no corpus reconversion is needed.
What's Changed
- perf: mining a compressed table is no longer several times slower by @osick in #4
- feat: corpus-wide
helpmate stats, plus a raw→compressed conversion script by @osick in #5
Full Changelog: v0.8.0...v0.8.2