Final documentation pass in the backend zone: keep what a session needs to work, drop the account of how we got there, and correct the stale claims about code

This commit is contained in:
heaven 2026-09-02 19:39:04 +03:00
parent bab0ee3961
commit 5c5fdc7b4a
8 changed files with 104 additions and 184 deletions

View file

@ -8,7 +8,7 @@
| Пакет | Что делает | Ключевые файлы |
|---|---|---|
| `cmd/tmctl` | CLI: `translate` / `status` (read-only N/M+паспорта глав+деньги, `--json`; работает ПРИ живом прогоне — store без flock) / `report` (request-log+леджер книги **+ per-run quality-report**: структурный KPI предл./нарратив-абзац, тире, cosmetic-strip/echo-rates, глоссарий-промахи, trust-gated — наблюдаемость, НЕ гейт; D39.2-T4) / `export` (**экспорт-поверхность для полигона**: final_hash→checkpoint→checks.ExportNormalize, manifest-join c pending/ghost-учётом, ConfigDrift-поле, `--plaintext`; D39.5) / `build` (**писатель книги**: EPUB 3 + чистый txt из той же экспорт-проекции в `<project_db>.book.<fmt>` рядом с БД, пути — в `artifacts.book_files`; книга с ЛЮБОЙ дырой — pending/withheld/incomplete/ghost — по умолчанию отказ **exit 16** с перечнем, `--partial` пишет с пометкой на первой странице и маркером на каждой дыре; слова читателя — данные `configs/langpacks/<цель>/reader.txt`, вне снапшота; `--format epub,txt`, `--out`) / `redrive` (переатака флагнутых: `--chapter/--chunk/--reason/--dry-run`, D15.3) / `manifest` (**$0-производитель персиста манифеста глав/чанков**: нужен ДО первого прогона — дерево глав разобранной, но не запущенной книги) / `migrate` (**$0-write-open без прогона** (D39.134): read-only команды схему НЕ мигрируют. Грузит ТОЛЬКО `book.yaml` — ни цен, ни ключей на $0-пути (строка 146); restore point берёт ПОД ЛОКОМ и только когда шаг реально применяется (имя `<метка>-pre-migrate.db` — вне секундного неймспейса платного пути, строка 173); несовпадение схемы у read-only путей — типизированный отказ **exit 13** с машинным токеном `schema_mismatch found=N expected=M`). **ДВА потолка прогона, и они ортогональны.** `--ceiling-usd` — ДЕНЬГИ: перекрывает книжный `ceilings.book_usd` ТОЛЬКО на этот прогон, в book.yaml не пишется, ноль/отрицательное = отказ запуска; каппит КУМУЛЯТИВНУЮ трату книги, а не приращение прогона. `--max-units` (D39.165 §1б; механика и денежный отчёт — D39.170) — ОБЪЁМ: не больше N ВЫХОДНЫХ ЮНИТОВ (гранулярность `units_total` манифеста, та самая, в которой платформа продаёт главы) будет ОПЛАЧЕНО этим прогоном. $0-юниты (резюм, ре-пин) потолок не тратят. Принимает только `translate`. **Остановка по объёму — ЗАВЕРШЕНИЕ (exit 0), а не пауза:** различение живёт в отчёте прогона и в логе. ⚠ На книге, которая МАЙНИТ банк, вторая покупка требует `--resnapshot` (авто-банк растёт между покупками и двигает edit-снапшот) — прогон предупреждает об этом в логе. main — тонкая обвязка: разбор/exit-коды/.env/рендеры в тестируемых функциях | `main.go`, `invocation.go`, `render.go`, `dotenv.go` |
| `cmd/tmctl` | CLI: `translate` / `status` (read-only N/M+паспорта глав+деньги, `--json`; работает ПРИ живом прогоне — store без flock) / `report` (request-log+леджер книги **+ per-run quality-report**: структурный KPI предл./нарратив-абзац, тире, cosmetic-strip/echo-rates, глоссарий-промахи, trust-gated — наблюдаемость, НЕ гейт; D39.2-T4) / `export` (**экспорт-поверхность для полигона**: final_hash→checkpoint→checks.ExportNormalize, manifest-join c pending/ghost-учётом, ConfigDrift-поле, `--plaintext`; D39.5) / `build` (**писатель книги**: EPUB 3 + чистый txt из той же экспорт-проекции в `<project_db>.book.<fmt>` рядом с БД, пути — в `artifacts.book_files`; книга с ЛЮБОЙ дырой — pending/withheld/incomplete/ghost — по умолчанию отказ **exit 16** с перечнем, `--partial` пишет с пометкой на первой странице и маркером на каждой дыре; слова читателя — данные `configs/langpacks/<цель>/reader.txt`, вне снапшота; `--format epub,txt`, `--out`) / `redrive` (переатака флагнутых: `--chapter/--chunk/--reason/--dry-run`, D15.3) / `manifest` (**$0-производитель персиста манифеста глав/чанков**: нужен ДО первого прогона — дерево глав разобранной, но не запущенной книги) / `migrate` (**$0-write-open без прогона** (D39.134): read-only команды схему НЕ мигрируют. Грузит ТОЛЬКО `book.yaml` — ни цен, ни ключей на $0-пути (строка 146); restore point берёт ПОД ЛОКОМ и только когда шаг реально применяется (имя `<метка>-pre-migrate.db` — вне секундного неймспейса платного пути, строка 173); несовпадение схемы у read-only путей — типизированный отказ **exit 13** с машинным токеном `schema_mismatch found=N expected=M`) / `bank-apply` (**входная дверь шва**, D39.156/D39.158: приём документа решений владельца по банку, $0; отчёт v2 на stdout, отказ по существу — **exit 14**, незавершённая запись — **exit 15**) / `backup` (`VACUUM INTO` + `integrity_check`, он же pre-flight боевого прогона) / `seed-lint` ($0-проверка сида и дельты владельца). **ДВА потолка прогона, и они ортогональны.** `--ceiling-usd` — ДЕНЬГИ: перекрывает книжный `ceilings.book_usd` ТОЛЬКО на этот прогон, в book.yaml не пишется, ноль/отрицательное = отказ запуска; каппит КУМУЛЯТИВНУЮ трату книги, а не приращение прогона. `--max-units` (D39.165 §1б; механика и денежный отчёт — D39.170) — ОБЪЁМ: не больше N ВЫХОДНЫХ ЮНИТОВ (гранулярность `units_total` манифеста, та самая, в которой платформа продаёт главы) будет ОПЛАЧЕНО этим прогоном. $0-юниты (резюм, ре-пин) потолок не тратят. Принимает только `translate`. **Остановка по объёму — ЗАВЕРШЕНИЕ (exit 0), а не пауза:** различение живёт в отчёте прогона и в логе. ⚠ На книге, которая МАЙНИТ банк, вторая покупка требует `--resnapshot` (авто-банк растёт между покупками и двигает edit-снапшот) — прогон предупреждает об этом в логе. main — тонкая обвязка: разбор/exit-коды/.env/рендеры в тестируемых функциях (полный перечень глаголов — `dispatchCommands` в `cmd/tmctl/main.go`) | `main.go`, `invocation.go`, `render.go`, `dotenv.go`, `bankapply.go`, `backup.go` |
| `internal/llm` | OpenAI-совместимый транспорт + retry/backoff, **capability-слой** (budget_field/temperature/reasoning per-модель), провайдеры openai/local (no-proxy)/anthropic (DEPRECATED-референс); маршрутизация лейблами живёт в config/pipeline (канал B, один хоп `chain[0]`, fail-closed; D4/D39.26) | `httpllm.go`, `capability.go`, `provider_*.go` |
| `internal/ledger` | Цены по usage (вкл. reasoning/cache-поля), `PriceForResponse` по фактической модели | `pricing.go` |
| `internal/store` | SQLite (modernc, CGO-free), цепочка миграций `schema_version`, reserve/settle+checkpoint, chunk_status, глоссарий (+подписной цикл терминолога), ruby, retrieval_state, request_log; `OpenReadOnly` — без flock/миграций/recovery для status/report/export (схема не совпала — типизированный `*store.SchemaMismatchError{Found,Expected}`, обе стороны); `Migrate` (+шов `beforeApply` под локом), `SchemaHead` — та самая `Expected`; write-open БД новее бинаря — ОТКАЗ (D39.134) | `ledger.go`, `migrate.go`, `glossary.go`, `store.go` |
@ -21,7 +21,10 @@
| `internal/membank` | Банк памяти v2, memmatch-v4: Aho-Corasick, спойлер-окна, disposition, **trust-gated longest-match** (draft-длиннее НЕ съедает вложенный approved; отказ = громкая телеметрия — терм-дрейф закрыт в КОДЕ, D39.2-T1), post-check, рендереры инъекции, загрузка/валидация сида (`SeedLint`) | `memory.go`, `memseed.go`, `mempostcheck.go` |
| `internal/miner` | Детерминированный оффлайн-майнер банка (WS3, $0): `MineBank` над нормализованными чанками + контраст-корпус → `[]Term`, `DeltaYAML` — сид-дельта на подпись владельца; все пар-данные приходят `*lang.Pack` | `miner.go`, `miner_*.go` |
| `internal/checks` | Детерминированные $0-вердикты над текстом чанка, **target-aware ПО ДАННЫМ (D39.64): `Checkers` компилируется из цель-данных, `TargetActive()`/`TargetScriptNonLatin()` гейтят всё — цель без данных инертна, Go-веток по паре нет**: санитайзер v7 (fold-first, CJK/Hangul-leak, CJK-глосс-whitelist) + `ExportNormalize` (**export-contract слой 6**, no-op без цель-данных), cheap-гейты и DC-чекеры (пар-данные из пака), coverage-гейт эксцизии, regression-guard. Флаг-вокабуляр НЕ импортирует: возвращает факт, диспозицию назначает драйвер | `sanitizer.go`, `cheapgates.go`, `checkers.go`, `coverage.go` |
| `internal/pipeline` | Композит-корень (драйвер): сетап `runner.go` → снапшот `snapshot.go` → сид `seeding.go` → цикл книги `bookrun.go` → волны `waverun.go` → петля чанка `chunkrun.go` → стадия `stagerun.go` → эскалация с ре-гейтом `escalation.go` → resume `resume.go`; classify/disposition; **реестр `roleInjectionRenderers`** (новая роль = данные+рендерер, не правка switch); `export.go`/`quality.go`/`status.go` — read-only проекции (общая derivation member-drop = `memberDrops`); **read-out файлы для платформы** (D39.85 — приватный SQLite движка ей закрыт): `manifest.go` (структура глав/чанков + стабильный id главы, строка 100), `bankexport.go` (весь банк тремя статусами, 125); оба пишутся через `artifact.go` (write-then-rename — их читают ПОКА идёт прогон) | `bookrun.go`, `waverun.go`, `stagerun.go`, `export.go`, `manifest.go`, `disposition.go` |
| `internal/pipeline` | Композит-корень (драйвер): сетап `runner.go` → снапшот `snapshot.go` → сид `seeding.go` → цикл книги `bookrun.go` → волны `waverun.go` → петля чанка `chunkrun.go` → стадия `stagerun.go` → эскалация с ре-гейтом `escalation.go` → resume `resume.go`; classify/disposition; **реестр `roleInjectionRenderers`** (новая роль = данные+рендерер, не правка switch); `export.go`/`quality.go`/`status.go` — read-only проекции (общая derivation member-drop = `memberDrops`); **read-out файлы для платформы** (D39.85 — приватный SQLite движка ей закрыт): `manifest.go` (структура глав/чанков + стабильный id главы, строка 100), `bankexport.go` (весь банк тремя статусами, 125); вместе с картой подписи и авто-банком в `mining.go` (`signatureMapPath` · `autoBankPath`) — все ЧЕТЫРЕ пишутся через `artifact.go` (write-then-rename — их читают ПОКА идёт прогон); человеческая стоп-таблица `.bank-stop.txt` — обычным `os.WriteFile`, БЕЗ этой гарантии, а машинной `.bank-stop.json` больше нет (снесена D39.158) | `bookrun.go`, `waverun.go`, `stagerun.go`, `export.go`, `manifest.go`, `disposition.go` |
| `internal/bookfile` | Писатель книги: EPUB 3 (контейнер/OPF/навигация) и чистый txt из экспорт-проекции; формат знает только он, `tmctl build` даёт ему данные | `epub.go`, `txt.go`, `container.go`, `model.go` |
| `internal/runevents` | ДВИЖКОВАЯ сторона шва кадров прогона (строка 103): конверт и payload'ы NDJSON-потока `events.jsonl` + append-only журнал; словарь исходов `finished`. Форма — здесь, КОГДА событие случилось — у драйвера, долговечная нумерация — у `store.events_outbox` | `runevents.go`, `journal.go` |
| `internal/standdata` | Резолв путей корпусных данных ОТ КОРНЯ РЕПОЗИТОРИЯ по маркеру (`<репозиторий>/books`, D39.157 п.2); `$HOME` не читается вовсе, env-переопределения `TM_*` старше дефолтов | `standdata.go` |
| `internal/obs` | trace_id, структурные логи (contextHandler несёт book/chapter/chunk/stage/role из ctx), safego | |
## Инварианты — ЛОМАТЬ НЕЛЬЗЯ (каждый закреплён тестами)
@ -37,14 +40,14 @@
## Подготовка ja-книги (чек-лист сида)
- **Kana-написания имён = matchable.** Ruby-чтения захватываются на инжесте и авто-подцепляются как alias ручной записи (D16.4, `attachRubyAliasesToManual`). Имя, встречающееся ТОЛЬКО каной, внеси в `aliases:` руками — иначе «тихо пусто».
- **Kana-написания имён = matchable.** Ruby-чтения захватываются на инжесте и авто-подцепляются как alias ручной записи (D16.4, `membank.AttachRubyAliasesToManual`). Имя, встречающееся ТОЛЬКО каной, внеси в `aliases:` руками — иначе «тихо пусто».
- **Двойные чтения (強敵→とも) — под флагом:** длинное двойное чтение может дать CONFIRMED-ложь — при подозрении убери из сида. Полная дизамбигуация — Ф2 (B6).
- **Kana-precision ≥4 не замерена** (minKeyLenPhonetic=3): кана-ключи не проверяются на границу слова (нет сегментации) — задача полигона + токенизатор B6.
- ⚠ **ja-книга требует каталога `prompts/ja-ru/` (по файлу на роль)** — промпт-резолв конвенцией fail-loud'ится без него, называя ожидаемый путь (пример: закомментированный ja-блок в `example/book.yaml`). Контент пакета = данные под реальную книгу (инвариант общности §0.1), не сочинять.
## Как гонять
Стенд: WSL2 (localhost из-под прокси = 403 — для local-вызовов no-proxy транспорт). Книга-стенд: `/home/ubuntu/books/gu-zhenren/` (GB18030; тексты и производные ВНЕ git).
Стенд: WSL2 (localhost из-под прокси = 403 — для local-вызовов no-proxy транспорт). Книга-стенд: `<репозиторий>/books/gu-zhenren/` (адрес по D39.157 п.2; GB18030; тексты и производные версионируются ОТДЕЛЬНЫМ git-репозиторием).
Батарея — ОДНА команда, `make` из `backend/` (Makefile):
@ -76,10 +79,10 @@ set -a; . ./.env; set +a; TM_LIVE=1 go test -tags live -run TestLive -v ./intern
| Что тёмное без данных | Флаг | Данные |
|---|---|---|
| `TestMinerFullBookParity` — единственная сверка Go-порта против Python-эталона на полной книге | `TM_MINER_PARITY=1` | jieba-словарь по внутрирепозиторному ПУТИ `eval/exp16/data/`, но ВНЕ git (`eval/.gitignore:4`) — клон его не получает, регенерируется из jieba 0.42.1 (SHA в `experiments/16-bank-mining.md:183`); плюс `~/books/gu-zhenren/{rerun/records.json, guzhenren-seed-v2.yaml}` |
| `TestCheckerLabelsBaseline`, `TestCheckerLabelsCandidates`, `TestK6LabelsBaseline` — единственный замер precision/recall $0-гейтов | `TM_CHECKER_LABELS=1` | `~/books/gu-zhenren/labels/` |
| `TestMinerFullBookParity` — единственная сверка Go-порта против Python-эталона на полной книге | `TM_MINER_PARITY=1` | jieba-словарь по внутрирепозиторному ПУТИ `eval/exp16/data/`, но ВНЕ git (`eval/.gitignore:4`) — клон его не получает, регенерируется из jieba 0.42.1 (SHA в `experiments/16-bank-mining.md:183`); плюс `<репозиторий>/books/gu-zhenren/{rerun/records.json, guzhenren-seed-v2.yaml}` |
| `TestCheckerLabelsBaseline`, `TestCheckerLabelsCandidates`, `TestK6LabelsBaseline` — единственный замер precision/recall $0-гейтов | `TM_CHECKER_LABELS=1` | `<репозиторий>/books/gu-zhenren/labels/` |
Пути дефолтятся ОТ `$HOME` и от корня репозитория (не от `/home/ubuntu`), так что клон под любым пользователем и по любому пути находит то, что есть; точечные переопределения — `TM_CHECKER_LABELS_DIR`, `TM_MINER_PARITY_{CONTRAST,RECORDS,SEED}`.
Пути дефолтятся от КОРНЯ РЕПОЗИТОРИЯ, найденного по маркеру (`internal/standdata`; `$HOME` не читается вовсе — D39.157 п.2), так что клон под любым пользователем и по любому пути находит то, что есть; точечные переопределения — `TM_CHECKER_LABELS_DIR`, `TM_MINER_PARITY_{CONTRAST,RECORDS,SEED}`.
**Golden-гард детерминизма** (`golden_test.go` + `testdata/golden/`): пинит бит-в-бит snapshotID, request_hash, wire-тела, вердикты и resume-байты. Обновлять ТОЛЬКО на ратифицированной смене поведения: `TM_UPDATE_GOLDEN=1 go test ./internal/pipeline/ -run TestGolden`; при re-capture — **маскированный структурный дифф** (хеши/версии → плейсхолдер) обязан быть пустым, если смена версий не меняла вердиктов.
@ -90,4 +93,4 @@ set -a; . ./.env; set +a; TM_LIVE=1 go test -tags live -run TestLive -v ./intern
- ⚠ ALTER-шаги миграций v8+ НЕ идемпотентны вопреки шапке `migrate.go` — полу-применённая БД не сходится (строка 49а).
- Открытый остаток строки 79 — граница ПЛОТНОСТИ письма Go-константой `cjkScriptNames` (`internal/lang/script.go`).
- `prompts/zh-ru/editor-mono.md` — DORMANT-референс D13.1 (не боевой, тестом закреплён); боевой = `prompts/zh-ru/editor.md` v3-discourse (БИЛИНГВ). Глосс-капы санитайзера (6 CJK / 24 лат-токен) — tunable-эвристики (D39.5). Флоры min_max_tokens = схема (D24.3).
- Хвост LOW/NOTE-находок адверсариала D39.4 — в ledger-очереди (строка 53).
- Хвост LOW/NOTE-находок адверсариала D39.4 (14 LOW + 14 NOTE) — диспозиция **«не чинить»**, носитель D39.4/D39.5, текст — `docs/archive/reports/SMALLPACK_TAILS_2026-08-02.md` (греп `D39.4 ledger-очередь`); живые пересечения — строки 43/78. ⚠ Прежний указатель на строку 53 мёртв: она закрыта D39.82 (`putUniqueDC`).

