Интерфейс командной строки (CLI)
Введение
blunderDB включает полноценный интерфейс командной строки (CLI) в том же исполняемом файле, что и графический интерфейс. CLI особенно полезен для:
массового импорта матчей: импортировать весь каталог файлов матчей (XG, SGF, MAT, BGF…) одной командой,
автоматизации: интегрировать blunderDB в shell-скрипты для регулярного резервного копирования, запланированного экспорта или конвейерной обработки,
работы на сервере: управлять базами данных на машинах без графического окружения,
быстрой проверки: проверить содержимое или целостность базы данных без запуска графического интерфейса.
CLI использует в точности тот же формат базы данных, что и графический интерфейс: обе программы пишут один и тот же файл, синхронизировать нечего.
Примечание
Если приложение открыто, пока пишет скрипт. Файл находится в режиме WAL: чтение никогда не блокирует запись, и обе программы работают с одной базой, не мешая друг другу. Две записи, напротив, следуют одна за другой — вторая ждёт блокировку записи (десять секунд на инструкцию плюс несколько повторных попыток) и завершается ошибкой, только если ожидание исчерпано, сообщением, называющим SQLite:
Error: failed to import match: sqlite: save match: database is locked (5) (SQLITE_BUSY)
Графический интерфейс не следит за файлом: он продолжает показывать то, что загрузил, пока CTRL-R не перезагрузит позиции. Ничего не теряется, но экран отстаёт от базы.
Общий синтаксис
Режим определяется автоматически: если первый аргумент является командой CLI, blunderDB запускается в безголовом режиме, иначе запускается графический интерфейс.
# GUI
./blunderdb
# CLI
./blunderdb <command> [options]
Примеры на этой странице пишут ./blunderdb: двоичный файл в том виде, в каком он скачан, вызываемый из папки, где он лежит. Установленный пакетом или связанный из папки в PATH (см. Загрузка и установка), он вызывается просто как blunderdb.
Булевы опции, помеченные «по умолчанию: да», отключаются формой --option=false — --recursive=false, --analysis=false. Формы через пробел не существует: --recursive false оставляет опцию в значении по умолчанию и трактует false как лишний аргумент.
Доступные команды
Команда |
Описание |
|---|---|
create |
Создать новую базу данных. |
import |
Импортировать данные (матч, позиция, пакет). |
export |
Экспортировать данные. |
identity |
Показывает или переносит идентичность издателя (ключ подписи водяных знаков). |
open |
Превращает файл, защищённый паролем (.dbx), в обычную базу. |
search |
Поиск позиций с фильтрами. |
list |
Отобразить содержимое базы. |
match |
Отобразить позиции и анализ матча. |
collection |
Управляет коллекциями (список, содержимое, создание, переименование, удаление, экспорт). |
anki |
Колоды интервального повторения (список, статистика, прогноз, синхронизация). |
rollout |
Доигрывает позицию до конца, чтобы различить её ходы или решение по кубу (XGID или OGID). |
epc |
Вычисляет Effective Pip Count и вердикт по кубу для позиции выброса (XGID или OGID). |
bearoff |
Создаёт, перечисляет, проверяет и удаляет базы выброса. |
analyze |
Записывает анализ gammonNet для каждой позиции, у которой его нет. |
info |
Отобразить метаданные базы. |
edit |
Изменить метаданные и пороги базы. |
verify |
Проверить целостность базы. |
vacuum |
Сжимает файл базы данных, возвращая освободившееся место. |
repair |
Пересчитывает то, что база выводит из того, что хранит. |
delete |
Удалить данные. |
healthcheck |
Опрашивает работающий демон |
mcp |
Предоставляет инструменты базы ИИ-ассистенту (Model Context Protocol). |
completion |
Выводит скрипт автодополнения оболочки (bash, zsh, fish). |
help |
Показать справку. |
version |
Показать версию. |
serve, migrate, call |
Серверный режим и миграция в PostgreSQL: см. Безголовый режим (сервер). |
Каждая команда принимает опцию --help для отображения подробной справки.
create — Создать базу данных
Создаёт новый файл базы данных с необязательными метаданными.
./blunderdb create --db <path> [--user <name>] [--description <text>] [--force]
Параметры:
--db— Путь к файлу базы данных для создания (обязательно).--user— Имя владельца базы данных.--description— Описание базы данных.--force— Перезаписать файл, если он уже существует.--format— Формат вывода:text(по умолчанию) илиjson(путь, версия, пользователь, описание, дата создания).
Расширение .db добавляется автоматически, если оно отсутствует. Родительские каталоги создаются при необходимости.
Пример:
./blunderdb create --db mes_matchs.db --user "Jean" --description "Matchs de tournoi 2025"
import — Импорт данных
Импортирует файлы матчей или позиций в базу данных.
./blunderdb import --db <path> --type <type> [options]
Параметры:
--db— Путь к базе данных (обязательно).--type— Тип импорта:match,positionилиbatch(обязательно).--file— Файл для импорта (дляmatchиposition).--dir— Каталог для импорта (дляbatch).--recursive— Рекурсивный просмотр подкаталогов (по умолчанию: да).--watch— С--type batch: не завершается и импортирует каждый файл матча по мере его появления в--dir(Ctrl-C для остановки).--watch-every— Как часто--watchсмотрит (по умолчанию: 10s, минимум 2s).--format— Формат вывода:text(по умолчанию) илиjson.--fail-on-error— Завершается с ошибкой, если хотя бы один элемент (positionилиbatch) не удалось импортировать, даже если остальные были импортированы успешно.
Код возврата подчиняется четырём правилам:
ничего не распознано — каждый файл завершился неудачей: ошибка, независимо от того, передан ли
--fail-on-error;одни дубликаты — каждый файл уже был в базе: успех. Каталог, перезапущенный без единого нового файла, — обычная ночь скрипта — завершается с кодом 0, и ненулевым остаётся только
duplicates;частичная неудача (одни элементы импортированы, другие отклонены): ошибка только в том случае, если передан
--fail-on-error;импортирован хотя бы один новый элемент, без
--fail-on-error: успех, а отклонённые файлы перечислены в таблице.
Слежение за папкой
--watch превращает импорт каталога в слежение: команда не возвращает управление и импортирует каждый файл матча, который появляется в папке. Это безынтерфейсная форма отслеживаемой папки приложения.
# Importer ce que le dossier contient déjà, puis surveiller ce qui arrive
./blunderdb import --db base.db --type batch --dir ~/XG/Matches
./blunderdb import --db base.db --type batch --dir ~/XG/Matches --watch
Импортируются только появляющиеся файлы: то, что папка содержит при запуске, записывается как известное и не трогается — направив слежение на четыре года матчей, не следует импортировать их все. Две команды выше поэтому складываются ровно так, как хотелось бы.
Файл импортируется лишь тогда, когда его размер устоялся, то есть увиден дважды без изменений: матч, который пишет другая программа, растёт от взгляда к взгляду, и импорт недописанного дал бы синтаксическую ошибку, с которой никто ничего не сделает. Папка не обходится рекурсивно. Сетевой ресурс, ставший нечитаемым, не останавливает слежение, и его содержимое не сойдёт за новое, когда он вернётся.
Ctrl-C останавливает между файлами, никогда посреди одного: текущий файл дописывает свой импорт и печатает отчёт до того, как команда вернёт управление.
Импорт матча
Поддерживаемые форматы: eXtreme Gammon (.xg, .xgp), GNUbg (.sgf), Jellyfish (.mat, .txt), BGBlitz (.bgf) и HedgeHog (.ogxm).
./blunderdb import --db base.db --type match --file match.xg
# Successfully imported match (ID: 1)
#
# Match Details:
# Players: Kévin Unger vs Maxence Job
# Event: HSBT Paris 2023
# Match Length: 7
# Games: 7
--format json выдаёт те же поля одним документом:
{
"type": "match",
"match_id": 1,
"player1": "Kévin Unger",
"player2": "Maxence Job",
"event": "HSBT Paris 2023",
"location": "Paris, Fédération Française de Bridge",
"match_length": 7,
"games": 7
}
Импорт позиций
Импортирует позиции из текстового файла, по одной JSON-позиции на строку. Это в точности то, что пишет export --type positions: обе команды отвечают друг другу, экспорт реимпортируется как есть, без единой правки.
./blunderdb import --db base.db --type position --file positions.txt
# Successfully imported 4 positions
Строка в том виде, в каком её выдаёт export, — доска занимает в ней почти всё: двадцать шесть пунктов, за которыми идут выброшенные шашки:
{"id":1,"board":{"points":[{"checkers":0,"color":0},{"checkers":1,"color":1},…],"bearoff":[0,0]},"cube":{"owner":-1,"value":0},"dice":[0,0],"score":[7,7],"player_on_roll":0,"decision_type":1,"has_jacoby":0,"has_beaver":0,"individually_imported":true,"flagged":false}
Анализ и комментарии этим форматом не передаются: он несёт позицию и ничего больше. Чтобы перенести целую библиотеку, нужен export --type database.
Пакетный импорт
Импортирует все файлы матчей из каталога в одной операции. Это наиболее эффективный метод для импорта большого числа матчей.
./blunderdb import --db base.db --type batch --dir ./matchs/
./blunderdb import --db base.db --type batch --dir ./matchs/ --recursive=false
./blunderdb import --db base.db --type batch --dir ./matchs/ --format json --fail-on-error
Итоговая таблица показывает для каждого файла, удался ли импорт (✓), завершился неудачей (✗) или это был дубликат (⊘). Дубликат не считается неудачей, а пакет, состоящий из одних лишь дубликатов, — это успех (см. правила выше).
Batch importing from: ./matchs/ (recursive: true)
Found 3 match file(s) to import
[1/3] Importing: 02_NDT_FR.txt... ERROR: failed to parse file: ingest: parse gnubg file: invalid MAT file: no match header found
[2/3] Importing: test.mat... DUPLICATE
[3/3] Importing: test.xg... OK (ID: 1, 341 positions)
====================================================================
IMPORT SUMMARY
====================================================================
Status File ID Player 1 Player 2 Games Positions Error
------ ---- -- -------- -------- ----- --------- -----
✗ 02_NDT_FR.txt 0 0 failed to parse file: ingest: ...
⊘ test.mat 0 0
✓ test.xg 1 Kévin Unger Maxence Job 7 341
--------------------------------------------------------------------
Total: 3 files | Success: 1 | Duplicates: 1 | Failed: 1 | Positions imported: 341
--format json даёт то же самое в пригодном для скрипта виде: по объекту на файл в files, затем итоги. После спокойной ночи ненулевым остаётся только duplicates, failed равен нулю, а код возврата — 0; с ошибкой завершается лишь тот пакет, в котором ничего не было распознано.
{
"files": [
{"file_path": "02_NDT_FR.txt", "success": false, "error": "failed to parse file: …"},
{"file_path": "test.xg", "success": true, "positions": 341}
],
"total": 3,
"success": 1,
"duplicates": 1,
"failed": 1,
"positions_imported": 341
}
export — Экспорт данных
Экспортирует содержимое базы в файлы.
./blunderdb export --db <path> --type <type> --file <output> [options]
Параметры:
--db— Исходная база (обязательно).--type— Тип экспорта:database,positions,matchesилиmat(экспорт одного или нескольких матчей в транскрипции Jellyfish.mat) (обязательно).--file— Выходной файл (обязательно, кроме случая--type mat, используемого с--dir).--dir— Выходной каталог для пакетного экспорта.mat(несколько матчей, один файл на матч; без--match-idsэкспортируются все матчи).--analysis— Включить анализ (по умолчанию: да).--comments— Включить комментарии (по умолчанию: да).--filters— Включить библиотеку фильтров (по умолчанию: да).--played-moves— Включить сыгранные ходы (по умолчанию: да).--matches— Включить матчи (по умолчанию: да).--collections— Включить коллекции (по умолчанию: нет).--collection-ids— Идентификаторы коллекций для экспорта (через запятую).--match-ids— Идентификаторы матчей для экспорта (через запятую, пусто = все).--tournament-ids— Идентификаторы турниров для экспорта (через запятую).--password— Оборачивает результат в зашифрованный контейнер (.dbx).--watermark— Записывает подписанное заявление о происхождении в экспортируемый файл (см. Распространение базы: происхождение и пароль).--watermark-note— Произвольный текст при водяном знаке (условия использования, контакт); применяется вместе с--watermark.--format— Формат вывода:text(по умолчанию) илиjson(документ с итогами экспорта: путь, размер в байтах, количества).
Примеры:
./blunderdb export --db base.db --type database --file sauvegarde.db
./blunderdb export --db base.db --type positions --file positions.txt
./blunderdb export --db base.db --type matches --file selection.db --match-ids 1,3,5
# .mat : un match, puis plusieurs (ou tous) dans un répertoire
./blunderdb export --db base.db --type mat --match-ids 5 --file match5.mat
./blunderdb export --db base.db --type mat --match-ids 5,9,12 --dir sorties/
./blunderdb export --db base.db --type mat --dir sorties/
# .dbx : filigrané et protégé par mot de passe
./blunderdb export --db cours.db --type database --file cours-diffusion.dbx \
--watermark "Cours de Jean Dupont — 12 mars 2026" \
--watermark-note "Merci de ne pas rediffuser." \
--password secret
Водяной знак подписывается локальной идентичностью издателя (см. команду identity ниже): подделать его нельзя, но убрать можно — файл остаётся обычной базой SQLite. Он ничего не защищает, он лишь говорит, откуда файл. Пароль защищает перевозку файла (затерявшуюся копию, вложение, отправленное по ошибке), но не саму базу: любой, кто получил пароль, сможет её открыть. blunderDB никогда ничего не записывает на стороне получателя (ни реестра, ни журнала) — см. ADR-0007.
identity — Идентичность издателя
Показывает или переносит вашу идентичность издателя — ключ Ed25519, которым подписывается каждый водяной знак. Он создаётся сам при первом нанесении знака; настраивать нечего. Он принадлежит человеку, а не базе: всё, что вы помечаете, несёт один и тот же публичный отпечаток.
./blunderdb identity
./blunderdb identity --name "Jean Dupont"
./blunderdb identity --export jean.bdbid --passphrase pw
./blunderdb identity --import jean.bdbid --passphrase pw
Параметры:
--name— Меняет отображаемое имя идентичности.--export— Экспортирует идентичность в файл.bdbid.--import— Импортирует идентичность из файла.bdbid.--passphrase— Необязательная парольная фраза, защищающая экспортируемый/импортируемый файл (сама локальная идентичность намеренно не защищена).--format— Формат вывода:text(по умолчанию) илиjson(имя, отпечаток, путь хранения).
Экспортированный файл позволяет любому, у кого он есть, подписывать от вашего имени — не передавайте его. Переименование меняет лишь подпись-ярлык: уже помеченные файлы сохраняют имя, под которым были запечатаны, и по-прежнему проверяются.
open — Открыть защищённый файл
Превращает файл, защищённый паролем (.dbx), в обычную базу. Пароль спрашивают один раз; дальше это обычный файл.
./blunderdb open --db cours.dbx --password secret
./blunderdb open --db cours.dbx --password secret --file ./mon-cours.db
Параметры:
--db— Файл.dbx, который нужно открыть (обязательно).--password— Пароль контейнера (обязательно).--file— Путь вывода для обычной базы (по умолчанию: то же имя, расширение.db).
Что защищает пароль: перевозку файла — копию, забытую в папке загрузок, вложение, отправленное по ошибке. Не базу: любой, кто получил пароль, сможет её открыть. Заголовок контейнера открыт, поэтому blunderdb info читает происхождение защищённого файла без пароля.
search — Поиск позиций
Поиск позиций в базе данных по комбинируемым критериям.
./blunderdb search --db <path> [options]
Основные параметры:
--db— База данных (обязательно).--format— Формат вывода:table,jsonилиxgid(по умолчанию:table).--limit— Максимальное количество результатов (0 = без ограничений).--offset— Пропустить первые n результатов, прежде чем начать отсчёт; вместе с--limitэто постраничный вывод.--export— Экспортировать результаты в новую базу данных.--query-help— Показывает список токенов, понятных--query, и на этом останавливается. Никакая база не открывается:--dbне нужен.
Доступные фильтры:
--decision— Тип решения:checkerилиcube.--dice— Бросок кубиков.5,3ищет позиции, где оба кубика совпадают (в любом порядке).5ищет позиции, где 5 выпадает на одном из кубиков (значение второго кубика игнорируется). Подразумевает--decision checker, если значение--decisionне указано.--pip-min/--pip-max— Диапазон разницы пипкаунта.--winrate-min/--winrate-max— Диапазон процента побед (%).--cube— Значение куба.--score1/--score2— Счёт игроков.--match-length— Длина матча.--error-min— Порог по тому, во сколько обходится ошибка в позиции: разрыв между лучшим ходом и вторым или наибольшая из трёх ошибок куба. В очках эквити —--error-min 0.1оставляет позиции, где ошибка стоит не менее одной десятой очка. О том, что было в них сыграно, он ничего не говорит.--move-error-min/--move-error-max— Порог по ошибке хода, фактически сыгранного игроком 1. В тысячных долях эквити (миллипоинтах):--move-error-min 50, то есть одна двадцатая очка. Это токенEграмматики поиска, записанный как есть.--has-analysis— Только позиции с анализом.--off1-min/--off2-min— Минимальное количество снятых шашек (игрок 1/2).--match-ids— Фильтр по идентификаторам матчей (через запятую).--tournament-ids— Фильтр по идентификаторам турниров (через запятую).--position-ids— Фильтр по идентификаторам позиций: интервал2,7(позиции с 2 по 7) или явный список через точку с запятой5;10;15.--individual— Только позиции, импортированные отдельно, то есть те, которые вы добавили сами, а не пришедшие с импортом матча.--flagged— Только позиции, помеченные (flag) для изучения в исходной программе (пометки eXtreme Gammon). Не действует задним числом: уже импортированные матчи нужно импортировать заново, чтобы получить их пометки.--has-comment— Только позиции с комментарием. Происхождение не различается: и заметка, набранная вручную, и комментарий, пришедший с импортом матча, считаются одинаково. Комментарии матча или турнира не просматриваются.--no-comment— Только позиции без комментария. Взаимоисключающе с--has-comment.
Предупреждение
--error-min и --move-error-min измеряют не одно и то же и принимают не одну и ту же единицу: множитель равен тысяче. Первый задаётся в очках эквити (0.1), два других — в тысячных (100): одно очко стоит 1000 тысячных. На вопрос «где я ошибся» отвечает --move-error-min; --error-min отвечает на вопрос «какие позиции были каверзными».
Что печатает search:
--format table (по умолчанию) даёт по строке на позицию: идентификатор, счёт, значение куба, тип решения, бросок, лучшее решение и его эквити. Два последних столбца остаются пустыми для позиции без анализа.
Found 5 position(s)
ID Score Cube Type Dice Best Move Equity
-- ----- ---- ---- ---- --------- ------
2 7-7 0 cube No Double -0.005
4 7-7 0 cube No Double -0.027
6 7-7 0 cube No Double -0.161
8 7-7 0 cube No Double 0.256
10 7-7 0 cube No Double -0.234
--format json даёт массив тех же позиций. Поля id, score, cube, decision_type (checker или cube) и dice присутствуют всегда; best_move, equity и xgid появляются, только если позиция несёт анализ, который их заполняет. Строка Found n position(s) по-прежнему печатается перед массивом: скрипт, ожидающий только JSON, должен пропустить первую строку или воспользоваться --export.
[
{
"id": 5266,
"score": [
5,
4
],
"cube": 1,
"decision_type": "checker",
"dice": [
4,
3
],
"best_move": "10/3",
"equity": 0.565
}
]
--format xgid печатает по одному XGID на строку и ничего больше. Он печатает только те позиции, чей сохранённый анализ несёт XGID: позицию, вставленную в приложение из текстового экспорта, или файл BGF, который его переносит. Позиции, пришедшие из импорта матча XG, GNUbg или Jellyfish, его не несут, и вывод тогда пуст. Подкоманда collection show, напротив, восстанавливает XGID по доске.
Язык запросов:
Приведённые выше флаги покрывают лишь часть фильтров. --query даёт доступ к языку запросов приложения — тому же, что и в командной строке, — и, следовательно, ко всем фильтрам, которые не рисуются на доске: шаблон хода, текст комментария, игрок, дата, эквити, исключённые броски, зоны и блоты.
Грамматика записана лишь в одном месте — Фильтры поиска. Её таблица даёт каждый токен, его форму и соответствующий ему флаг search, когда такой существует. Эта страница её не повторяет.
./blunderdb search --db base.db --query 's p>30 E>50'
./blunderdb search --db base.db --query 's m"13/11" t"blunder" pl"Alice" T>2026/01/01'
Упорядочивание соседей позиции идёт через ту же грамматику: --query 's like42' — отдельно или с другими токенами, сужающими упорядоченное множество.
--query-help напоминает этот список, не открывая базы:
$ ./blunderdb search --query-help
blunderdb search --query — the interface's query language
A query is the same text the application's command bar takes:
s cube p>30 E>50 cube decisions, 30+ pips behind, 50+ millipoints of error
s m"13/11" T>2026/01/01 played 13/11, imported this year
Flags (no value):
cube score match the cube / the score of the position on the board
d match the decision type (checker or cube)
…
Ranges — each takes x>n, x<n or xa,b (lower-case: you; upper-case: the opponent):
p P pip count difference / absolute pip count
…
E error of the played move, in millipoints
T creation date, T>2026/01/01
Values:
t"tag" comment text (";" separates alternatives)
…
--query заменяет флаги фильтрации, а не дополняет их: их сочетание отклоняется с указанием конфликтующего флага. Флаги, определяющие, где искать и как показывать — --db, --format, --limit, --offset, --export — остаются в силе.
Токен, который ничем не распознан, приводит к ошибке команды, а не к молчаливому сужению поиска. Два ограничения вытекают из отсутствия доски в командной строке: рисунок шашек напечатать нельзя, а пять токенов, читающих доску — cube, score, d, D/D1 и x, — сравниваются здесь с пустой доской. Поиск, которому нужен один из них, записывается целиком флагами, поскольку --query с ними не сочетается — например, решения по кубу с отставанием в 30 пипов и ошибкой не менее 50 миллипоинтов:
./blunderdb search --db base.db --decision cube --pip-min 30 --move-error-min 50
Примеры:
./blunderdb search --db base.db --decision cube
./blunderdb search --db base.db --individual
./blunderdb search --db base.db --error-min 0.1
./blunderdb search --db base.db --tournament-ids 1 --export cubes.db
# 6-5 dans les deux ordres, puis un 6 sur l'un des deux dés
./blunderdb search --db base.db --dice 6,5
./blunderdb search --db base.db --dice 6
# Pagination
./blunderdb search --db base.db --format json --limit 10 --offset 20
list — Список содержимого
Отображает содержимое базы данных.
./blunderdb list --db <path> --type <type> [--limit <n>] [--offset <n>]
Типы:
matches— Список импортированных матчей.tournaments— Список турниров.positions— Список позиций (по умолчанию 10;--offset <n>пропускает первые n). Читается только показываемое окно, каким бы ни был размер базы. С--format csvстановится табличным экспортом: одна строка на позицию с её XGID, фазой, счётом, кубом, пипами и производными столбцами анализа.imports— Записанные импорты, от новых к старым: идентификатор, дата, формат, источник, матчи импортированные / пропущенные / обогащённые, нечитаемые файлы и новые позиции. С--batch <id>показывается полный отчёт одного импорта: отмеченные позиции, позиции без анализа, PR по этой партии и её пять худших решений (см. Отчёт об импорте).stats— Отчёт со статистикой производительности: PR / Snowie ER / MWC (глобально, шашки, куб), скользящий PR за последние N решений, худшие ошибки, разбивка по действиям куба и гистограмма величин ошибок.players— Сравнительная таблица, по строке на каждого игрока базы: матчи, победы/поражения, учтённые решения, PR общий / шашки / куб, Snowie ER, ошибки, бландеры и удача. Это командный аналог вкладки «Игроки» панели статистики.moves— Табличный экспорт записанных ходов, по одному на строку, с матчем, которому они принадлежат, повторённым в каждой строке: идентификаторы, дата, игроки, длина, номер и тип хода, позиция, кости, сыгранный ход, действие с кубом, удача. Требуется--format csv.analyses— Табличный экспорт сохранённых анализов, по одному на строку: движок, глубина, лучший ход и его эквити, ошибка сыгранного хода, лучшее действие с кубом и его ошибка, шесть долей выигрыша. Требуется--format csv.tags— Словарь тегов базы: каждое#слово, написанное в комментарии, с числом позиций, которые его несут, от самого используемого к менее используемому. В базе без единого тега показывает рекомендуемый словарь вместо пустого списка (см. Теги). Принимает--format jsonи--format csv.
Табличные экспорты
Три типа — positions, moves и analyses — экспортируются в CSV для notebook, таблицы или скрипта:
./blunderdb list --db base.db --type positions --format csv > positions.csv
./blunderdb list --db base.db --type moves --format csv > moves.csv
./blunderdb list --db base.db --type analyses --format csv > analyses.csv
--limit действует только если вы его передали. Значение по умолчанию (10) существует, чтобы list в терминале не прокручивал всю базу; экспорт же уходит в файл, который читает программа, и молча обрезать его на десяти строках было бы ловушкой, незаметной до тех пор, пока цифры не окажутся неверными.
Столбцы — это контракт. Notebook или скрипт, написанный под эти имена, должен продолжать работать: столбцы добавляются в конец, никогда не переименовываются и не переставляются. Все эквити — в целых миллипунктах, потому что так они хранятся и потому что дробное число в CSV приглашает локаль его переформатировать.
Parquet не предлагается, и это измеренное, а не догматическое решение: колоночная библиотека весит несколько мегабайт в бинарнике, за размером которого следят, тогда как всё, ради чего существует этот экспорт, читает CSV одной строкой (pd.read_csv, polars.read_csv, read.csv, таблица). Parquet оправдывает себя на десятках миллионов строк; десятилетняя библиотека нард насчитывает сто тысяч. Если однажды разница окажется измеримой на настоящей базе, именно это измерение и откроет вопрос заново.
К этим экспортам прилагается пример notebook для Jupyter (notebooks/blunderdb-analyse.ipynb в репозитории): PR во времени, распределение величин ошибок, десять худших решений с их XGID. Он не использует ничего, кроме этих трёх CSV-файлов, и выполняется каждую ночь в непрерывной интеграции — notebook, который никто не запускает, это notebook, переставший работать так, что никто об этом не знает.
Опции (только для типа stats):
--metric— Отображаемая метрика:prилиmwc(по умолчанию:pr).--player— Ограничить указанным игроком.--tournament— Ограничить одним или несколькими идентификаторами турниров (через запятую).--from— Дата начала (ГГГГ-ММ-ДД).--to— Дата окончания (ГГГГ-ММ-ДД).--decision-type— Тип решения:all,checkerилиcube(по умолчанию:all).--top-blunders— Количество перечисляемых худших ошибок (по умолчанию: 10).--format— Формат вывода:textилиjson(по умолчанию:text).
Опции (только для типа imports):
--batch— Идентификатор партии: показывает её полный отчёт вместо списка.--queue— С--batch: очередь разбора пакета вместо его отчёта — позиции, заслуживающие второго взгляда, в том порядке, в каком их проходить (см. Очередь разбора). Сначала решения, которые чего-то стоили, затем позиции, отмеченные в исходной программе, затем спорные решения о кубе; позиция встречается лишь один раз.--format— Формат вывода:textилиjson(по умолчанию:text).
Измеряемая половина отчёта пересчитывается при каждом вызове: партия, позиции которой с тех пор были проанализированы, возвращает сегодняшние цифры, а не цифры дня импорта.
Опции (только для типа players):
--from/--to— Границы дат (ГГГГ-ММ-ДД), например дни соревнования.--tournament— Ограничить одним или несколькими ID турниров.--format— Формат вывода:text,jsonилиcsv(по умолчанию:text).
--player и --decision-type к этому типу не применяются: таблица охватывает всех игроков и уже разносит шашки и куб по отдельным столбцам.
Примечание
Прочерк «—» (в CSV — пустое поле) означает величину, которая никогда не измерялась, и её не следует путать с нулём. Так обстоит дело с удачей для любого матча, импортированного до версии схемы 2.15.0, а также для форматов, которые её не переносят (BGF, Jellyfish .mat): чтобы её получить, импортируйте исходные файлы заново. Столбец luck_rolls показывает, по скольким броскам взято среднее.
Каждый тип выводит по блоку на элемент, предваряя их найденным итогом. Последняя строка сообщает, какое окно показано: оно ограничено --limit (по умолчанию 10 для позиций) и сдвинуто --offset:
Found 3859 position(s):
ID: 1
Score: 7-7
Player on roll: 0
Decision: Checker play
ID: 2
Score: 7-7
Player on roll: 0
Decision: Cube action
…
(Showing 1-10 of 3859 positions, use --offset and --limit to see more)
Примеры:
# Les imports enregistrés, puis le compte rendu de l'un d'eux
./blunderdb list --db base.db --type imports
./blunderdb list --db base.db --type imports --batch 3
./blunderdb list --db base.db --type stats
./blunderdb list --db base.db --type stats --metric mwc --player "Alice"
./blunderdb list --db base.db --type stats --decision-type checker --from 2026-01-01
./blunderdb list --db base.db --type stats --format json
# Un tableau par joueur, borné aux dates d'une compétition
./blunderdb list --db base.db --type players --from 2026-03-01 --to 2026-03-08
./blunderdb list --db base.db --type players --format csv
./blunderdb list --db base.db --type matches
./blunderdb list --db base.db --type positions --limit 20
match — Отобразить матч
Отображает позиции и анализ импортированного матча.
./blunderdb match --db <path> --id <id> [--format <format>] [--output <file>]
Параметры:
--db— База данных (обязательно).--id— Идентификатор матча для отображения (обязательно).--format— Формат вывода:json,textилиsummary(по умолчанию:json).--output— Выходной файл (по умолчанию: стандартный вывод).
Примеры:
./blunderdb match --db base.db --id 1 --format summary
./blunderdb match --db base.db --id 1 --format text
./blunderdb match --db base.db --id 1 --output match1.json
collection — Управление коллекциями
Управляет коллекциями — наборами позиций, выбранных вручную на панели Коллекции интерфейса. Каждая подкоманда принимает --db; list и show принимают --format text (по умолчанию), json или csv, как и list.
./blunderdb collection <subcommand> [options]
Подкоманды:
list— Список коллекций: id, название, число позиций, описание.show --id <id>— Позиции коллекции: id, индекс (номер, начиная с 1, отображаемый в строке состояния интерфейса), счёт, тип решения и XGID.create --name <имя> [--description <текст>]— Создаёт пустую коллекцию.filter --id <id> --query <запрос>— Делает коллекцию живой: её содержимое становится результатом поиска, пересчитываемым при каждом открытии. Запрос пишется на собственной грамматике поиска приложения (см. Фильтры поиска).--clearвозвращает её к списку, составленному вручную, сохраняя содержавшиеся в ней позиции.rename --id <id> --name <имя> [--description <текст>]— Переименовывает коллекцию (описание сохраняется, если оно не задано).delete --id <id> [--confirm]— Удаляет коллекцию; её позиции остаются в базе.export --id <id[,id…]> --out <файл.db> [--analysis=false] [--comments=false] [--watermark <текст>] [--watermark-note <текст>]— Экспортирует одну или несколько коллекций в новый файл базы, тем же вызовом, что и окно экспорта интерфейса (о водяном знаке см. командуexport).
XGID, показываемый show, — это тот, что сохранён вместе с анализом позиции, если он есть (импорт BGF и XGP); иначе он генерируется из доски точно так же, как Копировать позицию в интерфейсе — длина матча тогда берётся как больший из двух оставшихся счётов, поскольку сохранённая позиция не хранит настоящую.
Примеры:
./blunderdb collection list --db base.db
# Found 2 collection(s):
#
# ID Name Positions Description
# -- ---- --------- -----------
# 1 Ouvertures blitz 0 À revoir
# 2 Videaux ratés 0
База без коллекций отвечает No collections found in database и всё равно завершается с кодом 0.
./blunderdb collection show --db base.db --id 3 --format csv
./blunderdb collection create --db base.db --name "Ouvertures blitz"
./blunderdb collection rename --db base.db --id 3 --name "Ouvertures"
./blunderdb collection delete --db base.db --id 3 --confirm
# Exporter deux collections, marquées de leur origine
./blunderdb collection export --db base.db --id 3,4 --out ouvertures.db \
--watermark "Cours de Jean Dupont - 12 mars 2026"
anki — Колоды интервального повторения
Просматривает и обслуживает колоды интервального повторения (FSRS) панели Anki интерфейса. Повторение карточки требует доски и остаётся в интерфейсе; CLI выводит список, измеряет и ресинхронизирует.
./blunderdb anki <subcommand> [options]
Подкоманды:
decks [--format text|json|csv]— Список колод: источник, число карточек, карточки к повторению, новые карточки.stats --deck <id> [--format text|json]— Статистика повторения колоды: всего, новых, изучаемых, к пересмотру, к повторению сейчас, и её параметры FSRS.forecast [--deck <id>] [--days <n>] [--format text|json|csv]— Карточки, наступающие по календарным дням (UTC) наnближайших дней (по умолчанию 30, максимум 365); день 0 включает все просроченные карточки;--deck 0(по умолчанию) охватывает все колоды.sync --deck <id>— Добавляет карточку для каждой позиции источника колоды, у которой её ещё нет; существующие карточки сохраняют своё расписание.retention --deck <id> [--format text|json]— измеренное удержание колоды в сравнении с целью, выбранной её владельцем.card --id <id> --action suspend|unsuspend|bury|remove [--format text|json]— действует на одну карточку. Приостановка откладывает её, не теряя историю (она больше не выпадает в сеансе); закапывание прячет её до следующего дня, ничего не говоря о её ценности; удаление убирает её из колоды — сама позиция остаётся в библиотеке, ведь колода лишь список изучения поверх неё.log [--deck <id>] [--limit <n>] [--format text|json]— журнал повторений, самые свежие сначала (--deck 0, по умолчанию, охватывает все колоды;--limitпо умолчанию 20). Журнал — это то, что планировщику действительно сообщили, в отличие от того, что он планирует сегодня: единственное место, где видна оценка, введённая по ошибке.
Колода, основанная на коллекции, перечитывает свою коллекцию. Колода, основанная на поиске, сохраняет поиск таким, каким его записал интерфейс (команда, доска и идентификаторы найденных на тот момент позиций): грамматика поиска живёт в интерфейсе, поэтому CLI ресинхронизирует по сохранённым идентификаторам и сообщает об этом в поток ошибок — откройте колоду в интерфейсе, чтобы заново выполнить сам поиск.
Примеры:
./blunderdb anki decks --db base.db
./blunderdb anki stats --db base.db --deck 2 --format json
./blunderdb anki forecast --db base.db --deck 2 --days 14
./blunderdb anki sync --db base.db --deck 2
./blunderdb anki card --db base.db --id 12 --action suspend
./blunderdb anki log --db base.db --deck 2 --limit 50
# Day Due
# --- ---
# 2026-09-02 12
# 2026-09-03 4
# ...
#
# 37 card(s) due over 14 day(s)
stats — Повторяющиеся ошибки
Группирует ошибки фильтра по плану игры и по теме, начиная с самой дорогой: таблица Повторяющиеся ошибки на вкладке Errors панели Stats (см. Панель Stats). Глобальная статистика остаётся в list --type stats.
./blunderdb stats recurring --db <fichier> [options]
Параметры:
--player <nom>— Только решения этого игрока.--tournament <ids>,--from <AAAA-MM-JJ>,--to <AAAA-MM-JJ>,--decision-type all|checker|cube— Тот же фильтр, что и уlist --type stats.--limit <n>— Число групп, выводимых текстом (по умолчанию 20,0— все).--format text|json— JSON содержит каждую группу с полным списком её позиций.--quiz— Случайно выбирает позиции из позиций трёх самых затратных групп (--quiz-size <n>, по умолчанию 20) и выводит их: это идентификаторы, которые оценивают викторина иquiz_grade. В JSON — полеQuiz.--deck <имя>— Создаёт колоду Anki с этим именем, заполненную всеми позициями трёх самых затратных групп.--group <ранг>— Вместе с--quizили--deck: группа этого ранга (1 — самая затратная) вместо первых трёх.
Тема хода фишками — gammon, blots, point или passive; тема куба — offer_missed, offer_premature, answer_wrong_pass или answer_wrong_take. Ошибки, которые не называет ни одно правило, выходят из рейтинга: они перечисляются отдельно, по одной строке на план игры (поле Unthemed в JSON), потому что пояснение высказывается только от 60 mp, выше порога Ошибка. Столбец COST (PR) — доля PR фильтра, которую составляет группа.
Примеры:
./blunderdb stats recurring --db base.db --player "Alice"
./blunderdb stats recurring --db base.db --decision-type checker --format json
./blunderdb stats recurring --db base.db --quiz --format json
./blunderdb stats recurring --db base.db --group 1 --deck "Mon pire groupe"
stats training — PR викторины «Решение», PR матчей и удержание Anki, свёрнутые по календарным окнам, как вкладка Тренировка панели Stats (см. Панель Stats).
./blunderdb stats training --db <fichier> [options]
Параметры:
--window week|month— Календарное окно (по умолчаниюweek).--player <имя>,--tournament <ids>,--from <ГГГГ-ММ-ДД>,--to <ГГГГ-ММ-ДД>,--decision-type all|checker|cube— Фильтр матчей; журналы викторины и Anki не содержат игрока.--format text|json— JSON содержит также список сессий викторины.
Каждый ряд хранит число своих выборок: окно без решений в тексте — прочерк, в JSON — нулевой счёт, но никогда не нулевое значение.
Примеры:
./blunderdb stats training --db base.db --player "Alice"
./blunderdb stats training --db base.db --window month --format json
cubematrix — Матрица куба
Даёт вердикт куба для позиции при любом счёте матча: для каждой клетки away × away — удваивать ли и принимать ли. Чистое вычисление: никакая база данных не открывается, позиция передаётся через XGID или OGID (OpenGammon).
./blunderdb cubematrix [options] '<XGID|OGID>'
Параметры:
--format— Формат вывода:textилиjson(по умолчанию:text).--match-length— Длина матча, которую покрывает сетка, от 1 до 25 (по умолчанию: 7).--ply— Глубина поиска для каждой клетки,0или2(по умолчанию: 2).--prune-k— Число ходов-кандидатов, оставляемых сетью отсечения (по умолчанию: 12).--jobs— Число параллельных поисков (по умолчанию: по одному на ядро). Сетка одинакова при любом значении; меняется только время.
Собственный счёт позиции игнорируется — сетка его заменяет — но её куб сохраняется: вопрос в том, при каком счёте стоит повернуть этот куб. Сетка всюду построена для положения после Кроуфорда.
Каждая клетка — отдельный поиск, потому что движок учитывает счёт: единственный поиск, прочитанный через разные матчевые эквити, был бы неверен именно там, где счёт важен.
Примеры:
# Grille d'un match en 5 points
./blunderdb cubematrix --match-length 5 'XGID=-b----E-C---eE---c-e----B-:0:0:1:00:0:0:0:7:10'
# Les équités de chaque case, pour un script
./blunderdb cubematrix --format json '<XGID>'
Вывод text: сетка, строки которой — очки, которых ещё не хватает игроку на ходу, а столбцы — очки соперника, затем легенда обозначений ND / DT / DP / TG и причина для каждой отклонённой клетки.
rollout — Rollout позиции
Играет позицию большое число раз с помощью gammonNet, чтобы решить то, чего не решает поиск: два хода, отличающихся на тысячные доли, или решение по кубу, в котором модель колеблется. С кубиками играются её ходы (лучшие на глубине rollout, не менее 2 ply, или названные через --move); без кубиков — её решение по кубу (Без удвоения и Удвоение/Принять; Удвоение/Отказ стоит ровно +1). Позиция берётся из XGID или OGID либо из базы (--db и --id); без --store ничего не записывается.
./blunderdb rollout [options] '<XGID|OGID>'
./blunderdb rollout --db <path> --id <position> [--store] [options]
Параметры:
--preset— Исходная настройка:fast(по умолчанию: 216 партий, усечённых на 7 полуходах, остановка при JSD 3 после 108) илиstandard(1296 партий, усечённых на 11, остановка при JSD 3 после 324). Обе играют на 0 ply — одна сеть, для ходов, куба и листьев;--ply 1и больше играет глубже, со временем в несколько раз больше. Следующие опции заменяют её по одной.--games,--min-games,--truncation,--jsd,--ply,--candidates— Параметры rollout (--truncation 0доигрывает каждую партию до конца,--jsd 0никогда не останавливается до конца).--move— Ход, который нужно сыграть, в нотации blunderDB (можно повторять).--seed— Зерно кубиков, по умолчанию фиксированное: одна и та же команда даёт те же числа.--jobs— Партии, играемые параллельно (по умолчанию: по одной на ядро); меняется только время.--format— Формат вывода:textилиjson(по умолчанию:text).--db,--id— База и идентификатор позиции, которую нужно сыграть, вместо XGID.--store— Записывает завершённый роллаут в позицию как второй анализ со своими настройками, рядом с импортированным или вычисленным анализом, который он никогда не заменяет. Прерванный роллаут не записывается; из двух роллаутов с одинаковыми настройками сохраняется более длинная серия, а роллаут с другими настройками добавляется рядом.--list— Выводит сохранённые для позиции роллауты, от новых к старым, вместо того чтобы проводить новый.
Все кандидаты играют одними и теми же кубиками, удача каждого броска вычитается из результата каждой партии (снижение дисперсии), первые два броска стратифицируются, а партия останавливается там, где её покрывает two-sided база окончания игры. Каждая строка даёт эквити, его 95 %-й интервал, число сыгранных партий и JSD — отставание от лучшего в стандартных отклонениях разности. Куб разыгрывается во время партий: рейтинг надёжнее абсолютного эквити. Ctrl-C показывает то, что установили завершённые партии.
Примеры:
./blunderdb rollout 'XGID=-b----E-C---eE---c-e----B-:0:0:1:31:0:0:0:0:10'
./blunderdb rollout --move '8/5 6/5' --move '24/23 13/10' '<XGID>'
./blunderdb rollout --db base.db --id 42 --preset standard --store
./blunderdb rollout --db base.db --id 42 --list
epc — Калькулятор EPC
Вычисляет Effective Pip Count, вероятность выигрыша и вердикт по кубу для игры на деньги для позиции выброса, заданной XGID или OGID (OpenGammon). Чистое вычисление: никакой файл базы не задействован.
./blunderdb epc [options] '<XGID|OGID>'
Параметры:
--format— Формат вывода:textилиjson(по умолчанию:text).--bearoff-ts— Необязательная двусторонняя база выброса (.bd), расширяющая встроенную TS-06-06 (читается также из переменной окруженияBLUNDERDB_TS_PATH). Побеждает самая широкая корректная база; неверный файл игнорируется с предупреждением.
Режимы. В области, покрытой двусторонней базой, вероятность выигрыша и анализ куба для игры на деньги (cubeless, ND, D/T, D/P, вердикт) точны. За её пределами вероятность выигрыша оценивается (свёртка односторонних распределений бросков плюс откалиброванная поправка) и выводится с измеренной погрешностью; вердикт по кубу намеренно никогда не оценивается (см. ADR-0009).
Примеры:
# Régime exact : six pions ou moins de chaque côté
./blunderdb epc 'XGID=-BBB------------------bbb-:0:0:1:00:0:0:0:0:10'
# Avec la table TS-06-11 calculée : exact jusqu'à onze pions par joueur
./blunderdb epc --bearoff-ts ~/.local/share/blunderdb/gnubg_ts6x11.bd 'XGID=…'
bearoff — Базы бироффа
Создаёт базы бироффа и управляет ими. Ничего не загружается и ничего не встроено: таблица вычисляется здесь и сверяется с отпечатком, который gnubg производит для её области. Ни одна подкоманда не обращается к базе данных — таблица бироффа есть арифметика об игре, а не о чьих-либо позициях, — поэтому ни одна не принимает --db.
./blunderdb bearoff generate --ts <domain> [options]
./blunderdb bearoff list [options]
./blunderdb bearoff verify <file.bd> [options]
./blunderdb bearoff delete --ts <domain> [options]
Область записывается как в makebearoff: 6x9 для двусторонней таблицы с девятью шашками у игрока, os8 для односторонней таблицы на восемь пунктов (одно os означает os6).
Два семейства отвечают на разные вопросы. Двусторонняя таблица расширяет область, где вероятность выигрыша и вердикт куба точны; односторонняя расширяет расстояние, на котором может стоять шашка без того, чтобы EPC умолк (до десяти пунктов).
generate. Называет размер, память и оценку времени до начала, затем показывает процент и измеренное оставшееся время.
--ts— Вычисляемая двусторонняя область, например6x9.--os— Вычисляемая односторонняя область, числом пунктов: от 6 до 12. Требуется ровно одно из двух.--cores— Используемые ядра (по умолчанию: все, кроме одного).--data-dir— Куда писать (по умолчанию: каталог данных приложения).--quiet— Без строки прогресса.
CTRL-C ставит на паузу. Сигнал перехватывается: состояние записывается рядом с таблицей, и та же команда, запущенная снова, продолжает с места остановки, а не пересчитывает всё. Полчаса арифметики стоит записать. bearoff delete выбрасывает отложенное продолжение. На паузу встаёт только двусторонний проход; односторонний последователен, и --cores ему ничего не даёт.
list. Оценивает каждую область — размер, память, время на этой машине — и говорит, какие уже есть, с их вердиктом, и у каких есть приостановленный проход. --format json для сценария, --cores чтобы изменить допущение оценки.
verify. Отвечает verified (те же байты, что у эталона), unverified (корректная, но для этой области отпечаток не записан) или corrupt (файл противоречит сам себе). В последнем случае завершается с ошибкой: эта команда сделана для сценария.
delete. Удаляет таблицу, отложенное продолжение и остатки погибшего прохода. Область по умолчанию пересчитывается при следующем запуске приложения; более широкая — нет.
Примеры:
# Ce que cette machine a, et ce que chaque domaine coûterait
./blunderdb bearoff list
./blunderdb bearoff generate --ts 6x9 --cores 4
# OS-08 : l'EPC répond alors jusqu'à un pion sur la 8
./blunderdb bearoff generate --os 8
# Sur un serveur, dans le volume que lit le démon
./blunderdb bearoff generate --ts 6x11 --data-dir /srv/bearoff
./blunderdb bearoff verify /srv/bearoff/gnubg_ts6x11.bd
analyze — Догоняющий анализ gammonNet
Записывает анализ gammonNet для каждой позиции, у которой нет никакого анализа, — догоняющий анализ библиотеки, собранной до появления этой функции (ADR-0013, ADR-0015). Это та же операция, что и автоматический запуск после импорта и кнопка «Анализировать сейчас» графического интерфейса, и что точка доступа /v1/gammonnet.analyzeMissing демона serve для одного арендатора — три разные формы одной операции, а не три разные логики (см. Безголовый режим (сервер)).
./blunderdb analyze --db <path> [options]
Параметры:
--db— База данных (обязательно).--ply— Глубина поиска (по умолчанию: 2, канонический параметр).--prune-k— Ширина отсечения (по умолчанию: 12, канонический параметр).--candidates— Число кандидатных ходов, сохраняемых для каждого решения о ходе (по умолчанию: 10).--jobs— Число позиций, анализируемых параллельно (по умолчанию: число ядер машины).--match— Ограничивает пакет позициями одного матча (0, значение по умолчанию, означает всю библиотеку).--compare— Ничего не пишет: сравнивает gammonNet с импортированными анализами вместо заполнения пробелов (см. ниже).--limit— С--compare: останавливается после указанного числа позиций (0 = все).--format— Формат вывода:text(по умолчанию, с индикацией хода выполнения) илиjson(единый итоговый документ, выводимый в конце).--rollout— Делает rollout позиций, выбранных--query, вместо заполнения пропусков (см. ниже).--query— С--rollout: позиции для игры, на языке запросов поиска (search --query-help); пусто — все.
Матч, импортированный без анализа, теперь получает PR. Это случай матча, сыгранного онлайн, или файла Jellyfish .mat, который никто не пропускал через XG. blunderDB знал его позиции и сыгранные ходы, но ничто не говорило, чего они стоят; после прогона фактически сыгранный ход сравнивается с ранжированием gammonNet, и разница питает PR и все остальные показатели. Сыгранный ход берётся из таблицы ходов самого матча, записанной при импорте, независимо от того, нёс ли файл анализ, — он никогда не угадывается.
Базу, проанализированную более ранней версией, не нужно переоценивать: repair пересчитывает столбцы по тому, что уже хранится, и возвращает этим матчам их PR.
Только один матч (--match). С идентификатором, который выводит list --type matches, пакет проходит только по позициям этого матча: то же правило пробела, те же гарантии, более узкая область. Только что импортированный матч получает свои анализы без обхода остальной библиотеки, а исправленный и проанализированный во второй раз матч стоит лишь тех позиций, которые создало исправление, поскольку все остальные уже несут анализ. Параметр не сочетается ни с --stale, ни с --compare: оба смотрят на позиции, у которых анализ уже есть, поэтому запрос обоих — ошибка, а не молча проигнорированная область.
Параллелизм (--jobs). Позиции пакета независимы — ни один поиск не влияет на следующий — поэтому они распределяются по --jobs потокам, каждый со своим собственным оценщиком. Записанные анализы идентичны при любом значении --jobs; меняется только время вычислений. --jobs 1 оставляет машину свободной для других задач. Отмена не затрагивается: Ctrl-C останавливает пакет перед любой новой позицией, и всё уже вычисленное записывается.
Правило пробела (ADR-0013). Позиция, уже имеющая анализ — XG, GNUbg, BGBlitz или предыдущий проход gammonNet, — никогда не затрагивается, какого бы движка ни недоставало. Записывается только позиция без какого-либо анализа. Поэтому команду можно без риска перезапускать в любой момент и корректно прерывать: Ctrl-C отменяет её, не теряя ничего из уже записанного, а следующий запуск возобновляет работу ровно с того места, где остановился предыдущий, — никакого журнала не нужно, ведь «позиции без анализа» пересчитываются при каждом запуске.
Пример:
./blunderdb analyze --db base.db
# Analyzing 1204 position(s) with gammonNet (2-ply, k=12, 16 job(s))...
# 1/1204 (0%)
# 61/1204 (5%)
# ...
# 1204/1204 (100%)
# Done.
./blunderdb analyze --db base.db --jobs 1
# Un seul match, celui qui vient d'être importé
./blunderdb analyze --db base.db --match 12
Rollout пакетом (--rollout). Каждая позиция, выбранная --query, играется rollout, одна за другой на всех ядрах, и rollout записывается рядом с её анализом, а не вместо него. Значение — пресет: fast (216 партий, усечённых на 7) или standard (1296 партий, усечённых на 11) — либо свободные настройки: необязательный пресет, затем games=, min-games=, truncation=, jsd=, ply=, candidates=, seed=, через запятую. Позиция, уже имеющая rollout с теми же настройками, пропускается: запуск, прерванный Ctrl-C, продолжается с того места, где остановился, а текущая позиция отбрасывается целиком. Позиция, которую анализирует только rollout, находится поиском через него; уже проанализированная позиция сохраняет столбцы своего анализа.
./blunderdb analyze --db base.db --rollout fast --query 'E>80'
./blunderdb analyze --db base.db --rollout 'standard,ply=1' --query 'c'
--compare: чего стоит gammonNet на вашей базе?
Точность движка измеряется в другом месте — на эталонных корпусах и на точной таблице снятия. Ни одно из этих измерений не отвечает на вопрос, который пользователь задаёт на самом деле и который касается его позиций: в матчах, импортированных из XG, где встроенный движок расходится с анализом, пришедшим вместе с файлом, и во что это расхождение обошлось бы?
--compare отвечает и ничего не пишет. Это не предосторожность, а смысл команды: ADR-0013 защищает импортированный анализ безусловно, и потому сравнение можно запустить на базе, которую совсем не хочется видеть переписанной.
Отчёт даёт:
долю совпадений по лучшему ответу, отдельно для ходов шашками и решений по кубу — эти две вещи никак не связаны, и единая доля скрыла бы, какая из них проседает;
стоимость расхождения, оценённую по шкале импортированного анализа: чего стоит предпочитаемый gammonNet ход по мнению импортированного движка, минус то, чего стоит его собственный лучший ход. Это направление — единственное, которое оба движка могут оценить вместе; оценивать расхождение дважды значило бы приглашать читать меньшее из двух чисел;
разбивку по фазе игры, которая и говорит, где расхождения сосредоточены;
десять самых дорогих расхождений, позиция за позицией.
Два движка пишут один и тот же ход по-разному — XG пишет «13/7» там, где gammonNet пишет «13/8 8/7», удары помечаются с одной стороны и не помечаются с другой, повтор иногда сворачивается в «(2)». Эти различия — диалект, а не расхождение: сравнение приводит обе записи к канонической форме, прежде чем сравнивать. Без этого тестовый корпус показывал 78,8 % совпадений вместо 93,2 % — пятнадцать пунктов ложных расхождений.
Ход, который импортированный движок не перечислил, нельзя оценить по его шкале: он считается расхождением нулевой стоимости, а не стоимости выдуманной.
# Comparer sur un échantillon de 500 positions
./blunderdb analyze --db base.db --compare --limit 500
# compared: 118 decision(s) (refused 2, failed 0)
# same best answer: 93.2% (110/118)
# checker play: 93.7% (59/63)
# cube decision: 92.7% (51/55)
# ...
transcribe — Воспроизвести запись
Воспроизводит запись и сообщает, что в ней обнаруживает повторное проигрывание. Источник — файл .mat, матч библиотеки или черновик записи, ровно один из трёх. Матч читается через тот .mat, который он дал бы при экспорте: воспроизводится, стало быть, то, что содержал бы экспорт.
./blunderdb transcribe --mat <fichier> [--check] [--render <sortie>]
./blunderdb transcribe --db <path> --match <id> --check
./blunderdb transcribe --db <path> --draft <id> --check
./blunderdb transcribe --db <path> --match <id> --edit [--accept-losses]
./blunderdb transcribe --db <path> --draft <id> --finish|--abandon
Параметры:
--mat— Воспроизводимый файл.mat.--db— База данных, для--matchи--draft.--match— Идентификатор воспроизводимого матча библиотеки.--draft— Идентификатор воспроизводимого черновика записи.--check— Перечисляет найденные несоответствия (поведение по умолчанию).--render— Записывает запись обратно в.matпо этому пути.--format— Формат вывода:text(по умолчанию) илиjson.--edit— Открывает черновик для--match(или возвращает уже открытый для него).--accept-losses— С--editдля импортированного матча: соглашается, что его анализы и комментарии могут быть потеряны.--finish— Завершает--draft: записывает его матч или заменяет тот, из которого он был открыт, и освобождает черновик.--abandon— Отказывается от--draft: удаляет его без матча; матч, из которого он был открыт, остаётся как есть.--yes— С--abandonдля черновика, который так и не породил матч: подтверждает, что всё записанное в нём будет потеряно.
--check называет каждое несоответствие с номером действия и партией, в которой оно находится: недопустимый ход, два хода подряд одного игрока, невозможное действие с кубом, действие после конца матча, ход, шаги которого не используют собственные кости, первый ход партии с дублем, которым стартовый бросок быть не может, незаписанный ход — ячейка ???, которую gnubg пишет, когда не сохранил сыгранный ход, и которая не означает, что игрок не смог сходить, несогласованный заявленный счёт — партия, строка счёта которой не та, что дают предыдущие партии, и которая переигрывается с записанным счётом.
Несоответствие сообщается, но никогда не ставится в упрёк: из-за него ничего не отвергается, и код возврата остаётся нулевым, что бы ни нашло проигрывание. Ненулевой код означает настоящий сбой — нечитаемый файл, база, которая не открывается, вывод, который невозможно записать. Скрипт, желающий действовать по этим наблюдениям, читает их в --format json, где испорченный файл и партия с недопустимым ходом не смешиваются.
--render записывает запись обратно в .mat, что позволяет проверить обратимость преобразования на настоящем файле вне тестов.
Записывают только три параметра, теми же методами, что и панель «Запись»: --edit открывает черновик для существующего матча, --finish завершает его — матч заменяется под тем же идентификатором — а --abandon удаляет черновик без матча и требует --yes для черновика, который так и не был завершён и уносит с собой всё записанное в нём. Импортированный матч несёт анализы и комментарии, которых нет в .mat: --edit сообщает самое большее их число и отказывает без --accept-losses.
Пример:
./blunderdb transcribe --mat match.mat --check
# match.mat: 7 point match, 4 game(s), 203 action(s)
# Final score: 9-2
# Inconsistencies: none
tournament — Чтение проведённого турнира
Читает руководимый турнир без графического интерфейса. Интерактивное руководство турниром — дело консоли движка Nicomaque; эти подкоманды читают, ни одна не ждёт ввода, и только move пишет.
./blunderdb tournament <sous-commande> --db <chemin> [options]
Подкоманды:
list [--format text|json]— Проведённые турниры базы, с их состоянием, версией движка, мероприятием, к которому принадлежит каждый (пусто, если ни к какому), и датой последнего решения.verify --id N [--format text|json]— Переигрывает проведение и сообщает о каждом оставшемся предупреждении. Завершается с ошибкой, если хоть одно осталось: это проверка после турнира, и скрипту, который прогоняет её по базам сезона, нужен код возврата, а не строка для фильтрации.standings --id N— Итоговая таблица в CSV, с призовыми, на языке интерфейса.ranking --season [--rencontre N] [--from AAAA-MM-JJ] [--to AAAA-MM-JJ] [--points 25,18,15] [--participation P] [--elo] [--format csv|json]— Сезонный рейтинг: завершённые турниры мероприятия или периода (границы включены, по дате турнира; без фильтра — все проведённые турниры), где каждое место переводится в очки по шкале (победитель первым; по умолчанию 25, 18, 15, 12, 10, 8, 6, 4, 2, 1), плюс--participationза каждый сыгранный турнир. Разделившие место делят среднее из занимаемых ими мест. Человек узнаётся от турнира к турниру по имени.--eloдобавляет клубный Elo, пересчитанный по матчам сезона (формула FIBS, старт с 1500). CSV содержит одну строку на человека и один столбец очков на турнир; незавершённый турнир указывается в списке, но ничего не приносит.page --id N|--rencontre N [--out <папка>]— HTML-страница для экрана одного состязания (--id), либо настенная страница мероприятия (--rencontre: одна строка на стол, независимо от того, какое состязание его занимает). Требуется ровно один из двух. Без--outона идёт в стандартный вывод; с ним записывается в папку, которая становится папкой проведения или мероприятия.export --id N— Сырой журнал событий, воспроизводимый инструментами движка. Журнал — вся правда о проведении: таблица, сетки и предупреждения воспроизводятся из него. Инструменту, читающему этот вывод, blunderDB не нужен вовсе.move --id N --match M --table T [--format text|json]— Меняет стол идущего матча, как перетаскивание одной ячейки на другую в сетке. Если целевой стол занят, два матча меняются столами; стол, выведенный из эксплуатации, отклоняется. В мероприятии, если стол занят другим состязанием, обмен происходит между двумя состязаниями: смена стола записывается в журнал каждого. Выводит стол каждого идущего матча.hall --rencontre N [--format text|json]— Все столы мероприятия: одна строка на стол, какое бы состязание его ни занимало (состязание, матч, игроки), затем предложения каждого состязания. Это сетка, которую показывает вид Все столы в Direction. Столы сгруппированы по залам, если в мероприятии есть залы, и подписаны названием, если оно у них есть.tables --rencontre N|--tournament N [--format text|json]— Свойства столов (название, зал, зарезервирован, закреплён за) и залы, где играет каждое состязание мероприятия (--rencontre), либо свойства состязания, которое играет отдельно (--tournament). Только чтение: запись идёт черезcall(rencontres.setTables,rencontres.setEventRooms,directions.setTables).
Общие параметры: --db (обязательно), --id (обязательно, кроме list, page --rencontre hall и tables), --format.
Примеры:
./blunderdb tournament list --db base.db
./blunderdb tournament verify --db base.db --id 3
./blunderdb tournament standings --db base.db --id 3 > classement.csv
./blunderdb tournament ranking --db base.db --season --from 2026-01-01 --to 2026-12-31 --elo > saison.csv
./blunderdb tournament page --db base.db --id 3 --out /tmp/affichage
./blunderdb tournament page --db base.db --rencontre 1 --out /tmp/evenement
./blunderdb tournament export --db base.db --id 3 > journal.json
./blunderdb tournament move --db base.db --id 3 --match m4 --table 7
./blunderdb tournament hall --db base.db --rencontre 1
./blunderdb tournament tables --db base.db --rencontre 1
trash — Корзина
Что было удалено и чем это вернуть. Удаление остаётся удалением: сначала записывается JSON-снимок исчезающего, и больше ничто в базе не знает, что эта таблица существует — ни фильтр поиска, ни статистика, ни правило хранения.
./blunderdb trash <sous-commande> --db <chemin> [options]
Подкоманды:
list— Что лежит в корзине, от недавно удалённого к более старому.restore --id N— Возвращает запись N и убирает её из корзины.discard --id N— Удаляет запись N сразу, не восстанавливая её.empty [--older-than Д]— Очищает корзину или только то, что старше Д дней.delete --kind K --id N— Удаляет объект через корзину, чтобы действие можно было отменить.K— этоposition,collectionилиcomment.
Общие параметры: --db (обязательный), --kind, --limit (по умолчанию 50), --format (text или json).
Примечание
blunderdb delete по-прежнему удаляет без страховки: скрипт, удаляющий позицию, ожидает, что она исчезнет, а тихо оставленный снимок растил бы файл, роста которого никто не просил. Отмену сохраняет именно trash delete.
Восстановление позиции снова проходит через дедупликацию Зобриста: дубликат не создаётся никогда, но старый идентификатор не возвращается — исходной строки больше нет. Восстановленная позиция — та же позиция под новым номером.
Всё старше тридцати дней удаляет blunderdb vacuum — никогда не открытие базы.
Примеры:
# Supprimer une position en gardant l'annulation
./blunderdb trash delete --db base.db --kind position --id 412
# Voir la corbeille, puis remettre une entrée
./blunderdb trash list --db base.db
./blunderdb trash restore --db base.db --id 3
# Ne garder que ce qui a moins de trente jours
./blunderdb trash empty --db base.db --older-than 30
info — Метаданные базы данных
Отображает метаданные и статистику базы данных.
./blunderdb info --db <path> [--format <format>]
Параметры:
--db— База данных (обязательно).--format— Формат вывода:textилиjson(по умолчанию:text).
Примеры:
./blunderdb info --db base.db
# Database Information
# ==================================================
# Path: /home/jean/bg/base.db
#
# Metadata:
# Version: 2.20.0
# User: Jean
# Description: Matchs de tournoi 2025
# Date of Creation: 2026-09-06 02:43:51
#
# Statistics:
# Positions: 3859
# Analyses: 3855
# Matches: 11
# Games: 61
# Moves: 3766
--format json добавляет происхождение файла: issuance несёт водяной знак, если он есть, и идентичность издателя этой машины:
./blunderdb info --db base.db --format json
{
"issuance": {
"watermarked": false,
"issuerFingerprint": "1186-57FA-060C-9378",
"issuerName": "unger"
},
"metadata": {
"database_version": "2.20.0",
"dateOfCreation": "2026-09-06 02:43:51",
"description": "Matchs de tournoi 2025",
"user": "Jean"
},
"path": "/home/jean/bg/base.db",
"stats": {
"analysis_count": 3855,
"game_count": 61,
"match_count": 11,
"move_count": 3766,
"position_count": 3859
}
}
edit — Изменить метаданные
Изменяет имя пользователя, описание или пороги базы данных.
./blunderdb edit --db <path> [options]
Параметры:
--db— База данных (обязательно).--user— Новое имя пользователя.--description— Новое описание.--clear-user— Очистить имя пользователя.--clear-description— Очистить описание.--error-threshold— Порог ошибки, в миллипунктах: решение, стоящее не меньше этого, является ошибкой.--blunder-threshold— Порог бландера, в миллипунктах: ошибка, стоящая не меньше этого, является бландером.--format— Формат вывода:text(по умолчанию) илиjson({"changes": [...]}).
Требуется хотя бы одна опция изменения.
Примеры:
./blunderdb edit --db base.db --user "Marie" --description "Ma collection"
./blunderdb edit --db base.db --clear-description
./blunderdb edit --db base.db --error-threshold 20 --blunder-threshold 80
verify — Проверка целостности
Проверяет целостность базы данных и, при необходимости, сравнивает матч с исходным файлом.
./blunderdb verify --db <path> [--match <id>] [--mat <file.mat>]
Параметры:
--db— База данных (обязательно).--match— Идентификатор матча для проверки.--mat— Файл MAT для сравнения (используется с--match).--format— Формат вывода:text(по умолчанию) илиjson(статистика, потерянные строки, отклонение схемы и проверка матча, если она выполнялась).
Без опции --match команда отображает общую статистику базы. С --match она проверяет данные матча и может сравнить их с оригинальным исходным файлом.
Каждый запуск также проверяет ссылочную целостность: он считает осиротевшие строки — партии без матча, ходы без партии, анализы хода без хода, анализы без позиции, записи журнала повторений без колоды или без позиции — и выводит строку WARNING с итогом, если такие есть. Здоровая база отвечает Orphaned rows: none. Сироты могут остаться в базе, записанной версией, которая не применяла внешние ключи на каждом соединении, или до того, как журнал повторений обзавёлся своими; они не относятся ни к одному матчу и ни к одной колоде и лишь занимают место. Команда всё равно завершается с кодом 0.
Каждый запуск также сравнивает схему с эталонной DDL и перечисляет таблицы, столбцы и индексы, которых не хватает базе. При открытии базы недостающее добавляется, когда это возможно, а то, что добавить нельзя (как правило, индекс UNIQUE, который не удаётся перестроить из-за дублирующихся строк), лишь записывается в журнал: именно здесь этот разрыв становится видимым, и запрос, обращающийся к одному из этих элементов, завершается ошибкой, пока причина не устранена. Здоровая база отвечает Schema: matches the reference DDL. Как и сироты, расхождение схемы — это наблюдение, а не сбой: код выхода остаётся 0.
Каждый запуск наконец проверяет правила, которые заявляет текущая DDL, но которые SQLite не может добавить к уже существующей таблице: ограничения диапазона CHECK (кости от 0 до 6, куб и пипы неотрицательны, от 0 до 15 снятых шашек, оценка повторения от 1 до 4), хеш Zobrist, которого у строки никогда не должно недоставать, и единственность одного анализа на позицию. База, созданная начиная с версии схемы 2.18.0, применяет их; более старая может ещё содержать строки, которые новая база отвергла бы, — именно они здесь и подсчитываются, правило за правилом. Здоровая база отвечает Constraints: every row satisfies the current DDL. Ещё одна констатация: ничего не исправляется, а код возврата остаётся 0.
Каждый запуск наконец пересчитывает два денормализованных счётчика, match.game_count и game.move_count, по строкам, которые они якобы считают, и сообщает, сколько из них расходятся и насколько в худшем случае. Оба записываются один раз, при импорте, по тому, что содержал исходный файл, и именно они показываются в списке матчей и в виде партии: небольшое расхождение обычно означает импорт, пропустивший то, что не смог преобразовать. Ничего не переписывается — заменить счётчик тем, что сохранено, значило бы стереть как раз то расхождение, на которое стоит посмотреть. Здоровая база отвечает Counters: game_count and move_count agree with the rows.
Примеры:
./blunderdb verify --db base.db
./blunderdb verify --db base.db --match 1
./blunderdb verify --db base.db --match 1 --mat original.mat
Сделать из этого заслон. Код возврата равен 0, что бы команда ни нашла: вердикт несёт --format json, и скрипт должен сам прочитать счётчики.
{
"stats": {
"analysis_count": 3855,
"game_count": 61,
"match_count": 11,
"move_count": 3766,
"position_count": 3859
},
"orphans": {
"games_without_match": 0,
"moves_without_game": 0,
"move_analyses_without_move": 0,
"analyses_without_position": 0,
"reviews_without_deck": 0,
"reviews_without_position": 0
},
"orphan_total": 0,
"schema_drift": {
"missing_tables": null,
"missing_columns": null,
"missing_indexes": null
},
"schema_drift_count": 0,
"constraint_violations": [
{"name": "position.zobrist_hash NOT NULL", "count": 0},
{"name": "position.dice_1 BETWEEN 0 AND 6", "count": 0}
],
"constraint_violation_total": 0,
"counter_drift": {
"matches_with_wrong_game_count": 0,
"games_with_wrong_move_count": 53,
"worst_game_count_gap": 0,
"worst_move_count_gap": 2
},
"counter_drift_total": 53
}
Тревоги стоят три поля: orphan_total, schema_drift_count и constraint_violation_total. Ненулевые, они описывают базу, которую нужно чинить.
./blunderdb verify --db base.db --format json \
| jq -e '.orphan_total == 0 and .schema_drift_count == 0 and .constraint_violation_total == 0'
counter_drift_total в их число не входит, и пример выше это показывает: база, его выдавшая, была только что импортирована и уже показывает 53 партии, где счётчик ходов расходится с тем, что содержат строки. Эти счётчики приходят из исходного файла, а не из базы; расхождение рассказывает об импорте, а не сигнализирует о повреждении. Смотрите на него, но не делайте из него порога.
vacuum — Сжатие базы данных
Возвращает место на диске, оставшееся после удалений (матчей, турниров, чисток): SQLite сам никогда не уменьшает файл при удалении данных, его нужно попросить явно. Это единственный способ запустить сжатие — при открытии базы оно не происходит автоматически никогда, поскольку на большой базе его стоимость непредсказуема.
./blunderdb vacuum --db <path>
Параметры:
--db— База данных (обязательно).--format— Формат вывода:text(по умолчанию) илиjson({"size_before", "size_after", "reclaimed"}, в байтах).
Команда начинает с wal_checkpoint(TRUNCATE), чтобы показанный до сжатия размер был честным, проверяет, что на диске остаётся примерно вдвое больше текущего размера файла (SQLite полностью перестраивает базу, прежде чем переключиться на неё), выполняет VACUUM, а затем ANALYZE, чтобы обновить статистику, которой пользуется планировщик запросов. Если места на диске не хватает, команда отказывается стартовать с внятным сообщением, вместо того чтобы рисковать прерванным сжатием.
Пример:
./blunderdb vacuum --db base.db
# Compacting database...
# Before: 128.4 MiB
# After: 41.2 MiB
# Reclaimed: 87.2 MiB
repair — Пересчитать то, что выведено
Пересчитывает то, что база выводит из того, что хранит: скалярные столбцы каждого анализа из самого анализа, проекцией которого они только и являются; фазу и тип игры каждой позиции из её доски; и признак Крофорда каждого счёта из матча, откуда позиция взята, или из XGID, с которым она пришла. Сами анализы не трогаются: переделываются значения, которые из них были выведены.
./blunderdb repair --db <path>
Параметры:
--db— База данных (обязательно).--format— Формат вывода:text(по умолчанию) илиjson— по одному счётчику на проход:repaired(столбцы анализа),phases(переклассифицированные позиции) иcrawford(позиции с пересчитанным хешем). Каждый показывает число реально изменённых строк.
Полезна после исправления того, как читается импортированный анализ. Это уже случалось дважды. Импортёр XG пишет «без удвоения» двумя способами, и второй понимался как настоящее удвоение — столбец нёс тогда ошибку удвоения, которого никогда не было. А анализ, вычисленный самим blunderDB, не знал, какой ход был сыгран, так что матч, импортированный без анализа, сохранял всюду нулевую ошибку и PR 0,00; теперь столбец пересчитывается по ходам матча. Исправление чтения ничего не меняет в уже записанных строках; эта команда их переделывает.
Проход Крофорда, в отличие от прочих, трогает сами позиции. Счёт 1 означает «остался один пункт, и эта партия И ЕСТЬ партия Крофорда»; 0 означает «остался один пункт, партия Крофорда позади». Пока импортёры не записывали это различие, всякая позиция после Крофорда сохранялась как крофордовская и потому читалась с мёртвым кубом — там, где отстающий на деле удваивает при первой же возможности. Исправление счёта меняет хеш позиции: строка поэтому перехешируется и сливается со своим правильным двойником, если база уже держит такой, — анализ, комментарии, подборки, карточки Anki и их журнал повторений, ходы матча и записи корзины, которые на неё ссылаются, следуют за выжившей строкой. Позиция, на которую не указывает ни один матч, исправляется только по слову XGID, который она принесла из другой программы (XG, BGBlitz…): когда поле Крофорда этого XGID говорит, что партия — не партия Крофорда, и этот XGID действительно описывает эту позицию. В обратную сторону позиция без матча, сохранённая со счётом 0 у обеих сторон, переходит на 1, когда принесённый ею XGID — это XGID матча до 1 пункта и он её описывает: единственная партия матча до 1 пункта начинается в одном пункте от цели, значит, это партия Крофорда, как и пишут импортёры. DMP после партии Крофорда в более длинном матче остаётся на 0: его XGID указывает длину этого матча. XGID, который blunderDB сам переписал, лишь повторяет сохранённый счёт и ничего не доказывает. Любая другая позиция без матча остаётся как есть: ничто не противоречит тому, что объявляет её счёт.
Ничто не запускает её автоматически, и это намеренно: переписывать столбцы анализа у всех или перехешировать позиции при одном лишь открытии базы — не то, что инструмент должен делать за спиной пользователя.
Пример:
./blunderdb repair --db base.db
# 42 analyses repaired.
# 7 positions reclassified.
# 3 positions rehashed onto the right Crawford sentinel.
delete — Удалить данные
Удаляет матч и все связанные данные (партии, ходы, анализы).
./blunderdb delete --db <path> --type match --id <id> [--confirm]
Параметры:
--db— База данных (обязательно).--type— Тип удаления:match(обязательно).--id— Идентификатор элемента для удаления (обязательно).--confirm— Удалить без запроса подтверждения.--format— Формат вывода:text(по умолчанию) илиjson({"match_id": N, "deleted": true}).
Примеры:
# Confirmation interactive, puis sans confirmation (scripts)
./blunderdb delete --db base.db --type match --id 1
./blunderdb delete --db base.db --type match --id 1 --confirm
healthcheck — Проверка демона
Спрашивает у работающего демона serve (см. Безголовый режим (сервер)), готов ли он: один запрос GET /readyz, код возврата 0, если демон отвечает 200 (хранилище доступно, схема ожидаемой версии), иначе 1 — хранилище недоступно, схема устарела или по адресу никто не слушает. Файл базы данных не открывается.
./blunderdb healthcheck [--addr host:port] [--timeout 2s]
Параметры:
--addr— Адрес, который слушает демон (по умолчаниюBLUNDERDB_ADDR, иначе:8080). Адрес без хоста (:8080) или с обобщённым хостом (0.0.0.0,[::]) проверяется через петлевой интерфейс.--timeout— Время, по истечении которого проверка прекращается (по умолчанию2s).
Это команда, которую выполняет HEALTHCHECK образа контейнера (образ distroless, без curl); двоичный файл serve, собранный из cmd/serve, тоже её понимает. Она так же пригодна для скрипта или юнита systemd.
Пример:
./blunderdb serve --db base.db --addr 127.0.0.1:8080 &
./blunderdb healthcheck --addr 127.0.0.1:8080 && echo "démon disponible"
# ready
При неудаче выводится причина, которую docker inspect показывает для контейнера в состоянии unhealthy:
Error: healthcheck: http://127.0.0.1:8080/readyz answered 503 Service Unavailable (version_mismatch)
mcp — Предоставить базу ИИ-ассистенту
Предоставляет инструменты базы ИИ-ассистенту через Model Context Protocol по стандартному вводу и выводу: команду запускает сам ассистент. Инструменты ищут позиции в грамматике командной строки, читают позицию и её анализ, объясняют ошибку, вычисляют статистику игрока, перечисляют матчи, турниры и коллекции и задают вопрос викторины. Они только читают, кроме случая --write. Полный список и HTTP-эквивалент демона: Инструменты для ИИ-ассистента (MCP).
./blunderdb mcp --db base.db [--write]
Параметры:
--db— Файл базы данных (обязательно).--write— Предоставляет также инструменты, которые пишут: сохранить позицию, прокомментировать её, создать и наполнить коллекцию. Ничего не удаляется.
Как и call, команда при открытии переносит схему старой базы, даже без --write.
Пример: объявить базу в Claude Code.
claude mcp add blunderdb -- blunderdb mcp --db /chemin/vers/base.db
completion — Автодополнение оболочки
Выводит на стандартный вывод скрипт автодополнения для имён подкоманд. Список команд, встроенный в каждый скрипт, формируется из той же таблицы, которую читают blunderdb help и диспетчеризация в main.go (handlers()): новая подкоманда предлагается автодополнением сразу после подключения, и ничего не нужно поддерживать вручную.
./blunderdb completion <bash|zsh|fish>
Примеры:
# bash
source <(blunderdb completion bash)
blunderdb completion bash | sudo tee /etc/bash_completion.d/blunderdb > /dev/null
# zsh : un répertoire déjà sur $fpath
blunderdb completion zsh > "${fpath[1]}/_blunderdb"
# fish
blunderdb completion fish | source
Пакеты устанавливают это автоматически: .deb/.rpm (nfpm) и пакет AUR генерируют три скрипта из собранного двоичного файла во время сборки, а cask Homebrew один раз запускает blunderdb completion <shell> при установке через generate_completions_from_executable. Ничего не фиксируется в репозитории, поэтому автодополнение никогда не может разойтись с таблицей подкоманд.
version — Показать версию
Выводит версию blunderDB и версию схемы базы данных, которую записывает этот бинарный файл; это первое, что нужно приложить к отчёту об ошибке.
./blunderdb version
# blunderDB version 0.36.0 (database schema 2.20.0)
Примеры рабочих процессов
Импорт каталога турнира
./blunderdb create --db tournoi_paris.db --user "Jean" --description "Open de Paris 2025"
./blunderdb import --db tournoi_paris.db --type batch --dir ./matchs_open_paris/
./blunderdb list --db tournoi_paris.db --type stats
Регулярное резервное копирование
./blunderdb export --db production.db --type database --file sauvegarde-$(date +%Y%m%d).db
Анализ ошибок
# Les positions délicates, puis celles de videau
./blunderdb search --db production.db --error-min 0.1 --export blunders.db
./blunderdb search --db production.db --decision cube --error-min 0.05 --export cube_errors.db
# Les coups réellement fautifs : au moins 100 millièmes d'équité perdus
./blunderdb search --db production.db --move-error-min 100 --format json
Коды возврата
0— Успех.1— Ошибка.
Это позволяет использовать CLI в скриптах с обработкой ошибок:
if ./blunderdb import --db base.db --type match --file match.xg; then
echo "OK"
else
echo "KO"
exit 1
fi