Ratify D23: refactor package accepted with proven equivalence, golden guard as invariant eight, OpenReadOnly sanctioned; issue acceptance session prompt, sync docs
This commit is contained in:
parent
296419c8ae
commit
c59dc77f01
10 changed files with 74 additions and 12 deletions
|
|
@ -14,7 +14,7 @@ Go-бэкенд издательского художественного пер
|
|||
|
||||
## Источники истины (по убыванию)
|
||||
|
||||
1. **`docs/architecture/05-decisions-log.md` (D1–D22)** — ратифицированный контракт; при конфликте с любым другим доком побеждает он.
|
||||
1. **`docs/architecture/05-decisions-log.md` (D1–D23)** — ратифицированный контракт; при конфликте с любым другим доком побеждает он.
|
||||
2. `docs/architecture/07-strategic-review.md` — стратегический аудит 09.07 (вердикт, риски, курс-коррекции).
|
||||
3. `docs/experiments/00-provider-quirks.md` — wire-квирки провайдеров (читать ПЕРЕД правкой адаптеров/вызовами провайдеров).
|
||||
4. `docs/architecture/01-decisions.md` (Р1–Р10), `02-mvp-plan.md` (фазы v3), `04-unhappy-paths.md`, `06-memory-risk-registry.md`.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# backend/ — Go-бэкенд TextMachine
|
||||
|
||||
Зона сессии «Бэкенд». Контракт — `docs/architecture/05-decisions-log.md` (D1–D22); контракты Фазы 0 — `03-implementation-notes.md`; квирки провайдеров — `docs/experiments/00-provider-quirks.md`. **`.env` не читать.**
|
||||
Зона сессии «Бэкенд». Контракт — `docs/architecture/05-decisions-log.md` (D1–D23); контракты Фазы 0 — `03-implementation-notes.md`; квирки провайдеров — `docs/experiments/00-provider-quirks.md`. **`.env` не читать.**
|
||||
|
||||
## Карта пакетов
|
||||
|
||||
|
|
|
|||
46
docs/ACCEPTANCE_SESSION_PROMPT.md
Normal file
46
docs/ACCEPTANCE_SESSION_PROMPT.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# Промт: приёмочная сессия Фазы 1 — 蛊真人 zh→ru end-to-end (2026-07-10)
|
||||
|
||||
Скопируй в новую сессию Claude Code в `/home/ubuntu/projects/textmachine`. **Предусловие: чистое дерево** (пакет №4 залендён; `git status` — если в `backend/` чужие незакоммиченные правки, стоп и пинг владельцу).
|
||||
|
||||
---
|
||||
|
||||
## Кто ты и что принимаешь
|
||||
|
||||
Ты — **приёмочная сессия Фазы 1**: прогоняешь реальную книгу end-to-end и выносишь вердикт по критериям приёмки. Приёмка — **инфраструктурная веха** (деньги/resume/гейты/консистентность; художественное качество меряет пилот Ф2.5 — не ты). Зона записи: `backend/` (только фиксы найденных багов, с тестами) + своя секция в `docs/PROGRESS.md` («## Приёмка Ф1»). **Ничего не коммитить** — лендинг у оркестратора. Гардрейлы `CLAUDE.md` жёсткие: `.env` не читать (ключи сорсятся скриптами/командами); книга и ВСЕ производные (store.db, выходные тексты, отчёты с цитатами) — ВНЕ git; 18+ уровень 3 — не обрабатывать (в 蛊真人 его нет — корпусные аудиты чисты, но правило в силе); никаких деструктивных git-операций.
|
||||
|
||||
## Онбординг (~40 мин)
|
||||
|
||||
1. `CLAUDE.md` → CURRENT-STATE в `docs/PROGRESS.md` → **`docs/architecture/02-mvp-plan.md` (критерии приёмки Ф1 — твой чек-лист)**.
|
||||
2. `docs/architecture/05-decisions-log.md`: **D18** (книга/скоуп), **D10** (знаменатель консистентности = ВСЕ approved-термины, порог 98%), **D11** (приёмка по стоимости = механизм budget_usd + точность телеметрии, жёсткие $-гейты СНЯТЫ; sanity — пропорции exp08), **D20.3** (glm-5-редактор допустим), **D22.11** (`escalation.budget_usd>0` ОБЯЗАТЕЛЕН), D2/D12 (диспозиции, паспорта, redrive).
|
||||
3. `backend/README.md` (инварианты, golden-гард, как гонять) + `docs/experiments/00-provider-quirks.md` + `08-cost-model-v2.md` (ценовая модель для сверки).
|
||||
4. Материал: книга `/home/ubuntu/books/gu-zhenren/guzhenren-gb18030.txt` (GB18030; smoke дал 2283 главы / 5088 чанков), сид `/home/ubuntu/books/gu-zhenren/guzhenren-seed.yaml` (49 записей, финализирован D19.3/D22: 白凝冰 gender=hidden).
|
||||
|
||||
## Конфигурация прогона (по контракту, не по вкусу)
|
||||
|
||||
- **Стадии:** draft = deepseek-v4-flash (thinking ON — эхо-мина; temperature там wire-no-op — известно, не чинить) → editor = **glm-5** (D20.3: чистого xAI-ключа нет; grok-4.3 НЕ гонять на книжном контенте текущим ключом — гигиена D8/D19.4); draft `escalate_to` = deepseek-v4-pro (заведён пакетом №3).
|
||||
- **Деньги:** `escalation.budget_usd > 0` (иначе echo-эскалация не стреляет — D22.11); потолок книги/дня выставить из этапности ниже; ledger-числа сверять с exp08-пропорциями.
|
||||
- Гейты — дефолт конфига (coverage zh-ru коридор [2.2,4.2]; postcheck-гейт OFF — флаги пишутся; cheap-gates как наблюдаемость). Промпты/пороги НЕ менять (правка промпта = resnapshot = переоплата — D15; анти-эхо правки гейтятся отдельно D21.6).
|
||||
|
||||
## Этапность (деньги — по нарастающей, с чекпоинтом владельца)
|
||||
|
||||
- **Этап A — срез 25 глав (~$0.3–0.6 по exp08-пропорции).** Полный цикл: ingest → прогон → паспорта → верификация ниже. По итогам — промежуточная запись в PROGRESS с деньгами/flag-rate и **СТОП: подтверждение владельца на полный прогон** (полная книга 2283 главы ≈ $25–55 по модели — это его согласие на трату, Р6).
|
||||
- **Этап B — полная книга** (после «да» владельца, с его потолком). Ночной прогон под супервизором (`tmctl` перезапускается — D4/D12); resume обязан подхватывать.
|
||||
|
||||
## Что верифицировать (приёмочный чек-лист, каждое — исполнением)
|
||||
|
||||
1. **Деньги:** `committed == SUM(checkpoints)` на живом прогоне; **kill -9 посреди этапа A** (настоящий SIGKILL) → resume без переоплаты байт-идентичных запросов; потолок: искусственно низкий `budget_usd` → прогон останавливается ЧЕСТНО (committed+reserved), возобновляется после поднятия.
|
||||
2. **Гейты/диспозиции в бою:** echo-эскалация реально стреляет и ре-гейтится (deepseek-эхо ~25% на этой книге — exp10); refusal/empty → flag+skip+continue, мусор в TM не коммитится; flagged-чанки переатакуются `tmctl redrive` (продемонстрируй на реальном флаге); `tmctl status` живой во время прогона (OpenReadOnly, пакет №4) — паспорта глав/N из M/деньги.
|
||||
3. **Консистентность (D10):** по завершении — замер: числитель = вхождения approved-dst (лемма по decl), знаменатель = вхождения src/алиасов ВСЕХ approved-терминов; порог **≥98%**; names-only — как под-метрика. Отчёт: где промахи, класс (инъекция не сработала / модель проигнорила / decl).
|
||||
4. **Телеметрия/паспорта:** `report`/`status --json` — chunks ok/flagged/skipped, worst reason, вердикты pass|attention|fail, $/глава; **первый замер G2**: flag-rate на главу на реальной книге (стратревью §8.10 — ёмкость человеческой петли).
|
||||
5. **Санити стоимости:** $/глава и доля редактора против exp08-модели (~90% стоимости на редакторе; glm-5 дешевле grok — пересчитай ожидание честно, не подгоняй).
|
||||
6. **Стиль-флаггеры:** счётчики по книге (наблюдаемость), примеры срабатываний БЕЗ длинных цитат книги в git-доки.
|
||||
|
||||
## Дисциплина находок
|
||||
|
||||
Баги чинить можно (зона твоя), но: фикс = минимальный + тест (mutation-verified где применимо); **golden-гард обязан остаться бит-в-бит** — если фикс меняет wire/вердикты, это НЕ багфикс, а изменение поведения → СТОП и пинг оркестратору (не обновляй golden сам); правки промптов/конфиг-семантики — запрещены. Всё странное от провайдеров — правило двух направлений (вендор-дока, не гадание — шапка quirks).
|
||||
|
||||
## Deliverable и приёмка сессии
|
||||
|
||||
1. Запись в `docs/PROGRESS.md` («## Приёмка Ф1»): таблица чек-листа (пункт → как проверено → результат), деньги этапов (committed/reserved/потолки, $/глава, доля стадий), консистентность D10 с разбором промахов, G2 flag-rate, список багов+фиксов, **вердикт: критерии 02-mvp-plan выполнены / не выполнены / выполнены с оговорками**.
|
||||
2. Вопросы владельцу — отдельным блоком (включая «этап B: да/нет/потолок» после этапа A).
|
||||
3. Производные книги (store.db, выходы, срезы) — вне git; в отчёте цифры и короткие иллюстрации, не тексты глав. Ничего не коммитить.
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
# Журнал прогресса
|
||||
|
||||
> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (обновляемый блок; на 2026-07-10). **Источник истины по РЕШЕНИЯМ — `architecture/05-decisions-log.md` (D1–D22); этот файл — ЖУРНАЛ, не спека.**
|
||||
> - **Фаза:** 0 ✅; машинерия Ф1 построена (пакеты №1–3 бэкенда: память v2+D16, status/redrive, GB18030-ingest, стиль-флаггеры, D15.2-спека v3, цепочка D3/канал B в конфиге, additive_total-биллинг Gemini; пакеты №1–3 полигона: пилот-харнесс, exp10 violence, **exp11 erotica — D14.4 ЗАКРЫТ, все critical сняты**; сид 蛊真人 финализирован). Все пакеты залендены после внешнего ревью; research/15 принят (D21), пакеты №3 ратифицированы (D22). **Приёмка Ф1 = 蛊真人 zh→ru (D18) РАЗБЛОКИРОВАНА** — остался промт приёмочной сессии (glm-5-редактор допустим D20.3; `escalation.budget_usd>0` обязателен — D22.11). Очередь: приёмка → бэкенд-№4 рефакторинг (промт выдан) → GPT-восхождение (промт выдан); порядок приёмка↔рефакторинг — за владельцем. Реализация D15.2 — после v3.1-правок (D22.2). Решающая точка — пилот Ф2.5 (блокеры: чистый xAI-ключ, корпус 25–35 глав, аннотаторы ≥3, проба судьи-дублёра 18+ — D22.6).
|
||||
> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (обновляемый блок; на 2026-07-10, вечер). **Источник истины по РЕШЕНИЯМ — `architecture/05-decisions-log.md` (D1–D23); этот файл — ЖУРНАЛ, не спека.**
|
||||
> - **Фаза:** 0 ✅; машинерия Ф1 построена и отрефакторена (бэкенд №1–4: память v2+D16, status/redrive, GB18030-ingest, стиль-флаггеры, спека D15.2 v3, цепочка D3/канал B, additive_total-биллинг Gemini, **runner → 8 файлов + golden-гард детерминизма (инвариант №8) + OpenReadOnly-status при живом прогоне — D23**; полигон №1–3: пилот-харнесс, exp10 violence, **exp11 erotica — D14.4 ЗАКРЫТ, все critical сняты**; сид финализирован). Все пакеты залендены после внешнего ревью (D21–D23). **Готовы к запуску владельцем (параллельны):** приёмочная сессия Ф1 (`ACCEPTANCE_SESSION_PROMPT.md`: этап A 25 глав → стоп-чекпоинт → полная книга; glm-5-редактор D20.3; `escalation.budget_usd>0` D22.11) · GPT-восхождение (деблокировано — рефакторинг залендён) · ридер-IDE ресёрч. Реализация D15.2 — после v3.1-правок (D22.2). Решающая точка — пилот Ф2.5 (блокеры: чистый xAI-ключ, корпус 25–35 глав, аннотаторы ≥3, проба судьи-дублёра 18+ — D22.6).
|
||||
> - **Стек:** черновик DeepSeek V4 Flash (thinking ON — эхо-мина; temperature там wire-no-op) · редактор **grok-4.3** `reasoning_effort:none` (D1-монолингв оспорен — решает пилот-арм D13.1/D17) · судья/апекс Gemini 3.1 Pro (**wire-слаг `-preview`**; mandatory thinking; биллинг `additive_total` — D22.3) · эскалация A: DeepSeek V4 Pro → GLM-5.1 → Gemini-preview (заведена, пакет №3) · **канал B (18+): переводчик Mistral (18/18 чист вкл. эротику) · эскалация grok-4.3 reasoning-ON (⚠ НЕ на архаичных zh — register-оговорка D22.5) · abliterated-скрининг · судьи: эротика — Grok (дублёр гейтится пробой D22.6), violence/SFW — Grok+Gemini** (DeepSeek в explicit запрещён ToS — D14.1). Anthropic выброшен, OpenAI оставлен. 7 ключей.
|
||||
> - **Экономика:** `experiments/08-cost-model-v2.md` (~$0.69 ранобэ / ~$10.94 вебновелла-500). ⚠ Resume: любой `--resnapshot` = переоплата книги — онгоинг гейтится D15.2 (v3.1 → реализация); exp08 v3 (annotator/voice-строки) заказан D21.8. Gemini-недоучёт 146×/вызов закрыт additive_total (D22.3).
|
||||
> - **Ждём от владельца:** чистый xAI-ключ без data-sharing (блокер пилота, не приёмки — D20.3) · провенанс двух внешних 12-*-доков · решение по юр-пакету · порядок «приёмка ↔ рефакторинг».
|
||||
|
|
@ -110,6 +110,12 @@
|
|||
- **Промты выданы (по заданию владельца):** [`GPT_EXTERNAL_ASCENT_PROMPT.md`](GPT_EXTERNAL_ASCENT_PROMPT.md) (внешняя критика GPT-5.6, анти-якорный трёхфазный протокол) и [`BACKEND_SESSION_PROMPT_REFACTOR.md`](BACKEND_SESSION_PROMPT_REFACTOR.md) (пакет №4: код-хелс + golden-гард детерминизма). Закрытые промты №3/erotica — в архив.
|
||||
- **Приёмка Ф1 разблокирована полностью** (D22.11): следующий деливерабл оркестратора — промт приёмочной сессии.
|
||||
|
||||
### 2026-07-10 (вечер) — Приёмка рефакторинг-пакета №4 + D23 (оркестратор)
|
||||
|
||||
- **Внешнее ревью** (5 ревьюеров, всё исполнением): эквивалентность «форма, не поведение» доказана трижды независимо — новый golden на ЧИСТОМ HEAD-коде PASS байт-в-байт; чувствительность golden 5/5 мутаций; AST-дифф 36 деклараций (0 потеряно, 7 изменены только заявленно); CLI байт-идентичен исполнением двух бинарей; 9/9 мутаций инвариантов убиты; миграции/промпты/конфиги sha256-нетронуты. Вердикты ACCEPT ×2 + ACCEPT_WITH_FIXES ×3 → **залендён (296419c), ратифицирован D23** (golden-гард = инвариант №8; OpenReadOnly санкционирован с трейд-оффом reserved-хвоста; fix-лист мелочи — с реализационным пакетом D15.2).
|
||||
- Микро-фиксы оркестратора: diffstat +3317, фикстура 4гл/11 тел, оговорка про тест-непокрытые лог-фиксы; line-refs старого runner.go починены в 06/07/research-13 (историю не переписывал); backend/README техдолг-строка синкнута с D22.
|
||||
- **Промт приёмки Ф1 выдан** (`ACCEPTANCE_SESSION_PROMPT.md`); GPT-восхождение деблокировано (условие владельца «после рефакторинга» выполнено). Оба запуска + ридер-IDE ресёрч — параллельны и независимы.
|
||||
|
||||
## Бэкенд
|
||||
|
||||
### 2026-07-04 — Сессия 1: шаг 0 (перевалидация) завершён
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@
|
|||
|
||||
## Структура
|
||||
|
||||
- `architecture/` — синтез. **Источник истины по решениям — [`05-decisions-log.md`](architecture/05-decisions-log.md) (D1–D22); при конфликте с любым доком он выше.**
|
||||
- `architecture/` — синтез. **Источник истины по решениям — [`05-decisions-log.md`](architecture/05-decisions-log.md) (D1–D23); при конфликте с любым доком он выше.**
|
||||
- `01-decisions.md` — принципы Р1–Р10; `02-mvp-plan.md` — фазы и приёмка (v3, 09.07); `03-implementation-notes.md` — контракты Фазы 0; `04-unhappy-paths.md` — ~70 режимов отказа → механизм; `06-memory-risk-registry.md` — реестр рисков банка памяти; **[`07-strategic-review.md`](architecture/07-strategic-review.md) — стратегический аудит (09.07): вердикт end-to-end, топ-риски, курс-коррекции**; `components.puml`/`pipeline.puml` — диаграммы v3 (владелец смотрит PlantUML-расширением VS Code; вручную НЕ рендерить).
|
||||
- `experiments/` — эмпирика «Полигона»: `00-provider-quirks` (читать перед любым вызовом провайдера), `01-token-calibration`, `02-refusal-benchmark`, `03-local-stand`, `04-editor-quality`, `06-local-extraction`, `07-coverage-precision`, `08-cost-model-v2` (актуальная денежная модель), `09-pilot-protocol` (пилот Ф2.5 + поправки D13), `10-explicit-benchmark` (18+ violence-рука канала B), `11-erotica-benchmark` (erotica по трём парам/регистрам — закрытие D14.4, D22).
|
||||
- `research/` — фактура исследований 04–05.07: `01–10` базовые, `11-gap-*` добор критиком, `12-*` режимы отказа/отзывы/таксономии (+ два внешних материала с провенанс-шапками), `13` валидация памяти, `14` адаптивная память, `15` голос и состояние (принят, D21). ⚠ Часть под superseded-баннерами (01/02/03/04/05/09 и gap-1/2/5) — **читай баннер прежде содержимого**.
|
||||
- `PROGRESS.md` — **журнал** (CURRENT-STATE сверху, ниже хронология; НЕ источник решений).
|
||||
- **Активные хендофф-промты**: [`ORCHESTRATOR_SESSION_PROMPT.md`](ORCHESTRATOR_SESSION_PROMPT.md) (роль оркестратора) · [`BACKEND_SESSION_PROMPT_REFACTOR.md`](BACKEND_SESSION_PROMPT_REFACTOR.md) (пакет №4: код-хелс + golden-гард) · [`GPT_EXTERNAL_ASCENT_PROMPT.md`](GPT_EXTERNAL_ASCENT_PROMPT.md) (внешняя критика GPT-5.6, анти-якорный протокол → research/17) · [`READER_IDE_RESEARCH_SESSION_PROMPT.md`](READER_IDE_RESEARCH_SESSION_PROMPT.md) (ресёрч «Ридер-IDE» → research/16). Закрытые (пакет №3, erotica, «Голос и состояние») — в `archive/prompts/`.
|
||||
- **Активные хендофф-промты**: [`ORCHESTRATOR_SESSION_PROMPT.md`](ORCHESTRATOR_SESSION_PROMPT.md) (роль оркестратора) · [`ACCEPTANCE_SESSION_PROMPT.md`](ACCEPTANCE_SESSION_PROMPT.md) (**приёмка Ф1 на 蛊真人**: этап A 25 глав → стоп-чекпоинт владельца → полная книга) · [`GPT_EXTERNAL_ASCENT_PROMPT.md`](GPT_EXTERNAL_ASCENT_PROMPT.md) (внешняя критика GPT-5.6, анти-якорный протокол → research/17; деблокирован — рефакторинг залендён) · [`READER_IDE_RESEARCH_SESSION_PROMPT.md`](READER_IDE_RESEARCH_SESSION_PROMPT.md) (ресёрч «Ридер-IDE» → research/16). Закрытые (пакеты №3–4, erotica, «Голос и состояние») — в `archive/prompts/`.
|
||||
- `archive/` — закрытые сессионные промты (только история, инструкции оттуда не исполнять).
|
||||
|
||||
## Статус (2026-07-09)
|
||||
|
|
|
|||
|
|
@ -274,6 +274,16 @@ D1 остаётся дефолтом Фазы 1 (менять конфигура
|
|||
10. **Кодифицировано:** transient-прогоны в ЧУЖОЙ зоне — только в копии вне рабочего дерева (полигон гонял go test в живом backend/ при чужих незакоммиченных правках — обошлось, но впредь запрещено).
|
||||
11. **Приёмка Ф1 разблокирована полностью:** сид финализирован (白凝冰 gender=hidden, 49 записей чисто — воспроизведено ревью боевым loader'ом), цепочка D3/escalate_to заведены, деньги Gemini честны, D14.4 закрыт. Приёмочная сессия ОБЯЗАНА выставить `escalation.budget_usd>0` (иначе echo-эскалация черновика D18 не стреляет). Очередь предложена: приёмка → бэкенд-№4 (рефакторинг, промт выдан) → GPT-восхождение (промт выдан); порядок приёмка↔рефакторинг — за владельцем.
|
||||
|
||||
## D23. Приёмка рефакторинг-пакета №4: golden-гард и OpenReadOnly (10.07, оркестратор). ✅
|
||||
|
||||
Внешнее ревью (5 ревьюеров, всё исполнением в scratchpad-копиях, $0): golden-эквивалентность / инварианты-деньги / дифф-аудит / OpenReadOnly / журнал-скоуп. Вердикты: invariants и diff — **ACCEPT**, остальные — **ACCEPT_WITH_FIXES**; **пакет залендён (296419c)**. Эквивалентность «форма, не поведение» доказана трижды независимо: (а) новый golden прогнан на ЧИСТОМ HEAD-коде — PASS байт-в-байт (snapshotID, все 11 request_hash вкл. эскалационные, wire-тела, вердикты, resume с 0 вызовов; единственный шим — аддитивный read-view); (б) чувствительность golden 5/5 кодовых мутаций (render / snapshotID-компонент / request_hash-домен / nil-гард injected_ids / порядок терминов) — все валят тест громко; (в) AST-дифф 36 деклараций: 29 байт-идентичны, 7 изменены только заявленными способами, 0 потеряно; CLI-контракты сверены исполнением двух бинарей (exit-коды/stderr байт-идентичны). Инварианты 1–7: 9/9 мутаций убиты; go.mod, миграции, схема БД, боевые промпты и конфиги — нетронуты (sha256).
|
||||
|
||||
1. **Golden-гард — постоянный инвариант №8 бэкенда.** Обновление `capture.golden` — ТОЛЬКО при ратифицированной смене поведения (`TM_UPDATE_GOLDEN=1` вручную; при заводке CI переменную в раннеры не экспортировать — сегодня «CI не перепишет» вакуумно, CI нет). Известные слепые пятна фикстуры задокументированы (attempt>1 regeneration-путь, STM, coverage/postcheck-гейты ON, AMBIGUOUS=0) — расширение опционально с реализационным пакетом D15.2.
|
||||
2. **OpenReadOnly САНКЦИОНИРОВАН как изменение поведения** (боль воспроизведена исполнением; покрыт приоритетом-2 мандата): `status`/`report` без flock/миграций/recovery, работают ПРИ живом прогоне; запись гарантированно падает (`PRAGMA query_only` на каждом соединении — mutation-verified; барьер SQL-уровня, НЕ файловый); кросс-процессная конкурентность доказана (WAL-снимок, 1702 чтения под settle-штормом без busy). **Трейд-офф ратифицирован:** после краха reserved-хвост (≤1 резервации — раннер последователен) виден в status до следующей write-команды; read-команды НИКОГДА не чинят ledger (честнее старого поведения, где «read-only» status сам мутировал ledger — это и было причиной flock); schema-mismatch громкий в обе стороны; нет БД → fallback на создающий Open; read-only ФС/иммутабельные бэкапы не поддерживаются (WAL). Рекомендация, не блокер: staleness-маркер через неблокирующий flock-probe.
|
||||
3. **Микро-дефекты исправлены оркестратором при лендинге:** diffstat +3317 (не +3295); фикстура фактически 4 главы/5 чанков/11 тел; line-refs старого runner.go починены в живых доках (06:71, 07:42/109/192, research/13:196/198 — по полной карте ревью); исторические цитаты (D-лог 04.07, журнал) не переписываются; refs D15.2-спеки (15 шт., зона бэкенда) — с v3.1-правками (уже в D22.2).
|
||||
4. **Fix-лист бэкенду (попутно с реализационным пакетом D15.2):** тест errTail на границу руны (реверт фикса сейчас выживает сьют — против дисциплины mutation-verified); лог-ассерты retryLoop (retry_in / отсутствие «will retry» на последней попытке — unit-able через slog-capture); AMBIGUOUS>0 ячейка в фикстуру или смягчение коммента golden_test.go:32; опц.: компонент-тест snapshotID-payload (самопроверка fold'а без golden), kill9 rounds 3→5.
|
||||
5. **Ф2-критерий выполнен:** канал B садится файлом в `escalation.go`, annotator/voice — в `chunkrun.go`; runner.go = 168 строк сетапа. Очередь размораживается: GPT-восхождение деблокировано (условие владельца «после рефакторинга» выполнено); промт приёмочной сессии Ф1 выдан (`ACCEPTANCE_SESSION_PROMPT.md`).
|
||||
|
||||
## Сопутствующие правки доков (оркестратор, 09.07)
|
||||
|
||||
`02-mvp-plan.md` → v3 (мёртвые пороги/интерим-18+/фазовые списки синхронизированы с D-логом); обе `*.puml` → v3 (убраны Opus/BYOK/«≤2×», дорисованы ре-гейт эскалации, три класса отказов D12, человек в петле, фазовые пометки); superseded-баннеры на `research/01, 02, 03, 04, 09`; провенанс-шапки на `research/12-architecture-as-antipattern.md` и `12-common-failures.md` (происхождение не зафиксировано — до уточнения владельцем числа оттуда не абсорбировать как факты); закрытые промты → `docs/archive/prompts/`; онбординг: корневой `CLAUDE.md` + `backend/README.md` + `eval/README.md`.
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
|
||||
| # | Сценарий отказа | Вер./Тяж. | Механизм защиты | Слой | Где в коде/схеме | Фаза | Статус |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| F1 | **`snapshotID` не покрывает память → тихий расходящийся ре-пэй (D5.2)**. Подтверждено кодом: `snapshotID` (`runner.go:145-163`) хэширует brief/chunker/план-стадий/сэмплинг, но **не** версию approved-глоссария и **не** параметры сборки контекста; `RequestHash` (`render.go:158`) включает контент `msgs`; `render.go:23-29` декларирует рендер «чистой функцией snapshot». Как только Фаза 1 инъектит память в `msgs` (`render.go:133-136`): изменённый глоссарий/STM меняет `request_hash`, но не `snapshotID` → resnapshot-гейт (`runner.go:260`) молчит → ре-ран старой главы промахивается мимо чекпоинта и **переоплачивает расходящимся переводом**, ломая инвариант Р6 | В / 🔴🔇 | **Свернуть в snapshot ОБА:** (1) состояние памяти (**content-hash материализованного** approved-глоссария + резюме/series-bible на момент старта джобы — рендер читает **замороженную** версию, не live; **D8: content-hash, НЕ версия-счётчик** — счётчик молча дрейфует, если забыли бампнуть) и (2) context-assembly-конфиг (`glossary_injection`, `stm_depth`, `overlap`). Тогда рендер снова чист по snapshot. **✅ УЖЕ СДЕЛАНО (commit 636919c): snapshot содержит `context_assembly` (`GlossaryInjection`/`GlossaryTokenBudget`) + `MemoryVersion` — материализует память → хеш (выбран мой рекомендованный «материализующий» вариант); `Capability` тоже свёрнут. `memoryVersion()` пока хеширует константу-заглушку `tm-memory-v1\x00`, т.к. банк памяти v2 ещё не приземлился (комментарий в коде явно фиксирует инвариант).** | DET | `runner.snapshotID()`/`memoryVersion()`/`contextSnap` | сделано; активируется с v2 | ✅ структурно закрыто (636919c). **ОСТАЁТСЯ узко: при приземлении глоссария заменить константу в `memoryVersion()` на хеш ORDER BY-стабильных материализованных строк (замороженных, не live) — иначе F1 тихо регрессирует.** |
|
||||
| F1 | **`snapshotID` не покрывает память → тихий расходящийся ре-пэй (D5.2)**. Подтверждено кодом: `snapshotID` (`snapshot.go:82 (до пакета №4 — runner.go:145-163)`) хэширует brief/chunker/план-стадий/сэмплинг, но **не** версию approved-глоссария и **не** параметры сборки контекста; `RequestHash` (`render.go:158`) включает контент `msgs`; `render.go:23-29` декларирует рендер «чистой функцией snapshot». Как только Фаза 1 инъектит память в `msgs` (`render.go:133-136`): изменённый глоссарий/STM меняет `request_hash`, но не `snapshotID` → resnapshot-гейт (`bookrun.go:108/stagerun.go:77 (до пакета №4 — runner.go:260)`) молчит → ре-ран старой главы промахивается мимо чекпоинта и **переоплачивает расходящимся переводом**, ломая инвариант Р6 | В / 🔴🔇 | **Свернуть в snapshot ОБА:** (1) состояние памяти (**content-hash материализованного** approved-глоссария + резюме/series-bible на момент старта джобы — рендер читает **замороженную** версию, не live; **D8: content-hash, НЕ версия-счётчик** — счётчик молча дрейфует, если забыли бампнуть) и (2) context-assembly-конфиг (`glossary_injection`, `stm_depth`, `overlap`). Тогда рендер снова чист по snapshot. **✅ УЖЕ СДЕЛАНО (commit 636919c): snapshot содержит `context_assembly` (`GlossaryInjection`/`GlossaryTokenBudget`) + `MemoryVersion` — материализует память → хеш (выбран мой рекомендованный «материализующий» вариант); `Capability` тоже свёрнут. `memoryVersion()` пока хеширует константу-заглушку `tm-memory-v1\x00`, т.к. банк памяти v2 ещё не приземлился (комментарий в коде явно фиксирует инвариант).** | DET | `runner.snapshotID()`/`memoryVersion()`/`contextSnap` | сделано; активируется с v2 | ✅ структурно закрыто (636919c). **ОСТАЁТСЯ узко: при приземлении глоссария заменить константу в `memoryVersion()` на хеш ORDER BY-стабильных материализованных строк (замороженных, не live) — иначе F1 тихо регрессирует.** |
|
||||
| F2 | **Токен-бюджет: eviction не определён**. При превышении бюджета (matched + sticky > лимит) **какая запись выпадает — не задано**; выпавшая нужная запись = тихая деградация | С / 🟡🔇 | Явная политика приоритета/вытеснения (World Info inclusion-groups: approved>auto; персонажи чанка>фоновые) **+ логировать факт вытеснения** (не молча) | DET | сборщик; `retrieval-state` запись | 1 | ❌ политика и лог вытеснения не специфицированы (находка критика) |
|
||||
| F3 | **Конкурентность/порядок в SQLite**: параллельный перевод чанков + запись auto-записей ломает `first-translation-wins` и sticky (оба предполагают последовательность); modernc — один писатель | С / 🟡 | Явное правило: auto-экстракция и коммит терминов — только на **границе джоб** (impl-notes §3.2 это уже фиксирует); sticky/порядок считаются от детерминированной пересборки чекпоинтов, не от wall-clock порядка | DET | граница джоб; write-пул store | 1 | 🔶 назвать явно (находка критика) |
|
||||
| F4 | **Один SQLite-файл на книгу = SPOF**: повреждение файла молча теряет весь глоссарий+резюме | Н / 🟠🔇 | Бэкап/интеграл-чек/версионирование файла книги; экспорт TMX/TBX как побочный бэкап | DET | store; экспорт | 2 | 🔶 нет строки бэкапа/интеграла (находка критика) |
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
## 2. Что реально построено (состояние на ff5f000)
|
||||
|
||||
**Код `backend/` (~9k строк + ~5k тестов).** Фаза 0 закрыта приёмкой на живых ключах; машинерия Фазы 1 в основном построена и **глубже буквы замысла**: чанкер v4 (sentence-pack, quote-depth, lossless-тайлинг, fuzz-тесты), ingest txt/epub с ruby-захватом и spine-reconciliation, disposition-классификатор (12 flag_reasons, refusal/echo ДО length — усечённый отказ не превращается в платный ретрай, `disposition.go:165-209`), coverage-гейт (порт Python-оракула бит-в-бит вплоть до U+001C-1F, `coverage.go:70-72`), single-hop эскалация с ре-гейтом и издержко-гардами (`runner.go:938-971`), банк памяти v2 (нормализация NFKC/trad2simp/kana/ignorables, Aho-Corasick, спойлер-hard-reject, трёхсторонний disposition, decl-aware post-check, D1-инъекция dst-констрейнтов в редактора), capability-слой с fail-fast эхо-миной DeepSeek (`models.go:288-333`), деньги с at-most-once-подходом (F3 — честно незакрытый техдолг). Клеймы журнала выборочно перепроверены кодом — **сходятся** (монолингвальный editor.md без `{{text}}`, editor-pinned структурно, C2 честно заблокирован `CheckRunnable`).
|
||||
**Код `backend/` (~9k строк + ~5k тестов).** Фаза 0 закрыта приёмкой на живых ключах; машинерия Фазы 1 в основном построена и **глубже буквы замысла**: чанкер v4 (sentence-pack, quote-depth, lossless-тайлинг, fuzz-тесты), ingest txt/epub с ruby-захватом и spine-reconciliation, disposition-классификатор (12 flag_reasons, refusal/echo ДО length — усечённый отказ не превращается в платный ретрай, `disposition.go:165-209`), coverage-гейт (порт Python-оракула бит-в-бит вплоть до U+001C-1F, `coverage.go:70-72`), single-hop эскалация с ре-гейтом и издержко-гардами (`escalation.go:63 maybeEscalate (до пакета №4 — runner.go:938-971)`), банк памяти v2 (нормализация NFKC/trad2simp/kana/ignorables, Aho-Corasick, спойлер-hard-reject, трёхсторонний disposition, decl-aware post-check, D1-инъекция dst-констрейнтов в редактора), capability-слой с fail-fast эхо-миной DeepSeek (`models.go:288-333`), деньги с at-most-once-подходом (F3 — честно незакрытый техдолг). Клеймы журнала выборочно перепроверены кодом — **сходятся** (монолингвальный editor.md без `{{text}}`, editor-pinned структурно, C2 честно заблокирован `CheckRunnable`).
|
||||
|
||||
**Не построено** (и не заявлялось построенным): Analyst/Terminologist/Judge, механика C2 (fan-out/селекция), NSFW-классификатор 0–3, резюме/series-bible, экспорт txt/epub/TMX, HTTP API, `tmctl status`/redrive, F3-идемпотентность, batch, streaming, нативный Gemini. Конфиг отстаёт от D3 (известный лаг, помечен интеримом): нет провайдеров gemini/openai, моделей v4-pro/glm-5.1/gemini-3.1-pro-preview, `budget_usd:0`, `permissive` не проставлен ни одному провайдеру → **канал B сейчас неконфигурируем даже формально** (`pipeline.go:246-251` fail-closed).
|
||||
|
||||
|
|
@ -106,7 +106,7 @@
|
|||
|
||||
### 4.4 Напряжение №3: экономика resume несовместима с онгоингом (verified)
|
||||
|
||||
`snapshotID` вшит в `RequestHash` каждого вызова (`render.go:212-214`), lookup чекпоинтов — только по request_hash → **любое** изменение снапшота (флип coverage-гейта D12/Q4, toggle postcheck_gate, бамп classifierVersion, **append approved-терминов онгоинг-книги** через memoryVersion, даже правка инертной ручки stm_depth) после `--resnapshot` переоплачивает **всю книгу**, включая байт-идентичные запросы — воспроизведено исполнением (2→4 оплаченных вызова на wire-идентичных телах). Комментарии `runner.go:156-160` и `coverage.go:29-33` обещают «re-classify from checkpoint for FREE / no re-bill» — **ложь** вне неизменного снапшота; механизм честного content-addressed reuse (msgsContentHash, `render.go:233-249`) существует, но заперт условием `cs.SnapshotID == snapID`. Вдобавок **нет redrive флагнутых** (D12 требует; tmctl умеет только translate|report) — единственный способ переатаковать один echo-флаг стоит переоплаты книги.
|
||||
`snapshotID` вшит в `RequestHash` каждого вызова (`render.go:212-214`), lookup чекпоинтов — только по request_hash → **любое** изменение снапшота (флип coverage-гейта D12/Q4, toggle postcheck_gate, бамп classifierVersion, **append approved-терминов онгоинг-книги** через memoryVersion, даже правка инертной ручки stm_depth) после `--resnapshot` переоплачивает **всю книгу**, включая байт-идентичные запросы — воспроизведено исполнением (2→4 оплаченных вызова на wire-идентичных телах). Комментарии `snapshot.go:24-32 (до пакета №4 — runner.go:156-160)` и `coverage.go:29-33` обещают «re-classify from checkpoint for FREE / no re-bill» — **ложь** вне неизменного снапшота; механизм честного content-addressed reuse (msgsContentHash, `render.go:233-249`) существует, но заперт условием `cs.SnapshotID == snapID`. Вдобавок **нет redrive флагнутых** (D12 требует; tmctl умеет только translate|report) — единственный способ переатаковать один echo-флаг стоит переоплаты книги.
|
||||
|
||||
Дизайн «снапшот = тотальная инвалидация» безопасен от тихих расхождений (гейт громкий), но **экономически ломает флагманский сценарий** — онгоинг-вебновеллу с живым глоссарием («ИИ-фабрики», Р9): каждое подтверждение пачки терминов на границе тома = пере-покупка всех готовых глав. До Ф1.5/онгоинга нужен либо content-addressed слой переиспользования чекпоинтов, либо селективный redrive; немедленно — поправить лгущие комментарии, чтобы флип гейта не сделали в ожидании $0.
|
||||
|
||||
|
|
@ -189,7 +189,7 @@
|
|||
|
||||
**P1 — код (до боевых прогонов / онгоинга):**
|
||||
6. Память: полисемия — fail-loud на пересекающихся окнах разных sense или даунгрейд в AMBIGUOUS; sticky — наследовать disposition; source-boundary для фонетических ключей ≥4; ruby-reading → auto-alias (или задокументированный чек-лист «kana-alias руками» для ja-книг); замерить kana-precision (расширение E1).
|
||||
7. Resume: спроектировать content-addressed reuse чекпоинтов (msgsContentHash уже есть) или селективный redrive **до** онгоинг-режима; `tmctl status` + redrive (D12-хвосты); немедленно — исправить лгущие комментарии `runner.go:156-160`/`coverage.go:29-33`; бампнуть edit `prompt_version` (D1-уточнение №3 не исполнено — один лейбл на два SHA).
|
||||
7. Resume: спроектировать content-addressed reuse чекпоинтов (msgsContentHash уже есть) или селективный redrive **до** онгоинг-режима; `tmctl status` + redrive (D12-хвосты); немедленно — исправить лгущие комментарии `snapshot.go:24-32 (до пакета №4 — runner.go:156-160)`/`coverage.go:29-33`; бампнуть edit `prompt_version` (D1-уточнение №3 не исполнено — один лейбл на два SHA).
|
||||
8. Канал B: убрать DeepSeek из explicit-части интерима D3 (ToS 27.03.2026); прогнать Mistral как фолбэк (single-hop контур готов); исправить xAI-обоснование (AUP, не «цитата про текст»); explicit-корпус от владельца → 18+ руки exp02 (это единственный critical).
|
||||
|
||||
**P2 — стратегические (до масштабирования):**
|
||||
|
|
|
|||
|
|
@ -193,9 +193,9 @@
|
|||
## Инвариант робастности D5.2 — подтверждён кодом (критично)
|
||||
|
||||
Промт требовал провалидировать инвариант «`snapshotID` покрывает состояние памяти + сборку контекста». **Подтверждаю против реального кода — дыра реальна:**
|
||||
- `snapshotID` (`backend/internal/pipeline/runner.go:145-163`) хэширует brief_hash, chunker/estimator-версии, pipeline_core, defaults (max_output_ratio/min_max_tokens) и per-stage план (model, prompt_version, PromptSHA256, temperature, reasoning, ExtraBody, provider-оверрайды) — **но НЕ версию approved-глоссария и НЕ параметры сборки контекста** (`glossary_injection`/`stm_depth`/`overlap`).
|
||||
- `snapshotID` (`backend/internal/pipeline/snapshot.go:82 (до пакета №4 — runner.go:145-163)`) хэширует brief_hash, chunker/estimator-версии, pipeline_core, defaults (max_output_ratio/min_max_tokens) и per-stage план (model, prompt_version, PromptSHA256, temperature, reasoning, ExtraBody, provider-оверрайды) — **но НЕ версию approved-глоссария и НЕ параметры сборки контекста** (`glossary_injection`/`stm_depth`/`overlap`).
|
||||
- `RequestHash` (`render.go:158`) включает контент `msgs`; `render.go:23-29` декларирует рендер **чистой функцией snapshot**; `Messages` (`render.go:133-136`) прямо говорит: инъекция глоссария/STM встанет между system и user в Фазе 1.
|
||||
- Следствие: как только память попадёт в `msgs`, изменённый глоссарий/STM меняет `request_hash`, но **не** `snapshotID` → resnapshot-гейт (`runner.go:260`) молчит → ре-ран старой главы промахивается мимо чекпоинта и **переоплачивает расходящимся переводом**, ломая инвариант Р6, на который D5 опирается. impl-notes §3.2 это уже **предписывает** («зафиксированное состояние approved-глоссария (версия-счётчик)») — **код отстаёт от доков**.
|
||||
- Следствие: как только память попадёт в `msgs`, изменённый глоссарий/STM меняет `request_hash`, но **не** `snapshotID` → resnapshot-гейт (`bookrun.go:108/stagerun.go:77 (до пакета №4 — runner.go:260)`) молчит → ре-ран старой главы промахивается мимо чекпоинта и **переоплачивает расходящимся переводом**, ломая инвариант Р6, на который D5 опирается. impl-notes §3.2 это уже **предписывает** («зафиксированное состояние approved-глоссария (версия-счётчик)») — **код отстаёт от доков**.
|
||||
- **Фикс (реестр F1):** свернуть в snapshot **оба** — (1) версию-счётчик approved-глоссария + резюме/series-bible (рендер читает **замороженную** версию, не live) и (2) context-assembly-конфиг. Общий гейт Фазы 1, держит D1 и D5; закрыть **до** инъекции памяти.
|
||||
|
||||
---
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue