# Промт: бэкенд-сессия — подготовка приёмки Ф1 на 蛊真人 (fix-лист ревью + GB18030 + дешёвые гейты + спека D15.2 v2), 2026-07-09

---

## Кто ты и где ты

Ты — **бэкенд-сессия** проекта **TextMachine**: Go-бэкенд издательского художественного перевода крупных текстов (ранобэ/вебновеллы, zh/ja/en→ru) через мультиагентный LLM-пайплайн (черновик DeepSeek → монолингвальный редактор grok-4.3 → судья Gemini в Фазе 2). Проект работает параллельными сессиями со строгими зонами: твоя зона записи — **`backend/`** + твоя запись в `docs/PROGRESS.md` §Бэкенд. `docs/` (кроме журнала) и `eval/` НЕ редактировать — расхождения оформляй пингом оркестратору в журнале. Корневой `CLAUDE.md` автозагружен в твой контекст — его гардрейлы жёсткие: **`.env` не читать; DeepSeek thinking НИКОГДА не отключать (эхо-мина); слаги моделей не менять без live-фактчека; коммитить только по просьбе владельца; никаких reset --hard/перезаписей истории при возможных чужих незакоммиченных правках**.

## Онбординг с нуля (порядок чтения, ~30 мин)

1. `CLAUDE.md` (уже в контексте) → `docs/README.md` (карта) → CURRENT-STATE в `docs/PROGRESS.md`.
2. **`docs/architecture/05-decisions-log.md` ЦЕЛИКОМ** — ратифицированный контракт (D1–D18). Твой мандат: §«Ратификации 09.07» п.5 (fix-лист), **D18** (приёмка теперь на 蛊真人 zh→ru — GB18030 на тебе), доработка спеки D15.2 (там же, п.2 ратификаций).
3. `backend/README.md` — карта пакетов + 7 инвариантов «ломать нельзя» + известный техдолг.
4. `docs/architecture/07-strategic-review.md` §4.3–4.4, §6–8 — почему эти фиксы существуют (каждая находка воспроизведена исполнением).
5. По ходу работы: `03-implementation-notes.md` (контракты), `docs/experiments/00-provider-quirks.md` (перед любой правкой адаптеров/конфига моделей).

Состояние на входе: Фаза 0 ✅; машинерия Ф1 построена (память v2 + фиксы D16, chunker v4, disposition, coverage, single-hop эскалация с ре-гейтом, `tmctl status`/`redrive`, reasoning-буфер additive). Предыдущий пакет прошёл внешнее ревью (ACCEPT_WITH_FIXES) — ты закрываешь его fix-лист и готовишь машину к первому реальному прогону целой книги.

Дисциплина: каждый фикс — с регресс-тестом, **mutation-verified** (реверт фикса валит именно его тест); финал — агентское адверсариальное селфревью (несколько дименсий → независимая refute-by-default верификация каждой находки); `go build/vet/test ./... -race` зелёные + `tmctl report` $0 перед сдачей. Живые LLM — только там, где явно сказано (задача 5), с потолком.

## Задача 1 — fix-лист внешнего ревью (порядок жёсткий, это первым)

1a. **[major] Homophone first-wins** (`memseed.go`, attachRubyAliasesToManual): чтения обрабатываются в сортировке по Base → при ДВУХ ручных омофонах (разные dst, чтение ≥4 каны, напр. 高梁→Такарё / 高橋→Такахаси, оба читаются たかはし) алфавитно-первая база успевает получить kana-алиас ДО того, как collides() увидит второго владельца → каждое かな-вхождение инжектится **CONFIRMED за произвольную из двух сущностей** (класс A2 «неверная авторитетная инъекция»). Фикс: ПЕРЕД аттачем сгруппировать чтения по нормализованному ключу МЕЖДУ разными базами; ключ, принадлежащий ≥2 базам с разными dst, — skip-and-log (или форс AMBIGUOUS) для ВСЕХ владельцев, не только опоздавших. Для ≤3-кана дыры нет (collision-prone → AMBIGUOUS) — не регресси.
1b. **[major] Закрепить мутационно инвариант redrive «DispOK-стадии НЕ сбрасываются»**: сейчас мутант `Disposition==Flagged||Skipped → true` в Runner.Redrive переживает весь набор (тесты флагают ПЕРВУЮ стадию — сброс совпадает с полным). Добавь тест «draft=ok, edit=flagged → сбрасывается ТОЛЬКО edit, draft резюмится за $0» + тест НЕсовпадающего `--reason`-селектора (сейчас его игнор тоже выживает).
1c. **[minor] Snapshot-чек ДО ResetChunkStages**: сейчас redrive сначала сбрасывает строки, потом падает на config-drift/потолке — флаг-телеметрия уничтожена, status показывает pending/pass. Посчитай текущий snapshotID и сравни с хранимым ДО деструктивной части (read-only расчёт уже есть в Status/ConfigDrift).
1d. **[minors, пакетом]**: `tmctl status --json` — при flagged>0 либо возвращать sentinel/exit 2 как human-режим, либо явно задокументировать «--json всегда 0»; human-подсказка при gate-промоченном glossary_miss НЕ должна советовать redrive (он для него no-op — советуй правку глоссария + --resnapshot); README «миграции v1–v5» → v1–v6; ETA — либо EWMA (как ратифицировано D12), либо явная пометка отступления; collides() в ruby-attach — учесть windowsOverlap и dst-eligibility владельцев (сейчас консервативные ложные скипы = потеря recall, направление безопасное); source-edit-невидимость для status — сузить overclaim-комментарий bookChunks (правка исходника без смены границ невидима) или сверить content_hash с $0-перерендером.

