diff --git a/docs/ORCHESTRATOR_SESSION_PROMPT.md b/docs/ORCHESTRATOR_SESSION_PROMPT.md index 6cd322ce..b0ac7c2f 100644 --- a/docs/ORCHESTRATOR_SESSION_PROMPT.md +++ b/docs/ORCHESTRATOR_SESSION_PROMPT.md @@ -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-лог (карта+эрраты; из тел — 2–3 последние; +правило чтения — CLAUDE.md). По теме: шапка `09-target-architecture` · `12-go-style-notes` · +`10-prompt-architecture`. ## Ситуации → инструкции diff --git a/docs/POLYGON_EXP2223_REDO_SESSION_PROMPT.md b/docs/POLYGON_EXP2223_REDO_SESSION_PROMPT.md index 196f74eb..14bad6bc 100644 --- a/docs/POLYGON_EXP2223_REDO_SESSION_PROMPT.md +++ b/docs/POLYGON_EXP2223_REDO_SESSION_PROMPT.md @@ -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-гейтом. > Любая резка сдвинула бы всё это молча, поэтому поправки — списком здесь, а не в теле.) > diff --git a/docs/POLYGON_PHASE_D_HANDOFF.md b/docs/POLYGON_PHASE_D_HANDOFF.md index 42f4bae8..2126c4cf 100644 --- a/docs/POLYGON_PHASE_D_HANDOFF.md +++ b/docs/POLYGON_PHASE_D_HANDOFF.md @@ -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; редакции 1–3 отвергнуты консилиумом). В `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, **в замер НЕ входят**. diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index e7bb3ad1..dabbbf53 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -1,11 +1,10 @@ # Журнал прогресса -> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-09-01, голова D39.185 — КУРС: движок и платформа до «работает и отдаёт результат», фронт ЗАМОРОЖЕН и P7 его НЕ размораживает (D39.147). **ОЧЕРЕДЬ №22** (единственный носитель — здесь; роль передана 01.09, №21 закрыт нотой передачи D39.184). ⚠ **ЗАКАЗ ВЛАДЕЛЬЦА 01.09 — ПЕРВЫМ:** (0а) **ревизия документации на ПРОТУХШЕЕ** — по всем зонам, не только тронутым; (0б) **планы доработок в БЭКЕНД и ПЛАТФОРМУ** по остатку бэклога и регистра; (0в) **вынос неактуального в АРХИВ** (`docs/archive/`, `platform/docs/archive/`) — за сутки 31.08 закрыто много, и часть носителей стала историей. ⚠ Трезвость по масштабу (пере-считано 02.09): **88** живых доков в `docs/` против **198** заархивированных, 8 в `platform/docs`, 9 в `backend/docs` — ⚠ из 88 три ВРЕМЕННЫЕ (`DOC_CLEANUP_PLAN` · `DOC_REVISION_FINDINGS` · `DOC_REVISION_REFUTED`), они уедут в архив по закрытии разбора, то есть постоянных **85**; счёт бэклога — бюллетенем ниже, открытых рядов регистра платформы — 97 (major 2) ⚠ (ревизией 02.09 ряды **154** и **157** переведены из «скоро» в «когда-нибудь»: их гейтом стоял первый холодный прогон, он ОТРАБОТАЛ 31.08 и оба предусловия оказались другими — разбор в самих ячейках, ни одна НЕ закрыта). ⚠ Числа доков `counts.py` НЕ сторожит — при переносе файлов пере-считывать руками командой `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`. ⚠ И предупреждение о МЕТОДЕ, купленное сменой №21: «выглядит протухшим» ≠ «протухло». Три факта оркестратора опровергнуты ЗАМЕРОМ сессий, а якоря `15-money-path.md` в девяти случаях из двенадцати РОДИЛИСЬ верными и сгнили дрейфом — то есть ревизия обязана быть исполнением, а не чтением. ⚠ **ОЧЕРЕДЬ, унаследованная от №21** (⚠ **пак P12 ПРИНЯТ И ЗАЛЕНДЖЕН 31.08 — D39.180**, вместе с контрактным минором **0.9.0**; `PD-425` закрыт им же. ⚠ **ДВА ЛЕНДИНГА 31.08:** бэкенд-пак **«ДЕНЬГИ И ЧЕСТНОСТЬ ВЫДАЧИ» — D39.182** (счёт линз, блокеров и урок «дефект в самом лекарстве» — телом ноты; тестов 1045→1083, удалённых ноль) и ратифицированный владельцем **ЗАКОН РАСКРЫТИЯ движка — D39.181**, применённый к одиннадцати экземплярам): **(1) РАЗРЫВ ЦИКЛА: книга не отдаётся файлом ПОЛЬЗОВАТЕЛЮ — открыта ПЛАТФОРМЕННАЯ половина.** Движок пишет файл с 30.08 (`tmctl build` — EPUB 3 + чистый txt, D39.175), и холодный прогон 31.08 предъявил это живьём: собранный EPUB настоящего перевода прошёл `epubcheck` 0/0/0/0 и передан владельцу. Открыто ровно одно: канон обещает `createExport`/`getExport`, а платформа их НЕ монтирует (смонтировано 15 операций из 20; нет также `getRun`, `updateBook`, `deleteBook`). Долг числится с P8 (`platform/BACKLOG.md` П-17), и НИ ОДИН пак платформы после P7 его не взял (проверка вместо ручного счёта, чтобы не гнило при каждом лендинге: `grep -rn 'createExport\|getExport' platform/internal/ --include=*.go` — пусто). **Слово «отдаёт результат» ложно по букве ТОЛЬКО платформенной половиной** (п.4) · **(2) ~~холодный прогон движка~~ ОТРАБОТАЛ 31.08, закрыт РЕШЕНИЕМ ВЛАДЕЛЬЦА «не доводить»** (отчёт — `archive/reports/COLDRUN_V16_REPORT_2026-08-31.md`, числа относятся к `065d8ac`). Потрачено **$0.436110** из санкции $0.80. ПРЕДЪЯВЛЕНО живьём: объёмный потолок · D39.158 ОБЕИМИ половинами (стоп и не-стоп) · exit 16 · строки 154/198/239/240. ⚠ **Причина большой доли редактора НЕ УСТАНОВЛЕНА** — три каузальные истории построены и две сняты. Доля редактора идёт с ДВУМЯ знаменателями: **49.3%** от всего прогона ($0.214865 из $0.436110) и **81.3%** внутри порции П1 (⚠ ходившее «73%» — фантом, в отчёте его нет ни разу). Следующий шаг — контролируемая проба по ЧЕТЫРЁМ осям (§14 отчёта): трудность чанка БЛОКИРОВАТЬ, длину входа КОНТРОЛИРОВАТЬ, промпт по SHA, эффорт `off` против `low`. Ось `stale` НЕДОСТИЖИМА (под дрейфом `staleUnits` возвращает UNKNOWN немедленно). ⚠ **Цена: слово владельца 31.08 — ≈$0.60, потолок $0.80, ДЕСЯТЬ глав ПОЛНОЙ цепью включая редакторскую волну.** ⚠ **ГЕЙТ КЛЮЧЕЙ СНЯТ словом владельца 30.08** (D39.176 п.6), но конвенционного `.env` НЕТ НИ У ОДНОЙ книги корпуса — прогон обязан передавать `--keys-file` абсолютным путём; заполнены только `projects/textmachine/backend/.env` и `.../eval/.env`. ⚠ Для п.3 нужен ДРУГОЙ файл — путь платформы `TM_PLATFORM_ENGINE_KEYS_PATH`. **Вопрос владельцу СНЯТ 31.08 вычитанием инженерной половины:** формат обоих файлов совпадает (`KEY=VALUE`), переменная требует АБСОЛЮТНОГО пути (`platform/internal/config/config.go`, греп `must be an absolute path`), едет `--keys-file` и только на `translate`; заполненный файл на машине существует. Лечение операционное и $0 — направить переменную на него; проверять ПРОГОНОМ, не чтением (гардрейл `.env`) · **(3) живой сквозной прогон через API платформы** — форма манифеста, сайдкара банка и карта причин флагов сочинены платформой САМОСТОЯТЕЛЬНО. ⚠ Уточнено 01.09: гейт СНЯТ холодным прогоном, и настоящие артефакты движка теперь ЕСТЬ (каталог `books/gu-zhenren/coldrun-v16/`), но сверка вышла ТОНКОЙ: на шов реально вышло **одно значение `flag_reason` из пятнадцати** (`sanitizer_stripped`), остальные четырнадцать по-прежнему только чтением кода, а манифест против `platform/internal/ingest/manifest.go` не сверялся вовсе · **(4) дверь выдачи** — строго ПОСЛЕ (3) (⚠ слово владельца 30.08: дверь ВСЕГДА строит файл — отказ юзеру не отдаётся, неполная книга уходит с пометкой, т.е. дверь зовёт `tmctl build --partial`; отказ по умолчанию остаётся операторской ручкой CLI; D29.1(б) «fail-closed» читать как «никогда молча» — честность несут пометки) · **(5) проводка `--max-units`** — снятие гейта, а не стройка: механизм в движке стоит (D39.170), живое основание гейта — `PD-422` · **(6) разморозка фронта** — ПОСЛЕ (4): зеркало отстало на СЕМЬ миноров (`frontend/docs/api-contract/openapi.yaml` — `0.2.3` против канона `0.9.0`, и первый из них — ЛОМАЮЩИЙ 0.3.0), 16 операций против 20; отставание ратифицировано D39.142 п.5 на время фриза и две ручки разъехались, размораживать раньше значит перегенерировать типы дважды. ⚠ **ДВА ЗАГЕЙЧЕННЫХ ТРИГГЕРА НАЖАТЫ И НЕ ОТРАБОТАНЫ — строка бэклога 237** (`go.work` · вендор-сверка эффорта `deepseek-v4-pro`; реестр `13-tech-debt-anchors.md` §Б-108). ⚠ **Состояние git — снимать КОМАНДАМИ, не чтением** (ветка `polygon` ушла вперёд, коммит здесь не цитирую): работа полигона лежит на ней и в `main` НЕ влита, а `git status -- eval/` в main-дереве пуст ПО ПОСТРОЕНИЮ и уводит в ложный вывод «работы нет»; **«развязка git с origin» ОПРОВЕРГНУТА** — `origin/main` остаётся ПРЕДКОМ `main`, расхождения нет (`git merge-base --is-ancestor origin/main main` → rc 0). ⚠ Пункт «развязка git с origin» в листе владельца ниже держится ТОЛЬКО как вопрос про force-push его рукой; утверждением о расхождении дерева он не является — арбитр этой пары именно здесь. +> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-09-01, голова D39.185 — КУРС: движок и платформа до «работает и отдаёт результат», фронт ЗАМОРОЖЕН и P7 его НЕ размораживает (D39.147). **ОЧЕРЕДЬ №22** (единственный носитель — здесь; роль передана 01.09, №21 закрыт нотой передачи D39.184). ⚠ **ЗАКАЗ ВЛАДЕЛЬЦА 01.09 — ПЕРВЫМ:** (0а) **ревизия документации на ПРОТУХШЕЕ** — по всем зонам, не только тронутым; (0б) **планы доработок в БЭКЕНД и ПЛАТФОРМУ** по остатку бэклога и регистра; (0в) **вынос неактуального в АРХИВ** (`docs/archive/`, `platform/docs/archive/`) — за сутки 31.08 закрыто много, и часть носителей стала историей. ⚠ Трезвость по масштабу (пере-считано 02.09): **88** живых доков в `docs/` против **198** заархивированных, 8 в `platform/docs`, 9 в `backend/docs` — ⚠ из 88 три ВРЕМЕННЫЕ (`DOC_CLEANUP_PLAN` · `DOC_REVISION_FINDINGS` · `DOC_REVISION_REFUTED`), они уедут в архив по закрытии разбора, то есть постоянных **85**; счёт бэклога — бюллетенем ниже, открытых рядов регистра платформы — 97 (major 2) ⚠ (ревизией 02.09 ряды **154** и **157** переведены из «скоро» в «когда-нибудь»: их гейтом стоял первый холодный прогон, он ОТРАБОТАЛ 31.08 и оба предусловия оказались другими — разбор в самих ячейках, ни одна НЕ закрыта). ⚠ Числа доков `counts.py` НЕ сторожит — при переносе файлов пере-считывать руками командой `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`. ⚠ И предупреждение о МЕТОДЕ, купленное сменой №21: «выглядит протухшим» ≠ «протухло». Три факта оркестратора опровергнуты ЗАМЕРОМ сессий, а якоря `15-money-path.md` в девяти случаях из двенадцати РОДИЛИСЬ верными и сгнили дрейфом — то есть ревизия обязана быть исполнением, а не чтением. ⚠ **ОЧЕРЕДЬ, унаследованная от №21** (три лендинга 31.08 — секция «СОСТОЯНИЕ ПАКОВ» ниже): **(1) РАЗРЫВ ЦИКЛА: книга не отдаётся файлом ПОЛЬЗОВАТЕЛЮ — открыта ПЛАТФОРМЕННАЯ половина.** Движок пишет файл с 30.08 (`tmctl build` — EPUB 3 + чистый txt, D39.175), и холодный прогон 31.08 предъявил это живьём: собранный EPUB настоящего перевода прошёл `epubcheck` 0/0/0/0 и передан владельцу. Открыто ровно одно: канон обещает `createExport`/`getExport`, а платформа их НЕ монтирует (смонтировано 15 операций из 20; нет также `getRun`, `updateBook`, `deleteBook`). Долг числится с P8 (`platform/BACKLOG.md` П-17), и НИ ОДИН пак платформы после P7 его не взял (проверка вместо ручного счёта, чтобы не гнило при каждом лендинге: `grep -rn 'createExport\|getExport' platform/internal/ --include=*.go` — пусто). **Слово «отдаёт результат» ложно по букве ТОЛЬКО платформенной половиной** (п.4) · **(2) ~~холодный прогон движка~~ ОТРАБОТАЛ 31.08, закрыт РЕШЕНИЕМ ВЛАДЕЛЬЦА «не доводить»** (отчёт — `archive/reports/COLDRUN_V16_REPORT_2026-08-31.md`, числа относятся к `065d8ac`). Потрачено **$0.436110** из санкции $0.80. ПРЕДЪЯВЛЕНО живьём: объёмный потолок · D39.158 ОБЕИМИ половинами (стоп и не-стоп) · exit 16 · строки 154/198/239/240. ⚠ **Причина большой доли редактора НЕ УСТАНОВЛЕНА** (каузальные истории и их снятие — §4 отчёта). Доля редактора идёт с ДВУМЯ знаменателями: **49.3%** от всего прогона ($0.214865 из $0.436110) и **81.3%** внутри порции П1 (⚠ ходившее «73%» — фантом, в отчёте его нет ни разу). Следующий шаг — контролируемая проба по ЧЕТЫРЁМ осям (роли осей и три требования, купленные ошибками этого прогона, — §14 отчёта; ось `stale` НЕДОСТИЖИМА — §10 там же). ⚠ **Цена: слово владельца 31.08 — ≈$0.60, потолок $0.80, ДЕСЯТЬ глав ПОЛНОЙ цепью включая редакторскую волну.** ⚠ **КЛЮЧИ: гейт снят словом владельца 30.08, разбор двух путей — D39.176 п.6.** Живое отсюда: конвенционного `.env` НЕТ НИ У ОДНОЙ книги корпуса (заполнены только `projects/textmachine/backend/.env` и `.../eval/.env`), поэтому прогон движка обязан передавать `--keys-file` абсолютным путём и только на `translate`; для п.3 нужен ДРУГОЙ файл — `TM_PLATFORM_ENGINE_KEYS_PATH`, тоже АБСОЛЮТНЫМ путём (`platform/internal/config/config.go`, греп `must be an absolute path`). Лечение операционное и $0 — направить переменную на уже заполненный файл; проверять ПРОГОНОМ, не чтением (гардрейл `.env`) · **(3) живой сквозной прогон через API платформы** — форма манифеста, сайдкара банка и карта причин флагов сочинены платформой САМОСТОЯТЕЛЬНО. ⚠ Уточнено 01.09: гейт СНЯТ холодным прогоном, и настоящие артефакты движка теперь ЕСТЬ (каталог `books/gu-zhenren/coldrun-v16/`), но сверка вышла ТОНКОЙ: на шов реально вышло **одно значение `flag_reason` из пятнадцати** (`sanitizer_stripped`), остальные четырнадцать по-прежнему только чтением кода, а манифест против `platform/internal/ingest/manifest.go` не сверялся вовсе · **(4) дверь выдачи** — строго ПОСЛЕ (3) (⚠ слово владельца 30.08: дверь ВСЕГДА строит файл — отказ юзеру не отдаётся, неполная книга уходит с пометкой, т.е. дверь зовёт `tmctl build --partial`; отказ по умолчанию остаётся операторской ручкой CLI; D29.1(б) «fail-closed» читать как «никогда молча» — честность несут пометки) · **(5) проводка `--max-units`** — снятие гейта, а не стройка: механизм в движке стоит (D39.170), живое основание гейта — `PD-422` · **(6) разморозка фронта** — ПОСЛЕ (4): зеркало отстало на СЕМЬ миноров (`frontend/docs/api-contract/openapi.yaml` — `0.2.3` против канона `0.9.0`, и первый из них — ЛОМАЮЩИЙ 0.3.0), 16 операций против 20; отставание ратифицировано D39.142 п.5 на время фриза и две ручки разъехались, размораживать раньше значит перегенерировать типы дважды. ⚠ **ДВА ЗАГЕЙЧЕННЫХ ТРИГГЕРА НАЖАТЫ И НЕ ОТРАБОТАНЫ — строка бэклога 237** (`go.work` · вендор-сверка эффорта `deepseek-v4-pro`; реестр `13-tech-debt-anchors.md` §Б-108). ⚠ **Состояние git — снимать КОМАНДАМИ, не чтением** (ветка `polygon` ушла вперёд, коммит здесь не цитирую): работа полигона лежит на ней и в `main` НЕ влита, а `git status -- eval/` в main-дереве пуст ПО ПОСТРОЕНИЮ и уводит в ложный вывод «работы нет»; **«развязка git с origin» ОПРОВЕРГНУТА** — `origin/main` остаётся ПРЕДКОМ `main`, расхождения нет (`git merge-base --is-ancestor origin/main main` → rc 0). ⚠ Пункт «развязка git с origin» в листе владельца ниже держится ТОЛЬКО как вопрос про force-push его рукой; утверждением о расхождении дерева он не является — арбитр этой пары именно здесь. > - ⚠ **Норма приёмки, купленная аудитом D39.167 п.1:** акт лендинга, объявивший закрытие строки регистра или бэклога, обязан быть СВЕРЕН СТАТУСОМ в тот же заход — иначе следующий пак собирается ПО РЕГИСТРУ и едет чинить построенное. Машинная половина — строка бэклога **225**. > - ⚠ **ЛЕНТА КОНТРАКТНЫХ МИНОРОВ** (что принёс каждый — телом ноты): **0.5.0** — D39.161 · **0.6.0** — D39.162/D39.163 · **0.7.0** — D39.166 · **0.8.0** — D39.169 · **0.9.0** — D39.180. Прожитые дампы приёмок P9/P10 — `archive/PROGRESS-2026-08-backend.md` и тела нот. -> - **Эра №15 закрыта — семь приёмок, все ПРИНЯТЫ и залендены**; лента, коммиты и разборы — D39.109–123 (D-лог) и реестр нот `architecture/05-decisions-index.md`; снимок прежних бюллетеней этой шапки — архив-слайс `-08-02-04`. > - **ЖИВОЕ:** полигон — **фаза Д ИДЁТ** (заказ 10.08; деньги санкционированы 15.08 напрямую полигону — ⚠ числа потолка в носителях расходятся, фактическую цепь сверить при лендинге петель; ja-книга `enkan_no_hate_ja`; при ратификации фазы Д в D-ноту: декой-правило + обязательный кросс-семейный опровергатель приёмки — одобрены 10.08; свежие фриз-коммиты полигона в дереве — НЕ трогать) · платформа и контракт — статус в строке выше, здесь НЕ дублируется (один носитель на факт) · **фронт ЗАМОРОЖЕН** (D39.136 п.2 + **D39.147: морозится ДАЛЬШЕ лендинга P7 — слово владельца 17.08; P7 зону НЕ размораживает, S5-промт не выдаётся, разморозка отдельным словом по достижении сквозного пути**; перечень первого касания зоны — синк зеркала на ТЕКУЩИЙ канон (отставание и его цена — п.6 очереди выше и строка бэклога 183(б)) + перегенерация типов + моки + гейт утечки конвейера + ФС-1..12 + Ф-63/Ф-28 + фразы В-11 по словарю кодов — не отменён, ждёт разморозки) · закрытые стройки эры — реестром нот `architecture/05-decisions-index.md` (D39.130–137, одна строка на ноту). -> - **Открыто на владельце:** **после пака «писатель книги» (D39.175):** лестница D25.1 — какая ступень даёт читателю копию БЕЗ пометки и что печатать на титуле/в имени файла · лейбл главы без заголовка (сейчас цифры; словесный шаблон = одна строка `reader.txt` после ратификации К-3) (⚠ три вопроса пака ЗАКРЫТЫ словом владельца 30.08: экспорт юзеру — всегда строить, см. п.4 очереди · модель пометок подтверждена как построена — надпись о пропуске в файле, отдельный варнинг-слой в интерфейсе НЕ строим, машинный отчёт сборки остаётся внутренним носителем (дрейф) · RTL — снят до появления право-налевой целевой пары) · ⚠ **ПЛАТФОРМЕННЫЙ ЛИСТ ЗАКРЫТ СЛОВОМ ВЛАДЕЛЬЦА 30.08 (D39.176):** квот нет (живём на покупке API, бонусы из админки) · продажа планируется, но не в бете · после пополнения баланса — явное действие пользователя (пункт «авто-резюм paused» СНЯТ) · фразы пользователя (В-3/К-6/Приложение А) ДЕЛЕГИРОВАНЫ проекту с требованием интернациональности: не литерал, а данные по коду причины и локали. ⚠ **Лист ПУСТ:** последний его пункт (`PD-421`, «держит ли открытый поток сессию живой») СНЯТ замером 30.08 — окно бездействия сессии **14 суток**, абсолютный срок **30** (`platform/internal/config/config.go:266`=`SessionIdleTTL`), скольжение окна идёт на любом аутентифицированном запросе, а поток теряется лишь после того, как подметён протухший ряд, то есть после ДВУХ НЕДЕЛЬ без единого действия пользователя. ⚠ Часовой интервал в этой теме — периодичность УБОРКИ, а не срок сессии (эррата 30.08-а к D39.176 п.5) · ⚠ По фразам пользователя подпись владельца НЕ ожидается — проектируют оркестратор + зоны; гейт — строка **204**, `PD-246` закрывается вместе со словарём. ⚠ Прежний указатель «строка 148» мёртв — строку удалил `a023e39` решением владельца, восстанавливать Приложение А по ней НЕ надо · **развязка git с origin** (локальная линия ИСТИННА, force-push его рукой; не пуллить) · В-4/Ф-30 (глава без заголовка — движковая половина строка 160) · мини-проба флора 44 (одобрена, промт не выдан; число — после ре-пробы 188) · подпись денежного шага 46 · **схема time-based DeepSeek** (доклад — архив-слайс `PROGRESS-2026-08-14-15`; рекомендация: пик оставить + операционное правило «прогоны в долины», scheduler не начинать без ответа вендора об отметке тарификации) · **вход ратификации фазы Д:** посылка «dspro дешевле glm» в пике ПЕРЕВЁРНУТА (×1.26 дороже, D39.137 п.4) · **возражение Sol по проходу `tier` эксп-23** (довод дословно — слайс `archive/PROGRESS-2026-08-10-15.md`: Sol судил СВОЁ семейство, что запрещено D13.3; подтвердить или снять — при лендинге петель фазы Д) · фронт-вопросы зонного журнала: В-7 (плотность; держит Ф-54) · В-8 (слово состояния в дереве) · В-9 (языки интерфейса — механизм готов, ПТ-36) · Ф-38 (вкладка «Замечания»). Закрытые пункты листа — в нотах D39.136–145, здесь не держатся. +> - **Открыто на владельце:** **после пака «писатель книги» (D39.175):** лестница D25.1 — какая ступень даёт читателю копию БЕЗ пометки и что печатать на титуле/в имени файла · лейбл главы без заголовка (сейчас цифры; словесный шаблон = одна строка `reader.txt` после ратификации К-3) (⚠ три вопроса пака ЗАКРЫТЫ словом владельца 30.08: экспорт юзеру — всегда строить, см. п.4 очереди · модель пометок подтверждена как построена — надпись о пропуске в файле, отдельный варнинг-слой в интерфейсе НЕ строим, машинный отчёт сборки остаётся внутренним носителем (дрейф) · RTL — снят до появления право-налевой целевой пары) · ⚠ **ПЛАТФОРМЕННЫЙ ЛИСТ ЗАКРЫТ СЛОВОМ ВЛАДЕЛЬЦА 30.08 — четыре ответа и их следствия ЦЕЛИКОМ телом D39.176** (квот нет · продажа не в бете · продолжение после пополнения — руками · фразы пользователя делегированы проекту с требованием интернациональности). ⚠ **Лист ПУСТ:** последний его пункт (`PD-421`, «держит ли открытый поток сессию живой») СНЯТ замером 30.08 — окно бездействия сессии **14 суток**, абсолютный срок **30** (`platform/internal/config/config.go:266`=`SessionIdleTTL`), скольжение окна идёт на любом аутентифицированном запросе, а поток теряется лишь после того, как подметён протухший ряд, то есть после ДВУХ НЕДЕЛЬ без единого действия пользователя. ⚠ Часовой интервал в этой теме — периодичность УБОРКИ, а не срок сессии (эррата 30.08-а к D39.176 п.5) · ⚠ Гейт словаря фраз — строка **204** (D39.176 п.4). ⚠ Прежний указатель «строка 148» мёртв — строку удалил `a023e39` решением владельца, восстанавливать Приложение А по ней НЕ надо · **развязка git с origin** (локальная линия ИСТИННА, force-push его рукой; не пуллить) · В-4/Ф-30 (глава без заголовка — движковая половина строка 160) · мини-проба флора 44 (одобрена, промт не выдан; число — после ре-пробы 188) · подпись денежного шага 46 · **схема time-based DeepSeek** — рекомендация и её доводы строкой **172**(а) · **вход ратификации фазы Д:** посылка «dspro дешевле glm» в пике ПЕРЕВЁРНУТА (×1.26 дороже, D39.137 п.4) · **возражение Sol по проходу `tier` эксп-23** (довод дословно — слайс `archive/PROGRESS-2026-08-10-15.md`: Sol судил СВОЁ семейство, что запрещено D13.3; подтвердить или снять — при лендинге петель фазы Д) · фронт-вопросы зонного журнала: В-7 (плотность; держит Ф-54) · В-8 (слово состояния в дереве) · В-9 (языки интерфейса — механизм готов, ПТ-36) · Ф-38 (вкладка «Замечания»). Закрытые пункты листа — в нотах D39.136–145, здесь не держатся. > - **Сделано (сводно)** — снимок ленты закрытых эр в [archive/PROGRESS-2026-08-04-09.md](archive/PROGRESS-2026-08-04-09.md); детали — D-лог и слайсы. > - **Курс:** этапы ОБЩНОСТЬ · КАЧЕСТВО БАНКА · ПАКЕТ-ЧЕКЕРОВ · ФРОНТ-ЭРА · шов/платформа/движковые блокеры — ПРОЙДЕНЫ (D39.59–123). Хвосты курса живут строками: 16 (полная цена холодного старта; edit-волна на малых прогонах отработала и оплачена — 58 вызовов волновым драйвером 23–25.07 плюс 648 до драйвера, счёт по леджерам `~/books/gu-zhenren/**/*.db`) · 46 (дизайн заморожен D39.92/93, промт ждёт выдачи) · coldrun-b фаза C заморожена чекпойнтом легитимно (D39.86; эталон денег/поведения — coldrun-a, read-only); развилка 0731 решена и исполнена (D39.87/91, код `553f1a3`). > - **Горизонт (D39.62/67, освежён D39.95):** **ДОБОР ИДЕАЛА** (первым прогоном: оси голоса 24 · авто-режим · цена 16; жильцы ролей решаются ДО прогона эксп-22 — строка 149 · веса K1–K12 13а · вне-претрейн чекпоинт 55; остаток арбитража банка = рецензент спорных кластеров при ре-пробе 74 — D39.102) → ВТОРАЯ ПАРА живьём (ja→ru; преп 81) → МАСШТАБ → пилот Ф2.5 (гейт резюме-строки 80; строки 62–68, 85) → Ф3 ридер-IDE (69–71). **Стоячие:** ToS-триггер 25.10 · Ш-2 до go1.27 (⚠ + x/text Unicode 17 тем же тулчейном — строка 119, реестр §Б-108 справочника якорей) · платные прогоны разблокированы (проба провода — D39.97, конфиги 112 залендены). @@ -15,7 +14,7 @@ ## 📌 СОСТОЯНИЕ ПАКОВ -**Залендены и ратифицированы, приёмочные дампы — телами нот:** платформенный **P11** — D39.169 · движковый пак **«деньги»** — D39.170 · платформенный **P12** — D39.180 · бэкенд-пак **«деньги и честность выдачи»** — D39.182 · **закон раскрытия** движка — D39.181. +**Залендены и ратифицированы, приёмочные дампы — телами нот:** платформенный **P11** — D39.169 · движковый пак **«деньги»** — D39.170 · платформенный **P12** — D39.180 (вместе с контрактным минором **0.9.0**; `PD-425` закрыт им же) · бэкенд-пак **«деньги и честность выдачи»** — D39.182 (тестов 1045→1083, удалённых ноль) · **закон раскрытия** движка — D39.181, ратифицирован владельцем и применён к одиннадцати экземплярам. ⛔ **Проводка `--max-units` в платформу остаётся ГЕЙЧЕНОЙ. Живое основание одно и оно механическое:** единственный писатель `bank_moved_at` — дверь правок банка (`platform/internal/runs/bank.go:182`), а рост АВТО-банка от майнинга этого флага не ставит, поэтому майнящая книга на второй покупке идёт без `--resnapshot` и умирает на снапшот-гарде движка — холд взят, попытка сожжена (`PD-422`). Это чинится проводкой признака движения банка от майнинга, а не решением владельца. @@ -54,11 +53,11 @@ | 12 | **`postcheck_gate` в hard-gate** — требует пере-замера recall (recall чекеров измерен и низок); ⚠ «fn=0» демоции #10 класс-вакуумен на labels (ноль одно-Han-позитивов, D39.78) — пере-замер обязан добрать одно-Han-позитивы, на «fn=0» не опираться; одно-Han-класс при gate-on вне гейта (Unverified+Demoted); тем же решением строится HARD-value-детектор 成/万 (Q3 §6 — честный hard-gate требует value-чека; либо раньше при ненулевом потоке value-дефектов добора, D39.79; **$0-прототип получен эксп-21: `battery.check_numbers`, симметричный разбор, синтетика 16/16 — D39.117**) · recall существующих гейтов печатал арм C эксп-21 на контаминированном срезе (D39.108/D39.117) | владелец | когда-нибудь (после фазы 2) | отдельное решение | D39.34(2), D24.4+D28.1, D39.39, D39.78, D39.79 | | 13 | **Включение платной петли ремонта + per-class исходы ремонта** (схемное решение принимается вместе) — вернуться при расширении классов детекторов и ненулевом остатке; ⚠ при включении: репэйр-гард №5 после #10 слеп на одно-Han-дифференциал (демоция в обоих прогонах ⇒ 0>0 — репэйр, стёрший верно отрендеренный одно-Han-термин, не ветируется; D39.78-ревью) | владелец | когда-нибудь | отдельное решение | D39.38, D39.39(а), D39.78, CURRENT-STATE | | 13а | Веса рубрики K1–K12 не выбраны (Q1: «по данным фазы B»; фаза B прошла на BWS без весов — выбор нужен к агрегатной приёмке качества книги) | владелец | когда-нибудь (к пилоту) | Ф2.5 / отдельное решение | D39.44 Q1, D39.46 | -| 13б | **`speech-cue.txt` zh НЕ шипить до замера голос-флаггера; замера НЕТ (D39.86): флаггер живёт на ФИНАЛЬНОЙ волне, редакторская волна не гонялась ⇒ оси не считались НИ РАЗУ.** Гейт: первый прогон добора идеала С редакторской волной (строка 24) → решение владельца о шипе. ⚠ Сам гейт в схеме ЕСТЬ (`internal/config/pipeline.go` `VoiceGate`, пак-19/D39.55). ⚠ `rules=` в отчёте = «гейт СКОНФИГУРИРОВАН», не «отработал» — до фикса 105 читать по знаменателям `replies=`. Археология дословно — `architecture/13-tech-debt-anchors.md` §Б-13б. ⚠ **ПОПРАВКА 23.08 (№19):** блокер — ПУСТОЙ РЕЕСТР профилей, а не выключенный гейт: заполнить `voices:`/`addresses:` может только подпись владельца (`internal/seed/seed.go:23`=`Voices and Addresses are the two D21 record types` — «no miner emits them»), а при пустом реестре `RunVoiceChecks` выходит на `!reg.HasData()` ДО ВСЕХ осей, поэтому нулями отдаются и оси, и знаменатели — «ноль флагов» неотличим от «оси не считались». ⚠ Отдельно: `gates.voice` отсутствует в `backend/configs/`, НО в конфигах реальных прогонов (вне git) он ВКЛЮЧЁН — `~/books/gu-zhenren/coldrun-a/pipeline.yaml:68` и `coldrun-b:71`, `enabled: true`; дыра не «оператор забыл включить», а «шаблоны репозитория гейт не несут» | владелец | отложено-до-замера | первый прогон добора идеала С РЕДАКТОРСКОЙ ВОЛНОЙ (оси голоса, строка 24) → отдельное решение | D39.56, PACK19_BUILD §7.2, чат 31.07, D39.86 | +| 13б | **`speech-cue.txt` zh НЕ шипить до замера голос-флаггера; замера НЕТ (D39.86) — оси не считались НИ РАЗУ.** ⚠ **Причина ПЕРЕ-НАЗВАНА: прежний довод «редакторская волна не гонялась» ПРОТУХ 31.08** (холодный прогон `coldrun-v16` её гонял и оплатил — строка 16); живой блокер — ПУСТОЙ РЕЕСТР профилей, см. ниже. Гейт: первый прогон добора идеала С редакторской волной И подписанными профилями (строка 24) → решение владельца о шипе. ⚠ Сам гейт в схеме ЕСТЬ (`internal/config/pipeline.go` `VoiceGate`, пак-19/D39.55). ⚠ `rules=` в отчёте = «гейт СКОНФИГУРИРОВАН», не «отработал» — до фикса 105 читать по знаменателям `replies=`. Археология дословно — `architecture/13-tech-debt-anchors.md` §Б-13б. ⚠ **ПОПРАВКА 23.08 (№19):** заполнить `voices:`/`addresses:` может только подпись владельца (`internal/seed/seed.go:23`=`Voices and Addresses are the two D21 record types` — «no miner emits them»), а при пустом реестре `RunVoiceChecks` выходит на `!reg.HasData()` ДО ВСЕХ осей, поэтому нулями отдаются и оси, и знаменатели — «ноль флагов» неотличим от «оси не считались». ⚠ Отдельно: `gates.voice` отсутствует в `backend/configs/`, НО в конфигах реальных прогонов (вне git) он ВКЛЮЧЁН — `~/books/gu-zhenren/coldrun-a/pipeline.yaml:68` и `coldrun-b:71`, `enabled: true`; дыра не «оператор забыл включить», а «шаблоны репозитория гейт не несут» | владелец | отложено-до-замера | первый прогон добора идеала С РЕДАКТОРСКОЙ ВОЛНОЙ (оси голоса, строка 24) → отдельное решение | D39.56, PACK19_BUILD §7.2, чат 31.07, D39.86 | | 14 | **Четыре data-инженерных флага фазы-2 общности, каждый с рекомендованным дизайном** (§5 отчёта): ё-фолд → target-данные (`char_fold`; смена сигнатуры core-примитива через вердикт-несущий банк, сдвиг `memory_version`) · segmentation-фолбэк громким (ломает контракт corridor-фолбэка `pipeline.go:839-848` + голден-фикстура на нём; лечение — объявить блок в голден-yaml) · `Fertility` per-script map (калибровка ждёт боевого токенизатора) · `source-encoding.txt` + Go-реестр декодеров | владелец | когда-нибудь (следующий пак общности) | отдельное решение | D39.64, GENERALITY_PHASE2 §5.1–5.4 | | 86 | **Мелкие открытые решения одним списком** (свип D39.66): echo-семантика дропнутого c-lite-члена (D39.18 — оставить pre-c-lite?) · magnitude-кап тяжёлой CJK-утечки (D38.3 п.4в; сейчас strip+flag) | владелец | когда-нибудь | отдельные решения | D39.66, D39.69(feed_cap закрыт §1) | | **— ХВОСТЫ ХОЛОДНОГО ПРОГОНА (исполнен достаточно, D39.58; Р7 владельца) —** | | | | | | -| 16 | Полная цена холодного старта: edit-волна не гонялась НА НЁМ (Р7 — на `coldrun-a`/`coldrun-b` НОЛЬ редакторских вызовов; на малых прогонах гонялась и оплачена); цена холодного старта измерена ДО редактуры (драфт+банкнота $0.0247/волна · терминолог $0.006–0.013/проход). ⚠ **Прогон НЕ НАЧАТ и закрыт владельцем как неуспешный на этом этапе (02.08, D39.90)** — деньги фазы C не тронуты ($0). Свежие числа с пробы `bank-low` (10 глав, `low` на черновике И на бэнк-ролях): черновая волна 20/20 ok. ⚠ **АРИФМЕТИКА СНЯТА 23.08 (№19) ПО БАЗЕ ПРОГОНА `~/books/gu-zhenren/coldrun-b/reprobe/bank-low/guzhenren-bank-low.db`:** вся ДРАФТ-стадия $0.031639 (flash $0.021289 + pro $0.010350) · терминолог $0.005750 · классификатор $0.007706 · **весь заход $0.045095**, слагаемые дают именно его. ⚠ **Довод «редакторская волна не гонялась» ПРОТУХ 31.08** (испр. 02.09): холодный прогон `coldrun-v16` редакторскую волну гонял и оплатил — 4 чекпойнта `edit/editor/deepseek-v4-pro` на $0.214865. **Живой остаток СУЖЕН до одного: цена ДОВЕДЁННОЙ ДО КОНЦА книги не измерена** — прогон отдал 3 юнита из 14 и остановлен снапшот-гардом. Строка держит и оси голоса (13б/24) | бэкенд | когда-нибудь (гейт: первый ЗАВЕРШЁННЫЙ прогон) | добор идеала | D39.58, **D39.90** | +| 16 | **Полная цена холодного старта — ЖИВОЙ ОСТАТОК ОДИН: цена ДОВЕДЁННОЙ ДО КОНЦА книги не измерена.** Холодный прогон `coldrun-v16` 31.08 отдал 3 юнита из 14 и остановлен снапшот-гардом. ⚠ **Довод «редакторская волна не гонялась» ПРОТУХ 31.08** (испр. 02.09): она гонялась и оплачена — 4 чекпойнта `edit/editor/deepseek-v4-pro` на $0.214865; не мерена именно ПОЛНАЯ цепь одним заходом до конца книги. **Числа ДО редактуры — база прогона `~/books/gu-zhenren/coldrun-b/reprobe/bank-low/guzhenren-bank-low.db`** (10 глав, `low` на черновике И на бэнк-ролях; арифметика снята 23.08 №19): вся ДРАФТ-стадия $0.031639 (flash $0.021289 + pro $0.010350) · терминолог $0.005750 · классификатор $0.007706 · **весь заход $0.045095**, слагаемые дают именно его. ⚠ Числа в ИЮЛЬСКИХ деньгах — множитель пере-пина DeepSeek 4.47 (D39.179 п.1), сегодня тот же заход $0.2017. ⚠ Фаза C `coldrun-b` закрыта владельцем как неуспешная (02.08, D39.90), её деньги не тронуты ($0). Строка держит и оси голоса (13б/24) | бэкенд | когда-нибудь (гейт: первый ЗАВЕРШЁННЫЙ прогон) | добор идеала | D39.58, **D39.90** | | 18 | **Эмиссия головы 蛊**: сид-половина = чек-лист (определяющий терм книги сидится `allow_short`, D39.50); эмиссия-КАНАЛ демотирован до ИЗМЕР-ГЕЙТА (Q7): полигон-замер «меняет ли эмиссия головы рендер композитов» — строить ТОЛЬКО по эффекту и ПОСЛЕ #10 (однознаковый пост-чек чинится чекер-паком); перед стройкой резолвить K-гейт и KWIC-грязь одиночной головы | полигон → бэкенд | скоро (санкция Q7 D39.70 — после #10, очередью с ре-пробой) | полигон-замер → решение | D39.58, D39.60, D39.69 | | 24 | **Остаток: авто-режим флага** (проект Б не гонялся) · оси голоса A–D (профили не подписаны; черновик готов — `coldrun-a/SIGN-PACKAGE.md` §3) ; + слот инъекции голоса и решение gates.voice при ненулевых осях (D39.55/D21 п.2) · слой-2 voice не строим до доказательства слоя-1 · сверить until_ch 白凝冰 при курации сида (D19.3в) | бэкенд | когда-нибудь (первый прогон добора идеала) | добор идеала | D39.40, D39.58 | | **— ТЕКУЩАЯ ОЧЕРЕДЬ (D39.59) —** | | | | | | @@ -115,7 +114,7 @@ | 144 | **Вахта: grok `reasoning_tokens` ВНЕ `completion_tokens`** — формула цены харнессов может недосчитывать (до $0.0325 на exp20); вендор-сверка биллинга xAI при следующем прогоне с grok | полигон | когда-нибудь (следующий xAI-прогон) | вендор-чек | D39.108 (приёмка) | | 146 | **Два техдолга движка без строки трекера** (свип 08.08): `prices_checked` (120 д) гейтит read-only `report` и $0-resume — свежесть цен проверять только на ПЛАТНОМ пути (`03-implementation-notes:244`) · `cache_ttl` ↔ `cache_write_per_m`: цена записи в кэш задана под ОДИН TTL (5 м), при другом TTL расчёт врёт (`:246`). Оба жили только в справочнике якорей, то есть вне единственного трекера · **приёмка D39.134:** ценовой гейт держит и ДЕТЕКТОР самолечения деплоя — на стенде с протухшими ценами `status` даёт 10, а не 13, и цикл «поймал 13 → migrate → повтор» не наступает | бэкенд | когда-нибудь | малое касание | свип доков 08.08, D39.134 | | 147 | **Транспортные частичные из research/21 без носителя** (свип 08.08): п.16 HTTP/1.1-escape на последней попытке как ДИАГНОСТИКА тихого усечения 2–8k [PARTIAL, GATED] · п.17 assistant-prefill continuation на `finish=length` вместо ре-рана всего вызова [PARTIAL, DEFER]. Оба помечены в ресёрче как отложенные и ни в одной строке трекера не появились | бэкенд/полигон | когда-нибудь | замер → решение | свип доков 08.08, research/21 §16–17 | -| 149 | **Эксп-22 «панель жильцов»**: профиль-скрин (pass/fail пороги ДО замера; урок эксп-21 — скрин, убивший 2 из 12, скрином не был) → панель черновиков (слот несёт ~70% эффекта финала, мерился ТОЛЬКО flash за всю историю) → панель редакторов поверх замороженных черновиков (обязательный кандидат `gemini-3.1-pro` — аутлаер-гипотеза эксп-04) + шумовой пол + прямой `D_/A` довесками; агент-судейство под капом ≤60; невиданный zh-срез — повторный жёсткий заказ | полигон | **ИСПОЛНЕН и заленден 10.08** (приёмка №16; промт — `archive/prompts/POLYGON_TENANT_PANEL_SESSION_PROMPT_2026-08-08.md`); выводы заморожены до фазы Д — закрыть строку при ратификации | прогон по промту → ратификация | **D39.117**, приёмка №16 | +| 149 | **Эксп-22 «панель жильцов»** — состав панели и её заказ ИСПОЛНЕНЫ; выводы заморожены до фазы Д, строка закрывается при её ратификации | полигон | **ИСПОЛНЕН и заленден 10.08** (приёмка №16; заказ дословно — промт `archive/prompts/POLYGON_TENANT_PANEL_SESSION_PROMPT_2026-08-08.md`, выводы — телом **D39.117**) | ратификация фазы Д | **D39.117**, приёмка №16 | | 150 | **Sol-арбитраж — внешний контур вместо слепого чтения владельца**: пере-суд расходящихся контрастов эксп-21 (`A/F`: luna +0.84 против gemini +3.03 — расхождение 14 sd шума судьи-замены) и слепых пар эксп-22 руками владельца через подписку (третье семейство, high reasoning); пакеты готовит эксп-22 Ф0.4 (слепые метки · оба порядка · декой), транскрипты персистятся как голоса внешнего судьи; luna-клетки Sol не судит (своё семейство) | владелец + полигон | скоро (пакет арбитража — из существующего сырья) | эксп-22 Ф0.4 + руки владельца | **D39.117** | | 151 | **Отказной режим связки**: эхо-мина черновика воспроизводима на материале (глава 11 — 3/3 попыток; частота 31% на zh), связка покрыла 9/10 подряд идущих глав против 10/10 у однопроходки — единственный довод ПРОТИВ связки во всём эксп-21; движку нужен fallback при невозможности годного черновика (вариация ре-гена · эскалация модели черновика · деградация в однопроходку) | владелец → бэкенд | когда-нибудь (до МАСШТАБА) | СТОП-решение | **D39.117**, exp21 §14 | | 152 | **Слипание абзацев — слепое пятно детерминированного контура**: батарея на тех же текстах даёт ДРУГОЙ порядок армов (`D` — худший по судье — лучший по правилам), расхождение локализовано в слипании, которого не проверяет ни одно правило; правило в батарею полигона + кандидат в гейты движка | бэкенд/полигон | когда-нибудь | малое касание + тест | **D39.117**, exp21 §13 | @@ -133,43 +132,43 @@ | 163 | **Версии модулей x/text|x/net двигают нарезку МИМО всех ключей** (NFC в NormalizeSource — таблицы модуля, не тулчейна; epub-токенайзер): бамп `go get -u` тихо меняет нарезку при свежих на вид манифесте/чекпойнтах/снапшоте — класс всей чекпойнт-плоскости, унаследован манифестом; вплести версии модулей (debug.ReadBuildInfo) в NormVersion/chunkerVersion либо явный запрет бампа без `--resnapshot` | бэкенд | когда-нибудь (до второго прогона книги) | малое касание | **D39.122**, приёмка (охотник №1) | | 164 | **Rebill-проекция `status` с nil baseMemory завышает RebillUSD**: read-путь не материализует base-банк → renderedContentHashes даёт пустую инъекцию → repin недоопознан, строка считается re-pay (консервативная сторона, но противоречит комменту «status can never quote a different number than translate»); материализовать base-банк на read-пути либо смягчить клейм | бэкенд | когда-нибудь | малое касание | **D39.122**, приёмка (охотник №1); preexisting | | 166 | **Движковая поверхность оценки $/глава** (ставка-константа платформы $0.03 из exp08 v2 — временная мера беты, П-10 зоны платформы; честная оценка по книге/паре — движковая) | бэкенд | когда-нибудь | отдельный пак | D39.123 | -| 167 | **Докс-пак по аудиту D39.125 — ЯДРО ИСПОЛНЕНО (D39.126):** реестр всех нот `architecture/05-decisions-index.md` · counts.py `--check` полнота реестра + `--lint` якорей · разгрузка топ-10 строк · входы 15-money-path/16-events-emitter/STACK.md · К-статусы сведены · 09-target/product-requirements освежены. **Остаток строки:** статус-баннеры экспов + шапка эндпоинтов quirks (передано полигону промтом фазы Д, §Д8 п.12) (⚠ пункт «DEFECT_REGISTER секциями» СНЯТ 22.08 — исполнено зоной ещё в P5: файл секционирован по весу и по эрам, форма проверена аудитом доков) | доки/полигон/платформа | скоро (остаток — фаза Д полигона) | пинги зонам | D39.125, **D39.126** | +| 167 | **Докс-пак по аудиту D39.125 — ЯДРО ИСПОЛНЕНО, состав — телом D39.126.** **Остаток строки:** статус-баннеры экспов + шапка эндпоинтов quirks (передано полигону промтом фазы Д, §Д8 п.12) (пункт «DEFECT_REGISTER секциями» СНЯТ 22.08 — исполнено зоной ещё в P5) | доки/полигон/платформа | скоро (остаток — фаза Д полигона) | пинги зонам | D39.125, **D39.126** | | 168 | **Состав волн пайплайна = пар-конфиг (данные), не общий хардкод**: вопрос владельца 10.08 «нормально ли под китайский строить весь бэкенд и конфиги?» — жильцы ролей и промпты уже конфиг/langpacks, но ТОПОЛОГИЯ волн (перепис · точечный edit-контур · без второго прохода) одна на всех пар; если фаза Д покажет разных победителей по парам (H-3/H-4: en-черновик+edit против zh-связки), состав волн уезжает в пар-конфиг данными; ревью-вопрос общности §0 `12-go-style-notes.md` | бэкенд | когда-нибудь (после данных фазы Д) | замер (фаза Д) → решение владельца → малое касание | слово владельца 10.08, промт фазы Д | -| 169 | **Экспорт банка для чтения фронтом — ДВИЖКОВАЯ половина ПОСТРОЕНА, строка заводилась слепой к ней (испр. оркестратором 14.08):** сайдкар `.bank.json` — весь банк тремя статусами, стабильные id, атомарная запись — существует с D39.122 (`internal/pipeline/bankexport.go`; ⚠ **прежняя приписка «рядом `bank-stop.json` — полная таблица подписи для S5» СНЯТА 02.09: файла больше НЕТ** — снесён вместе с писателем и четырьмя тестами при постройке входной двери шва (D39.158), в Go-коде движка ни одного вхождения, холодный прогон 31.08 подтвердил на диске). ОСТАТОК: платформенная проекция сайдкаров в `GET /books/{id}/bank` + канал решений подписи — пак читающей поверхности платформы; без неё витрина банка фронта стоит на моке, подписной экран S5 строить не на чем ⚠ **ПЛАТФОРМЕННАЯ ПОЛОВИНА: ЧТЕНИЕ ПОСТРОЕНО P7, ЗАПИСЬ СНЯТА 22.08** (D39.153, затем D39.154). Живо: проекция банка `listBankTerms` с агрегатами. ⚠ Приём решений `submitBankDecisions` **удалён вместе со всей пер-термной моделью подписи** (`PD-370`, ратификация D39.144). Остаток строки стал ШИРЕ, а не уже: нет ни доставки решений до движка, ни самой ручки, куда их вводить; носитель — строка **199(а) [ЗАКРЫТА D39.166]** плюс контрактная **206** | платформа | скоро (остаток = доставка, строка 199а) | строка 199(а) [ЗАКРЫТА D39.166] | Ф-43 фронта, D39.122, **D39.127**, испр. 14.08 | +| 169 | **Экспорт банка для чтения фронтом — ДВИЖКОВАЯ половина ПОСТРОЕНА:** сайдкар `.bank.json` — весь банк тремя статусами, стабильные id, атомарная запись (`internal/pipeline/bankexport.go`, с D39.122). ⚠ **`bank-stop.json` НЕ существует** — снесён вместе с писателем и четырьмя тестами при постройке входной двери шва (D39.158); в Go-коде движка ни одного вхождения, холодный прогон 31.08 подтвердил на диске. ⚠ Не путать с ЖИВЫМ текстовым сайдкаром таблицы стопа `.bank-stop.txt` (`backend/internal/pipeline/mining.go`, греп `bankStopTablePath`) — он на месте и машинной проекцией банка не является. **ПЛАТФОРМЕННАЯ половина: ЧТЕНИЕ ПОСТРОЕНО P7** — проекция банка `listBankTerms` с агрегатами; **ЗАПИСЬ СНЯТА 22.08** — `submitBankDecisions` удалён вместе со всей пер-термной моделью подписи (`PD-370`, ратификация D39.144; D39.153, затем D39.154). **ЖИВОЙ ОСТАТОК стал ШИРЕ, а не уже:** нет ни доставки решений до движка, ни самой ручки, куда их вводить — без неё витрина банка фронта стоит на моке, а подписной экран S5 строить не на чем; носители — строка **199(а) [ЗАКРЫТА D39.166]** плюс контрактная **206** | платформа | скоро (остаток = доставка, строка 199а) | строка 199(а) [ЗАКРЫТА D39.166] | Ф-43 фронта, D39.122, **D39.127**, испр. 14.08 | | 170 | **`tmctl init` — движок сам заводит книгу** (форма В развилки интейка): платформа зовёт $0-команду, движок пишет СВОЙ `book.yaml` — требования к полям живут там же, где проверяются (`config/book.go`); до неё бета живёт формой Б (рендер из деплой-шаблона платформой при создании книги, ратификация D39.130) | бэкенд | когда-нибудь (после беты формы Б) | малый пак | приёмка P5, **D39.130** | | 172 | **Остаток после пере-пина DeepSeek (пин ИСПОЛНЕН и ПРИНЯТ — D39.137, `76049bb`):** (а) **схемное решение владельца по time-based** — доклад §5 отчёта вендор-сессии (рекомендация: пик оставить; scheduler-вариант строки 60 не начинать до ответа вендора «по какой отметке времени тарифицируется вызов» — вендором НЕ задокументировано — и замера доли пика; дешёвый рычаг: операционное правило «прогоны не стартуют в 01–04/06–10 UTC» — почти всё ×2 без строчки Go; гибрид «резерв пиком, сеттл по окну факта» назван) · (б) пере-калибровка ставки $0.03/глава (166/П-10; множитель счёта замерен) · (в) exp08 v3 (85) обязателен до budget_usd · (г) **вахта весов V4-Pro-0813** (класс D39.61): риг готов, порог ратифицированной ВЫБОРОЧНОЙ формы («≥4/5 прогонов N=5 достигают 6/6», D39.136 п.6б) **в риге ИСПОЛНЕН** паком честности — арифметика вынесена в `live_reprobe_threshold_test.go`, сам риг применяет её же. ⚠ **ИМЯ СТРОКИ ВВОДИТ В ЗАБЛУЖДЕНИЕ (испр. №18 17.08, сверено кодом):** названный риг меряет роль КЛАССИФИКАТОРА, а она ходит на **flash** (стендовый `pipeline.yaml:64` + артефакт прошлого прогона `model = deepseek-v4-flash`), тогда как сменившиеся веса — у **pro**, а pro у нас = РЕДАКТОР (`configs/pipeline-c1.yaml:62,76`). Владелец 17.08 санкционировал ТОЛЬКО вариант (а) — пере-съём классификаторного гейта, потолок $0.20, исполняется п.5 пака честности. **По этому прогону строку НЕ закрывать:** вопрос «сменились ли веса редактора» остаётся открытым, дешёвый вход к нему — данные фазы Д, где pro гоняется именно редактором (спросить полигон прежде, чем покупать новый замер) | владелец → бэкенд/полигон | скоро (схема — на владельце; вахта — после 16.08) | СТОП-решение (схема) + замер (вахта) | вендор 13.08, **D39.137**, строка 60, D30.4 | | 180 | **`prices_checked` — одно поле на ВСЮ таблицу цен** (находка вендор-сессии, D39.137): бамп по факт-чеку одного вендора сдвинул 120-дневный гейт свежести остальным семи моделям (дедлайн уехал ~07.11→~13.12); лечение — пер-модельная дата проверки (правка схемы) ЛИБО ре-чек остальных вендоров отдельным заходом до исходного дедлайна | бэкенд | когда-нибудь (ре-чек вендоров — до ~07.11) | малое касание / вендор-заход | D39.137, отчёт §7.1 | | 182 | **Wire-батч перед добором идеала — КОПИТЬ и вносить ОДНИМ касанием** (каждая правка двигает RequestHash / `memory_version` / снапшот = перекупка волн; дриблить по одной = платить пере-снапшот несколько раз): 46 экран цели (+предпосылка 113 фикстура) · 134 инжект-заголовки (гейт пал D39.108) · 131 кап инъекции · 140 банковый контур в shipping (СТОП-решение) · 105(а) вердикт-половина классификатора · 130-остаток (мердж авто-банка, гейт WARN второго прогона) · 14 ё-фолд (носитель «следующий пак общности») · **119+124(+115 пер-парный хеш EmbeddedVersion) — ОДНИМ дизайн-паком** (строка 124 требует принимать целиком; сверено кодом: `cutTag` фолдит `chunkerVersion`/`EmbeddedVersion`/`NormVersion` — `manifest.go:160-169`); вне батча свободен только 118 (tools/go.mod). Состав — аудит корпуса 15.08 (archive/reports/CORPUS_AUDIT_2026-08-15.md §В.г) | оркестратор → бэкенд | скоро (собрать к ратификации фазы Д; вносить перед первым платным прогоном добора идеала) | координационная строка → промт(ы) батча | аудит 15.08, D39.134/136/137 | | 171 | **Число символов книги — от движка** (PD-177 платформы: `character_count` интейка точен только для UTF-8; GB18030/UTF-16 движок декодирует сам — цифра платформы на них неверна, для UTF-16 занижена ~вдвое): счёт символов в манифест (рядом `source_bytes`/`encoding`) либо перерасчёт платформой после разбора | бэкенд | когда-нибудь | малое касание (манифест) | П-13 платформы, PD-177, приёмка P5 | | 173 | **`backupStamp` секундной точности**: два `translate` в одну секунду дают коллизию имени бэкапа и exit 1, маскируя класс «проект занят» (12) — метка до наносекунд/uniquify либо распознавать коллизию явно; преexisting, вскрыт ревью эмиттер-пака | бэкенд | когда-нибудь | малое касание | приёмка D39.131 | -| 175 | **Деплой движка «в полёте» — ДАЛЬНИЙ ОСТАТОК** (ближняя половина — типизированный version-mismatch у `status` + money-тест — ИСПОЛНЕНА паком migrate, принята D39.134; правило свипа «мигрировать только книги БЕЗ открытых попыток» + settle ЗАПИНЕННЫМ бинарём попытки — аддендум P6, D39.132). Остаток: (а) при СЛЕДУЮЩЕМ бампе схемы проставить в файл книги `application_id` + `min_reader_version` — данные-задел под окно совместимости, ~0 логики; (б) GC бинарей: удалять не пиненные ни одной незакрытой попыткой, последние 2–3 релиза держать для отката; (в) окно совместимости читателей / пин уровня книги — строить ТОЛЬКО по триггерам: много тенантов · бампы схемы еженедельно+ · потребители `status` кроме платформы. Археология захода — ресёрч 14.08 (вывод: exact-match читателей на деньгах = осознанный fail-closed, корень не выдёргивать, приделать дверь) | платформа/бэкенд | когда-нибудь (по названным триггерам; (а) — попутно первым бампом схемы) | данные-задел + малые касания | владелец 14.08, ресёрч 14.08, строка 139, D39.134 | +| 175 | **Деплой движка «в полёте» — ДАЛЬНИЙ ОСТАТОК** (ближняя половина ИСПОЛНЕНА паком migrate — D39.134; правило свипа и settle запиненным бинарём — аддендум P6, D39.132). Остаток: (а) при СЛЕДУЮЩЕМ бампе схемы проставить в файл книги `application_id` + `min_reader_version` — данные-задел под окно совместимости, ~0 логики; (б) GC бинарей: удалять не пиненные ни одной незакрытой попыткой, последние 2–3 релиза держать для отката; (в) окно совместимости читателей / пин уровня книги — строить ТОЛЬКО по триггерам: много тенантов · бампы схемы еженедельно+ · потребители `status` кроме платформы. Археология захода — ресёрч 14.08 (вывод: exact-match читателей на деньгах = осознанный fail-closed, корень не выдёргивать, приделать дверь) | платформа/бэкенд | когда-нибудь (по названным триггерам; (а) — попутно первым бампом схемы) | данные-задел + малые касания | владелец 14.08, ресёрч 14.08, строка 139, D39.134 | | 177 | **Гигиена restore point `tmctl migrate`** (находки приёмки ВНЕ карты отчёта; фикс-лист ФМ — запись приёмки 15.08, слайс [archive/PROGRESS-2026-08-14-15.md](archive/PROGRESS-2026-08-14-15.md)): ретрай в ту же секунду после сорванного шага = exit 1 «backup already exists» вне полосы — ровно на цикле самолечения платформы · kill -9 посреди шва оставляет РВАНУЮ копию под легитимным именем (ручной откат по ней = потеря данных; лечение — temp+rename) · копии restore point не подчищаются (повтор после срыва копит их) · SIGINT/SIGTERM в migrate не прерывают (ctx не доезжает) · комментарий migrate.go «no money touched» на no-op неверен (recovery зануляет leftover reserved) | бэкенд | когда-нибудь (следующее касание migrate/бэкапа) | малое касание + тесты | D39.134, приёмка №17 | | 178 | **Калибровка `sense` банка** — слово владельца 15.08 (D39.136 п.4б): смысл должен быть «ёмкий и достаточный на всю книгу, но не слишком подробный» (образец: «спутница главного героя»); сейчас возможно КОРОТКОВАТ; замер длины/достаточности на подписанном банке → правка промптов банкноты/терминолога (двигает провод — цену назвать при внесении) | бэкенд/полигон | когда-нибудь (касание банка) | замер → правка промптов | D39.136 п.4б | | 183 | **Батч 0.3.0 — ОТРАБОТАН ЦЕЛИКОМ** (батч D39.142 + дофикс D39.143, `86720cf`; промт в архиве). ⚠ Номер канона в этой строке НЕ держим — канон ушёл на **0.9.0** (D39.180), лента миноров — в шапке. **ЖИВОЙ ОСТАТОК ОДИН — (б):** зеркало `frontend/docs/api-contract/` + типы + моки + гейт утечки, первое касание фронта при разморозке; расхождение канона и зеркала ВРЕМЕННО ратифицировано D39.142 п.5. Пункты (а) и (в) СНЯТЫ (D39.153; D39.144 п.4)| оркестратор | скоро (остаток = только (б) зеркало фронта при разморозке) | P7 → фронт при разморозке | D39.138, D39.142, **D39.143** | | 184 | **Жанр книги — ВЫКИНУТЬ (слово владельца 16.08). ⚠ ДВЕ ПОЛОВИНЫ ИЗ ЧЕТЫРЁХ УЖЕ ИСПОЛНЕНЫ** (сверено кодом при аудите доков 22.08): поле ушло из контракта и из формы интейка батчем 0.3.0, и платформа жанра больше НЕ ЗНАЕТ — `platform/internal/books/render.go` несёт `genre` шаблона нечитаемым насквозь и говорит об этом прямо. **ЖИВЫМИ остаются две:** (а) движковая — снять `{{genre}}` из промптов пары (⚠ испр. 30.08: он в ШЕСТИ промптах пары, а не в трёх; состав здесь НЕ держим — снимать командой `grep -rln "{{genre}}" backend/prompts/`) + поле из канона брифа: двигает `BriefHash` ⇒ ТОЛЬКО в общее resnapshot-окно, координировать со 161/182, дешёвое окно пока платная книга одна; (б) фронтовая — форма при разморозке; влияние жанр-строки на качество не измерено и уже не будет | бэкенд (+платформа/контракт/фронт) | скоро (движковая половина — resnapshot-окном) | касание в окне 161/182 + батч 183 | research/28 Б-23/§8 п.6, D39.138 п.2в | | 185 | **Дописывание глав в ТЕКУЩУЮ книгу («костылей не будет»):** форма `POST /books/{id}/parts` + ответ «сколько глав добавится, что сдвинется и почём» ДО подтверждения; экономика уже позволяет В КОНЕЦ за ~$0.02 (ключ вызова позиционный, исходник вне снапшота), вставка в середину = МОЛЧАЛИВАЯ перекупка хвоста ~$9–11/500 глав — движковый гейт против молчания ОБЯЗАТЕЛЕН (родня дыры Р6 строки 160); платформа второй файл принять не может (re-parse нет); ja-мина: новый ruby-алиас двигает `memory_version` → снапшот (громкий `--resnapshot`, уточнение приёмки); полный $0-резюм хвоста — предусловие D15.2 (строка 49) | бэкенд+платформа+контракт | когда-нибудь (вместе со строками 160–162 — дизайн в паке 161) | дизайн-пак 161 → стройка | research/28 Б-19а/§8 п.7, D39.138 п.2г | -| 186 | **Сеть: перечитывания ничем не удешевлены** (замер 16.08: дерево 2283 глав = 250 КБ на каждый кадр `status`, фокус-рефетч 12 вкладок = 562 КБ — самый частый трафик порождает переключение вкладок, не пайплайн; гипотетический кадр банка на главу = 372 МБ/прогон; сжатия/ETag/304 нет НИГДЕ): план по эффекту — (1) gzip на текстовых ответах, НЕ на SSE (2) `ETag`/`If-None-Match`→304 на списочных GET (3) скоуп в кадре (id+версия, БЕЗ текста) (4) дельта-чтение банка/замечаний `?after_version=` (5) `staleTime` у клиента; шаги 1–2 — платформа (её же `platform/docs/PLATFORM_DIRECTION.md`, греп `Условные запросы` — ⚠ прежний голый якорь `:202-205` съехал, там сегодня про склейку `note`), семантика — в спеку батчем 183; транспорт НЕ менять (решение владельца по §5б) ⚠ **ШАГИ 1–2 ПОСТРОЕНЫ И ЗАЛЕНДЕНЫ P7 (D39.153)** — gzip на JSON и НЕ на SSE + `ETag`/`If-None-Match`→`304` на коллекциях, карточке книги и `/capabilities` — **и ПЕРЕ-ПРОВЕРЕНЫ ЗАМЕРОМ 28.08** (воркфлоу-ревью P9 на стенде, приёмка D39.162): банк 437 Б холодным → повтор с `If-None-Match` даёт **304 / 0 Б**; юниты главы 3008 Б → **740 Б gzip (×4.1)**; ниже порога 1024 Б gzip честно НЕ применяется; SSE корректно не сжимается. То есть половина строки не просто заленджена, а измеренно РАБОТАЕТ. Остаток — шаги 3–5 | платформа (+контракт/фронт) | скоро (остаток: шаги 3–5) | мидлварь/edge платформы + батч 183 + разморозка фронта | research/28 §5б/Б-11а, D39.138 п.2д | +| 186 | **Сеть: перечитывания ничем не удешевлены** (замер 16.08: дерево 2283 глав = 250 КБ на каждый кадр `status`, фокус-рефетч 12 вкладок = 562 КБ — самый частый трафик порождает переключение вкладок, не пайплайн; гипотетический кадр банка на главу = 372 МБ/прогон; сжатия/ETag/304 нет НИГДЕ): план по эффекту — (1) gzip на текстовых ответах, НЕ на SSE (2) `ETag`/`If-None-Match`→304 на списочных GET (3) скоуп в кадре (id+версия, БЕЗ текста) (4) дельта-чтение банка/замечаний `?after_version=` (5) `staleTime` у клиента; шаги 1–2 — платформа (её же `platform/docs/PLATFORM_DIRECTION.md`, греп `Условные запросы`), семантика — в спеку батчем 183; транспорт НЕ менять (решение владельца по §5б) ⚠ **ШАГИ 1–2 ПОСТРОЕНЫ И ЗАЛЕНДЕНЫ P7 (D39.153)** — gzip на JSON и НЕ на SSE + `ETag`/`If-None-Match`→`304` на коллекциях, карточке книги и `/capabilities` — **и ПЕРЕ-ПРОВЕРЕНЫ ЗАМЕРОМ 28.08** (воркфлоу-ревью P9 на стенде, приёмка D39.162): банк 437 Б холодным → повтор с `If-None-Match` даёт **304 / 0 Б**; юниты главы 3008 Б → **740 Б gzip (×4.1)**; ниже порога 1024 Б gzip честно НЕ применяется; SSE корректно не сжимается. Остаток — шаги 3–5 | платформа (+контракт/фронт) | скоро (остаток: шаги 3–5) | мидлварь/edge платформы + батч 183 + разморозка фронта | research/28 §5б/Б-11а, D39.138 п.2д | | 188 | **Носитель события «ре-проба 74»** (аудит D39.140: событие ждали строки 5 · 36б · 44 и шапка CURRENT-STATE, а владельца у него не было — строка 74 закрыта D39.91): дешёвая ре-проба flash при ПЕРВОМ платном прогоне добора идеала (D39.63 п.4) + слоты, подвешенные на неё: рецензент спорных кластеров банка (остаток 5) · замер второго мнения (36б) · выбор числа флора (44, после одобренной мини-пробы) · итерация №2 редакторов (D39.22/63) · выборочный порог 116 в риге (дописка 172-г) · решение о включении ре-гена перед эскалацией (экс-77, D39.64: «включение — решением при ре-пробе 74»; ручка построена, мертва во всех конфигах, ре-ген ≈7.6× дешевле эскалации) | полигон/бэкенд | скоро (гейт добора идеала — первый платный прогон) | проб-пакет при первом платном прогоне → решения по слотам | D39.63 п.4, D39.91, аудит D39.140 | | 189 | **Мультиязычность фраз ЛОГОВ и АРТЕФАКТОВ движка — вторая половина слова владельца 15.08** (D39.136 п.4а «фразы ВСЕХ зон»; первая половина — юзерский провод — решена ревью 28 Б-1/батчем 183): фразы в `bank-stop`/статусных артефактах и логи движка вне контракта, носителя не было (research/28 §6, строка Ф-61: «носителя назвать отдельно» — аудит D39.140 подтвердил: не назван); разобрать, что из этого читает ПОЛЬЗОВАТЕЛЬ (артефакты банка — да, через проекцию платформы) и что оператор (логи — легитимно английские) | бэкенд | когда-нибудь (до второй локали интерфейса) | разбор → точечная правка | research/28 §6, D39.136 п.4а, аудит D39.140 | | 190 | **Кросс-СЕМЕЙНЫЙ проход контракт-ревью** (не-Claude опровергатели; буква заказа владельца D39.136 п.5 «кросс-модели», исполненная в ревью только кросс-тирами Claude — ограничение честно заявлено research/28 §7/§10): проверка вердиктов доклада моделью другого семейства полигонным контуром; жила только колонкой «ЖИВОЕ» реестра нот — аудит D39.140 дал строку | полигон | когда-нибудь (после фазы Д; перед лендингом батча 183 — если владелец захочет второй рубеж) | полигон-слот с внешним провайдером | research/28 §10, аудит D39.140 | -| 191 | **Подпись банка = ОДИН ОК всему банку (модель владельца 16.08, D39.144)** — пер-термный полный набор решений НЕ гейт нигде: (а) контракт поправлен (409-полноты снят с resume, `pending_decisions` информационный — исполнено D39.144); (б) **движок**: verify_bank-пауза снимается командой resume с решениями «как есть», нерешённое едет авто-строками с пометкой — авто-провод D39.42 п.3 УЖЕ так работает, проверить/ослабить только границу самой паузы; (в) **платформа**: канал решений P7 строится накопительным БЕЗ гейта полноты + проводка «resume = снятие стопа» до движка; (г) пост-ридинговый цикл правок — выселен строкой **192** (носитель думания) ⚠ **ДИСПОЗИЦИЯ ЛЕНДИНГА P7 (D39.153):** (в) проводка «resume = снятие стопа» до движка ИСПОЛНЕНА платформой (флаг `--verify-bank` на resume не передаётся, пин есть); (б) граница паузы движка СВЕРЕНА чтением его кода — зависания нет, движок уходит по авто-ветке при снятом флаге. ⚠ **ОСТАТКА-РАТИФИКАЦИИ НЕТ — снято 22.08 сквозной трассировкой (разбор в 203(з)).** Разбор — строка **203(з)**; эррата к атрибуции — карта шапки D-лога, запись 20.08 ⚠ **ПЕРЕ-ДИСПОЗИЦИЯ 27.08 (D39.158 п.1/п.7): движковая половина УСТРАНЕНА, не обойдена.** Отложенная половина пункта (б) — «ослабить границу самой паузы» — исполнена: стоп срабатывает только на кластере, которого ни один прежний стоп не предъявлял (память `bank_stop_presented`, схема v16), возобновление БЕЗ решений продолжает прогон. Остаток строки — снятие обхода в платформе (её пак), и он ТОЛЬКО после лендинга движка.| бэкенд+платформа | скоро (остаток — движковая половина, 203з; (б) сверка границы паузы движка — внутри P7 чтением кода, правка движка при расхождении = пинг №18) | (б) малое касание движка · (в) внутри P7 | слово владельца 16.08, D39.144, D39.42 п.3 | +| 191 | **Подпись банка = ОДИН ОК всему банку (модель владельца 16.08, D39.144)** — пер-термный полный набор решений НЕ гейт нигде: (а) контракт поправлен (409-полноты снят с resume, `pending_decisions` информационный — исполнено D39.144); (б) **движок**: verify_bank-пауза снимается командой resume с решениями «как есть», нерешённое едет авто-строками с пометкой; (в) **платформа**: канал решений строится накопительным БЕЗ гейта полноты + проводка «resume = снятие стопа» до движка; (г) пост-ридинговый цикл правок — выселен строкой **192** (носитель думания). ⚠ **(в) и (б) ИСПОЛНЕНЫ:** проводку сделала платформа лендингом P7 (D39.153, флаг `--verify-bank` на resume не передаётся, пин есть), а движковую половину **УСТРАНИЛ, а не обошёл, пак входной двери (D39.158 п.1/п.7)** — стоп срабатывает только на кластере, которого ни один прежний стоп не предъявлял (память `bank_stop_presented`, схема v16), возобновление БЕЗ решений продолжает прогон. ⚠ Остатка-РАТИФИКАЦИИ нет — снято 22.08 сквозной трассировкой, разбор строкой **203(з)**. **ЖИВОЙ ОСТАТОК ОДИН:** снять обход в платформе (её пак).| бэкенд+платформа | скоро (остаток — платформенный, разбор 203з) | пак платформы | слово владельца 16.08, D39.144, D39.42 п.3 | | 192 | **Пост-ридинговый цикл правок банка — «наше подумать» владельца 16.08 (записано, чтобы не потерялось; точную механику «не продумал ещё никто и нигде» — его слово).** UX-модель целиком: юзер нажал перевод → черновая волна + майнинг вместе → на фронте появляются ЧЕРНОВОЙ перевод и ЧЕРНОВОЙ банк · подписывается ВЕСЬ банк одним ОК (D39.144) → перевод уходит в доработку · дальше юзер ЧИТАЕТ, и его опции: поправить термин в банке ЛИБО добавить свой → кнопка «поправить» → пере-генерация, которая по ВХОЖДЕНИЯМ правит запрошенное. Открытые вопросы дизайна: что именно перегенерируется (вхождения ключа · затронутые юниты · со сметой и согласием?) · нужен ли движковый ТОЧЕЧНЫЙ РЕДАКТОР (полигон над этим работает — фаза Д) · форма в контракте (ручки нет) и на экране. Уже лежит под ногами: движковый re-edit по ключу банка со сметой и $0-пере-пином ПОСТРОЕН (строка 49: `repin.go`/`rebill.go`, D39.42 п.5/D39.45) · пометка неподписанных строк · дельта-чтение банка (0.3.0). НЕ проектировать до полигонных итогов; затем дизайн-пак на их результатах → слово владельца → стройка | владелец+полигон → бэкенд/контракт/фронт | когда-нибудь (триггер: итоги фазы Д по точечному редактору) | дизайн-пак после полигона → слово владельца → стройка | слово владельца 16.08, D39.144 п.1 | | 195 | **ОСЬ «идентичность оплаченной работы» — переселена в дизайн-пак 124 (решение владельца 17.08, вариант А; D39.151).** Как САМОСТОЯТЕЛЬНАЯ стройка ЗАКРЫТА: маркер `snapshot_id`/`run_id` на `checkpoints` отдельной колонкой НЕ строится. Причина — внешний разбор опроверг посылку «колонка = тождество»: $0-пере-пин законно переносит строку на новый снапшот со СТАРОЙ ценой (`stagerun.go:96-105`, сверено оркестратором), у старых чекпоинтов бэкфилла нет вовсе (`jobs.snapshot_id` перезаписывается каждым ре-снапшотом) ⇒ вывод-обход остаётся в коде навсегда как legacy-ветка, а колонка лишь добавляет рядом второй путь. **Настоящий корень глубже:** в сторе нет первоклассной связи «строка диспозиции ↔ вызовы, которые её оплатили»; снапшот на чекпоинте — прокси, а не примитив. ⚠ Границы семьи сужены тем же разбором: 49 и 195 — про РАЗНОЕ (49 = когда переиспользование законно, 195 = как честно посчитать будущую покупку), общий у них субстрат, не задача; из 124 родня только ось (в). **Срочности нет:** под контрактом D39.150 («направление ошибки, не точность») ни один исход не занижает молча — недостача несётся историческими деньгами С РАСКРЫТИЕМ, пойманный откат называется вслух. Остаточные нарушения контракта чинятся БЕЗ схемы: 197 и 194 | бэкенд | когда-нибудь (гейт — триггеры пака 124: дописывание глав 185 · МАСШТАБ · первый внешний потребитель числа) | ось дизайн-пака 124 | **D39.151**, внешний разбор 17.08 | | 196 | **Остаточный класс строки 176: неперехватываемые `fatal error` Go** (конкурентная запись в map, OOM, стек-оверфлоу) по-прежнему дают exit 2, то есть читаются платформой как «завершено с флагами» — `recover` их не ловит по устройству языка (подтверждено линзой шва исполнением). Строка 176 закрыта для ПАНИК, не для fatal. Лечение — вне exit-контракта: сторож процесса у платформы либо маркер живости в артефакте прогона | бэкенд/платформа | когда-нибудь | отдельное решение | приёмка №18, линза шва | -| 197 | **Фикс-лист приёмки пака честности ФЧ-1…ФЧ-8** (D39.149; тело — [archive/PROGRESS-2026-08-17.md](archive/PROGRESS-2026-08-17.md), запись приёмки №18): три НЕПРИБИТЫЕ гарантии (снятие фильтра по книге в `CheckpointUsageForBook` не валит ни один тест — воспроизведено оркестратором · ключ ячейки без `chunk_idx` съедает деньги соседнего чанка · ветка «строка не пере-оценена» не ловится на продовом пути) · два докстринга `reprice.go` описывают НЕ то, что делает код · 187 исполнен наполовину (тот же снятый закон в докстринге теста и `backend/docs/D15.2-*.md:317`) · `HistoricalRows` не доезжает до `status`/`--json`, второй операторский текст (`--accept-rebill`) без basis · **ФЧ-5 РЕШЁН владельцем 17.08 (D39.150): прайсить по модели, которую стадия резолвит СЕЙЧАС, + округление вверх и оговорка в тексте согласия** · `Status()` жёстко падает при ошибке репрайсера против соседней политики деградации · паника поверх ceiling-стопа даёт `failed` вместо `paused` (PD-113) · три стейл-докстринга. Носителя-сессии НЕТ — по слову владельца 17.08 пока только записано | бэкенд | скоро (следующее касание денежного пути; ФЧ-5 обязателен до первого пере-прогона со сменой модели) | дофикс-промт ЛИБО попутно ближайшим паком | **D39.149**, **D39.150** | +| 197 | **Фикс-лист приёмки пака честности ФЧ-1…ФЧ-8** — восемь пунктов класса «заявленное не прибито» и «текст обещает больше числа», ни один не блокировал лендинг. **Тело списка дословно, с весами и с секцией «что НЕ проверено», — [archive/PROGRESS-2026-08-17.md](archive/PROGRESS-2026-08-17.md), запись приёмки №18** (D39.149). Здесь держим только ратифицированное: **ФЧ-5 РЕШЁН владельцем 17.08 (D39.150): прайсить по модели, которую стадия резолвит СЕЙЧАС, + округление вверх и оговорка в тексте согласия.** Носителя-сессии НЕТ — по слову владельца 17.08 пока только записано | бэкенд | скоро (следующее касание денежного пути; ФЧ-5 обязателен до первого пере-прогона со сменой модели) | дофикс-промт ЛИБО попутно ближайшим паком | **D39.149**, **D39.150** | | 198 | **Апгрейд движка стирает замечания и счётчики книги БЕЗВОЗВРАТНО — композиция двух половин, каждая известна по отдельности** (приёмка P7, линза «вне карты», обе половины пере-прочитаны оркестратором). Платформа при смене `manifest_key` сносит ВСЕ `unit_resolutions` книги (`platform/internal/pgstore/readmodel.go:164-165`), рассчитывая, что поток их пере-наполнит; движок анонсирует юнит РОВНО ОДИН РАЗ за жизнь книги — ключ `unit::::` БЕЗ метки нарезки (`backend/internal/pipeline/events.go:399-400`), а леджер анонсов переживает прогоны (`backend/internal/store/outbox.go:96` «already announced… by one that ran before it») ⇒ совпавшие координаты не переанонсируются НИКОГДА. Обостряется порядком: долг на материализацию ставится только на ГРАНИЦАХ работы, поэтому первая зачистка после апгрейда случается в КОНЦЕ первого пост-апгрейдного прогона и сносит замечания ТОГО ЖЕ прогона, за который заплачено. Следствия на проводе: «0 из N» на переведённой книге навсегда · шкала снова предлагает купить переведённое · замечания читателя исчезают. **Лечится с обеих сторон:** движковая половина — метка нарезки в ключе анонса (решение зоны движка), платформенная — не сносить вслепую либо восстанавливать из экспорта. ⚠ Гейт холодного прогона: смысл упражнения — гонять книгу против МЕНЯЮЩЕГОСЯ движка, то есть первый же апгрейд обнулит библиотеку | бэкенд + платформа | **скоро (до первого реального пользователя И до холодного прогона с апгрейдами)** | связка: решение по ключу анонса в движке → правка платформы | приёмка P7 (D39.153) | | 201 | **Движковое «Глава N» доезжает читателю ВНУТРИ текста, обходя дисциплину `heading: null`** (линза шва P7, пере-прочитано оркестратором): `backend/internal/pipeline/export.go:58`=`ApplyHeading` (испр. оркестратором №20 30.08: якорь уезжал с `:230` и с `:266` — код растёт) приклеивает детерминированный порядковый к экспортному тексту первой юнит-главы (`ce.FinalText = chunk.ApplyHeading(...)`), колонка `Source` при этом остаётся heading-stripped. Платформа переносит обе как есть и честно отдаёт `heading: null` — то есть клиент нарисует СВОЙ порядковый на языке своего интерфейса над абзацем, который уже начинается с русского «Глава N», а исходная колонка соответствующего маркера не несёт: пара визуально рассинхронизирована на каждой первой главе. Конкретное следствие открытого К-2 контракта; родня движковой строки **160** (глава без заголовка) | бэкенд | когда-нибудь (с 160) | отдельное решение | приёмка P7 (D39.153) | | 202 | **Живой перевод книги НАСКВОЗЬ через API платформы не гонялся НИ РАЗУ** (obstacle сессии P7, подтверждён приёмкой): всё после «прогон стартовал и остановился» — подпись банка, halt на потолке, резюм после пополнения — покрыто батареей против живого Postgres, но с движком-заглушкой; настоящий манифест, сайдкар банка и причины флагов будут ПЕРВЫМИ данными, форму которых платформа не сочинила сама. Форма проверки (решена): только через API, как ходил бы клиент — интейк → старт → живой движок с ключами провайдера → поток событий → подпись и продолжение → чтение глав/юнитов/замечаний/банка и сверка с тем, что движок реально произвёл; качество перевода НЕ предмет (полигон). ⚠ **Цена ≈$0.05 СНЯТА как протухшая** (D39.179 п.1: пере-пин DeepSeek, множитель ×4.47; испр. 02.09). Замер 31.08 на ровно такой десятиглавой книге: **куплено $0.436110** при собственной проекции движка **`projected_book_usd = 1.1377277707`** и полном оттоке кассы **≈$1.44** (§4 отчёта). ⚠ Это цена НЕПОЛНОГО захода — доставлено 3 юнита из 14; как смету для покупателя брать нельзя. ⚠ Путь ключей платформы — переменная `TM_PLATFORM_ENGINE_KEYS_PATH`, требует АБСОЛЮТНОГО пути (греп по `platform/internal/config/`). **Решение владельца 20.08: ПОСЛЕ холодного прогона движка** — гонять одну неготовую систему против другой смысла нет | платформа | скоро (⚠ прежний гейт «холодный прогон движка» ПАЛ 31.08; живой блокер теперь один — файл ключей платформы `TM_PLATFORM_ENGINE_KEYS_PATH`, лечение операционное и $0) | короткая сессия по промту оркестратора | слово владельца 20.08, D39.153 | -| 203 | **Хвосты контракта после синка 0.4.0 — ОТКРЫТ ОДИН ПУНКТ, остальное исполнено** (тела релеев — `platform/docs/archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md` §7; сюда переписан НЕ текст, а статус — один носитель на факт). **ИСПОЛНЕНЫ, сверено грепом при лендинге:** (а) минором 0.5.0 (D39.161) — канон предупреждает, что конверт вне `/v0` может прийти БЕЗ обязательного `code` · (б) срезанная фраза компаньона §2.14 на месте (`14-api-contract/README.md:509`=`различать причины отказа клиент не может по замыслу`) · (д) клетка приложения А заполнена `unspecified` (`README.md:1376`) · (и) поле `stop_requested` (D39.152) · (л)(м)(н)(о) — контрактной сессией (остаток по фразам Приложения А несёт строка **204** и лист владельца) · **(г) наполовину** — `unspecified` ратифицирован в каноне (`docs/architecture/14-api-contract/openapi.yaml:1903`=`is reserved and is the server`; адрес пере-нацелен 02.09 — минор 0.9.0 сдвинул прежний 1784-1787), открыта только ГРАНИЦА ступеней замечаний (две ступени при девяти рангах движка); ⚠ её прежний носитель — строка 148 — СНЯТ 21.08 по слову владельца · **(з) СНЯТ как ратификация 22.08 сквозной трассировкой (разбор, на который ссылается строка 191):** конфликта моделей НЕТ — гейт движка проверяет полноту не ПОДПИСЕЙ, а ФАЙЛА решений, и ОДИН файл со всем банком его снимает (`loadMinedDelta` штампует только `Source`, `mining.go:855-867` → опущенный статус дефолтится в `approved`, `membank/memseed.go:96`=`status = "approved"` → `unsignedEngineSurfaces` выбрасывает лишь `Source=="mined" && Status!="approved"`, `mining.go:710-719`). Пере-диспозиция 27.08 (D39.158 п.7): движковый гейт полноты УСТРАНЁН, не обойдён; остаётся снять обход в платформе — одна боевая строка (`platform/internal/runs/spawn.go`, `--verify-bank` не передаётся на resume) плюс семь строк ставшего ложным обоснования, работа платформенного пака. **ОТКРЫТО РЕАЛЬНО — (к):** ключ `project_db` в `book.yaml`, договорить, кто им владеет: шаблон оператора его не содержит, движок делает необязательным. ⚠ Следствие «на штатном деплое банк не читается» ОПРОВЕРГНУТО живым кодом: путь публикует ДВИЖОК конвертом артефактов, пустой путь — ГРОМКИЙ отказ (`platform/internal/runner/artifacts.go:39`=`the engine published no bank read-out path`); остаток (к) чисто договорной| контракт/доки | скоро (следующее касание контракта) | контрактная сессия | приёмка P7 (D39.153) | -| 204 | **Движок не публикует причины флагов ДАННЫМИ — карта причин у платформы рукописная и расходится молча** (релей §7(в) хендоффа P7; зона платформы в чужой бэклог не пишет и просила строку сюда — `platform/docs/archive/platform-PROGRESS-P7.md:206`). Сегодня `platform/internal/ingest/notes.go` держит рукописную копию закрытого словаря ЧУЖОЙ зоны: 15 причин движка → коды замечаний контракта, сверено побайтно на 20.08 и верно СЕЙЧАС. Импортировать движок платформе нельзя (D39.85 — разные модули), поэтому расхождение появится молча в тот день, когда движок добавит причину: платформа отдаст `unspecified` и напишет ERROR в лог, то есть деградация честная, но карта протухнет незаметно. ⚠ **Правила заполнения контрактных фраз по этим причинам УЖЕ НАПИСАНЫ** и выводить их заново не надо — компаньон `14-api-contract/README.md`, греп `по ДОККОММЕНТУ` (фраза пишется по доккомменту `disposition.go`, а не по имени константы; класс 2 схлопывается в ОДИН код). Лечение: движок публикует свой словарь причин артефактом-данными (тем же классом, что манифест и сайдкары банка), платформа читает его вместо копии. ⚠ Носителем был ТОЛЬКО регистр платформы (PD-246) — то есть обязательство к зоне движка жило внутри зоны автора; поймано ревьюером полноты выгрузки при лендинге | бэкенд | когда-нибудь (со следующим касанием эмиссии флагов) | отдельное решение | приёмка P7 (D39.153), релей §7(в) | -| 205 | **Гейт якорей: ИСПОЛНЕН 21.08 — сверка по СОДЕРЖИМОМУ, двусторонняя дельта, объявленная слепота** (`docs/scripts/counts.py --lint`; область — `docs/` + `platform/docs` + `frontend/docs`; из хука убран быстрый выход по «коммит не трогает docs/»: цели у нас в основном КОД, то есть главный двигатель протухания приезжал ровно тем коммитом, на котором хук молчал). Форма якоря: ОПТ-ИН токен ожидания `` `путь:12-14`=`подстрока` ``, сверка ПРОБЕЛЬНО-нормализованная. ⚠ **Слепота печатается САМИМ гейтом каждый прогон — читать оттуда, копии здесь нет.** Одна её грань в вывод не попала: в ручном прогоне «дельта» = всё незакоммиченное кем угодно, поэтому ТРЕБОВАНИЕ токена живёт только под `--from-index` (ПРОВЕРКА уже написанных токенов дельтой не ограничивается вовсе — токен был истинным при записи, значит упавший есть гниль по построению). **ОСТАТОК:** миграция корпуса на токен-форму органическая — токен требуется на ЗАТРОНУТЫХ строках, счёт растёт сам с каждым касанием. ⚠ Числа здесь НЕ держим (прежняя редакция держала «4 из ~580» и протухла за сутки): текущий счёт токенов, якорей и доков гейт печатает КАЖДЫЙ прогон| оркестратор/доки | сделано 21.08, миграция органическая | исполнено; остаток гасится касаниями | аудит работы №18 + разбор с внешним ревьюером, 21.08 | +| 203 | **Хвосты контракта после синка 0.4.0 — ОТКРЫТ ОДИН ПУНКТ, остальное исполнено** (тела релеев — `platform/docs/archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md` §7; сюда переписан НЕ текст, а статус — один носитель на факт). **ИСПОЛНЕНЫ и сверены грепом при лендинге:** (а) минором 0.5.0 (D39.161) · (б) · (д) · (и) поле `stop_requested` (D39.152) · (л)(м)(н)(о) контрактной сессией — остаток по фразам Приложения А несёт строка **204** и лист владельца. **(г) наполовину** — `unspecified` ратифицирован в каноне (`docs/architecture/14-api-contract/openapi.yaml:1903`=`is reserved and is the server`), открыта только ГРАНИЦА ступеней замечаний (две ступени при девяти рангах движка); ⚠ её прежний носитель — строка 148 — СНЯТ 21.08 по слову владельца. **(з) СНЯТ как ратификация 22.08 сквозной трассировкой (разбор, на который ссылается строка 191):** конфликта моделей НЕТ — гейт движка проверяет полноту не ПОДПИСЕЙ, а ФАЙЛА решений, и ОДИН файл со всем банком его снимает (`loadMinedDelta` штампует только `Source`, `mining.go:855-867` → опущенный статус дефолтится в `approved`, `membank/memseed.go:96`=`status = "approved"` → `unsignedEngineSurfaces` выбрасывает лишь `Source=="mined" && Status!="approved"`, `mining.go:710-719`). Пере-диспозиция 27.08 (D39.158 п.7): движковый гейт полноты УСТРАНЁН, не обойдён; остаётся снять обход в платформе — одна боевая строка (`platform/internal/runs/spawn.go`, `--verify-bank` не передаётся на resume) плюс семь строк ставшего ложным обоснования, работа платформенного пака. **ОТКРЫТО РЕАЛЬНО — (к):** ключ `project_db` в `book.yaml`, договорить, кто им владеет: шаблон оператора его не содержит, движок делает необязательным. ⚠ Следствие «на штатном деплое банк не читается» ОПРОВЕРГНУТО живым кодом: путь публикует ДВИЖОК конвертом артефактов, пустой путь — ГРОМКИЙ отказ (`platform/internal/runner/artifacts.go:39`=`the engine published no bank read-out path`); остаток (к) чисто договорной| контракт/доки | скоро (следующее касание контракта) | контрактная сессия | приёмка P7 (D39.153) | +| 204 | **Движок не публикует причины флагов ДАННЫМИ — карта причин у платформы рукописная и расходится молча** (релей §7(в) хендоффа P7; зона платформы в чужой бэклог не пишет и просила строку сюда — `platform/docs/archive/platform-PROGRESS-P7.md:206`). Сегодня `platform/internal/ingest/notes.go` держит рукописную копию закрытого словаря ЧУЖОЙ зоны: 15 причин движка → коды замечаний контракта, сверено побайтно на 20.08 и верно СЕЙЧАС. Импортировать движок платформе нельзя (D39.85 — разные модули), поэтому расхождение появится молча в тот день, когда движок добавит причину: платформа отдаст `unspecified` и напишет ERROR в лог, то есть деградация честная, но карта протухнет незаметно. ⚠ **Правила заполнения контрактных фраз по этим причинам УЖЕ НАПИСАНЫ** и выводить их заново не надо — компаньон `14-api-contract/README.md`, греп `по ДОККОММЕНТУ` (фраза пишется по доккомменту `disposition.go`, а не по имени константы; класс 2 схлопывается в ОДИН код). Лечение: движок публикует свой словарь причин артефактом-данными (тем же классом, что манифест и сайдкары банка), платформа читает его вместо копии. ⚠ Класс: носителем был ТОЛЬКО регистр платформы (PD-246) — обязательство к ЧУЖОЙ зоне жило внутри зоны автора | бэкенд | когда-нибудь (со следующим касанием эмиссии флагов) | отдельное решение | приёмка P7 (D39.153), релей §7(в) | +| 205 | **Гейт якорей ИСПОЛНЕН 21.08** — `docs/scripts/counts.py --lint`, область `docs/` + `platform/docs` + `frontend/docs`, сверка по СОДЕРЖИМОМУ, двусторонняя дельта. ⚠ Быстрый выход по «коммит не трогает docs/» из хука убран НАМЕРЕННО: цели якорей — в основном КОД, и главный двигатель протухания приезжал ровно тем коммитом, на котором хук молчал. Форма якоря: ОПТ-ИН токен ожидания `` `путь:12-14`=`подстрока` ``, сверка ПРОБЕЛЬНО-нормализованная. ⚠ **Слепота печатается САМИМ гейтом каждый прогон — читать оттуда, копии здесь нет.** Одна её грань в вывод не попала: в ручном прогоне «дельта» = всё незакоммиченное кем угодно, поэтому ТРЕБОВАНИЕ токена живёт только под `--from-index` (ПРОВЕРКА уже написанных токенов дельтой не ограничивается вовсе — токен был истинным при записи, значит упавший есть гниль по построению). **ОСТАТОК:** миграция корпуса на токен-форму органическая — токен требуется на ЗАТРОНУТЫХ строках, счёт растёт сам с каждым касанием. ⚠ Числа здесь НЕ держим (прежняя редакция держала «4 из ~580» и протухла за сутки): текущий счёт токенов, якорей и доков гейт печатает КАЖДЫЙ прогон| оркестратор/доки | сделано 21.08, миграция органическая | исполнено; остаток гасится касаниями | аудит работы №18 + разбор с внешним ревьюером, 21.08 | | 207 | **Пол самосогласованности манифеста стоит только у материализатора, интейк тот же документ ПРИНИМАЕТ — и по такой книге можно ОПЛАТИТЬ прогон** (`PD-367`, вторая волна ревью P8-FIX). Манифест `{ChaptersTotal: 120, UnitsTotal: 400}` с пустым списком глав `Whole()` отвергает, а `books.Parse` заводит книгу `not_started` с `chapter_count=120` и пустым деревом; потолок считается ОТ `chapter_count`. **Очевидное лекарство опровергнуто исполнением самой зоной:** применить `Whole()` на интейке нельзя — вся батарея интейка ездит на манифестах без списка глав, контракт интейка это только счётчики. Значит решение не зонное: либо контракт интейка меняется, либо пол ставится в другом месте цепи | оркестратор → платформа | скоро | нужно решение (лекарство ломает запиненный контракт интейка) | D39.154 п.10, `PD-367` | | 209 | **Риг живых проб не может залогировать тела запросов ни при каких env** (находка бэкенд-пака честности 17.08, оставшаяся без носителя до аудита доков 22.08): `LOG_LLM_BODIES=1`+`LOG_LEVEL=debug` объявлены носителем тел, но ключ читается из `obs.ReqInfo` контекста, а `live_reprobe_test.go` строит ctx БЕЗ `WithReqInfo` — гейт `obs/logging.go` не пропускает. Обход, которым пользовались: ручной дамп сообщений в файл. Цена — каждая живая проба, которой нужно прочитать провод глазами, платит за обход заново | бэкенд | когда-нибудь (следующее касание рига живых проб) | малое касание (`WithReqInfo` в риге) + пин | пак честности 17.08, вынесено аудитом доков 22.08 | -| 210 | **Род НЕ ПРОИЗВОДИТСЯ авто-путём вовсе — механизм доставки построен, а данных для него нет** (найдено трассировкой цепи банка 22.08, сверено кодом оркестратором; полигон вскрыл то же независимо: «в банке НЕТ ПОЛЕЙ ПОЛА»). Доставка рода на провод ПОСТРОЕНА и работает: `membank/memory.go` кладёт `genderConstraintNote` в черновую инъекцию — но ТОЛЬКО для строк со статусом `Confirmed`, по прямой директиве владельца D39.21 «род должен доезжать». Данных ей никто не даёт: промпт терминолога возвращает РОВНО ТРИ поля (`backend/prompts/zh-ru/terminologist.md`: термин · перевод · уверенность 0–100) — поля рода в ответе НЕТ; майнер берёт `gender` исключительно из СИДА (`internal/miner/miner_emit.go` `seedMeta`, `meta.gender = e.Gender`), эмитируемые кандидаты его не несут. ⇒ **на любой книге без ручного сида ось рода мертва по построению**, и «плывущий род» — это не дефект рендера, а отсутствие входных данных. Прямо бьёт по цели №1: реестр памяти C3 называет русский глагол прош. вр. при скрытом роде «механическим спойлер-каналом» и «жалобой №1 читателей MTL» (строка 82). **Развилка, которую надо назвать до стройки:** добавлять ли поле рода в ответ терминолога (двигает провод ⇒ ТОЛЬКО в вайр-батч 182) ЛИБО выводить род отдельным дешёвым проходом, ЛИБО признать род сид-только свойством и гейтить им качество явно. Родня 82 (морфо-гейт рода) и 178 (калибровка `sense`). ⚠ **ДОПОЛНЕНО 23.08 (№19):** замка ДВА и они независимы — род рендерится только при `Disp == Confirmed` (`membank/memory.go:705-713,823-827`=`Mirrors the editor block's confirmed-only gender`), а `mining.go:676` запрещает авто-банку статус `approved`. Род НЕ единственное осиротевшее поле: `Sense`/`Speech`/`Decl` тоже приходят только из сида, авто-продюсер есть лишь у `Dst` (терминолог) и `Type` (классификатор). ⚠ Поле `Gender` в схеме сида УЖЕ ЕСТЬ (`internal/seed/seed.go:71`=`Gender string`) — ось мертва в ПИСАТЕЛЯХ, не в формате. ⚠ **И тесты слепы ПО ПОСТРОЕНИЮ** (пере-проверено 23.08): все gender-кейсы конструируют род РУКАМИ, то есть зелёная батарея не отличает «производитель работает» от «производителя нет»; гейта на дрейф рода в движке нет | бэкенд (+полигон на замер) | **скоро (цель №1; правка провода — вайр-батчем 182)** | развилка → решение → правка промпта/прохода + замер на прогоне с редактурой | трассировка цепи банка 22.08, D39.21, C3 реестра памяти | -| 213 | **ОСТАТОК — одна строка в ДЕВ-пути: супервизор зашивает `"book.yaml"` мимо константы `ConfigFile`** (`platform/internal/ingest/supervisor.go:142`=`"status", "--config"`). ⚠ **ГЛАВНАЯ половина ЗАКРЫТА лендингом P9 (D39.162):** платформа больше не парсит `book.yaml` нестрогим декодером и не вычисляет `.bank.json` по чужой конвенции — путь берётся из конверта артефактов, который публикует движок (`platform/internal/runner/artifacts.go:28-35`; пустой путь — ГРОМКИЙ отказ, а не тихий недо-чит), и собственный `projectDB()` снесён вместе с суффиксом. Осталась ровно та тривиальность, которую строка называла рядом с дефектом. ⚠ Пере-именование банк-экспорта в фикс-имя рядом с `events.jsonl` — ЛОМАЮЩЕЕ, его место в окне строки **161**, НЕ здесь | платформа | когда-нибудь (одна строка, следующим касанием зоны) | правка дев-супервизора | консилиум шва 22.08; главная половина — D39.162 | +| 210 | **Род НЕ ПРОИЗВОДИТСЯ авто-путём вовсе — механизм доставки построен, а данных для него нет** (найдено трассировкой цепи банка 22.08, сверено кодом оркестратором; полигон вскрыл то же независимо: «в банке НЕТ ПОЛЕЙ ПОЛА»). Доставка рода на провод ПОСТРОЕНА и работает: `membank/memory.go` кладёт `genderConstraintNote` в черновую инъекцию — но ТОЛЬКО для строк со статусом `Confirmed`, по прямой директиве владельца D39.21 «род должен доезжать». Данных ей никто не даёт: промпт терминолога возвращает РОВНО ТРИ поля (`backend/prompts/zh-ru/terminologist.md`: термин · перевод · уверенность 0–100) — поля рода в ответе НЕТ; майнер берёт `gender` исключительно из СИДА (`internal/miner/miner_emit.go` `seedMeta`, `meta.gender = e.Gender`), эмитируемые кандидаты его не несут. ⇒ **на любой книге без ручного сида ось рода мертва по построению**, и «плывущий род» — это не дефект рендера, а отсутствие входных данных. Прямо бьёт по цели №1: реестр памяти C3 называет русский глагол прош. вр. при скрытом роде «механическим спойлер-каналом» и «жалобой №1 читателей MTL» (строка 82). **Развилка, которую надо назвать до стройки:** добавлять ли поле рода в ответ терминолога (двигает провод ⇒ ТОЛЬКО в вайр-батч 182) ЛИБО выводить род отдельным дешёвым проходом, ЛИБО признать род сид-только свойством и гейтить им качество явно. Родня 82 (морфо-гейт рода) и 178 (калибровка `sense`). ⚠ Замка ДВА и они независимы — род рендерится только при `Disp == Confirmed` (`membank/memory.go:705-713,823-827`=`Mirrors the editor block's confirmed-only gender`), а `mining.go:676` запрещает авто-банку статус `approved`. Род НЕ единственное осиротевшее поле: `Sense`/`Speech`/`Decl` тоже приходят только из сида, авто-продюсер есть лишь у `Dst` (терминолог) и `Type` (классификатор). ⚠ Поле `Gender` в схеме сида УЖЕ ЕСТЬ (`internal/seed/seed.go:71`=`Gender string`) — ось мертва в ПИСАТЕЛЯХ, не в формате. ⚠ **И тесты слепы ПО ПОСТРОЕНИЮ** (пере-проверено 23.08): все gender-кейсы конструируют род РУКАМИ, то есть зелёная батарея не отличает «производитель работает» от «производителя нет»; гейта на дрейф рода в движке нет | бэкенд (+полигон на замер) | **скоро (цель №1; правка провода — вайр-батчем 182)** | развилка → решение → правка промпта/прохода + замер на прогоне с редактурой | трассировка цепи банка 22.08, D39.21, C3 реестра памяти | +| 213 | **ОСТАТОК — одна строка в ДЕВ-пути: супервизор зашивает `"book.yaml"` мимо константы `ConfigFile`** (`platform/internal/ingest/supervisor.go:142`=`"status", "--config"`). ⚠ **ГЛАВНАЯ половина ЗАКРЫТА лендингом P9 (D39.162):** путь банк-экспорта берётся из конверта артефактов движка (`platform/internal/runner/artifacts.go:28-35`; пустой путь — ГРОМКИЙ отказ), нестрогий парс `book.yaml` и собственный `projectDB()` снесены. Осталась ровно та тривиальность, которую строка называла рядом с дефектом. ⚠ Пере-именование банк-экспорта в фикс-имя рядом с `events.jsonl` — ЛОМАЮЩЕЕ, его место в окне строки **161**, НЕ здесь | платформа | когда-нибудь (одна строка, следующим касанием зоны) | правка дев-супервизора | консилиум шва 22.08; главная половина — D39.162 | | 214 | **Подпись банка не оставляет на банке НИ ОДНОГО следа.** Единственная долговечная запись акта подписи — булев `bank_released` на прогоне (`platform/internal/pgstore/runs.go`, греп `bank_released` (номер строки двигает живая сессия зоны)): кто и когда подписал, что именно вошло в подписанный набор — не хранится нигде. Следствие: пост-фактум ответить «почему в книге этот перевод термина» нельзя, а при пере-нарезке или пере-прогоне восстановить намерение человека не из чего. ⚠ **ЧАСТИЧНЫЙ ответ появился с дверью правок (D39.162):** её документы решений — долговечная запись того, ЧТО владелец решил, и они переживают прогон. Не отвечено по-прежнему: КТО и КОГДА подписал, и что именно вошло в подписанный набор. Всплыло трассировкой цепи банка 22.08, подтверждено пере-проверкой | платформа + бэкенд | когда-нибудь (с трубой доставки правок, D39.156) | отдельное решение о провенансе подписи | трассировка цепи банка 22.08, пере-проверено №19 | | 216 | **Подпись банка, halt на потолке и резюм после пополнения не проверялись против ЖИВОГО движка ни разу.** Проверки этих путей в батарее платформы стоят на фейках; единственный живой прогон движка в батарее — не по этим маршрутам. То есть три несущих сценария продукта держатся на договорённости о поведении чужой стороны, а не на замере. ⚠ Гейтится тем же, чем и живой прогон книги (строка 202): холодный прогон движка | платформа | когда-нибудь (с 202) | живой прогон по трём маршрутам | трассировка цепи банка 22.08, пере-проверено №19 | -| 227 | **`signature` в квитанции двери правок считается от карты, которую переписывает ЛЮБАЯ граница майнинга** (находка воркфлоу-ревью P9, 28.08): запись карты стоит ВЫШЕ решения о стопе (`backend/internal/pipeline/mining.go:191`=`writeFileAtomic(r.signatureMapPath()`), поэтому `signature != null` НЕ означает состоявшегося стопа подписи; `surfaces`/`undecided` дрейфуют между двумя вызовами владельца, а `undecided: 0` достижим при НЕпредъявленных решениях (кап top-200 вытесняет). ⚠ Починка аддитивна и носитель для неё уже есть: карта несёт СВОЙ идентификатор (`backend/internal/membank/decisions.go:955`=`id, err := seed.SignatureMapID(content)`), а шов его не читает — отдать идентификатор в квитанцию и судить по нему. ⚠ Якорь находки был неверен (`pipeline/signaturemap.go` не существует) — исправлен приёмкой чтением. Цена сегодня мала (поле информационное, гейтом не служит) и растёт вместе с экраном подписи: именно он будет решать «что я подписываю» по этому числу | бэкенд | когда-нибудь (гейт: заказ экрана подписи) | аддитивная правка квитанции | воркфлоу-ревью P9, D39.162 | +| 227 | **`signature` в квитанции двери правок считается от карты, которую переписывает ЛЮБАЯ граница майнинга** (находка воркфлоу-ревью P9, 28.08): запись карты стоит ВЫШЕ решения о стопе (`backend/internal/pipeline/mining.go:191`=`writeFileAtomic(r.signatureMapPath()`), поэтому `signature != null` НЕ означает состоявшегося стопа подписи; `surfaces`/`undecided` дрейфуют между двумя вызовами владельца, а `undecided: 0` достижим при НЕпредъявленных решениях (кап top-200 вытесняет). ⚠ Починка аддитивна и носитель для неё уже есть: карта несёт СВОЙ идентификатор (`backend/internal/membank/decisions.go:955`=`id, err := seed.SignatureMapID(content)`), а шов его не читает — отдать идентификатор в квитанцию и судить по нему. Цена сегодня мала (поле информационное, гейтом не служит) и растёт вместе с экраном подписи: именно он будет решать «что я подписываю» по этому числу | бэкенд | когда-нибудь (гейт: заказ экрана подписи) | аддитивная правка квитанции | воркфлоу-ревью P9, D39.162 | | 228 | **Отклонённая поверхность возвращается АЛИАСОМ уцелевшей строки — движок не держит того, что канон уже обещает** (находка воркфлоу-ревью P9 в форме Д1, УЗКО пере-сформулирована бэкенд-сессией 28.08 и принята приёмкой): канон говорит дословно «declining a surface removes EVERY window of that surface» (`docs/architecture/14-api-contract/openapi.yaml:2079`=`declining a surface removes EVERY window`; адрес пере-нацелен 02.09 — минор 0.9.0 сдвинул прежний 2051), а эмиссия майнера энтити-широка (`backend/internal/pipeline/miner_emit.go`, `clusterTouches`), тогда как фильтр авто-банка ключуется только по собственному `src` строки (`backend/internal/pipeline/mining.go:662`). ⚠ **Правильная форма — снять АЛИАС со строки, а не снести строку:** расширение `decline` до энтити противоречило бы ратифицированному контракту, и именно поэтому бэкенд-сессия применила право §9 и НЕ чинила это попутно. Предмет — банковая онтология (`18-bank-ontology.md`), не тихая порча | бэкенд | скоро (гейт: заказ по читающей стороне банка) | отдельный заказ узкой формы | воркфлоу-ревью P9; форма — бэкенд-сессия 28.08, D39.164 | | 229 | **Снапшот не фолдит модель ВНУТРЕННИХ гейтов — флип провода под неизменным `request_hash`** (самонаходка бэкенд-сессии 28.08, подтверждена приёмкой): снапшот фолдит `Capability` СТАДИЙНЫХ моделей и их эскалации (`backend/internal/pipeline/snapshot.go:316-340`), но модель `gates.terminology.model` / `gates.repair.model` (`backend/internal/config/internal_call.go:72`) не фолдится сознательно — а терминолог шлёт ДВА системных сообщения, так что смена оси `capabilities.system_messages` у провайдера, которым пользуется только гейт, меняет байты запроса при неизменном хеше: тихий false-hit класса D5.2. ⚠ **Сегодня ЛАТЕНТНА и денег не стоит — проверено приёмкой: гейта `terminology` нет НИ В ОДНОМ конфиге репозитория** (`grep -c terminology configs/pipeline-c1.yaml` = 0). Триггер починки — день, когда гейт включат с провайдером, объявляющим НЕдефолтную возможность. ⚠ Цена лечения — денежная: фолд гейт-моделей сдвигает хеши и обесценивает чекпойнты; дешёвая форма — фолдить ТОЛЬКО недефолтное (приём `omitempty`, прецедент `MinMaxTokens`), тогда сегодняшние снапшоты остаются байт-равными | бэкенд | когда-нибудь (гейт: включение внутреннего гейта либо следующее касание снапшот-контракта) | правка снапшот-контракта | самонаходка бэкенд-сессии, D39.164 | | 230 | **Инертный `decline` подписанного сид-терма отвечает `already_applied` вместо единственной работающей инструкции** (названный размен пака «тихая порча», D39.164): сузив отказ по поверхности ради СХОДИМОСТИ повтора, движок потерял поучение в одном углу — когда отказ и записан, и по-прежнему инертен против `glossary_seed`, пользователь получает «уже применено» вместо «убери терм из сида». Сходимость сочтена более тяжёлой обязанностью (на ней стоит вся раскладка класса 15 и синхронная дверь платформы), но размен РЕАЛЕН. **Форма закрытия — поле отчёта со стоячим фактом**, то есть аддитивная правка формы шва: платформенный `BankReport` — аллоулист, лишнее поле на провод не уедет само | бэкенд + контракт | скоро (с ближайшим касанием отчёта двери) | аддитивное поле отчёта | размен пака «тихая порча», D39.164 | @@ -179,15 +178,15 @@ | 237 | **Два загейченных триггера НАЖАТЫ и не отработаны** (реестр `13-tech-debt-anchors.md` §Б-108, сверено 30.08). **(а) `go.work`:** условие «появление Go-кода платформы» выполнено давно — `platform/go.mod` есть, `ls go.work` в корне даёт «No such file or directory». Ратифицировано D39.85 §8 п.4 (`docs/research/23-engine-platform-seam.md:66` = `go.work — коммитить, когда у платформы появится Go-код`); цена — один файл, по тому же §6 он решает только dev-удобство и не меняет ни видимости, ни версий. **(б) вендор-сверка маппинга эффорта `deepseek-v4-pro`:** вахта D39.92 сработала 13.08 changelog'ом вендора, а носители до сих пор ПРОТИВОРЕЧАТ (квирк-канон и `STACK.md` говорят «ручки у pro НЕТ»), и по гардрейлу владельца это закрывается ТОЛЬКО вендор-докой, а не выбором стороны. Держит жильца Д5 и калибровку цены редакторского арма. ⚠ **Класс важнее двух пунктов: спроектированный механизм без носителя события тихо становится долгом, и никто не проверяет, не нажат ли спусковой крючок.** | оркестратор | скоро | (а) один файл в корень; (б) заказ полигону на вендор-сверку | аудит очереди 30.08 | | 241 | **Канон противоречит сам себе на ДОЧИТАННОЙ книге, и принятая правка банка умирает молча** (названо телом D39.165 §3 28.08, носителя не получило; заведено оркестратором №20 30.08 по находке сессии P12). Две фразы: правка банка «takes effect on the NEXT run» (`docs/architecture/14-api-contract/openapi.yaml:504`=`takes effect on the NEXT run`) против «finished work is not bought twice» + подъём потолка только у ПРИОСТАНОВЛЕННОЙ книги (`:590`=`finished work is not bought twice`). У дочитанной книги следующего прогона купить нечем: пользователь правит банк, получает квитанцию об успехе — и правка не доезжает ни до одной строки никогда. ⚠ Смежное лечение уже существует и не связано с этой дырой: пере-проход ПОКУПАЕТСЯ членом `RunRequest.re_pass` (канон 0.7.0, D39.166) — то есть механизм есть, а фраза канона его не признаёт для дочитанной книги. Решать формой: либо канон признаёт пере-проход входом для дочитанной книги, либо дверь правок отказывает такой книге ЧЕСТНО вместо ложной квитанции | контракт (+платформа) | скоро (следующее касание контракта) | контрактный минор + пин на дочитанной книге | D39.165 §3, эррата 30.08-б, находка сессии P12 | | 242 | **Реестр D-нот: колонки «статус» и «тело» разъехались на 74 строках из 224** (замер аудита доков 30.08). У свежих нот в «статусе» стоит заметка «ЖИВОЕ: …», а слово `жив` уехало в «тело»; шапка таблицы описывает другой порядок. Гейт `counts.py --check` этот класс НЕ ловит по устройству (сверяет полноту номеров, не форму ячеек). Лечение — не ручная перекладка (дороже пользы и легко внести новую ложь), а машинное: правило формы в `counts.py` + разовый прогон приведения. Пока не сделано — в легенде реестра стоит правило чтения (испр. 30.08) | оркестратор | когда-нибудь | правило в `counts.py` + разовое приведение | аудит доков 30.08 | -| 243 | **Остаток аудита доков 30–31.08: 19 удержанных находок НЕ применены** (аудит — 5 линз + верификатор на каждую, 57 находок, 55 удержаны, 36 применены сменой №20). Перечень: ~~**arch-3**~~ **ЗАКРЫТ 31.08 (D39.179 п.5)** — и был вдвое больше заявленного: не 13 якорей, а **51** (34 уехали, 1 мёртв, 16 верны), а дороже адресов оказались ЛОЖНЫЕ КЛЕЙМЫ (цитата контракта, которой нет; потерянный третий член `Usage`; живой К-13 при закрытом D39.132; метод `Settle`, которого нет). Чинилась ФОРМА, не номера: сверяемых гейтом по содержимому стало 89→127 · **arch-5** (правило языка знает две корзины, `reader.txt` — третья) · **arch-7** (§2 закона шва: дисциплина флока не описывает новый глагол-писатель) · **arch-9** (реестр загейченных триггеров не знает нажатых 30.08) · ~~**arch-10**~~ **ЗАКРЫТ 02.09** — числа словаря из тела дока сняты, носитель назван кодом (`docs/architecture/16-events-emitter.md`, греп `Словарь событий — В КОДЕ, не здесь` → `backend/internal/runevents/runevents.go`, греп `const StreamVersion`) · ~~**arch-11**~~ **ЗАКРЫТ 02.09** — ключ назван ОТВЕРГНУТЫМ, а не действующим (`docs/architecture/10-prompt-architecture.md`, греп `ОТВЕРГАЕТСЯ загрузкой`) · **arch-12** (шапка `09-target` сама зовёт себя неполной — строку под таблицей слоёв надо внести; ⚠ ЖИВ на 02.09: греп `D39.181` по `docs/architecture/09-target-architecture.md` — 0 хитов, греп `D39.182` — 0 хитов, то есть лендинги 31.08 в док слоёв не внесены) · **contract-8** (эррата 15.08-в в шапке D-лога указывает на промт, уехавший в архив) · **contract-10** (`Export.failure_code` «becomes an enum with the first built format» — формат построен, условие наступило) · **progress-6/7/8/10/11/12/13/14/15** (мелочь CURRENT-STATE и строк бэклога: протухшие «запушена»/«строка 200»/якорь `miner_emit.go`/дубль 238 внутри 160 и пр.). ⚠ Отчёт аудита жил в песочнице сессии №20 и умирает с ней — здесь ЕДИНСТВЕННЫЙ носитель списка; воспроизведение = повторный аудит (5 агентов, ~2 часа) | оркестратор | скоро | пройти списком; major (arch-3) первым — док про деньги врёт указателями | аудит доков 30–31.08, сдача смены №20 | +| 243 | **Остаток аудита доков 30–31.08: 19 удержанных находок НЕ применены** (аудит — 5 линз + верификатор на каждую, 57 находок, 55 удержаны, 36 применены сменой №20). Перечень: ~~**arch-3**~~ **ЗАКРЫТ 31.08 — разбор телом D39.179 п.5** (был вдвое больше заявленного: 51 указатель вместо 13, и дороже адресов оказались ЛОЖНЫЕ КЛЕЙМЫ) · **arch-5** (правило языка знает две корзины, `reader.txt` — третья) · **arch-7** (§2 закона шва: дисциплина флока не описывает новый глагол-писатель) · **arch-9** (реестр загейченных триггеров не знает нажатых 30.08) · ~~**arch-10**~~ и ~~**arch-11**~~ **ЗАКРЫТЫ 02.09** (числа словаря событий сняты в пользу кода; отвергнутый ключ назван отвергнутым) · **arch-12** (шапка `09-target` сама зовёт себя неполной — строку под таблицей слоёв надо внести; ⚠ ЖИВ на 02.09: греп `D39.181` по `docs/architecture/09-target-architecture.md` — 0 хитов, греп `D39.182` — 0 хитов, то есть лендинги 31.08 в док слоёв не внесены) · **contract-8** (эррата 15.08-в в шапке D-лога указывает на промт, уехавший в архив) · **contract-10** (`Export.failure_code` «becomes an enum with the first built format» — формат построен, условие наступило) · **progress-6/7/8/10/11/12/13/14/15** (мелочь CURRENT-STATE и строк бэклога: протухшие «запушена»/«строка 200»/якорь `miner_emit.go`/дубль 238 внутри 160 и пр.). ⚠ Отчёт аудита жил в песочнице сессии №20 и умирает с ней — здесь ЕДИНСТВЕННЫЙ носитель списка; воспроизведение = повторный аудит (5 агентов, ~2 часа) | оркестратор | скоро | пройти списком | аудит доков 30–31.08, сдача смены №20 | | 244 | **Гейт якорей на пре-коммите ломается всякий раз, когда зона правит КОД и СВОЙ реестр одним незакоммиченным деревом** — и врёт в обе стороны. Механика: хук судит ЗАКОММИЧЕННЫЙ док против РАБОЧЕГО кода, поэтому пере-нацеленные, но не залёнджённые якоря читаются как битые. Замерено на приёмке P12 31.08: у оркестратора хук напечатал 13 битых якорей `platform/docs/DEFECT_REGISTER.md`, у зоны `counts.py --lint` на том же дереве дал **0**; права зона — в HEAD `internal/runs/runs.go:323`, в рабочем `:347`, и токен по новому адресу на месте. ⚠ Обратная сторона опаснее и не замерена: якорь, ставший битым ПО-НАСТОЯЩЕМУ, тем же механизмом может оказаться зелёным. Свойство общее, не про этот пак | оркестратор | когда-нибудь | либо судить обе стороны из одного состояния (`--from-index` уже есть — проверить, покрывает ли он случай), либо печатать, что сравниваются РАЗНЫЕ состояния | приёмка P12 оркестратором №21, 31.08, разрешено командой | | 245 | **Pathspec-форма коммита молча роняет UNTRACKED-файлы, и сломанный коммит выглядит нормальным до первого чужого прогона.** `git commit -- <пути>` обходит ИНДЕКС и берёт рабочее дерево только для ОТСЛЕЖИВАЕМЫХ путей: предварительный `git add` нового файла она игнорирует. Поймано на лендинге P12 31.08 — коммит `e1cb692` унёс `migrations.sha256`, уже ссылавшийся на три миграции, а сами миграции 00029/00030/00031 и три теста остались снаружи; починено амендом секундного неопубликованного коммита при пустом индексе (`0a680a3`). ⚠ Канон git-координации в `CLAUDE.md` объясняет про pathspec ТОЛЬКО то, что она не трогает чужой индекс — то есть учит половине правды и ровно этим создаёт ловушку. Норма, которую предлагаю вписать: новые файлы стейджить явно и проверять состав `git show --name-only`, а не доверять форме. ⚠ **ПОЛОВИНА ПОСТРОЕНА 31.08** (`94381bb`, испр. 02.09): в `docs/scripts/githooks/pre-commit` стоит warn-блок, который перед каждым коммитом печатает неотслеживаемые файлы в каталогах коммита. Живой остаток — блок ПРЕДУПРЕЖДАЕТ, но не блокирует, и на свежем клоне хук вообще не установлен (строка 220) | оркестратор | скоро (решение владельца — его канон) | одна строка в `CLAUDE.md` §«Git-координация мультисессий»; вписывает владелец или оркестратор по его слову | лендинг P12 оркестратором №21, 31.08 | | 246 | ⚠ **ДВЕ КОПИИ ПОЛОСЫ ОТКАЗОВ 10–19 ОБЕЩАЮТ РАЗНОЕ — потребитель держит гарантию, которую производитель ОТОЗВАЛ.** Движок (`backend/cmd/tmctl/main.go:53`=`Nothing was written` is NOT the band's promise any more): «„Nothing was written“ is NOT the band's promise any more … **exit 15 legitimately answers with files on disk**». Платформа (`platform/internal/ingest/exit.go:38`=`nothing this process would have written was written`): «… and nothing this process would have written was written». ⚠ Опасность не теоретическая: по `PD-196` интейк действует по полосе РАЗРУШИТЕЛЬНО (отклоняет книгу и удаляет загрузку), а `exit 15` теперь легитимно оставляет файлы на диске. Хвост: движковый `exitBookIncomplete = 16` у платформы константы НЕ имеет вовсе (её словарь 10·11·12·13·14·15·19). ⚠ **Денежная половина ЦЕЛА в обеих копиях** (`nothing was spent` — по одному хиту в каждой), поэтому запрет отказывать классом полосы там, где деньги уже потрачены, в силе. Предсказано п.6 закона шва 17 | платформа (правка) + оркестратор (маршрут) | СРОЧНО | зона платформы приводит свою копию к движковой ЛИБО обе стороны идут в ратификацию, если расхождение намеренное | пак «деньги и честность», находка A15 вне заказа, 31.08; пере-проверено оркестратором дословно обеими копиями | | 247 | **§2.2 закона раскрытия опровергает себя следующей же строкой — эррата зонного дока.** Формальная фраза требует «держит ОБА операнда сравнения и обязано их НАПЕЧАТАТЬ», а её собственный пример тут же говорит обратное: честная форма — НАЗВАТЬ ОСЬ («снапшот разошёлся» честно, «конфиг/промпты изменились» ложно). ⚠ **Ратифицированный текст D39.181 п.1 требования «напечатать» НЕ СОДЕРЖИТ ВОВСЕ** — оно живёт только в `backend/docs/DISCLOSURE_LAW_DESIGN.md`, значит противоречия с ратификацией нет и решает ЗОНА, не владелец. ⚠ Довод «граница прячет имена моделей и хеши» ОПРОВЕРГНУТ исполнением: эти значения уже едут по тому же stderr штатным INFO-логом, включая `memory_version=<12 hex>` — значение того самого поля. Цена бездействия на живых данных = НОЛЬ (единственная сдвинувшаяся ось — хешевая, печать дала бы две несравнимые строки SHA) | бэкенд | когда-нибудь | эррата к §2.2: операнды называются осью, а не значением | приёмка D39.182 + разведка оркестратора 31.08 | | 248 | **Полнота самообъявления о правках чужих тестов ничем не проверяется — и трижды оказалась неполной.** P11 назвала файл, которого не трогала; P12 не назвала тест, у которого переписаны ОБА утверждения; сессия пака «деньги и честность» в первой редакции комментария утверждала неверное о силе собственной правки. ⚠ **Мой метод проверки был слабее, чем я его подал:** греп `^[-+].*t\.(Error|Fatal)` ловит строку СООБЩЕНИЯ, а утверждение — это строка СРАВНЕНИЯ, и она другая (замер: греп локализует утверждение в 1 случае из 475). Предложение разведки: warn-only гейт-детектор при лендинге — список пред-существующих тестов с изменёнными строками утвержденческой формы ВНУТРИ пред-существующих тел; прототип ~25 строк sh прогнан на двух лендингах и указал ровно на `bankfixpack_test.go`. Площадка есть — `docs/scripts/githooks/pre-commit` уже warn-only. ⚠ Ложняки измерены: целиком новый `t.Run` внутри старого `func` даёт срабатывание (1 из 6 на P12) | оркестратор | скоро | гейт-детектор warn-only + пункт чек-листа приёмки | разведка оркестратора 31.08 по вопросу владельца | -| 249 | **Колонка веса бэклога не судится ничем, и девять рядов её потеряли.** Правило таблицы (легенда ниже) даёт ТРИ веса — «блокер-очереди» · «скоро» · «когда-нибудь», — но `counts.py` словаря весов бэклога НЕ ИМЕЕТ: `WEIGHT_VOCAB` в нём — словарь РЕГИСТРА платформы (`major/minor/info`), а `backlog()` лишь считает подстроку «скоро». Замер 02.09 самопроверочным скриптом (`cells(l)[-4]` по всем рядам): **девять** ячеек веса не содержат ни одного слова словаря — ряды **5 · 13б · 94 · 96 · 97 · 149 · 205 · 221 · 246** («отложено-до-замера», «СРОЧНО», «—», «сделано 21.08», «гейчена разморозкой фронта»…). Три из них — 96/97 — надгробия переехавших в зонный бэклог строк, у них «—» законно; остальные шесть потеряли вес молча. ⚠ Найдено не ревизией, а ПОБОЧНО: контролёр приёмки заметил, что мои же две правки снесли вес-слово, я починил свои и пере-считал весь трекер. ⚠ **ВТОРАЯ ПОЛОВИНА КЛАССА, найдена тем же заходом: у ячейки веса нет ни словаря, ни ЭКРАНИРОВАНИЯ.** Счётчик ищет подстроку ГДЕ УГОДНО в ячейке, поэтому упоминание веса в прозе неотличимо от самого веса: фраза «переведена из «скоро»» ре-добавила два ряда в счёт (53 → 56 при одной новой строке), поймано пере-счётом скриптом. **Лечение ОДНИМ правилом на обе половины: вес обязан быть ПРЕФИКСОМ ячейки** (`startswith` по трём словам), и «скоро» считается тоже по префиксу, а не подстрокой — тогда потеря веса и ре-добавление счётом умирают одной проверкой, без экранирования. Сегодня такой гейт даёт **9 нарушений, а не 0** — он родится КРАСНЫМ, и это правильно: покажет то, что есть. ⚠ Два ряда девятки шире класса: **149** («исполнен и заленден 10.08») и **205** («сделано 21.08») объявляют себя ИСПОЛНЕННЫМИ прямо в колонке веса, хотя по правилу таблицы закрытые строки в ней не живут — это либо живой остаток без веса, либо непойманный класс C; **246** несёт самодельное «СРОЧНО», которого в словаре нет. **Решение владельца нужно только на форму гейта; сами девять ячеек чинит оркестратор.** | оркестратор | скоро ($0, гигиена трекера) | режим `counts.py` + правка девяти ячеек | ревизия доков 02.09, приёмка контролёра | +| 249 | **Девять рядов бэклога потеряли слово веса, и гейт на них НЕ краснеет.** ⚠ **Лечение ПОСТРОЕНО (сверено кодом 02.09): вес судится ПРЕФИКСОМ ячейки** — `docs/scripts/counts.py`, греп `BACKLOG_WEIGHTS` (три слова: «блокер-очереди» · «скоро» · «когда-нибудь»), и «скоро» считается тем же префиксом. Этим убита ВТОРАЯ половина класса: подстрока ловила слово в ПРОЗЕ, и фраза «переведена из «скоро»» ре-добавляла ряд в счёт — число скакнуло **53 → 56** при одной новой строке (замер 02.09, пере-счёт скриптом). ⚠ Гейт рождён ЗЕЛЁНЫМ, а не красным: девять известных рядов внесены «дедовщиной» — греп `WEIGHT_GRANDFATHERED` там же, ряды **5 · 13б · 94 · 96 · 97 · 149 · 205 · 221 · 246**. **ЖИВОЙ ОСТАТОК — сами ячейки:** у 96/97 прочерк ЗАКОНЕН (надгробия строк, уехавших в зонный бэклог, D39.84), остальные семь потеряли вес молча и чинятся оркестратором — каждая починенная выходит из списка дедовщины. ⚠ Два ряда шире класса: **149** («исполнен и заленден 10.08») и **205** («сделано 21.08») объявляют себя ИСПОЛНЕННЫМИ прямо в колонке веса, хотя по правилу таблицы закрытые строки в ней не живут — это либо живой остаток без веса, либо непойманный класс C; **246** несёт самодельное «СРОЧНО», которого в словаре нет. | оркестратор | скоро ($0, гигиена трекера) | правка семи ячеек → выход из `WEIGHT_GRANDFATHERED` | ревизия доков 02.09, приёмка контролёра | | 217 | **Скрипты полигона захардкодили АБСОЛЮТНЫЕ пути двух корней и не работают на этой машине вовсе.** ДВА РАЗНЫХ слома. **Корень репо** — смена пользователя: литерал в 121 файле, из них 104 дословно `REPO = Path("/home/ubuntu/projects/textmachine")`, портабельных форм всего 5. **Корень книг** — оба события порознь: литерал `/home/ubuntu/books` 86 файлов (пользователь), портабельный `Path.home()/"books"` 89 файлов (переезд каталога; на прежних машинах работал). Объединение 173 файла. Пользователь теперь `ubuntu-26`, книги переехали в `<репозиторий>/books` ⇒ ломается и то и другое, включая ЖИВОЙ гейт фазы Д `eval/conformance.py:48`=`REPO = Path("/home/ubuntu/projects/textmachine")`. Живых носителей 26 по корню книг (среди них портабельная форма преобладает 20:6) плюс корневые гейты и сборщики корпусов; остальное — скрипты закрытых эксп-12–16, их владелец велел ВЫБРОСИТЬ, а не чинить (D39.157 п.4а). Форма правки — за зоной; приор оркестратора: один модуль путей, корень резолвится МАРКЕРОМ вверх по дереву (движок так и делает — `backend/internal/miner/miner_parity_test.go:29`=`derived from the repository MARKER`), книги от него, обе ручки перекрываются env | полигон | скоро (блокирует любой прогон зоны) | пак путей полигона | переезд машины 24.08, №19 | -| 219 | **Line-якоря в тела D-лога обречены съезжать, и механизм именно в дисциплине эррат.** Эрраты вписываются в КАРТУ ШАПКИ (append-only, D23.3), то есть в начало файла, — значит каждая эррата сдвигает номера строк ВСЕХ тел ниже, и любой якорь вида `05-decisions-log.md:NNN` умирает молча. ⚠ Замерено на себе 27.08: три эрраты за сессию убили якоря в `docs/architecture/17-seam-inbound-law.md` (греп `Эррата, которую ратифицирующая нота обязана поставить`) и `docs/research/25-seam-cold-review.md:5`=`адресуем НОМЕРОМ, а не строкой` (оба целили в `:232`, тело уехало на `:239`; ⚠ 02.09 обе площадки уже переведены на форму номера ноты — прежний голый указатель `17-seam-inbound-law.md:120` показывает пустую строку). Лечение — не пере-нацеливание (оно повторится через эррату), а СМЕНА ФОРМЫ якоря: в тела D-лога целиться номером ноты (`^## D39.106`), который стабилен навсегда, а не строкой. ⚠ Строка ОБЪЯВЛЕНА в CURRENT-STATE 24.08 и до 27.08 в таблице НЕ СУЩЕСТВОВАЛА — очередь три дня ссылалась на носитель, которого нет; поймано свипом якорей при выдаче контрактного минора (⚠ D39.157 п.6 объявил класс закрытым 24.08 — носителя в таблице тогда не было). ⚠ **Первая половина лекарства ПОСТРОЕНА:** `counts.py --lint` сверяет якоря в тела D-лога СТРУКТУРНО и без токена — владелец целевой строки (ближайший `^## D<номер>`) обязан совпасть с номером, названным рядом; остаётся перевести живые якоря на форму номера | оркестратор | скоро (растёт с каждой эрратой) | `--lint` учит форму `файл:^## D<номер>`, живые якоря в D-лог переводятся на неё | ревью доков 24.08, механизм и отсутствие носителя — 27.08, D39.160 | +| 219 | **Line-якоря в тела D-лога обречены съезжать, и механизм именно в дисциплине эррат.** Эрраты вписываются в КАРТУ ШАПКИ (append-only, D23.3), то есть в начало файла, — значит каждая эррата сдвигает номера строк ВСЕХ тел ниже, и любой якорь вида `05-decisions-log.md:NNN` умирает молча. ⚠ Замерено на себе 27.08: три эрраты за сессию убили якоря в `docs/architecture/17-seam-inbound-law.md` (греп `Эррата, которую ратифицирующая нота обязана поставить`) и `docs/research/25-seam-cold-review.md:5`=`адресуем НОМЕРОМ, а не строкой` (оба целили в `:232`, тело уехало на `:239`; ⚠ 02.09 обе площадки уже переведены на форму номера ноты — прежний голый указатель `17-seam-inbound-law.md:120` показывает пустую строку). Лечение — не пере-нацеливание (оно повторится через эррату), а СМЕНА ФОРМЫ якоря: в тела D-лога целиться номером ноты (`^## D39.106`), который стабилен навсегда, а не строкой. ⚠ **Первая половина лекарства ПОСТРОЕНА:** `counts.py --lint` сверяет якоря в тела D-лога СТРУКТУРНО и без токена — владелец целевой строки (ближайший `^## D<номер>`) обязан совпасть с номером, названным рядом; остаётся перевести живые якоря на форму номера | оркестратор | скоро (растёт с каждой эрратой) | `--lint` учит форму `файл:^## D<номер>`, живые якоря в D-лог переводятся на неё | ревью доков 24.08, механизм и отсутствие носителя — 27.08, D39.160 | | 220 | **Репо-широкий гейт доков бутстрапится пакетным менеджером ОДНОЙ зоны, и та заморожена.** Диспетчер `.git/hooks/pre-commit` зоно-нейтрален по построению (`for hook in */scripts/githooks/pre-commit`, `#!/bin/sh`, node не нужен) и судит `CLAUDE.md` + `docs/**` + `platform/docs/**` + `frontend/docs/**` (`docs/scripts/counts.py:543`=`ROOT / "CLAUDE.md"`), но единственный его УСТАНОВЩИК — `frontend/scripts/githooks/install.mjs`, вызываемый ключом `prepare` из `frontend/package.json`. Охват и бутстрап не совпадают ⇒ инструмент решает свою задачу не в полной мере. Проверено исполнением 24.08: на этой машине `.git/hooks/` содержал только `*.sample`, гейт МОЛЧАЛ, ничего не проверив, и поймал первые четыре дефекта только после ручной установки; сессия бэкенда или доков `npm install` не делает никогда. Приор: зоно-нейтральный установщик в `docs/scripts/githooks/` как ЕДИНСТВЕННЫЙ писатель диспетчера, `prepare` фронта зовёт его — фронтовая половина выписана пингом №19 в зонный журнал фронта. ⚠ Ручная установка — временная мера, пока строка открыта; записывать её как порядок работы ЗАПРЕЩЕНО (это ровно тот обход, цену которого называет шапка `CLAUDE.md`) | доки + фронт | скоро | зоно-нейтральный бутстрап + правка `prepare` при разморозке | аудит переезда 24.08, №19 | | 49 | **Этапы Б+В спеки D15.2** (content-addressed resume / `guard_hash` — D39.31 сознательно не строил) ; этап В = tmctl export-контракт D29.1 (annot-v1 · цвет-мап+rollup · политика красных fail-closed) + операторский протокол-документ релиза гендер-твиста (D5.1): сам механизм УЖЕ построен — until_ch-правка → точечный re-edit со сметой и $0-пере-пином (`repin.go`/`rebill.go`, D39.42 п.5/D39.45) | бэкенд | скоро (ПОДТЯНУТА D39.81: annot-v1 = источник замечаний для фронта — критический путь подключения) | отдельное решение (annot-половина — по контракту 14, D39.99) | D39.34(4), D33 п.5, D39.81 | | 49а | **ALTER-шаги миграций v8–v14 не идемпотентны вопреки шапке `migrate.go:9-11`** (полу-применённая БД не сходится; счётчик версий скрывает) — находка критика полноты пака-19 | бэкенд | когда-нибудь | отдельное решение | D39.56, PACK19_BUILD §6.9 | @@ -241,42 +240,29 @@ | 225 | **Гейт «строка `open`, а лекарство уже в дереве».** При лендинге пересекать ПОЛНЫЕ пути застейдженных файлов с якорями открытых строк регистра и бэклога; совпадение — вопрос лендеру, а не находка следующего пака. Замерено прежде решения: по именам файлов 22 совпадения, почти все ложные; по полным путям 2, оба настоящие, и один из них (`PD-157`) убил мой же лендинг `d1eb8a9`. Норма-половина уже стоит в `platform/docs/ENGINEERING_STANDARDS.md` §3 п.8; здесь — машинная половина, режимом `counts.py` | оркестратор | скоро (окупился до постройки) | режим `counts.py`, берущий список путей и печатающий открытые строки, чьи якоря в них целят | приёмка пака P8-REVIEW 27.08, D39.159 п.7 | | 226 | **История ПРЕДЪЯВЛЕННОГО не ведётся — «почему меня не остановило на этом термине» ответить нечем.** Карта и человеческая таблица стопа перезаписываются каждым прогоном, память флажка — плоское множество поверхностей без `map_id` и без времени. Это прямая расплата за то, что стоп срабатывает ОДИН раз (кластерная память, названный остаток дофикса-2), и единственная возможная диагностика спора. Кандидат в пак решённости, не заказ. ⚠ Шестое, названное консилиумом и оставленное владельцу: авторство и время решения — сегодня цена нуля (владелец один), станет нужным при мультипользовательской платформе, и тогда его захотят ЗАДНИМ ЧИСЛОМ | бэкенд | скоро (диагностики нет вовсе) | движок метит предъявленное `map_id` и временем; оверлей отвечает «что предъявлялось на прошлом стопе» | консилиум по читающей стороне банка 27.08 | -*(Хроника сессий №11–№13, 02–04.08 (D39.91–105: ручки эффорта · стандарты репо · archguard · S2 · контракт API v0 · платформа P0 · банк-арбитраж research/24) — в [archive/PROGRESS-2026-08-02-04.md](archive/PROGRESS-2026-08-02-04.md).)* - -*(Хроника сессий №9/№10, 31.07–02.08 (D39.59–90: курс «общность вперёд» · свип полноты · качество банка · фикс-пак · coldrun-b · фронт/платформа открыты · шов движок↔платформа · промт арбитража банка) — в [archive/PROGRESS-2026-08-01-02.md](archive/PROGRESS-2026-08-01-02.md).)* - - -*(Хроника 25.07–31.07 до курса D39.59 — эры №7/№8 и начало №9: паки 16–20, мини-прогон, полигон-пакеты 5–8, ToS-речеки, пак-19, холодный прогон (лендинги D39.26–58) — в [archive/PROGRESS-2026-07-25-31.md](archive/PROGRESS-2026-07-25-31.md).)* +*(Указатели на архив-слайсы хроники — бюллетенем «Архивы хроники» в CURRENT-STATE; здесь копий нет.)* ## Бэкенд -> ⚠ **Прожитая проза зоны за 24–30.08 ВЫНЕСЕНА в слайс -> [archive/PROGRESS-2026-08-backend.md](archive/PROGRESS-2026-08-backend.md)** (28.08 — пять итогов сессий -> и их записки-планы, D39.167; 30.08 — дампы паков «писатель книги» и «деньги», 103 КБ). Всё заленджено и -> ратифицировано, решения живут телами D39.175 и D39.170. Читать НЕ надо — там история, а не состояние. +> **Состояние зоны на 31.08:** активного промта НЕТ, дерево `backend/` чисто. Ратифицированные лендинги +> зоны: входная дверь шва — **D39.158** (`d1eb8a9`) · «тихая порча» — **D39.164** (`7d0c6f2`) · «деньги» — +> **D39.170** · гейт схемы — **D39.173** · «писатель книги» — **D39.175** (`8adcb86`) · «деньги и честность +> выдачи» — **D39.182** (`bb541a8`) · ЗАКОН РАСКРЫТИЯ, ратифицирован владельцем — **D39.181** · четыре +> строки бэклога закрыты тем же лендингом — **D39.185**. Диспозиция по D25.1 ратифицирована D39.175 п.2 +> (drift — не дыра файла; лестница — владельцу между паком и дверью). > -> **Состояние зоны на 31.08 (после лендинга):** активного промта НЕТ — последний пак зоны «деньги и -> честность выдачи» ПРИНЯТ И ЗАЛЕНДЖЕН (**D39.182**), до него «писатель книги» (**D39.175**, `8adcb86`). -> Дерево `backend/` чисто. Свободная работа зоны — строками бэклога: -> прежние **228** (отклонённая поверхность возвращается алиасом) · **229** (снапшот не фолдит -> модель внутренних гейтов) · **230** (размен «сходимость против поучения») · **141**-остаток · **131** -> (⚠ строк 231 и 236 в таблице БОЛЬШЕ НЕТ — 231 съел пак «деньги», 236 сужена D39.175). Диспозиция по D25.1 ратифицирована D39.175 п.2 -> (drift — не дыра файла; лестница — владельцу между паком и дверью). Входная дверь шва — `D39.158` (`d1eb8a9`), пак «тихая -> порча» — `D39.164` (`7d0c6f2`), пак «деньги» — `D39.170`, гейт схемы — `D39.173`. - -> ⚠ **Прожитый дамп пака «ДЕНЬГИ И ЧЕСТНОСТЬ ВЫДАЧИ» (31.08, сессия `textmachine-main-8a`, $0) СНЯТ отсюда 02.09.** -> Пак ПРИНЯТ И ЗАЛЕНДЖЕН — **D39.182** (`bb541a8`); закон раскрытия ратифицирован владельцем — **D39.181**; -> четыре строки бэклога закрыты тем же лендингом — **D39.185**. Доказательная база и ВСЕ пинги сессии живут -> файлами зоны: `backend/docs/MONEY_HONESTY_REPORT.md` (§7 — пинги оркестратору, §9 — десять экземпляров -> закона по одному, §0.1 — батарея ИСПОЛНЕНИЕМ, **§5.1 — разложение покупок П1/П2/П3**: ось пере-покупки -> терминолога = БАЙТЫ БАТЧА, а не сдвиг снапшота — это и есть «пинг №2», которым D39.185 п.1 адресует сюда; -> ⚠ испр. 02.09: **§6.2 «адверсариальный проход» в отчёте ЖИВ** — `backend/docs/MONEY_HONESTY_REPORT.md`, греп -> `^## 6.2`; ревизией доков 02.09 снят только дифф `^func Test`, и счёт тестов 1045→1083 при нуле удалённых -> держат теперь шапка CURRENT-STATE и тело **D39.182**), -> `backend/docs/DISCLOSURE_LAW_DESIGN.md`, `backend/docs/MONEY_HONESTY_PLAN-NOTE.md`; промт — -> `archive/prompts/BACKEND_MONEY_HONESTY_SESSION_PROMPT.md`. **Живой остаток пака — строками бэклога:** -> **246** (две копии полосы отказов 10–19 обещают РАЗНОЕ, СРОЧНО) · **247** (§2.2 закона опровергает себя) · -> **232** · **233** · **197** (ресурс ушёл в фазу 1, строка не взята). Читать дамп НЕ надо — там история. +> **Свободная работа зоны — строками бэклога:** **246** (СРОЧНО, две копии полосы отказов обещают РАЗНОЕ) · +> **247** · **232** · **233** · **197** (ресурс ушёл в фазу 1, строка не взята) · **228** · **229** · **230** · +> **141**-остаток · **131**. ⚠ Строк 231 и 236 в таблице БОЛЬШЕ НЕТ — 231 съел пак «деньги», 236 сужена D39.175. +> +> ⚠ **Прожитая проза зоны за 24–31.08 СНЯТА отсюда** — история живёт слайсом +> [archive/PROGRESS-2026-08-backend.md](archive/PROGRESS-2026-08-backend.md) и телами нот выше; читать её +> не надо. Доказательная база пака «деньги и честность» и ВСЕ его пинги — файлами зоны: +> `backend/docs/MONEY_HONESTY_REPORT.md` (§7 — пинги оркестратору, §9 — экземпляры закона по одному, +> §0.1 — батарея ИСПОЛНЕНИЕМ, **§5.1 — разложение покупок П1/П2/П3**: ось пере-покупки терминолога = +> БАЙТЫ БАТЧА, а не сдвиг снапшота — это и есть «пинг №2», которым D39.185 п.1 адресует сюда; §6.2 — +> адверсариальный проход), `backend/docs/DISCLOSURE_LAW_DESIGN.md`, `backend/docs/MONEY_HONESTY_PLAN-NOTE.md`; +> промт — `archive/prompts/BACKEND_MONEY_HONESTY_SESSION_PROMPT.md`. ## Полигон @@ -321,19 +307,15 @@ в файле. Живым из неё остаётся только ⚠0731 (смена весов под слагом) и стохастичность эха. 2. **`eval/README.md` описывает каталог `dovodka/` ОДНИМ файлом `runs.py`**, тогда как там сорок скриптов и главный инструмент фазы; `docs/experiments/README.md` объявляет себя сведённой «до эксп-22», а строк для 22 и 23 в ней нет. -3. **`naklon.py` (гейт позиционного наклона) лежит коммитами ветки `polygon`, в `main` НЕ влит.** ⚠ Испр. 02.09: - прежняя редакция пункта утверждала «в git ОТСУТСТВУЕТ ⇒ из чистого клона эта часть фазы не воспроизводится» — - **обе половины ЛОЖНЫ.** Файл несут и локальная `polygon`, и запушенная `origin/polygon` (проверка: - `git ls-tree origin/polygon -- eval/dovodka/naklon.py` — один блоб; `git ls-tree main -- eval/dovodka/naklon.py` - пусто — из этой-то пустоты, снятой в main-дереве, и родился ложный вывод «вне git»). Живой остаток — не «вне git», а НЕ ВЛИТО в `main`: - в `eval/dovodka/` у `main` 42 отслеженных файла против 80 у `polygon`. ⚠ Прежний дамп состояния - дерева (13 изменённых + 6 неотслеженных файлов, 22.08) СНЯТ 02.09 как прожитый: `git status -- eval/` в main-дереве - пуст, работа зоны лежит коммитами на ветке `polygon`. +3. **`naklon.py` (гейт позиционного наклона) лежит коммитами ветки `polygon`, в `main` НЕ влит.** «Вне git» + ЛОЖНО: файл несут и локальная `polygon`, и запушенная `origin/polygon`. Живой остаток — НЕ ВЛИТО в `main`: + в `eval/dovodka/` у `main` 42 отслеженных файла против 80 у `polygon` (снимать командой + `git ls-tree -r <ветка> -- eval/dovodka/`, а не чтением). **ФАЗА Д «ДОВОДКА ЭКСП-22/23» — ИДЁТ.** ⚠ **Живое состояние фазы живёт В ЗОНЕ, не здесь** (`eval/dovodka/` — планы, консилиум, ревью; свежий носитель курса зона называет сама), приёмка фазы — у ПАРАЛЛЕЛЬНОГО оркестратора, деньги и цепь потолков — `eval/dovodka/money_d.py` (`PACK_CEILING`/`CEILINGS`), а не литералом здесь: три поколения записей в одном месте и были причиной, по которой состояние фазы стало нечитаемым. *(Хроника фазы Д — записи 10.08 (сессия №1) и 15.08 (сессия №2, сквозной аудит дуги 19→23 и пере-судейство `tier`) — вынесена в [archive/PROGRESS-2026-08-10-15.md](archive/PROGRESS-2026-08-10-15.md) с тремя поправками в шапке: потолок, закрытые пункты листа владельца, протухшие «долги». Открытым на владельце из неё остаётся ОДИН пункт — возражение Sol по проходу `tier`.)* -**Диспозиция оркестратора №17 (15.08), живая до приёмки фазы Д:** просьба хендоффа «эррата zh-канона: пере-сборка = правка закрытой оси, ратифицирует оркестратор» (`docs/POLYGON_PHASE_D_HANDOFF.md:85`=`Пере-сборка = правка закрытой оси`, завышение +0.0039, вердикты не двигает) — **к ПАРАЛЛЕЛЬНОМУ оркестратору при приёмке, не к движковому** (приёмка фазы Д — его зона, №17 полигон не трогает **по слову владельца**). Прожитое из записи (вторая передача и мелочи аудита корпуса) — `archive/reports/CORPUS_AUDIT_2026-08-15.md`; санкции владельца по деньгам фазы и замене ja-книги — D39.136 п.1. +**Диспозиция оркестратора №17 (15.08), живая до приёмки фазы Д:** просьба хендоффа «эррата zh-канона: пере-сборка = правка закрытой оси, ратифицирует оркестратор» (`docs/POLYGON_PHASE_D_HANDOFF.md`, греп `Пере-сборка = правка закрытой оси` — файл дирти, номер строки не ставим по норме D39.179 п.4; завышение +0.0039, вердикты не двигает) — **к ПАРАЛЛЕЛЬНОМУ оркестратору при приёмке, не к движковому** (приёмка фазы Д — его зона, №17 полигон не трогает **по слову владельца**). Прожитое из записи (вторая передача и мелочи аудита корпуса) — `archive/reports/CORPUS_AUDIT_2026-08-15.md`; санкции владельца по деньгам фазы и замене ja-книги — D39.136 п.1. *(Память · Голос и состояние · Ридер-IDE — ЗАКРЫТЫЕ секции (D39.125): темы исполнены/переехали в зонные журналы; хроника — в архив-слайсах. Фронт пишет ТОЛЬКО в frontend-PROGRESS.md.)* diff --git a/docs/README.md b/docs/README.md index 75e42772..1fba89a4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -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). diff --git a/docs/STACK.md b/docs/STACK.md index 0233b970..4ac2168e 100644 --- a/docs/STACK.md +++ b/docs/STACK.md @@ -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-лога) — ⚠ число ДО пере-пина цен 13–15.08: таблица запинена ПИКОМ, счёт шиппинга = 100% DeepSeek ⇒ ×4.2–4.4 в пике и ×2.1–2.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. diff --git a/docs/architecture/01-decisions.md b/docs/architecture/01-decisions.md index 4520c87e..9d5204dc 100644 --- a/docs/architecture/01-decisions.md +++ b/docs/architecture/01-decisions.md @@ -2,7 +2,7 @@ > **⚠ ЧИТАТЬ ПРЕЖДЕ ТЕЛА (статус 25.07, оркестратор №7).** Принципы Р1–Р10 живы; **вся конкретика моделей/цен/каналов ниже — состояние 04–05.07 и проигрывает D-логу** (D30–D39.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` прямо переносится ~2–2,5 тыс. строк проверенной инфраструктуры: OpenAI-совместимый транспорт с retry/backoff, фейловер «локальная GPU → облако» с circuit breaker, прайсинг + reserve/settle-ledger, телеметрия (request_log, трейсы W3C), fail-fast конфиг. Это 3–6 недель сэкономленной разработки. +- Из `vojo/apps/ai-bot` прямо переносится ~2–2,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 рук: ~25–35 глав zh/ja/en→ru; решающий критерий — человеческие попарные сравнения (протокол LAIT; для двух систем это pairwise, не BWS — BWS только с ≥3 объектами, третьим якорем берём человеческий перевод) + панель LLM-судей чужих семейств. Правило: если C2/C3 лучше C1 менее чем на 5 п.п. win rate — берём C1 (в 2–3 раза дешевле). Бюджет: <$50 API + внешние редакторы 20–40 ч; **elapsed 2–3 недели, отдельная фаза** (см. план MVP v2) — подготовка корпуса стартует параллельно с Фазы 0 (работа владельца + сессия «Полигон»). +- Пилот 4 рук: ~25–35 глав zh/ja/en→ru; решающий критерий — человеческие попарные сравнения (протокол LAIT; для двух систем это pairwise, не BWS — BWS только с ≥3 объектами, третьим якорем берём человеческий перевод) + панель LLM-судей чужих семейств. Правило: если C2/C3 лучше C1 менее чем на 5 п.п. win rate — берём C1 (в 2–3 раза дешевле). Бюджет: <$50 API + внешние редакторы 20–40 ч (фаза и её протокол — `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, ~100–800 токенов). **Принцип «лучше ничего, чем мусор»**: пустой матч — норма, не тревога; бюджет допустимо недозаполнить; фильтр по точности ПЕРЕД приоритетом. Реальная тихая деградация — не пустота, а **ошибочная инъекция** (модель послушно следует неверной строке, уверенность↑ точность↓) → **трёхстороннее решение на каждую запись** (CONFIRMED / AMBIGUOUS+обязательный post-check / REJECT+лог) + per-chunk `retrieval-state` запись (наблюдаемость с первого дня). - Трёхслойная защита (GalTransl): pre-replace нормализация (только на источнике) → мягкий глоссарий в промпте → **обязательный post-CHECK** (не опциональный флаггер: soft молча теряет 17–36% терминов). **Слепой 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-паттернов; сам гейт проверяется мини-набором из 20–30 фрагментов с искусственно выпиленными предложениями), правило «в TM коммитится только вывод, прошедший все гейты». Фаза 2 (Python-сайдкар) — морфодетектор канцелярита по чек-листу Галь (pymorphy/Natasha), MTLD/distinct-n, дисперсия длин, доля пассива, порт BlonDe-подобных дискурсивных проверок на русскую морфологию. -- Метрика глоссарной консистентности — с процедурой: знаменатель = вхождения `src`/алиасов в исходных чанках; числитель = наличие леммы `dst` (по полю `decl`) в соответствующем выводе; прономинализация («Ли Вэй → он») не штрафуется, гейт считает только `approved`-термины; в безлюдном режиме auto→approved автоматом с записью в журнал. **Это post-CHECK и он ОБЯЗАТЕЛЕН** (не опциональный флаггер — soft-глоссарий молча теряет 17–36% терминов; правка валидации Р3): главный почти-бесплатный детектор тихой деградации, ловит и «модель проигнорировала термин», и «мы инъектили неверное». **Слепой post-replace форм в русский выход — запрещён** (ломает согласование). +- Метрика глоссарной консистентности — с процедурой: знаменатель = вхождения `src`/алиасов в исходных чанках; числитель = наличие леммы `dst` (по полю `decl`) в соответствующем выводе; прономинализация («Ли Вэй → он») не штрафуется, гейт считает только `approved`-термины; в безлюдном режиме auto→approved автоматом с записью в журнал. **Это post-CHECK и он ОБЯЗАТЕЛЕН** (не опциональный флаггер — soft-глоссарий молча теряет 17–36% терминов; правка валидации Р3): главный почти-бесплатный детектор тихой деградации, ловит и «модель проигнорировала термин», и «мы инъектили неверное» (запрет слепого post-replace — в Р3). - Оффлайн: паттерн routedecide/routereval из vojo → **golden-set реплей** решений об эскалации и вердиктов судьи со свипом порогов. Золотой набор — приватно из лицензионных изданий; GuoFeng Webnovel V2 — только dev (non-commercial, референсы MTPE-качества). ## Р8. Юридическая и продуктовая позиция. **Принято (переориентировано на EU после коррекции контура)** diff --git a/docs/architecture/02-mvp-plan.md b/docs/architecture/02-mvp-plan.md index 16a94b45..a90c9578 100644 --- a/docs/architecture/02-mvp-plan.md +++ b/docs/architecture/02-mvp-plan.md @@ -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.26–D39.28) — чанк-классификатор 0–3 и «каналы 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 на гетерогенных кандидатах; панель 2–3 семейства × 11+ повторов со свапом позиций, Bradley-Terry/медиана, grok не судит grok-выходы; пре-регистрация MDE и N≥3; харнесс чинится до прогона — эхо-стрип memory_eval, полные выходы, fidelity-ось; имена M0–M3 для memory-режимов). Решения пилота: ядро C0–C3, 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)*. 2–3 главы 18+ в корпусе — замер отказов по ролям (вкл. пробу Mistral, D14.2). +Протокол: `experiments/09-pilot-protocol.md` **+ обязательные поправки D13** (шесть пунктов, тело — слайс `../archive/architecture/05-decisions-D1-D38.md`, греп `^## D13`; полигон вносит их в док и харнесс ДО пре-регистрации). Решения пилота: ядро C0–C3, 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)*. 2–3 главы 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.26–D39.28; живые ограничения данных — «Правило 18+» выше). diff --git a/docs/architecture/03-implementation-notes.md b/docs/architecture/03-implementation-notes.md index 36907aa7..12eda84c 100644 --- a/docs/architecture/03-implementation-notes.md +++ b/docs/architecture/03-implementation-notes.md @@ -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 кэша истекает между вызовами одной стадии** (латентности чанков 63–278 с + гейты) ⇒ 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`. diff --git a/docs/architecture/04-unhappy-paths.md b/docs/architecture/04-unhappy-paths.md index ca2d07d3..12be0274 100644 --- a/docs/architecture/04-unhappy-paths.md +++ b/docs/architecture/04-unhappy-paths.md @@ -15,7 +15,7 @@ | Режим отказа | Механизм | Фаза | Статус | |---|---|---|---| | Дрейф имён/терминов между вызовами | Глоссарий + гейт консистентности (по леммам через `decl`) | 1 | ✅ | -| Система имён 名/字/号/прозвища: «один персонаж = 3–6 людей» | **Alias-граф** в глоссарии + NER-гейт «новая форма известной сущности = блок»; новое имя без фуриганы/контекста → эскалация | 1–2 | 🔶 схему Р3 расширить: aliases → граф с типами (имя/цзы/хао/прозвище/титул) | +| Система имён 名/字/号/прозвища: «один персонаж = 3–6 людей» | **Alias-граф** в глоссарии + NER-гейт «новая форма известной сущности = блок»; новое имя без фуриганы/контекста → эскалация | 1–2 | 🔶 половина: типы узлов в схеме ЕСТЬ (`store/migrate.go`, греп `alias_type TEXT NOT NULL` — name/zi/hao/nickname/title); NER-гейт не построен | | Коллапс терминосистемы рангов («Immortal, immortal or immortal») | Глоссарий-тип **ranked-set** + проверка инъективности (2 исходных ≠ 1 целевой) и порядка ступеней | 1–2 | 🔶 новый тип записи | | Значащие прозвища: перевести один раз и навсегда | Поле `nickname_translation`, первичный перевод — сильная модель/человек, дальше — лок | 1 | ✅ (консенсус изданий: имена — Палладий, прозвища — переводить) | | Обращения шисюн/гэгэ/о-нии-чан: транскрипция vs перевод | Пресеты brief «фанатский/издательский» (войны фандомов — 586 стр. холивара по одной Мосян; смертный грех — непоследовательность) + **матрица обращений по парам** с версионированием | 1–2 | 🔶 матрица обращений = расширение 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%» | 2–3 | 🔶 | | Мат: недожим (RLHF) и пережим | Двусторонний лексиконный гейт силы обсценности (0–3) + профиль грубости персонажа + политика 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`, здесь копий нет. ## Следствия для плана (сводка изменений) diff --git a/docs/architecture/05-decisions-index.md b/docs/architecture/05-decisions-index.md index 41ed94ff..0cb7512b 100644 --- a/docs/architecture/05-decisions-index.md +++ b/docs/architecture/05-decisions-index.md @@ -6,7 +6,8 @@ > Одна строка на КАЖДУЮ ноту журнала решений: № · дата · суть · статус · где тело · темы. > ⚠ **ФОРМА ДВУХ ПОСЛЕДНИХ КОЛОНОК РАЗЪЕХАЛАСЬ, замерено 30.08 (аудит доков):** из 224 строк 74 несут в колонке «статус» не статус, а ЗАМЕТКУ о живом остатке («ЖИВОЕ: …»), а собственно `жив` уехал в колонку «тело». Читать так: **колонки 4–5 у свежих нот — пара «статус ⟷ что осталось живым», порядок в паре не гарантирован; статус ноты определяй по слову `жив`/`superseded`/`частично`, где бы из двух оно ни стояло, а место тела — по слову `слайс`.** Приведение к одной форме — строка бэклога **242**; чинить руками 74 строки без гейта дороже, чем читать по этому правилу. Ведёт оркестратор при лендингах: новая нота = новая строка ТЕМ ЖЕ коммитом (полноту сторожит `docs/scripts/counts.py --check`). Суть и статус здесь — НАВИГАЦИЯ, не контракт: при конфликте побеждает ТЕЛО ноты (живой [`05-decisions-log.md`](05-decisions-log.md) → слайсы `../archive/architecture/05-decisions-*.md`). Несущие эрраты к фактам старых нот живут в шапке живого D-лога — их читать ОБЯЗАТЕЛЬНО, реестр их не дублирует. Темы (для грепа оси «какой закон по X»): деньги · шов · банк · промпт · судья · гейты · контракт · платформа · фронт · полигон · ToS · общность · процесс · нарезка · голос · инфра · модели. -> Родословная реестра (прозаическая карта D1–D39.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 строк реестра. | № | дата | суть | статус | тело | темы | |---|---|---|---|---|---| diff --git a/docs/architecture/06-memory-risk-registry.md b/docs/architecture/06-memory-risk-registry.md index e1d989bd..2b99cecf 100644 --- a/docs/architecture/06-memory-risk-registry.md +++ b/docs/architecture/06-memory-risk-registry.md @@ -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 (персонажи из предыдущих 1–2 чанков остаются); это состояние, а не 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 81–108 мс на 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). diff --git a/docs/architecture/09-target-architecture.md b/docs/architecture/09-target-architecture.md index 6b63410f..1a46b518 100644 --- a/docs/architecture/09-target-architecture.md +++ b/docs/architecture/09-target-architecture.md @@ -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`). +### Слои 4–7 — тело замысла СНЯТО, адреса здесь -### Слой 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; всё предписанное построено либо отменено, действующие статусы с номерами паков — **строки 4–7 шапки-таблицы**, пофакторный разбор находок с диспозициями — `../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` по слоям 1–7 СНЯТ: все они закрыты стройкой (статусы — шапка-таблица), а тела находок с диспозициями живут в ледджере. Живой остаток — только процессная строка: + | Слой | Несущие находки (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): плоский тест-срез не задействует рычаги границы/когезии, поэтому «не сработало на нём» ≠ «не нужно в движке». --- diff --git a/docs/architecture/10-prompt-architecture.md b/docs/architecture/10-prompt-architecture.md index 173494aa..f60158fb 100644 --- a/docs/architecture/10-prompt-architecture.md +++ b/docs/architecture/10-prompt-architecture.md @@ -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.1–39.2) и research/18–19. Док — одно место по теме промптинга и реестр открытого; **при конфликте побеждает D-лог**, обновлять при каждом лендинге, трогающем промты или слой 2. +> «Структурированный пакет конвенций пары» (§3) остаётся дальним планом. **Заметка собрана оркестратором 2026-07-16 по запросу владельца** («где заметка про промтинг?») — одно место по теме промптинга и реестр открытого; **при конфликте побеждает D-лог**, обновлять при каждом лендинге, трогающем промты или слой 2. ## 1. Четыре вопроса владельца → где ответ и что с ним diff --git a/docs/architecture/13-tech-debt-anchors.md b/docs/architecture/13-tech-debt-anchors.md index 1aea9e75..b6f0d3e0 100644 --- a/docs/architecture/13-tech-debt-anchors.md +++ b/docs/architecture/13-tech-debt-anchors.md @@ -1,32 +1,32 @@ # Якоря техдолга — справочник к строкам бэклога (НЕ трекер) -> ⚠ **Освежение 04.08 (D39.101):** якоря были входом пакета-чекеров (исполнен D39.78) и арки банка (закрыта D39.69/71); часть находок ниже уже ЗАКРЫТА — закрытия помечены стрелками «→» по месту, счёт закрытий не дублируется в трекер. -> **Единственный трекер — таблица «Бэклог» в `../PROGRESS.md`.** Этот файл — справочные file:line-якоря и скоуп-заметки к её строкам (родился как пост-сверка свипа D39.66, 01.08.2026; вынесен из архива решением владельца — содержимое ЖИВОЕ). Актуализируется лендингами паков, которые трогают эти строки; исполненный пункт помечать ссылкой на D-номер, не удалять. -> **Снятая мёртвая половина** (историческая улика ОТСУТСТВИЯ механизмов — снимок свипа 26.07–01.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.07–01.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:166–171: 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:201–246) знает ветки decodeErrorFinish/content_filter/refusal/length — model_context_window_exceeded не матчится ни одной: пустой выход упадёт в FlagEmpty («retryable — thinking usually ate the entire budget», строки 230–233) — платный ретрай, обречённый при 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:201–246) знает ветки decodeErrorFinish/content_filter/refusal/length — model_context_window_exceeded не матчится ни одной: пустой выход упадёт в FlagEmpty («retryable — thinking usually ate the entire budget», строки 230–233) — платный ретрай, обречённый при 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:466–474, «key … is already defined … and the overlay redefines it») — но внутрифайловые дубли схлопываются в parseCategoryRows ДО того, как merge их увидит. Ровно так это и зафиксировано открытым в отчёте: docs/archive/reports/PACK15_STRUCTURE_REPORT_2026-07-25.md:274–276 «Дубль ключа ВНУТРИ одного 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:1–4: «Фаза 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 п.4в): «альтернатива 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` размышление 170–313 ток. и флор 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` размышление 170–313 ток. и флор 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.20–0.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.20–0.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`, пункты A–F этапа 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.0–1.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.0–1.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). diff --git a/docs/architecture/14-api-contract/README.md b/docs/architecture/14-api-contract/README.md index 4b626d61..9b540c68 100644 --- a/docs/architecture/14-api-contract/README.md +++ b/docs/architecture/14-api-contract/README.md @@ -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::::` не несёт ни снапшота, ни прогона -(`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::::` не ### Ревью диффа и второе ревью 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` у клиента. Шаги 3–4 — уже в - контракте (0.3.0), шаги 1–2 — ⚠ **сжатие УЖЕ ПОСТРОЕНО в Go платформой** (`conditional.go`, греп `gzipFloor`), конфигурацией остаётся только edge, шаг 5 — зона фронта. + → скоуп в кадре → дельта-чтения `?after_version=` → `staleTime` у клиента. Шаги 1–2 ПОСТРОЕНЫ + паком P7 (D39.153), шаги 3–4 — в контракте с 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 глотает diff --git a/docs/architecture/15-money-path.md b/docs/architecture/15-money-path.md index 38a4dc51..5d1d2239 100644 --- a/docs/architecture/15-money-path.md +++ b/docs/architecture/15-money-path.md @@ -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.6–2.6×**» — ⚠ но НЕ покрывает максимум: источник (D39.165 §1) добавляет «и отдельные главы её уже пробивают» ($0.0375 против $0.03 = ×1.25), и «купить 10 глав» отдаёт движку $0.30, покупающий ~16–26 глав («денежная ручка с подписью „главы"», `PD-410`). РЕШЕНО: цена — от ОБЪЁМА ИСХОДНИКА (носитель `chapters.units_total`, пишется интейком за $0), настоящий стоп — объёмный потолок В ДВИЖКЕ (см. §2). ⛔ Константу по сегодняшним числам НЕ калибровать (D39.165 ⛔г) — гейт строка 202 бэклога (`docs/PROGRESS.md:162`=`Живой перевод книги НАСКВОЗЬ через API платформы`). Исторический провенанс: exp08 v2 $0.0219/глава → ревизия D30.4 +15–25% → округление ВВЕРХ (низкая ставка опаснее высокой — прогон встанет на потолке посреди книги; `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.6–2.6×**» — ⚠ но НЕ покрывает максимум: источник (D39.165 §1) добавляет «и отдельные главы её уже пробивают» ($0.0375 против $0.03 = ×1.25), и «купить 10 глав» отдаёт движку $0.30, покупающий ~16–26 глав («денежная ручка с подписью „главы"», `PD-410`). РЕШЕНО: цена — от ОБЪЁМА ИСХОДНИКА (носитель `chapters.units_total`, пишется интейком за $0), настоящий стоп — объёмный потолок В ДВИЖКЕ (см. §2). ⛔ Константу по сегодняшним числам НЕ калибровать (D39.165 ⛔г) — гейт строка 202 бэклога (`docs/PROGRESS.md`, греп `Живой перевод книги НАСКВОЗЬ через API платформы`). Исторический провенанс: exp08 v2 $0.0219/глава → ревизия D30.4 +15–25% → округление ВВЕРХ (низкая ставка опаснее высокой — прогон встанет на потолке посреди книги; `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. Карта носителей темы diff --git a/docs/architecture/16-events-emitter.md b/docs/architecture/16-events-emitter.md index 502011a5..5d38c0e3 100644 --- a/docs/architecture/16-events-emitter.md +++ b/docs/architecture/16-events-emitter.md @@ -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`, а не формула). \ No newline at end of file +⚠ **Прежние разделы этого файла сняты как отработанный хендофф** (D39.131, `9cfe080`): пять развилок дизайна решены (формат = одиночный JSONL · политика PD-60 = громкая деградация · fsync каталога один раз при создании · значение exit-кодов · словарь) — ответы читать в `backend/internal/runevents/journal.go` и `runevents.go`, не здесь. \ No newline at end of file diff --git a/docs/architecture/17-seam-inbound-law.md b/docs/architecture/17-seam-inbound-law.md index 387b91ba..9c715345 100644 --- a/docs/architecture/17-seam-inbound-law.md +++ b/docs/architecture/17-seam-inbound-law.md @@ -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** — «после беты формы Б». Каталогизировать их сейчас значит выдумывать. -Прецедент, разрешающий спор, — исходящее направление: там выиграла ратификация ПОЛОСЫ и ДИСЦИПЛИНЫ, -а не перечня. +Прецедент — исходящее направление: там выиграла ратификация ПОЛОСЫ и +ДИСЦИПЛИНЫ, а не перечня. ## Закон: семь пунктов diff --git a/docs/architecture/18-bank-ontology.md b/docs/architecture/18-bank-ontology.md index 7e077062..317c9fa5 100644 --- a/docs/architecture/18-bank-ontology.md +++ b/docs/architecture/18-bank-ontology.md @@ -4,11 +4,9 @@ > при конфликте побеждает журнал решений. Собрано оркестратором №19 по консилиуму со сторонним > архитектором при приёмке четырёх паков входной двери шва. > -> **Зачем страница.** Вокруг одного понятия — «состояние банка этой книги» — живут десять носителей, -> выросших пак за паком. Форма при этом СТРОГАЯ: поток однонаправленный, у каждого источника -> единственный писатель, вид пересобирается полностью на каждой границе прогона. Но эта строгость не -> была записана нигде — каждый файл документировал свою роль, ни одно место не документировало поток -> (D39.158 п.8). +> **Зачем страница.** Вокруг одного понятия — «состояние банка этой книги» — живут десять носителей. +> Форма СТРОГАЯ: поток однонаправленный, у каждого источника единственный писатель, вид пересобирается +> полностью на каждой границе прогона (D39.158 п.8). ## Четыре роли, и они не смешиваются @@ -62,8 +60,7 @@ ⚠ **КЛАСС B — другой, и путать их нельзя: межносительный инвариант, живущий комментарием без пина.** Член — порядок «карта → память» до фикс3. Он НЕ подпадает под класс A: там дефект в том, что документ не несёт контракта, здесь — в том, что связь ДВУХ носителей держится только текстом, который ничего не -проверяет. Разделено 27.08 по вычитке старшего: в одном классе они были бы неподсудны — первый же -судья отклонил бы членство порядка, и вместе с ним ушёл бы весь класс. +проверяет. ⚠ **Второй ярус КЛАССА A (D39.159): носитель с ДВУМЯ писателями и НОЛЬ читателей.** Здесь опасность не в отсутствии потребителя — она в том, что расхождение писателей ничем не судится, пока читателя нет, а в день, diff --git a/docs/glossary.md b/docs/glossary.md index cb4732fc..565f926a 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -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.5x–6x = вопросы/решения владельца по банку и промптам (D39.63 и соседние) — «Р2 = ЗНАЧЕНИЕ» из CURRENT-STATE не про принцип Р2. **H1–H18 / L1–L8** — находки стратегического аудита (`09-target-architecture.md` §3); H — HIGH, в т.ч. незакрытые владельческие требования. +- **Р-номер — ДВА смысла по контексту:** Р1–Р10 = десять ранних принципов (`01-decisions.md`, историчны); Р1–Р7 в записях эры D39.5x–6x = вопросы/решения владельца по банку и промптам (D39.63 и соседние) — «Р2 = ЗНАЧЕНИЕ» (D39.63) не про принцип Р2. **H1–H18 / L1–L8** — находки стратегического аудита (`09-target-architecture.md` §3); H — HIGH, в т.ч. незакрытые владельческие требования. - **Q1–Qn** — нумерованные вопросы КОНКРЕТНОГО пакета/отчёта — контекст локален, Q2 пака-19 ≠ Q2 чекер-пака. - **V0–Vn** — секции идей владельца в `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). diff --git a/docs/product-requirements.md b/docs/product-requirements.md index 5145e3fd..11420bbd 100644 --- a/docs/product-requirements.md +++ b/docs/product-requirements.md @@ -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); строки 69–71; F3-brief — D29 п.3. Ф3 ОТКРЫТА 02.08 (D39.81): фронт-сессия живёт на моках; контракт API ратифицирован (D39.99; ⚠ версию канона брать ФАЙЛОМ, не этой ячейкой — норма и команда в карте `README.md`. Открытыми по контракту остаются хвост строки **203** и строка **241** — самопротиворечие канона на дочитанной книге.); платформа построена до читающей поверхности и денежной двери (паки P0…P12 — реестр нот; ⚠ КВОТ нет ни строки кода, и по D39.176 п.1 не будет — продуктовых квот нет, фри-тир-лимиты не проектируются; ретеншен/свип остаются инженерной гигиеной); фронт — S0–S4 приняты, **зона ЗАМОРОЖЕНА** (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-гейт «текст местом» · стор языка с персистом · `` следует выбору; содержимое — только ru; продуктовый список языков — 🔒 владелец (В-9 зоны фронта) | ## Качество процесса и самоулучшение