View file

@ -22,6 +22,12 @@ re-classify-ить на resume бесплатно); ответы на три в
на `stagerun.go` / `chunkrun.go` / `escalation.go` / `bookrun.go` / `resume.go` / `status.go`; актуальные
локации — в §12-плане и по grep имени функции.
**ЭРРАТА (сверено исполнением 02.09; тело §11/§12 по норме не переписывается).** С момента письма
голова схемы уехала **v7 → v16** (`backend/internal/store/migrate.go:441=the bank-stop memory`,
`SchemaHead() = len(migrations)`), и номер **v8 занят чужой миграцией**: при реализации §11/§12 брать
СЛЕДУЮЩИЙ свободный (`store.SchemaHead()+1`), а не v8 из текста. Якорь `render.go:212` мёртв — литерал
ключа лежит на `backend/internal/pipeline/render.go:306=w("tm-request-v2", req.BookID`.
**Гейтит:** онгоинг-режим (`add-chapters`, сегмент «ИИ-фабрик», Р9 / D15 п.2). Текущий
all-or-nothing resnapshot остаётся **приемлемым для статичной приёмочной книги Ф1 (D15.1 / D18 蛊真人)
НЕ трогать до приёмки**; эта спека — для онгоинга (Ф1.5).

View file

@ -237,6 +237,13 @@ number up; a class this build has never heard of still lands inside the band and
## 5. Корпус: все десять строк, разобранные законом
**ЧИТАТЬ КАК ДИАГНОЗ ДО ПРАВКИ, А НЕ КАК ОПИСАНИЕ СЕГОДНЯШНЕГО КОДА.** Все десять применены
(D39.181/D39.182), поэтому каждая фраза «**Делает:** …» ниже описывает состояние ДО лечения и сегодня
ложна как утверждение о коде; что стало — `MONEY_HONESTY_REPORT.md` §9 (по одному экземпляру, с
мутацией и её дословным выводом). Секция оставлена целиком по двум причинам: она и есть проверка
качества закона на корпусе (§0), и она несёт названные ЛОВУШКИ и опровержения, которые правки учли и
которые переоткрывать не надо.
Формат: **что движок ЗНАЕТ** (с якорем) → **какая статья нарушена****потребитель****канал**
**класс правки по ст. 3**.