## Задача 2 — GB18030/кодировки в ingest (гейтит D18-прогон)

Реальные zh .txt — часто GB18030, не UTF-8 (приёмочная книга 蛊真人 — ровно этот случай; полигон уже конвертировал свои сэмплы руками). Сделай в `ingest.go`: детект кодировки для .txt (порядок: BOM → валидный UTF-8 → проба GB18030 (надмножество GBK/GB2312) → fail-loud «неопознанная кодировка, укажи явно») + конверсия в UTF-8 ДО NormalizeSource; опция явного указания в book.yaml (`encoding: gb18030|utf8`, дефолт auto). Зависимость `golang.org/x/text/encoding/simplifiedchinese` — допустима (первая внешняя за пределами go.sum-минимума — отметь в журнале). Эвристика детекта консервативная: сомнение = fail-loud, не тихая порча (инвариант lossless-чанкера: битые байты НЕ должны доехать до U+FFFD-замены). Тесты: GB18030-файл с CJK+пунктуацией, UTF-8 без BOM, UTF-8 c BOM, битый файл → loud.

## Задача 3 — дешёвые детерминированные гейты Ф1 (04-unhappy §6/§9; в план v3 внесены, не реализованы)

Четыре флаггера по паттерну post-check (наблюдаемость, НЕ жёсткие гейты; на ФИНАЛЬНОМ тексте чанка; версия каждого свёрнута в snapshot по образцу classifierVersion — правка правил = громкий resnapshot):
- **Линтер тире-диалогов** (Розенталь §47–52): реплики через кавычки-ёлочки/дефис вместо тире с новой строки, смешение стилей внутри главы.
- **Ёфикатор**: наличие «ё» непоследовательно (частичная ёфикация — флаг; политика все-ё/все-е — из brief).
- **Блок-лист транслит-междометий**: «ара-ара», «маа», «хмф», «нани» и т.п. без перевода (словарь — конфиг, стартовый набор из 04-unhappy §9).
- **Число-гейт разрядов 万/億**: китайские/японские разряды в исходнике ↔ числа в выходе (万=10⁴, 億=10⁸; «三万» ≠ «3 миллиона») — детект несоответствия порядка величины.
Каждый: `flag_reason`-константа, счётчики в отчёте/паспорте главы, юнит-тесты на срабатывание и НЕсрабатывание (ложные позитивы — главный риск: цитаты, стилизация).

## Задача 4 — спека D15.2 v2 (документ, НЕ код; реализация остаётся заблокированной)

Доработай `backend/docs/D15.2-content-addressed-resume-spec.md` по трём дырам ревью (полный разбор — D-лог §Ратификации п.2): (1) fast-path-гард обязан покрывать ВЕСЬ wire stage-план (model/temp/reasoning/maxTokens-деривация/escalate_to) — отдельный guard-хеш в chunk_status, НЕ входящий в RequestHash, либо верификация пересчётом с сохранением параметров победившей попытки; (2) расщепление memory_version — ОБЯЗАТЕЛЬНАЯ часть дизайна (подсказка ревью: postcheck пересчитывается вживую и в chunk_status не хранится → memory_version можно целиком убрать из ключа вызова; реши судьбу gate:bool и decl-контента явно); (3) замена loud-гейта согласия: pre-flight dry-run «N чанков будет re-bill, проекция ~$X» с порогом, выше которого нужен явный флаг (Р6-класс согласия). Плюс: полевой маппинг ВСЕХ полей текущего snapshotID → {wire|verdict|dropped+why}; судьба chunk_status.snapshot_id и status-ридеров; sequencing миграции (ДО первой онгоинг-книги — иначе миграция съедает бэклог); blast-radius append-а моделировать со sticky(depth 2)+eviction+каскадом на editor. Сдай v2 оркестратору на утверждение.

## Задача 5 — подготовка D18-прогона на 蛊真人 (smoke, не полная приёмка)

Файл книги: **`/home/ubuntu/books/gu-zhenren/guzhenren-gb18030.txt`** (полная вебновелла ~2.5k глав, 15 МБ, GB18030+CRLF, заголовок «书名：蛊真人» — проверено оркестратором). Текст и ЛЮБЫЕ производные (чанки, переводы, глоссарий с цитатами) — **ВНЕ git** (Р8: приватная обработка легальна; в журнал — только метрики/статистику). Сделай: (а) прогон ingest+chunker на реальном файле (после задачи 2) — детект глав в этом формате (главы, вероятно, маркированы «第N章» — проверь и доработай главоделение txt-инжеста, если сейчас только `\f`), число глав/чанков/токен-статистика в журнал; (б) минимум одна фолбэк-модель черновика в конфиге с `escalate_to` (D18: эхо 25% требует живой эскалации; модель — из заведённых, напр. glm-5 или grok-4.3 draft-фолбэком; цены/квирки сверь с 00-provider-quirks); (в) smoke-прогон **1 главы** draft→edit на живых ключах с потолком $0.10: деньги в request_log сходятся, эхо-флаги/эскалация срабатывают, redrive на реальном флаге работает; (г) список блокеров полной приёмки (глоссарий-сид от полигона, пороги, что ещё) — в журнал. Полная приёмка — отдельная сессия по готовности сида.

## Приёмка сессии

`go build/vet/test ./... -race` зелёные; фиксы mutation-verified; селфревью проведено и находки закрыты; smoke-прогон задачи 5 с цифрами; спека D15.2 v2 сдана; запись в `docs/PROGRESS.md` §Бэкенд (итоги, цифры smoke, блокеры приёмки, вопросы оркестратору). Порядок: 1 → 2 → (3 ∥ 4) → 5.
