Final documentation pass in the docs 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:03 +03:00
parent 33ac90009e
commit bab0ee3961
22 changed files with 212 additions and 305 deletions

View file

@ -16,17 +16,17 @@
## Кто ты
Оркестратор — координационный центр проекта (движок · платформа · фронт · полигон · доки).
Владелец стартует рабочие сессии по ТВОИМ промтам и пересылает тебе их отчёты; он — единственный
канал между сессиями. **Зона записи:** `docs/` + корневые онбординг-доки + записи/пинги в зонных
Владелец стартует рабочие сессии по ТВОИМ промтам и пересылает тебе их отчёты; он — единственный ВЕЧНЫЙ
канал между сессиями (прямой — блок 12). **Зона записи:** `docs/` + корневые онбординг-доки + записи/пинги в зонных
журналах `frontend-PROGRESS.md`/`platform-PROGRESS.md`. Чужой код читаешь — не правишь; коммитишь
ВСЁ ты (исключение — пре-рег фризы полигона). **Функции:** промты сессий → приёмки → ратификации
D-нотами → синхронизация доков → ответы владельцу.
## Онбординг и состояние
`CLAUDE.md``docs/README.md` → CURRENT-STATE в `docs/PROGRESS.md` → D-лог (карта+эрраты+живая
голова; правило чтения — CLAUDE.md). По теме: шапка `09-target-architecture` · `12-go-style-notes` ·
`10-prompt-architecture`. Авто-память — point-in-time, сверяй с доками.
`CLAUDE.md``docs/README.md` → CURRENT-STATE в `docs/PROGRESS.md` → D-лог (карта+эрраты; из тел — 23 последние;
правило чтения — CLAUDE.md). По теме: шапка `09-target-architecture` · `12-go-style-notes` ·
`10-prompt-architecture`.
## Ситуации → инструкции

View file

@ -210,8 +210,11 @@ sol-border, эксп-23 §12в). Закрытие пункта = **непуст
> ⚠ **ЗАКАЗ ЖИВОЙ, НО ЧЕТЫРЕ ЕГО СОБСТВЕННЫХ ФАКТА ДЕРЕВО УЖЕ ОПРОВЕРГЛО** (приписка ревизии доков
> 02.09; тело выше НЕ тронуто и трогать его нельзя — на его НОМЕРА СТРОК ссылаются код и отчёт:
> `eval/dovodka/runs.py` цитирует строку 25 как источник капа, заголовки секций Д2 · Д5 · Д8 отчёта
> `docs/experiments/23-editor-tier.md` цитируют диапазоны строк заказа, а `eval/dovodka/requirements.md`
> `eval/dovodka/runs.py` цитирует строку 25 как источник капа; отчёт `docs/experiments/23-editor-tier.md`
> ссылается на строки заказа ТРИНАДЦАТЬЮ якорями — не только заголовками секций Д2 · Д5 · Д8, но и
> точечно по всему телу, включая последние его строки (пере-снять счёт:
> `grep -cE 'заказа? :' docs/experiments/23-editor-tier.md`); по строке же цитируют заказ
> `eval/dovodka/itog_d4.py` и `eval/dovodka/SESSION2-LOG.md`. А `eval/dovodka/requirements.md`
> объявлен прочитанным ПОСТРОЧНО и выводит отсюда 77 строк реестра, сверяемых conformance-гейтом.
> Любая резка сдвинула бы всё это молча, поэтому поправки — списком здесь, а не в теле.)
>

View file

@ -3,21 +3,22 @@
> ⚠⚠ **СНИМОК НА 15.08, ПЕРЕКРЫТЫЙ ЗОНОЙ. Живое состояние фазы Д — НЕ здесь** (баннер дописан
> оркестратором №18 22.08 при актуализации доков; тело ниже не переписано).
>
> Зона с тех пор ведёт свою цепь носителей в `eval/dovodka/` — планы 16.08 → 17.08 → 21.08 → 22.08,
> ревью и консилиум; какой из них ЖИВОЙ, зона называет сама. Прежде чем читать этот файл как
> инструкцию, спроси у владельца, что сейчас живой носитель курса.
> Зона с тех пор ведёт свою цепь носителей в `eval/dovodka/`, и живой её конец НЕ в `main`: планы,
> ревью и консилиумы лежат на ветке `polygon` (`git ls-tree --name-only polygon eval/dovodka/`),
> последний на 02.09 — `PLAN-01-09.md` (редакция 4; редакции 13 отвергнуты консилиумом). В `main`
> из цепи есть только `PLAN-21-08.md` и `PLAN-22-08.md`. Какой носитель ЖИВОЙ, называет зона:
> прежде чем читать этот файл как инструкцию, спроси у владельца.
>
> **Снимок ПОДРЕЗАН 02.09** (ревизия доков): снято то, что дерево с тех пор опровергло или
> исполнило — маршрут онбординга, числа 15.08, закрытые пункты «что осталось», денежная рамка.
> Куда снятое уехало: записи полигона 15.08 — `archive/PROGRESS-2026-08-10-15.md` · числа и
> вердикты — `docs/experiments/23-editor-tier.md` · фактическая цепь потолков —
> `eval/dovodka/money_d.py` (`PACK_CEILING`/`CEILINGS`), а не текст.
> ⚠ Там же и прибор: `eval/.venv` из команд §2/§4 в `main`-дереве отсутствует — они рассчитаны на
> рабочее дерево ветки `polygon` (`git worktree list`).
>
> **Снимок ПОДРЕЗАН 02.09** (ревизия доков): опровергнутое и исполненное деревом снято, адреса
> уехавшего — в §1 и §3.
>
> Что в файле по-прежнему полезно: устройство приборов, грабли отладки и незакрытое требование Д5.
> Приёмка фазы — у ПАРАЛЛЕЛЬНОГО оркестратора.
Передача следующей сессии. Что снято, что осталось, на чём споткнёшься, чего не принимать за
твёрдое. Развёрнутая версия с историями отладки — в git-истории коммитов фазы.
Развёрнутая версия с историями отладки — в git-истории коммитов фазы.
---
@ -27,8 +28,8 @@
Прошлая сессия читала грепом и потеряла целый пункт заказа (внешнюю подпись Sol). В конце заказа
— приписка-эррата 02.09: четыре его факта (кап 80 · состав секций · ja-книга · потолок) дерево
опровергло, тело при этом не правится.
2. **Живой носитель курса — в `eval/dovodka/`** (планы 16.08 → 22.08, ревью, консилиум); какой
из них живой, называет зона. Онбординг под него лежит в самом плане (`PLAN-22-08.md`, §0).
2. **Живой носитель курса — ветка `polygon`, каталог `eval/dovodka/`** (см. баннер выше).
Онбординг под план 22.08 лежит в нём самом (`PLAN-22-08.md`, §0).
3. Отчёт `docs/experiments/23-editor-tier.md` — состав секций с 15.08 вырос, грепать
`grep '^## Д' docs/experiments/23-editor-tier.md`; записи полигона 15.08 из `docs/PROGRESS.md`
срезаны в `docs/archive/PROGRESS-2026-08-10-15.md`.
@ -59,8 +60,7 @@
Числа фазы живут в отчёте `docs/experiments/23-editor-tier.md`, и с 15.08 они ПЕРЕ-СУЖЕНЫ:
вердикты двух семейств — Д13.1 · панели осей — Д3 / Д6 / Д1 · сводка «пробел → чем закрыт» — Д9 ·
пере-суд починенным прибором — Д15 и дальше. ⚠ Копия таблиц, стоявшая здесь, местами уже
расходилась с отчётом и снята: у числа один носитель, и это отчёт.
пере-суд починенным прибором — Д15 и дальше. ⚠ У числа один носитель, и это отчёт.
**Деньги:** фактическая цепь потолков — `eval/dovodka/money_d.py` (`PACK_CEILING`/`CEILINGS`),
механизм её подъёмов — отчёт Д14.9. ⚠ $10.00 в заказе — ИСХОДНАЯ рамка 10.08, с тех пор
@ -176,9 +176,8 @@
## 9. Новые файлы фазы
Состав каталога читается `ls eval/dovodka/` (39 файлов) — перечень «создано / существенно
переписано», стоявший здесь, им и заменяется. Существенно одно: провайдера пары `para.py` и
пар-промтов **не существовало, банк новой пары собрать было нечем**.
Состав каталога читается `ls eval/dovodka/` (39 файлов). Существенно одно: провайдера пары
`para.py` и пар-промтов **не существовало, банк новой пары собрать было нечем**.
`prompts-free/{en-ru,ja-ru}/` — свободные редакции от Fable-5, **в замер НЕ входят**.

File diff suppressed because one or more lines are too long

View file

@ -17,19 +17,18 @@
- `research/` — фактура ресёрчей; у принятых — ревью-шапки, часть тел под ⚠ superseded: **читай баннер прежде содержимого**. Ключевые для навигации: 15 голос · 16 ридер-IDE · 17 внешняя критика · 18 рычаги качества · 19 нарезка · 20 банк-майнинг · 21 обзор транспорта · 22 доменные харнессы · 23 шов движок↔платформа · 25 холодное ревью шва — **читать перед любым кодом стыка** · 24 арбитраж банка · 26 официальные практики Anthropic · 28 контракт-ревью API v0 — **носитель для исполняющих сессий, читать оригинал, не пересказ**.
- [PROGRESS.md](PROGRESS.md) — журнал: CURRENT-STATE + **ЕДИНЫЙ БЭКЛОГ** (единственный трекер) + живой хвост хроники. НЕ источник решений.
- **Тулчейн на чистой машине.** Версии не здесь — их носители: `backend/Makefile` и `platform/Makefile` (`GO_MIN_VERSION`, `GOLANGCI_VERSION`), `frontend/package.json` (`engines`), `platform/docs/STACK_DECISIONS.md` §«Postgres на стенде без root», `eval/requirements.txt` + `eval/.python-version`. Здесь только то, чего нет нигде: ставим в `~/.local/opt/<инструмент>` с симлинком в `~/.local/bin` (он уже в `PATH`), берём **последний патч пинованного минора, а не следующий минор** — линтер пинован точным равенством и разъедется. Root требуют ровно два пакета: `build-essential` (без C-компилятора нет `-race`, а снять `-race` значит выдать отсутствие тулчейна за зелёный прогон — см. комментарий над целью `test` в `backend/Makefile`) и `python3-venv` (в системном питоне нет `ensurepip`, и установка полигона по `eval/README.md` обрывается на первом шаге).
- `scripts/counts.py`**производные числа доков считаются им, а не руками** (голова по трём носителям · счёт очереди и зон · вес открытых строк регистра платформы · полнота реестра нот); `--check` даёт ненулевой код на расхождении; `--lint` — линтер file:line-якорей живых доков (D39.126). Его же зовёт зонный хук `scripts/githooks/pre-commit`: **`--lint` якорей — при коммите, задевающем ЛЮБОЙ док или `CLAUDE.md`; `--check` чисел и головы — при коммите с D-логом или PROGRESS** (оба `--from-index`, предупреждает, не блокирует). ⚠ **Гейт бутстрапится ЧУЖОЙ зоной — это ДЕФЕКТ, а не порядок работы (строка бэклога 220):** судит он `CLAUDE.md` и доки трёх зон, а в `.git/hooks/` его кладёт единственный установщик `frontend/scripts/githooks/install.mjs`, то есть побочный эффект `npm install` в зоне, которая ЗАМОРОЖЕНА. На свежем клоне `.git/hooks/` пуст и гейт молчит, не проверив ничего. Пока строка открыта, бутстрап делается руками (`node frontend/scripts/githooks/install.mjs`) — и это ВРЕМЕННАЯ мера, которую строка 220 закрывает, а не способ жить дальше. ⚠ Шапка систематически отстаёт от хвоста у ЛЮБОГО автора — потому проверка механическая, а не «посмотрю внимательно».
- `scripts/counts.py`**производные числа доков считаются им, а не руками** (голова по трём носителям · счёт очереди и зон · вес открытых строк регистра платформы · полнота реестра нот); `--check` даёт ненулевой код на расхождении; `--lint` — линтер file:line-якорей живых доков (D39.126). Его же зовёт зонный хук `scripts/githooks/pre-commit`: **`--lint` якорей — при ЛЮБОМ коммите с непустым индексом, включая коммиты чистого КОДА (гейт по составу снят 21.08: цели якорей живут в коде, и двигает их кодовый коммит; шумовое следствие — строка бэклога 244); `--check` чисел и головы — только при коммите с D-логом или PROGRESS** (оба `--from-index`, предупреждает, не блокирует). ⚠ **Гейт бутстрапится ЧУЖОЙ зоной — это ДЕФЕКТ, а не порядок работы (строка бэклога 220):** судит он `CLAUDE.md` и доки трёх зон, а в `.git/hooks/` его кладёт единственный установщик `frontend/scripts/githooks/install.mjs`, то есть побочный эффект `npm install` в зоне, которая ЗАМОРОЖЕНА. На свежем клоне `.git/hooks/` пуст и гейт молчит, не проверив ничего. Пока строка открыта, бутстрап делается руками (`node frontend/scripts/githooks/install.mjs`) — и это ВРЕМЕННАЯ мера, которую строка 220 закрывает, а не способ жить дальше. ⚠ Шапка систематически отстаёт от хвоста у ЛЮБОГО автора — потому проверка механическая, а не «посмотрю внимательно».
- **Активные хендофф-промты — какой файл ТВОЙ** (состав обновляется при каждом лендинге, D39.80; хроника, причины и статусы РАБОТ — CURRENT-STATE и D-лог):
| Роль | Активный промт | Статус |
|---|---|---|
| Оркестратор | [ORCHESTRATOR_SESSION_PROMPT.md](ORCHESTRATOR_SESSION_PROMPT.md) | роль и нормы; счётчик роли — CURRENT-STATE |
| Бэкенд | активного НЕТ | последний пак — «деньги и честность выдачи», принят и заленджен 31.08 (**D39.182**; закон раскрытия — **D39.181**); до него холодный прогон v16 (**D39.179**) — развилка «довести ≈$1.00 / остановиться» ЗАКРЫТА словом владельца «не доводить» (**D39.184**). Открыто: различение уровней теста (вопрос владельцу) · §2.2 против `snapshotdiff` · строка **246** (чинит платформа) |
| Бэкенд | активного НЕТ | последний пак — «деньги и честность выдачи», принят и заленджен 31.08 (**D39.182**; закон раскрытия — **D39.181**). Открыто: различение уровней теста (вопрос владельцу) · §2.2 против `snapshotdiff` · строка **246** (чинит платформа) |
| Платформа | активного НЕТ | последний пак — P12 «долги под ногами», принят и заленджен 31.08 (**D39.180**) вместе с контрактным минором. Открытое зоны — её регистр дефектов (`platform/docs/DEFECT_REGISTER.md`, счёт — `counts.py --check`) |
| Полигон | [POLYGON_EXP2223_REDO_SESSION_PROMPT.md](POLYGON_EXP2223_REDO_SESSION_PROMPT.md) (отложенный — [POLYGON_PACKAGE4_SESSION_PROMPT.md](POLYGON_PACKAGE4_SESSION_PROMPT.md), строка 85) | фаза Д ИДЁТ; ⚠ живой носитель курса — в `eval/dovodka/`, какой именно называет зона (⚠ [POLYGON_PHASE_D_HANDOFF.md](POLYGON_PHASE_D_HANDOFF.md) — перекрытый снимок, читать не как курс) |
| Фронт | активного НЕТ | **ЗОНА ЗАМОРОЖЕНА** (D39.136 п.2 + D39.147: разморозка отдельным словом владельца, не привязана к P7); перечень первого касания — в зонном журнале |
| Контракт | активного НЕТ | канон — `architecture/14-api-contract/`; ⚠ версию брать ФАЙЛОМ (`grep '^ version:' openapi.yaml`), не отсюда: миноры ратифицируются D-нотами и их содержание грепается по реестру нот. ⚠ Названная цена минора 0.7.0 СНЯТА 29.08 (D39.170): читающий путь движка сворачивает банк, поэтому смета доезжает до покупателя ДО покупки |
| Контракт | активного НЕТ | канон — `architecture/14-api-contract/`; ⚠ версию брать ФАЙЛОМ (`grep '^ version:' openapi.yaml`), не отсюда: миноры ратифицируются D-нотами и их содержание грепается по реестру нот. |
Отработанные промты — `archive/prompts/`, отчёты с ревью-шапками — `archive/reports/`. Зонные журналы фронта и платформы — `frontend-PROGRESS.md` / `platform-PROGRESS.md` в их зонах (прогресс зон только там, D39.100).
- Чужие зоны — фронт и платформа (читать при касании стыка; каждая ведёт СВОЙ зонный бэклог — единый бэклог их строк не принимает, D39.84): [../frontend/](../frontend/) — веб-интерфейс: промт фронт-сессий + [STACK_DECISIONS.md](../frontend/docs/STACK_DECISIONS.md) (пины версий точными числами и ловушки) + [BACKLOG.md](../frontend/docs/BACKLOG.md) · [../platform/](../platform/) — SaaS control plane: README + [BACKLOG.md](../platform/BACKLOG.md) + `docs/` (зонный журнал `platform-PROGRESS.md` · регистр дефектов · `STACK_DECISIONS.md` с рецептом стенда и инвентарём каналов шва · **[ENGINEERING_STANDARDS.md](../platform/docs/ENGINEERING_STANDARDS.md) — ратифицирован; КАЖДЫЙ промт платформенной сессии обязан на него ссылаться, отступление = пинг** · **[PLATFORM_DIRECTION.md](../platform/docs/PLATFORM_DIRECTION.md) — ратифицированное направление зоны: аутентификация, деньги, стандарты, скорость** · архив промтов).
- Чужие зоны — фронт и платформа (читать при касании стыка; каждая ведёт СВОЙ зонный бэклог — единый бэклог их строк не принимает, D39.84): [../frontend/](../frontend/) — веб-интерфейс: зонный журнал `docs/frontend-PROGRESS.md` (прогресс зоны только там, D39.100) + промт фронт-сессий + [STACK_DECISIONS.md](../frontend/docs/STACK_DECISIONS.md) (пины версий точными числами и ловушки) + [BACKLOG.md](../frontend/docs/BACKLOG.md) · [../platform/](../platform/) — SaaS control plane: README + [BACKLOG.md](../platform/BACKLOG.md) + `docs/` (зонный журнал `platform-PROGRESS.md` · регистр дефектов · `STACK_DECISIONS.md` с рецептом стенда и инвентарём каналов шва · **[ENGINEERING_STANDARDS.md](../platform/docs/ENGINEERING_STANDARDS.md) — ратифицирован; КАЖДЫЙ промт платформенной сессии обязан на него ссылаться, отступление = пинг** · **[PLATFORM_DIRECTION.md](../platform/docs/PLATFORM_DIRECTION.md) — ратифицированное направление зоны: аутентификация, деньги, стандарты, скорость** · архив промтов).
- `archive/` — история ([правила архива](archive/README.md)): закрытые промты (`prompts/`) · отчёты с ревью-шапками (`reports/` — на них ссылаются приёмки) · исполненные арх-доки (`architecture/`) · слайсы хроники `PROGRESS-*.md`. Инструкции оттуда не исполнять.
- Диаграммы: [../backend/docs/components.puml](../backend/docs/components.puml) · [../backend/docs/pipeline.puml](../backend/docs/pipeline.puml) — дом рядом с кодом (D39.80), правятся бэкендом одним коммитом с кодом; не рендерить (гардрейл CLAUDE.md).

View file

@ -4,19 +4,19 @@
| Роль | Модель (слаг) | thinking / effort | Носитель конфига | Статус | Квирки |
|---|---|---|---|---|---|
| **draft** (translator) | `deepseek-v4-flash` | thinking ON, `reasoning:"low"` явно (D39.87/91 «вариант б») | `configs/pipeline-c1.yaml:36-60` | боевой ИНТЕРИМ (exp13; бейк-офф эксп-22 заленден 10.08 — черновик менять не на что, но выводы заморожены до фазы Д, НЕ ратифицированы) | quirks §0731 п.1 (дефолт-эффорт пробивает флор 8000), п.3а (не слать эффорт = ехать на `high`), п.4 (`low` пере-вооружает эхо), п.6 (эхо стохастично по вызову; ре-ген дешевле эскалации ×7.6). Thinking-OFF — НИКОГДА (эхо-мина, `echoMineViolation`) |
| **draft** (translator) | `deepseek-v4-flash` | thinking ON, `reasoning:"low"` явно (D39.87/91 «вариант б») | `configs/pipeline-c1.yaml`, стадия `draft` | боевой ИНТЕРИМ (exp13; бейк-офф эксп-22 заленден 10.08 — черновик менять не на что, но выводы заморожены до фазы Д, НЕ ратифицированы) | quirks §0731 п.1 (дефолт-эффорт пробивает флор 8000), п.3а (не слать эффорт = ехать на `high`), п.4 (`low` пере-вооружает эхо), п.6 (эхо стохастично по вызову; ре-ген дешевле эскалации ×7.6). Thinking-OFF — НИКОГДА (эхо-мина, `echoMineViolation`) |
| **+ банкнота** (WHAT-канал драфта) | та же flash, промпт `translator-banknote.md` | как draft | ⚠ НЕ в shipping-c1 — ран-локальный конфиг книги: `~/books/gu-zhenren/coldrun-b/pipeline.yaml` (`gates.banknote` + `prompt_override`) | ⚠0731; включение в c1 = СТОП-решение владельца (строка 140: двигает RequestHash) | те же |
| **терминолог** | `deepseek-v4-flash` | thinking ON, `gates.terminology.reasoning:"low"` (одна ручка на обе бэнк-роли) | ран-локальный `~/books/gu-zhenren/coldrun-b/reprobe/bank-low/pipeline.yaml:68-78`; схема — `internal/config/pipeline.go:298` (TerminologyGate); в shipping-c1 гейта НЕТ (opt-in OFF) | боевой по факту прогонов; носитель — конфиг книги | quirks §0731 п.3а: пустой `reasoning` = вендор-`high` → 4/5 `length` с пустым телом; экран `target_script: Cyrillic` обязателен при гейте ON |
| **терминолог** | `deepseek-v4-flash` | thinking ON, `gates.terminology.reasoning:"low"` (одна ручка на обе бэнк-роли) | ран-локальный `~/books/gu-zhenren/coldrun-b/reprobe/bank-low/pipeline.yaml:68-78`; схема — `internal/config/pipeline.go:298`=`type TerminologyGate struct` (TerminologyGate); в shipping-c1 гейта НЕТ (opt-in OFF) | боевой по факту прогонов; носитель — конфиг книги | quirks §0731 п.3а: пустой `reasoning` = вендор-`high` → 4/5 `length` с пустым телом; экран `target_script: Cyrillic` обязателен при гейте ON |
| **классификатор** (типы кандидатов) | flash (`classify_model` пуст ⇒ = model) | та же ручка | там же: `classify_types: true` + `classify_budget_usd` | проба/полигон; в shipping выключен ВЕЗДЕ | латентный мис-вердикт `cjk_artifact``13-tech-debt-anchors.md` §Б-105 |
| **editor** | `deepseek-v4-pro` **БИЛИНГВ** | thinking ON; `reasoning:"off"` = осознанный NO-OP (ReasoningNone); ручки эффорта у pro НЕТ (`low``high`) — так говорит квирк-канон §3а, помеченный пере-снятым. ⚠ **НОСИТЕЛИ ПРОТИВОРЕЧАТ, и это НЕ решено:** `PROGRESS.md` CURRENT-STATE утверждает обратное — «у pro эффорт стал настраиваемым low/high/max, квирк 3а устарел». Кто прав, из репозитория НЕ выводится: замера поведением после 13.08 нет ни у одной стороны. ⚠ **D39.137 про эффорт МОЛЧИТ** (11 строк, ноль упоминаний) — ссылаться на неё как на «ручка появилась 13.08» уже пробовали (испр. №18 20.08): конфабуляция по смежности, `V4-Pro-0813` — чекпойнт ВЕСОВ при вендорском «Model names remain unchanged», а не дата появления ручки. **Закрывается вендор-сверкой, а не выбором стороны**; до неё в силе КАНОН | `configs/pipeline-c1.yaml` блок редактора; floor 16000 — `models.yaml` ключ `deepseek-v4-pro`, поле `min_max_tokens` | боевой ИНТЕРИМ (D30.1/D39.22); D39.117: топология 2-прохода ПОДТВЕРЖДЕНА (`A/F3` +2.50 Holm 0.0004), жильцы dspro/glm-5 неразличимы ⇒ выбор = цена; закон-блок ОБЯЗАТЕЛЕН (строка 134) | quirks §0731 п.3а (маппинг pro), п.3б (замер `low` на pro ОТОЗВАННЕ УСТАНОВЛЕНО); вахта смены маппинга «early August 2026» — §Б-108 |
| **editor** | `deepseek-v4-pro` **БИЛИНГВ** | thinking ON; `reasoning:"off"` = осознанный NO-OP (ReasoningNone); ручки эффорта у pro НЕТ (`low``high`) — так говорит квирк-канон §3а, помеченный пере-снятым. ⚠ **НОСИТЕЛИ ПРОТИВОРЕЧАТ, и это НЕ решено:** `PROGRESS.md` утверждает обратное (пинг зоне полигона + строка бэклога **237**(б)): вахта §Б-108 сработала 13.08 changelog'ом вендора — pro/flash получили low/high/max. Кто прав, из репозитория НЕ выводится: замера поведением после 13.08 нет ни у одной стороны. ⚠ **D39.137 про эффорт МОЛЧИТ** (11 строк, ноль упоминаний) — ссылаться на неё как на «ручка появилась 13.08» уже пробовали (испр. №18 20.08): конфабуляция по смежности, `V4-Pro-0813` — чекпойнт ВЕСОВ при вендорском «Model names remain unchanged», а не дата появления ручки. **Закрывается вендор-сверкой, а не выбором стороны**; до неё в силе КАНОН | `configs/pipeline-c1.yaml` блок редактора; floor 16000 — `models.yaml` ключ `deepseek-v4-pro`, поле `min_max_tokens` | боевой ИНТЕРИМ (D30.1/D39.22); D39.117: топология 2-прохода ПОДТВЕРЖДЕНА (`A/F3` +2.50 Holm 0.0004), жильцы dspro/glm-5 неразличимы ⇒ выбор = цена; закон-блок ОБЯЗАТЕЛЕН (строка 134) | quirks §0731 п.3а (маппинг pro), п.3б (замер `low` на pro ОТОЗВАННЕ УСТАНОВЛЕНО); вахта смены маппинга «early August 2026» — §Б-108 |
| **editor-резерв** | `glm-5` | thinking OFF ЯВНО (`extra_body {thinking:{type:disabled}}`, иначе таймауты ×3) | `configs/pipeline-arm-glm.yaml` блок редактора + `models.yaml` ключ `glm-5` | резерв; флип = один арм-конфиг. mistral-арм есть, но mistral ИСКЛЮЧЁН как редактор (D39.20) | quirks thinking-таблица (glm-5); эхо-экспозиция билингва при thinking-OFF НЕ измерена (`sourceEchoExposure`) |
| **судья Ф2** | Gemini (нативный адаптер — Ф2, строка 33); в C2-скелете провизорно `glm-5` | Gemini: thinking mandatory | `models.yaml` ключ `gemini-3.1-pro-preview`; `pipeline-c2.yaml` блок `select` («DO NOT FLIP») | Ф2/полигон — в движке НЕ построен; C2 неисполняем | quirks: `thinking_budget:0` → HTTP 400; учёт `additive_total`; судья ЭРОТИКИ непригоден (PROHIBITED_CONTENT неконфигурируем, D22.6) → первичный судья 18+ = grok |
| **канал B (18+)** | `mistral-large-2512` (переводчик-дефолт, D19.1) + `grok-4.3` (эскалация reasoning-ON + судья 18+) | mistral: не-reasoning; grok: OFF только явным `reasoning_effort:"none"` | `models.yaml` ключи `mistral-large-2512` (accepts_labels, rate_limit) и `grok-4.3` · c1 `chains.adult:[grok-4.3]` | данные заведены; полный wiring — Ф2; `content_policy` пуст во всех shipping (сознательно) | quirks §Транспорт: mistral rate-limiter (~48% retry-fails → `max_concurrency:2`); grok: вложенная форма эффорта молча глотается; additive-биллинг (think-ON только за резервом D6.2) |
| **эскалация (канал A)** | draft single-hop → `deepseek-v4-pro`; цепочка `[deepseek-v4-pro, glm-5.1, gemini-3.1-pro-preview]` | наследует политику мишени; апекс mandatory-thinking | `configs/pipeline-c1.yaml:118-135` | заведена, но ⚠ `budget_usd: 0` в shipping ⇒ НЕ исполняется (ран-локальные: 0.10 / 0.015) | слаг ИМЕННО `-preview` (без него 404); C2-цепочка `[kimi-k2.6]` = интерим-заглушка, НЕ контракт |
| **арбитр** | Sol (ChatGPT, внешний контур, руки владельца) · grok-агентские роли полигона | — | строка 150 бэклога + `eval/tenant_panel/sol.py`; кредиты xAI — лист владельца (PROGRESS строка 6) | пакет (а) прогнан 09.08 — арбитраж НЕ состоялся (N=3 недомощен, шкала дрейфует ×2.6); пакет (б) заморожен до починки оснастки; возражение Sol по `tier` эксп-23 — на владельце | Sol = LLM: «издательское качество» им не доказывается, человеческий контур — пилот Ф2.5 (D39.117 п.5б) |
| **эскалация (канал A)** | draft single-hop → `deepseek-v4-pro`; цепочка `[deepseek-v4-pro, glm-5.1, gemini-3.1-pro-preview]` | наследует политику мишени; апекс mandatory-thinking | `configs/pipeline-c1.yaml`, блок `escalation` | заведена, но ⚠ `budget_usd: 0` в shipping ⇒ НЕ исполняется (ран-локальные: 0.10 / 0.015) | слаг ИМЕННО `-preview` (без него 404); C2-цепочка `[kimi-k2.6]` = интерим-заглушка, НЕ контракт |
| **арбитр** | Sol (ChatGPT, внешний контур, руки владельца) · grok-агентские роли полигона | — | строка 150 бэклога + `eval/tenant_panel/sol.py`; кредиты xAI — на владельце (носителя в CURRENT-STATE сегодня НЕТ) | пакет (а) прогнан 09.08 — арбитраж НЕ состоялся (N=3 недомощен, шкала дрейфует ×2.6); пакет (б) заморожен до починки оснастки; возражение Sol по `tier` эксп-23 — на владельце | Sol = LLM: «издательское качество» им не доказывается, человеческий контур — пилот Ф2.5 (D39.117 п.5б) |
## Примечания
- **⚠0731 (D39.61):** flash пере-обучен под тем же слагом; `/models` молчал. Развилка решена вариантом (б): явный `reasoning_effort:"low"` черновику + ручка эффорта бэнк-ролям (код `553f1a3`). Версию модели проверять ПОВЕДЕНИЕМ.
- **⚠0731 (D39.61):** развилка решена вариантом (б) — явный `reasoning_effort:"low"` черновику + ручка эффорта бэнк-ролям (код `553f1a3`).
- **Вахта эффорта pro:** реестр загейченных триггеров — `architecture/13-tech-debt-anchors.md` §Б-108 (статус ручки — в строке редактора выше).
- **Цена:** ~$0.85/ранобэ (D30.4; тело — `archive/architecture/05-decisions-D1-D38.md`, карта — шапка D-лога) — ⚠ число ДО пере-пина цен 1315.08: таблица запинена ПИКОМ, счёт шиппинга = 100% DeepSeek ⇒ ×4.24.4 в пике и ×2.12.2 в долине (D39.137). ⚠ **Пере-калибровки НЕТ:** первый платный прогон редакторской волной отработал 31.08 (D39.184; числа — `archive/reports/COLDRUN_V16_REPORT_2026-08-31.md`), пересчёта книги из него никто не сделал — фактура и статус довода «редактор не гонялся» в `PROGRESS.md` строка 16. Ставка платформы $0.03/глава (D39.123 п.2г). Цены слагов — `models.yaml` (**`2026-08-15`**: `backend/configs/models.yaml:34`=`prices_checked: "2026-08-15"`; ⚠ бампнут факт-чеком ТОЛЬКО по DeepSeek; катовер 0731 цен не менял).
- **Ключи API:** какой ключ нужен провайдеру — поле `api_key_env` в `models.yaml`, один носитель на факт. **`.env` НЕ читать** (гардрейл CLAUDE.md), `.env.example` можно. Ключи деплоя доезжают до движка аргументом `--keys-file` (движковая половина — D39.158, платформенная — пак P9); в окружение юнита ключи НЕ кладутся, и каталог пользовательского контента их больше не несёт. Строка бэклога **211** ЗАКРЫТА — история дефекта и его разбор в D39.156/D39.162.

