8.1 KiB
Записка-план: бэкенд-пак «входная дверь шва» (движковая половина D39.156)
Сессия бэкенда, 24.08.2026. Промт — docs/BACKEND_SEAM_PACK_SESSION_PROMPT.md.
Доказательная база и посадки — backend/docs/SEAM_PACK_FINDINGS.md (пишется по ходу).
0. Точка отсчёта, снятая ИСПОЛНЕНИЕМ (до правок)
| факт | команда |
|---|---|
go build ./... · go vet ./... · go test ./... -count=1 — зелены |
из backend/ |
стенд-батарея с переопределениями: красен ровно TestMinerFullBookParity, причина — отсутствующий eval/exp16/data/jieba_dict_general_zh.txt |
TM_MINER_PARITY=1 TM_CHECKER_LABELS=1 TM_CHECKER_LABELS_DIR=<repo>/books/gu-zhenren/labels TM_MINER_PARITY_RECORDS=<repo>/books/gu-zhenren/rerun/records.json TM_MINER_PARITY_SEED=<repo>/books/gu-zhenren/guzhenren-seed-v2.yaml go test ./... -count=1 |
рабочее дерево backend/ чистое; незакоммиченная чужая работа — только в eval/ |
git status --porcelain |
1. Комплектность против §4 промта (сверка МЕХАНИЧЕСКАЯ)
| § | заказ | форма, которую я выбрал | где |
|---|---|---|---|
| 4.1 | дефолты пустых ключей mined_delta/mined_rejects по конвенции каталога книги |
<dir книги>/<book_id>.mined-delta.yaml и <book_id>.mined-rejects.yaml; дефолт ТОЛЬКО на пустом ключе; отсутствующий дефолтный файл = «решений нет» |
internal/config/book.go, internal/pipeline/mining.go |
| 4.2 | $0-глагол приёма правок банка | tmctl bank-apply --config <book.yaml> --decisions <decisions.json> [--dry-run] |
internal/membank/decisions.go (чистая логика), internal/pipeline/bankdecisions.go (обвязка), cmd/tmctl/bankapply.go |
| 4.3 | путь к файлу ключей аргументом | --keys-file <path> ТОЛЬКО у translate; грузится ПЕРВЫМ; названный и нечитаемый = отказ конфигом (10) |
cmd/tmctl/invocation.go, cmd/tmctl/dotenv.go, cmd/tmctl/main.go |
| 4.4 | строгость загрузчика сида + тест на unknown-key | strict-декодер схемы в internal/seed (seed.DecodeFile), им же читается reject-файл |
internal/seed/decode.go, internal/membank/memseed.go, internal/pipeline/mining.go |
| 4.5 | путь артефакта и версия документа в status --json |
status_version + аддитивный объект artifacts{project_db,bank_export} (абсолютные пути) |
internal/pipeline/status.go |
| 4.6 | дефолт стендового корпуса в трёх тест-хелперах | маркерный резолв корня репозитория (repoFile), корпус — <repo>/books |
internal/miner/miner_parity_test.go, internal/checks/labelharness_test.go, internal/membank/labelharness_test.go |
| 4.7 | платных вызовов ноль | глагол $0 по построению; --keys-file — юнит-тесты + фейковые ключи |
— |
2. Порядок работ
- §4.6 (дешёвая, независимая) → стенд-батарея зеленеет без переопределений.
- §4.4 строгость схемы — она нужна ДО глагола: глагол читает и пишет те же файлы, и нестрогий читатель обесценил бы строгого писателя.
- §4.1 дефолты путей — без них глаголу некуда писать на книге, которая ключей не объявляла.
- §4.2 глагол (основной кусок).
- §4.3
--keys-file. - §4.5 версия и пути артефактов в
status --json. - Адверсариальные посадки, живая проба на копии стендовой книги, отчёт.
3. Развилки, которые я вижу, и как решаю
(а) Имена дефолтных файлов — каталог книги или сайдкар при базе?
Все банк-сайдкары движка висят на project_db (.bank.json, .auto-bank.yaml, .mined-signature.yaml).
Беру всё-таки КАТАЛОГ КНИГИ с префиксом book_id, ровно как project_db по умолчанию:
project_db может указывать КУДА УГОДНО (в т.ч. за пределы каталога книги), а решения пользователя —
это его данные, они обязаны ехать с книгой в бэкапе и экспорте каталога. Префикс book_id повторяет
механизм <book_id>.db и не даёт двум книгам в одном каталоге столкнуться.
(б) Форма проекции до мутации. --dry-run, прецедент — redrive --dry-run и строка 124(в)
(resnapshot --dry-run поименован там дословно). Проекция получается БЕЗ мутации: с флагом не
пишется ни один байт.
(в) Код выхода для отвергнутого набора решений. Занятый лок — ровно 12 (заказано). Для
отвергнутых решений НЕ завожу новый номер полосы: беру 10 (config_invalid). Довод по оси, которая
у D39.134 несущая, — КТО ДЕЙСТВУЕТ: при 12 действует время («подожди и повтори»), при 10 действует
человек. Набор решений, конфликтующий с подписанной строкой сида, чинит человек, а не время.
Отчёт при этом печатается в stdout ВСЕГДА и называет каждый отказ поимённо (прецедент: status --json
печатает отчёт и выходит 2).
(г) Словарь входа глагола. Ровно словарь УЖЕ публикуемой поверхности банк-экспорта
(id/src/dst/kind/sense/since_chapter/until_chapter/aliases) плюс note. Поля, которого
движок не публикует, во входе нет — в частности gender (строка 210: ось мертва в производителях);
строить «на вырост» запрещено §4.3.
(д) Канонизация файла. Глагол — единственный писатель своей схемы, поэтому при изменении файл
пере-рендерится целиком из разобранной схемы (комментарии оператора не переживают первую правку).
Это ВИДНО до мутации: проекция несёт canonical_rewrite. Порядок термов сохраняется (замена — на
месте, добавление — в хвост), чтобы правка не выглядела как переписывание всего файла.
(е) Что я НЕ делаю и почему. Не проектирую «глубину до черновика» (§4.2, прямое слово владельца):
правка едет через mined_delta до РЕДАКТОРСКОЙ волны, и ответ глагола говорит это явным полем
depth: edit_wave. Не трогаю redrive флагом ключей (промт: «флаг только у translate») — наблюдение
о том, что redrive тоже платный путь, уходит ПИНГОМ, а не тихой правкой.