# Малая пачка: ingest грязных епабов (14а) + комментарии промпт-файлов (14б) **База:** записка оркестратора №8 от 30.07, санкции владельца 26.07 (бэклог `docs/PROGRESS.md`, строки 14а/14б). **Зона:** `backend/`. **Деньги сессии: $0** — ни одного вызова провайдера, вся приёмка на локальном сырье. **Статус:** построено и проверено исполнением. Сессия НЕ коммитит, лендинг — оркестратора. > **Ревью-шапка (оркестратор №9, 30.07): ПРИНЯТО И ЗАЛЕНДЕНО, D39.54.** Приёмка исполнением на > неподвижных копиях (старая = HEAD, новая = деливерабл): собственный дампер old-vs-new по трём епабам > стенда — 205 документов, дифф глав и ruby ПУСТ (3.29 МБ на сторону); полный сьют `-race -count=1` > 14/14 зелёный, gofmt/vet чисто; четыре спот-мутации вне порядка сессии (D — SHA по сырому, M8 — > нейтрализация вырезания, M7 — raw-text везде, M10 — flushRuby в no-op) — все КРАСНЫЕ, восстановление > зелёное. Финальная сверка сессии (§2.8, несбалансированный ruby — третий улов ревью) вошла в приёмку: > копии сняты ПОСЛЕ фикса, мутационная таблица сессии 17/17. Посылки > перемерены независимо: 126 itemref (не 958) · 8/8 книг стенда txt · ровно 2 сущности из 252 расходятся > (кросс-чек через WHATWG-таблицу python и GOROOT-таблицу `xml.HTMLEntity`) · цитата `snapshot.go:138` > дословна · grep `terminolog` по `snapshot.go` пуст. Диспозиции: CDATA (§7.4) — В СКОУПЕ (без неё > переезд = регрессия на валидном XHTML); chunkerVersion НЕ поднят — ратифицировано D39.54 (экспозиция — > пустое множество); mimetype — верность формату, не фикс поведения (§7.5 принят, в D-ноте так и > записано). Фикс-лист (1): комментарий поля `SHA256` в `render.go:89` остался «hash of the raw file» — > одна строка, на ближайшее касание. Кандидат §8 (`` без XML-объявления) — бэклог 34а. > **Две поправки к посылкам записки — читать до §1.** Обе найдены замером, обе меняют формулировки > приёмки, ни одна не меняет решение строить. > > 1. **«Empire of the Dawn, 958 документов spine» — неверно.** В книге **126** `` (288 записей > zip, 283 `` манифеста, из них 154 `.jpg`). Число 958 не соответствует ничему в файле. Сравнение > проведено на **всех трёх** епабах стенда — 205 документов суммарно. > 2. **«Ingest выполняется при создании книги — существующие БД и снапшоты не трогаются» — обоснование > неверно, вывод верен.** `TranslateBook` вызывает `chunk.IngestEncoded` и `SplitChunks` на **КАЖДОМ > прогоне** (`bookrun.go:112,140`; то же в `status.go:190,194`) — источник переизвлекается и > перерезается каждый раз. Существующие БД защищены другим фактом: **все книги стенда — txt/gb18030** > (`book.yaml` восьми проектов `gu-zhenren/*`), а `extractXHTML` достижим только из `ingestEPUB`. > Ни одна существующая книга епаб-путь не проходит. Подробно — §6. --- ## §1 Что построено | № | Пункт | Где | |---|---|---| | 14а-1 | `extractXHTML` на токенайзере `x/net/html` вместо `encoding/xml` | `chunk/ingest.go` | | 14а-1а | Паритетные помощники: `voidTags`, `rawTextTags`, `tokenTagName`, `checkXHTMLCharset`, `unwrapCDATA`, `flushRuby` | там же | | 14а-2 | `Chapter.EntryName` + два теста (percent-href, `#fragment`) | `chunk/chunktest/epub.go`, `chunk/ingest_test.go` | | 14а-3 | `mimetype` фикстуры через `zip.Store` + тест-пин OCF | `chunk/chunktest/epub.go`, `chunk/ingest_test.go` | | 14б-1 | Вырезание `` ДО сплита по `---USER---` | `pipeline/render.go` (`stripPromptComments`) | | 14б-2 | SHA по канонической (очищенной) форме | там же, `LoadPromptTemplate` | | 14б-3 | Шапка `terminologist.md` ужата 12 строк → 2 | `prompts/zh-ru/terminologist.md` | | 14б-4 | Тест-пины + мутации | `pipeline/promptcomments_test.go` | Диффа: 5 отслеживаемых файлов +651/−97 (из них `ingest.go` +216/−70, `ingest_test.go` +374) плюс новый `promptcomments_test.go` (161 строка). --- ## §2 14а — переезд на токенайзер ### 2.1 Четыре класса: КРАСНЫЕ до, ЗЕЛЁНЫЕ после Приёмка «красное-до» снята не рассуждением, а **исполнением оригинальной функции**: старый `extractXHTML` извлечён дословно из `git show HEAD:backend/internal/chunk/ingest.go` и прогнан по тем же фикстурам рядом с новым. Старый на всех четырёх — жёсткая ошибка и **пустой текст**, то есть в `ingestEPUB` это `return nil, err`: один грязный документ убивал импорт всей книги. | Класс | Старый `encoding/xml` | Новый токенайзер | |---|---|---| | голый `<` в прозе | `XML syntax error on line 3: expected element name after <` | `"Если a < b, то дальше.\n\n\n\nВторой абзац."` | | перехлёст тегов | `XML syntax error on line 3: unexpected end element ` | `"жирный оба курсив хвост."` | | содержимое `