View file

@ -2,7 +2,7 @@
> **⚠ ЧИТАТЬ ПРЕЖДЕ ТЕЛА (статус 25.07, оркестратор №7).** Принципы Р1Р10 живы; **вся конкретика моделей/цен/каналов ниже — состояние 0405.07 и проигрывает D-логу** (D30D39.25) и `configs/pipeline-c1.yaml`. Действующий состав: черновик deepseek-v4-flash СОХРАНЁН бейк-оффом exp13 (D32.1); редактор — **deepseek-v4-pro ИНТЕРИМ** и **БИЛИНГВ** (D30.1 → D39.22; glm-5 резерв, mistral исключён — D39.20); grok больше не редактор — концентрация ролей на xAI распалась (снимает Р4-гигиену аккаунтов и Р10-риск-6), у grok остались судья-фолбэк 18+ и эскалация; канал B — переводчик-дефолт Mistral + grok-ON эскалация (D14.1/D19.1), Gemini-судья fail-closed на эротике (D22.6); ключ xAI един, с data-sharing (D27); COGS ~$0.85/ранобэ после флипа D1 (D30.4); кэш ≈2% стоимости, НЕ главный рычаг (exp08). Контент-роутинг Р4 переопределён D39.25: в движке НЕТ понятия «18+» — generic content-labels × provider-capabilities (данные + конфиг), refusal причино-агностичен, «канал B» — продуктовое имя; L3 — политика ВХОДА, не чанк-классификатор. Что построено — шапка-таблица `09-target-architecture.md`; точечные пометки — по тексту.
Синтез по итогам исследований `docs/research/01…11-*`. v2 — после адверсариального ревью тремя критиками (техархитектура, экономика, red-team); все найденные противоречия разрешены явно. Формат — ADR-подобный: решение → обоснование → что отвергнуто. Статусы: **принято** (можно кодить), **гипотеза** (нужен пилот/валидация).
Синтез по итогам исследований `docs/research/01…11-*`. Формат — ADR-подобный: решение → обоснование → что отвергнуто. Статусы: **принято** (можно кодить), **гипотеза** (нужен пилот/валидация).
---
@ -10,7 +10,7 @@
Из [10-vojo-ai-bot-review.md](../research/10-vojo-ai-bot-review.md):
- Из `vojo/apps/ai-bot` прямо переносится ~22,5 тыс. строк проверенной инфраструктуры: OpenAI-совместимый транспорт с retry/backoff, фейловер «локальная GPU → облако» с circuit breaker, прайсинг + reserve/settle-ledger, телеметрия (request_log, трейсы W3C), fail-fast конфиг. Это 36 недель сэкономленной разработки.
- Из `vojo/apps/ai-bot` прямо переносится ~22,5 тыс. строк проверенной инфраструктуры: OpenAI-совместимый транспорт с retry/backoff, фейловер «локальная GPU → облако» с circuit breaker, прайсинг + reserve/settle-ledger, телеметрия (request_log, трейсы W3C), fail-fast конфиг.
- Goroutines/context — идеальная модель для тысяч параллельных LLM-вызовов; один статический бинарь без рантайма — идеально для локального режима у пользователя.
- **Отвергнуто:** C++/userver — ноль переиспользования, производительность здесь не монетизируется (мы ждём сеть, а не CPU), а код пишет Claude, не владелец. Python — только оффлайн-евалы и Python-сайдкар качества (CometKiwi, морфология русского — в Go-экосистеме зрелого лемматизатора нет). TypeScript — для будущего IDE-фронтенда.
@ -27,7 +27,7 @@
- Пункты брифа, по которым решение принято явно: **консультант поп-культуры / языковой аналитик** (бриф п.2; прототип — CRAT arXiv:2410.21067) и **tool-calling / переводческие тулзы** (п.32; в vojo tool-calling нет) — вне скоупа MVP, кандидаты Фазы 3; **webfetch за культурным контекстом** (п.16) — post-MVP, только по явному сигналу «незнакомый термин» и с подтверждением через глоссарий (риск многозначности, о котором предупреждал сам бриф).
- У каждого пасса **узкий мандат** (запрет менять чужую зону) и диффы вместо полной перегенерации.
- Приоритет силы моделей: **редактор > черновик** (вывод arXiv:2605.13368 — refinement проецирует текст в распределение редактора).
- Пилот 4 рук: ~2535 глав zh/ja/en→ru; решающий критерий — человеческие попарные сравнения (протокол LAIT; для двух систем это pairwise, не BWS — BWS только с ≥3 объектами, третьим якорем берём человеческий перевод) + панель LLM-судей чужих семейств. Правило: если C2/C3 лучше C1 менее чем на 5 п.п. win rate — берём C1 (в 23 раза дешевле). Бюджет: <$50 API + внешние редакторы 2040 ч; **elapsed 23 недели, отдельная фаза** (см. план MVP v2) — подготовка корпуса стартует параллельно с Фазы 0 (работа владельца + сессия «Полигон»).
- Пилот 4 рук: ~2535 глав zh/ja/en→ru; решающий критерий — человеческие попарные сравнения (протокол LAIT; для двух систем это pairwise, не BWS — BWS только с ≥3 объектами, третьим якорем берём человеческий перевод) + панель LLM-судей чужих семейств. Правило: если C2/C3 лучше C1 менее чем на 5 п.п. win rate — берём C1 (в 23 раза дешевле). Бюджет: <$50 API + внешние редакторы 2040 ч (фаза и её протокол — `02-mvp-plan.md` §Фаза 2.5).
## Р3. Банк памяти книги — собственный модуль на SQLite. **Принято (схема+гейты) / ставка — гейтится in-house eval**
@ -37,7 +37,7 @@
- Хранилище: **SQLite (один файл на книгу) + FTS5** (FTS5 — НЕ в горячем пути: unicode61 не сегментирует CJK → молча вернёт ничего). Драйвер — modernc.org/sqlite. **sqlite-vec в MVP не используется — но причина в том, что держим modernc единым драйвером и избегаем WASM-миграции, НЕ «pure-Go не может»** (правка формулировки: CGO-free sqlite-vec существует через ncruces/go-sqlite3 WASM). Brute-force KNN подтверждён эмпирически: <20 мс на 100k×1024-d на порядки внутри нужд одной книги. Эмбеддинги **второй эшелон, Фаза 2, low-trust** (см. ниже).
- **Горячий путь — детерминированный multi-pattern матч** (Aho-Corasick / double-array trie по `src`+алиасам над нормализованным чанком; ru/en — по леммам/`decl`), НЕ FTS5, НЕ эмбеддинги. Эмпирика сессии: точный многосимвольный подстрочный матч — **precision 1.0, 0/4 ложных срабатываний на омографах-ловушках** (送灶/修/炎/气); char-BM25/фаззи — все 4 в top-5. Значит одиночные Han/кана как ключ — запрет схемы, longest-match, замена целой сущности.
- Спецификация модуля = **SillyTavern World Info / NovelAI lorebook** + иерархические резюме. ⚠ **DelTA (2410.08143, ICLR 2025) валидирует концепт многоуровневой памяти, но НЕ нашу ставку:** её память — LLM-в-цикле per-предложение, а не детерминированный no-LLM горячий путь; LTCR-1 = самосогласованность (не корректность); нет zh/ja→ru. Её Proper-Noun-Records (first-wins-без-обновления) сам порождает stale/contradiction/drift → наивно нельзя. **Наш детерминированный горячий путь академически нов → гейтится in-house eval (ниже).**
- Схема записи глоссария (D7 v1 + добавления реестра): `src, dst, type, aliases (граф с типами), gender (+hidden until_ch), speech, decl, since_ch/until_ch, status, note, translit_policy` **+ новое из валидации: `sense`** (полисемия/омографы), **ось «редакционное время»** отдельно от спойлер-окна (против DelTA first-wins-навсегда), констрейнты `UNIQUE(src,sense,window)` + обратная проверка dst-коллизий, `min_key_len` per-язык + запрет одиночных ключей, **артефакт нормализации** (NFKC + OpenCC упрощ./трад. + kana-folding + ruby-захват — симметрично к ключам и тексту; «самый вероятный баг тихо-пусто»). `decl`**safety-механизм грамматичности** (не фича рынка): без него форс формы в косвенный падеж ломает согласование.
- Схема записи глоссария (D7 v1 + добавления реестра): `src, dst, type, aliases (граф с типами), gender (+hidden until_ch), speech` *(→ DEPRECATED паком-19: «never read, never hashed», носитель голоса — `address_pairs` + профиль `memvoice.go`)*`, decl, since_ch/until_ch, status, note, translit_policy` **+ новое из валидации: `sense`** (полисемия/омографы), **ось «редакционное время»** отдельно от спойлер-окна (против DelTA first-wins-навсегда), констрейнты `UNIQUE(src,sense,window)` + обратная проверка dst-коллизий, `min_key_len` per-язык + запрет одиночных ключей, **артефакт нормализации** (NFKC + OpenCC упрощ./трад. + kana-folding + ruby-захват — симметрично к ключам и тексту; «самый вероятный баг тихо-пусто»). `decl`**safety-механизм грамматичности** (не фича рынка): без него форс формы в косвенный падеж ломает согласование.
- Инъекция — **селективная детерминированная** (v1: ключи/алиасы/леммы + sticky, ~100800 токенов). **Принцип «лучше ничего, чем мусор»**: пустой матч — норма, не тревога; бюджет допустимо недозаполнить; фильтр по точности ПЕРЕД приоритетом. Реальная тихая деградация — не пустота, а **ошибочная инъекция** (модель послушно следует неверной строке, уверенность↑ точность↓) → **трёхстороннее решение на каждую запись** (CONFIRMED / AMBIGUOUS+обязательный post-check / REJECT+лог) + per-chunk `retrieval-state` запись (наблюдаемость с первого дня).
- Трёхслойная защита (GalTransl): pre-replace нормализация (только на источнике) → мягкий глоссарий в промпте → **обязательный post-CHECK** (не опциональный флаггер: soft молча теряет 1736% терминов). **Слепой post-replace форм в русский выход — ЗАПРЕТ** (ломает согласование); форс только при инвариантном термине или полном `decl` с разрешимым падежом, иначе флаг. Спойлер-окно `since_ch/until_ch`**safety-гейт с жёстким reject+лог**, не UX-фича.
- Series bible — first-class; series-bible-lite (gender + ты/вы-журнал событий) в MVP.
@ -97,7 +97,7 @@ COGS (прямые ключи, **актуально — [experiments/08-cost-mod
- Деньги: дисциплина vojo целиком — биллинг по usage из ответа API (включая reasoning-токены), reserve-before-call/settle-after, потолок $ на книгу/день, request_log per-агент/per-глава/per-стадия, trace_id насквозь.
- Качество онлайн: **CometKiwi** (reference-free, локальная, не умеет отказывать — валидировать на 18+ ru-корпусе до доверия) + периодический GEMBA-MQM-подобный LLM-судья; **сырой BLEU/COMET как KPI художественности запрещён** (LitEval: автометрики отличают человеческий перевод максимум в 20% случаев).
- **Не-LLM гейты по фазам**: Фаза 1 (реализуемо в Go без морфологии) — детектор CJK-артефактов, глоссарная консистентность, coverage-гейт v1 (счёт предложений регэксп-сегментацией `。!?/.!?`, соотношение длин ±порог, blacklist refusal-паттернов; сам гейт проверяется мини-набором из 2030 фрагментов с искусственно выпиленными предложениями), правило «в TM коммитится только вывод, прошедший все гейты». Фаза 2 (Python-сайдкар) — морфодетектор канцелярита по чек-листу Галь (pymorphy/Natasha), MTLD/distinct-n, дисперсия длин, доля пассива, порт BlonDe-подобных дискурсивных проверок на русскую морфологию.
- Метрика глоссарной консистентности — с процедурой: знаменатель = вхождения `src`/алиасов в исходных чанках; числитель = наличие леммы `dst` (по полю `decl`) в соответствующем выводе; прономинализация («Ли Вэй → он») не штрафуется, гейт считает только `approved`-термины; в безлюдном режиме auto→approved автоматом с записью в журнал. **Это post-CHECK и он ОБЯЗАТЕЛЕН** (не опциональный флаггер — soft-глоссарий молча теряет 1736% терминов; правка валидации Р3): главный почти-бесплатный детектор тихой деградации, ловит и «модель проигнорировала термин», и «мы инъектили неверное». **Слепой post-replace форм в русский выход — запрещён** (ломает согласование).
- Метрика глоссарной консистентности — с процедурой: знаменатель = вхождения `src`/алиасов в исходных чанках; числитель = наличие леммы `dst` (по полю `decl`) в соответствующем выводе; прономинализация («Ли Вэй → он») не штрафуется, гейт считает только `approved`-термины; в безлюдном режиме auto→approved автоматом с записью в журнал. **Это post-CHECK и он ОБЯЗАТЕЛЕН** (не опциональный флаггер — soft-глоссарий молча теряет 1736% терминов; правка валидации Р3): главный почти-бесплатный детектор тихой деградации, ловит и «модель проигнорировала термин», и «мы инъектили неверное» (запрет слепого post-replace — в Р3).
- Оффлайн: паттерн routedecide/routereval из vojo → **golden-set реплей** решений об эскалации и вердиктов судьи со свипом порогов. Золотой набор — приватно из лицензионных изданий; GuoFeng Webnovel V2 — только dev (non-commercial, референсы MTPE-качества).
## Р8. Юридическая и продуктовая позиция. **Принято (переориентировано на EU после коррекции контура)**

View file

@ -18,7 +18,7 @@
## Фаза 0 — Каркас. ✅ ЗАВЕРШЕНА (04.07, приёмка на живых ключах)
Порт ядра vojo (llm/ledger/obs/store), SQLite + идемпотентные миграции, durable jobs + чанк-чекпоинты, translation brief + brief_hash, YAML-конфиги C1/C2 (граница «конфиг vs код» Р2). Приёмка выполнена исполняемо: `tmctl translate` гоняет чанк draft→edit с полным учётом $, повторный запуск из чекпоинтов за $0, kill -9 теряет максимум один вызов, `committed == SUM(checkpoints)`.
Порт ядра vojo (llm/ledger/obs/store), SQLite + идемпотентные миграции, durable jobs + чанк-чекпоинты, translation brief + brief_hash, YAML-конфиги C1/C2 (граница «конфиг vs код» Р2). Приёмочный инвариант денег — `committed == SUM(checkpoints)`; резюмируемость и «≤1 вызов» перечислены в приёмке Фазы 1 ниже.
## Фаза 1 — Перевод целой книги (текущая; машинерия в основном построена)
@ -48,7 +48,7 @@
- Чувствительный контент: **механизм построен паком-17** (content-labels × `accepts_labels`, D39.25/D39.26D39.28) — чанк-классификатор 03 и «каналы A/B» упразднены. Остаётся в Ф2: детектор молчаливых вырезаний, refusal-мониторинг.
- Интеграция llama-server (скрининг, abliterated канала B, эмбеддинги bge-m3 — второй эшелон, low-trust A7).
- Python-сайдкар качества: CometKiwi (валидировать на ru-литературе до доверия) + **морфо-гейт рода** (жалоба №1 читателей; pymorphy, вкл. глагол прош. вр. — C3 реестра) + гейт ты/вы по series-bible-lite + канцелярит-чеклист Галь; кандидат: T-index как офлайн-метрика translationese (готовое решение, 0.5B — влезает в стенд).
- **B6: валидатор Палладия/Поливанова — ПОСТРОЕНА ТОЛЬКО ПАЛЛАДИЙ-ПОЛОВИНА** (⚠ испр. 02.09): generic-парсер таблиц + сами таблицы-данные — `backend/internal/lang/langpack.go`, греп `pairFiles = []string{"palladius.txt"` + `backend/configs/langpacks/<пара>/palladius*.txt`; алгоритм слого-сегментации — `backend/internal/miner/miner_palladius.go`, греп `buildPalladiusCyrSyllables` (D39.16). **Поливанов-валидатора в коде НЕТ**: таблицы Поливанова = данные ja-пары, которых в репо нет (ruby-reading — их ground-truth); улика и грепы — `docs/architecture/13-tech-debt-anchors.md`, срез строки 81, греп `Поливанов-валидатор`.
- **B6: валидатор Палладия/Поливанова — ПОСТРОЕНА ТОЛЬКО ПАЛЛАДИЙ-ПОЛОВИНА** (⚠ испр. 02.09). Поливанов-валидатора в коде НЕТ: его таблицы = данные ja-пары, которых в репо нет (ruby-reading — их ground-truth). Грепы обеих половин — `06-memory-risk-registry.md`, абзац «Гейты … ИСПОЛНЕНЫ»; улика долга — `13-tech-debt-anchors.md`, греп `Поливанов-валидатор`.
- Резюме глава→арка→книга + гейт фактичности резюме (D1 реестра — у резюме нет post-check-аналога). Ты/вы-журнал ПОСТРОЕН — `address_pairs` (D7-Amendment-1/D21 п.2), `speech` deprecated D39.55.
- Batch API (50% только Gemini-судье/QA — exp08), нативный Gemini-адаптер (safety-контроль судьи, rf-замер), стриминг keep-alive.
- Eval-харнесс (golden-set реплей, свип порогов); регрессионный сьют из чек-листа «особо опасных ошибок» (12-common-failures §16: отрицание, перепутанный субъект, внутренняя речь→прямая).
@ -57,7 +57,7 @@
## Фаза 2.5 — Пилот 4 рук (решающая точка)
Протокол: `experiments/09-pilot-protocol.md` **+ обязательные поправки D13** (арм «моно vs билингв редактор same-model»; C2 на гетерогенных кандидатах; панель 23 семейства × 11+ повторов со свапом позиций, Bradley-Terry/медиана, grok не судит grok-выходы; пре-регистрация MDE и N≥3; харнесс чинится до прогона — эхо-стрип memory_eval, полные выходы, fidelity-ось; имена M0M3 для memory-режимов). Решения пилота: ядро C0C3, go/no-go ставки памяти (банк vs длинный контекст + adversarial-рука), валидность LLM-судьи (κ vs IAA, s*), think-ON/OFF (вкл. grok после reasoning-буфера в EstimateUSD), D1 моно-vs-билингв *(→ D30.1: решён досрочно exp12, арм остаётся ПОДТВЕРЖДАЮЩИМ)*, Annotator A/B, flag-rate G2 *(первый замер сделан этапом A: 5.3% — D24; в пилоте — minutes/flag, D25.6)*. 23 главы 18+ в корпусе — замер отказов по ролям (вкл. пробу Mistral, D14.2).
Протокол: `experiments/09-pilot-protocol.md` **+ обязательные поправки D13** (шесть пунктов, тело — слайс `../archive/architecture/05-decisions-D1-D38.md`, греп `^## D13`; полигон вносит их в док и харнесс ДО пре-регистрации). Решения пилота: ядро C0C3, go/no-go ставки памяти (банк vs длинный контекст + adversarial-рука), валидность LLM-судьи (κ vs IAA, s*), think-ON/OFF (вкл. grok после reasoning-буфера в EstimateUSD), D1 моно-vs-билингв *(→ D30.1: решён досрочно exp12, арм остаётся ПОДТВЕРЖДАЮЩИМ)*, Annotator A/B, flag-rate G2 *(первый замер сделан этапом A: 5.3% — D24; в пилоте — minutes/flag, D25.6)*. 23 главы 18+ в корпусе — замер отказов по ролям (вкл. пробу Mistral, D14.2).
Побочная ценность: человеческие BWS-данные zh/ja→ru — уникальный актив (академия пары не покрывает, WMT-лит. трек мёртв с 2024).
## Фаза 3 — Продуктовизация (после MVP)
@ -70,8 +70,7 @@ IDE-фронтенд (закладываем только API), B2B white-label,
## Метрики успеха MVP (v3)
1. COGS: телеметрия денег точна; эскалация уважает `budget_usd`; sanity-якоря ~$0.7/ранобэ стандарт, ~$11/вебновелла-500, селективный премиум ≤$25 (exp08; жёсткие $-гейты сняты D11).
2. Глоссарная консистентность approved-терминов ≥98% (процедура Р7/D10); ноль молчаливых потерь (coverage + spine-reconciliation).
3. Качество: **статистически значимый win rate >50%** (биномиальный тест, α=0.05, ≥150 человеческих попарных сравнений, пре-регистрация MDE — D13.4) против baseline «DeepSeek+селективный глоссарий» (уровень VseGPT).
4. Резюмируемость: kill -9 в середине главы → продолжение с потерей максимум одного LLM-вызова.
5. 18+: канал B (Grok + abliterated, интерим D14) переводит explicit-корпус без молчаливых вырезаний, подтверждено детектором.
Деньги (sanity-якоря ~$0.7/ранобэ, ~$11/вебновелла-500, селективный премиум ≤$25 — exp08; жёсткие $-гейты сняты D11) · глоссарная консистентность ≥98% · ноль молчаливых потерь · резюмируемость с потерей ≤1 вызова — те же критерии, что «Приёмка Фазы 1» выше, здесь не дублируются. Сверх них:
1. Качество: **статистически значимый win rate >50%** (биномиальный тест, α=0.05, ≥150 человеческих попарных сравнений, пре-регистрация MDE — D13.4) против baseline «DeepSeek+селективный глоссарий» (уровень VseGPT).
2. Чувствительный контент: explicit-корпус проходит пайплайн без молчаливых вырезаний, подтверждено детектором. ⚠ **испр. 02.09:** прежняя формулировка «канал B (Grok + abliterated, интерим D14)» СНЯТА — в движке нет понятия «18+» и нет фиксированного состава канала, маршрут = `content_labels` × `accepts_labels` (D39.25/D39.26D39.28; живые ограничения данных — «Правило 18+» выше).

View file

@ -4,7 +4,7 @@
> **СТАТУС-АПДЕЙТ 25.07 (оркестратор №7): код-география §3 перечёркнута паком-15 (D39.23).** Контракты §3 живы семантикой, но монолита `internal/pipeline` больше нет: движок разложен на `internal/{text,seed,chunk,miner,checks,membank}` + композит-корень `pipeline`; конфиг-слой §3.8 расширен `configs/pairs/<пара>` + `configs/langpacks/` + промпт-конвенцией `prompts/<пара>/<роль>.md` и строгим KnownFields-декодом (паки 15/16). Что из §6-техдолга закрыто — перечислено там же, с грепами; снапшот-дисциплина и golden-гард D23 живы в новой раскладке (golden байт-в-байт, парити EXACT — D39.23).
Вердикт шага 0 — перевалидации решений v2 глазами реализатора перед Фазой 0 (метод: построчное чтение донорского кода vojo + четыре критик-линзы, ~940k токенов; донорский отчёт — `../research/10-vojo-ai-bot-review.md`).
Вердикт шага 0 — перевалидации решений v2 глазами реализатора перед Фазой 0 (донорский отчёт — `../research/10-vojo-ai-bot-review.md`).
**Живое здесь — §3: контракты, которые Фаза 0 приняла на себя.** Разделы «общий вердикт исполнимости» и «упущения передавшей сессии» СНЯТЫ как прожитые: их предмет либо стал контрактом §3 (cache-write в `Usage` и формула стоимости — §3.5 · таймауты/ретраи параметрами клиента и чтение `Retry-After` вместо трёх захардкоженных · мини-раннер C1), либо ушёл в свои дома — прокси-ловушка (Go stdlib не проксирует loopback, опасны не-loopback локальные адреса вроде WSL-gateway 172.x; в коде `llm.NoProxyClient`) и мёртвый Grok 4.1 Fast живут в `docs/experiments/00-provider-quirks.md` и `backend/configs/models.yaml`, оценка переписывания `store.go` и счётчики донора — в `../research/10-vojo-ai-bot-review.md`, хроника — `../archive/PROGRESS-2026-07-04-10.md`.
> ⚠ **§2 СНЯТ — а код на него ещё ссылается, поэтому вот куда он уехал** (заглушка, испр. 02.09): **п. 2 (таймауты/ретраи параметрами клиента, чтение `Retry-After` вместо трёх захардкоженных)** → параметры клиента в `backend/internal/llm/httpllm.go`, греп `03-implementation-notes §2 item 2`; **п. 5 (single-connection write pool + `BEGIN IMMEDIATE`)** → §3.6 «SQLite-рецепт» ниже, носитель кода — `backend/internal/store/store.go`, греп `03-implementation-notes §2 item 5`. Комментарии в коде НЕ трогались — их адресат теперь описан здесь.
@ -38,7 +38,7 @@ style sheet, резюме книги/арок на момент старта д
### 3.4 Ключ TM (Фаза 1)
Действующий ключ — ратифицированный оркестратором `(chunk_src_hash, lang_pair, model_id, prompt_version, brief_hash, context_snapshot_hash)`: **`model_id` и `prompt_version` ВХОДЯТ в ключ**, а не в метаданные (тюнинг промпта и смена модели легитимно инвалидируют TM; перечанкование — by design). Носитель — Р6, `01-decisions.md`, греп `Ключ TM подтверждён`; строить по нему, а не по первой редакции этого параграфа (она клала `model`/`prompt_version` в метаданные и снята). Нормализация src перед хэшем — только whitespace/Unicode NFC и **до** pre-replace терминов, иначе подтверждение термина инвалидирует TM через чёрный ход (прямой запрет Р6). В Фазе 0 это неважно: cross-book TM не реализован, есть только checkpoint/resume request-hash, который `model`+`prompt_version` уже включает через snapshot.
Действующий ключ — ратифицированный оркестратором `(chunk_src_hash, lang_pair, model_id, prompt_version, brief_hash, context_snapshot_hash)`: **`model_id` и `prompt_version` ВХОДЯТ в ключ**, а не в метаданные (тюнинг промпта и смена модели легитимно инвалидируют TM; перечанкование — by design). Носитель — Р6, `01-decisions.md`, греп `Ключ TM подтверждён`. Нормализация src перед хэшем — только whitespace/Unicode NFC и **до** pre-replace терминов, иначе подтверждение термина инвалидирует TM через чёрный ход (прямой запрет Р6). В Фазе 0 это неважно: cross-book TM не реализован, есть только checkpoint/resume request-hash, который `model`+`prompt_version` уже включает через snapshot.
### 3.5 Нейтральный интерфейс LLM (расширения к типам vojo)
@ -101,10 +101,6 @@ C2, cache TTL per-стадия. В models.yaml: цены (+cache write/read), п
Что из того среза — МЕХАНИКА, а не цена, и потому остаётся здесь (проверено 04.07 по официальным докам вендоров): **минимальный кэшируемый префикс зависит от модели** (короче лимита кэш молча НЕ создаётся, у Anthropic — 1024/4096 токенов по моделям) · **thinking биллится как output** полным объёмом, даже когда отображается summary · **TTL кэша истекает между вызовами одной стадии** (латентности чанков 63278 с + гейты) ⇒ TTL — параметр стадии, а телеметрия обязана показывать `cache_read=0` при повторных вызовах, иначе тихая инвалидация невидима · **DeepSeek-кэш best-effort** — экономику считать только по фактическому `usage`.
## 4. Мелкие поправки к research/10 — СНЯТЫ
Уточнения счётчиков донора относились к отчёту `../research/10-vojo-ai-bot-review.md` и к коду, которого в этом репозитории нет; мерило порта — сам порт.
## 5. [НУЖНО РЕШЕНИЕ] — СНЯТО, всё развязано
Пять вопросов 04.07 закрыты, карта развязок — в баннере вверху (тела D11/D14/D19/D23 — в слайсе `../archive/architecture/05-decisions-D1-D38.md`); пятый, не попавший в карту, — пункты оркестратору (фазовые пометки диаграмм, владелец задачи cache-hit), отработан арх-ресетом D39. Формулировки вопросов — `../archive/PROGRESS-2026-07-04-10.md`.

View file

@ -15,7 +15,7 @@
| Режим отказа | Механизм | Фаза | Статус |
|---|---|---|---|
| Дрейф имён/терминов между вызовами | Глоссарий + гейт консистентности (по леммам через `decl`) | 1 | ✅ |
| Система имён 名/字/号/прозвища: «один персонаж = 36 людей» | **Alias-граф** в глоссарии + NER-гейт «новая форма известной сущности = блок»; новое имя без фуриганы/контекста → эскалация | 12 | 🔶 схему Р3 расширить: aliases → граф с типами (имя/цзы/хао/прозвище/титул) |
| Система имён 名/字/号/прозвища: «один персонаж = 36 людей» | **Alias-граф** в глоссарии + NER-гейт «новая форма известной сущности = блок»; новое имя без фуриганы/контекста → эскалация | 12 | 🔶 половина: типы узлов в схеме ЕСТЬ (`store/migrate.go`, греп `alias_type TEXT NOT NULL` — name/zi/hao/nickname/title); NER-гейт не построен |
| Коллапс терминосистемы рангов («Immortal, immortal or immortal») | Глоссарий-тип **ranked-set** + проверка инъективности (2 исходных ≠ 1 целевой) и порядка ступеней | 12 | 🔶 новый тип записи |
| Значащие прозвища: перевести один раз и навсегда | Поле `nickname_translation`, первичный перевод — сильная модель/человек, дальше — лок | 1 | ✅ (консенсус изданий: имена — Палладий, прозвища — переводить) |
| Обращения шисюн/гэгэ/о-нии-чан: транскрипция vs перевод | Пресеты brief «фанатский/издательский» (войны фандомов — 586 стр. холивара по одной Мосян; смертный грех — непоследовательность) + **матрица обращений по парам** с версионированием | 12 | 🔶 матрица обращений = расширение series-bible-lite |
@ -37,9 +37,9 @@ Pro-drop (местоимения лишь в ~11% японских предло
| Режим отказа | Механизм | Фаза | Статус |
|---|---|---|---|
| Рандомное ты/вы внутри сцены | ты/вы-матрица series-bible-lite → **журнал событий переходов** + детектор несанкционированных флипов; судья классифицирует флаг (ошибка vs мотивированный переход) | 2 | 🔶 матрица → журнал событий (уточнение Р3) |
| Рандомное ты/вы внутри сцены | ты/вы-матрица series-bible-lite → **журнал событий переходов** + детектор несанкционированных флипов; судья классифицирует флаг (ошибка vs мотивированный переход) | 2 | 🔶 журнал ПОСТРОЕН — `address_pairs` (D7-Amendment-1/D21 п.2); детектор несанкционированных флипов и судья — Ф2 |
| Кэйго-сдвиг как перелом отношений | **Регистровый трекер** пар персонажей по оригиналу (детерминированный: desu/masu, -сан→имя) → событие в ты/вы-журнал; русский передаёт это напрямую через ты/вы — эксплуатировать преимущество ru | 2 | 🔶 новый пре-пасс |
| Gendered 1-е лицо (боку/орэ/атаси), yakuwarigo | Анкета персонажа: `first_person`, речевой профиль, ru-компенсация маски; судья консистентности голоса | 2 | ✅ (поля speech в Р3) |
| Gendered 1-е лицо (боку/орэ/атаси), yakuwarigo | Анкета персонажа: `first_person`, речевой профиль, ru-компенсация маски; судья консистентности голоса | 2 | ✅ `first_person` + профиль голоса пака-19 (`membank/memvoice.go`, `self_ref`). ⚠ испр. 02.09: `glossary.speech` из Р3 DEPRECATED — never read, never hashed (`store/migrate.go`, греп `superseded by the address_pairs journal`) |
| Стирание голосов («все говорят одинаково, как ИИ-озвучка») | Речевые профили + монолингвальный судья «отличимы ли реплики без атрибуции?» + анти-translationese пасс | 2 | ✅ |
| Нормализация акцентов/диалектов/pidgin | Профиль девиации + стратегия компенсации (лексика, не фонетика) + сигнал «в источнике девиация есть, в цели 0%» | 23 | 🔶 |
| Мат: недожим (RLHF) и пережим | Двусторонний лексиконный гейт силы обсценности (03) + профиль грубости персонажа + политика brief (18+ маркировка) | 2 | ✅ |
@ -118,8 +118,7 @@ Pro-drop (местоимения лишь в ~11% японских предло
- **Нестабильность качества по чанкам** (41.7% MT-чанков с всплеском негатива против 11.9% у человека — LAIT): телеметрия распределения вердиктов по чанкам, эскалация хвоста, а не среднего. → в Р7.
- **«Проклятие 300-й главы»** (витрина отредактирована, платный хвост — сырец; бойкоты Novelous/Webnovel): равномерные гейты по всем главам + **«паспорт качества главы»** в отчёте. → ПОСТРОЕН: `pipeline.ChapterPassport` (D12), rollup в `tmctl export` (D29.1).
- **Надёжность как дифференциатор**: Trustpilot booktranslator.ai — непереведённые файлы, смесь языков, молчащая поддержка. Наши детерминированные гейты целостности — конкурентное преимущество сами по себе.
- **Пользователи хотят рычаги, а не магию** (любимые фичи — редактируемые глоссарии и правка местоимений): подтверждение IDE-стратегии и «глоссарий — ядро продукта».
- Позиционные следствия этой карты (надёжность как дифференциатор против booktranslator.ai; «пользователи хотят рычаги, а не магию» → редактируемый глоссарий как ядро продукта) живут в своих домах: Р9/Р10 `01-decisions.md` и `research/12-consumer-feedback.md`, здесь копий нет.
## Следствия для плана (сводка изменений)

View file

@ -6,7 +6,8 @@
> Одна строка на КАЖДУЮ ноту журнала решений: № · дата · суть · статус · где тело · темы.
> ⚠ **ФОРМА ДВУХ ПОСЛЕДНИХ КОЛОНОК РАЗЪЕХАЛАСЬ, замерено 30.08 (аудит доков):** из 224 строк 74 несут в колонке «статус» не статус, а ЗАМЕТКУ о живом остатке («ЖИВОЕ: …»), а собственно `жив` уехал в колонку «тело». Читать так: **колонки 45 у свежих нот — пара «статус ⟷ что осталось живым», порядок в паре не гарантирован; статус ноты определяй по слову `жив`/`superseded`/`частично`, где бы из двух оно ни стояло, а место тела — по слову `слайс`.** Приведение к одной форме — строка бэклога **242**; чинить руками 74 строки без гейта дороже, чем читать по этому правилу. Ведёт оркестратор при лендингах: новая нота = новая строка ТЕМ ЖЕ коммитом (полноту сторожит `docs/scripts/counts.py --check`). Суть и статус здесь — НАВИГАЦИЯ, не контракт: при конфликте побеждает ТЕЛО ноты (живой [`05-decisions-log.md`](05-decisions-log.md) → слайсы `../archive/architecture/05-decisions-*.md`). Несущие эрраты к фактам старых нот живут в шапке живого D-лога — их читать ОБЯЗАТЕЛЬНО, реестр их не дублирует. Темы (для грепа оси «какой закон по X»): деньги · шов · банк · промпт · судья · гейты · контракт · платформа · фронт · полигон · ToS · общность · процесс · нарезка · голос · инфра · модели.
> Родословная реестра (прозаическая карта D1D39.28 пересобрана докс-паком строки 167, вместе с путём worksheet и методом сверки полноты) — D39.126 п.1(а). «тело: жив» = живой D-лог; «слайс N» = `../archive/architecture/05-decisions-N.md`.
> Легенда колонки «тело»: «жив» = живой D-лог, «слайс N» = `../archive/architecture/05-decisions-N.md` (родословная реестра — D39.126 п.1(а)).
> ⚠ **«ЖИВОЕ: строка N» — снимок НА МОМЕНТ ноты.** ID закрытой строки бэклога `../PROGRESS.md` ИСЧЕЗАЕТ (закрытая уходит в D-лог с номером решения, ID не переиспользуется), поэтому «строки N в трекере нет» читается как ЗАКРЫТА, а не как битая ссылка — замерено 02.09: так уехали ссылки 18 строк реестра.
| № | дата | суть | статус | тело | темы |
|---|---|---|---|---|---|

View file

@ -12,7 +12,7 @@
Выход сессии **«Валидация банка памяти»** (промт `docs/archive/prompts/MEMORY_RESEARCH_SESSION_PROMPT.md`). Писался как вход для фиксации схемы store/глоссария v2 (D7); схема с тех пор зафиксирована и построена.
Метод: многоагентный ресёрч по 7 направлениям + независимая адверсариальная верификация каждой находки по первоисточникам + локальный эмпирический бенчмарк retrieval на реальном PD-корпусе (`eval/retrieval_bench.py`, `eval/data/retrieval_bench/`) + чтение реального кода `backend/`. Полный разбор с источниками и датами — `docs/research/13-memory-bank-validation.md`. Продуктовый код здесь не пишется — реестр описывает требования к нему.
Эмпирика строк ниже снята локальным бенчмарком retrieval на реальном PD-корпусе (`eval/retrieval_bench.py`, `eval/data/retrieval_bench/`); полный разбор с источниками и датами — `docs/research/13-memory-bank-validation.md`. Продуктовый код здесь не пишется — реестр описывает требования к нему.
**Главный вывод для чтения таблицы.** Опасение владельца («retrieval вернёт пусто/мусор → перевод деградирует тихо») уточнено литературой: **пустой retrieval — нормальное и безопасное состояние** детерминированного горячего пути (большинство чанков законно не содержат ключей глоссария); откат к базовому поведению модели. **Реальная тихая деградация — это ошибочная инъекция** (омограф/короткий алиас/спойлер-утечка/низкорелевантный эмбеддинг-сосед): подсунутая строка глоссария работает как мягкая инструкция, и сильная модель ей **послушно следует — уверенность растёт, а точность падает** (arXiv 2510.00829). Поэтому вся защита строится на двух принципах: **«лучше ничего, чем мусор»** (не добивать токен-бюджет соседями — arXiv 2401.14887, 2310.01558) и **точность важнее полноты на горячем пути**, плюс **обязательный детерминированный post-check** как главный (и почти бесплатный) детектор тихой деградации.
@ -29,9 +29,9 @@
| # | Сценарий отказа (как ломает перевод) | Вер./Тяж. | Механизм защиты | Слой | Где в коде/схеме | Фаза | Статус |
|---|---|---|---|---|---|---|---|
| A1 | **Пустой/слабый retrieval трактуется как ошибка** → пайплайн «добивает» бюджет ближайшими эмбеддинг-соседями или фоновыми записями → near-miss дистрактор роняет качество (до 67%, 2401.14887; NLI-фильтр спасает, 2310.01558) | С / 🟠🔇 | «Лучше ничего, чем мусор»: на пустом ключевом матче инъектить **только** активные sticky-записи; бюджет **допустимо недозаполнить**; фильтр по точности **перед** сортировкой по приоритету (не только `approved>auto`) | DET | сборщик контекста (`render.Messages`, инъекция между system и user, `render.go:133-136`) | 1 | 🔶 добавить precision-gate; в research/05 §5.2 бюджет заполняется по приоритету, не по точности |
| A1 | **Пустой/слабый retrieval трактуется как ошибка** → пайплайн «добивает» бюджет ближайшими эмбеддинг-соседями или фоновыми записями → near-miss дистрактор роняет качество (до 67%, 2401.14887; NLI-фильтр спасает, 2310.01558) | С / 🟠🔇 | «Лучше ничего, чем мусор»: на пустом ключевом матче инъектить **только** активные sticky-записи; бюджет **допустимо недозаполнить**; фильтр по точности **перед** сортировкой по приоритету (не только `approved>auto`) | DET | сборщик контекста (`render.Messages`, инъекция между system и user, `render.go:133-136`) | 1 | ✅ ПОСТРОЕНО (⚠ испр. 02.09): точность ПЕРЕД приоритетом — `membank.priorityRank` (Confirmed → не-sticky → approved), пустая выборка не инъектит НИ ОДНОГО сообщения (`internal/membank/memory.go`, греп `better nothing than garbage`); в research/05 §5.2 бюджет заполняется по приоритету, не по точности |
| A2 | **Ошибочная инъекция** (омограф/короткий алиас/низкорелевантный сосед) → модель послушно следует мягкой инструкции, уверенность растёт, точность падает (2510.00829) — **главный источник тихой деградации** | С / 🔴🔇 | Трёхстороннее явное решение **на каждую запись-кандидат**: `CONFIRMED` (точный ключ/лемма, `approved`, спойлер-валидна) → авторитетно; `AMBIGUOUS` (короткий/общий алиас, коллизия поверхности, `auto/draft`) → инъекция с явной пометкой «unverified — проверить» **+ принудительный post-check**; `REJECT` → выкинуть и залогировать. Паттерн CRAG (accept/verify/reject), но каждая ветка наблюдаема | DET | сборщик контекста + `disposition`-запись | 1 | ✅ ПОСТРОЕНО: disposition + `retrieval-state` в `internal/membank` (абзац «Гейты … ИСПОЛНЕНЫ» ниже); ⚠ AMBIGUOUS-пометку «проверить» читать через D39.104 в шапке — с провода она снята |
| A3 | **CJK-подстрока срабатывает на чужом смысле** (阿Q, 送灶-обряд vs «送到灶», 炎=пламя vs имя 萧炎, 道/气/修 полисемия) → инъекция неверной записи | В / 🟠🔇 | Запрет одиночных Han/каны/латинской буквы как самостоятельного ключа (schema-констрейнт, не соглашение); longest-match; замена только целой сущности; условные `judgment word` (GalTransl post-dict). **Эмпирика (`retrieval_bench`): точный многосимвольный подстрочный матч — precision 1.0, 0/4 ложных срабатываний на этих ловушках; char-BM25/фаззи — все 4 ловушки в top-5** → фаззи/одиночные ключи на горячий путь не пускать | DET | матчер ключей; `glossary.min_key_len` per-язык; поле `sense` | 1 | 🔶 ключевая гигиена как констрейнт схемы (новое) |
| A3 | **CJK-подстрока срабатывает на чужом смысле** (阿Q, 送灶-обряд vs «送到灶», 炎=пламя vs имя 萧炎, 道/气/修 полисемия) → инъекция неверной записи | В / 🟠🔇 | Запрет одиночных Han/каны/латинской буквы как самостоятельного ключа (schema-констрейнт, не соглашение); longest-match; замена только целой сущности; условные `judgment word` (GalTransl post-dict). **Эмпирика (`retrieval_bench`): точный многосимвольный подстрочный матч — precision 1.0, 0/4 ложных срабатываний на этих ловушках; char-BM25/фаззи — все 4 ловушки в top-5** → фаззи/одиночные ключи на горячий путь не пускать | DET | матчер ключей; `glossary.min_key_len` per-язык; поле `sense` | 1 | ✅ ПОСТРОЕНО (⚠ испр. 02.09): пер-язычный пол ключа + явный escape-hatch — `internal/membank/memseed.go`, грепы `minKeyLenFor` и `AllowShort` |
| A4 | **Молчаливо-пустой матч из-за орфографии** (упрощ./трад. 鲁/魯, полу/полноширинные, кандзи↔кана 鈴木/すずき, ruby-чтения) → ключ есть в тексте, но не в той форме → запись не инъектируется | В / 🟠🔇 | Обязательный слой **нормализации перед матчем** (NFKC + OpenCC упрощ./трад. + kana-folding + захват ruby-чтений), симметрично к ключам/алиасам и тексту чанка; версионированный тестируемый артефакт | DET | pre-match нормализация (связать с pre-replace GalTransl); поле `aliases` | 1 | ✅ ПОСТРОЕНО: `internal/text` + данные пары; «тихо пусто» остаётся самым вероятным багом этого слоя |
| A5 | **Местоименные чанки** (имя не встречается, только «он/她/彼») → нужная запись не активируется | В / 🟡 | Sticky scene-inertia (персонажи из предыдущих 12 чанков остаются); это состояние, а не retrieval — **не** решать эмбеддингами | DET | sticky-состояние сборщика | 1 | ✅ (в дизайне; см. World Info sticky) |
| A6 | **Lost-in-the-middle**: глоссарий закопан между стопкой резюме книги/арки/главы | Н / 🟡 | Авторитетный блок глоссария — рядом с чанком (конец промпта), не в середине; при наших размерах инъекции эффект мал, но избежать бесплатно | DET | раскладка `render.Messages` (согласовать с кэш-раскладкой Р5) | 1 | 🔶 |
@ -81,7 +81,7 @@
| F1 | **`snapshotID` не покрывает память → тихий расходящийся ре-пэй (D5.2)**: инъекция памяти меняет `request_hash`, но не `snapshotID` → resnapshot-гейт молчит → ре-ран старой главы промахивается мимо чекпоинта и **переоплачивает расходящимся переводом**, ломая инвариант Р6 | В / 🔴🔇 | **Свернуть в snapshot ОБА:** (1) состояние памяти (**content-hash материализованного** банка на момент старта джобы — рендер читает **замороженную** версию, не live; **D8: content-hash, НЕ версия-счётчик** — счётчик молча дрейфует, если забыли бампнуть) и (2) context-assembly-конфиг (`glossary_injection`, `stm_depth`, `overlap`). Тогда рендер снова чист по snapshot. | DET | `runner.snapshotID()`/`memoryVersion()`/`contextSnap` | 1 | ✅ ЗАКРЫТО: `Runner.memoryVersion()` (`pipeline/snapshot.go`) сворачивает в snapshot `membank.ComputeVersion` + `context_assembly` + `Capability`. ⚠ ЧТО именно фолдится — по ⚠-поправке 22.08 в шапке (КАЖДАЯ строка банка, не approved-only), не по формулировке этой строки. |
| F2 | **Токен-бюджет: eviction не определён**. При превышении бюджета (matched + sticky > лимит) **какая запись выпадает — не задано**; выпавшая нужная запись = тихая деградация | С / 🟡🔇 | Явная политика приоритета/вытеснения (World Info inclusion-groups: approved>auto; персонажи чанка>фоновые) **+ логировать факт вытеснения** (не молча) | DET | сборщик; `retrieval-state` запись | 1 | ✅ ЗАКРЫТО: приоритет — `membank.priorityRank` (confirmed>ambiguous, exact>sticky, approved>auto/draft), вытеснение логируется (`Select.Evicted``n_evicted`) |
| 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 | 🔶 нет строки бэкапа/интеграла (находка критика) |
| F4 | **Один SQLite-файл на книгу = SPOF**: повреждение файла молча теряет весь глоссарий+резюме | Н / 🟠🔇 | Бэкап/интеграл-чек/версионирование файла книги; экспорт TMX/TBX как побочный бэкап | DET | store; экспорт | 2 | ✅ ПОСТРОЕНО (⚠ испр. 02.09): `store.BackupSQLite`/`store.IntegrityCheck` + `tmctl backup` (`internal/store/backup.go`); хвост — в бэклоге, см. абзац «Гейты … ИСПОЛНЕНЫ» |
| F5 | **Коррелированный отказ судьи-экстрактора**: адъюдикация конфликтов и подтверждение кандидатов — одна модель на одних и тех же трудных кейсах (редкие имена, неоднозначный смысл) → систематически-неверный судья тихо промоутит плохие approved-ключи → retrieval-state lock-in | С / 🟠🔇 | Независимая проверка (судья чужого семейства / человек) на промоушене approved-ключа; first-encounter имя не промоутится в approved до батч-подтверждения раз в главу | LLM(2-й)+HUMAN | пайплайн подтверждения терминов | 2 | 🔶 (находка критика; смыкается с A2/B1) |
## G. Популяция глоссария и человеческая ёмкость (корень и петля)
@ -95,9 +95,7 @@
## Контракт горячего пути (снять противоречие до «где в коде»)
**Резолюция** (то же решение — `03-implementation-notes.md` §3.6):
1. **Горячий путь — НЕ FTS5**, а **детерминированный multi-pattern матч** (Aho-Corasick/double-array trie по `src`+алиасам над нормализованным чанком; для ru/en — по леммам/`decl`). FTS5/BM25 на горячем пути для zh/ja **молча вернёт ничего** (дефолтный токенайзер не сегментирует CJK) — их туда не ставить. Эмбеддинги на горячем пути — тоже нет (Р3). Это подтверждено эмпирикой (A3).
1. **Горячий путь — НЕ FTS5 и не эмбеддинги**, а детерминированный multi-pattern матч. Развёрнуто, с причиной и эмпирикой — Р3 `01-decisions.md`, `03-implementation-notes.md` §3.6 и строка A3 выше; здесь копия снята как третий пересказ одного решения.
2. **sqlite-vec: brute-force KNN в MVP остаётся верным** — эмпирика Q2: <20 мс на 100k×1024-d в чистом numpy, sqlite-vec-scalar 81108 мс на 1M, на порядки выше нужд одной книги. Рациональ отказа (не «pure-Go не может») Р3 `01-decisions.md`; `ncruces/go-sqlite3`+sqlite-vec самый дешёвый триггер миграции, если вектора станут узким местом.
## Гейты для бэкенда перед фиксацией схемы store/глоссария v2 — ИСПОЛНЕНЫ
@ -117,4 +115,4 @@
## In-house eval — обязателен (числа литературы не переносятся)
**Ни один процитированный источник не меряет zh/ja→ru** (DelTA/TransAgents/Karpinska/WMT25 — En-центричны или ru только как *источник*; вендорские memory-числа — про chat-память о пользователе, при честной методологии их бьёт ванильный RAG). Поэтому перед заморозкой ставки нужен **свой замер на реальном стеке и направлении** — детали, acceptance-критерии и протокол (bank-vs-long-context baseline, «random-terminology» адверсариальный arm из WMT25) — в `docs/research/13-memory-bank-validation.md` §Вердикт. Реестр рисков не заменяет этот замер — он делает провалы **явными**, что и есть ответ на опасение владельца: **тихую деградацию мы конвертируем в громкую (post-check + disposition-лог + retrieval-state), а не устраняем её обещанием.**
**Ни один процитированный источник не меряет zh/ja→ru** (DelTA/TransAgents/Karpinska/WMT25 — En-центричны или ru только как *источник*; вендорские memory-числа — про chat-память о пользователе, при честной методологии их бьёт ванильный RAG). Поэтому перед заморозкой ставки нужен **свой замер на реальном стеке и направлении** — детали, acceptance-критерии и протокол (bank-vs-long-context baseline, «random-terminology» адверсариальный arm из WMT25) — в `docs/research/13-memory-bank-validation.md` §Вердикт. Реестр рисков этот замер не заменяет: он лишь конвертирует тихую деградацию в громкую (post-check + disposition-лог + retrieval-state).

View file

@ -108,59 +108,27 @@
- Целевой контракт: переводчик отдаёт **структурный ~верный черновик**; редактор — узкая правка смысла+стиля,
в идеале **diff-based** (search/replace-спаны + детерм. Go-apply → ограниченный blast-radius, дешевле, аудируемо,
структурно omission-safe). Между проходами — гейт.
- **⚠ Арм «переводчик отдаёт структуру» никогда не тестировался** — решает ресёрч-матрица (§4), а не догадка.
- ⚠ **Арм «переводчик отдаёт структуру» ДО СИХ ПОР не тестировался** — это Q4c (reflow отдельным проходом), единственное неизмеренное плечо; измерены только соседи: Q4a (верность на translate-стадии не покупается, D39.9) и Q4b (диффы ОТЛОЖЕНЫ, D39.108), топологию решил эксп-21 (D39.117). ⚠ испр. 02.09: «решает ресёрч-матрица §4» СНЯТО — §4 отработан, маршрут вопроса теперь `10-prompt-architecture.md` §4 п.4 + `experiments/19-editor-contract-q4b.md` §«Границы».
### Слой 4 — Память (код-корень) · концерн 3
- Починить **disposition-слепой** `suppressContained`: более длинный НИЗКО-доверенный ключ (draft/ambiguous) не должен
подавлять вложенный ВЫСОКО-доверенный (approved/confirmed). Это закрывает терм-дрейф в КОДЕ (сейчас — сид-воркэраунд).
- **Тихие дропы → в громкие**: подавленный approved-термин обязан попадать в retrieval-state (обещание research/13).
- ✅ ИСПОЛНЕНО (D39.13, пак-11 WS2): D1-моно-рационализация из редакторского блока убрана, и «давать ли билингв-редактору src→dst» больше не открытый вопрос — блок рендерится src→dst-мэппингом, CONFIRMED-only, форма зафолжена в снапшот (`internal/membank/memory.go`, греп `RenderEditorConstraintBlock` и `RenderFormatVersion`).
### Слои 47 — тело замысла СНЯТО, адреса здесь
### Слой 5 — Измерение качества в контуре · главная цель + концерн 5
- Per-run/per-segment авто-сигнал: **детерминированный структурный KPI** (предл./абзац, диалог-тире, CJK-утечка,
глоссарий-консистентность) — дёшево, build-now — + **дешёвая span-проверка смысла** (полярность/число/ранг/пропуск →
тот самый inversion/omission-бэкстоп; семантический span-судья — ресёрч-зависим, позже).
- Даёт то, что владелец просил (телеметрия качества с 1-го дня, п.25/п.31) и делает КАЖДУЮ правку ниже измеримой;
предпосылка самоулучшения.
### Слой 6 — Export-contract (нормализация) · концерн 3
- Единая нормализация КАЖДОГО финального текста (NFKC-fold + пробелы/CJK-пунктуация/U+3000) — тот самый D29.1a-слой,
который D-лог откладывает. Санитайзер сводится к **чистому детектору** (флагует только по-настоящему невосстановимое).
- Убирает: дефект чинится на флагнутом чанке, но уезжает сырым на чистом; дубль NFKC; churn регексов v1→v4.
### Слой 7 — Гигиена расширяемости · концерн 3 п4
- **Реестр** `role→инъекция` (map/стратегия из конфига) вместо рукоправимого switch — чтобы Ф2-annotator/voice
добавлялся данными, не хирургией.
- **Target-aware гейты**: readability-набор за `TargetLang` (сейчас слеп — любой не-ru target даст ложные флаги).
- Де-размазать strip-and-export (5 файлов → один resolver `classification→(disposition, exportText)`).
- Снести сироты-промпты (`analyst.md`/`terminologist.md`/дубль `editor-mono.md`), мёртвый `gatesEnabled()`;
вынести `foldModelWire()` (tripwire на 3-ю модель-ось уже стоит).
- Эталоны для копирования: `config→stage-list`, `baseRequestLog`.
Слой 4 «Память» · 5 «Измерение качества в контуре» · 6 «Export-contract» · 7 «Гигиена расширяемости» стояли здесь предписанием 13.07; всё предписанное построено либо отменено, действующие статусы с номерами паков — **строки 47 шапки-таблицы**, пофакторный разбор находок с диспозициями — `../archive/architecture/08-sync-audit-ledger.md`, эталонные сеамы `config→stage-list`/`baseRequestLog` — §1 и §6. Единственный код-факт, которого шапка не несёт: редакторский блок памяти рендерится src→dst-мэппингом, CONFIRMED-only, форма зафолжена в снапшот — D1-моно-рационализация убрана, «давать ли билингв-редактору src→dst» больше не открытый вопрос (`internal/membank/memory.go`, греп `RenderEditorConstraintBlock` и `RenderFormatVersion`; D39.13, пак-11 WS2).
---
## 3. Карта находок → слои (полный ледджер — `../archive/architecture/08-sync-audit-ledger.md`)
Пофамильный перечень `L1-*``L8-*`/`H1``H5`/`H12`/`H14` по слоям 17 СНЯТ: все они закрыты стройкой (статусы — шапка-таблица), а тела находок с диспозициями живут в ледджере. Живой остаток — только процессная строка:
| Слой | Несущие находки (HIGH, CONFIRMED) |
|---|---|
| 1 Сегментация | `L2-1500-untested-apriori`, `L2-budget-wrong-unit`, `L2-token-budget-not-semantic`, `L2-edit-unit-equals-chunk`, `L2-cross-chunk-only-glossary`, `L2-d357-phantom-decision`, `H1-smart-chunking-never-formalized`, `L2-no-boundary-algo-research` |
| 2 Слой пар | `L4-prompts-not-per-pair-zh-baked`, `L4-convention-pack-layer-never-built`, `L4-prompt-language-always-russian`, `H2`, `L4-adding-a-pair-is-a-rewrite-not-config` |
| 3 Контракт t/e | `L1-editor-four-mandates-one-fullregen-pass`, `L1-fidelity-has-no-owner-in-cheap-path`, `L1-diff-editing-never-built`, `H3/H4`, `L1-translator-structure-arm-never-tested` |
| 4 Память | `L3-seed-workaround-not-code-root`, `L3-recurrence-draft-longer-eats-approved-shorter`, `L3-suppressor-disposition-blind-right-fix`, `L3-editor-block-stale-monolingual-D1` |
| 5 Качество | `H5-no-in-loop-quality-signal`, `H14-inversion-guard` (D37 §2г), `H12-cross-boundary-coherence-untested` |
| 6 Export | `L5-normalization-fused-to-flag-path`, `L5-broken-word-class-*`, `L5-diacritics-class-lost`, `L5-legit-cjk-gloss-stripped`, `L6-technique-not-norm-overclaim` |
| 7 Гигиена | `L8-*` (target-blind gates, role-switch, strip-smear, prompt-orphans, dead gatesEnabled, foldModelWire) |
| Процесс (к.5) | `H18-no-standing-findings-ledger-process` + незакрытые владельческие: `H6` running-summary, `H7` input-size-limit, `H8` abuse-prescreen, `H9` parallelism/speed (V4-п1), `H15` glossary-auto-build (V4-п4), `H10` user-stop, `H16` self-improvement |
---
## 4. Дорожная карта 13.07 — ОТРАБОТАНА (тело снято)
**Трек A (build-now)** исполнен целиком: слои 4·5·6·7·2 — статусы и номера паков в таблице шапки; док-долг оркестратора закрыт там же (фантом «D35.7» формализован — D39 п.4, разбор `../archive/architecture/08-sync-audit-ledger.md`).
**Трек B (ресёрч перед постройкой)** ЗАВЕРШЁН: программа нарезки/когезии — exp15/exp16, **D39.7/D39.10** (граница `logical` — не рычаг НА ЭТОМ МАТЕРИАЛЕ, когезия под флором; скоуп замера — книги класса zh-вебновелла, а не весь спектр §0.1); конфликт exp14 ↔ research/18 §A решён этими же нотами. Методика-guard замеров — **D32.4** (fidelity-first · leave-one-out · катастроф-скрин: полигон трижды собирал ложную сходимость).
**Гейт пере-прогона** пройден фактом rerun2 — **D39.20**; планка «≤2 претензии владельца» НЕ пройдена, эксперимент ЗАКРЫТ **D39.22** (редактор = deepseek-v4-pro, интерим).
Статус обоих треков и гейта пере-прогона — в шапке; фантом «D35.7» формализован (D39 п.4, разбор `../archive/architecture/08-sync-audit-ledger.md`). Что из трека B переживает статус: граница `logical`**не рычаг НА ЭТОМ МАТЕРИАЛЕ**, когезия под флором (**D39.7/D39.10**), и **скоуп замера — книги класса zh-вебновелла, а не весь спектр §0.1**; конфликт exp14 ↔ research/18 §A решён этими же нотами; методика-guard замеров — **D32.4** (fidelity-first · leave-one-out · катастроф-скрин: полигон трижды собирал ложную сходимость).
⚠ Ограничение дизайна эксперимента, которое НИКОГДА не переносится в продукт (§0.1): плоский тест-срез не задействует рычаги границы/когезии, поэтому «не сработало на нём» ≠ «не нужно в движке».
---

View file

@ -2,7 +2,7 @@
> **СТАТУС: несущая часть ПОСТРОЕНА.** Pair-keyed промпты резолвятся КОНВЕНЦИЕЙ пути `prompts/<пара>/<роль>.md` + конфиг-слой пары `configs/pairs/` (пак-15, D39.23), repair-промпты — `prompts/<пара>/repair/<класс>.md` (пак-16, D39.24). Паком-20 добавились роль `terminologist` (пар-пак, интерим-текст) и вариантный `translator-banknote.md`; редакторская инъекция стала двухсекционной (D39.45), а жанровый словарь ОТМЕНЁН как класс (D39.47). ⚠ **Ждёт внесения:** D39.104 — инъекция схлопывается в ЕДИНЫЙ закон-блок, маркер ⟨проверить⟩ снимается с провода, право «перевести иначе» упраздняется; внесение = строка 134 ПОСЛЕ пробы 18.
>
> «Структурированный пакет конвенций пары» (§3) остаётся дальним планом. **Заметка собрана оркестратором 2026-07-16 по запросу владельца** («где заметка про промтинг?») — до неё тема концерна 4 арх-ресета была размазана по `08-sync-audit-ledger` (дорожка L4), `09-target-architecture` (§0.1, §2 слой 2), D-логу (D30.2, D39 п.7, D39.139.2) и research/1819. Док — одно место по теме промптинга и реестр открытого; **при конфликте побеждает D-лог**, обновлять при каждом лендинге, трогающем промты или слой 2.
> «Структурированный пакет конвенций пары» (§3) остаётся дальним планом. **Заметка собрана оркестратором 2026-07-16 по запросу владельца** («где заметка про промтинг?») — одно место по теме промптинга и реестр открытого; **при конфликте побеждает D-лог**, обновлять при каждом лендинге, трогающем промты или слой 2.
## 1. Четыре вопроса владельца → где ответ и что с ним

View file

@ -1,32 +1,32 @@
# Якоря техдолга — справочник к строкам бэклога (НЕ трекер)
> **Освежение 04.08 (D39.101):** якоря были входом пакета-чекеров (исполнен D39.78) и арки банка (закрыта D39.69/71); часть находок ниже уже ЗАКРЫТА — закрытия помечены стрелками «→» по месту, счёт закрытий не дублируется в трекер.
> **Единственный трекер — таблица «Бэклог» в `../PROGRESS.md`.** Этот файл — справочные file:line-якоря и скоуп-заметки к её строкам (родился как пост-сверка свипа D39.66, 01.08.2026; вынесен из архива решением владельца — содержимое ЖИВОЕ). Актуализируется лендингами паков, которые трогают эти строки; исполненный пункт помечать ссылкой на D-номер, не удалять.
> **Снятая мёртвая половина** (историческая улика ОТСУТСТВИЯ механизмов — снимок свипа 26.0701.08 с file:line того времени) живёт носителем: `docs/archive/architecture/05-decisions-D39-59-90.md`, греп `D39.66-пост-сверка`; исполнение среза строки 25 — там же греп `D39.78`; закрытия банк-арки — `D39.69`. Здесь оставлен только ДЕЙСТВУЮЩИЙ статус. Метод и итог свипа (23 пункта: 20 CONFIRMED · 0 «передумали» · 3 RESCOPE, вправленные в строки 81/73/49) — там же, в теле `D39.66-пост-сверка`.
> ⚠ **Второй гвоздь под якоря НЕ строить — гейт уже построен и ратифицирован (D39.126):** `docs/scripts/counts.py --lint` сверяет якорь ПО СОДЕРЖИМОМУ через опт-ин токен `` `путь:123`=`подстрока` ``, органический остаток мигрируется на ЗАТРОНУТЫХ строках (бэклог-строка 205). Этот док — концентрат якорей, и органика на нём не сработала: токен-форму несут единицы, остальные гейт не видит ПО ПОСТРОЕНИЮ. Правильное действие — пакетная миграция якорей в токен-форму, не новый механизм. Цель якоря §Б-105 — `run.texts[i] = att.text`, греп по `backend/internal/pipeline/terminologist.go`.
> **Часть находок ниже уже ЗАКРЫТА — закрытие помечено по месту D-номером, счёт закрытий в трекер не дублируется (D39.101).**
> **Единственный трекер — таблица «Бэклог» в `../PROGRESS.md`.** Этот файл — справочные file:line-якоря и скоуп-заметки к её строкам (вынесен из архива решением владельца — содержимое ЖИВОЕ). Актуализируется лендингами паков, которые трогают эти строки; исполненный пункт помечать ссылкой на D-номер, не удалять.
> **Снятая мёртвая половина** (историческая улика ОТСУТСТВИЯ механизмов — снимок свипа 26.0701.08 с file:line того времени) живёт носителем: `docs/archive/architecture/05-decisions-D39-59-90.md`, греп `D39.66-пост-сверка`; исполнение среза строки 25 — там же греп `D39.78`; закрытия банк-арки — `D39.69`. Здесь оставлен только ДЕЙСТВУЮЩИЙ статус.
> ⚠ **Второй гвоздь под якоря НЕ строить — гейт уже построен и ратифицирован (D39.126):** `docs/scripts/counts.py --lint` сверяет якорь ПО СОДЕРЖИМОМУ через опт-ин токен `` `путь:123`=`подстрока` ``, органический остаток мигрируется на ЗАТРОНУТЫХ строках (бэклог-строка 205). Этот док — концентрат якорей, и органика на нём не сработала: токен-форму несут единицы, остальные гейт не видит ПО ПОСТРОЕНИЮ. Правильное действие — пакетная миграция якорей в токен-форму, не новый механизм.
## Срез: строки 81/83/85 + инфра-дописки
### [RESCOPE ИСПОЛНЕН] Строка 81 — ja-преп B6-ja: Поливанов-валидатор + kana-омограф POS/known-word гейтинг (D17.1) + чек-лист kana-алиасов сида (D16.4)
Два компонента реально отсутствуют: (1) Поливанов-валидатор — `backend/internal/store/migrate.go:187`=`translit_policy TEXT` («field only in v1; validator = Phase 2») и `backend/internal/store/migrate.go:195`=`ruby_reading` («bridge to Polivanov dst validation, B6 Phase 2 — NOT a dst»); grep polivanov/Поливанов по backend/*.go даёт только значения конфига в тестах/примерах и коммент `backend/internal/config/book.go:50`=`Transcription string `yaml:"transcription"` /` — валидирующего кода нет. (2) kana-омограф гейтинг — `backend/internal/membank/memory.go`, греп `KANA and HAN are deliberately NOT boundary-checked`: «… their ≥4 precision is deferred to the kana-precision measurement + the B6 tokenizer»; подтверждено D-логом (D17, тело — слайс `D1-D38`: митигация kana-омографов → «скоуп B6»). Третий компонент — чек-лист kana-алиасов сида (D16.4) — ПОСТРОЕН (`backend/README.md:38`=`Подготовка ja-книги (чек-лист сида)` §ja + `backend/internal/pipeline/bankmaterialize.go`, греп `AttachRubyAliasesToManual`); в чек-листе остался лишь Ф2-хвост «двойные чтения (強敵→とも) полная дизамбигуация», и он тоже под B6.
Два компонента отсутствуют (полный состав и токен-якоря — строка 81 бэклога в `../PROGRESS.md`; здесь только отрицательная улика). **(1) Поливанов-валидатор:** валидирующего кода НЕТ — grep `polivanov`/`Поливанов` по `backend/**/*.go` даёт только значения конфига в тестах/примерах, коммент `Transcription` (`backend/internal/config/book.go`) и мост ruby-чтения (`backend/internal/membank/memseed.go`, греп `Polivanov bridge`, там же «B6, Phase 2»); поля схемы `translit_policy`/`ruby_reading` помечены «Phase 2» самим кодом. **(2) kana-омограф гейтинг** отложен явно: «KANA and HAN are deliberately NOT boundary-checked … their ≥4 precision is deferred to the kana-precision measurement + the B6 tokenizer» (`backend/internal/membank/memory.go`), подтверждено D17 (тело — слайс `D1-D38`: митигация kana-омографов → «скоуп B6»). **Третий компонент — чек-лист kana-алиасов сида (D16.4) — ПОСТРОЕН** (`backend/README.md` §ja + `AttachRubyAliasesToManual`); в чек-листе остался лишь Ф2-хвост «двойные чтения (強敵→とも) полная дизамбигуация», и он тоже под B6.
### [ЗАКРЫТО D39.82] Строка 83 — F4: бэкап + integrity_check SQLite перед платным прогоном (VACUUM INTO) → **ИСПОЛНЕНО D39.82: `tmctl backup` + pre-flight (`backend/cmd/tmctl/backup.go`, коммит `9f60746`; команда `backup` в `dispatchCommands`), строка 83 закрыта; остаток F4-хвоста — строка 93**
### [CONFIRMED_LOST] Строка 85 — пилот-преп добор: Bertalign GOLD-пары (D29.2в) · R2 shadow (D25.2) · exp08 v3 (D21.8)
Bertalign: grep -rni bertalign по eval/ и backend/ — 0 вхождений (нет ни кода, ни данных). exp08 v3: в docs/experiments/ существует только 08-cost-model-v2.md; его шапка (греп `Пере-съём заказан как exp08 v3`) прямо говорит «Пере-съём заказан как exp08 v3 (D21.8 … D25.8 …)» — т.е. заказан, не исполнен; в eval/ есть только cost_model_v2.py (v3-скрипта нет). Подтверждается и D-логом (D21): «→ exp08 v3 … до фиксации budget_usd-дефолтов Ф2» — висящее поручение, и `docs/architecture/02-mvp-plan.md:37`=`пере-съём exp08 v3` — как открытый (⚠ прежний голый якорь `:34` съехал, там пустая строка). Скоуп — пилот-преп-промт Ф2.5, дельта вписана в `docs/POLYGON_PACKAGE4_SESSION_PROMPT.md:4`=`exp08 v3 (D21.8)`.
Bertalign: grep -rni bertalign по eval/ и backend/ — 0 вхождений (нет ни кода, ни данных). exp08 v3: в docs/experiments/ существует только 08-cost-model-v2.md; его шапка (греп `Пере-съём заказан как exp08 v3`) прямо говорит «Пере-съём заказан как exp08 v3 (D21.8 … D25.8 …)» — т.е. заказан, не исполнен; в eval/ есть только cost_model_v2.py (v3-скрипта нет). Подтверждается и D-логом (D21): «→ exp08 v3 … до фиксации budget_usd-дефолтов Ф2» — висящее поручение, и `docs/architecture/02-mvp-plan.md:37`=`пере-съём exp08 v3` — как открытый. Скоуп — пилот-преп-промт Ф2.5, дельта вписана в `docs/POLYGON_PACKAGE4_SESSION_PROMPT.md:4`=`exp08 v3 (D21.8)`.
### [CONFIRMED_LOST] Дописка к строке 59 — GLM context-overflow гард (finish=model_context_window_exceeded)
backend/internal/llm/provider_openai.go:166171: normalizeOpenAIFinish схлопывает только content_filter-композит и sensitive; «EVERY other value — network_error, model_context_window_exceeded … passes through RAW». Тест фиксирует это как осознанный дефер: backend/internal/llm/pack12_transport_test.go:190 «model_context_window_exceeded … raw (deferred GLM-overflow item)». Ниже по потоку гарда тоже нет: classify() (backend/internal/pipeline/disposition.go:201246) знает ветки decodeErrorFinish/content_filter/refusal/length — model_context_window_exceeded не матчится ни одной: пустой выход упадёт в FlagEmpty («retryable — thinking usually ate the entire budget», строки 230233) — платный ретрай, обречённый при overflow; непустой выход пройдёт как reasonOK (строка 245) — усечённый по контексту текст принят как годный. Скоуп: NOT-do пака-12 без решения, полигон-пакет до МАСШТАБА.
`normalizeOpenAIFinish` (`backend/internal/llm/provider_openai.go`, греп `EVERY other value`) схлопывает только content_filter-композит и `sensitive`: «EVERY other value — network_error, model_context_window_exceeded … passes through RAW». Тест фиксирует это как осознанный дефер: backend/internal/llm/pack12_transport_test.go:190 «model_context_window_exceeded … raw (deferred GLM-overflow item)». Ниже по потоку гарда тоже нет: classify() (backend/internal/pipeline/disposition.go:201246) знает ветки decodeErrorFinish/content_filter/refusal/length — model_context_window_exceeded не матчится ни одной: пустой выход упадёт в FlagEmpty («retryable — thinking usually ate the entire budget», строки 230233) — платный ретрай, обречённый при overflow; непустой выход пройдёт как reasonOK (строка 245) — усечённый по контексту текст принят как годный. Скоуп: NOT-do пака-12 без решения, полигон-пакет до МАСШТАБА.
### [CONFIRMED_LOST] Дописка к строке 53 — внутрифайловый дубль ключа pair-файла → громкая ошибка → **частично ИСПОЛНЕНО D39.82 (putUniqueDC, строка 53 закрыта); остаток parseCategoryRows — строка 111** (PACK15 §Внутрифайловый)
backend/internal/lang/langpack.go:824 (parseCategoryRows): `cats[f[0]][f[1]] = val` повторный ключ ВНУТРИ одного файла молча перезаписывает предыдущий (last-wins), без проверки дубля. Громкая коллизия есть только на стыке уже слитого состояния и следующего источника: unionStringMap (langpack.go:466474, «key … is already defined … and the overlay redefines it») — но внутрифайловые дубли схлопываются в parseCategoryRows ДО того, как merge их увидит. Ровно так это и зафиксировано открытым в отчёте: docs/archive/reports/PACK15_STRUCTURE_REPORT_2026-07-25.md:274276 «Дубль ключа ВНУТРИ одного pair-файла всё ещё тихо разрешается „последний выигрывает" … фикс — кандидат следующего пака». Теста на внутрифайловый дубль в langpack_test.go нет (grep duplicate/дубл/already defined — 0). Скоуп: мелкие хвосты качества одним паком.
`parseCategoryRows` (`backend/internal/lang/langpack.go`, греп `cats[f[0]][f[1]] = val`): повторный ключ ВНУТРИ одного файла молча перезаписывает предыдущий (last-wins). ГРОМКО коллизия ловится только на стыке уже слитого состояния и следующего источника `unionStringMap` («key … is already defined … and the overlay redefines it»); внутрифайловые дубли схлопываются ДО того, как merge их увидит. Теста нет (grep duplicate/дубл/already defined по `langpack_test.go` — 0). Скоуп: мелкие хвосты качества одним паком; улика — `docs/archive/reports/PACK15_STRUCTURE_REPORT_2026-07-25.md`, греп `Дубль ключа ВНУТРИ`.
### [CONFIRMED_LOST] Дописка к строке 11 — судьба v1.1 quote-absorption при флипе coverage-гейта (D12-Q1)
@ -36,26 +36,26 @@ Go-гейт стоит на v1 без поглощения кавычек: backe
### [CONFIRMED_LOST] Дописка к строке 33 — включить sanitizer в pipeline-c2 при оживлении (D33.4б)
grep sanitiz по backend/configs/pipeline-c2.yaml — 0 вхождений (exit 1), при том что секцию `sanitizer:` несут pipeline-c1.yaml:87 и все три arm-конфига (pipeline-arm-mistral.yaml:47, pipeline-arm-glm.yaml:50, pipeline-arm-deepseek-pro.yaml:51). C2 — спящий скелет (pipeline-c2.yaml:14: «Фаза 0 фиксирует СХЕМУ … исполнение fan-out/селекции — механика раннера Фазы 2»), поэтому отсутствие сейчас безвредно, но при оживлении C2 без правки конфига финал пойдёт без санитайзера — строка корректно держит это как условие оживления. Нюанс цитаты: «D33.4б» как секции в 05-decisions-log.md нет (есть D33/D33.1; нотация D33.4a встречается в research/18-quality-levers.md:213) — на вердикт не влияет, носитель решения = серия D33.x в теле D33.
`backend/configs/pipeline-c2.yaml` секции `sanitizer:` НЕ несёт (греп = 0), при том что её несут `pipeline-c1.yaml` и все три arm-конфига. C2 — спящий скелет («Фаза 0 фиксирует СХЕМУ … исполнение fan-out/селекции — механика раннера Фазы 2»), поэтому отсутствие сейчас безвредно, но при оживлении C2 без правки конфига финал пойдёт БЕЗ санитайзера — строка держит это условием оживления. ⚠ Секции «D33.4б» в журнале нет и не будет: это ПОДНОМЕР, тело — `^## D33`.
## Срез: строки 80/82/84 + кандидаты 73
### [CONFIRMED_LOST] Строка 80: резюме-слой памяти (глава→арка→книга) + fact-gate
### [ЗАКРЫТО ПО НУЖНОСТИ D39.69 — строка 80 живёт ГЕЙТОМ ПИЛОТА Ф2.5] Резюме-слой памяти (глава→арка→книга) + fact-gate
В backend/internal/ резюме-механизма НЕТ: grep summary/резюме даёт только несвязанное — RedriveSummary (pipeline/status.go:592-593, план redrive), SanitizerResult.Summary() (checks/sanitizer.go:165-167, текст флага), детектор ХВОСТОВОГО edit-summary модели (sanitizer.go:90), коммент-плейсхолдер «approved-glossary+summary+series-bible» в pipeline/snapshot.go:391 при том, что memoryVersion() материализует ТОЛЬКО frozen APPROVED glossary rows (snapshot.go:179-189); в схеме store/migrate.go нет таблицы/колонки резюме (строка 18 — лишь коммент о payload снапшота). Не закрыт решением (D30.8 п.8): «слой авто-памяти/состояния (Annotator, межглавные резюме…) — Ф2, связка с пилотом Ф2.5 зафиксирована» — отложено, не отменено; в списке «ЗАКРЫТО ЯВНО» D39.66 его нет.
Механизма резюмирования в `backend/internal/` нет: grep `summary`/`резюме` даёт только несвязанное (план redrive, текст флага санитайзера, детектор ХВОСТОВОГО edit-summary модели, коммент-плейсхолдер «approved-glossary+summary+series-bible» в снапшоте, где `memoryVersion()` материализует ТОЛЬКО frozen APPROVED glossary rows); таблицы/колонки резюме нет и в схеме `backend/internal/store/migrate.go`.
**Фикс/скоуп:** → **Диспозиция ДАНА D39.69: закрыт по нужности; строка 80 = гейт пилота Ф2.5.**
### [CONFIRMED_LOST] Строка 82: морфо-гейт РОДА (C3, глагол прош. вр. при gender=hidden)
В checks/*.go НОЛЬ упоминаний gender (grep gender по backend/internal/checks/ пуст); checks/sanitizer.go:83 и :429 прямо документируют «NOT offline-detectable without a morphology/dictionary pass (Ф2) — left silent»; pymorphy в бэкенде существует только в комментах ОТБРОШЕННОГО pymorphy3-подканала лемматизатора майнера (miner/miner.go:18-23, дефолт B). Gender в банке хранится как TEXT «male|female|hidden|''» (`backend/internal/store/migrate.go`, колонка `gender` — тот же якорь, что в пункте «Строка 84» ниже; membank/memory.go:140); hidden даёт лишь ИНЪЕКЦИЮ-мандат избегать род-маркирующих конструкций (memory.go:810-823, GenderHidden-текст), а ДЕТЕКТОРА нарушения нет — membank.SpoilerLeaks проверяет только появление dst-поверхности до окна (mempostcheck.go:205-224), не род глагола. Отложенность зафиксирована 06-memory-risk-registry.md (греп по названию пункта — номера съехали +6 коммитом d2cd30c) («Отложено в v1.1/Фазу 2 … морфо-гейт глагольного рода (C3)») — жива, не закрыта.
В checks/*.go НОЛЬ упоминаний gender (grep gender по backend/internal/checks/ пуст); checks/sanitizer.go:83 и :429 прямо документируют «NOT offline-detectable without a morphology/dictionary pass (Ф2) — left silent»; pymorphy в бэкенде существует только в комментах ОТБРОШЕННОГО pymorphy3-подканала лемматизатора майнера (miner/miner.go:18-23, дефолт B). Gender в банке хранится как TEXT «male|female|hidden|''» (`backend/internal/store/migrate.go`, колонка `gender` — тот же якорь, что в пункте «Строка 84» ниже; membank/memory.go:140); hidden даёт лишь ИНЪЕКЦИЮ-мандат избегать род-маркирующих конструкций (memory.go:810-823, GenderHidden-текст), а ДЕТЕКТОРА нарушения нет — membank.SpoilerLeaks проверяет только появление dst-поверхности до окна (mempostcheck.go:205-224), не род глагола. Отложенность зафиксирована реестром рисков (`docs/architecture/06-memory-risk-registry.md`, греп `морфо-гейт глагольного рода`: «Отложено в v1.1/Фазу 2») — жива, не закрыта.
**Фикс/скоуп:** Строка верна как есть (python-сайдкар/pymorphy, связка с морфопроходом Decl из 73).
### [ЗАКРЫТО D39.69 §3] Строка 84: канон D39.21 «generic „гу" = средний род» — носитель ПОСТРОЕН
Канон ратифицирован (D39.21: «generic-«гу» СРЕДНИЙ род, именные — по-термово из банка»; ⚠ прежний якорь вёл в строку карты шапки, которой в живом логе БОЛЬШЕ НЕТ — грепать по тексту, проверено 24.08). **Носитель ПОСТРОЕН и строка ЗАКРЫТА ратифицированной D39.69 §3** (там же закрыта строка 27): `neuter` работает end-to-end — `genderConstraintNote` принимает `neuter`/`n` (`backend/internal/membank/memory.go`, греп `case "neuter", "n":`) · ключ пары `gender_neuter` в разборе и структуре (`backend/internal/lang/embedded.go`, греп `GenderNeuter`) + `lang/data/injection.txt` · род ВАЛИДИРУЕТСЯ: SeedLint ГРОМКО отбраковывает неизвестный род (`backend/internal/membank/memseed.go`, греп `knownGenders`) · ось снапшота = scoped-фолд `neuter-directive-v1` в `memory_version` (книга без neuter байт-идентична).
Канон ратифицирован (D39.21: «generic-«гу» СРЕДНИЙ род, именные — по-термово из банка»). **Носитель ПОСТРОЕН и строка ЗАКРЫТА ратифицированной D39.69 §3** (там же закрыта строка 27): `neuter` работает end-to-end — `genderConstraintNote` принимает `neuter`/`n` (`backend/internal/membank/memory.go`, греп `case "neuter", "n":`) · ключ пары `gender_neuter` в разборе и структуре (`backend/internal/lang/embedded.go`, греп `GenderNeuter`) + `lang/data/injection.txt` · род ВАЛИДИРУЕТСЯ: SeedLint ГРОМКО отбраковывает неизвестный род (`backend/internal/membank/memseed.go`, греп `knownGenders`) · ось снапшота = scoped-фолд `neuter-directive-v1` в `memory_version` (книга без neuter байт-идентична).
**ЖИВОЙ ОСТАТОК — косметика комментария, не поведение:** комментарий схемы БД до сих пор перечисляет `male|female|hidden|''` без neuter (`backend/internal/store/migrate.go:184`=`male|female|hidden|`). Оговорка к альтернативе: `decl.Invariant` (memory.go:128,151,311; seed.go:85) несёт только несклоняемость формы, не род для согласования глагола/прилагательных — «decl.invariant достаточно» неверно.
@ -65,13 +65,13 @@ grep sanitiz по backend/configs/pipeline-c2.yaml — 0 вхождений (exi
### [ЗАКРЫТО D39.69] Кандидат 73: STITCH-ретирование инъекции отработанных термов
Механизма подавления инъекции терма, стабильно отработанного N чанков подряд (research/15-voice-and-state.md:204), в membank НЕТ: бюджет Select ранжирует по priorityRank = confirmed/exact/sticky (memory.go:645-661) без какого-либо счётчика «отработанности»; sticky A5 — ИНЕРЦИЯ в противоположную сторону (наследование в следующий чанк, memory.go:500-505); grep retire/streak/consecutive/отработ по internal/ даёт только loopguard (повтор сегментов) и retired-конфиг-флаги — не о том. Post-check (mempostcheck.go) следит за промахами, но не влияет на подачу.
Механизма подавления инъекции терма, отработанного N чанков подряд, в membank нет; идея — `docs/research/15-voice-and-state.md`, греп `STITCH-паттерн`.
**Фикс/скоуп:** → **Закрыто D39.69 (реопен-триггеры: бюджет инъекции / измеренный эффект размера).** Счётная база для «N чанков подряд без промаха» уже есть в retrieval_state/post-check — стройка сводится к политике селекции.
### [ЗАКРЫТО D39.69] Кандидат 73: эмбеддинг-второй-эшелон A7/D2
В ДВИЖКЕ ретривала по эмбеддингам нет: единственные следы — плейсхолдер-колонка `embedding_tier_used INTEGER NOT NULL DEFAULT 0, -- always 0 in v1 (no embeddings on the hot path, Р3)` (store/migrate.go:248) и её протаскивание в store/glossary.go:71,305-391; miner_substrate.go:15 прямо декларирует «$0, no LLM, no embeddings»; grep cosine/vector/embedding по internal/ иных хитов не даёт. В eval бенч существует (eval/retrieval_bench.py). Реестр держит A7/D2 отложенными в Ф2 low-trust (06-memory-risk-registry.md (греп по названию пункта — номера съехали +6 коммитом d2cd30c),61,105) — живо, не закрыто.
Ретривала по эмбеддингам в движке нет (плейсхолдер-колонка `embedding_tier_used` = always 0; бенч живёт в `eval/retrieval_bench.py`).
**Фикс/скоуп:** → **Закрыто по нужности D39.69 (реопен: измеренный recall-разрыв на масштабе).**
@ -93,24 +93,24 @@ grep sanitiz по backend/configs/pipeline-c2.yaml — 0 вхождений (exi
- **`fn=0` демоции пост-чека КЛАСС-ВАКУУМЕН** (D39.78): в labels НОЛЬ одно-Han-позитивов, recall-цена `singleHanKeyFired` не измерена — **hard-gate строки 12 на этот ноль опираться НЕ должен**. Остаточные 6 K6-fp (元石/蛊虫 плюральные формы) = сид-полнота, не код.
- **Слепота магнитуд объявлена и НЕ закрыта:** узкий DC2-проб покрывает РОВНО `数十万→«десятки тысяч»`, а `数万`/`数百万`/`数千万` и иные рендеры слепы для обоих механизмов (`hasDigitBeforeBigMarker` требует ЦИФРУ, 数 не numeral rune). Расширение 数-коэффициента ловит **0 новых единиц** на labels ⇒ не чинить; **на иных корпусах может понадобиться — текущая эмпирика этого не закрывает**.
- **Precision латиница-детектора = 0.971, а 1.0 — только ЕСЛИ бренд занесён в `style_allowlist`**; боевой конфиг «Qidian» не заносит — дыра открыта.
- **K5c-супрессор гасит по ВСЕМУ юниту** (`backend/internal/checks/checkers.go`, греп `ok-suppressor`): одно верное 千万 маскирует второе неверное, DC1 берёт только ПЕРВЫЙ матч. Пер-вхожденческий супрессор — Р4-потолок, не строить. Value-сравнения у `lintPercentScale` тоже нет — доккомментарий `backend/internal/checks/cheapgates.go` (греп `a design, not a patch`) признаёт это сам: «A correct fix compares the rendered VALUE… a design, not a patch. Left firing».
- **K5c-супрессор гасит по ВСЕМУ юниту** (`backend/internal/checks/checkers.go`, греп `ok-suppressor`): одно верное 千万 маскирует второе неверное, DC1 берёт только ПЕРВЫЙ матч. Пер-вхожденческий супрессор — Р4-потолок, не строить. Value-сравнения у `lintPercentScale` тоже нет: чекер стреляет по ПРИЗНАКАМ (в источнике `成`-паттерн, в выходе нет процентной формы и есть дробный маркер), а не по числу — `backend/internal/checks/checkers.go`, греп `percent-scale checker`. ⚠ Испр. 02.09: доккомментарий-самопризнание («A correct fix compares the rendered VALUE… a design, not a patch») в дереве БОЛЬШЕ НЕ ЖИВЁТ, чекер переехал из `cheapgates.go` — цитату не искать.
**Р4-потолки, записанные В КОНТРАКТ правил** (двигать только замером): chevron-речь ~0.22 (24 безатрибутивные реплики офлайн неотличимы от цитат) · `minLatinResidueLen` = 3 (замер THRESHOLD=2 дал 0 изменений; гомоглиф «гy» — mixed-скрипт токен, ловится `detectBrokenWords`, не длиной) · HARD-value-чек 成/万 **не строить** (§6-Q3 → D39.79 п.4; реопен ДВУМЯ триггерами: флип hard-gate строки 12 ЛИБО ненулевой поток value-дефектов с добора идеала). ⚠ Inline-записи потолка на самих функциях НЕТ — хвост в строке 93.
**НЕ построено, диспозиции даны:** DC7 grade/role-чекер — вслепую НЕ строить, сперва $0-замер нужности на боевых финалах labels (§6-Q1 → D39.79 п.2; триггер — первая книга с живой грейд-серией) · DC2 word↔word дроби — 分之-дроби в корпусе есть (8 юнитов), размеченных дефектов класса НОЛЬ ⇒ строить вслепую — против мандата; сперва разметить 分之-срез · полный детектор повторов лемм для alignment-защиты рефренов — промпт-половина закрыта (`editor.md` + `editor-mono.md` несут исключение авторского рефрена), детектора в `checks/` нет, связка с alignment/Bertalign — строка 85. Требование защиты живо: `04-unhappy-paths.md:97`=`| **Повторы: сорный vs авторский рефрен (ритм ` («повтор в параллельных позициях оригинала = „не трогать“ … иначе редактор-агент убивает рефрены») и :130 п.5.
**Построено, возврата не требует:** omission-бэкстоп = стеммер `declinedFormPresent` (лемма-матч {dst,decl.forms}; сам починил 2 K6-fp 凡人/甲等) — ⚠ target-алиасы к нему НЕ заведены, это сид-концерн, не код.
**Построено, возврата не требует:** omission-бэкстоп = стеммер `declinedFormPresent` (`backend/internal/membank/mempostcheck.go`; лемма-матч {dst,decl.forms}; сам починил 2 K6-fp 凡人/甲等) — ⚠ target-алиасы к нему НЕ заведены, это сид-концерн, не код.
## Срез: строка 86 + дописки 79/41/24/74/49
### [CONFIRMED_LOST] (1) Echo-семантика дропнутого c-lite-члена (строка 86, D39.18): код сохраняет pre-c-lite семантику «эхо где угодно, вкл. дропнутых членов»
Код реально реализует pre-c-lite семантику, альтернатива не построена. backend/internal/pipeline/quality.go:216-218: «echo_draft is counted DIRECTLY from the draft rows (no c-lite per-unit re-derivation — a dropped member's own draft row already carries cjk_artifact)»; quality.go:295-318: draftEcho считается по ВСЕМ draft-stage рядам (FlagReason/FirstFlagReason == cjk_artifact), без фильтра по member-drop — т.е. эхо дропнутого c-lite-члена ВХОДИТ в метрику; backend/cmd/tmctl/render.go:308: «draft = the translator echoed (incl. dropped c-lite members)». Альтернативный путь «echo только в шипнутом тексте» в коде ОТСУТСТВУЕТ (в quality.go нет ветки, исключающей дропнутые члены из draftEcho). D-лог (D39.18): «ОТКРЫТОЕ решение владельцу: сохранена pre-c-lite семантика…; альтернатива — one-line, за владельцем»; D39.66 (строка 1209) повторно числит его открытым. Решения после D39.18 не найдено (grep по голове D39.x).
Код реализует pre-c-lite семантику, альтернатива не построена: `echo_draft` считается ПРЯМО по draft-рядам (`backend/internal/pipeline/quality.go`, греп `no c-lite per-unit re-derivation`), `draftEcho` берёт ВСЕ draft-ряды с `cjk_artifact` без фильтра по member-drop ⇒ эхо дропнутого c-lite-члена ВХОДИТ в метрику; то же в рендере (`backend/cmd/tmctl/render.go`, греп `incl. dropped c-lite members`). Ветки «echo только в шипнутом тексте» в `quality.go` НЕТ. **ОТКРЫТОЕ решение владельцу (D39.18):** «сохранена pre-c-lite семантика…; альтернатива — one-line, за владельцем»; D39.66 числит открытым, решения после D39.18 нет.
### [CONFIRMED_LOST] (2) Magnitude-кап тяжёлой CJK-утечки (строка 86, D38.3 п.4в): сейчас только strip+flag, капа >X%→drop нет
Капа в коде нет. backend/internal/checks/sanitizer.go:770 StripCosmetic — косметический стрип; backend/internal/pipeline/disposition.go:96-104 FlagSanitizerStripped — «cleaned, exported flagged, NOT dropped». detectCJKLeak (sanitizer.go:636) вообще не считает долю утечки — только собирает раны. Единственные share-пороги: disposition.go:275 cjkEchoThreshold=0.15 (это класс ЭХА → FlagCJKArtifact, не кап под-эховой утечки) и sanitizer.go:137 latinHeavyShare=0.25 (Latin-класс, не CJK). Промежуточного порога «CJK-доля >X% (X<15) drop» нет нигде в checks/ и disposition.go. D-лог (D38.3 п.): «альтернатива magnitude-кап (>X%→drop) НЕ реализована — нужен ли кап, за владельцем»; D39.66 повторно числит открытым.
Капа в коде нет: `StripCosmetic` — косметический стрип, `FlagSanitizerStripped` — «STRIPPED, остаток ЭКСПОРТИРОВАН, чанк НЕ теряется» (`backend/internal/pipeline/disposition.go`, греп `FlagSanitizerStripped`), `detectCJKLeak` доли утечки не считает вовсе — только собирает раны. Единственные share-пороги: `cjkEchoThreshold` = 0.15 (класс ЭХА → `FlagCJKArtifact`, не кап под-эховой утечки) и `latinHeavyShare` = 0.25 (Latin-класс, не CJK). Промежуточного «CJK-доля >X% (X<15) drop» нет ни в `checks/`, ни в `disposition.go`. **ОТКРЫТО владельцу (D38.3 п.4в):** «нужен ли кап»; D39.66 повторно числит открытым.
### [ПОСТРОЕНО D39.78] (3) lintNumberMagnitude — гейт по письму источника (дописка 79) СТОИТ
@ -125,12 +125,12 @@ grep sanitiz по backend/configs/pipeline-c2.yaml — 0 вхождений (exi
### [CONFIRMED_LOST] (5) Слот инъекции голоса (дописка 24): инъекционная половина построена условно и НЕ включена, оба провода
Оба провода подтверждены. Провод 1 (инъекция): половина построена в membank УСЛОВНЫМ фолдом — backend/internal/membank/memory.go:248-252 (`InjectVoice reports whether the voice/address rows reach the WIRE... It is the CONDITION`), 370-377 («A book with no voice rows, or a run with the injection off, hashes BYTE-IDENTICALLY»), 448-465 (фолд под `if !in.InjectVoice`); но pipeline захардкоживает выключенность: backend/internal/pipeline/bankmaterialize.go:291-294 — «InjectVoice is FALSE and has no config knob: pack-19 builds the schema and the flagger, and D21 п.2 holds the injection conditional until the polygon experiment... Wiring the injection means setting it and accepting a full --resnapshot». Провод 2 (флаггер): гейтится Gates.Voice.Enabled, opt-in OFF (backend/internal/pipeline/voicerun.go:46; config/pipeline.go:264-281). Совпадает с D39.55: «слот инъекции НЕ выбран, оба провода, решит полигон-эксперимент»; решение по `gates.voice` и инъекции — на следующем живом прогоне.
Оба провода подтверждены. **Провод 1 (инъекция)** построен в membank УСЛОВНЫМ фолдом (`backend/internal/membank/memory.go`, греп `InjectVoice reports whether`; книга без voice-строк и прогон с выключенной инъекцией хешируются БАЙТ-ИДЕНТИЧНО), но pipeline захардкоживает выключенность: `backend/internal/pipeline/bankmaterialize.go`, греп `InjectVoice is FALSE` — «no config knob… Wiring the injection means setting it and accepting a full `--resnapshot`». **Провод 2 (флаггер)** гейтится `Gates.Voice.Enabled`, opt-in OFF (`backend/internal/pipeline/voicerun.go`, греп `Gates.Voice.Enabled`). Совпадает с D39.55: «слот инъекции НЕ выбран, оба провода, решит полигон-эксперимент»; решение по `gates.voice` и инъекции — на следующем живом прогоне.
### [ЗАКРЫТО D39.95] (6) Остаток §12.7 (дописка 74): 8 несудимых fidelity-пар P4 существуют в ~/books/gu-zhenren/research15-probes/
Сырьё существует, суд не докуплен (проверено счётом файлов и метаданными, тексты не читались). P4-артефакты: ~/books/gu-zhenren/research15-probes/probes/raw/ — 100 файлов, вкл. полные сетки echo-ds-gu008-{D0,D1,D2,DP}×{s0,s1,s2} (12 шт.) и echo-grok-gu-001..010×{G0..G4} (50 шт.). Судейское сырьё: ~/books/gu-zhenren/promptlang/judge_p4/votes.jsonl = 36 голосов ровно над 16 distinct (fam,arm,frag)-комбо: deepseek только gu008-s2×{D1,D2,DP} (3), grok G1×{001,002,004,005,006} + G2×{001,002,004,005} + G4×{001,002,004,005} (13). Отчёт POLYGON_PROMPTLANG_ANTIECHO_2026-07-31.md:775-776 («Судья остановлен своим капом $0.28 на 16 парах из 24») и :784 («Добрать 8 несудимых пар P4 ≈$0.10»); файлы несудимых комбо (ds-gu008 s0/s1 × 3 арма; grok gu-006 G2/G4 и далее) в raw/ присутствуют.
Сырьё существует, суд не докуплен: судья остановлен своим капом $0.28 на 16 парах из 24 (улика и разбор комбо — `docs/archive/reports/POLYGON_PROMPTLANG_ANTIECHO_2026-07-31.md`, греп `Судья остановлен своим капом`, §12.7).
**Фикс/скоуп:** → **Строка 74 закрыта D39.95, P4-хвост принят D39.61; добор ≈$0.10 — резидуал §12.7 D39.61 (цены записаны там), отдельного носителя не заводилось.**
@ -143,6 +143,7 @@ grep sanitiz по backend/configs/pipeline-c2.yaml — 0 вхождений (exi
## Архео-хвосты жирных строк бэклога (выселение докс-паком строки 167, 09.08.2026)
> Тела ячеек «Хвост» перенесены сюда ДОСЛОВНО на момент выселения (норма D39.125 п.3: «диспозиция сверху, археология вниз»; ячейка >800 байт — не трекер). Живая диспозиция каждой строки — ТОЛЬКО таблица бэклога `../PROGRESS.md`; здесь справочная археология. Закрытия помечать по месту стрелкой «→ Dxx», не удалять.
> ⚠ **Голые `file.go:NNN` в этой секции — снимок 09.08.2026, и часть номеров с тех пор съехала (сверено 02.09).** Сверяйся ГРЕПОМ по названной функции/константе/цитате, а не по номеру строки; пере-нацеленный якорь пиши токен-формой `` `путь:123`=`подстрока` ``.
### Б-13б — тело строки 13б на 09.08.2026
@ -150,7 +151,7 @@ grep sanitiz по backend/configs/pipeline-c2.yaml — 0 вхождений (exi
### Б-44 — тело строки 44 на 09.08.2026
**Флор — калиброванная константа без модели «thinking в completion»: МОДЕЛЬ ПОЛУЧЕНА замером (D39.86), сама строка сужена до выбора числа.** Замер боевой формы: при вендор-дефолте `high` размышление на плотном хане потолком НЕ ограничивается (8496 → 0/9 пригодных, 16992 → 1/5; вендорская норма вывода для `high` = 384K) ⇒ **флор не является рычагом против неограниченного думания — рычаг это `reasoning_effort`**; при `low` размышление 170313 ток. и флор 8000 избыточен. Остаток строки: какое число ставить ПОСЛЕ развилки 74 (и помнить, что у `deepseek-v4-pro` эффорт не настраивается — вендор-маппинг `low→high`, quirks п.3а). ⚠ **РАСХОЖДЕНИЕ ТРЕКЕРА СНЯТО (D39.90):** строка 74 объявляла 44 «закрытой этим замером» — это верно только для ПОЛОВИНЫ «поднять флор» (фальсифицирована). Живой остаток — обратный: **опустить/пере-калибровать число по числам пробы `bank-low`**, где стена на `low` не исчезла, а разредилась (упавший батч: `content=""`, `finish=length`, `completion=7999`, `reasoning=7999` — тот же тяжёлый хвост, 1/5 вместо 4/5, и это стохастика вызова: батч не самый большой по входу). ⚠ **Флор при `low` НЕ варьировался ни разу** — упавший батч умер ровно на потолке 8000, так что «сколько ставить» остаётся незамеренным вопросом, а не выводом
**Флор — калиброванная константа без модели «thinking в completion»: МОДЕЛЬ ПОЛУЧЕНА замером (D39.86), сама строка сужена до выбора числа.** Замер боевой формы: при вендор-дефолте `high` размышление на плотном хане потолком НЕ ограничивается (8496 → 0/9 пригодных, 16992 → 1/5; вендорская норма вывода для `high` = 384K) ⇒ **флор не является рычагом против неограниченного думания — рычаг это `reasoning_effort`**; при `low` размышление 170313 ток. и флор 8000 избыточен. Остаток строки: какое число ставить ПОСЛЕ развилки 74 (⚠ испр. 02.09: клейм «у `deepseek-v4-pro` эффорт не настраивается, `low→high`» БОЛЬШЕ НЕ ДЕЙСТВУЕТ — звено про `low` отозвано самим же квирком (`docs/experiments/00-provider-quirks.md`, греп `ЗВЕНО (б) ПРО`, п.3б: статус `low` «НЕ УСТАНОВЛЕНО»), а вендор-чейнджлог 13.08 дал V4-Pro уровни low/high/max — §Б-108, вахта D39.92). ⚠ **РАСХОЖДЕНИЕ ТРЕКЕРА СНЯТО (D39.90):** строка 74 объявляла 44 «закрытой этим замером» — это верно только для ПОЛОВИНЫ «поднять флор» (фальсифицирована). Живой остаток — обратный: **опустить/пере-калибровать число по числам пробы `bank-low`**, где стена на `low` не исчезла, а разредилась (упавший батч: `content=""`, `finish=length`, `completion=7999`, `reasoning=7999` — тот же тяжёлый хвост, 1/5 вместо 4/5, и это стохастика вызова: батч не самый большой по входу). ⚠ **Флор при `low` НЕ варьировался ни разу** — упавший батч умер ровно на потолке 8000, так что «сколько ставить» остаётся незамеренным вопросом, а не выводом
### Б-46 — тело строки 46 на 09.08.2026
@ -158,7 +159,7 @@ grep sanitiz по backend/configs/pipeline-c2.yaml — 0 вхождений (exi
### Б-105 — тело строки 105 на 09.08.2026
**Роль `classifier` мис-вердиктится как эхо + честность двух новых строк наблюдаемости (D39.86).** (а) `classifyOutput` даёт поблажку `SourceEchoExpected` только `roleTerminologist` (`chunkrun.go:37`), а ответ классификатора по формату состоит из исходных ханьских термов ⇒ доля исходного письма 0.200.29 > порога 0.15 на каждом батче: живой артефакт пробы 6/6 несёт `verdict=cjk_artifact` при `bad_lines=0`. Ущерб узкий — `runBankRoleBatches` кладёт `run.texts[i] = att.text` без проверки диспозиции (`terminologist.go:603`), посчитанные эхо-ставки (`quality.go:313-321`) берутся из `chunk_status`, куда бэнк-путь не пишет ⇒ портятся только строки `tmctl report`/лога; **латентно** (`classify_types` выключен во всех шиппинг-конфигах). ⚠ Цена дисциплинированного фикса, которую надо знать заранее: бамп `classifierVersion` (литерал, сам не двигается) меняет payload снапшота → snapshot id → `RequestHash` ⇒ промах ВСЕХ чекпойнтов книги, то есть `--resnapshot` + пере-покупка. (б) тем же касанием — честность поверхностей: строка `VOICE` берёт `rules=` из конфига ВРЕМЕНИ ОТЧЁТА (`quality.go:436`), поэтому включение `gates.voice` после прогона печатает «измерено, чисто» для неизмеренной книги (воспроизведено); и она печатается при выключенном гейте, если `SpoilerLeaks>0` (дизъюнкция — поведение верное, формулировка отчёта/коммента неверна); знаменатель `BANKNOTE` = `len(states)` включая призрачные строки `retrieval_state`, тогда как соседний агрегатор их фильтрует (`quality.go:259-260`) ⇒ после пере-чанковки покрытие занижается
**Роль `classifier` мис-вердиктится как эхо + честность двух новых строк наблюдаемости (D39.86).** (а) `classifyOutput` даёт поблажку `SourceEchoExpected` только `roleTerminologist` (`chunkrun.go:37`), а ответ классификатора по формату состоит из исходных ханьских термов ⇒ доля исходного письма 0.200.29 > порога 0.15 на каждом батче: живой артефакт пробы 6/6 несёт `verdict=cjk_artifact` при `bad_lines=0`. Ущерб узкий — `runBankRoleBatches` кладёт `run.texts[i] = att.text` без проверки диспозиции (`backend/internal/pipeline/terminologist.go`, греп `run.texts[i] = att.text`), посчитанные эхо-ставки (`quality.go:313-321`) берутся из `chunk_status`, куда бэнк-путь не пишет ⇒ портятся только строки `tmctl report`/лога; **латентно** (`classify_types` выключен во всех шиппинг-конфигах). ⚠ Цена дисциплинированного фикса, которую надо знать заранее: бамп `classifierVersion` (литерал, сам не двигается) меняет payload снапшота → snapshot id → `RequestHash` ⇒ промах ВСЕХ чекпойнтов книги, то есть `--resnapshot` + пере-покупка. (б) тем же касанием — честность поверхностей: строка `VOICE` берёт `rules=` из конфига ВРЕМЕНИ ОТЧЁТА (`quality.go:436`), поэтому включение `gates.voice` после прогона печатает «измерено, чисто» для неизмеренной книги (воспроизведено); и она печатается при выключенном гейте, если `SpoilerLeaks>0` (дизъюнкция — поведение верное, формулировка отчёта/коммента неверна); знаменатель `BANKNOTE` = `len(states)` включая призрачные строки `retrieval_state`, тогда как соседний агрегатор их фильтрует (`quality.go:259-260`) ⇒ после пере-чанковки покрытие занижается
### Б-106 — тело строки 106 на 09.08.2026
@ -174,12 +175,12 @@ grep sanitiz по backend/configs/pipeline-c2.yaml — 0 вхождений (exi
### Б-121 — тело строки 121 на 09.08.2026
**archguard v2 (посадки приёмки D39.96 + §7-12/13 + §7-9). ⚠ Пункты (0а)/(0б) — РЕГРЕССИЯ против снесённого байт-гарда; дофикс ИСПОЛНЕН и принят D39.97 — (0а)/(0б)/(а) ЗАКРЫТЫ, плюс блокер type-param, ось имени и ложное срабатывание сверх промта; остаток строки — (б)/(в)/(г)/(д).** (0а) egressseam пропускает пакетную `llm.Complete(...)`: nil-`Selections` → молчаливый выход (`archguard.go:240-242`; фикс — fallback на `Uses`); (0б) пропускает интерфейс с llm-типами внутри композита (`Complete(ctx, []llm.LLMRequest)…``touchesPkg` не рекурсивен, `:79-82`); старый регекс `.Complete(` ловил обе формы; комменты «cannot be hidden» (`:250-253` и фикстура) фальсифицированы — переписать честно; (а) `runRequestSeam` обходит ТОЛЬКО `*ast.CompositeLit` (`archguard.go:197`): `var r pipeline.Request`+присваивание и `new(pipeline.Request)` проходят МОЛЧА — подтверждено на реконструкции: дыра ОБЩАЯ со старым гардом (не регрессия); фикс ~10 строк: симметрия ValueSpec/CallExpr со stage-сеамом + негативная фикстура, документирующая осознанные пропуски; (б) класс «встраивание · make+присваивание · дженерик-ноль» закрывается не свитчем, а ТИПОМ (нулевое значение `config.Stage` непригодно вне пакета); (в) политика build-тегов vet (сегодня default+live; чужой тег невидим — других в репо нет); (г) кандидат 4-й анализатор границы импортов — `backend/README.md:3`=`go list -deps` заявляет «проверяется `go list -deps`», что не автоматизировано ничем; (д) семь осознанных пропусков после дофикса 03.08 (принят D39.97; фикстуры БЕЗ want — покраснеют, когда начнут ловиться): llm.Ask-класс · пара внутри named-обёртки · встраивание/make/generic-zero · `internal/llm` исключён целиком (второй провод внутри адаптеров ловится только ревью) · внешние тест-пакеты · рефлексия (статикой не закрывается) · файлы за третьим сборочным тегом — всё, что закрываемо, закрывается типовым швом (б), не свитчем
**archguard v2 (посадки приёмки D39.96 + §7-12/13 + §7-9). ⚠ Пункты (0а)/(0б) — РЕГРЕССИЯ против снесённого байт-гарда; дофикс ИСПОЛНЕН и принят D39.97 — (0а)/(0б)/(а) ЗАКРЫТЫ вместе с блокером type-param, осью имени и ложным срабатыванием сверх промта (разбор и посадки — `docs/archive/reports/ARCHGUARD_DOFIX_2026-08-03.md`, пункты AF этапа 1); остаток строки — (б)/(в)/(г)/(д).** (б) класс «встраивание · make+присваивание · дженерик-ноль» закрывается не свитчем, а ТИПОМ (нулевое значение `config.Stage` непригодно вне пакета); (в) политика build-тегов vet (сегодня default+live; чужой тег невидим — других в репо нет); (г) кандидат 4-й анализатор границы импортов — `backend/README.md:3`=`go list -deps` заявляет «проверяется `go list -deps`», что не автоматизировано ничем; (д) семь осознанных пропусков после дофикса 03.08 (принят D39.97; фикстуры БЕЗ want — покраснеют, когда начнут ловиться): llm.Ask-класс · пара внутри named-обёртки · встраивание/make/generic-zero · `internal/llm` исключён целиком (второй провод внутри адаптеров ловится только ревью) · внешние тест-пакеты · рефлексия (статикой не закрывается) · файлы за третьим сборочным тегом — всё, что закрываемо, закрывается типовым швом (б), не свитчем
### Б-122 — тело строки 122 на 09.08.2026
**Гигиена пака стандартов (не-блокеры приёмки).** `TestCheckerLabelsCandidates` — ни одного ассерта (дизайн-REPL в одежде теста) · сообщение `TestMemoryVersionPinsTheUnverifiedRenderRevision` не различает «изменился рендер»/«изменилась нормализация» · Makefile: regex GO_MIN_VERSION пропускает go1.26.01.26.3 (патч-уровень не проверяется) · включить `unconvert` (1) и `wastedassign` (2) — дешевле уже включённых по собственному правилу конфига · `.skips.log` не в gitignore (прерванная battery оставляет мусор в дереве) · Fprint-исключение errcheck скоупить на `cmd/` (сейчас весь модуль — будущий писатель файла экспорта получит молча съеденную ошибку) · `w\.Write`-исключение ключуется ИМЕНЕМ receiver-а вопреки собственному принципу конфига · miningstop-исключение глушит текстом весь файл — якорить на функцию · provenance-числа конфига дрейфуют от дерева (293/31/93 против 294/33/91; контрпример «все прод-Close — читатели»: `chunktest/epub.go:51`) · коммент c1 «echo mine unarmed» поправлен дофиксом 03.08 (снят) · инвариант-коммент `httpllm.go:77` «zero wire bytes» — верен для полей пинга, неверен для бампа x/net, который их привёз (находка-4 D39.96) — переписать честно
**Гигиена пака стандартов (не-блокеры приёмки).** `TestCheckerLabelsCandidates` — ни одного ассерта (дизайн-REPL в одежде теста) · сообщение `TestMemoryVersionPinsTheUnverifiedRenderRevision` не различает «изменился рендер»/«изменилась нормализация» · Makefile: regex GO_MIN_VERSION пропускает go1.26.01.26.3 (патч-уровень не проверяется) · включить `unconvert` (1) и `wastedassign` (2) — дешевле уже включённых по собственному правилу конфига · `.skips.log` не в gitignore (прерванная battery оставляет мусор в дереве) · Fprint-исключение errcheck скоупить на `cmd/` (сейчас весь модуль — будущий писатель файла экспорта получит молча съеденную ошибку) · `w\.Write`-исключение ключуется ИМЕНЕМ receiver-а вопреки собственному принципу конфига · miningstop-исключение глушит текстом весь файл — якорить на функцию · provenance-числа конфига дрейфуют от дерева (293/31/93 против 294/33/91; контрпример «все прод-Close — читатели»: `chunktest/epub.go:51`) · инвариант-коммент `httpllm.go:77` «zero wire bytes» — верен для полей пинга, неверен для бампа x/net, который их привёз (находка-4 D39.96) — переписать честно
### Б-126 — тело строки 126 на 09.08.2026
**Потолок прогона — УПРАВЛЯЕМЫЙ, решение владельца 07.08: настройка в интерфейсе фронта, шкала от минимума (ноль выбрать НЕЛЬЗЯ, подсвечен серым) до максимума баланса аккаунта.** Форма снимает конфликт с Р7 бесплатно: максимум = баланс ⇒ движок всегда получает положительное число и состояния «выключено» не существует, валидатор `book.go:250` не правится. **Три следствия, ратифицированы формой (D39.110):** (а) **единица — НЕ доллары**, а главы (или % баланса): тогда минимум объясняет себя сам («одна глава»), а D39.84 цел — читатель не видит структуру расходов; доллары на пользовательском экране = осознанный амендмент D39.84, не побочный эффект виджета; (б) это потолок ПРОГОНА ⇒ в `book.yaml` он не пишется, движку нужен приём потолка на прогон — строка 145; (в) **максимум шкалы = ДОСТУПНЫЙ ОСТАТОК, то есть `Balance` как есть** — ⚠ испр. 08.08 (D39.115): формулировка «баланс минус открытые холды» была ОШИБКОЙ приёмки, вычитанием дважды. Холд — это дебет в момент взятия (`credits.go:179`), поэтому баланс уже без него; замерено: $10 грант + $1 холд = `Balance` 9, `Reserved` 1, «минус Reserved» дало бы 8. Спека несёт верную форму: `max_chapters` приходит УЖЕ подрезанным и по остатку, и по непереведённому хвосту книги, клиенту подрезать второй раз ЗАПРЕЩЕНО. **НОСИТЕЛЬ ПЕРЕСЧЁТА НАЗВАН (добор после верификации 07.08):** «сколько глав влезает в доступный остаток» считает ПЛАТФОРМА (по оценке движка) и отдаёт фронту ГРАНИЦЫ шкалы и выбранное значение в главах; сама формула наружу не выходит. Ручки под это в контракте НЕТ — сегодняшний `GET /v0/usage` несёт только процент, поэтому поверхность объявляется при правке спеки вместе с созданием прогона (работа П-1 + S3), и до её объявления фронт максимум шкалы взять неоткуда. Прежнее тело строки (механизм поднятия потолка для resume после ceiling-стопа: движок продолжает «once the ceiling is raised», `stagerun.go:488-489`) — половина этой же работы. Продуктовое слово стопа — К-8 у владельца
**Потолок прогона — УПРАВЛЯЕМЫЙ, решение владельца 07.08: настройка в интерфейсе фронта, шкала от минимума (ноль выбрать НЕЛЬЗЯ, подсвечен серым) до максимума баланса аккаунта.** Форма снимает конфликт с Р7 бесплатно: максимум = баланс ⇒ движок всегда получает положительное число, состояния «выключено» не существует, валидатор `book.go:250` не правится. Три следствия ратифицированы формой, тело — D39.110 п.2: единица шкалы = ГЛАВЫ, а не доллары (доллары на пользовательском экране = осознанный амендмент D39.84) · потолок принадлежит ПРОГОНУ, в `book.yaml` не пишется · максимум = ДОСТУПНЫЙ ОСТАТОК, то есть `Balance` как есть. ⚠ Звено «баланс МИНУС открытые холды» было ОШИБКОЙ приёмки — вычитание дважды: холд есть дебет в момент взятия (`credits.go:179`), снято D39.115 п.2(а) замером ($10 грант + $1 холд = `Balance` 9, `Reserved` 1, «минус Reserved» дало бы 8). **Поверхность ПОСТРОЕНА (испр. 02.09, прежний текст «ручки в контракте НЕТ» протух):** границы шкалы отдаёт `GET /books/{bookId}/run-options` (`docs/architecture/14-api-contract/openapi.yaml`, греп `run-options`), `ceiling_chapters` приходит УЖЕ подрезанным и клиенту подрезать второй раз ЗАПРЕЩЕНО; «сколько глав влезает в остаток» считает ПЛАТФОРМА по оценке движка, формула наружу не выходит. Продуктовое слово стопа — К-8, ЗАКРЫТ владельцем 04.08 (D39.100: страница лимитов = СТАТУС без сумм, стоп по потолку = `paused` + оповещение; ПТ-35).

View file

@ -1017,7 +1017,6 @@ the original request was never applied». Каждый `POST /books` созда
|---|---|---|
| `POST /books/{id}/parts` — дописать главы в существующую книгу | форма и движковый гейт против МОЛЧАЛИВОЙ перекупки хвоста при вставке не в конец — отдельная работа вместе с этапом структуры глав | **строка 185** |
| Снятие жанра из брифа и промптов | двигает `BriefHash` ⇒ только в общее resnapshot-окно | **строка 184** |
| Сжатие и условные чтения НА ПЛАТФОРМЕ | контракт их объявил; включение — работа платформы | **строка 186** |
| Сворачивание замечаний в тексте под кнопку | зона фронта, при разморозке | пинг фронту 16.08 |
| История прогонов книги | **снята решением владельца 16.08: «в МВП не нужно».** Данные уже в Postgres и не удаляются, индекс `runs (book_id, started_at desc)` стоит — если поддержка попросит, это один read-путь | research/28 §8 п.10 |
| Двухшаговая загрузка (метаданные JSON → `PUT` байтов) | три из четырёх greenfield-дизайнов выбрали её, и при ней проблема порядка частей не существует. Ц3: переписывается построенный путь с обеих сторон. Направление на после-беты | research/28 §5 «не в батч» |
@ -1031,18 +1030,10 @@ the original request was never applied». Каждый `POST /books` созда
| **Список экспортов** `GET /books/{id}/exports` | Б-4 просил СОСТОЯНИЕ экспорта, не список. Восстановление после перезагрузки закрыто иначе — `Idempotency-Key` на создании возвращает исходный `202` с тем же `Location` | research/28 §2 (Б-4) |
| Новое число страницы замечаний | **замера нет ни одного**: сколько замечаний даёт настоящая книга, не знает никто. 500 выбрано без числа, и выдумывать второе число вместо первого — та же ошибка. Число ушло из спеки в `Capabilities.page_size_default`; калибровка — после первого настоящего прогона | research/28 §7, §10 |
### 6а. Что РЕЗАЛОСЬ по §5а и что резать отказались
### 6а. Резать отказались (§5а) — контраргумент на каждое
Снято: `Problem.instance` (структуры на платформе нет; функцию несёт `request_id`) · кадр
`EventCeiling` целиком (единственное поле `halted` всегда `true`, дубль кадра `status`, который уже
несёт `paused_reason`) · `EventHello.run_id` (поток теперь книжный) · `EventResyncRequired.reason` ·
схема `Counter` (одна полоса вместо двух) · `Book.genre` и `BookIntake.genre` (Б-23) · значение
`finalizing` · прогонный поток `GET /runs/{id}/events` (перевешен на книгу) · зашитые числа размеров
страниц из прозы операций · генезис-проза (история ратификации semver, две апологии RFC 9110,
объяснение имени `source`) — **ужата НА МЕСТЕ до ссылки на источник, а не перенесена сюда**: в спеке
остались `semver §4` и одна строка про `Retry-After` на `200`, целиком выброшенного текста нет.
**Резать отказались, с контраргументом на каждое:**
Перечень СНЯТОГО батчем 0.3.0 здесь не дублируется: он в диффе лендинга `8d82096` (`git log -S`) и в
research/28 §5а, а живые следствия каждого снятия стоят в своих §2.
- **параметр `limit`** («клиент не отправил его ни разу»). Тот же §5 требует объявить у него
`maximum` и подрезание вместо понижения (Б-10) — у удалённого параметра максимума не объявишь.
@ -1067,11 +1058,8 @@ the original request was never applied». Каждый `POST /books` созда
## 6б. Дофикс-раунд 16.08 (ФБ-1…ФБ-10): что он изменил в каноне и почему
Заказ раунда — D39.142 п.3, приёмка с перечнем всех десяти закрытых правок поимённо — D39.143 п.1;
сами правки живут нормами в `openapi.yaml` (ФБ-1 — пример кадра на `EventEnvelope`; ФБ-2 — `0` на
книге без истории и нумерация истории с `1`; ФБ-5 — `end`/`resync_required` неразличимы по форме,
диспетчеризация по имени события; ФБ-7 — пол под моделью ошибок, «not one byte of its body»; ФБ-3/4/6
— §2.10 и таблица `resume` в каноне). Здесь остаётся только то, чего нет ни там, ни в нотах:
Все десять правок живут нормами в `openapi.yaml`, поимённый перечень — D39.143 п.1 (заказ раунда —
D39.142 п.3). Здесь остаётся только то, чего нет ни там, ни в нотах:
- **ФБ-9, шов имён.** `parser_unavailable` переименован на проводе в `processing_failed`. ⚠ **Живое
следствие для шва:** проводное имя отличается от внутреннего словаря платформы, где значение
@ -1084,10 +1072,8 @@ the original request was never applied». Каждый `POST /books` созда
## 6в. Синк с платформой 20.08 → канон 0.4.0: что решено и почему
Вход — `platform/docs/archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md`, четырнадцать мест, где провод сообщает
состояние и не даёт клиенту действия. Записка честно разделяет ФАКТ / ⚠ МНЕНИЕ ПЛАТФОРМЫ / ГРАНИЦА,
и разбор шёл по этой границе: ФАКТы перепроверены исполнением, МНЕНИЯ проверялись на ПОСЫЛКУ, а не
только на предложенную форму. Два мнения посылку не выдержали (B, часть A), одно оказалось
слабее собственного факта (L о метках глав).
состояние и не даёт клиенту действия. Метод разбора и его итог по всем четырнадцати — D39.152;
вердикт каждого пункта — в таблице ниже.
**База ссылок этого раздела — РАБОЧЕЕ ДЕРЕВО 20.08, а не HEAD.** В `platform/` на этот момент 81
незакоммиченный файл (P7 в работе), поэтому одна и та же строка в HEAD и в дереве разная, и ссылка
@ -1097,40 +1083,20 @@ the original request was never applied». Каждый `POST /books` созда
### п.0. Сверка на потери прозы 0.2.3 → 0.3.0 — исполнена; найдена ОДНА потеря, она и была заявлена
Метод: полный дифф лендинга `8d82096` по обоим файлам (300 удалённых строк компаньона, 597 канона),
чтение ВСЕХ удалённых строк, выделение из них утверждений-правил и проверка каждого на наличие
смыслового двойника в живых файлах.
**Отдельно про метод, потому что он чуть не дал ложный результат.** Первый проход греп-проверки
шёл построчно и дал шесть «пропаж», которых нет: правило переносится через перенос строки, и
`grep "fewer rows than asked"` не находит текст, где `fewer` заканчивает строку. Сверка пере-ранена
на файлах, склеенных в одну строку (`tr '\n' ' '`), — и все шесть нашлись на месте. Тот же класс
ошибки в этой сессии уже ловился однажды; ставлю его сюда как метод, а не как случай.
Метод (полный дифф лендинга `8d82096` по обоим файлам, чтение ВСЕХ удалённых строк) и разбор трёх
классов удалённого — D39.152; сами строки держит тот же дифф (`git log -S`).
Итог: **единственная потерянная НОРМА — фраза §2.14** («различать причины отказа клиент не может по
замыслу»), восстановлена. Остальное удалённое — три класса, и ни один не является потерей правила:
замыслу»), восстановлена. Второе — правило пустого `kind` уцелело в каноне, но потеряло здесь
ПРОЕКЦИЮ (`""``null` — работа платформы); клауза возвращена в §2.8. Остальное удалённое правил не
несло.
- **правило уцелело в КАНОНЕ, а канон нормативен**`kind`/`null` («MUST NOT drop it or invent a
kind»), «MUST NOT clamp it again», «stale read is the CLIENT's duty», «catch-up reads `>=`»,
«assembling a book's text on the client is forbidden», «pairs are read PER CHAPTER», уникальность
термина по пятёрке, «a phrase MUST exist for a reason we do not know yet», `no-store`, CSRF,
запрет реплея истории, «`max_chapters: 0` = экран исчерпанности». Один из них — правило пустого
`kind` — уцелел в каноне, но потерял здесь ПРОЕКЦИЮ (`""``null` — работа платформы); клауза
возвращена в §2.8;
- **утверждение снято ОСОЗНАННО и с записанным основанием** — «carried forward marked as
unverified» (ФБ-8, обещание без носителя), «замена в `failed` запрещена» (ужато до «не `failed`»),
«Required: HTTP/2 at the edge» (Б-16, RFC 9205), пофазные счётчики, `EventCeiling`, `genre`,
`finalizing`, пример `«CJK leak … 第一节»` (он и был утечкой, §2.12);
- **пропала МОТИВИРОВКА, а не норма** — «1.9 юнита на главу», «иначе строки выглядят дубликатами и
удаляются», «portable to the desktop client», `Intl.DisplayNames`. Это цена резки прозы, принятая
осознанно; ни одно не меняет того, что обязана делать сторона.
**Вывод, который стоит записать отдельно.** Приёмка батча сверяла мультимножество модальных глаголов
и этот класс структурно не ловила — но пере-сверка показала, что улов класса равен одному. Отсюда
дешёвый гейт вместо дорогого: при следующей резке прозы сверять не модальность, а **список
собственных имён формы** (полей, значений, кодов, заголовков) — норма почти всегда стоит рядом с
именем, а фраза §2.14 пропала именно там, где имени не было (`/auth/*` — не поле). Носитель: эта
запись.
**Гейт на следующую резку прозы, и он дешевле того, что был.** Приёмка батча сверяла мультимножество
модальных глаголов и этот класс структурно не ловила. Сверять надо не модальность, а **список
собственных имён формы** (полей, значений, кодов, заголовков): норма почти всегда стоит рядом с
именем, а фраза §2.14 пропала именно там, где имени не было (`/auth/*` — не поле). ⚠ Греп по
исходному файлу даёт ЛОЖНЫЕ пропажи — правило переносится через перенос строки; сверять на копии,
склеенной в одну строку (`tr '\n' ' '`). Носитель: эта запись.
**Диспозиции пунктов, исполненных без остатка: тела сняты, содержимое живёт по адресу.** Пункты
A · B · G · H · J · L разобраны ниже полностью — их предмет либо открыт, либо несёт провенанс,
@ -1247,8 +1213,7 @@ focus»), то есть цена платится на горячем пути
неизменённая уже начерновленная книга переигрывается с чекпойнтов за $0 — то есть в обычном случае
холд возвращается целиком и не берётся ничего. Плата возникает только если между прогонами сдвинулся
снапшот (слаг модели, промпт, langpack, флип гейта), и тогда пере-покупка действительно оплачивает
переведённое заново. Довод «предлагают уже сделанное» стоит сам по себе и в поправке не нуждается;
денежный довод был сильнее фактов, и это ровно тот класс ошибки, который у меня уже ловился.
переведённое заново. Довод «предлагают уже сделанное» стоит сам по себе и в поправке не нуждается.
**Ответ контракта.** «Сделано» = последний проход, который эта книга на ЭТОМ деплое реально
получает. Записано в `Progress` и в `Book.chapters_done` — вместе с доводом: контракт не говорит,
@ -1263,11 +1228,15 @@ focus»), то есть цена платится на горячем пути
`waverun.go:139-140,205-206`), и `redrive`/`--resnapshot`/правка исходника пере-атакуют юнит, так
что второе разрешение законно может выйти `flagged=false`. Но эмиссия идёт через
announce-once-леджер: ключ `unit:<book>:<wave>:<chapter>:<unit>` не несёт ни снапшота, ни прогона
(`events.go:399-401`), `EnqueueOnce` вторую строку не пишет (`store/outbox.go:74-106`), леджер
переживает прогоны (`outbox.go:205-212`) и запинен тестом
(`runevents_test.go:242-246`). Единственное окно — падение между записью строки в журнал и
пометкой (`events.go:154-164,200-202`); плюс `redrive` платформа не вызывает вовсе
(`runner/engine.go:83-124`).
(`backend/internal/pipeline/events.go`, греп `unit:%s:%s:%d:%d`), `EnqueueOnce` вторую строку не
пишет, а леджер переживает прогоны — «announced ONCE for the life of the book, whatever crashes and
resumes happen in between» (`backend/internal/store/outbox.go`, символы `EnqueueOnce` и
`onceKeyLookup`); запинено `TestAResumedRunOpensItsOwnStreamAndDoesNotRecountFinishedUnits`.
Единственное окно — падение между записью строки в журнал и пометкой
(`events.go:154-164,200-202`); плюс `redrive` платформа не вызывает вовсе: сборщики argv знают
`translate`/`status`/`manifest`/`export`/`bank-apply`, глагола `redrive` среди них нет
(`platform/internal/runner`, греп `Args(workdir`).
⚠ Адреса пере-нацелены 02.09 с номеров на символы: три из шести съехали за паки, вывод не изменился.
**Поэтому: строка «недостижимо» в регистр, а не механизм** — ровно тот исход, который зона назвала
правильным. Но в каноне закрыт РАЗРЫВ ПРАВИЛА, который эта проверка обнажила: §AfterVersion говорил
@ -1306,13 +1275,9 @@ announce-once-леджер: ключ `unit:<book>:<wave>:<chapter>:<unit>` не
### Ревью диффа и второе ревью 20.08 — что от них осталось живого
Четыре независимые линзы по диффу (холодный потребитель другой модели · опровергатель ПОСЫЛОК
диспозиций · регрессионная · линза стандартов по первоисточникам), каждая находка потом
адверсариально верифицирована отдельным агентом с установкой «по умолчанию опровергнуто»:
**31 находка, 5 подтверждено, 26 опровергнуто; 35 агентов, 0 упавших** (упавший агент — это НЕ
«опровергнуто»). Ни одна из пяти не опрокинула диспозицию — все пять о точности текста и внесены
НА МЕСТЕ: они и есть сегодняшние оговорки в пунктах A, B, G и в строке PD-298 таблицы §3. Разбор —
D39.152.
Веер линз, счёт находок и их адверсариальная верификация — D39.152. Ни одна не опрокинула
диспозицию; все подтверждённые внесены НА МЕСТЕ и живут сегодняшними оговорками в пунктах A, B, G и
в строке PD-298 таблицы §3. Живого здесь — два провенанса ниже.
**Провенанс `cause.code: credit_unavailable`.** Три линзы независимо споткнулись об один шов —
что отвечает `resume`, когда у прогона лимит ещё есть, а СЧЁТ не тянет холд. Каждую формулировку
@ -1341,12 +1306,9 @@ D39.152.
## 7. Эксплуатационные примечания — НЕ норма контракта
Вынесено из спеки в 0.3.0 (Б-16). RFC 9205 §4.1 прямо про наш случай: «Requiring a particular version
of HTTP … harms interoperability. Therefore, it is **NOT RECOMMENDED** that applications using HTTP
specify a minimum version … However, if an application's deployment benefits from the use of a
particular version of HTTP (for example, HTTP/2's multiplexing), **this ought be noted**». Отметить, а
не потребовать. Спека 0.2.3 требовала («Required: HTTP/2 at the edge») и держала в норме вендорный
заголовок конкретного прокси.
Вынесено из спеки в 0.3.0 (Б-16) по RFC 9205 §4.1: требовать минимальную версию HTTP —
**NOT RECOMMENDED**, а выигрыш деплоя от конкретной версии «**ought be noted**». Отметить, а не
потребовать.
Норма в спеке — то, что клиент НАБЛЮДАЕТ и на что вправе рассчитывать: `ETag`/`If-None-Match`/`304`
· **обязанность честить `Accept-Encoding` на JSON-ответах и НЕ сжимать `text/event-stream`** · `Vary`
@ -1358,16 +1320,18 @@ heartbeat · форма `id` кадра. Сжатие как ТРЕБОВАНИ
Ниже — то, что клиент не наблюдает и что деплой обязан себе устроить сам:
- **Чем и на каком слое сжимать** (middleware, обратный прокси, CDN). ⚠ **ПРОТУХЛО (испр. 02.09):**
платформа сжимает САМА, в Go — `platform/internal/httpapi/conditional.go`, греп `gzipFloor` (порог 1<<10 байт) и `acceptsGzip`; edge-слой для этого не нужен.
- **Сжатие — в приложении, а не на edge** (испр. 02.09; прежний текст требовал устроить его деплою):
платформа жмёт САМА, в Go — `platform/internal/httpapi/conditional.go`, греп `gzipFloor` (порог
1<<10 байт) и `acceptsGzip`. Деплою остаётся одно НЕ сжимать ВТОРОЙ раз на прокси/CDN и не
сжимать `text/event-stream`.
- **HTTP/2 на edge.** Клиент держит одно SSE-соединение на книгу; на HTTP/1.1 шесть соединений на
origin — потолок вкладок. Сервис на HTTP/1.1 обязан работать ХУЖЕ, а не не работать.
- **`X-Accel-Buffering: no`** (или эквивалент прокси) — механизм для нормы «поток не буферизуется».
- **Сколько это даёт.** Замер ревью на настоящей книге (`~/books/gu-zhenren`, 2283 главы): глава
26,1 КБ → 10,4 КБ; дерево глав 250 КБ → 39 КБ; банк 1000 строк 167 КБ → 17 КБ.
- **Порядок работ по эффекту на килобайт усилия** (research/28 §5б, строка 186): сжатие → `ETag`/304
→ скоуп в кадре → дельта-чтения `?after_version=``staleTime` у клиента. Шаги 34 — уже в
контракте (0.3.0), шаги 12 — ⚠ **сжатие УЖЕ ПОСТРОЕНО в Go платформой** (`conditional.go`, греп `gzipFloor`), конфигурацией остаётся только edge, шаг 5 — зона фронта.
→ скоуп в кадре → дельта-чтения `?after_version=``staleTime` у клиента. Шаги 12 ПОСТРОЕНЫ
паком P7 (D39.153), шаги 34 — в контракте с 0.3.0, шаг 5 — зона фронта.
- **Транспорт НЕ меняется** (проверено независимым агентом другого тира + сверка первоисточников):
наша нагрузка — художественный текст, и после gzip разница между JSON и protobuf единицы процентов;
gRPC-web требует прокси и теряет `If-None-Match`/304; Connect возвращает то, что у нас уже есть.
@ -1377,11 +1341,9 @@ heartbeat · форма `id` кадра. Сжатие как ТРЕБОВАНИ
## Приложение А. Карта «причина → КОД контракта → продуктовая фраза» — ЗАГОТОВКА
**Что изменилось в 0.3.0.** Прежняя карта вела «причина движка → фраза», то есть предполагала, что
ФРАЗУ рисует сервер. Это ровно та политика, которую вариант B отменил для ошибок (§2.17), и держать
её для замечаний значило бы оставить на проводе серверную локализованную строку — второй русский
текст, приходящий из зоны, у которой нет ни `Accept-Language`, ни локалей. Поэтому `Note` несёт
**`code`**, а фразу рисует клиент; `Note.message` с провода снят.
**Форма карты (0.3.0).** `Note` несёт **`code`**, а фразу рисует КЛИЕНТ; `Note.message` с провода
снят. Серверная локализованная фраза — ровно та политика, которую вариант B отменил для ошибок
(§2.17), и держать её для замечаний значило бы слать второй русский текст из зоны без локалей.
**Правила заполнения.**
@ -1454,8 +1416,11 @@ heartbeat · форма `id` кадра. Сжатие как ТРЕБОВАНИ
| `service_unavailable` | 503 | `runner.ErrCeilingNotWired` + `runs.ErrRunnerIncomplete` (`v0.go`) |
| `internal_error` | 500 | `v0.go` · `middleware.go` |
**Коды, которых платформа сегодня достигает, а контракт до 0.3.0 не объявлял:** 403 (`server.go:99`),
500 (`v0.go:518,572`), 431 от `net/http` (`serve.go:79`), 429 на `/auth` (`login.go:173,234`). Из них
**Коды, которых платформа сегодня достигает, а контракт до 0.3.0 не объявлял:** 403
(`platform/internal/httpapi/server.go`, греп `CauseHandler(CodeForbidden`), 500
(`platform/internal/httpapi`, греп `Fail(w, r, CodeInternalError)``v0.go`, `middleware.go`,
`conditional.go`, `idempotency.go`, `bank.go`), 431 от `net/http` (`serve.go:79`, `MaxHeaderBytes`),
429 на `/auth` (`login.go:173,234`). Из них
контракт объявляет 403 (это нарушение правила, которое ИЗОБРЁЛ сам документ) и не объявляет 500
(Zalando: «500 Internal Server Error · use · **do not document**»), 431 (уровень stdlib) и 429 (на
`/v0` лимитера нет вовсе — форвард-вопрос платформы). `405` на `/v0` не бывает: catch-all глотает

View file

@ -11,7 +11,7 @@
## 1. Канон одним абзацем
Деньги видимы с первого вызова: телеметрия, потолки, явное согласие на пере-оплату (CLAUDE.md, цель 5). Леджер без потолка запрещён — Р7: книга обязана нести хотя бы один из `book_usd`/`day_usd` (`backend/internal/config/book.go:321`=`a ledger with no ceiling is forbidden`, текст валидатора: «a ledger with no ceiling is forbidden, Р7»). Суммы на пользовательский экран НЕ выходят — запрет D39.84, подтверждён D39.100/К-8 (дословно: «страница лимитов/использования в настройках (СТАТУС, не суммы — запрет денег на экране D39.84 в силе и НЕ superseded)» — `docs/architecture/05-decisions-log.md`, греп `^## D39.100` → пункт К-8, дословная подстрока `СТАТУС, не суммы — запрет денег на экране`; ⚠ адресуем НОМЕРОМ: прежний голый `:232` убила эррата 02.09 в шапке, ровно как предсказывает строка бэклога 219) и держится в контракте (`docs/architecture/14-api-contract/openapi.yaml`, греп `State of the credit balance. No window` — ⚠ номер не ставим: контракт переверстывается минорами, греп-форма дешевле поддержки (прежнее обоснование «файл двигает пак 0.9.0» протухло — пак заленджен 31.08)). Защита от перерасхода двойная и не зависит от событий: холд платформы делает кредит недоступным следующему прогону, а движок сам останавливается на потолке — «an overspend is impossible even while the platform is blind. The event stream is freshness only» (док-коммент `Hold``platform/internal/pgstore/credits.go`, греп `an overspend is impossible even`).
Деньги видимы с первого вызова: телеметрия, потолки, явное согласие на пере-оплату (CLAUDE.md, цель 5). Леджер без потолка запрещён — Р7: книга обязана нести хотя бы один из `book_usd`/`day_usd` (`backend/internal/config/book.go:321`=`a ledger with no ceiling is forbidden`, текст валидатора: «a ledger with no ceiling is forbidden, Р7»). Суммы на пользовательский экран НЕ выходят — запрет D39.84, подтверждён D39.100/К-8 (дословно: «страница лимитов/использования в настройках (СТАТУС, не суммы — запрет денег на экране D39.84 в силе и НЕ superseded)» — `docs/architecture/05-decisions-log.md`, греп `^## D39.100` → пункт К-8, дословная подстрока `СТАТУС, не суммы — запрет денег на экране`; ⚠ адресуем НОМЕРОМ ноты, а не строкой журнала) и держится в контракте (`docs/architecture/14-api-contract/openapi.yaml`, греп `State of the credit balance. No window` — ⚠ номер не ставим: контракт переверстывается минорами, греп-форма дешевле поддержки). Защита от перерасхода двойная и не зависит от событий: холд платформы делает кредит недоступным следующему прогону, а движок сам останавливается на потолке — «an overspend is impossible even while the platform is blind. The event stream is freshness only» (док-коммент `Hold``platform/internal/pgstore/credits.go`, греп `an overspend is impossible even`).
## 2. Деньги ДВИЖКА (зона `backend/`)
@ -22,7 +22,7 @@
- **`--ceiling-usd` — КНИЖНЫЙ потолок, не бюджет прогона.** Дословно из флага: «the book USD ceiling in force for THIS RUN ONLY — it OVERRIDES book.yaml `ceilings.book_usd` and is never written back. It caps the book's CUMULATIVE committed+reserved spend, not this run's increment…» (`backend/cmd/tmctl/invocation.go:142`=`the book USD ceiling in force for THIS RUN ONLY`; ⚠-коммент `backend/cmd/tmctl/main.go:260`=`--ceiling-usd is NOT a per-run budget`; многоточие закрывает обрыв цитаты — во флаге дальше стоит «, and must be > 0»). Ратификация — D39.122 п.2(в): пересчёт «пользовательский прирост → абсолют» — обязанность ПЛАТФОРМЫ, вторая денежная ось не заводится. День-потолок флаг НЕ перекрывает (PD-157). Проводка внутри: `Ceilings.BookUSD` в `Reserve` и именование сработавшего потолка в ошибке — `backend/internal/pipeline/stagerun.go:496`=`BookUSD: r.bookCeilingUSD()` и `backend/internal/pipeline/stagerun.go:525`=`overrides the book's ceilings.book_usd` (стоп = `errReserveCeiling`, `backend/internal/pipeline/escalation.go:49`=`var errReserveCeiling`).
- **Потолки — wiring, не семантика:** `Ceilings` намеренно исключены из `BriefHash` («Wiring fields (paths, ceilings, db) deliberately excluded», `backend/internal/config/book.go:334`=`Wiring fields (paths, ceilings, db) deliberately excluded`; канон — `backend/internal/config/book.go:350`=`canon := struct {`) ⇒ смена ДЕНЕЖНОГО потолка не двигает ни снапшот, ни ре-билл (D39.110 п.2б). ⚠ Верно ровно про ДЕНЬГИ: потолок СЕГМЕНТАЦИИ `edit_ceiling_out` в снапшот ВХОДИТ и меняет границы чанков (`backend/internal/pipeline/snapshot.go:34`=`EditCeilingOut int`).
- **`status --json` отдаёт фигуры платформе:** `committed_usd`, `reserved_usd`, `book_ceiling_usd`, `ceiling_pct` = 100·(committed+reserved)/book_ceiling (`backend/internal/pipeline/status.go:290`=`book_ceiling_usd,omitempty`; арифметика `ceiling_pct``backend/internal/pipeline/status.go:788`=`100 * (committed + reserved)`). Дневной фигуры в status нет (PD-157 — `platform/docs/DEFECT_REGISTER.md`, греп `PD-157`).
- **Леджер = НИЖНЯЯ граница** (строка 78 бэклога, `docs/PROGRESS.md:65`=`Леджер денег = НИЖНЯЯ граница`): «2xx body decode failed (call IS billed)» — провайдер списал, попытка в `request_log` не попадает; живой замер D39.86 — 3 вызова из 14, неизвестность $0.015111 при леджере $0.114378; движок сеттлит оценку и печатает `estimated-cost rows: 3`. Канал виден, фикс — money-паком (дизайн GENERALITY_PHASE2 §5.6).
- **Леджер = НИЖНЯЯ граница** (строка 78 бэклога, `docs/PROGRESS.md`, греп `Леджер денег = НИЖНЯЯ граница`): «2xx body decode failed (call IS billed)» — провайдер списал, попытка в `request_log` не попадает; живой замер D39.86 — 3 вызова из 14, неизвестность $0.015111 при леджере $0.114378; движок сеттлит оценку и печатает `estimated-cost rows: 3`. Канал виден, фикс — money-паком (дизайн GENERALITY_PHASE2 §5.6).
- **Согласие на пере-оплату — ДВИЖКОВЫЙ гейт**. Прогон, который пере-покупает уже оплаченные юниты дороже порога, ОСТАНАВЛИВАЕТСЯ и требует явного согласия. Порог по умолчанию ратифицирован D20.2-Q2: `min($0.50, 5% × ProjectedBookUSD)`. Носитель — `backend/internal/pipeline/rebill.go`, греп `rebillConsentThreshold`; единственная ручка книги — `rebill_consent_usd` (валидатор `backend/internal/config/book.go`, греп `rebill_consent_usd`; 0 = ратифицированный дефолт). ⚠ Порог считается БЕЗ контура банк-ролей (D39.182 §3), то есть срабатывает позже, чем подсказывает полная проекция.
@ -30,7 +30,7 @@
1. **Грант.** `Grant` — строка леджера `kind='grant'`, идемпотентная по `(аккаунт, source, source_id)`: `on conflict (user_id, source, source_id) do nothing` (`platform/internal/pgstore/credits.go`, греп `func (s *Store) Grant(`; сама идемпотентность после пака sqlc уехала В ЗАПРОС — `platform/internal/pgstore/queries/credits.sql`, греп `on conflict (user_id, source, source_id) do nothing`). Фри-тир — тот же механизм в ТОЙ ЖЕ транзакции, что создание аккаунта (`platform/internal/pgstore/identity.go`, греп `appendLedger(ctx, tx, userID, "grant"`; ⚠ **дефолт `SignupGrantMicroUSD` — НОЛЬ** (`platform/internal/config/config.go`, греп `SignupGrantMicroUSD:`), а НЕ «5 × 1_000_000» — эта сумма ходила по докам и ложна: предложение «на бете дефолт в НОЛЬ» (D39.110 п.3) ИСПОЛНЕНО, `PD-104` в регистре стоит `fixed(P7, дерево сессии)`).
2. **Выбор потолка — шкала в ГЛАВАХ** (D39.110: от 1 до максимума, ноль не выбираем; потолок принадлежит ПРОГОНУ, в `book.yaml` не пишется). **Максимум = Balance КАК ЕСТЬ** (D39.115 п.2а; эррата в шапке D-лога — `docs/architecture/05-decisions-log.md:4`=`Balance КАК ЕСТЬ`): `Hold` — дебет в момент взятия, баланс уже не содержит открытых холдов, повторное вычитание вдвое укорачивает шкалу. Реализация: `pricing.Model.Scale``affordable = balance / PerChapter`, кламп по остатку глав, дефолт = верх шкалы (ратифицировано D39.123 п.2е; компромисс «весь баланс под одну книгу» принят осознанно) — `platform/internal/pricing/pricing.go`, греп `func (m Model) Scale(`.
3. **Ставка $0.03/глава — конфиг-константа платформы:** `DefaultPerChapter = 30_000` micro-USD (`platform/internal/pricing/pricing.go`, греп `DefaultPerChapter`), переопределяется `PerChapterMicroUSD` (`platform/internal/config/config.go`, греп `PerChapterMicroUSD`). ⚠⚠ **ЧИСЛА НИЖЕ — ИЮЛЬСКИЕ ДЕНЬГИ И С 16.08 НЕ ДЕЙСТВУЮТ (испр. ревизией 02.09).** D39.179 п.1 ратифицировал: DeepSeek пере-пинен под цены, вступившие **16.08 16:00 UTC**, множитель к июльским деньгам **×4.47**. ⇒ по действующему прайсу та же выборка даёт среднюю главу **≈$0.051$0.085** и максимум **≈$0.168**, то есть константа $0.03 не завышена, а **ЗАНИЖЕНА**, и знак вывода перевернулся. ⚠ Иллюстрация живыми деньгами (НЕ калибровка): холодный прогон 31.08 дал полную цепь главы $0.093 и $0.151 при `projected_book_usd = 1.1377277707` — но это **n=2 главы из десяти**, прогон остановлен снапшот-гардом, промпт черновика был банкнотным вместо конвенционного, и сам отчёт запрещает такое употребление дословно (`archive/reports/COLDRUN_V16_REPORT_2026-08-31.md`, греп `калибровать ставку платформы`). **Провенанс ниже — ИСТОРИЯ (D39.165 §1, 28.08):** средняя **$0.0115$0.0190**, максимум одной главы $0.0375, «завышена в **1.62.6×**» — ⚠ но НЕ покрывает максимум: источник (D39.165 §1) добавляет «и отдельные главы её уже пробивают» ($0.0375 против $0.03 = ×1.25), и «купить 10 глав» отдаёт движку $0.30, покупающий ~1626 глав («денежная ручка с подписью „главы"», `PD-410`). РЕШЕНО: цена — от ОБЪЁМА ИСХОДНИКА (носитель `chapters.units_total`, пишется интейком за $0), настоящий стоп — объёмный потолок В ДВИЖКЕ (см. §2). ⛔ Константу по сегодняшним числам НЕ калибровать (D39.165 ⛔г) — гейт строка 202 бэклога (`docs/PROGRESS.md:162`=`Живой перевод книги НАСКВОЗЬ через API платформы`). Исторический провенанс: exp08 v2 $0.0219/глава → ревизия D30.4 +1525% → округление ВВЕРХ (низкая ставка опаснее высокой — прогон встанет на потолке посреди книги; `platform/internal/pricing/pricing.go`, греп `Provenance, so the number is auditable`). Временная мера беты — честная оценка движковая (строка 166 бэклога, `docs/PROGRESS.md:135`=`Движковая поверхность оценки`).
3. **Ставка $0.03/глава — конфиг-константа платформы:** `DefaultPerChapter = 30_000` micro-USD (`platform/internal/pricing/pricing.go`, греп `DefaultPerChapter`), переопределяется `PerChapterMicroUSD` (`platform/internal/config/config.go`, греп `PerChapterMicroUSD`). ⚠⚠ **ЧИСЛА НИЖЕ — ИЮЛЬСКИЕ ДЕНЬГИ И С 16.08 НЕ ДЕЙСТВУЮТ (испр. ревизией 02.09).** D39.179 п.1 ратифицировал: DeepSeek пере-пинен под цены, вступившие **16.08 16:00 UTC**, множитель к июльским деньгам **×4.47**. ⇒ по действующему прайсу та же выборка даёт среднюю главу **≈$0.051$0.085** и максимум **≈$0.168**, то есть константа $0.03 не завышена, а **ЗАНИЖЕНА**, и знак вывода перевернулся. ⚠ Иллюстрация живыми деньгами (НЕ калибровка): холодный прогон 31.08 дал полную цепь главы $0.093 и $0.151 при `projected_book_usd = 1.1377277707` — но это **n=2 главы из десяти**, прогон остановлен снапшот-гардом, промпт черновика был банкнотным вместо конвенционного, и сам отчёт запрещает такое употребление дословно (`archive/reports/COLDRUN_V16_REPORT_2026-08-31.md`, греп `калибровать ставку платформы`). **Провенанс ниже — ИСТОРИЯ (D39.165 §1, 28.08):** средняя **$0.0115$0.0190**, максимум одной главы $0.0375, «завышена в **1.62.6×**» — ⚠ но НЕ покрывает максимум: источник (D39.165 §1) добавляет «и отдельные главы её уже пробивают» ($0.0375 против $0.03 = ×1.25), и «купить 10 глав» отдаёт движку $0.30, покупающий ~1626 глав («денежная ручка с подписью „главы"», `PD-410`). РЕШЕНО: цена — от ОБЪЁМА ИСХОДНИКА (носитель `chapters.units_total`, пишется интейком за $0), настоящий стоп — объёмный потолок В ДВИЖКЕ (см. §2). ⛔ Константу по сегодняшним числам НЕ калибровать (D39.165 ⛔г) — гейт строка 202 бэклога (`docs/PROGRESS.md`, греп `Живой перевод книги НАСКВОЗЬ через API платформы`). Исторический провенанс: exp08 v2 $0.0219/глава → ревизия D30.4 +1525% → округление ВВЕРХ (низкая ставка опаснее высокой — прогон встанет на потолке посреди книги; `platform/internal/pricing/pricing.go`, греп `Provenance, so the number is auditable`). Временная мера беты — честная оценка движковая (строка 166 бэклога, `docs/PROGRESS.md`, греп `Движковая поверхность оценки`).
4. **Холд прироста ДО спавна.** `holdTx` пишет отрицательную строку `('hold', -amount)` и тем же знаком двигает кэш баланса (`platform/internal/pgstore/credits.go`, греп `func holdTx(` — строку леджера пишет `appendLedger(… "hold", -amount …)`, кэш баланса двигает `MoveBalance` внутри неё); нехватка — `ErrInsufficientCredit`. Холд + прогон + попытка + очередь — одна транзакция (`platform/internal/pgstore/runs.go`, греп `func (s *Store) StartRun(`; рестарт — греп `func (s *Store) RestartRun(`; форма D39.123 п.2д).
5. **Аргумент движку: `bookCap = committed + прирост×ставка`, БЕЗ reserved — PD-158, дословно из кода: `return m.committed + increment`** (`platform/internal/runs/spawn.go`, греп `return m.committed + increment`). Обе фигуры читаются ОДНИМ вызовом `status --json` перед стартом (`bookMeter``platform/internal/runs/spawn.go`, греп `func (s *Service) bookMeter(`; отказы — греп `Absent is not zero`); отсутствие любой из них = отказ спавна («absent is not zero», PD-40). Почему без reserved: write-open движка занулит leftover до первой резервации, значит цифра из read-only status к моменту сравнения уже мертва; ратифицированная ранее формула с reserved переплачивала запасом ровно на leftover сверх холда — исполнено обеими формулами против гейта (D39.123 п.2б, поправка к D39.122(в)). Аргумент ≠ холд: он больше холда на committed (`docs/glossary.md:55`=`ЭТО НЕ ХОЛД — он больше холда`). Фактически ушедшее значение хранится в `run_attempts.ceiling_arg_micro_usd` (PD-144, миграция 00011); потолок уходит argv-шаблоном `{{usd}}` (шаблон — `platform/internal/config/config.go`, греп `CeilingArg`; подстановку делает `platform/internal/runner/engine.go`, греп `{{usd}}`; подстановку и рендер argv делает `platform/internal/runner/engine.go`, греп `func (t CeilingTemplate) Args(`; `platform/internal/runs/runs.go`, греп `func (s *Service) ceilingFor(` — однострочная делегация к нему; `spawn.go` потолок только передаёт); строка 145 закрыта D39.122.
6. **Baseline и списание.** `baseline = committed` книги на старте попытки (`platform/internal/runs/spawn.go`, греп `baseline, bookCap := m.committed`); списание попытки = разница счётчика с baseline; счётчик ниже baseline = подменённая БД, сеттлится в ноль с WARN — сами цифры в лог не идут (D39.84; `platform/internal/runs/reconcile.go`, греп `the book's meter reads below`).
@ -38,7 +38,7 @@
8. **Settle по фигуре движка.** `reconcile.settle` (`platform/internal/runs/reconcile.go`, греп `func (s *Service) settle(` — ⚠ номера строк в файлы живой зоны не ставим, пока её сессия работает) читает committed из status; `credits.Settle` одной транзакцией закрывает резервацию, возвращает холд и списывает spent; **spent > холда — капится холдом** с явной пометкой «capped at the hold; the engine reported …» (`platform/internal/pgstore/credits.go`, греп `capped at the hold; the engine reported`), перерасход движка счётом не абсорбируется.
9. **SpendBound (PD-159).** Отложенный settle читает пожизненный счётчик КНИГИ и без границы оплатил бы работу прогона-преемника (замер: $2.10 за прогон ценой $0.10, и преемник платил снова). Граница = наименьший baseline попыток той же книги, стартовавших ПОЗЖЕ: `committed = min(счётчик сейчас, SpendBound)` (`platform/internal/runs/reconcile.go`, греп `bound != nil`; `platform/internal/pgstore/runs.go`, греп `func (s *Store) SpendBound(`).
10. **Открытое — эскроу/intent (строка 136 бэклога, `docs/PROGRESS.md:108`=`Write-ahead intent`):** write-ahead intent + состояние `uncertain`-эскроу + `closing`; холд НЕ освобождается по выходу юнита (сигнал обгоняет денежные события); spend не постится без свидетельства провайдера; расход сверх холда — полной суммой, превышение явной строкой убытка. Стройка по research/25, «скоро». ⚠ **«Строка 103» — ФАНТОМ, снят 31.08:** такой строки в бэклоге нет (закрыта D39.131), а эмиттер шва ПОСТРОЕН с обеих сторон — платформа тейлит `events.jsonl` и принимает кадр `spend` (`platform/internal/ingest/events.go`, греп `TypeSpend Type`). Денежной слепоты это НЕ снимает по построению: поток событий — только свежесть. Платформа между спавном и settle слепа — защита держится холдом и потолком движка (§1).
10. **Открытое — эскроу/intent (строка 136 бэклога, `docs/PROGRESS.md`, греп `Write-ahead intent`):** write-ahead intent + состояние `uncertain`-эскроу + `closing`; холд НЕ освобождается по выходу юнита (сигнал обгоняет денежные события); spend не постится без свидетельства провайдера; расход сверх холда — полной суммой, превышение явной строкой убытка. Стройка по research/25, «скоро». ⚠ **«Строка 103» — ФАНТОМ, снят 31.08:** такой строки в бэклоге нет (закрыта D39.131), а эмиттер шва ПОСТРОЕН с обеих сторон — платформа тейлит `events.jsonl` и принимает кадр `spend` (`platform/internal/ingest/events.go`, греп `TypeSpend Type`). Денежной слепоты это НЕ снимает по построению: поток событий — только свежесть. Платформа между спавном и settle слепа — защита держится холдом и потолком движка (§1).
## 4. Фронт (зона `frontend/`)
@ -48,9 +48,9 @@
| Дыра | Носитель |
|---|---|
| **Строка 166** — движковая поверхность оценки $/глава; $0.03 — временная мера беты (П-10 зоны) | `docs/PROGRESS.md:135`=`Движковая поверхность оценки` |
| **Строка 78** — леджер = нижняя граница (биллящийся decode-fail мимо request_log, ≤13% захода на ре-пробе) | `docs/PROGRESS.md:65`=`Леджер денег = НИЖНЯЯ граница` |
| **Строка 136** — эскроу/intent (см. §3 п.10) | `docs/PROGRESS.md:108`=`Write-ahead intent` |
| **Строка 166** — движковая поверхность оценки $/глава; $0.03 — временная мера беты (П-10 зоны) | `docs/PROGRESS.md`, греп `Движковая поверхность оценки` |
| **Строка 78** — леджер = нижняя граница (биллящийся decode-fail мимо request_log, ≤13% захода на ре-пробе) | `docs/PROGRESS.md`, греп `Леджер денег = НИЖНЯЯ граница` |
| **Строка 136** — эскроу/intent (см. §3 п.10) | `docs/PROGRESS.md`, греп `Write-ahead intent` |
| *(добавка сборщика)* **PD-157 (minor)**`day_usd` книги флагом не перекрывается, платформой не виден и не задаётся; в `status --json` дневной фигуры нет | `platform/docs/DEFECT_REGISTER.md`, греп `PD-157` |
## 6. Карта носителей темы

View file

@ -10,7 +10,7 @@
**Что.** Машинный канал живого статуса движок→платформа: NDJSON-журнал `events.jsonl` в каталоге книги — словарь-enum со стабильными типами, version-хендшейк первой строкой (правило terraform), плотная нумерация `seq`, событие потолка и событие денег. Заказ жил строками бэклога **103** (эмиттер) и **165** (различимые exit-коды); обе ЗАКРЫТЫ D39.131 и из живого бэклога сняты — дословные формулировки заказа, если понадобятся, лежат в архивных слайсах `../archive/PROGRESS-*.md`.
**Зачем две ноги.** (а) *Свежесть статуса* — слово владельца 08.08: «эмиттер нужен СВЕЖЕСТИ статуса и деньгам шва, не первым экранам» (D39.119 п.1); резерв на время без него — периодический `status --json`-резюнк. (б) *Деньги шва*: без события потолка «экран покажет „ошибка“ там, где верно „остановлено: лимиты“» (PD-113), а после поправки формулы потолка (D39.123, PD-158) стоп по потолку = ровно исчерпание холда, поэтому цена неразличимости выросла (⚠ неразличимость вскрыта **приёмкой раннера на РЕАЛЬНОМ tmctl** — фейк пробы умирал от сигнала; дословный заказ — `docs/archive/prompts/BACKEND_EMITTER_SESSION_PROMPT_2026-08-10.md:96`=`Новые exit-коды tmctl`).
**Зачем две ноги.** (а) *Свежесть статуса* — слово владельца 08.08: «эмиттер нужен СВЕЖЕСТИ статуса и деньгам шва, не первым экранам» (D39.119 п.1); резерв на время без него — периодический `status --json`-резюнк. (б) *Деньги шва*: без события потолка «экран покажет „ошибка“ там, где верно „остановлено: лимиты“» (PD-113), а после поправки формулы потолка (D39.123, PD-158) стоп по потолку = ровно исчерпание холда, поэтому цена неразличимости выросла.
**Что эмиттер НЕ решает** (и не решал): реконсилятор и свип — платформа (строки 138·139 закрыты, D39.123 п.3) · write-ahead intent / `uncertain`-эскроу / `closing` — строка 136 бэклога · пиннинг версии бинаря на прогон — исполняется резюмом (PD-143/134 закрыты) · движковая оценка $/глава — строка 166 · тейлер/декодер платформы — `platform/internal/ingest/`, эмиттер пишет ПОД их контракт.
@ -66,4 +66,4 @@
1. **Знаменатели голосов панелей `research/25` различаются между вариантами** (0/15 · 0/~18) — это РАЗНЫЕ плечи панелей, не усреднять. Оговорка нужна ровно там, где §2 цитирует счёт голосов отвергнутых альтернатив.
2. Тела D39.84/D39.85/D39.100 вошли сюда через цитаты D39.106 и доккомменты кода — при сомнении открывать первоисточники (живой D-лог/слайсы), а не эту сборку.
**Снято как отработанный хендофф** (D39.131, `9cfe080`) — речь о ПРЕЖНИХ разделах этого файла, нумерация с тех пор сдвинулась и живой §5 выше — другой (⚠ испр. 02.09: надгробие называло их «§5·§6·§7» как действующие). **Прежний раздел развилок** — «пять открытых развилок дизайна», все пять решены (формат = одиночный JSONL · политика PD-60 = громкая деградация · fsync каталога один раз при создании · значение exit-кодов · словарь, отвеченный диффом), ответы читать в `backend/internal/runevents/journal.go` и `runevents.go`. **Прежний чек-лист входного чтения эмиттер-сессии** (ратифицирован D39.123 п.4) — исполнен, ни одной внешней ссылки на него не было. **Из прежних «оговорок сборки»** две первые сняты стройкой (сверка словаря с `research/23` сделана диффом; «строка события в той же SQLite-транзакции, что чекпойнт» — теперь факт кода `backend/internal/store/outbox.go`, а не формула).
**Прежние разделы этого файла сняты как отработанный хендофф** (D39.131, `9cfe080`): пять развилок дизайна решены (формат = одиночный JSONL · политика PD-60 = громкая деградация · fsync каталога один раз при создании · значение exit-кодов · словарь) — ответы читать в `backend/internal/runevents/journal.go` и `runevents.go`, не здесь.

View file

@ -12,8 +12,8 @@
> исследование шва дошло до «события пишутся в `events.jsonl`» и дальше отвечало только на вопрос «как запускать
> движок» (`research/23`, транспортная часть §1 superseded D39.106; `research/25` — ратифицированная форма и
> отвергнутые альтернативы). НАРУЖУ из движка идёт богатый поток — журнал событий по курсору, полоса кодов
> выхода, версионированные артефакты-проекции, — а ВНУТРЬ не шло ничего, кроме запуска с флагами: данные, которыми
> владеет пользователь продукта, движок принимать не умел вовсе, и каждый внешний участник был вынужден имперсонировать человека-оператора с текстовым редактором.
> выхода, версионированные артефакты-проекции, — а ВНУТРЬ не шло ничего, кроме запуска с флагами: данные,
> которыми владеет пользователь продукта, движок принимать не умел вовсе.
## Почему НОРМА, а не каталог команд
@ -26,8 +26,8 @@
**192** прямо запрещена к проектированию до полигонных итогов (D39.144 п.1; ⚠ область сужена D39.165 — открыть дверь к построенному ≠ проектировать цикл, см. ⚠-строку под таблицей дверей), **161**/**185** ждут
дизайн-пака, **170** — «после беты формы Б». Каталогизировать их сейчас значит выдумывать.
Прецедент, разрешающий спор, — исходящее направление: там выиграла ратификация ПОЛОСЫ и ДИСЦИПЛИНЫ,
а не перечня.
Прецедент — исходящее направление: там выиграла ратификация ПОЛОСЫ и
ДИСЦИПЛИНЫ, а не перечня.
## Закон: семь пунктов

View file

@ -4,11 +4,9 @@
> при конфликте побеждает журнал решений. Собрано оркестратором №19 по консилиуму со сторонним
> архитектором при приёмке четырёх паков входной двери шва.
>
> **Зачем страница.** Вокруг одного понятия — «состояние банка этой книги» — живут десять носителей,
> выросших пак за паком. Форма при этом СТРОГАЯ: поток однонаправленный, у каждого источника
> единственный писатель, вид пересобирается полностью на каждой границе прогона. Но эта строгость не
> была записана нигде — каждый файл документировал свою роль, ни одно место не документировало поток
> (D39.158 п.8).
> **Зачем страница.** Вокруг одного понятия — «состояние банка этой книги» — живут десять носителей.
> Форма СТРОГАЯ: поток однонаправленный, у каждого источника единственный писатель, вид пересобирается
> полностью на каждой границе прогона (D39.158 п.8).
## Четыре роли, и они не смешиваются
@ -62,8 +60,7 @@
⚠ **КЛАСС B — другой, и путать их нельзя: межносительный инвариант, живущий комментарием без пина.**
Член — порядок «карта → память» до фикс3. Он НЕ подпадает под класс A: там дефект в том, что документ
не несёт контракта, здесь — в том, что связь ДВУХ носителей держится только текстом, который ничего не
проверяет. Разделено 27.08 по вычитке старшего: в одном классе они были бы неподсудны — первый же
судья отклонил бы членство порядка, и вместе с ним ушёл бы весь класс.
проверяет.
**Второй ярус КЛАССА A (D39.159): носитель с ДВУМЯ писателями и НОЛЬ читателей.** Здесь опасность не в отсутствии
потребителя — она в том, что расхождение писателей ничем не судится, пока читателя нет, а в день,

View file

@ -4,7 +4,7 @@
## Роли и фазы
- **Оркестратор / Бэкенд / Полигон / Фронт / Платформа** — роли сессий с зонами записи (CLAUDE.md §Роли); платформа = SaaS control plane (`platform/`, D39.81). «Оркестратор №N» — канонический счётчик преемственности роли (текущий N — в шапке ORCHESTRATOR_SESSION_PROMPT).
- **Оркестратор / Бэкенд / Полигон / Фронт / Платформа** — роли сессий с зонами записи (CLAUDE.md §Роли); платформа = SaaS control plane (`platform/`, D39.81). «Оркестратор №N» — канонический счётчик преемственности роли (текущий N — CURRENT-STATE `docs/PROGRESS.md`, единственный носитель; выдаёт номер автор промта передачи, D39.112 п.6).
- **Хендофф(-промт)** — передача роли новой сессии файлом-промтом; аддендумы к бегущей сессии доезжают только релеем владельца.
- **Владелец** — человек; ратифицирует деньги, скоуп-сдвиги, продукт, 18+; связной между сессиями.
- **Ф0Ф3** — фазы: Ф0 скелет · Ф1 инфраструктура · Ф2 качество (судья/гейты) · Ф2.5 пилот · Ф3 продукт (веб-фронт, ридер-IDE).
@ -17,7 +17,7 @@
## Решения и документы
- **D-номер (D39.x)** — ратифицированная запись в `architecture/05-decisions-log.md`; **голова** — последний номер; **эра** — куст решений одного курса; **лендинг** — коммит работ сессии оркестратором после приёмки.
- **Р-номер — ДВА смысла по контексту:** Р1Р10 = десять ранних принципов (`01-decisions.md`, историчны); Р1Р7 в записях эры D39.5x6x = вопросы/решения владельца по банку и промптам (D39.63 и соседние) — «Р2 = ЗНАЧЕНИЕ» из CURRENT-STATE не про принцип Р2. **H1H18 / L1L8** — находки стратегического аудита (`09-target-architecture.md` §3); H — HIGH, в т.ч. незакрытые владельческие требования.
- **Р-номер — ДВА смысла по контексту:** Р1Р10 = десять ранних принципов (`01-decisions.md`, историчны); Р1Р7 в записях эры D39.5x6x = вопросы/решения владельца по банку и промптам (D39.63 и соседние) — «Р2 = ЗНАЧЕНИЕ» (D39.63) не про принцип Р2. **H1H18 / L1L8** — находки стратегического аудита (`09-target-architecture.md` §3); H — HIGH, в т.ч. незакрытые владельческие требования.
- **Q1Qn** — нумерованные вопросы КОНКРЕТНОГО пакета/отчёта — контекст локален, Q2 пака-19 ≠ Q2 чекер-пака.
- **V0Vn** — секции идей владельца в `START_PROMT.MD` (живой бриф; разобраны в `product-requirements.md`).
- **Ш-1/Ш-2** — стоячие трипваеры голден-дрейфа стандартной библиотеки; Ш-2 = пересмотр `unicode.Version`-зависимых мест (memnorm/classifier/style + chunker/estimator) до перехода на go1.27 (детали — grep «Ш-2» по D-логу).
@ -49,7 +49,7 @@
- **tmctl** — CLI бэкенда. Полный список глаголов — ОДИН в коде (`backend/cmd/tmctl/main.go`, `dispatchCommands`), и он же печатается в usage (паритет «список ↔ usage ↔ switch» прибит тестом `cmd/tmctl/invocation_test.go`); сверка одной командой: `grep -n -A3 "dispatchCommands = " backend/cmd/tmctl/main.go`. ⚠ Копия списка стояла здесь и трижды отставала от кода — снята: носитель один, отдельные глаголы (`build`, `bank-apply`) расшифрованы строками ниже.
- **COGS** — себестоимость перевода; **ре-проба** — дешёвый повторный замер провайдера после аномалии (носитель события — строка 188; исходная 74 закрыта D39.91).
### Неймспейсы номеров (полная легенда — испр. D39.125 по докс-аудиту)
### Неймспейсы номеров
- **PD-N** — регистр дефектов ПЛАТФОРМЫ (`platform/docs/DEFECT_REGISTER.md`; счёт — `counts.py`); **П-N** — зонный бэклог платформы (`platform/BACKLOG.md`); **Ф-N** — зонный бэклог фронта (`frontend/docs/BACKLOG.md`); **В-N** — вопрос ВЛАДЕЛЬЦУ от фронта (журнал `frontend-PROGRESS.md`); **К-N** — вопрос контракта API (`14-api-contract/README.md`). «Строка N» без префикса = ЕДИНЫЙ бэклог `docs/PROGRESS.md` (НЕ номер строки файла).
- **Глава** — единица структуры книги: детект `chunk/ingest.go` (txt: CJK-шапки/form-feed; epub: документ spine), нумерация плотная позиционная + титульная политика `chunk/chunker.go` (`stripHeading`/`ApplyHeading` по `langpacks/*/heading.txt`), идентичность = контент-хеш в манифесте (`pipeline/manifest.go`), деньги ключуются ПОЗИЦИЕЙ (сдвиг границы = перекупка хвоста). Дизайн будущего — `research/27`.
- **Деньги платформы:** **холд** — резервация суммы прироста на счёте ДО спавна; **прирост** — купленные главы × ставка ($0.03, `platform/internal/pricing/pricing.go`); **аргумент потолка** — что уходит движку в `--ceiling-usd` = committed книги + прирост (PD-158; ЭТО НЕ ХОЛД — он больше холда на committed); **baseline** — счётчик книги на старте попытки, списание = разница; **settle/расчёт** — закрытие холда по фигуре движка; **leftover-reserved** — висячий reserved движка после краша (зануляется его write-open); **SpendBound** — верхняя граница отложенного расчёта по baseline следующей попытки (PD-159).

View file

@ -47,20 +47,20 @@
| ПТ-17 | Лимит размера входа настройкой (V2-п.3, H7) | ⭕ | строка 94 |
| ПТ-18 | Стоп и продолжение пайплайна; абьюзивный прогон НЕ продолжать (V2-п.2, H10) | 🔶 | graceful stop по сигналу (`cmd/tmctl/main.go` NotifyContext) + чекпойнты/redrive; продукт-кнопки и связка с прескрином = строка 94; API-форма в контракте 14 (D39.99: stop/resume; отказ прескрина — К-9 закрыт D39.138 п.2б) |
| ПТ-19 | Скорость: «очень быстрый перевод книги — киллерфича» (V4-п.1, H9); видимый прогресс/ETA — из Ф3-видения ридер-IDE (цветная полоса статуса), не из V4 | 🔶 | волны параллельны по чанкам; замер скорости и ETA на целой книге = строка 54 (МАСШТАБ); пофазные счётчики draft/edit НА ГЛАВУ построены движком (D39.122 — строка 99 ЗАКРЫТА); ETA ПОКАЗЫВАТЬ — решение владельца 04.08 (D39.100/К-5), `eta_seconds` в спеке (0.2.0+, D39.115); оценка $/глава движком = строка 166 |
| ПТ-44 | **Готовый перевод отдаётся ПОЛЬЗОВАТЕЛЮ файлом** — читаемая книга (EPUB 3 + чистый txt), а не JSON-выхлоп; неполная книга выдаётся ВСЕГДА, с пометкой на титуле и маркером на месте каждой дыры (слово владельца 30.08: «дверь ВСЕГДА строит файл — отказ юзеру не отдаётся»; отказ по умолчанию остаётся операторской ручкой CLI) | 🔶 | **Движковая половина ПОСТРОЕНА** (D39.175, `8adcb86`) — глагол `tmctl build`, пакет `backend/internal/bookfile`, шесть состояний честности и полоса отказов расшифрованы в `glossary.md`, флаги и конверт `tm-export-v1` — в теле ноты. **НЕ построена дверь платформы** (`createExport`/`getExport`) — очередь №20 п.4, гейт: живой прогон п.3. Открытое на владельце: лестница D25.1 (какая ступень даёт копию БЕЗ пометки, что печатать на титуле) |
| ПТ-44 | **Готовый перевод отдаётся ПОЛЬЗОВАТЕЛЮ файлом** — читаемая книга (EPUB 3 + чистый txt), а не JSON-выхлоп; неполная книга выдаётся ВСЕГДА, с пометкой на титуле и маркером на месте каждой дыры (слово владельца 30.08: «дверь ВСЕГДА строит файл — отказ юзеру не отдаётся»; отказ по умолчанию остаётся операторской ручкой CLI) | 🔶 | **Движковая половина ПОСТРОЕНА** (D39.175, `8adcb86`) — глагол `tmctl build`, пакет `backend/internal/bookfile`, шесть состояний честности и полоса отказов расшифрованы в `glossary.md`, флаги и оба конверта (`tm-build-v1` у глагола build, аддитивно расширенный `tm-export-v1`) — в теле ноты. **НЕ построена дверь платформы** (`createExport`/`getExport`) — очередь CURRENT-STATE, п.4 «дверь выдачи», гейт: живой прогон п.3. Открытое на владельце: лестница D25.1 (какая ступень даёт копию БЕЗ пометки, что печатать на титуле) |
## Фронт (Ф3)
| ID | Требование (источник) | Статус | Носитель / доказательство |
|---|---|---|---|
| ПТ-20 | Ридер-IDE: VS Code-подобный фронт агентного перевода (V0-п.20/23) | ⭕ | research/16 принят (D29); строки 6971; F3-brief — D29 п.3. Ф3 ОТКРЫТА 02.08 (D39.81): фронт-сессия живёт на моках; контракт API ратифицирован (D39.99; ⚠ версию канона брать ФАЙЛОМ, не этой ячейкой — норма и команда в карте `README.md`. Открытыми по контракту остаются хвост строки **203** и строка **241** — самопротиворечие канона на дочитанной книге.); платформа построена до читающей поверхности и денежной двери (паки P0…P12 — реестр нот; ⚠ КВОТ нет ни строки кода, и по D39.176 п.1 не будет — продуктовых квот нет, фри-тир-лимиты не проектируются; ретеншен/свип остаются инженерной гигиеной); фронт — S0S4 приняты, **зона ЗАМОРОЖЕНА** (D39.136 п.2 + D39.147: сначала движок и платформа до «работает и отдаёт результат», фронт накручивается на готовую функциональность) |
| ПТ-21 | Параллельное чтение двух текстов с выравниванием по смыслам (V0-п.21); выравнивание грубое, по единицам экспорта — принято владельцем 02.08, спаны внутри текста не строятся | 🔶 | механизм готов: `tmctl export --pairs` выравнивает пары побайтно по единицам редактуры (`internal/pipeline/export.go:89-93`); якорь = **edit-unit**, НЕ чанк (переформулировано D39.84 — финальный текст существует только на уровне юнита, ~1.9 юнита/главу, местами глава = один блок; читалка обязана это выдерживать); UI-читалка = Ф3 (этап S6) |
| ПТ-21 | Параллельное чтение двух текстов с выравниванием по смыслам (V0-п.21); выравнивание грубое, по единицам экспорта — принято владельцем 02.08, спаны внутри текста не строятся | 🔶 | механизм готов: `tmctl export --pairs` выравнивает пары побайтно по единицам редактуры (`internal/pipeline/export.go:147`=`aligned byte-for-byte`); якорь = **edit-unit**, НЕ чанк (переформулировано D39.84 — финальный текст существует только на уровне юнита, ~1.9 юнита/главу, местами глава = один блок; читалка обязана это выдерживать); UI-читалка = Ф3 (этап S6) |
| ПТ-22 | Настройки от человека: 18+, жанр и т.п. (V0-п.22) | 🔶 | `book.yaml` (labels) данными; UI = Ф3. ⚠ ЖАНР из продукта ВЫКИНУТ словом владельца 16.08 (D39.138 п.2в, строка 184: ни на чём не ветвится, влияние не измерено; снимается из промптов/брифа/контракта/формы) |
| ПТ-23 | Веб-ПЕРВЫЙ фронт; SEO/ранжирование Google — куки, страницы-сироты, актуальные алгоритмы (V5-п.2); продукт = **SaaS**, не локальное приложение (решение владельца 02.08, D39.81 — натив-прицел V0-п.26 СНЯТ этим решением, вернуть только новым словом владельца); SEO только под Google, Яндекс снят; рынок глобальный; десктоп = PWA первым шагом, Tauri по явным триггерам (решения владельца 02.08, D39.84) | ⭕ | строка 71 (Ф3-бриф); SEO вошёл в стек-дизайн ДО выбора (D39.84, требование исполнено): двухконтурный деплой — SPA `app.<домен>` целиком под noindex + статический публичный контур ≤3 кликов от главной (лечение страниц-сирот), `frontend/docs/STACK_DECISIONS.md` §4; SSR-вопрос закрыт этим решением |
| ПТ-24 | Цикл согласования глоссария с профпереводчиком/редактором (V0-п.23) | 🔶 | подписной цикл терминолога в бэкенде есть; UI = Ф3. Модель цикла записана словом владельца 16.08 (D39.144 + строка 192): черновой перевод и черновой банк появляются вместе → ОДИН ОК всему банку (не пер-термная масс-подпись) → доработка → пост-ридинговые точечные правки с пере-генерацией по вхождениям (механика — после полигона) |
| ПТ-33 | Интерфейс НЕ раскрывает конвейер: ни моделей, ни стадий, ни внутренней терминологии (решение владельца 02.08; граница пере-читана 15.08 — охранять АЛГОРИТМЫ, не минорную механику, D39.136 п.4а). ⚠ «Лестница» фаз «загрузка → … → финал → готово» — устная фраза владельца, НЕ норма продукта (его слово 16.08, D39.138: `finalizing` сворачивается) | 🔶 | инвариант D39.81; словарь статусов принят (D39.100/К-1); карта «вердикт → фраза» — приложение А компаньона (В-3), после D39.138 пишется по словарю машинных кодов Б-1. Машинный ГЕЙТ на утечку волн draft/edit — фронту при разморозке (пинг 16.08; сама утечка снята батчем 0.3.0, D39.142/143). Полоса прогресса — ОДНА монотонная доля на всю работу прогона через обе волны, считает СЕРВЕР, плюс подпись «что делается сейчас» (`Progress.stage`, ВТОРОЕ и последнее исключение границы — D39.163, словарь ОТКРЫТ, клиент рисует незнакомое нейтрально). ⚠ **Остаток, который НЕ закрылся и назван честно:** платформа продаёт ГЛАВЫ, а движку передаёт только денежный потолок — единица продажи не равна единице остановки (`PD-410`, архитектурный стоп; направление лечения — D39.165 §1). И полоса ПЕРЕ-ПРОХОДА гранулярности не имеет вовсе: движок анонсирует работу один раз за жизнь книги, поэтому она объявлена «одной неделимой единицей работы» (D39.166), а не выведена |
| ПТ-34 | Пользовательский перевод НИКОГДА не попадает на публично индексируемый URL — ни витрин примеров, ни «поделиться главой», ни публичных ссылок чтения (жёсткий продуктовый запрет, решение владельца 02.08; авторское право на исходники + политика Google по масштабируемому машин-контенту действуют на весь домен) | ⭕ | инвариант D39.84; носители: двухконтурный деплой `frontend/docs/STACK_DECISIONS.md` §4 (SPA под `X-Robots-Tag: noindex` на каждом HTML-ответе; публичный контур без контента переводов) + контракт 14 (`architecture/14-api-contract/`, D39.99) + платформенный бэклог П-1; правило доступа к экспорт-ссылке (срок/подпись) — батч 183 (research/28 Б-4) |
| ПТ-35 | Лимиты «как в Claude Code» (решение владельца 04.08, D39.100): страница лимитов/использования в настройках (статус, НЕ суммы — запрет денег на экране в силе); стоп по потолку = статус `paused` + оповещение «перевод остановлен: лимиты исчерпаны» | 🔶 | контракт К-8 закрыт, спека несёт `paused`/`paused_reason` (0.2.0+, D39.115); ручки /v0 — платформа-раннер P4 (D39.123); статус `paused` по потолку ЧЕСТЕН с P6 (D39.132: exit 4/событие → `paused`, не `failed`; дневной потолок оператора различим и из платформенного шаблона убран — решение владельца 15.08); остаток: страница лимитов и оповещение на фронте (после P7) · ⚠ фразы (В-3 · К-6 · Приложение А) ДЕЛЕГИРОВАНЫ проекту словом владельца 30.08 (D39.176 п.4): подписи владельца НЕ ждём, требование ИНЖЕНЕРНОЕ — фраза не литерал ни в Go, ни в TSX, а ДАННЫЕ по машинному коду причины и локали; вместе со словарём закрывается `PD-246`, гейт — строка бэклога 204 · К-13 ЗАКРЫТ (D39.132 п.2а: `null` на проводе) |
| ПТ-35 | Лимиты «как в Claude Code» (решение владельца 04.08, D39.100): страница лимитов/использования в настройках (статус, НЕ суммы — запрет денег на экране в силе); стоп по потолку = статус `paused` + оповещение «перевод остановлен: лимиты исчерпаны» | 🔶 | контракт К-8 закрыт, спека несёт `paused`/`paused_reason` (0.2.0+, D39.115); ручки /v0 — платформа-раннер P4 (D39.123); статус `paused` по потолку ЧЕСТЕН с P6 (D39.132: exit 4/событие → `paused`, не `failed`; дневной потолок оператора различим и из платформенного шаблона убран — решение владельца 15.08); остаток: страница лимитов и оповещение на фронте (после РАЗМОРОЗКИ зоны: лендинг P7 её НЕ размораживает — D39.147) · ⚠ фразы (В-3 · К-6 · Приложение А) ДЕЛЕГИРОВАНЫ проекту словом владельца 30.08 (D39.176 п.4): подписи владельца НЕ ждём, требование ИНЖЕНЕРНОЕ — фраза не литерал ни в Go, ни в TSX, а ДАННЫЕ по машинному коду причины и локали; вместе со словарём закрывается `PD-246`, гейт — строка бэклога 204 · К-13 ЗАКРЫТ (D39.132 п.2а: `null` на проводе) |
| ПТ-36 | Интерфейс МУЛЬТИЯЗЫЧНЫЙ, русский не хардкодится в разметке (слово владельца 10.08; язык интерфейса — отдельная ось от языков перевода) | 🔶 | ПОСТРОЕНО S3.7 (принят D39.129): каталог `frontend/src/i18n/ru.ts` (⚠ число ключей здесь НЕ держим — оно растёт каждым касанием зоны; счёт снимается командой `grep -cE "^\s+'[a-z][a-zA-Z0-9.]*':" frontend/src/i18n/ru.ts`) · механизм `@internationalized/string` · ESLint-гейт «текст местом» · стор языка с персистом · `<html lang>` следует выбору; содержимое — только ru; продуктовый список языков — 🔒 владелец (В-9 зоны фронта) |
## Качество процесса и самоулучшение