diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md
index e82cd9c1..c71ea3b0 100644
--- a/docs/PROGRESS.md
+++ b/docs/PROGRESS.md
@@ -281,493 +281,10 @@
> порча» — `D39.164` (`7d0c6f2`), пак «деньги» — `D39.170`, гейт схемы — `D39.173`.
-### 📝 ЗАПИСКА-ПЛАН — пак «писатель книги» (промт `docs/archive/prompts/BACKEND_BOOKWRITER_PACK_SESSION_PROMPT_2026-08-30.md`, строка 236), сессия `textmachine-main-fc`, 30.08
-
-**Что беру (зона `backend/`, HEAD на старте `67c05be`, дерево чисто).**
-1. Прод-пакет `backend/internal/bookfile` (только stdlib — `archive/zip`, `encoding/xml`; без `import "testing"`):
- `container.go` — OCF-контейнер (`mimetype` первым и `zip.Store`, `container.xml`, запись entry в порядке вызовов,
- нулевые таймметки) — `chunktest/epub.go` переводится на него, его OPF-заглушка и XHTML-декой остаются тестовыми;
- `epub.go` — EPUB 3 из нейтральной модели `Book{Identifier, Title, Language, Modified, Description,
- Chapters[]{Title, Paragraphs[]}}`: `dc:identifier`/`dc:title`/`dc:language`/`dcterms:modified`, nav
- (`properties="nav"`, ⛔ НЕ в spine), один XHTML на главу, `
` = заголовок главы, `
` = абзац;
- `txt.go` — чистый текст из той же модели (заголовок строкой, абзацы через пустую строку, главы через
- пустую строку; ни баннеров, ни флагов, ни `gapMarker`).
-2. Сборка из `BookExport` — `backend/internal/pipeline/bookbuild.go`: `Runner.BuildBook(formats, partial)` →
- `Export(false)` → дыры → отказ либо файл. Запись `writeFileAtomic` рядом с ProjectDB
- (`.book.`, как `.manifest.json`/`.bank.json`), путь публикуется в
- `StatusArtifacts.BookFiles` (`book_files`: map формат→путь, аддитивно) — приор промта принят: платформа
- пути не выводит сама (17 §1). Существующий файл — перезапись: производный детерминированный артефакт, как
- манифест; бэкап отказывает потому, что он точка восстановления, а файл книги пересобирается из стора.
-3. Аддитивные поля `tm-export-v1` (форма не меняется, все `omitempty`): `ChunkExport.Heading` (`heading`) —
- литерал `u.Members[0].Heading` в момент сборки записи (и у pending-юнита тоже, он из манифеста);
- `BookExport.GhostUnits` (`ghost_units`: `[{chapter,chunk_idx}]`) — ключи ghost-строк, чтобы маркер стоял
- в главе, а не только в счётчике; `BookExport.TextModified` (`text_modified`, `CCYY-MM-DDThh:mm:ssZ`) —
- max(`chunk_status.updated_at`) по финальным строкам, вошедшим в файл (колонка `NOT NULL DEFAULT
- datetime('now')`, `store/migrate.go:37`; в `ChunkStatus` дочитывается доп. полем). Это и есть
- `dcterms:modified`: последнее изменение отгруженного текста — факт стора, не часов процесса.
-4. Глагол `tmctl build --config b.yaml [--format epub,txt] [--out path] [--partial]` (по умолчанию оба формата;
- `--out` — только при одном формате). Stdout — JSON-конверт `tm-build-v1` (пути, счётчики, `complete`).
- Новый глагол, а не флаг `export`: `export` — чистое чтение в stdout, писать файлы из него — смешать
- аудит-проекцию с артефактом; `manifest` — прецедент глагола-писателя сайдкара. `dispatchCommands` и
- usage-строка расширяются — контрактное расширение того же рода, что `bank-apply` (тест
- `TestParseNoArgsUsage` сам перечисляет такие расширения); чужим глаголам новые флаги ОТКАЗЫВАЮТСЯ
- (дисциплина `--keys-file`/`--max-units`).
-5. Отказ — новый `pipeline.RefusalBookIncomplete = "book_incomplete"` → exit **16** (полоса 10–19; таблица
- тотальна по `TestTheRefusalTableIsTotal`); сообщение перечисляет дыры `глава/юнит/причина`.
-6. Читательские слова — ДАННЫЕ: `//reader.txt` (`keyvalue`, плейсхолдеры
- `{chapter} {unit} {dropped} {holes} {total} {ghost}`), читает ОТДЕЛЬНЫЙ загрузчик `lang.LoadReaderWords`;
- в `Pack.Version()` НЕ фолдится (пин тестом «наличие reader.txt не меняет Version()» + `current_snapshot`
- minirun до/после). Ключ — язык ЦЕЛИ, не пара: слова читает читатель целевого языка, и они не зависят от
- исходного. Поставляю `backend/configs/langpacks/ru/reader.txt`. Каталог `/` загрузчик пака не
- читает (`Load` — только `/` и `/`, `langpack.go:215-330`), так что канал вне фолда по
- построению, а не по соглашению.
-
-**Политика §3.2 — по умолчанию ОТКАЗ, `--partial` — файл с пометкой; довод:**
-- Дыры: pending · withheld (`Disposition!="pending" && FinalText==""`) · incomplete (`DroppedMembers>0` при
- непустом тексте) — арифметика `render.go:573-587` выносится в общий хелпер `pipeline`, которым пользуется и
- `renderExport` (вывод `--plaintext` побайтово прежний) · **ghost — тоже дыра**: при укрупнении нарезки
- строка-лидер несёт текст ПРЕЖНЕГО, более короткого юнита, а остаток источника лежит в ghost-строках и в
- файл не попадает (acceptance: 57 строк → 37 юнитов, 20 ghost при `pending 0` — ровно «молча полная»
- книга). Позиция ghost внутри главы неизвестна → маркер в конце главы с числом потерянных строк.
-- Default = отказ: D29.1(б) — reader-facing выдача fail-closed; дверь платформы получит `--partial` для
- контрактного «may be exported, finished or not» (14 §createExport).
-- `--partial`: пометка неполноты — первый абзац первого документа spine (то, что читатель видит, открыв
- книгу) + `dc:description`; маркер — отдельный абзац на месте КАЖДОЙ дыры (pending/withheld — вместо текста
- юнита; incomplete — перед текстом юнита, как `gapMarker`; ghost — в конце главы). Форма — из `reader.txt`;
- без пака (acceptance, `runner.go:346`) — несловесная: `⚠ {chapter}.{unit}` у дыры, `⚠ {holes}/{total}` в
- пометке (символ + числа, никакого словаря в Go). В `FinalText`/`export.go` маркер не попадает.
-- drift — НЕ дыра: текст файла побайтово текст прогона (`export.go`, комментарий к `exportConfigDrift`);
- попадает в JSON-конверт `build` и в WARN, в файл — нет («config drift» — операторский словарь).
- Следствие §4 заявляю сразу: чистого бездрейфового файла на реальной книге на этом HEAD НЕТ — чистый
- путь доказывается синтетикой, реальные книги — посадки на дыры.
-- Оглавление и `` при `Heading==""` — номер главы цифрами (пустая ссылка nav невалидна; цифры —
- единственный лейбл, который не решает открытый К-3 «какой лейбл видит читатель у главы без заголовка»;
- словесный шаблон в данных — 1 строка после ратификации, вопрос владельцу в отчёте). При `Heading!=""` —
- срез известного префикса `heading+"\n\n"` из `FinalText` (`chunker.go:186-192`), `` = Heading.
-- Абзац = непустая строка `FinalText`. Замерено на `minirun/export.json`: юнит 1/0 — 14 разделителей `\n\n`
- и 7 одиночных `\n`, юнит 2/0 — 56 и 0: редактор чередует их без семантики, различать = выдумать
- различие; строка — единица абзаца исходника-вебновеллы. Круг §4 сравнивает абзацы ингеста с абзацами,
- которые положил писатель.
-- Метаданные: `dc:title` = `config.Book.Title` как есть (на стенде `蛊真人` — ограничение в отчёт), `dc:language`
- = `TargetLang`, `dc:identifier` = `urn:textmachine:book:`, `dc:creator` нет (источника нет).
-- 0 юнитов — отказ `sourceHasNoContent` (spine без элементов невалиден); 1 юнит — обычная книга.
-
-**Что НЕ беру:** платформу и дверь `createExport`/`getExport`; лестницу D25.1 в коде и в `BookExport`;
-строки 160/201 (`ApplyHeading` и три точки склейки не трогаю; модельные заголовки в прозе не извлекаю и не
-правлю); `--resnapshot` и любые платные вызовы; `langpack_root` в копию acceptance; направление письма
-(`dir`/`page-progression-direction`) — в `internal/lang` данных о направлении нет (`lang-script.txt` —
-только скрипты), RTL-цели в репо нет → вопрос в отчёт, не литерал; CSS/обложку; новые зависимости.
-
-**Чем докажу:** герметично — `bookfile` (mimetype первым/stored, nav не в spine, детерминизм двух сборок,
-экранирование, 0/1 глава), `pipeline` (круг `IngestEncoded` равенством абзацев на прогоне fake-провайдера;
-pending через потолок; withheld через санитайзер; **ghost — усадка исходника после прогона (посадки в
-тестах не было, строю)**; drift — бамп `prompt_version`; синтетический `BookExport` на incomplete), `cmd/tmctl`
-(incomplete бинарём через `setupGapProject`; парс флагов; exit 16 через totality-тест), `lang` (парс
-`reader.txt`; `Version()` не меняется от его наличия). На копиях книг в песочнице с переписанными путями:
-minirun — оракул июля 14/14 по `final_text/snapshot_id/disposition`, `current_snapshot` до/после
-`reader.txt`, `cmp` двух ПРОЦЕССОВ, epubcheck 5.3.0 `0 fatal / 0 error`, круг ингестом; acceptance — отказ с
-перечнем и `--partial`-файл с несловесными маркерами; coldrun-a — отказ 14/14 pending;
-`git -C books status --short -- gu-zhenren` до/после одинаков (снят до старта: 6 строк `D …-wal/-shm`).
-`make battery` + `-race`; в середине — субагент-ревью готовой части против критериев; в конце —
-адверсариальный проход по направлениям §4.
-
-### ✅ ИТОГ — пак «писатель книги» (промт `docs/archive/prompts/BACKEND_BOOKWRITER_PACK_SESSION_PROMPT_2026-08-30.md`, строка 236), сессия `textmachine-main-fc`, 30.08
-
-**Что построено (зона `backend/`, поверх `67c05be`; НЕ закоммичено — дерево на лендинг оркестратору; `git status`: 10 изменённых + 8 новых путей в `backend/`, плюс этот журнал).**
-- `internal/bookfile/` (новый прод-пакет, только stdlib, без `testing`): `container.go` — OCF-контейнер (`mimetype` первым, `Store`, через `CreateRaw` — без data-descriptor, флаги `0x0000`; `container.xml`; entry в порядке вызовов; нулевые zip-таймметки); `epub.go` — EPUB 3 (`dc:identifier`+`unique-identifier`, `dc:title`, `dc:language`, `dcterms:modified`, nav `properties="nav"` ⛔ не в spine, XHTML на главу: `` + `
`); `txt.go` — чистый текст; `model.go` — модель `Book/Chapter`, `Blocks(i)` (единственное определение содержимого документа главы), `CleanText` (общая чистка XML-недопустимых символов для обоих форматов), экранирование.
-- `internal/chunk/chunktest/epub.go` переведён на `bookfile.NewContainer`; тест-декои (OPF-заглушка, `
c