View file

@ -533,28 +533,11 @@ was taken`). Посадка `TestTheContourDoesNotWeakenTheConsentGate`: мут
## 10. Изменённые файлы
| файл | что |
|---|---|
| `configs/pipeline-c1.yaml` + 4 (`c2`, три `arm-*`) | A1: `regenerate_echo_before_escalate: 1` + довод, замер и ОБА режима `escalation.budget_usd` |
| `internal/pipeline/snapshotdiff.go` | **НОВЫЙ** — A4: детерминированный диф полей payload'а + текст «что двинулось» |
| `internal/pipeline/driftbasis.go` | **НОВЫЙ** — A7+A12: словарь базиса и ОДНО определение правила осиротевшей стадии |
| `internal/pipeline/paidtail.go` | **НОВЫЙ** — A0: разложение денег по тому, что они купили |
| `internal/pipeline/stagerun.go` | A4: гард зовёт диф вместо утверждения причины |
| `internal/pipeline/status.go` | A7+A12: правило + базис; A10: контур банк-ролей в проекции |
| `internal/pipeline/export.go` | A7+A12: то же правило из общего определения + базис |
| `internal/pipeline/bookbuild.go` | A3(а)+(б): отчёт переживает сбой уборки; удалённый файл назван; `stale` слушает базис |
| `internal/pipeline/rebill.go` | A6: сверка контента при совпавшем снапшоте + дешёвый зонд; A10: контур в базе согласия |
| `internal/pipeline/terminologist.go` | A2: план режется ДО первого вызова; `BatchesDropped` в результате |
| `internal/pipeline/quality.go` | A0: публикация разложения в `report` |
| `internal/pipeline/events.go` | A11: `unitOnceKey` → пакетная функция; A5: леджер на кадре `finished` |
| `internal/pipeline/volume.go` | A11: ось доставки по анонс-леджеру + «текст ещё существует» |
| `internal/runevents/runevents.go` | A5: `VolumeLedger` на `Finished` (ратифицировано D39.181 п.2) |
| `internal/store/outbox.go` | A11: `AnnouncedOnceKeys()` — читающий метод строки 232 |
| `cmd/tmctl/render.go` | A7: строка дрейфа больше не утверждает пере-оплату; A12: базис вслух; A0: секция денег |
| 11 новых `*_test.go` + `testdata/prompt-labels.json` | 33 посадки |
| `internal/pipeline/bankfixpack_test.go` | ⚠ касание чужого теста — ПРЕДПОСЫЛКА, разбор §9.10 |
| `backend/docs/*.md` (3) | записка-план, дизайн закона, этот отчёт |
| `docs/PROGRESS.md` | секция «Бэкенд» — единственное исключение канона |
Пофайловая таблица «файл → за какой экземпляр отвечает» снята: пофайловый состав лендинга берётся
командой `git show bb541a8 --stat`, а КАКОЙ код за каким экземпляром — §9 выше, по одному на пункт
(там же названы три новых файла: `internal/pipeline/snapshotdiff.go` — A4, `driftbasis.go` — A7+A12,
`paidtail.go` — A0). Вне `backend/` тронута ровно одна строка канона — секция «Бэкенд» в
`docs/PROGRESS.md`; ни `platform/`, ни `frontend/`, ни `eval/`, ни `books/` не тронуты.
**Касаний ЧУЖИХ тестов три класса, все санкционированы ЯВНО и ни одно не тихое** (условия и разбор —
D39.182 §2): ПРЕДПОСЫЛКА `bankfixpack_test.go` (§9.10) · УТВЕРЖДЕНИЕ `TestTheDecompositionIsNotTheOkColumn`

View file

@ -4,7 +4,7 @@
> D39.158 (стоп банка — флажок; полоса в два яруса и класс 15; отчёт двери v2; пути решений — только
> конвенцией). Что реально сделано, с доводами и остатками — `backend/docs/SEAM_PACK_FINDINGS.md`:
> состав и пофайловый список §36, решения §4.1§4.3 с доводами §37, замеры §38, живые пробы §39,
> «что НЕ удалось» §41, попунктный чек всех тринадцати §43. Промт архивирован:
> «что НЕ удалось» §41. Промт архивирован:
> `docs/archive/prompts/BACKEND_SEAM_FIX2_SESSION_PROMPT_2026-08-27.md`.
## Названные заранее развилки — и что с ними стало

View file

@ -2,7 +2,7 @@
> ⚠ **Записка ОТРАБОТАВШЕЙ сессии (25.08.2026), а не задание: не исполнять.** Дофикс закончен, принят и
> залендён — D39.158. Что реально сделано по каждому из шестнадцати пунктов, с командами и остатками —
> `backend/docs/SEAM_PACK_FINDINGS.md` §26 (попунктный чек), §15 (замер и механика корня формата
> `backend/docs/SEAM_PACK_FINDINGS.md` §15 (замер и механика корня формата
> `yaml.v3` — шире и точнее этой записки), §24 (что НЕ удалось), §23 (пинги). Промт архивирован:
> `docs/archive/prompts/BACKEND_SEAM_FIX_SESSION_PROMPT_2026-08-27.md`.

View file

@ -3,6 +3,16 @@
Бэкенд-сессия 24.08.2026. Промт архивирован — `docs/archive/prompts/BACKEND_SEAM_PACK_SESSION_PROMPT_2026-08-27.md`; записка-план — `SEAM_PACK_PLAN.md`.
**Каждое число — с командой, которой получено;** приёмка пере-раняет выборочно. Команды из `backend/`.
**Карта чтения — что здесь ЖИВОЕ, а что улика закрытого пака.** Четыре пака приняты и заленджены
(D39.158), поэтому целиком файл читать не надо; входи по предмету:
· **живые остатки и PLAUSIBLE** — §41, §24, §7, §9, хвосты §45 и §46 ·
· **пинги, правок по которым НЕ делали** — §10, §23, хвост §46 ·
· **решения зоны с доводами** — §21 (девять мелочей), §37 (модель флажка), §17 (выживший гейт) ·
· **провенанс чисел** — §18 (цена глагола), §29 п.1 (кап в количестве), §38 (хвост за потолком), §15 (цена рендера) ·
· **правила протокола, вынесенные инцидентами** — §11, §25, §35 ·
· **что построено** — §0, §28, §36 (состав трёх паков), §40 (счёт тестов).
Попунктные чеки заказов (§12, §26, §43) вырезаны как прожитая приёмка — на их местах стоят адреса.
## 0. Состав пака
**Новое:** `internal/membank/decisions.go` (чистая логика решений) · `internal/pipeline/bankdecisions.go`
@ -33,7 +43,7 @@
красен ровно `TestMinerFullBookParity`, причина — отсутствующий `eval/exp16/data/jieba_dict_general_zh.txt`;
`make lint``0 issues.`; `go vet ./... && go vet -tags live ./...` и `gofmt -l .` — чисто. Стенд-картина
совпала с опорной точкой оркестратора ⇒ **критерий §4.6 выполнен буквально.** Батареи дерева, которое
передавалось дальше, — §31 (дофикс), §43 строка §5 (фикс2), §46 (фикс3).
передавалось дальше, — §31 (дофикс), §38 (фикс2), §46 (фикс3).
## 2. Адверсариальные посадки: 16/16 краснеют
@ -161,15 +171,19 @@ file or directory` — та же причина, по которой красе
её сторона шва. Бэкап в движке не строил: механизм не заказан, носителя нет, существующий покрывает
обе стороны. Владельцу: провенанс из комментариев шапки переносить в поле `note:`.
- ~~Размер документа решений не ограничен~~**закрыто дофиксом:** два капа (1 МиБ на чтение и 5 000
решений на применение, оба классом 14). Довод и замер худшего случая — §29 п.1, чек — §26 4.5.
решений на применение, оба классом 14). Довод и замер худшего случая — §29 п.1.
## 10. Пинги — предметы ВНЕ карты пака, правок не делал
1. **`rubyToCandidates` мёртв в проде.** `grep -rn "rubyToCandidates" --include=*.go .` → 4 хита:
определение `internal/membank/memseed.go:301`, два комментария и ЕДИНСТВЕННЫЙ вызов —
`memseed_test.go:204`. `internal/pipeline/seeding.go:36-38` строит `manualSrcs` (аргумент этой
функции) и никуда не передаёт; Go молчит, потому что запись в map считается использованием.
Следствие: строк `Source:"ruby"` в банке не возникает, а платформа держит для них ветку словаря
1. **`rubyToCandidates` мёртв в проде — пере-проверено 02.09.** `grep -rn "rubyToCandidates" --include=*.go .`
→ 4 хита: определение, два комментария и ЕДИНСТВЕННЫЙ вызов — из теста
(`backend/internal/membank/memseed_test.go:204=cands := rubyToCandidates`). ⚠ Адрес механизма из
первой редакции («`seeding.go:36-38` строит `manualSrcs` и никуда не передаёт») МЁРТВ: ruby-путь
переехал, и сегодня прогон читает чтения в
`backend/internal/pipeline/bankmaterialize.go:84=RubyReadingsForBook(r.Book.BookID)` и отдаёт их
ТОЛЬКО в `AttachRubyAliasesToManual` — аргумента `manualSrcs` в проде не строит вообще НИКТО, то
есть кандидатная половина просто не подключена. Следствие прежнее: строк `Source:"ruby"` в банке не
возникает, а платформа держит для них ветку словаря
(`platform/internal/ingest/bank.go` `termOrigin``OriginAnnotated`).
2. **Гейт `TestDispatchCommandsCoversTheSwitch` слеп к `case` с КОНСТАНТОЙ** — считает только
`*ast.BasicLit`, поэтому команда, объявленная константой, невидима гейту, чей смысл в том, что дефект
@ -208,47 +222,19 @@ file or directory` — та же причина, по которой красе
изоляции ⇒ нагрузка»), затем другой одиночный прогон дал ровно обратное. Решает только чередующийся
A/B (§10 п.7).
## 12. Попунктный чек промта
## 12. Чек заказа и дифф тестов — сняты
| пункт | статус |
|---|---|
| §2 зона записи только `backend/` + секция «Бэкенд» в `docs/PROGRESS.md`; не коммитить; чужое не трогать | ✅ `git status` подтверждает |
| §4.1 дефолты пустых ключей; гард ЯВНОГО пути не ослаблен; отсутствующий дефолт = «решений нет» | ✅ на момент пака — M1 + `TestDeclaredAndUnreadableDecisionPathStillRefuses`. ⚠ **Механизм СНЯТ фикс2:** объявляемых ключей больше нет, путь — чистая функция каталога и `book_id` (D39.158 п.5), оба пина сняты вместе с предметом (§40) |
| §4.2 глагол $0; байтовый no-op; отзыв = ЗАМЕНА; всё-или-ничего; два решения по терму = отказ; конфликт с сидом С ИМЕНЕМ; проекция БЕЗ мутации; занятый лок РОВНО 12; flock неблокирующе; версия в ответе; `depth` явным полем | ✅ M2M8 + `TestDeclineWritesTheRejectAndWithdrawsTheApproval`, `TestOneCallDecidesATermOnce`, `TestDecisionOnASignedSeedTermIsRefusedByName`, `TestBankApplyDryRunWritesNothing`, `TestBankApplyDeclineThenApproveConverges`; §3, §4 |
| §4.2 НЕ проектировать «глубину до черновика» | ✅ `depth: edit_wave`; `TestTheRunReadsTheConventionalDelta` доказывает `Source:"mined"` |
| §4.3 `--keys-file` только у `translate`; деплой-файл ПЕРВЫМ; нечитаемый = отказ конфигом; ничего «на вырост» | ✅ M6 + `TestKeysFileWinsOverTheConventionalEnv` + `TestAnUnreadableKeysFileRefusesWithTheConfigClass` |
| §4.4 строгость сид-загрузчика + тест на unknown-key | ✅ 2 кейса в `TestSeedLintCatchesDefects` (`gendr`, `termz`) |
| §4.5 путь артефакта аддитивно + версия документа; НЕ тащить пере-именование банк-экспорта (ЛОМАЮЩЕЕ, окно — строка 161) | ✅ `artifacts{}` + `status_version`; пин `rep.Artifacts.BankExport == r.bankExportPath()` |
| §4.6 дефолт корпуса маркерным резолвом, env-переопределения старше | ✅ §1 |
| §4.7 платных вызовов НОЛЬ; `--keys-file` фейковыми ключами; вердикт PLAUSIBLE | ✅ sha256 базы (§4) + `TestTheKeysFileActuallyReachesTheProvider` (сверяет `Authorization` на fake-провайдере, и БЕЗ флага тот же прогон отказывает конфигом — проверка не вакуумна); §7 |
| §5 батарея после каждой правки; красный тест не подгонять; посадки ВНЕ списка промта; посадка называет ПАКЕТ; живая проба в КОПИИ; артефакт-находок | ✅ 16 посадок, 8 сверх списка; флейки охарактеризованы и НЕ тронуты; §2, §3 |
| §5.1 последний абзац — план или обещание? сделать СЕЙЧАС | ✅ всё найденное ревью закрыто в этом дереве; единственное отложенное — §8, вне моих возможностей по деньгам |
| §5.1 дифф `^func Test` исполнением; интервальная самоверификация субагентом | ✅ §13; ревью гонялось в СЕРЕДИНЕ пака против явных критериев |
| §6 оси: шов (инвентарь ЧУЖОГО кода) · общность · деньги | ✅ читал `artifacts.go`/`bank.go`/`engine.go`/`spawn.go`/`resync.go`/`exit.go` сам; проверил, что ни один декодер платформы не строгий ⇒ аддитивные поля безопасны; Go не ветвится по паре/книге; деньги — sha256 базы |
| §8 число с командой · §9 эхо до работы · §10 «что НЕ удалось» · §11 развилки пингом | ✅ §1§4 · выдано · §7 · §10 |
## 13. Дифф `^func Test` — исполнением
**Удалено: НОЛЬ** — сводный счёт по трём пакам и обе команды в §40. Новых тест-функций пака шесть файлов
несут в себе, плюс `TestTheRefusalTableIsTotal` в существующем `cmd/tmctl/exitcontract_test.go`.
**Тронуто в существующих файлах — шесть, ни у одной сигнатура не изменилась:**
- `exitcontract_test.go` — в список полосы добавлены `exitSchemaMismatch` и `exitDecisionsRejected`
(иначе гейт молча перестал бы покрывать новый код) + тест тотальности;
- `invocation_test.go` — frozen-строка usage расширена именем `bank-apply`. Объявленное расширение
контракта тем же механизмом, которым строка росла пять раз до меня (её собственный комментарий их
перечисляет), и второй половине того же теста («usage обязана называть каждую dispatch-команду»)
иначе не удовлетворить;
- `checks/labelharness_test.go`, `membank/labelharness_test.go`, `miner/miner_parity_test.go` — §4.6:
три копии резолвера заменены на `standdata` (120 строк, +62);
- `membank/seedlint_test.go` — два кейса unknown-key (§4.4).
Попунктный чек шестнадцати пунктов промта и пофайловый дифф `^func Test` этого пака были прожитой
приёмкой и вырезаны: сам заказ живёт в `docs/archive/prompts/BACKEND_SEAM_PACK_SESSION_PROMPT_2026-08-27.md`,
доказательства по каждому пункту — в §1§11 выше, а сводный счёт тестов по всем трём пакам («удалено
НОЛЬ», обе команды, поимённые переименования) — в §40.
---
# Дофикс той же двери (сессия 25.08.2026)
Промт (16 пунктов §4) архивирован — `docs/archive/prompts/BACKEND_SEAM_FIX_SESSION_PROMPT_2026-08-27.md`;
записка-план — `SEAM_FIX_PLAN.md`. Секции 013 выше — улика приёмки, не тронуты.
записка-план — `SEAM_FIX_PLAN.md`. Секции 012 выше — улика приёмки, не тронуты.
## 14. Батареи
@ -342,44 +328,11 @@ marshal → разбор настоящим строгим декодером
$ cd <копия backend> && go run ./cmd/tmmutate -root . -logs <dir>
```
| # | посадка (свойство) | пакет пина | что покраснело |
|---|---|---|---|
| A | лок двери — тот же flock, что держит ПРОГОН | `pipeline` | `TestBankApplyRefusesAProjectAN_RUNIsHolding` |
| B | `canonical_rewrite` + `preexisting_problems` (2 правки в 1 файле) | `pipeline` | `TestTheReportCarriesTheTwoFieldsThePackMitigatesItsRisksWith` |
| C | класс отказа без номера уезжает в catch-all 19 | `cmd/tmctl` | `TestTheRefusalTableIsTotal` |
| D | нормализация в REPLACEMENT-половине отказа | `membank` | `TestADeclineWithdrawsAnApprovalWrittenInAnotherOrthography` |
| E1 | глубокая копия алиасов в `withRubyAliases` | `membank` | `TestWithRubyAliasesDoesNotWriteIntoTheCallersRows` |
| E2 | перенос `note` при промоушене | `membank` | `TestPromotionCarriesTheOwnersNote` +1 |
| E3 | рантайм-половина гарда ОБЪЯВЛЕННОГО пути | `pipeline` | ⚠ пере-выражена фикс2 («unreadable ≠ undecided»): `TestAnAbsentDecisionFileIsUndecidedAndAnUnreadableOneIsAnError` |
| F | абсолютность путей в `artifacts{}` | `pipeline` | `TestTheReportedPathsAreAbsoluteEvenWhenTheConfigIsNOT` |
| G | байтовый гейт `changedDoc` | `pipeline` | **ВЫЖИВАЕТ — см. §17** |
| H | решения едут С КНИГОЙ, а не с `project_db` | `config` | `TestTheDecisionFilesTravelWithTheBookAndNotWithTheDatabase` |
| I | нормализация ДОКУМЕНТА (значение уже в файле) | `membank` | `TestAHandAuthoredNoteTheEngineCannotWriteIsRepairedNotRefused` |
| J | равенство в `renderProved` (а не «просто разобралось») | `membank` | `TestTheRenderGateRefusesBytesThatReadBackAsAnotherDocument` |
| K | нормализация ЗАПРОСА (идемпотентность повтора) | `membank` | `TestARepeatOfADecisionWhoseTextIsPaddedIsStillAlreadyApplied` |
| L | `book_id` — один элемент пути | `config` | `TestBookIDIsRefusedWhenItIsNotAPathElement` |
| M | четыре движковых пути попарно различны | `config` | ⚠ переименован фикс2: `TestDeclaredKeysCannotLandOnTheDecisionFiles` |
| N | гард флага — на ПРИСУТСТВИЕ, не на значение | `cmd/tmctl` | `TestAFlagIsRefusedForBEINGTHERE_NotForCarryingAValue` |
| O | перевёрнутое окно глав | `membank` | `TestAReversedChapterWindowIsRefused` |
| P | инертный отказ судится по НАБОРУ | `membank` | `TestApprovingATermAndDecliningItsAliasInOneCallIsRefused` |
| Q | `note` не стирается умолчанием | `membank` | `TestANoteIsNotErasedByAnOmission` |
| R | кап документа решений | `pipeline` | `TestTheDecisionDocumentIsCapped` |
| S | стоп между решением и записью не пишет | `pipeline` | `TestAStopRequestWritesNothing/cancelled_while_the_decision_is_being_computed` |
| T | пред-существующая поломка — по СУБЪЕКТУ | `membank` | `TestRepairingOneOfTwoBrokenTermsIsAccepted` |
| U | честность отчёта о непогасшем стопе | `pipeline` | ⚠ переименован фикс2: `TestTheChainOwnerDecidesTheWholeMapAndTheRunGoesOn` |
| V | конверт путей на поверхности потребителя | `pipeline` | `TestTheManifestCarriesTheArtifactEnvelope` |
| W | кап на КОЛИЧЕСТВЕ решений (§29 п.1) | `pipeline` | `TestTheDecisionCOUNTIsCappedBecauseTheBYTESCannotBound` |
| Y | субъект поломки без рендеринга (§29 п.2) | `membank` | `TestAFaultTheDoorHasNoChannelForCannotDeadlockIt` +1 |
| Z | нечитаемая карта подписи ≠ «всё решено» (§29 п.6) | `pipeline` | `TestASignatureMapThatCannotBeReadDoesNotReportAsAllDecided` |
| AB | побег «это был терм сам по себе» (§30 п.2) | `membank` | `TestADeclineIsRefusedWhenTheSurfaceGOESONFiringAsAnotherTermsAlias` |
| AC | `aliasOwner` игнорирует статус (§30 п.3) | `membank` | `TestDecliningTheAliasOfAnUNSIGNEDRowIsAccepted` |
| AD | загрузчик отдаёт построенные записи при отказе (§30 п.1) | `membank` | `TestRepairingAnUnloadableDocumentIsNotRefusedOverWhatItUNMASKS` |
| AE | позиционный субъект (§30, «плюс два») | `membank` | `TestTwoRecordsWithNoIdentityDoNotBlockEachOthersRepair` |
| AF | довод отказа описывает всех, кого отвергает (§30 п.4) | `cmd/tmctl` | `TestTheKeysFileRefusalDescribesEveryoneItTurnsAway` |
| AG | остановленный вызов не печатает, что применил (§34) | `pipeline` | `TestAStoppedCallDoesNotPRINTThatItApplied` |
| AH | нечитаемая карта подписи ≠ «всё решено» (§34) | `pipeline` | `TestASignatureMapThatCannotBeReadDoesNotReportAsAllDecided` |
| AI | отказ не предупреждает о перезаписи, которой не будет (§34) | `pipeline` | `TestARefusedCallDoesNotWarnAboutARewriteThatWillNotHappen` |
| AJ | отказ по алиасу сида сужен до случая, где он инертен (§34) | `membank` | `TestDecliningASeedAliasIsAcceptedWhenTheDeltaHoldsThatRow` |
**Пофайловая таблица «посадка → пакет пина → что покраснело» здесь НЕ дублируется:** её живой и
авторитетный носитель — сам каталог `backend/cmd/tmmutate/mutations.json` (у каждой записи `id`, `why`
свойство, за которое она отвечает, — и `package`), а имена пинов инструмент называет ПОИМЁННО в выводе
прогона. Снимок в отчёте протух бы в первом же паке: записей было 36 на дату дофикса, 56 после фикс2,
60 после фикс3.
## 17. Единственная выжившая мутация — и почему пин на неё невозможен
@ -504,12 +457,22 @@ YAML не накладывает ничего. Новый гоняет прои
"signature": { "map": "<путь>", "surfaces": 2, "undecided": 0 }
```
`undecided > 0`**факт**, что стоп не погаснет. `undecided == 0`**не обещание**, и это написано в
комментарии типа явно. Пустой `map` значит «прогон до границы банка ещё не доходил». В режиме проекции
число — то, что БУДЕТ после применения (единственное чтение, которое может иметь превью).
Пустой `map` значит «прогон до границы банка ещё не доходил». В режиме проекции число — то, что БУДЕТ
после применения (единственное чтение, которое может иметь превью).
Запинено там, где оно осмысленно, — в тесте цепи §4.12: частичный документ на карте из двух сурфейсов
даёт `undecided=1`, полный — `undecided=0`, и после него стоп действительно гаснет.
**СТАРАЯ ФОРМУЛА ЭТОГО АБЗАЦА ОТМЕНЕНА, и вот действующая.** Пак писал «`undecided > 0` — факт, что
стоп не погаснет»; под моделью флажка (D39.144, фикс2) поле **не отвечает на вопрос о стопе НИ В ОДНУ
СТОРОНУ**, и это записано в самом коде:
`backend/internal/pipeline/bankdecisions.go:92=IT DOES NOT ANSWER «погаснет ли стоп»`. Причина —
механическая: стоп срабатывает, когда СВЕЖЕ-намайненная карта следующего прогона держит кластер вне
предъявленной памяти (`hasUnpresentedCluster`, `internal/pipeline/mining.go`), а этого набора ещё не
существует ни у кого за $0. Что поле ЕСТЬ: информационный счётчик для экрана подписи — «о скольких
поверхностях последней карты владелец ещё не высказался», считанный ТЕМ ЖЕ правилом, которым прогон
сворачивает решения в банк (`ownerHandled(unsignedEngineSurfaces(...))`).
Пины сегодня — цепи `internal/pipeline/bankchain_test.go`
(`TestTheChainOwnerDecidesTheWholeMapAndTheRunGoesOn` · `TestTheStopIsAFlagNotAGateOnDecisions`): решение
по всей карте прогон НЕ останавливает, а стоп — флажок, а не гейт на решения.
## 23. Пинги — предметы ВНЕ карты дофикса, правок не делал
@ -581,49 +544,15 @@ YAML не накладывает ничего. Новый гоняет прои
**Общая форма правила, шире этого инструмента:** самопроверка, чей эталон снят ПОСЛЕ первого изменения,
не проверяет ничего. Эталон снимается один раз, на состоянии, которое известно как чистое.
## 26. Попунктный чек §4 — все шестнадцать
## 26. Чек заказа и дифф тестов дофикса — сняты
Комплектность сверена механически: `grep -cE '^### 4\.' docs/archive/prompts/BACKEND_SEAM_FIX_SESSION_PROMPT_2026-08-27.md`**16**.
Попунктный чек шестнадцати пунктов §4 и пофайловый дифф `^func Test` дофикса вырезаны как прожитая
приёмка. Адреса: заказ — `docs/archive/prompts/BACKEND_SEAM_FIX_SESSION_PROMPT_2026-08-27.md`
(комплектность сверялась механически: `grep -cE '^### 4\.' <промт>` → 16); доказательства по каждому
пункту — §15§25 выше; сводный счёт тестов и переименования — §40; каталог посадок —
`backend/cmd/tmmutate/mutations.json`.
| пункт | статус | чем закрыт |
|---|---|---|
| **4.1** ⛔ блокер: round-trip на ОБОИХ документах | ✅ **сделано ШИРЕ заказа** | нормализация документа + запроса, рендер ДОКАЗЫВАЕТ равенство (не только разбираемость — заказанная форма пропустила бы две тихие потери), байты проверены один раз и один раз записаны, фаззер пути ДВЕРИ, характеризационный тест на библиотеку. §15, §20; мутации I/J/K; живая проба §19 |
| **4.2** пред-существующие чинятся по одной | ✅ сделано; **дважды углублено по ревью** | вердикт загрузчика разложен по СУБЪЕКТАМ (`membank/problems.go`), ключ сравнения — субъект, который НЕ несёт рендеринга (§29 п.2), и проверки ПОД загрузчиком выполняются по обе стороны (§30 п.1). Мутации T, Y, AD (⚠ X снята вместе с правилом маски, каталог её больше не несёт); пины `TestRepairingOneOfTwoBrokenTermsIsAccepted`, `TestAFaultTheDoorHasNoChannelForCannotDeadlockIt`, `TestRepairingAnUnloadableDocumentIsNotRefusedOverWhatItUNMASKS`; живая проба §19 |
| **4.3** два ключа на один путь | ✅ **сделано ШИРЕ на одну проверку** | попарно различны четыре движковых пути (`project_db`, `glossary_seed`, `mined_delta`, `mined_rejects`) — `project_db == mined_delta` означало бы YAML поверх sqlite. Проверено на всех `book.yaml` репозитория и стенда (`find . -name book.yaml \| wc -l`**22**): нарушителей ноль. Мутация M |
| **4.4** гард флага на ПРИСУТСТВИЕ | ✅ сделано | `fs.Visit` (единственное, что отвечает на этот вопрос), оба гарда, плюс пустое значение у присутствующего флага — тоже отказ. Мутация N |
| **4.5** кап документа + строка отказа полосой | ✅ сделано, ПЕРЕСМОТРЕНО по ревью | ДВА капа: 1 МиБ на чтение + **5 000 решений** на применение. Первая редакция капила только байты и утверждала, что этим ограничено ВРЕМЯ — опровергнуто замером (§29). Класс 14 у обоих. Хвост про `exit 2` — пингом. Мутации R, W |
| **4.6** конверт путей потребителю | ✅ сделано, компромисс назван | `manifest --json` несёт тот же `artifacts{}`; ВЫВОДИТСЯ на каждом чтении, поэтому версия документа не двигалась. Компромисс вслух: манифест семантически про дерево глав, путь артефакта там гость. Мутация V |
| **4.7** алиас судится по НАБОРУ | ✅ сделано; **углублено по §30 п.2** | проверка перенесена ПОСЛЕ свёртки и судит РЕЗУЛЬТАТ — именно поэтому два отказа (терм + его алиас) остаются законными: к концу вызова алиасом никто не владеет. ⚠ Побега «своя поверхность проверяется по ВХОДНОМУ документу» в коде НЕТ — он был заведён и снят как вредный (§30 п.2), заводить заново не надо. Мутации P, AB |
| **4.8** перевёрнутое окно глав | ✅ сделано | отказ с цитатой окна; открытая верхняя граница законна. Мутация O |
| **4.9** честность про непогасший стоп | ✅ **исполнено фактом, не предсказанием** | `signature{map,surfaces,undecided}` по правилу самого прогона; `undecided>0` — факт, `undecided==0` — явно не обещание. Аргумент в §22. Мутация U |
| **4.10** SIGTERM | ✅ сделано; сомнение записки СНЯТО замером; **довод в комментарии исправлен по ревью** | ctx проверяется дважды, стоп не пишет ничего, exit 5. Несущий довод — НЕ длина непрерываемого участка (первая редакция назвала её «≈20 с, два порядка внутри stop grace»; замер §29 п.1 дал **308.2 с** на 28 900 минимальных `decline`, которые байтовый кап пускает, — оценка неверна в 15 раз), а то, что записи идут последними и атомарно: убитый где угодно до них процесс не записал ничего. Мутация S (пин целится именно во вторую проверку) |
| **4.11** десять посадок, пин на каждую | ✅ 9 из 10 + доказательство по десятой | AH, E1E3 краснеют своими пинами; **G недостижима за первым гейтом — доказано, не предположено** (§17), вместо поведенческого пина запинен контракт функции |
| **4.12** цепь в репозитории | ✅ сделано | `internal/pipeline/bankchain_test.go`, $0 на фейковом провайдере, ОДИН проект от стопа до погасшего стопа; форма фикстуры (2 терма = 1 approve + 1 decline) проверяется как ПРЕМИСА; ограничение синтетики названо в комментарии; карта подписи после погасшего стопа зафиксирована явно |
| **4.13** девять мелочей | ✅ по каждой решение и довод | §21: починено 3, отклонено с аргументом 5, пингом 1 |
| **4.14** довод отказа `--keys-file` | ✅ сделано | текст называет `redrive` (платный, свой `.env`), `backup`/`migrate` (деплой-шаги) и $0-читающие поимённо. Развилку про канал ключей `redrive` НЕ решал |
| **4.15** три тавтологичных пина | ✅ сделано | вердикт `Preexisting` исполняется всеми четырьмя проверками (`TestAPreExistingFaultOfEveryKindStaysReportedAndUnblocking`); четвёртый оракул фаззера снят с тавтологии и стал НЕПОДВИЖНОЙ ТОЧКОЙ; `TestDecisionByBankID` сверяется с НЕЗАВИСИМО посчитанными константами + отдельный пин на инъективность, ради которой в `TermID` сделана длина-префикс |
| **4.16** платных вызовов ноль | ✅ | `sha256` базы стенда не сдвинулся; рантайм по платному пути — PLAUSIBLE, как и ожидалось |
| §5 батарея после каждой правки · посадки СВЕРХ списка · посадка называет ПАКЕТ · живая проба в КОПИИ · артефакт-находок | ✅ | 36 посадок (26 сверх списка §4.11), пакет пина ≠ пакет правки записан в каталоге, проба в копии, эта секция |
| §5.1 последний абзац — план или обещание? · дифф `^func Test` исполнением · интервальная самоверификация субагентом · каждый клейм — с результатом инструмента ЭТОЙ сессии | ✅ | обещаний в отчёте нет: всё найденное закрыто в дереве; §27; ревью гонялось в СЕРЕДИНЕ работы против явных критериев; каждое число выше — с командой |
| §6 три оси | ✅ | round-trip формата (§15, §20) · слепота гейта (§16, §17) · общность: в Go, которую я тронул, нет ни одного литерала пары/письменности/орфографии (проверено грепом по девяти файлам); нормализация — `strings.TrimSpace`, определённый Юникодом, а не скриптом |
| §8 заявление = команда · §9 эхо до работы · §10 «что НЕ удалось» · §11 развилки | ✅ | §14§27 · выдано до кода · §24 · §21§23 |
## 27. Дифф `^func Test` — исполнением
**Удалено: НОЛЬ** — сводный счёт и обе команды в §40; поимённая половина проверки прошла по семнадцати
пинам, которые отчёт пака называет по имени (каждый существует ровно один раз).
**Тронуто (тело изменено, сигнатура — нет), и вот почему это законно:**
- `cmd/tmctl/exitcontract_test.go``TestTheRefusalTableIsTotal` перестал держать ручной список и
читает классы из ИСХОДНИКА обходом `GenDecl`/`ValueSpec` (⚠ не по `*ast.BasicLit` в `case`, как
соседний гейт диспетча: значения `RefusalClass` объявлены КОНСТАНТАМИ, и копирование той техники
воспроизвело бы её собственную слепоту — это её же пинг);
- `internal/membank/decisions_test.go``TestDecisionByBankID` сверяется с НЕЗАВИСИМО посчитанными
константами; `decisions_fuzz_test.go` — оракул 4 переписан с тавтологии на неподвижную точку;
- `internal/pipeline/bankdecisions_test.go`, `statusartifacts_test.go` — сигнатура `ApplyBankDecisions`
получила `context.Context`.
**Новый файл:** `internal/pipeline/bankchain_test.go` (цепь §4.12).
⚠ D39.158 называет «вход §26» — читатель, пришедший по этой ссылке, попал верно: адреса выше.
## 28. Состав дофикса
@ -646,7 +575,8 @@ YAML не накладывает ничего. Новый гоняет прои
Ревью запрашивалось по решениям, где заказ оставлял форму на сессии. **Каждую находку сессия
воспроизвела сама прежде, чем чинить** — чужой результат, взятый на веру, ровно так же становится
нормой. У двух подтверждённых решений ревью дало довод СИЛЬНЕЕ, и довод заменён в комментариях кода: у конверта путей на манифесте — что бамп версии выбросил бы все сохранённые сайдкары
и пере-нарезал каждую книгу ради аддитивного поля; у SIGTERM — атомарность и порядок записей вместо
и пере-нарезал каждую книгу ради аддитивного поля (компромисс назван вслух: манифест семантически про
дерево глав, путь артефакта там гость); у SIGTERM — атомарность и порядок записей вместо
длины непрерываемого участка.
### 1. Кап в БАЙТАХ не ограничивает ВРЕМЯ — мой довод был неверен
@ -794,6 +724,10 @@ off-by-one · после второй проверки контекста нич
`backend/internal/membank/decisions_test.go:348=Computed outside Go, from the spec in TermID's own comment`) ·
`SeedProblems.Error()` побайтно равен прежнему склеенному сообщению.
**Общность — проверена грепом по девяти тронутым файлам:** в Go, которую дофикс тронул, нет ни одного
литерала пары/письменности/орфографии; нормализация — `strings.TrimSpace`, определённый Юникодом, а не
скриптом.
**Унаследованное замечание, не дефект пака:** всё, на чём эта дверь ключуется, проходит через
`internal/text/norm.go`, где таблица `trad2simp` и ветка катакана→хирагана живут В GO, а не в langpack'е.
Пара, которой в репо нет, деградирует до NFKC+lowercase — то есть не блокирована, но фолд Go-резидентный.
@ -883,7 +817,7 @@ ApplyDecisions → resolveAll · refuseSeedConflicts · foldAccepted · ref
ApplyBankDecisions → openDecisionRequest · readBookState · decisionReport · changedFiles · writeDecisionFiles
```
⚠ Фаза `decisionReport` позже заменена единым конструктором исходов `finishReport` (фикс2, §43 4.5) —
⚠ Фаза `decisionReport` позже заменена единым конструктором исходов `finishReport` (фикс2, §36§37) —
грепать надо его. Тело `ApplyDecisions` стало последовательностью из пяти судящих фаз, из которых
**ровно одна** что-то меняет (`foldAccepted`): это и есть контракт двери, теперь видимый в самом коде, а
не только в комментарии.
@ -946,13 +880,13 @@ ANYTHING IS PLANTED» и «NOT a red …»; второй копии этот о
На вопрос «все замечания исправлены?» сессия не отвечала по памяти: независимые агенты прошли по всем
пережившим находкам §34 и по живому дереву решали КАЖДУЮ — закрыта / не закрыта / частично / отклонена
осознанно. Закрыто оказалось не всё; все остатки доделаны, и их результат живёт не здесь, а в
исправленных по месту секциях (§15, §16, §18, §26, §27, §31, §33) — второй копии этот отчёт намеренно не
исправленных по месту секциях (§15, §16, §18, §31, §33) — второй копии этот отчёт намеренно не
держит.
**Два остатка были признаны вне полномочий пака, и оба закрылись позже:** межкнижная гонка за один
`mined_delta` — снятием объявляемых ключей (D39.158 п.5; остаток «второй конфиг ТОЙ ЖЕ книги» заведён
строкой бэклога 222), запись карты подписи обычным `os.WriteFile` — атомарной записью с конвертом
43 4.10).
36, §41).
**Вывод, который стоит унести дальше самого пака.** Это было ТРЕТЬЕ ревью подряд, и каждое находило
настоящие дефекты, которых не видели предыдущие: одиночный старший ревьюер — три (§29), интервальное —
@ -1130,33 +1064,20 @@ $ git ls-files --others --exclude-standard -- . | grep '_test.go$' \
retired-ключи ловятся полями, а не голым strict-decode · конверт карты читают все движковые читатели,
`DecodeFile` на карту не наведён · дверь память не читает · в новом Go-коде ветвлений по паре/книге нет.
## 43. Попунктный чек §4 — все тринадцать
## 43. Чек заказа фикс2 — снят
Комплектность сверена механически: `grep -cE '^### 4\.' docs/archive/prompts/BACKEND_SEAM_FIX2_SESSION_PROMPT_2026-08-27.md`**13**.
Попунктный чек тринадцати пунктов §4 фикс2 вырезан как прожитая приёмка. Адреса: заказ —
`docs/archive/prompts/BACKEND_SEAM_FIX2_SESSION_PROMPT_2026-08-27.md` (комплектность сверялась
механически: `grep -cE '^### 4\.' <промт>` → 13); решения с доводами и названные остатки — §37; замеры —
§38; живые пробы — §39; дифф тестов и переименования — §40; что НЕ удалось — §41; сужения воркфлоу-ревью
— §45.
| пункт | статус | чем закрыт |
|---|---|---|
| **4.1** память «предъявленного стопом» | ✅ | store v16 `bank_stop_presented` (плоское множество поверхностей кластеров — Src+Aliases, `INSERT OR IGNORE`, без обрезки); предикат `hasUnpresentedCluster` — пересечение кластера с памятью, домен — ИТОГОВАЯ карта после потолков (обе секции); двусторонний остаток записан пином. Цена миграции названа (§37). Пины: цепь Б, `stopflag_test.go`, `stopmemory_test.go`, реверс-новизна; мутации FX1FX3 |
| **4.2** порядок и момент записи | ✅ | карта (атомарно) → память, в момент СТОПА; отказ памяти НЕ валит стоп (ERROR-строка, названо §37); «подтверди карту» НЕ заведено; draft-only ветка названа. Развилка карта/SQLite-транзакция решена явно (направление потерь — доброкачественный повторный стоп) |
| **4.3** авто-провод при поднятом флаге | ✅ | «останавливаться ли» и «проводить ли» — два решения; авто-провод на ЛЮБОМ неостановившемся прогоне; вторая половина названа: остановившийся прогон авто-банк НЕ пишет (решение с доводом, §37). Мутация FX4; пины в WHATSurvives и цепи Б |
| **4.4** хвост за потолком | ✅ не лечился | пере-замер своей командой (2354/209/11/198, §38) — числа промта без первоисточника не цитируются; фильтр карты НЕ заведён; пинг в журнале |
| **4.5** единая точка фиксации | ✅ | вердикт (`decisionVerdict`) / исход (`finishReport` — единственный конструктор, свитч по `applyOutcome`, шесть исходов); «записано» — пост-состояние ПЕРЕЧИТАННЫХ файлов; пин `TestEveryOutcomeStampsItsOwnMode` + греп-инвариант (присваиваний вне конструктора нет — подтверждено интервальным ревью). Вердиктная половина сохранена (сильная форма отвергнута по букве промта) |
| **4.6** `signature.undecided` | ✅ | пере-документирован: НЕ отвечает на вопрос о стопе (в обе стороны), информационный счётчик для экрана подписи; память дверь НЕ читает (решение с доводом: ответ требовал бы следующего намайненного набора, которого нет ни у кого за $0); поле не удалено |
| **4.7** полоса в два яруса | ✅ | пол «нет отката, повтор безопасен»; клауза «ничего не произошло» — у пяти исходных классов; гардрейл «разрушительное — только на классе» буквой; класс `write_incomplete` (exit 15) один на оба исхода, различие — `written_*`; отказ по обоим капам печатает отчёт (контракт сведён к одному носителю). Мутации FX18FX20 |
| **4.8** подготовка обоих файлов | ✅ | stage обоих (write+sync+chmod) → два rename → fsync каталога; заявлено НЕ шире сделанного (атомарность против среды, не против SIGKILL — довод в `writeDecisionFiles`, остаток в §41); отказ синка — класс 15 с оговоркой долговечности. Мутации FX16FX17, пины staged/unsyncable |
| **4.9** Clean + конвенция | ✅ | (а) `filepath.Clean` абсолютных в resolve, репро приёмки закрыто пином; (б) оба ключа СНЯТЫ retired-отказом с лечением в тексте (прецедент `adult:`), пути — чистая функция каталога и book_id: МЕЖКНИЖНАЯ гонка (⛔-пинг прошлого пака) снята; воркфлоу-ревью показало ОСТАТОК той же оси — второй конфиг ТОЙ ЖЕ книги (один каталог, один book_id, другой объявленный project_db) пишет те же файлы под другим локом; остаток — пинг, не решение пака (§45). Мутации FX12FX13 |
| **4.10** карта: атомарность и конверт | ✅ | `writeFileAtomic` + конверт `map_version`/`map_id` (sha256 содержимого), рендер ДОКАЗЫВАЕТ round-trip (`RenderSignatureMap` через `renderProved`); легаси-карта читается; карта НЕ накопитель (слияния нет). Мутации FX14FX15; живьём — инод-пин |
| **4.11** слепые пятна | ✅ | все шесть строк таблицы закрыты посадкой+пином (normText-класс · субъект-класс · субъект-окно · абсолютность путей отчёта двери · границы обоих капов · граница окна); пин семантики §4.1 — цепь Б + два переписанных харнесс-теста (возврат старой формулы краснит ТРИ теста, вывод tmmutate по FX2 поимённо — §40). Вакуумный пин пойман посадкой ДО записи (§38) |
| **4.12** наследие — списком | ✅ | шапка mining.go · комментарий у loadMinedRejects · unsignedEngineSurfaces · docstring runBankMiningStop · сообщение стопа · renderSignatureStop + два стейл-хинта render.go · help `--verify-bank` · WaveSignatureStop/waverun · комментарий v16; новое состояние «дельта непустая, нового нет» — явная WARN-строка; цепной тест переписан (замена названа: `TestTheStopIsAFlagNotAGateOnDecisions`); пинги с ПОРЯДКОМ и миграционная нота — в журнале |
| **4.13** платных вызовов ноль | ✅ | фейковый провайдер + харнесс + копия стенда; sha256 стендовой базы не сдвинулся; рантайм по платному пути — PLAUSIBLE; «выигрыш по чекпоинтам» НЕ заявлен (механизма нет, §41) |
| §5 батарея/каталог/проба/артефакт | ✅ | батарея после каждой правки; `make battery` EXIT=0; стенд-батарея красна ровно на jieba-парити; каталог 36→56, `NOTHING` роняет гейт (свойство не тронуто); живая проба §39; эта база |
| §6 три оси | ✅ | семантика флажка — прогонами движка (цепи, харнесс), без кода платформы · точка фиксации — конструктор + греп + пин исходов · слепота гейта — 56 посадок / 0 неожиданных |
| §7§11 | ✅ | план до кода (`SEAM_FIX2_PLAN.md`, механическая сверка 13) · эхо до работы · «что НЕ удалось» §41 · развилки решались по букве промта, интерпретаций против него нет |
⚠ D39.158 называет «вход §43» — читатель, пришедший по этой ссылке, попал верно: адреса выше.
## 44. Проверка ЗАКРЫТИЯ — отдельным агентом, не чинившим (§5.1)
Прогнана по презумпции «каждое заявленное закрытие ложно, пока не увидено исполнением»: все 13 строк §43
и все 4 диспозиции §42 подтверждены в дереве (13 точечных тестовых прогонов + 3 полных пакета — зелёные;
Прогнана по презумпции «каждое заявленное закрытие ложно, пока не увидено исполнением»: все 13 пунктов
заказа фикс2 (§36§41, §45) и все 4 диспозиции §42 подтверждены в дереве (13 точечных тестовых прогонов + 3 полных пакета — зелёные;
носители по file:line; реверс-пин признан невакуумным с названным механизмом падения). Расхождения нашлись
и здесь (⚠-вывод §35 держится и на этой сессии), все закрыты по месту — правки видны в §38, §40 и §42.
Одно стоит того, чтобы его запомнили: пере-замер §4.4 жил только в скратчпаде — то есть был «числом без

View file

@ -2,7 +2,7 @@
> ⚠ **Записка ОТРАБОТАВШЕЙ сессии (24.08.2026), а не задание: не исполнять.** Пак закончен, принят и
> залендён — D39.158. Что реально построено, чем доказано и что осталось — доказательная база
> `backend/docs/SEAM_PACK_FINDINGS.md` (состав §0, попунктный чек заказа §12, пинги §10). Промт
> `backend/docs/SEAM_PACK_FINDINGS.md` (состав §0, дефекты §5, пинги §10). Промт
> архивирован: `docs/archive/prompts/BACKEND_SEAM_PACK_SESSION_PROMPT_2026-08-27.md`.
## Развилки, которые сессия решала своим доводом