From 4a1ecc3aa6f4fd42f2b322510e7f7893c158b08d Mon Sep 17 00:00:00 2001 From: heaven Date: Wed, 2 Sep 2026 11:49:07 +0300 Subject: [PATCH] Second cut pass in the docs zone: restore what the review found lost, and take the sediment the first pass left behind --- docs/ORCHESTRATOR_SESSION_PROMPT.md | 10 +- docs/POLYGON_EXP2223_REDO_SESSION_PROMPT.md | 20 ++++ docs/POLYGON_PACKAGE4_SESSION_PROMPT.md | 9 +- docs/POLYGON_PHASE_D_HANDOFF.md | 62 +++++----- docs/PROGRESS.md | 59 +++++----- docs/README.md | 8 +- docs/STACK.md | 6 +- docs/architecture/01-decisions.md | 8 +- docs/architecture/02-mvp-plan.md | 14 +-- docs/architecture/03-implementation-notes.md | 12 +- docs/architecture/04-unhappy-paths.md | 8 +- docs/architecture/05-decisions-index.md | 14 +-- docs/architecture/05-decisions-log.md | 14 +-- docs/architecture/06-memory-risk-registry.md | 18 +-- docs/architecture/09-target-architecture.md | 8 +- docs/architecture/10-prompt-architecture.md | 6 +- docs/architecture/12-go-style-notes.md | 2 +- docs/architecture/13-tech-debt-anchors.md | 114 ++++++------------- docs/architecture/14-api-contract/README.md | 112 ++++++------------ docs/architecture/15-money-path.md | 6 +- docs/architecture/16-events-emitter.md | 8 +- docs/architecture/17-seam-inbound-law.md | 19 ++-- docs/architecture/18-bank-ontology.md | 8 +- docs/glossary.md | 17 ++- docs/product-requirements.md | 21 ++-- 25 files changed, 247 insertions(+), 336 deletions(-) diff --git a/docs/ORCHESTRATOR_SESSION_PROMPT.md b/docs/ORCHESTRATOR_SESSION_PROMPT.md index 4b5f94fe..6cd322ce 100644 --- a/docs/ORCHESTRATOR_SESSION_PROMPT.md +++ b/docs/ORCHESTRATOR_SESSION_PROMPT.md @@ -66,7 +66,7 @@ D-нотами → синхронизация доков → ответы вла УКАЗАТЕЛЬ на файл, а не имя, велит сессии вписать туда себя и повторяет дословно «канала нет ⇒ НЕ искать»; эхо (блок 9) идёт первым действием по адресу из файла и служит проверкой канала. -Плюс к любому промту: **прямой канал (блок 12) — проверить, что `/tmp/textmachine-channel` написан ЭТОЙ сессией роли, а не остался от прошлой** · построчная сверка инструкций с путями/каналами ВНЕ зоны сессии против зонной +Плюс к любому промту: построчная сверка инструкций с путями/каналами ВНЕ зоны сессии против зонной таблицы CLAUDE.md (D39.99 п.4) · состав против ВСЕХ листов владельца (реестр требований · зонные журналы · его явные просьбы; пропуск подписывается пропуском) · фантом-гард: каждая цитируемая D-ссылка грепается по D-логу · mid-flight аддендумы доезжают ТОЛЬКО релеем — владелец пере-передаёт @@ -156,10 +156,9 @@ D-ссылка грепается по D-логу · mid-flight аддендум ### Лендишь? -`git status` (опознать ЧУЖОЕ; в дереве бывают ≥2 живые сессии — они живы, пока владелец не сказал -обратное, артефакты в дереве ≠ финиш) → `git diff --cached` → коммит ТОЛЬКО явным СПИСКОМ файлов -`git commit -- <файлы>`, стейдж+коммит одной командой (⚠ даже каталожный pathspec своей зоны опасен: -чужие сессии пишут ВНУТРИ `docs/`) → финал `git status --short` (pathspec не берёт untracked). +Git-дисциплина — канон `CLAUDE.md` §«Git-координация мультисессий». Сверх неё: ⚠ даже каталожный +pathspec своей зоны опасен (чужие сессии пишут ВНУТРИ `docs/`) · финал `git status --short` (pathspec +не берёт untracked) · артефакты в дереве ≠ финиш. Мутации — только на закоммиченном дереве; в Bash — абсолютные пути. `docs/README.md` (состав активных промтов) — тем же коммитом (D39.80). Перед ратификационным коммитом: `counts.py --check` и `--lint`. Самоаудит диффа ДО показа владельцу: полный дифф глазами как чужой отчёт · числа к первоисточнику · @@ -224,7 +223,6 @@ Y»), а не «посмотри». По умолчанию **Fable 5**, при дифф, если менялись только версии/хеши. - Прод-инъекцию воспроизводить `tmctl translate` + `LOG_LLM_BODIES` байт-диффом (не по `injected_ids`); порт-зеркала — «при расхождении верить Go». -- `/tmp` волатилен — рабочее временное клади туда, где оно переживёт перезапуск. - Промт-архивация: только отработанные, с баннером-исходом; residual-трекеры держать активными. ## Чего НЕ делать diff --git a/docs/POLYGON_EXP2223_REDO_SESSION_PROMPT.md b/docs/POLYGON_EXP2223_REDO_SESSION_PROMPT.md index 45580d82..196f74eb 100644 --- a/docs/POLYGON_EXP2223_REDO_SESSION_PROMPT.md +++ b/docs/POLYGON_EXP2223_REDO_SESSION_PROMPT.md @@ -205,3 +205,23 @@ sol-border, эксп-23 §12в). Закрытие пункта = **непуст отдельной таблицей, включая опровержения. CONFIRM/DENY владельцу — только с артефактом-носителем. Деньги: итог по фазам двумя путями. Пинг в `docs/PROGRESS.md` секция «Полигон» при закрытии. Запуск — по слову владельца; первым сообщением сессии сверить санкцию потолка $10.00. + +--- + +> ⚠ **ЗАКАЗ ЖИВОЙ, НО ЧЕТЫРЕ ЕГО СОБСТВЕННЫХ ФАКТА ДЕРЕВО УЖЕ ОПРОВЕРГЛО** (приписка ревизии доков +> 02.09; тело выше НЕ тронуто и трогать его нельзя — на его НОМЕРА СТРОК ссылаются код и отчёт: +> `eval/dovodka/runs.py` цитирует строку 25 как источник капа, заголовки секций Д2 · Д5 · Д8 отчёта +> `docs/experiments/23-editor-tier.md` цитируют диапазоны строк заказа, а `eval/dovodka/requirements.md` +> объявлен прочитанным ПОСТРОЧНО и выводит отсюда 77 строк реестра, сверяемых conformance-гейтом. +> Любая резка сдвинула бы всё это молча, поэтому поправки — списком здесь, а не в теле.) +> +> * **Строка 25, «кап агент-сессий: 80» — СНЯТ владельцем 15.08.** Живое число — `CAP` в +> `eval/dovodka/runs.py`; там же комментарием над ним вся история подъёмов и их основания. +> * **Строка 17, «отчёт фазы — секции Д0–Д8»** — состав давно шире; считать командой +> `grep -c '^## Д' docs/experiments/23-editor-tier.md`, а не читать отсюда. +> * **Строка 112, японский материал `isekai_majutsushi_jp` — ЗАМЕНЁН** на `enkan_no_hate_ja` +> санкцией владельца 15.08 (D39.136 п.1а; тем же словом снят СТОП ja-оси). Прибор отбора и +> причина замены — `eval/dovodka/material_ja.py`. +> * **Пакетный потолок фазы $10.00 (строки 20 и 207) — НЕ ТЕКУЩИЙ.** Фактическая цепь потолков +> живёт в `eval/dovodka/money_d.py` (`PACK_CEILING`/`CEILINGS`), подъёмы шли рукой владельца +> напрямую полигону (D39.136 п.1а). Санкцию ПЕРЕД покупками сверять там и словом владельца. diff --git a/docs/POLYGON_PACKAGE4_SESSION_PROMPT.md b/docs/POLYGON_PACKAGE4_SESSION_PROMPT.md index 07dc06d0..43630f8b 100644 --- a/docs/POLYGON_PACKAGE4_SESSION_PROMPT.md +++ b/docs/POLYGON_PACKAGE4_SESSION_PROMPT.md @@ -4,7 +4,7 @@ > **Дельта 01.08 №2 (свип полноты D39.66):** при переупаковке в пилот-преп-промт добрать строку 85 бэклога — Bertalign GOLD-пары + spot-check (D29.2в) · fidelity-каскад R2 shadow (D25.2) · exp08 v3 (D21.8); echo-калибровка D25.7 остаётся здесь residual-ом (не потеряна). > **Что уже отработано:** как отдельная сессия пакет №4 НЕ запускался; исполнена только **Задача 1** (сид-мн.ч. → сид v2 внутри exp13, D32), а **Задача 4 в части P4 fidelity-хвоста ЗАКРЫТА D39.61 — не исполнять**. > **ЖИВОЙ residual — Задачи 2/3/4 ниже**, ПИЛОТ-трек: ортогонален бэкенд-курсу, в бэкенд-паки НЕ вносить. Из него НАЗВАННЫМ БЛОКЕРОМ пилота остаётся судья-дублёр 18+ (п.2ж, D22.6; бэклог — строка 64). При активации пилот-препа residual переупаковывается в свежий промт — или гони отсюда, слаги судей брать live-фактчеком `/models`. -> Гигиена D39.20: авто-QA слепых пакетов ключевать слепыми метками. 18+: только существующие артефакты `eval/data`, счётчики/метаданные в отчёт. +> Гигиена D39.20: авто-QA слепых пакетов ключевать слепыми метками. --- @@ -24,9 +24,9 @@ > Влито в `guzhenren-seed-v2.yaml`; императив относился к МЁРТВОМУ `guzhenren-seed.yaml` v1 и снят: > правка v1 = работа впустую плюс смена content-hash памяти и лишний resnapshot. Тело задания, если -> понадобится провенанс, — D24.4 (мн.ч. в `decl.forms` против ложных промахов inflection_gap) и -> D24.2 (alias-слепое пятно post-check — занесено в `docs/architecture/06-memory-risk-registry.md`, -> греп «Alias-слепое пятно», вместе с репро 古月方源 → «гу юэ»). +> понадобится провенанс, — D24.4 и D24.2 (alias-слепое пятно post-check — занесено в +> `docs/architecture/06-memory-risk-registry.md`, греп «Alias-слепое пятно», вместе с репро +> 古月方源 → «гу юэ»). ### 2. Fix-лист D22.8 (major-часть) @@ -49,6 +49,5 @@ ## Дисциплина - Пробы за деньги — центы, по пре-регистрации; Python-зеркало ↔ Go: при расхождении верить Go; transient-прогоны в чужой зоне — только в копиях вне дерева (D22.10). -- Аномалия провайдера → официальная вендор-дока, НЕ гадание (шапка quirks); слаги — live-фактчек `/models`. - `.env` не читать; `eval/data/*corpus*` — только по прямой задаче (п.2ж — метаданные/счётчики); `/home/ubuntu/books/` тексты в доки не цитировать. - Отчёт: секция в `docs/PROGRESS.md` «Полигон» — числа, провенанс артефактов, вопросы. Не коммитить. diff --git a/docs/POLYGON_PHASE_D_HANDOFF.md b/docs/POLYGON_PHASE_D_HANDOFF.md index df52c873..42f4bae8 100644 --- a/docs/POLYGON_PHASE_D_HANDOFF.md +++ b/docs/POLYGON_PHASE_D_HANDOFF.md @@ -10,8 +10,8 @@ > **Снимок ПОДРЕЗАН 02.09** (ревизия доков): снято то, что дерево с тех пор опровергло или > исполнило — маршрут онбординга, числа 15.08, закрытые пункты «что осталось», денежная рамка. > Куда снятое уехало: записи полигона 15.08 — `archive/PROGRESS-2026-08-10-15.md` · числа и -> вердикты — `docs/experiments/23-editor-tier.md` (секции грепаются `grep '^## Д'`) · фактическая -> цепь потолков — `eval/dovodka/money_d.py` (`PACK_CEILING`/`CEILINGS`), а не текст. +> вердикты — `docs/experiments/23-editor-tier.md` · фактическая цепь потолков — +> `eval/dovodka/money_d.py` (`PACK_CEILING`/`CEILINGS`), а не текст. > > Что в файле по-прежнему полезно: устройство приборов, грабли отладки и незакрытое требование Д5. > Приёмка фазы — у ПАРАЛЛЕЛЬНОГО оркестратора. @@ -23,8 +23,10 @@ ## 1. Старт -1. `CLAUDE.md` → `docs/POLYGON_EXP2223_REDO_SESSION_PROMPT.md` — **заказ, 207 строк, читать - ЦЕЛИКОМ**. Прошлая сессия читала грепом и потеряла целый пункт заказа (внешнюю подпись Sol). +1. `CLAUDE.md` → `docs/POLYGON_EXP2223_REDO_SESSION_PROMPT.md` — **заказ, читать ЦЕЛИКОМ**. + Прошлая сессия читала грепом и потеряла целый пункт заказа (внешнюю подпись Sol). В конце заказа + — приписка-эррата 02.09: четыре его факта (кап 80 · состав секций · ja-книга · потолок) дерево + опровергло, тело при этом не правится. 2. **Живой носитель курса — в `eval/dovodka/`** (планы 16.08 → 22.08, ревью, консилиум); какой из них живой, называет зона. Онбординг под него лежит в самом плане (`PLAN-22-08.md`, §0). 3. Отчёт `docs/experiments/23-editor-tier.md` — состав секций с 15.08 вырос, грепать @@ -38,11 +40,11 @@ | что | где | |---|---| | код | `textmachine/eval/` | -| **сырьё и судейство** | `~/books/` — **отдельный git-репозиторий**, закоммичен целиком (`4c3ff02`, 1295 файлов) | +| **сырьё и судейство** | `~/books/` — **отдельный git-репозиторий**, закоммичен целиком (`4c3ff02`, 1295 файлов — снимок 15.08, не пере-снимался) | | клетки фазы | `~/books/dovodka/dv-*.json` (579) + карантин `.ERROR .LENGTH .TWIN .STALE` | | слепые ключи | `~/books/dovodka/blind-keys-{d1,d3,d4,d6}` и `-sol` — **по семействам**; соль отдельными `SALT-*.txt` | | судейство | `~/books/judging/sud-{d1,d3,d4,d6}` (claude) и `sol-*-work` (Sol) | -| **адъюдикация zh** | `~/books/judging/adjud-d4/` (7 заданий, 7 ответов) + ключ истины `~/books/dovodka/adjud-key.json` — **адъюдикатору НЕ давать** | +| **адъюдикация zh** | `~/books/judging/adjud-d4/` (154 претензии → 7 заданий, 7 ответов) + ключ истины `~/books/dovodka/adjud-key.json` — **адъюдикатору НЕ давать** | | внешняя подпись Sol | `~/books/editor-tier/sol-tier/` (16), `sol-border/` (32) | | банки | `role-topology/bank-en.json` · `dovodka/bank-ja.json` · `tenant-panel/bank.json` (zh) | | журнал gemini | `~/books/dovodka/d1-attempts.jsonl` | @@ -58,11 +60,11 @@ Числа фазы живут в отчёте `docs/experiments/23-editor-tier.md`, и с 15.08 они ПЕРЕ-СУЖЕНЫ: вердикты двух семейств — Д13.1 · панели осей — Д3 / Д6 / Д1 · сводка «пробел → чем закрыт» — Д9 · пере-суд починенным прибором — Д15 и дальше. ⚠ Копия таблиц, стоявшая здесь, местами уже -расходилась с отчётом (Д6: `D0` **5.44** в отчёте против 5.11 в копии; `E4` 1.28 против 1.38) — -снята: у числа один носитель, и это отчёт. +расходилась с отчётом и снята: у числа один носитель, и это отчёт. **Деньги:** фактическая цепь потолков — `eval/dovodka/money_d.py` (`PACK_CEILING`/`CEILINGS`), -механизм её подъёмов — отчёт Д14.9; рамка заказа $10.00 — сам заказ, §«Статус и рамка». +механизм её подъёмов — отчёт Д14.9. ⚠ $10.00 в заказе — ИСХОДНАЯ рамка 10.08, с тех пор +поднятая: сверять цепь, а не заказ (приписка в конце заказа). --- @@ -71,7 +73,9 @@ **Сессии:** 1. **Адъюдикация английской оси** — П-1 требует при расхождении семейств, файлов нет. Единственное, что блокирует несущий вывод. Запуск: `eval/.venv/bin/python eval/dovodka/adjud.py`; контроли, - дефектные на 15.08, починены и закрыты гейтом `--controls` (отчёт §Д14.8). + дефектные на 15.08, починены и закрыты гейтом `--controls` (отчёт §Д14.8). ⚠ **Починка живёт на + ветке `polygon`; в `main` файл ПРЕ-ФИКС** — грепа `--controls` там нет, дефектный регекс разбора + осей стоит живым. Перед прогоном сверить наличие гейта: нет его — не запускать. 2. **Д5 — требование заказа НЕ ИСПОЛНЕНО** (секция в отчёте есть, требование — нет). Места потерь отсняты честно (`~/books/dovodka/canon-dissect.json`, 24 записи), но КЛАССИФИКАЦИЯ мест негодна: поле `why` несёт случайное слово окна. Честное закрытие — ручная пере-классификация 24 мест @@ -107,9 +111,9 @@ 5. **Гард отказывает по ОЖИДАЕМОЙ цене**, втрое выше фактической ($0.028 против $0.0092). Решать по срабатыванию гарда, а не по смете. 6. **Новый суффикс карантина — сразу в глоб свода.** `.STALE`/`.TWIN` не были вписаны, и цена - `E3` печаталась $0.00528 вместо $0.00644 (пять нулевых клеток тянули медиану). -7. **Порог различимости — свойство СЕМЕЙСТВА, а не оси.** Пол Sol шире на всех трёх осях при не - меньших оценках эффекта. Сравнивать «перешёл/не перешёл» без сверки полов — ошибка. + `E3` уехала вниз: пять нулевых клеток тянули медиану (числа — отчёт §Д13.4). +7. **Порог различимости — свойство СЕМЕЙСТВА, а не оси** (§Д13.3). Сравнивать «перешёл/не + перешёл» без сверки полов — ошибка. 8. **Классы маржевых посадок пар-зависимы.** Подобранные на китайском (числительные) на английском ложатся 5/16, на японском 4/9. Рабочий класс — «подмена принадлежности» (`его`→`её`): en 15/16, ja 8/9. Флаг `--wide-plants`, **только для новых эмиссий** (декой восстанавливается при разборе). @@ -153,8 +157,7 @@ * **Флаги разбираются на уровне модуля из `sys.argv`** — при импорте поведение зависит от argv вызывающего. Я этим пользовался; хрупко и неочевидно. * **`sud.py` грузит `ja_axis.py` под именем `en_axis_sud`** — работает, имя врёт. -* **`itog_d4.py`: `KEYS = KEYS_D4`** — алиас вместо второй переменной (сам дубль и был багом); - там же `_dead` — пустой остаток рефактора, удалить при первой правке. +* **`itog_d4.py`: `KEYS = KEYS_D4`** — алиас вместо второй переменной (сам дубль и был багом). * **`sud.py:setup`: `FLOOR_HOOK=lambda u: (… if False else None)`** — мёртвая ветка. * **`bank.py`: `sys.modules.setdefault("para", …)` + `exec_module`** — при уже загруженном `para` исполнится второй экземпляр. Отмечено вычиткой, не починено. @@ -164,31 +167,20 @@ ## 8. Дисциплина, которой я не держал -* **Не объявлять закрытие по памяти — инвентаризовать диск.** Так потерялся Sol: в отчёте стояло - «каталог ответов пуст», а там лежало 16 ответов с результатом против вывода пака 23. -* **Читать заказ на АРТЕФАКТЫ, а не только на требования:** «а не сделано ли уже?». -* **Вести зонный журнал ПО ХОДУ**, не в конце. -* **Закрывать судейские сессии** `runs.py --done` сразу после ответов. -* **Полигон коммитит только пре-рег-фризы**, основание вслух ПЕРЕД каждым; обязательны лишь фризы - ПОКУПАЮЩЕГО кода. +* **Инвентаризовать диск, а не объявлять закрытие по памяти.** Так потерялся Sol: отчёт писал + «каталог ответов пуст», а лежало 16 ответов против вывода пака 23 (разбор — §Д11). +* **Вести зонный журнал ПО ХОДУ**; судейские сессии закрывать `runs.py --done` сразу после ответов. +* **Обязательны лишь фризы ПОКУПАЮЩЕГО кода**, основание вслух ПЕРЕД каждым. --- ## 9. Новые файлы фазы -`para.py` (провайдер пары: письменность, банк, промты, парсер числительных, конформность имён, -снятые классы флагов) · `en_axis.py` · `ja_axis.py` · `d1_gemini.py` · `d7_self.py` · -`prompts/{en-ru,ja-ru}/terminologist.md` — **их не существовало, банк новой пары собрать было -нечем**. - -Существенно переписаны: `contour.py` (пара как параметр, диспетчер армов по ВИДУ контура, общая -покупка баз, пол по оси, бюджет вывода, карантин) · `sud.py` (ось и семейство как параметры, -гейты близнеца и пустых половин пола, пар-зависимые посадки) · `itog_d4.py` · `bank.py` · -`battery.py` (хуки пары) · `pair_en.py` · `contam_d.py` (платный путь с нуля) · `promptdiff.py` · -`sessii.py`. +Состав каталога читается `ls eval/dovodka/` (39 файлов) — перечень «создано / существенно +переписано», стоявший здесь, им и заменяется. Существенно одно: провайдера пары `para.py` и +пар-промтов **не существовало, банк новой пары собрать было нечем**. ⚠ `prompts-free/{en-ru,ja-ru}/` — свободные редакции от Fable-5, **в замер НЕ входят**. -⚠ Память машины пополнена тремя записями: фриз-гейт смотрит на покупающий файл · деньги при -срабатывании гарда, не по смете · файл клетки ≠ годная клетка. Память машинно-локальна; общие -уроки — в промт. +⚠ Три урока фазы (§5 пп.3–5) записаны и в память машины. Память машинно-локальна и в +репозиторий не едет — общие уроки класть в промт, а не в неё. diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index c8520341..680035a7 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -1,15 +1,15 @@ # Журнал прогресса -> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 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**; строк бэклога «скоро» **54**, открытых рядов регистра платформы — 97 (major 2) ⚠ (было 55: ревизией 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, №20 закрыт нотой D39.177; ⚠ **пак P12 ПРИНЯТ И ЗАЛЕНДЖЕН 31.08 — D39.180**, вместе с контрактным минором **0.9.0**; `PD-425` закрыт им же. ⚠ **ДВА ЛЕНДИНГА 31.08:** бэкенд-пак **«ДЕНЬГИ И ЧЕСТНОСТЬ ВЫДАЧИ» — D39.182** (приёмка 5 линз, 3 блокера / 15 major / 12 minor, ⚠ два блокера были дефектами В САМОМ ЛЕКАРСТВЕ; тестов 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 · epubcheck 0/0/0/0 · строки 154/198/239/240. ⚠ **Причина большой доли редактора НЕ УСТАНОВЛЕНА** — три каузальные истории построены и две сняты. ⚠⚠ **Число «73%» ИСПРАВЛЕНО 02.09: в отчёте его НЕТ НИ РАЗУ** (греп `73%` по `archive/reports/COLDRUN_V16_REPORT_2026-08-31.md` → 0). Отчёт даёт долю с ДВУМЯ знаменателями: **49.3%** от всего прогона ($0.214865 из $0.436110) и **81.3%** внутри порции П1. Следующий шаг — контролируемая проба по ЧЕТЫРЁМ осям (§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 (снято командами 30.08, не чтением):** работа полигона лежит коммитом `28c2d0f` на ветке `polygon`, запушена, в `main` НЕ влита — `git status -- eval/` в main-дереве пуст ПО ПОСТРОЕНИЮ и уводит в ложный вывод «работы нет»; `origin/main` остаётся ПРЕДКОМ `main`, расхождения нет (`git merge-base --is-ancestor origin/main main` + `git rev-list --left-right --count main...origin/main` — правая цифра 0). +> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 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-дереве пуст ПО ПОСТРОЕНИЮ и уводит в ложный вывод «работы нет»; `origin/main` остаётся ПРЕДКОМ `main` (`git merge-base --is-ancestor origin/main main`). > - ⚠ **Норма приёмки, купленная аудитом 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 по словарю кодов — не отменён, ждёт разморозки) · закрытые стройки эры — лентой нот: эмиттер D39.131 · P5/P6 D39.130/132 · migrate D39.134 · S4+0.2.3 D39.135 · DeepSeek-репин D39.137 (тела — D-лог и слайсы). -> - **Открыто на владельце:** **после пака «писатель книги» (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 (вкладка «Замечания»). Закрытые пункты листа (PD-104 · В-10 · В-11-форма · Ф-56/57/61/62/63 · Ф-28 · ПТ-33-граница · 116 · 126 · 172-пин · PD-203 · санкции фазы Д · дизайн 160/161 · title) — в нотах D39.136–145, здесь не держатся. +> - **ЖИВОЕ:** полигон — **фаза Д ИДЁТ** (заказ 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, здесь не держатся. > - **Сделано (сводно)** — снимок ленты закрытых эр в [archive/PROGRESS-2026-08-04-09.md](archive/PROGRESS-2026-08-04-09.md); детали — D-лог и слайсы. -> - **Курс:** ОБЩНОСТЬ ✅ → КАЧЕСТВО БАНКА ✅ → ПАКЕТ-ЧЕКЕРОВ ✅ (D39.59–78) → **ФРОНТ-ЭРА** (D39.81–100: зоны живые, контракт API ратифицирован) → **шов/платформа/движковые блокеры построены** (D39.106–123). Хвосты курса живут строками: 16 (полная цена холодного старта; edit-волна на малых прогонах отработала и оплачена — 58 вызовов волновым драйвером 23–25.07 плюс 648 до драйвера, счёт по леджерам `~/books/gu-zhenren/**/*.db`; держит и оси голоса 13б/24) · 46 (дизайн заморожен D39.92/93, промт ждёт выдачи) · coldrun-b фаза C заморожена чекпойнтом легитимно (D39.86; эталон денег/поведения — coldrun-a, read-only); развилка 0731 решена и исполнена (D39.87/91, код `553f1a3`). +> - **Курс:** этапы ОБЩНОСТЬ · КАЧЕСТВО БАНКА · ПАКЕТ-ЧЕКЕРОВ · ФРОНТ-ЭРА · шов/платформа/движковые блокеры — ПРОЙДЕНЫ (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 залендены). -> - **Стек (полная карта роль→модель→конфиг→квирки — [STACK.md](STACK.md), D39.126):** draft deepseek-v4-flash thinking-ON `low` **⚠0731** → терминолог (та же модель) → editor deepseek-v4-pro БИЛИНГВ ИНТЕРИМ (топология ПОДТВЕРЖДЕНА при неразличимости жильцов — D39.117; закон-блок ОБЯЗАТЕЛЕН — строка 134; glm-5 резерв; вахта маппинга эффорта pro — §Б-108) → судья gemini (Ф2, в движке НЕ построен — строка 33); канал B Mistral+grok; ~$0.85/ранобэ (D30.4) — ⚠ **ТРИГГЕР ПЕРЕ-КАЛИБРОВКИ СРАБОТАЛ 31.08** (испр. 02.09): платный прогон отработал и дал собственную оценку движка `projected_book_usd = 1.1377277707` на десяти главах при куплённых $0.436110; число D30.4 держать как июльское. ⚠ **Вендор-факты 13–15.08 (пере-пин ИСПОЛНЕН и ПРИНЯТ, D39.137):** таблица цен запинена ПИКОМ (flash 0.44/1.32 · pro 1.32/3.96/кэш-хит 0.044 за 1M; счёт шиппинг-c1 = 100% DeepSeek ⇒ ×4.2–4.4 в пике / ×2.1–2.2 в долине — замер по трём прогонам); ⚠ про эффорт pro НОСИТЕЛИ ПРОТИВОРЕЧАТ и это НЕ РЕШЕНО: квирк-канон и `STACK.md` говорят «ручки у pro НЕТ», замера поведением после 13.08 нет ни у одной стороны, и по гардрейлу владельца такое закрывается ВЕНДОР-СВЕРКОЙ, а не выбором стороны; до неё в силе канон, разбор — `STACK.md` строка редактора; ⚠ ВЕСА pro сменились под тем же слагом (V4-Pro-0813, класс D39.61) — вахта-риг готов (остаток 172); ⚠ посылка интерим-редактора «dspro дешевле glm» в пике ПЕРЕВЁРНУТА (×1.26 дороже — вход ратификации фазы Д, D39.137 п.4); покупки фазы Д на deepseek до 16.08 16:00 UTC — по старым ценам. ⚠ **ВЕСЬ банковый контур (банкнота+терминолог+классификатор) в shipping-c1 НЕ включён** — жив ран-локальным конфигом книги (строка 140; сверка STACK.md 09.08 — факт шире прежней декларации «одна банкнота»); эскалация в shipping за `budget_usd: 0` (STACK.md §примечания). +> - **Стек (полная карта роль→модель→конфиг→квирки — [STACK.md](STACK.md), D39.126):** draft deepseek-v4-flash thinking-ON `low` **⚠0731** → терминолог (та же модель) → editor deepseek-v4-pro БИЛИНГВ ИНТЕРИМ (топология ПОДТВЕРЖДЕНА при неразличимости жильцов — D39.117; закон-блок ОБЯЗАТЕЛЕН — строка 134; glm-5 резерв; вахта маппинга эффорта pro — §Б-108) → судья gemini (Ф2, в движке НЕ построен — строка 33); канал B Mistral+grok; ~$0.85/ранобэ (D30.4) — ⚠ **ТРИГГЕР ПЕРЕ-КАЛИБРОВКИ СРАБОТАЛ 31.08** (испр. 02.09): платный прогон отработал и дал собственную оценку движка `projected_book_usd = 1.1377277707` на десяти главах при куплённых $0.436110; число D30.4 держать как июльское. ⚠ **Вендор-факты 13–15.08 (пере-пин ИСПОЛНЕН и ПРИНЯТ, D39.137):** таблица цен запинена ПИКОМ (flash 0.44/1.32 · pro 1.32/3.96/кэш-хит 0.044 за 1M; счёт шиппинг-c1 = 100% DeepSeek ⇒ ×4.2–4.4 в пике / ×2.1–2.2 в долине — замер по трём прогонам); ⚠ про эффорт pro носители ПРОТИВОРЕЧАТ, до вендор-сверки в силе канон — разбор строкой **237**(б); ⚠ ВЕСА pro сменились под тем же слагом (V4-Pro-0813, класс D39.61) — вахта-риг готов (остаток 172); покупки фазы Д на deepseek до 16.08 16:00 UTC — по старым ценам. ⚠ **ВЕСЬ банковый контур (банкнота+терминолог+классификатор) в shipping-c1 НЕ включён** — жив ран-локальным конфигом книги (строка 140; сверка STACK.md 09.08 — факт шире прежней декларации «одна банкнота»); эскалация в shipping за `budget_usd: 0` (STACK.md §примечания). > - **ЕДИНЫЙ БЭКЛОГ — секция «Бэклог» ниже** (одна таблица, единственный трекер; каждая петля обязана иметь диспозицию: решено / отложено-с-записью / отклонено; ведёт оркестратор). **СЧЁТ ОЧЕРЕДИ на 30.08 (скриптом по таблице — `python3 docs/scripts/counts.py`; обновлять при каждом лендинге):** всего **186** строк · зона бэкенд **85** строго / **121** широко (⚠ колонки счётчик читает С КОНЦА — испр. D39.116) · **блокеров очереди 0** (236 закрыта D39.175), платные прогоны разблокированы · «скоро» **54** (перечень — грепом по таблице, рукописный список снят D39.126) · гейт-строки эксп-22: 55·153 (плюс 150 — руки владельца); строка 5 — остаток гейчен ре-пробой 74, носитель события теперь строка 188 (аудит D39.140); остальное «когда-нибудь». ⚠ Счёт — НИЖНЯЯ граница долга, не потолок (разбор — легенда таблицы ниже). > - Архивы хроники: `archive/PROGRESS-2026-07-04-10.md` (D31) · `-10-13` (D39.6-гигиена) · `-13-25` (стройка паков 11–16, rerun2) · **`-25-31` (паки 17–20 · мини-прогон · полигон-пакеты 5–8 · ToS · холодный прогон; D39.26–58)** · **`-08-01-02` (сессии №9/№10: общность · качество банка · coldrun-b · открытие фронта/платформы; D39.59–90, срез D39.105)** · **`-08-02-04` (сессии №11–№13: ручки эффорта · стандарты · контракт API · платформа P0 · банк-арбитраж; D39.91–105 + снимок шапки эры №15)** · `-08-04-09` (пинги закрытых паков эры №15) · **`-08-14-15` (закрытые бэкенд-записи №16–17: эмиттер шва · migrate · пере-пин DeepSeek; вынесено D39.139)**. Записи ниже — живой хвост (№16+, эра D39.124+; подрезка D39.139). @@ -58,7 +58,7 @@ | 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; на малых прогонах гонялась и оплачена); цена холодного старта измерена ДО редактуры (драфт+банкнота $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 | Полная цена холодного старта: 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** | | 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) —** | | | | | | @@ -145,8 +145,8 @@ | 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 | | 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. Пункты (а) «P7 разблокирован» и (в) «вопрос владельцу про `BankTerm.decision`» СНЯТЫ (P7 заленджен D39.153; вопрос снят 16.08 как стоящий на ложной посылке, 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: он в ШЕСТИ промптах пары, а не в трёх — `editor.md` · `translator.md` · `translator-banknote.md` · `terminologist.md` · `editor-mono.md` · `classifier.md`; перечень был неполон уже при внесении, сверка одной командой: `grep -rln "{{genre}}" backend/prompts/`) + поле из канона брифа: двигает `BriefHash` ⇒ ТОЛЬКО в общее resnapshot-окно, координировать со 161/182, дешёвое окно пока платная книга одна; (б) фронтовая — форма при разморозке; влияние жанр-строки на качество не измерено и уже не будет | бэкенд (+платформа/контракт/фронт) | скоро (движковая половина — resnapshot-окном) | касание в окне 161/182 + батч 183 | research/28 Б-23/§8 п.6, D39.138 п.2в | +| 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_DIRECTION.md:202-205`), семантика — в спеку батчем 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 | @@ -160,8 +160,8 @@ | 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:516`=`различать причины отказа клиент не может по замыслу`) · (д) клетка приложения А заполнена `unspecified` (`README.md:1376`) · (и) поле `stop_requested` (D39.152) · (л)(м)(н)(о) — контрактной сессией (остаток по фразам Приложения А несёт строка **204** и лист владельца) · **(г) наполовину** — `unspecified` ратифицирован в каноне (`docs/architecture/14-api-contract/openapi.yaml:1903`=`unspecified` is reserved`; адрес пере-нацелен 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 в лог, то есть деградация честная, но карта протухнет незаметно. Лечение: движок публикует свой словарь причин артефактом-данными (тем же классом, что манифест и сайдкары банка), платформа читает его вместо копии. ⚠ Носителем был ТОЛЬКО регистр платформы (PD-246) — то есть обязательство к зоне движка жило внутри зоны автора; поймано ревьюером полноты выгрузки при лендинге | бэкенд | когда-нибудь (со следующим касанием эмиссии флагов) | отдельное решение | приёмка P7 (D39.153), релей §7(в) | +| 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`=`unspecified` is reserved`; адрес пере-нацелен 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 | | 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 | @@ -268,7 +268,10 @@ > Пак ПРИНЯТ И ЗАЛЕНДЖЕН — **D39.182** (`bb541a8`); закон раскрытия ратифицирован владельцем — **D39.181**; > четыре строки бэклога закрыты тем же лендингом — **D39.185**. Доказательная база и ВСЕ пинги сессии живут > файлами зоны: `backend/docs/MONEY_HONESTY_REPORT.md` (§7 — пинги оркестратору, §9 — десять экземпляров -> закона по одному, §0.1 — батарея и дифф `^func Test`, §6.2 — адверсариальный проход), +> закона по одному, §0.1 — батарея ИСПОЛНЕНИЕМ, **§5.1 — разложение покупок П1/П2/П3**: ось пере-покупки +> терминолога = БАЙТЫ БАТЧА, а не сдвиг снапшота — это и есть «пинг №2», которым D39.185 п.1 адресует сюда; +> ⚠ §6.2 «адверсариальный проход» и дифф `^func Test` в отчёте БОЛЬШЕ НЕ ЖИВУТ — сняты ревизией доков 02.09, +> и счёт тестов 1045→1083 при нуле удалённых держит теперь только шапка CURRENT-STATE), > `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 закона опровергает себя) · @@ -277,25 +280,19 @@ ## Полигон **📌 ПИНГ ПОЛИГОНУ от оркестратора №19 (28.08, D39.164) — вендор-вердикт по Gemini для `docs/experiments/00-provider-quirks.md`.** -Материал добыт бэкенд-сессией (curl по вендор-доке, не пересказ), но файл — ВАША зона, поэтому вписываете вы, а не я. Строка 157 сегодня -несёт три утверждения сильнее, чем даёт источник: -- ⚠ **«слой ФИЗИЧЕСКИ не может пронести больше одного системного» — переоценка.** Вендор даёт структурный факт: в - `GenerateContentRequest` поле `systemInstruction` — ОДИН `object (Content)` (в той же таблице `contents[]` и `tools[]` несут суффикс - повторяемого поля), а `Content.role` документирован как «Must be either 'user' or 'model'». Что делает с двумя системными - OpenAI-совместимый ШИМ — вендор НЕ документирует нигде: раздел «Current limitations» молчит и в живой странице - (ai.google.dev/api/generate-content, помечена 2026-08-17, снято 2026-08-28), и в снимке Wayback 2026-08-21. -- ⚠ **`Content.parts[]` — ПОВТОРЯЕМОЕ поле,** и вендорская заметка на самом `systemInstruction` гласит «Only text should be used in parts - and content in each part will be in a separate paragraph». То есть нативный API МОЖЕТ нести N системных текстов как N частей ОДНОГО - `Content`; вывод «уход на нативный API проблемы не решает» верен по сути (склеивать всё равно пришлось бы), но не по причине. -- ⚠ **«форум Google» — НЕ вендорский источник.** Тред `discuss.ai.google.dev/t/86097` — два поста, оба от НЕ-сотрудников (staff=false), - 30.05.2025, ответа Google нет. Сейчас читается как авторитет наравне с нашим замером. -**Что остаётся ОТКРЫТЫМ честно:** «выживает ровно одно» против «не выживает ни одного» не разрешено. Твёрдо установлено: НЕ склеиваются -(`prompt_tokens` схлопнулись 2994 → 535) и first-wins ложно. Причина неразрешимости — в самой пробе: маркер приписан к `msgs[0]`, поэтому его -отсутствие одинаково совместимо с обоими чтениями, а зеро-системного контроля в скрипте нет. **Дешёвое решающее доизмерение, если возьмётесь:** -тот же скрипт, маркер на ПОСЛЕДНЕЕ системное плюс user-only базовая клетка. ⚠ Отдельная граница: проба гонялась на `gemini-3.1-flash-lite`, а в -цепочке эскалации стоит `gemini-3.1-pro-preview` — слой тот же, слаг другой. -**Для движка это уже безразлично:** склейка на нашей стороне — единственная форма, которая потерять не может, и она заленджена (D39.164); -вендор-ссылка с датой вписана прямо в `configs/models.yaml` у провайдера `gemini`, чтобы следующая сессия не переоткрывала. +Материал добыт бэкенд-сессией (curl по вендор-доке, не пересказ), но файл — ВАША зона, вписываете вы. ⚠ Вендор-основание +ДОСЛОВНО, со ссылкой и датами снятия, уже лежит в `backend/configs/models.yaml` у провайдера `gemini` (греп +`ВЕНДОР-ОСНОВАНИЕ`) — сюда не переписываю. **Строка 157 квирков несёт ТРИ утверждения сильнее источника:** (1) «слой +ФИЗИЧЕСКИ не может пронести больше одного системного» — вендор говорит про НАТИВНЫЙ `systemInstruction`, а что делает с +двумя системными OpenAI-совместимый ШИМ, не документирует нигде; (2) «уход на нативный API проблемы не решает» — верно по +сути, не по причине: `Content.parts[]` ПОВТОРЯЕМОЕ, и нативный API МОЖЕТ нести N системных текстов как N частей ОДНОГО +`Content`; (3) «форум Google» — НЕ вендорский источник: тред `discuss.ai.google.dev/t/86097` — два поста, оба от +НЕ-сотрудников (staff=false), 30.05.2025, ответа Google нет, а читается наравне с нашим замером. +**Открыто честно:** «выживает ровно одно» против «не выживает ни одного» не разрешено — маркер пробы приписан к `msgs[0]`, +и его отсутствие совместимо с обоими чтениями, а зеро-системного контроля в скрипте нет. Твёрдо: НЕ склеиваются +(`prompt_tokens` 2994 → 535) и first-wins ложно. **Дешёвое решающее доизмерение:** тот же скрипт, маркер на ПОСЛЕДНЕЕ +системное плюс user-only базовая клетка. ⚠ Граница: проба гонялась на `gemini-3.1-flash-lite`, а в цепочке эскалации стоит +`gemini-3.1-pro-preview` — слой тот же, слаг другой. Для движка безразлично: склейка на нашей стороне заленджена (D39.164). **ИТОГ ПОЛИГОН-СЕССИИ 23.08 — ШАГ 1 ПЛАНА 22.08 ЗАКРЫТ (панель-0, $0).** Отчёт целиком — секция **Д32** `docs/experiments/23-editor-tier.md`; фризы `bedc39a`, `9e33a1b`; денег не потрачено (панель собрана на уже @@ -331,7 +328,7 @@ **ФАЗА Д «ДОВОДКА ЭКСП-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 — две передачи ПАРАЛЛЕЛЬНОМУ оркестратору (приёмка фазы Д — его зона, №17 полигон не трогает по слову владельца).** (1) Просьба хендоффа фазы Д «эррата zh-канона: пере-сборка = правка закрытой оси, ратифицирует оркестратор» (`POLYGON_PHASE_D_HANDOFF.md:84-86`, завышение +0.0039, вердикты не двигает) — диспозиция №17: к параллельному при приёмке, не к движковому. (2) Мелочь аудита корпуса 15.08: `23-editor-tier.md:2243` цитирует «PROGRESS.md:346» для потолка $4.50 — фактически строка была :348; учесть при приёмке тел. Санкции владельца по деньгам фазы и замене ja-книги уже записаны (D39.136 п.1, CURRENT-STATE). +**Диспозиция оркестратора №17 (15.08), живая до приёмки фазы Д:** просьба хендоффа «эррата zh-канона: пере-сборка = правка закрытой оси, ратифицирует оркестратор» (`POLYGON_PHASE_D_HANDOFF.md:84-86`, завышение +0.0039, вердикты не двигает) — **к ПАРАЛЛЕЛЬНОМУ оркестратору при приёмке, не к движковому** (приёмка фазы Д — его зона). Прожитое из записи (вторая передача и мелочи аудита корпуса) — `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 be3654d4..75e42772 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,12 +18,12 @@ - [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 закрывает, а не способ жить дальше. ⚠ Шапка систематически отстаёт от хвоста у ЛЮБОГО автора — потому проверка механическая, а не «посмотрю внимательно». -- **Активные хендофф-промты — какой файл ТВОЙ** (состав обновляется при каждом лендинге, D39.80; здесь — только то, что отвечает на вопрос «какой файл мой»; хроника, причины и статусы РАБОТ — CURRENT-STATE и D-лог): +- **Активные хендофф-промты — какой файл ТВОЙ** (состав обновляется при каждом лендинге, D39.80; хроника, причины и статусы РАБОТ — CURRENT-STATE и D-лог): | Роль | Активный промт | Статус | |---|---|---| | Оркестратор | [ORCHESTRATOR_SESSION_PROMPT.md](ORCHESTRATOR_SESSION_PROMPT.md) | роль и нормы; счётчик роли — CURRENT-STATE | - | Бэкенд | активного НЕТ | последний пак — «деньги и честность выдачи», принят и заленджен 31.08 (**D39.182**; закон раскрытия — **D39.181**); до него холодный прогон v16 (**D39.179**). Промты — `archive/prompts/`, отчёты — `archive/reports/`. Открыто: различение уровней теста (вопрос владельцу) · §2.2 против `snapshotdiff` · строка **246** (чинит платформа) | - | Платформа | активного НЕТ | последний пак — P12 «долги под ногами», принят и заленджен 31.08 (**D39.180**) вместе с контрактным минором. Промт — `archive/prompts/`. Открытое зоны — её регистр дефектов (`platform/docs/DEFECT_REGISTER.md`, счёт — `counts.py --check`) | + | Бэкенд | активного НЕТ | последний пак — «деньги и честность выдачи», принят и заленджен 31.08 (**D39.182**; закон раскрытия — **D39.181**); до него холодный прогон v16 (**D39.179**) — развилка «довести ≈$1.00 / остановиться» ЗАКРЫТА словом владельца «не доводить» (**D39.184**). Открыто: различение уровней теста (вопрос владельцу) · §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): читающий путь движка сворачивает банк, поэтому смета доезжает до покупателя ДО покупки | @@ -31,7 +31,7 @@ Отработанные промты — `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) — ратифицированное направление зоны: аутентификация, деньги, стандарты, скорость** · архив промтов). - `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), правятся бэкендом одним коммитом с кодом; вручную НЕ рендерить — их смотрят нативно, рендер не нужен. +- Диаграммы: [../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 9cdbbda9..0233b970 100644 --- a/docs/STACK.md +++ b/docs/STACK.md @@ -1,6 +1,6 @@ # Стек моделей — карта «роль → модель → конфиг → квирки» -> **Топикальный вход, НЕ источник истины.** ⚠ Носители конфига здесь адресуются КЛЮЧОМ модели, а не номером строки (испр. 22.08 аудитом доков: номера уехали и вели в чужие блоки — цена, которую номер в файле-справочнике платит каждым касанием). При конфликте побеждают D-лог (`architecture/05-decisions-log.md`) и shipping-конфиги `backend/configs/`. Слаги менять ТОЛЬКО с live-фактчеком `/models` + пробный вызов (правило двух направлений, quirks-шапка); ⚠ «слаг живой» ≠ «модель та же» — DeepSeek 31.07 сменил веса flash под слагом (D39.61, quirks §0731). Квирки: `docs/experiments/00-provider-quirks.md` (далее quirks). +> **Топикальный вход, НЕ источник истины.** ⚠ Носители конфига здесь адресуются КЛЮЧОМ модели, а не номером строки (норма формы указателей — D39.179 п.4). При конфликте побеждают D-лог (`architecture/05-decisions-log.md`) и shipping-конфиги `backend/configs/`. Слаги менять ТОЛЬКО с live-фактчеком `/models` + пробный вызов (правило двух направлений, quirks-шапка); ⚠ «слаг живой» ≠ «модель та же» — DeepSeek 31.07 сменил веса flash под слагом (D39.61, quirks §0731). Квирки: `docs/experiments/00-provider-quirks.md` (далее quirks). | Роль | Модель (слаг) | thinking / effort | Носитель конфига | Статус | Квирки | |---|---|---|---|---|---| @@ -17,6 +17,6 @@ ## Примечания - **⚠0731 (D39.61):** flash пере-обучен под тем же слагом; `/models` молчал. Развилка решена вариантом (б): явный `reasoning_effort:"low"` черновику + ручка эффорта бэнк-ролям (код `553f1a3`). Версию модели проверять ПОВЕДЕНИЕМ. -- **Вахта эффорта pro:** реестр загейченных триггеров — `architecture/13-tech-debt-anchors.md` §Б-108; статус ручки `low` на pro = НЕ УСТАНОВЛЕНО (quirks §3б). -- **Цена:** ~$0.85/ранобэ (⚠ число ДО пере-пина цен 13–15.08: таблица запинена ПИКОМ, счёт шиппинга = 100% DeepSeek ⇒ ×4.2–4.4 в пике и ×2.1–2.2 в долине — D39.137; пере-калибровать первым же платным прогоном. D30.4; тело — `archive/architecture/05-decisions-D1-D38.md`, карта — шапка D-лога); пере-калибровка при следующем платном прогоне (112 залендена, D39.97). Edit-волна не гонялась на ПОЛНОМ холодном прогоне (строка 16); на малых прогонах отработала и оплачена (установлено №19 по леджерам); ставка платформы $0.03/глава (D39.123 п.2г). Цены слагов — `models.yaml` (**`2026-08-15`**: `backend/configs/models.yaml:34`=`prices_checked: "2026-08-15"`; ⚠ бампнут факт-чеком ТОЛЬКО по DeepSeek; катовер 0731 цен не менял). +- **Вахта эффорта 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 279f398d..4520c87e 100644 --- a/docs/architecture/01-decisions.md +++ b/docs/architecture/01-decisions.md @@ -55,15 +55,15 @@ | Роль | Основная модель | Альтернативы/эскалация | |---|---|---| | Черновик | DeepSeek V4 Flash ($0.14/$0.28; cache-hit input $0.0028; лучший zh-токенизатор) | GPT-5 nano ($0.05/$0.40), Qwen-Flash. ⚠ эксп.04: DeepSeek «эхал» оригинал на высоко-CJK фрагменте (82% CJK, 3/3) → тихий отказ = оригинал вместо перевода; ловит CJK-гейт + фолбэк-черновик | -| **Редактор (ru-стиль)** *(→ состав СНЯТ: D30.1 редактор БИЛИНГВ → D39.22 deepseek-v4-pro интерим)* | по D-логу, не по этой строке | премиум-эскалация **gemini-3.1-pro-preview** (лучшая проза, дорогая/медленная, иногда дописывает). Бейк-офф эксп.04 (ранги, ~11k reasoning-ток. Kimi, снятие GLM-4.6 с дефолта, «перемерить при GLM-5») — `experiments/04-editor-quality.md`, там же ⚠-баннер об отмене его рекомендации | +| **Редактор (ru-стиль)** *(→ состав СНЯТ: D30.1 редактор БИЛИНГВ → D39.22 deepseek-v4-pro интерим)* | по D-логу, не по этой строке | премиум-эскалация **gemini-3.1-pro-preview** (лучшая проза, дорогая/медленная, иногда дописывает). Бейк-офф эксп.04 и ⚠-баннер об отмене его рекомендации — `experiments/04-editor-quality.md` | | Эскалация канал A (по сигналу гейта) | DeepSeek V4 Pro → GLM-5.1 → gemini-3.1-pro-preview (апекс) | нативный Gemini-адаптер для safety-судьи — Ф2 | | Судья | Gemini 3.1 Pro (для явного safety-контроля — нативный API, Ф2) | GPT-5 mini — second-opinion судья чужого семейства; **Grok 4.3 — судья 18+** (не отказывается оценивать explicit, в отличие от Gemini/Claude); локальный POLLUX-judge-7B — бесплатный гейт | | Эмбеддинги/скрининг/экстракция терминов | локально: bge-m3, Qwen3.5-9B | Qwen3-Embedding-0.6B | -| Канал B (чувствительный контент) *(→ состав СНЯТ: D14.1/D19.1 → D39.25 — в движке нет понятия «18+», состав идёт content-labels × provider-capabilities)* | по D14.1/D19.1: переводчик-дефолт Mistral, эскалация grok reasoning-ON, локальная abliterated; ⚠ **DeepSeek в explicit запрещён его ToS** (D14.1) | провайдерские квирки xAI (reasoning аддитивен, thinking-OFF только явным `reasoning_effort:"none"`, ретайр дешёвого слага 15.05.2026) — `experiments/00-provider-quirks.md`; копий квирков здесь нет по гардрейлу CLAUDE.md. Аккаунт-политика xAI — D27 | +| Канал B (чувствительный контент) *(→ состав СНЯТ: D14.1/D19.1 → D39.25 — в движке нет понятия «18+», состав идёт content-labels × provider-capabilities)* | по D14.1/D19.1: переводчик-дефолт Mistral, эскалация grok reasoning-ON, локальная abliterated; ⚠ **DeepSeek в explicit запрещён его ToS** (D14.1) | провайдерские квирки xAI — `experiments/00-provider-quirks.md` (копий здесь нет по гардрейлу CLAUDE.md); аккаунт-политика xAI — D27 | Контент-роутинг ([11-gap-2](../research/11-gap-2.md)): - Механизм роутинга **переопределён D39.25**: не чанк-классификатор «горячести» 0–3, а content-label книги/главы × `accepts_labels` провайдера (`backend/configs/models.yaml`, подписи D39.30); L3 — политика ВХОДА. Живые инварианты этой строки: жёсткий отказ только на CSAM-категории (Р8) и «ложное срабатывание не убивает многочасовую оплаченную джобу» — чанк помечается в отчёте, глава и книга продолжают обрабатываться. -- **Эскалация channel-aware**: для чанков канала B дорогая эскалация — Grok 4.3 / Gemini (safety off) / крупные open-weights; канал A — DeepSeek V4 Pro / GLM-5.1 / Gemini 3.1 Pro. Anthropic из роутинга исключён (дорого); OpenAI остаётся, но **в канал B не включать** (политика 18+ строгая, adult mode заморожен — как и раньше). При подключении failover (Фаза 2) пара primary/fallback канала B — только пермиссивные провайдеры (xAI/DeepSeek/local/open-weights) или fail loudly (иначе пустой ответ local-abliterated молча уйдёт в непермиссивную облачную ногу — дыра D3 ревью бэкенда). +- **Эскалация channel-aware**: для чанков канала B дорогая эскалация — Grok 4.3 / Gemini (safety off) / крупные open-weights; канал A — DeepSeek V4 Pro / GLM-5.1 / Gemini 3.1 Pro; OpenAI **в канал B не включать** (политика 18+ строгая, adult mode заморожен). Инвариант «непермиссивная нога не получает помеченный контент» живёт как fail-closed `accepts_labels` (D39.26/D39.28; `failover.go` удалён). - Гигиена аккаунтов xAI **снята D27**: ключ единый, с data-sharing на тесты/пилот; живой остаток — отключить data-sharing перед продом (строка 67 бэклога `../PROGRESS.md`). Провайдер лёг → роль пауза→resume (D4, не сайлент-своп). Think-ON на Grok — только после reasoning-буфера в EstimateUSD (D6.2); off-switch и аддитивность reasoning — `experiments/00-provider-quirks.md`. - Обязателен **детектор молчаливых вырезаний** (сверка покрытия предложений вход↔выход) — Qwen-подобные внешние фильтры молча портят перевод. - Внутренний refusal/excision-бенчмарк (50–100 фрагментов), прогонять при каждой смене версии модели. @@ -134,4 +134,4 @@ COGS (прямые ключи, **актуально — [experiments/08-cost-mod 3. **Западные сервисы добавят ru-таргет** (booktranslator.ai уже имеет ru-лендинг и демпингует): окно — не первенство, а глубина (память серии, редакционная петля). 4. **Приём платежей от ru-in-Russia клиентов** (RU-карты не проходят EU-SaaS) — открытый GTM-вопрос, не архитектурный; разбор и варианты аудитории — в Р9. 5. **Волатильность цен API**: конфиг с датами, ежеквартальный пересмотр, буфер +25%. -6. **Концентрация ролей на xAI/Grok** (редактор + канал B + судья 18+): провайдер лёг → пауза/resume (D4); мониторить, при риске — держать валидированную замену редактора (gemini как премиум уже есть). +6. **Концентрация ролей на xAI/Grok** — **риск СНЯТ** (шапка выше: редактор = deepseek-v4-pro, D30.1→D39.22). Живой остаток: у grok судья 18+ и эскалация — провайдер лёг → пауза/resume (D4), не сайлент-своп. diff --git a/docs/architecture/02-mvp-plan.md b/docs/architecture/02-mvp-plan.md index 37baaf00..9fa94906 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)`. Anthropic-адаптер остался DEPRECATED-референсом (Р1) — не «к написанию». +Порт ядра 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)`. ## Фаза 1 — Перевод целой книги (текущая; машинерия в основном построена) @@ -26,11 +26,11 @@ **Осталось до приёмки Фазы 1:** - ✅ ПОСТРОЕНО (адрес — шапка-таблица `09-target-architecture.md`): границы доверия памяти D16 (D39.2) · `tmctl status`+redrive (D15.3) · дешёвые гейты 04-unhappy §6/§9 (`checks.cheapgates`, v2 — D20.4) · output-санитайзер D30.3 (`checks/sanitizer.go`) · автопопуляция G1 — Go-майнером (`internal/miner`, D39.10/D39.14/D39.17), а не спот-локалью из exp06. Живой остаток: **диалог-флаггер парности (D29.1д)** — в `internal/checks` его нет; **чек-лист ja-книги — kana-написания сид-имён вносить aliases руками (D16.4)**. -- Реальный прогон end-to-end **приёмочной книги 蛊真人 zh→ru (D18; ja→ru понижен до второго прогона при появлении ja-epub)**. *(v3.2: этап A ✅ 10.07 (D24); этап B ЗАМОРОЖЕН D26 до читаемых 25 глав — сначала пере-прогон кандидат-конфигом D30.9 с re-gate верности.)* +- Реальный прогон end-to-end **приёмочной книги 蛊真人 zh→ru (D18; ja→ru понижен до второго прогона при появлении ja-epub)**. *(этап A ✅ 10.07 — D24; этап B НЕ открыт: пере-прогон исполнен, планка не пройдена — шапка, D39.20/D39.22.)* - Режим онгоинга (`add-chapters`) — **сдвинут в Фазу 1.5**: гейтится resume-экономикой (D15.2 — content-addressed reuse чекпоинтов или селективный redrive; спека в Фазе 1, реализация Ф1.5). До этого онгоинг не продаётся. - Экспорт txt/epub + отчёт (D29.1): ✅ ПОСТРОЕНА ассемблер-часть — `tmctl export` + `checks.ExportNormalize` + паспорт-rollup (`pipeline.ChapterPassport`). НЕ построено (греп по `backend/`, `platform/`, `frontend/` — 0 хитов): `annotations.json`, политика красных, цвет-мап+GREY, `human_override` LOCK; плюс release-state лестница D25.1 — до первого reader-facing артефакта. -**Интерим-правило 18+ (v3.1, до NSFW-роутера Фазы 2):** приёмочный корпус — только SFW. При `18+: да` в brief: канал B в составе **D19.1/D22 — переводчик-дефолт Mistral (18/18 чист на violence+эротике), эскалация grok-4.3 reasoning-ON (⚠ не на архаичном Хане — D22.5), local abliterated скрининг/фолбэк** (DeepSeek для explicit ЗАПРЕЩЁН его ToS — D14.1); судьи: эротика — только Grok (Gemini fail-closed `PROHIBITED_CONTENT` — D22.6, дублёр гейтится пробой), violence/SFW — Grok+Gemini; OpenAI в explicit-роутинг не включать; refusal-blacklist-гейт перед коммитом в TM обязателен (ветка `content_filter` мертва у OpenAI-совместимых — exp07; у Gemini 3.x жива составной строкой — D21.9). **L3-скрин обязателен до первой erotica-книги в проде (D22.7 + D25.4).** +**Правило 18+:** приёмочный корпус — только SFW. Маршрутизация чувствительного контента — не «канал B» фиксированным составом (состав D19.1/D22 отставлен паком-17: D39.25/D39.26–D39.28, шапка `09-target-architecture.md`), а `content_labels` × `accepts_labels`. Живые ограничения данных: DeepSeek для explicit ЗАПРЕЩЁН его ToS (D14.1); ⚠ эскалация на grok reasoning-ON НЕ снимает эхо на архаичном плотно-ханьском (D22.5); эротику судит только Grok — Gemini fail-closed `PROHIBITED_CONTENT` (D22.6); OpenAI в explicit-роутинг не включать; refusal-blacklist-гейт перед коммитом в TM обязателен (ветка `content_filter` мертва у OpenAI-совместимых — exp07; у Gemini 3.x жива составной строкой — D21.9). **L3-скрин обязателен до первой erotica-книги в проде (D22.7 + D25.4).** **Приёмка Фазы 1 (v3.1, по D11/D10/D1.1/D18/D24):** 1. SFW-книга **蛊真人 zh→ru (D18)** end-to-end этапами с чекпоинтами владельца (этап A 25 глав ✅ D24; этап B ~300 глав) с резюмируемостью; kill -9 → потеря максимум одного вызова. *(ja→ru том — второй прогон при появлении ja-epub.)* @@ -45,15 +45,15 @@ - **Judge-роль** (билингвальный, судья-анкета узких вопросов с MQM-весами — паттерн LiTransProQA/DITING, НЕ холистический скор; словарь тегов ошибок в request_log с первого дня фазы), C2/C3 как конфиги (C2 — только гетерогенные кандидаты, D13.2); second-opinion судья чужого семейства на Gemini-эскалированных чанках (self-preference). - **Пре-пасс Annotator** (04-unhappy «Следствия» п.1: speaker-ID, регистровый трекер, чэнъюй-маски — питает 8+ режимов отказа; в v2-плане отсутствовал — внесён). -- NSFW-роутер: локальный классификатор 0–3 (**требует спеки и метрики приёмки** — false-negative уровня 3 = юридическая экспозиция; сейчас классификатор не специфицирован — 07-ревью), каналы A/B (состав D14), channel-aware эскалация типом, детектор молчаливых вырезаний, refusal-мониторинг. +- Чувствительный контент: **механизм построен паком-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: валидатор Палладия/Поливанова** на коммите dst-имён (ruby-reading как ground-truth для ja) — желательно ДО ja-приёмки, обязательно до масштабирования. -- Резюме глава→арка→книга + гейт фактичности резюме (D1 реестра — у резюме нет post-check-аналога); series-bible ты/вы-журнал. +- **B6: валидатор Палладия/Поливанова** — ПОСТРОЕН generic-парсером + langpack-таблицами (D39.16, `internal/lang` + `configs/langpacks/zh-ru/palladius*.txt`); таблицы Поливанова = данные ja-пары, которых в репо ещё нет (ruby-reading — их ground-truth). +- Резюме глава→арка→книга + гейт фактичности резюме (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: отрицание, перепутанный субъект, внутренняя речь→прямая). -Приёмка: 18+ книга проходит пайплайн без молчаливых потерь (детектор + refusal-бенчмарк на explicit-корпусе); гейт рода/ты-вы работает; C2/C3 запускаются конфигом; классификатор 0–3 имеет измеренную точность на уровне 3. +Приёмка: 18+ книга проходит пайплайн без молчаливых потерь (детектор + refusal-бенчмарк на explicit-корпусе); гейт рода/ты-вы работает; C2/C3 запускаются конфигом. ## Фаза 2.5 — Пилот 4 рук (решающая точка) diff --git a/docs/architecture/03-implementation-notes.md b/docs/architecture/03-implementation-notes.md index 36bd685f..13edcda2 100644 --- a/docs/architecture/03-implementation-notes.md +++ b/docs/architecture/03-implementation-notes.md @@ -2,7 +2,7 @@ > **⚠ Точка-во-времени 04.07 (ревизия D31).** §3-контракты Фазы 0 — живой референс бэкенда (request_hash охраняется golden-гардом D23); §5 «[НУЖНО РЕШЕНИЕ]» — все пункты развязаны D-логом (премиум-бюджет → D11/exp08; TM-политика → Р6/D-лог; канал B → D14.1/D19.1; стриминг → keep-alive Ф2); онлайн-факты §3.9 датированы 04.07 — цены/слаги сверять с models.yaml/quirks. -> **⚠ СТАТУС-АПДЕЙТ 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-техдолга закрыты: гонка `Runner.clients` (WS1a, D39.13) · F4 — усечённый length флагуется disposition-классификатором · F3-класс — кап пере-биллинга пака-12; снапшот-дисциплина и golden-гард D23 живы в новой раскладке (golden байт-в-байт, парити EXACT — D39.23). +> **⚠ СТАТУС-АПДЕЙТ 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`). **Живое здесь — §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`. @@ -51,7 +51,7 @@ style sheet, резюме книги/арок на момент старта д `extra_body` per-модель в models.yaml, мёрджится в JSON запроса OpenAI-совместимым адаптером (эмпирика полигона: thinking GLM-4.6 — таймауты ×3, Gemini молча жрёт max_tokens на thinking). - Стриминг в Фазе 0 НЕ реализуется, но интерфейс проектируется под него (второй метод в будущем не ломает - адаптеры); длинные генерации закрываются длинными attempt-таймаутами из профиля (см. §5: провайдерский стриминг отнесён к Ф2). + адаптеры); длинные генерации закрываются длинными attempt-таймаутами из профиля; провайдерский стриминг отнесён к Ф2. - DeepSeek-адаптер парсит **оба** варианта cache-полей usage (`prompt_tokens_details.cached_tokens` и `prompt_cache_hit_tokens`/`prompt_cache_miss_tokens`) — иначе эксперимент Фазы 0 по кэшу покажет ложный ноль. - Ответ транспорта читается через `LimitReader` (у донора кап есть только в gemini-native). @@ -99,17 +99,17 @@ 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 — СНЯТЫ (были помечены «для истории») +## 4. Мелкие поправки к research/10 — СНЯТЫ -Уточнения счётчиков донора (46 колонок `request_log`, 137 тест-функций, стиль тестов, объём переносимого из `config.go`, раскладка telemetry/trace) относились к отчёту `../research/10-vojo-ai-bot-review.md` и к коду, которого в этом репозитории нет; сам порт давно построен и мерилом служит уже он. +Уточнения счётчиков донора относились к отчёту `../research/10-vojo-ai-bot-review.md` и к коду, которого в этом репозитории нет; мерило порта — сам порт. ## 5. [НУЖНО РЕШЕНИЕ] — СНЯТО, всё развязано -Пять вопросов 04.07 закрыты и повторного решения не требуют (карта — в баннере вверху): премиум-бюджет Р5 → D11 + эксп-08 · политика инвалидации TM → Р6, `01-decisions.md`, греп `Ключ TM подтверждён` · канал B без дешёвого Grok → D14.1/D19.1, состав и цены живут в `backend/configs/models.yaml` · стриминг как keep-alive → закрыт длинными attempt-таймаутами профиля, провайдерский стриминг отнесён к Ф2 · пункты оркестратору (фазовые пометки диаграмм, владелец задачи cache-hit) отработаны арх-ресетом D39. Формулировки вопросов — `../archive/PROGRESS-2026-07-04-10.md`. +Пять вопросов 04.07 закрыты, карта развязок — в баннере вверху (тела D11/D14/D19/D23 — в слайсе `../archive/architecture/05-decisions-D1-D38.md`); пятый, не попавший в карту, — пункты оркестратору (фазовые пометки диаграмм, владелец задачи cache-hit), отработан арх-ресетом D39. Формулировки вопросов — `../archive/PROGRESS-2026-07-04-10.md`. ## 6. Что осталось от Фазы 0 живым долгом -Селфревью Фазы 0 (две волны, коммиты `dc6ea8e` → `a32ec2e`) и независимое внешнее ревью **приняты, блокеров ноль**; хроника волн и диспозиция находок F1–F8/D1–D3 — `../archive/PROGRESS-2026-07-04-10.md` (§«Фаза 0 принята»). Из тогдашнего техдолга ЗАКРЫТО: гонка `Runner.clients` (клиенты строятся eager-проходом ДО волн, дальше map read-only — `internal/pipeline/runner.go`, греп `the clients map is READ-ONLY in the waves`; D39.13) · F4 «finish=length с обрезанным черновиком» (флаг диспозиции `FlagLength` — `internal/pipeline/disposition.go`, греп `FlagLength FlagReason`) · F3-класс оплаченных ретраев (кап пере-биллинга: второй нечитаемый оплаченный 2xx ТЕРМИНАЛЕН, ре-биллы капятся одним — `internal/llm/httpllm.go`, греп `Cap billed-decode re-bills at ONE`) · D1/D2 (билингв-редактор ратифицирован D30.1 — требование «убрать `{{text}}`» ОТМЕНЕНО, не исполнять; per-chunk skip+flag построен диспозиция-классификатором) · D3 (изоляция канала B: `failover.go` удалён, механизм лейблов `content_labels`×`accepts_labels` — D39.26/27/28). +Селфревью Фазы 0 (скелет `7954325` → волна 1 `e861541` → волна 2 `214e005`) и независимое внешнее ревью **приняты, блокеров ноль**; хроника волн и диспозиция находок F1–F8/D1–D3 — `../archive/PROGRESS-2026-07-04-10.md` (§«Фаза 0 принята»). Из тогдашнего техдолга ЗАКРЫТО: гонка `Runner.clients` (клиенты строятся eager-проходом ДО волн, дальше map read-only — `internal/pipeline/runner.go`, греп `the clients map is READ-ONLY in the waves`; D39.13) · F4 «finish=length с обрезанным черновиком» (флаг диспозиции `FlagLength` — `internal/pipeline/disposition.go`, греп `FlagLength FlagReason`) · F3-класс оплаченных ретраев (кап пере-биллинга: второй нечитаемый оплаченный 2xx ТЕРМИНАЛЕН, ре-биллы капятся одним — `internal/llm/httpllm.go`, греп `Cap billed-decode re-bills at ONE`) · D1/D2 (билингв-редактор ратифицирован D30.1 — требование «убрать `{{text}}`» ОТМЕНЕНО, не исполнять; per-chunk skip+flag построен диспозиция-классификатором) · D3 (изоляция канала B: `failover.go` удалён, механизм лейблов `content_labels`×`accepts_labels` — D39.26/27/28). **Живой остаток (носители — бэклог-строка 146 `docs/PROGRESS.md`, греп `Два техдолга движка без строки трекера`):** - **Дневной потолок — пер-книжный** (ledger в файле проекта одной книги): `day_usd` сбрасывается в UTC-полночь и ограничивает burn-rate одной книги, а не «оператора за день по всем проектам»; общий потолок потребует shared spend-файла (раскладка «файл БД на книгу» из Р3/Р6). Платформенная половина — `PD-157`. diff --git a/docs/architecture/04-unhappy-paths.md b/docs/architecture/04-unhappy-paths.md index b4db3906..ca2d07d3 100644 --- a/docs/architecture/04-unhappy-paths.md +++ b/docs/architecture/04-unhappy-paths.md @@ -55,7 +55,7 @@ Pro-drop (местоимения лишь в ~11% японских предло | Молчаливые цензурные вырезания провайдера | Детектор вырезаний (полигон, эксперимент 02) + refusal-мониторинг | 2 | ✅ | | CJK-осколки, смесь языков | Регэксп CJK-диапазонов + langid по абзацам | 1 | ✅ | | Разрушение форматирования/вёрстки | Структурный diff документа (главы/абзацы/разметка) до и после | 1 (текст) / 3 (разметка) | 🔶 epub v1 теряет инлайн-разметку осознанно | -| **Потеря ruby/фуриганы на инжесте** (двухслойные термины, авторские чтения) | Парсер ruby-тегов на инжесте: чтения имён → глоссарий-лок, двухслойные термины → флаг | 1 | ❌→действие: добавить в спеку импорта Фазы 1 (сейчас «epub v1 = извлечение текста» молча убивает слой) | +| **Потеря ruby/фуриганы на инжесте** (двухслойные термины, авторские чтения) | Парсер ruby-тегов на инжесте: чтения имён → глоссарий-лок, двухслойные термины → флаг | 1 | ✅ ПОСТРОЕН: `ruby_readings` на инжесте + сид-контракт (`06-memory-risk-registry.md` §Ruby-seed); двухслойные термины — классификатор `ruby_class` | ## 5. Идиоматика, реалии, аллюзии @@ -76,7 +76,7 @@ Pro-drop (местоимения лишь в ~11% японских предло | Режим отказа | Механизм | Фаза | Статус | |---|---|---|---| -| Английские кавычки вместо тире-диалогов | Линтер прямой речи (Розенталь §47–52), автофикс, 100% детерминированный | 1 | ✅→ включить в гейты Фазы 1 (дешевле coverage) | +| Английские кавычки вместо тире-диалогов | Линтер прямой речи (Розенталь §47–52), автофикс, 100% детерминированный | 1 | ✅ (D20.4, см. «Следствия» п.3) | | Транслит-междометия («Ауч!», «Упс», «Ара?») | Блок-лист + автозамена по словарю + per-project allowlist | 1 | ✅ | | Непоследовательная ё (Пётр/Петр в одной книге) | Ёфикатор + режим проекта + сверка имён с глоссарием | 1 | ✅ | | Висячие деепричастия («Подъезжая к станции, слетела шляпа») | UD-парсер, флаг + автофикс дешёвой моделью | 2 | ✅ | @@ -111,7 +111,7 @@ Pro-drop (местоимения лишь в ~11% японских предло | Режим отказа | Действие | |---|---| -| **Числительные и меры CJK**: разряды 万/億 (三万 → «три миллиона» — ошибка порядка!), 里/斤/сяку/стражи 时辰, счёт возраста (16 суй ≈ 15 лет) | Новый детерминированный **число-гейт**: извлечение и сверка числовых значений вход/выход с таблицей конвертации разрядов и единиц; словарь мер в глоссарий-пресеты жанра. Фаза 1–2. Дёшево и частотно — включить в план | +| **Числительные и меры CJK**: разряды 万/億 (三万 → «три миллиона» — ошибка порядка!), 里/斤/сяку/стражи 时辰, счёт возраста (16 суй ≈ 15 лет) | Новый детерминированный **число-гейт**: извлечение и сверка числовых значений вход/выход с таблицей конвертации разрядов и единиц; словарь мер в глоссарий-пресеты жанра. Число-гейт 万/億 ПОСТРОЕН (D20.4, «Следствия» п.3); словарь мер — Ф2 | | **Западные имена через катакану/фонозапись**: 约翰 → «Юэхань» вместо «Джон», ヴァイオレット → Вайолет/Виолетта, васэй-эйго ложные друзья (マンション = квартира, не «особняк») | Поле глоссария `translit_policy` для псевдоевропейских имён (массовый случай в исекай-ранобэ) + словарь васэй-эйго ложных друзей. Фаза 1 (поле) / 2 (словарь) | ## 10. Мета-режимы (процесс, не лингвистика) @@ -124,7 +124,7 @@ Pro-drop (местоимения лишь в ~11% японских предло ## Следствия для плана (сводка изменений) 1. **Новая стадия «Annotator» (пре-пасс разметки оригинала)** — Фаза 2: speaker-ID, субъекты клауз, регистровый трекер пар, чэнъюй/вэньянь-маски. Один дешёвый пре-пасс питает 8+ режимов; это конкретизация «аннотированного подстрочника» из Р2. В Фазу 1 из него — только детерминированная часть: ruby-парсер на инжесте (закрывает дыру §4) + NER имён. -2. **Расширение схемы глоссария/series bible** (Р3) — в схеме ПОСТРОЕНО (`store/migrate.go`: `alias_type`, `first_person`, `gender=hidden`, `nickname_translation`, `translit_policy`, формы обращения). НЕ построено: тип `ranked-set` + порядок ступеней (долг — `13-tech-debt-anchors.md`), словарь эвфемизмов, профиль грубости, ты/вы-журнал (Ф2). +2. **Расширение схемы глоссария/series bible** (Р3) — в схеме ПОСТРОЕНО (`store/migrate.go`: `alias_type`, `first_person`, `gender=hidden`, `nickname_translation`, `translit_policy`, формы обращения). НЕ построено: тип `ranked-set` + порядок ступеней (долг — `13-tech-debt-anchors.md`), словарь эвфемизмов, профиль грубости. Отдельное поле `keep_ambiguous_until` НЕ нужно — покрыто `gender=hidden`+`until_ch` (`store/migrate.go`); не построен его ГЕЙТ — детерминированный блокер утечки рода через глагол прош. вр. (C3 реестра `06-memory-risk-registry.md`, Ф2). Ты/вы-журнал построен — `address_pairs` (D7-Amendment-1/D21 п.2). 3. **Дешёвые гейты Фазы 1 — ПОСТРОЕНЫ** (D20.4, `checks/cheapgates.go`, flagger-only): тире-линтер, ёфикатор, блок-лист транслит-междометий, число-гейт 万/億; §6/§9 этой карты — их спека. 4. **Промпт судьи — анкета бинарных вопросов по осям** (κ=0.94 против 0.84 у «оцени 1–10», DITING; M-MAD без рубрик уходит в отрицательную корреляцию) + обязательная калибровка на человеческом якоре (LAIT: все LLM-судьи предпочли MT). Словарь ~12 тегов ошибок с MQM-весами (minor=1, major=5, non-translation=25) зафиксировать в Фазе 1 — request_log копит статистику с первого дня. → вход для «Редакции». 5. **Alignment-защита рефренов** в анти-translationese пассе (иначе чиним стиль ценой авторского ритма). diff --git a/docs/architecture/05-decisions-index.md b/docs/architecture/05-decisions-index.md index 217c31e0..41ed94ff 100644 --- a/docs/architecture/05-decisions-index.md +++ b/docs/architecture/05-decisions-index.md @@ -6,7 +6,7 @@ > Одна строка на КАЖДУЮ ноту журнала решений: № · дата · суть · статус · где тело · темы. > ⚠ **ФОРМА ДВУХ ПОСЛЕДНИХ КОЛОНОК РАЗЪЕХАЛАСЬ, замерено 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 (ревизии D31–D38.2) пересобрана в реестр докс-паком 167 (09.08.2026, №16): извлечение 6+6 агентов по worksheet `../archive/reports/DOC_AUDIT_INVENTORY_2026-08-09.md`, полнота сверена скриптом против заголовков всех шести файлов. «тело: жив» = живой D-лог; «слайс N» = `../archive/architecture/05-decisions-N.md`. +> Родословная реестра (прозаическая карта D1–D39.28 пересобрана докс-паком строки 167, вместе с путём worksheet и методом сверки полноты) — D39.126 п.1(а). «тело: жив» = живой D-лог; «слайс N» = `../archive/architecture/05-decisions-N.md`. | № | дата | суть | статус | тело | темы | |---|---|---|---|---|---| @@ -200,10 +200,10 @@ | D39.140 | 16.08 | Аудит целостности бэклога по заказу владельца (292 ревизии PROGRESS, 200 ID; свип 26 закрытых строк): **ПОТЕРЬ НЕТ** — 56 ушедших все со следом; 3 аномалии формы до ратификации норм; 9 загейченных хвостов без носителя закрыты строками 188–190 и дописками | ЖИВОЕ: строки 188–190; порог в риг — до вахты V4-Pro-0813 | жив | процесс бэклог оркестратор приёмка | | D39.141 | 16.08 | Реструктуризация промта оркестратора по заказу владельца: форма «ситуация → инструкция», генезис D-ссылками, чек-лист 11 блоков + два рубежа выдачи (механическая сверка + опровергатель-субагент), таблица линз приёмки по характеру работы; −59% объёма, потерь 0 | ЖИВОЕ: действующая редакция роли | жив | процесс оркестратор промпт | | D39.142 | 16.08 | Приёмка батча 0.3.0 (8d82096): канон 0.3.0 в каноне; ратифицированы отступления (поток один книжный, `Note.code`, `content_refused`, единый `page_size_default`); дофикс ФБ-1..10 заказан аддендумом промта; зеркало фронта временно отстаёт ратифицированно | ЖИВОЕ: дофикс у сессии батча; строка 183 пере-скоуплена | жив | контракт приёмка платформа фронт | -| D39.143 | 16.08 | Дофикс батча принят: ФБ-1..10 закрыты — SSE-форма кадра однозначна, петля реконнекта убита `id:0`, note-гарантия сужена до соединения + обязательное дельта-чтение, Revision одна модель, resume-таблица без нового enum, `processing_failed`; вывод о доле прозы честно перевёрнут (42→47%) | ЖИВОЕ: ⚠ ПРОТУХЛО (испр. 22.08): P7 принят и заленден D39.153, P8-FIX — D39.154; прежний текст «P7 — запуск владельцем; владельцу — BankTerm.decision (D39.142 п.4) | жив | контракт приёмка платформа | +| D39.143 | 16.08 | Дофикс батча принят: ФБ-1..10 закрыты — SSE-форма кадра однозначна, петля реконнекта убита `id:0`, note-гарантия сужена до соединения + обязательное дельта-чтение, Revision одна модель, resume-таблица без нового enum, `processing_failed`; вывод о доле прозы честно перевёрнут (42→47%) | ЖИВОЕ: ⚠ ПРОТУХЛО (испр. 22.08): P7 принят и заленден D39.153, P8-FIX — D39.154 | жив | контракт приёмка платформа | | D39.144 | 16.08 | Модель подписи банка — слово владельца напрямую: подписывается ВЕСЬ банк одним ОК, пер-термная масс-подпись отменена как инерция контрактной линии; канон поправлен (409-полноты снят с resume, `pending_decisions` информационный, `bank_decisions_incomplete` удалён); пост-ридинговые правки банка → пере-генерация по вхождениям, механику до полигона не проектировать | ЖИВОЕ: строка 191; P7 — запуск владельцем | жив | контракт банк владелец фронт платформа | | D39.145 | 16.08 | Промт P7 пересобран по слову владельца (два рубежа D39.141: автор-перечтение + опровергатель, 8 HIGH): демонтаж построенного гейта полноты `reconcile.go` заказан явно, недочистка D39.144 вычищена эрратой 16.08-д, `structure_version`/`genre`/`halt_reason`/`heading`/`Note.code` влиты; PD-241 императивом | ЖИВОЕ: P7 готов, запуск — слово владельца | жив | платформа промпт контракт процесс | -| D39.146 | 16.08 | Закрытие сессии оркестратора №17, передача №18 (лента D39.134–145: приёмки migrate/S4/DeepSeek, контракт-ревью + батч 0.3.0 + дофикс — канон 0.3.0 финален, модель подписи один ОК, аудит бэклога, реструктуризация роли) | ЖИВОЕ: очередь — CURRENT-STATE | жив | хендофф оркестратор | +| D39.146 | 16.08 | Закрытие сессии оркестратора №17, передача №18 (лента D39.134–145) | ЖИВОЕ: очередь — CURRENT-STATE | жив | хендофф оркестратор | | D39.147 | 17.08 | Слово владельца напрямую №18: фронт морозится ДАЛЬШЕ лендинга P7 (условие D39.136 п.2 амендировано — разморозка отдельным словом, S5 не выдаётся), курс — движок и платформа до «работает и отдаёт результат», моки фронта уступают дев-стенду платформы; инвентарь трёх аудитов кодом разведён по строкам бэклога 49 · 54 · 136/137 · 140 · 193 | ЖИВОЕ: курс и условие разморозки | жив | процесс фронт платформа владелец | | D39.148 | 17.08 | Ревизия D39.126: `--lint` якорей вплетён в pre-commit хук доков (warn-only, `--from-index`), `--check` остаётся на D-логе/PROGRESS; метод-урок: хук судится ТЕСТ-КОММИТОМ, а не ручным прогоном — git отдаёт хуку временный индекс через `GIT_INDEX_FILE` | ЖИВОЕ: действующая форма гейта доков | жив | процесс инфра доки | | D39.149 | 17.08 | Приёмка пака «честные числа и статусы»: **ПРИНЯТ С ФИКС-ЛИСТОМ ФЧ-1…ФЧ-8**, регрессов нет; ратифицированы паника→exit 1, `PanicError` без `Unwrap`, пере-прайс фактическими токенами через шов сеттла, выборочный порог в риге (4/5 PASS); деньги пробы $0.005582424 сошлись двумя независимыми путями | ЖИВОЕ: фикс-лист ФЧ и два решения владельца | жив | деньги приёмка шов бэкенд | @@ -217,21 +217,21 @@ | D39.157 | 24.08 | Переезд на новую машину: стенд пересобран без root (обе батареи EXIT=0 под `-race`), носитель подъёма — карта `README.md`; корень книг переопределён на `<репозиторий>/books` со своим git, якорь `/books/` в игноре починен; цена переезда ЗАМЕРЕНА (движок — 3 хелпера, строка 218; полигон — 173 файла по корню книг и 121 по корню репо, строка 217); решения владельца — легаси выкидывать, а не чинить, GPU нет; маршрут холодного входа починен по СЛЕПОМУ замеру трёх ролей; класс «line-якорь в D-лог» закрыт (51 из 55 съехал), гейт вооружён структурной сверкой | ЖИВОЕ: строки 217/218; очередь — CURRENT-STATE | жив | инфра процесс доки полигон бэкенд | | D39.158 | 27.08 | Входная дверь шва закончена: стоп банка — ФЛАЖОК в движке (память предъявленного, схема v16); полоса — два яруса + гардрейл «разрушительное на классе»; класс `write_incomplete`/exit 15; отчёт двери v2; пути решений только конвенцией; эрраты 191(б)/203(з) | жив | живой файл | шов · банк · полоса отказов | | D39.159 | 27.08 | Пак P8-REVIEW принят: числа воспроизведены приёмкой на дереве С лендингом бэкенда (18 пакетов, EXIT=0, скипов 0; регистр 398/96). Ратифицированы норма копии-с-каноном (`ENGINEERING_STANDARDS` §3 п.3), эррата `STACK_DECISIONS` §13 и токен `ОСПОРЕНО(PD-N)` при двусторонней ссылке. Правка гейта формы регистра ОТКЛОНЕНА замером (краснит 7 законных строк) | жив | ЖИВОЕ: 24 строки PD-375…PD-398, единственный vuln PD-379 | платформа ревью регистр | -| D39.160 | 27.08 | Контрактный минор 0.4.0 → 0.5.0 выдан промтом; **сквозная полоса прогресса (строка 200) ИЗЪЯТА из него словом владельца** и едет с платформенным паком (2в): гейт версии требует совпадения канона и деплоя в момент лендинга, а сервер прогресс по-новому не считает. Цена «одним куском» обнулена заморозкой фронта | жив | ИСПОЛНЕНО: полоса уехала с паком (2в) и закрыта D39.162 | контракт полоса процесс | +| D39.160 | 27.08 | Контрактный минор 0.4.0 → 0.5.0 выдан промтом; **сквозная полоса прогресса (строка 200) ИЗЪЯТА из него словом владельца** и едет с платформенным паком (2в); основание механическое (гейт версии), не вкусовое | жив | ИСПОЛНЕНО: полоса уехала с паком (2в) и закрыта D39.162 | контракт полоса процесс | | D39.161 | 27.08 | Контрактный минор **0.5.0** принят и заленджен: отменённая пер-термная модель снесена из канона и компаньона, дверь `POST …/bank/corrections` выведена из словаря `bank-apply` поле в поле, признак «не построено» машиночитаем, счётчики упразднённой модели сняты; константа платформы поднята тем же коммитом. Ошибка промта про «поля навсегда нули» вынесена `PD-399` | жив | ЖИВОЕ: канон 0.5.0; дверь правок объявлена | контракт банк дверь | | D39.162 | 28.08 | **Платформенный пак P9 принят и заленджен + контрактный минор 0.6.0**: дверь правок банка смонтирована синхронно, ключи доехали `--keys-file`, дубль конвенции пути снят, полоса стала СКВОЗНОЙ вместе с каноном, `PD-399` снят. Р3 — архитектурный стоп `PD-410`, канон НЕ смягчён | жив | ЖИВОЕ: канон 0.6.0; строки 200/211 закрыты, 213 сужена | платформа контракт полоса банк | | D39.163 | 28.08 | **Граница контракта получает ВТОРОЕ исключение — `Progress.stage`**, ограниченное двумя условиями: значение ВЫВОДИТСЯ платформой из тех же счётчиков (не проброс из движка) и словарь ОТКРЫТ (клиент рисует незнакомое нейтрально, версия не поднимается). Ради канона мультиязычности: пара с иной формой работы не требует нового клиента. Оговорка по `PD-410`: подпись — модель платформы, не отчёт движка. Третьего исключения нота НЕ разрешает. | жив | ЖИВОЕ: второе и последнее исключение границы | контракт граница мультиязычность | | D39.164 | 28.08 | **Бэкенд-пак «тихая порча» принят и заленджен**: ось `SystemMessages` склеивает системный ряд у провайдера с одним слотом (инъекция банка перестала теряться), дыра выдачи видна в потоке текста, порядок записи решений сменён на rejects-first и повтор документа сходится. Заказ §3.2 пере-формулирован находкой исполнителя (маркер существовал и ВРАЛ), подсказка промта про место правки отклонена с грунтом и это ратифицировано | жив | ЖИВОЕ: строки 193/208 закрыты, 141 наполовину; 228-230 заведены | бэкенд банк экспорт провайдеры | | D39.165 | 28.08 | **Три продуктовых развилки сняты словом владельца.** (1) Единица продажи — цена от ОБЪЁМА исходника (носитель `chapters.units_total`, известен на интейке за $0), потолок объёма в ДВИЖКЕ рядом с денежным, хвост качества в тариф и мерить; ⛔ константу по сегодняшним числам НЕ калибровать (гейт — строка 202). ⚠ Числа §1 ноты — **ИЮЛЬСКИЕ ДЕНЬГИ, с 16.08 не действуют** (×4.47, D39.179 п.1; действующий разбор — `architecture/15-money-path.md` §3 п.3). (2) Смена формы конвейера — СОБЫТИЕ КНИГИ («эпоха»), пересчёт через границу `structure_version`. (3) Продажа пере-прохода — дверь к построенному механизму, смета из `status --json` без долларов (⚠ мина «падение без `--resnapshot`» обезврежена D39.166). Область D39.144 п.1 сужена явно | жив | ЖИВОЕ: три развилки; калибровка цены гейчена строкой 202 | продукт деньги полоса банк | | D39.166 | 28.08 | **Пак P10 принят и заленджен + контрактный минор 0.7.0**: мина под правкой банка обезврежена, пере-проход продаётся членом `RunRequest.re_pass`, согласие даётся ДЕНЬГАМИ (потолок = холд), полоса — «одна неделимая единица работы». ⚠ Первая сдача пака была НЕВЕРНОЙ: широкий самопроход (заказан владельцем) нашёл ТРИ ФАТАЛЬНЫЕ (мина СТОЯЛА, $0-цена муровала дверь, глава-полоса мертва). Новый класс: предложение канону, пережившее пересборку кода, — ГИПОТЕЗА, пока не сверено с деревом | жив | ЖИВОЕ: канон 0.7.0; строки 199/215 закрыты, 231 заведена | платформа контракт банк деньги | -| D39.167 | 28.08 | **Аудит документации (хребет)**: очередь пять дней звала активным исполненный промт и держала на владельце решённую развилку; регистр платформы расходился с актами лендинга ЧЕТЫРЬМЯ строками, одна major — класс «open, а лекарство в дереве» без гейта (строка 225); реестр D-нот потерял две колонки на восьми строках. Журнал ужат 943 → 347 строк, прожитая проза бэкенда — в слайс | жив | ЖИВОЕ: строка 225 (гейт класса); три участка обхода не пройдены | доки процесс регистр аудит | +| D39.167 | 28.08 | **Аудит документации (хребет)**: регистр платформы расходился с актами лендинга ЧЕТЫРЬМЯ строками, одна major — класс «open, а лекарство в дереве» без гейта (строка 225); реестр D-нот потерял две колонки на восьми строках. Журнал ужат 943 → 347 строк, прожитая проза бэкенда — в слайс | жив | ЖИВОЕ: строка 225 (гейт класса); три участка обхода не пройдены | доки процесс регистр аудит | | D39.168 | 28.08 | **Аудит доков, часть 2 — архитектура и ресёрчи.** Класс дороже протухшего факта: НОРМА требует уже ПОСТРОЕННОГО (закон шва предписывал «`status --json` версию не несёт — закрыть», а несёт); доки врали про `accepts_labels` («пусты у всех» при трёх заполненных эндпоинтах) и про грант $5 при коде 0. Четыре мёртвых отчёта (290 КБ) вынесены в `archive/research/` по графу входящих ссылок; двум ресёрчам без шапки поставлены ревю-шапки | жив | ЖИВОЕ: системный класс line-якорей в архитектуре; часть 3 не пройдена | доки ресёрчи архив аудит | | D39.169 | 29.08 | **Платформенный пак P11 принят и заленджен + контрактный минор 0.8.0.** Отзыв сессии гасит открытый SSE-поток (`PD-379`, единственная уязвимость major) и объявляет причину кадром `session_ended`, а не молчаливым обрывом в `401`. ⚠ Второй рубеж поймал СЕМЬ ложных подтверждений в отчёте самой сессии (включая выдуманную мутационную посадку) — код цел, достоверность рассказа нет; охотник вне карты нашёл ЧЕТЫРЕ регресса, введённых самим паком. Норма: линтер якорей гонять ПОСЛЕДНИМ шагом, после того как код замер | жив | ЖИВОЕ: `PD-425` — открытый денежный major, отсрочка на оркестраторе; `PD-424`/`PD-426` отложены с доводом; `PD-423` — условие батареи, которого не знал рецепт | платформа контракт деньги сессии приёмка | | D39.170 | 29.08 | **Движковый пак «деньги» принят и заленджен**: потолок ОБЪЁМА оплаченной работы (`--max-units`) + читающий путь `status` СВОРАЧИВАЕТ банк, поэтому смета пере-прохода впервые доезжает до покупателя ДО покупки, оставаясь $0. ⚠ Пак СНЯЛ ПОСЫЛКУ чужой зоны: довод платформы «status читает ноль сразу после apply» устарел. Блокирующая находка охотника: потолок ПРОБИВАЛСЯ пере-сидом банка посреди прогона (грант 1 → 4 вызова, $0.0073 вместо $0.0036); лечение структурное — пере-план + отказ волны работать с планом чужого снапшота | жив | ЖИВОЕ: ось отгрузки на `once_key` — отдельный заказ; терминолог вне потолка — вход в калибровку цены; проводка `--max-units` ГЕЙЧЕНА | движок деньги потолок приёмка шов | | D39.171 | 29.08 | **Гейт денежной безопасности при `kill -9` четверть раундов проверял ТАВТОЛОГИЮ**: `kill9_test.go` сторожил живость счётчиком по ВСЕЙ базе, а путь создаётся вне цикла раундов ⇒ на пустой базе `committed == sum` = `0 == 0`; замер — **10 раундов из 40 не утверждали ничего**. Второй тест ужимал бюджет ДО построения фикстуры. Оба починены структурно, боевой код не тронут. **Норма: тест не имеет права утверждать о ВРЕМЕНИ, если предмет утверждения — не время; тихо-зелёное дороже красного** | жив | ЖИВОЕ: две замеренные формы дефектного теста; узость класса проверяется по формам и зоне, а не вообще | тесты гейты движок приёмка | | D39.172 | 29.08 | **Пак `sqlc` принят и заленджен**: 40 запросов пяти файлов `pgstore` на типизированный слой, пин 1.31.1, `sqlc diff` в `make check`. ⚠ Решение принято НЕ тем доводом, которым заказывалось: покрытие дало «почти ничего» (3 из 42), а шесть посаженных мутаций ВЫЖИЛИ при зелёной батарее — `sqlgate` видит строку SQL и никогда Go-сторону вызова (`PD-430`). Честные границы: `observe.go` структурно не конвертируется, `Touch` выбрасывает `RowsAffected` — конверсией не чинится | жив | ЖИВОЕ: П-19 править на 40 конвертируемых; `Touch` строкой; пересборка `tmctl` в рецепте стенда; `PD-423` пере-проверить | платформа sqlc гейты деньги | | D39.173 | 30.08 | **У движка появился гейт схемы**: каждый SQL-оператор компилируется `db.Prepare` против схемы, поднятой ПРОДОВОЙ цепью миграций во временный файл — раньше покрытие этого класса равнялось покрытию батареи. ОДИН новый тестовый файл, продовый код не тронут; склейки не пропускаются, а раскладываются. 70 операторов против схемы v16 за 0.02 с, пол экстрактора 65; расхождений в живом коде нет | жив | ЖИВОЕ: гейт не доказывает верность оператора, только существование имён; пол 65 — суждение | движок гейты схема тесты | -| D39.174 | 30.08 | **Передача роли оркестратора №19 → №20.** Смена приняла пять паков (P11 + минор 0.8.0, движковые «деньги», починка двух зеленевших вхолостую store-тестов, `sqlc`, гейт схемы движка). Три урока: тихо-зелёное дороже красного · метод измерения бывает слабее предмета (покрытие сказало «почти ничего», решение приняли шесть выживших мутаций) · верный прогон при неверной гипотезе неотличим от «дефекта нет». Семь ошибок оркестратора названы полностью | жив | ЖИВОЕ: очередь №20 в CURRENT-STATE; `PD-425` на оркестраторе; строка 237 — два нажатых триггера | передача процесс нормы | +| D39.174 | 30.08 | **Передача роли оркестратора №19 → №20.** Смена приняла пять паков — D39.169–D39.173. Три урока: тихо-зелёное дороже красного · метод измерения бывает слабее предмета (D39.172) · верный прогон при неверной гипотезе неотличим от «дефекта нет». Семь ошибок оркестратора названы полностью | жив | ЖИВОЕ: очередь №20 в CURRENT-STATE; `PD-425` на оркестраторе; строка 237 — два нажатых триггера | передача процесс нормы | | D39.175 | 30.08 | **Бэкенд-пак «писатель книги» принят и заленджен** (`8adcb86`): `tmctl build` — EPUB 3 + чистый txt из `BookExport` (`internal/bookfile`, stdlib), шесть состояний честности (pending·withheld·incomplete·ghost·stale; drift — отчётом), отказ exit 16 / `--partial` с маркером на каждой дыре, пути в `StatusArtifacts.book_files`, `tm-export-v1` аддитивно, reader-слова — данные вне `Pack.Version()`. **Слово владельца: drift — НЕ дыра файла; дверь выдачи обязана сверять `BuildReport`** | жив | ЖИВОЕ: строка 236 сужена до двери платформы; хвосты — 238/239; вопросы владельцу — лестница D25.1, лейбл К-3, RTL | движок экспорт файл приёмка дрейф | | D39.176 | 30.08 | **Пакет слов владельца по платформе**: продуктовых КВОТ НЕТ (живём на покупке API, бонусы из админки — `П-12`/`PD-175` сняты как продуктовая развилка, техническая гигиена остаётся инженерной) · продажа ПЛАНИРУЕТСЯ, но не в бете (`П-7` отложен, не отменён) · после пополнения баланса прогон возобновляется ЯВНЫМ действием · фразы пользователя ДЕЛЕГИРОВАНЫ проекту с требованием ИНТЕРНАЦИОНАЛЬНОСТИ — не литерал, а данные по коду причины и локали (гейт `PD-246`/строка 204). Ключи: движок берёт `--keys-file` ИЛИ конвенционный `.env` | жив | ЖИВОЕ: на владельце остался ОДИН платформенный пункт — `PD-421` (держит ли открытый поток сессию живой), переформулирован | платформа продукт владелец квоты фразы | | D39.177 | 31.08 | **Передача роли оркестратора №20 → №21.** Смена приняла пак «писатель книги» (D39.175), закрыла продуктовый лист платформы (D39.176), выдала промт P12 и ратифицировала минор 0.9.0. Три урока: опровергатель промта окупился в третий и четвёртый раз (62 находки) · долг без носителя переживает приёмки · якорь по номеру в файл живой сессии заведомо мёртв. Четыре ошибки названы; ТРИ поймал ВЛАДЕЛЕЦ вопросами «ты уверен / ты дочитал / почему не закрыл» | жив | ЖИВОЕ: очередь №21 в CURRENT-STATE; пять обязательств переходят; незакоммиченное дерево пака P12 — норма, лендить при приёмке | передача процесс нормы аудит | @@ -241,5 +241,5 @@ | D39.181 | 31.08 | **Закон раскрытия движка РАТИФИЦИРОВАН** (слово владельца): правило «факт класса X → потребителю Y по каналу Z» + четыре обязанности как норма зоны `backend/`; **поля леджера доставки в кадре `finished`** (признак объёмного стопа едет ЧИСЛОМ) и **`config_drift_basis` в `status --json`** — оба класса «новое поле контракта шва». Генезис — вопрос владельца «не хаки ли это»: десять из тринадцати правок оказались одной формой «движок знает и не говорит». ⚠ Честная цена: закон загейчен на 40% | жив | ЖИВОЕ: применение к десяти экземплярам — фаза 2 пака; строка 246 (расхождение копий полосы отказов) | движок раскрытие шов контракт | | D39.182 | 31.08 | **Бэкенд-пак «деньги и честность выдачи» ПРИНЯТ И ЗАЛЕНДЖЕН**: закон раскрытия (D39.181) применён к одиннадцати экземплярам; 3 блокера / 15 major / 12 minor, доработка принята. ⚠ ДВА блокера — дефекты В САМОМ ЛЕКАРСТВЕ: разложение денег завышало потери на **+59.8%**, отвергая наивный срез за 29.2%; «дешёвый зонд» выключал починку на денежной поверхности. Три касания чужих тестов санкционированы явно (утверждение · предпосылка · сценарий) | жив | ЖИВОЕ: различение уровней теста — вопрос владельцу · §2.2 против `snapshotdiff` · строка 246 | движок деньги раскрытие приёмка | | D39.183 | 31.08 | **Слово владельца: запрет «не подгонять тесты под зелень» — про МОТИВ.** Правка *чтобы прошло* запрещена; правка от ЗАКАЗАННОЙ или ратифицированной смены поведения — обслуживание, протухший тест не держим. ⚠ Заказанность решает ЗАКАЗ, а не сессия. Условие — объявление в отчёте | жив | ЖИВОЕ: полноту объявления не проверяет ничто — строка бэклога 248 | тесты канон процесс | -| D39.184 | 01.09 | **Передача роли оркестратора №21 → №22.** Смена приняла пак платформы P12 + контрактный минор 0.9.0, холодный прогон движка (закрыт словом владельца), закон раскрытия и его одиннадцать экземпляров; `arch-3` закрыт (89→127 сверяемых якорей). Девять названных ошибок оркестратора. ⚠ Класс смены: **отсутствие в своей области видимости принято за отсутствие вообще — четырежды у трёх участников**; норма — отрицательный результат с ПОЛОЖИТЕЛЬНЫМ КОНТРОЛЕМ | жив | ЖИВОЕ: заказ владельца 01.09 — ревизия доков на протухшее, планы бэкенда и платформы, вынос в архив | передача процесс | +| D39.184 | 01.09 | **Передача роли оркестратора №21 → №22.** Смена приняла P12 + минор 0.9.0, холодный прогон, закон раскрытия и одиннадцать экземпляров — D39.179–D39.182; `arch-3` закрыт. Девять названных ошибок оркестратора. ⚠ Класс смены: **отсутствие в своей области видимости принято за отсутствие вообще — четырежды у трёх участников**; норма — отрицательный результат с ПОЛОЖИТЕЛЬНЫМ КОНТРОЛЕМ | жив | ЖИВОЕ: заказ владельца 01.09 — ревизия доков на протухшее, планы бэкенда и платформы, вынос в архив | передача процесс | | D39.185 | 01.09 | **Четыре строки бэклога закрыты лендингами 31.08, а в таблице стояли открытыми:** 194 (деньги банк-ролей в проекции, A10) · 238 (деньги слепы к правке исходника на месте, A6) · 239 (`checkWave` не видел исчезнувшую стадию, A7+A12) · 240 (оплаченный стоп подписи мог исчезнуть молча, P12). ⚠ 238 и 239 стояли в шапке секции «Бэкенд» как СВОБОДНАЯ РАБОТА ЗОНЫ. Два опровержения текста 194 и честная граница: проекция денег стала НИЖНЕЙ | жив | diff --git a/docs/architecture/05-decisions-log.md b/docs/architecture/05-decisions-log.md index ef129ae1..20d716cd 100644 --- a/docs/architecture/05-decisions-log.md +++ b/docs/architecture/05-decisions-log.md @@ -273,7 +273,7 @@ **2. Докс-диета (заказ владельца 09.08: stale-вес мешает моделям читать).** Перемещено ДОСЛОВНО, без переписывания: (а) зонный журнал платформы 1856→~630 строк — эры P0–P3 (сессии + ратификации P1/P2/P3, вопросы P0/P1) → `platform/docs/archive/platform-PROGRESS-P0-P3.md`; «Текущее состояние» переписано на живые факты; пинги оркестратора (формы артефактов движка) оставлены живыми в хвосте; (б) `docs/PROGRESS.md`: хроника №11–№13 (D39.91–105) + снимок шести бюллетеней шапки эры №15 → `docs/archive/PROGRESS-2026-08-02-04.md`; шапка CURRENT-STATE пересобрана (лента · живое · открыто-на-владельце · указатели; служебные буллеты курс/горизонт/стек/счёт сохранены) (лента закрытого · живое · открыто-на-владельце · указатели); (в) `docs/README.md`: строка «активные промты» сведена к действительно активным, отработанные — общим указателем на архив. Правило прежнее: архив = дословный перенос с баннером, решения живут в D-логе. -**3. Хендофф №16** *(очередь ДОПОЛНЕНА D39.125 п.4: докс-пак 167 — первой задачей)*. Счётчик в `ORCHESTRATOR_SESSION_PROMPT.md` бампнут (№15 закрыт после этой ноты). Очередь — CURRENT-STATE п. «ЖИВОЕ»: лендинг эксп-22 (+вопрос про эксп-23) · промт эмиттера (входное чтение — п.4 D39.123) · платформенный промт по слову. Норма-добавка в промт оркестратора: хендофф-артефакты другим сессиям — только durable абсолютные пути (`~/tm-handoff/`, `~/tm-backups/`), не scratchpad. Незакоммиченного за №15 не осталось; в дереве — только живой полигон (09.08.2026, оркестратор №15). ✅ +**3. Хендофф №16** *(очередь пере-выписана D39.125 п.4 ниже — докс-пак 167 первой задачей; читать её)*. Счётчик в `ORCHESTRATOR_SESSION_PROMPT.md` бампнут (№15 закрыт после этой ноты). Норма-добавка в промт оркестратора: хендофф-артефакты другим сессиям — только durable абсолютные пути (`~/tm-handoff/`, `~/tm-backups/`), не scratchpad. Незакоммиченного за №15 не осталось; в дереве — только живой полигон (09.08.2026, оркестратор №15). ✅ ## D39.125 — ДОКС-ДИЕТА ПО АУДИТУ: D-лог слайсирован (−66%), PROGRESS −42%, факты-против-кода исправлены; нормы формы доков; сессия №15 закрыта передачей №16 (09.08). ✅ @@ -310,7 +310,7 @@ **2. Промты (запуск обоих — по слову владельца; параллельность легальна, зоны не пересекаются; фронт S3.7 живёт в `frontend/` параллельно).** (а) **Бэкенд-эмиттер** `docs/BACKEND_EMITTER_SESSION_PROMPT.md`: строка 103 (журнал `events.jsonl` по форме D39.106; словарь — ответ ДИФФОМ на предложение платформы `events.go`; сквозная проба своим журналом через настоящий декодер платформы в копии зоны) + 135 (гейт потолка пер-вызов) + 165 (различимые exit-коды — PD-113) + 102 опционально; $0; дизайн-развилки нормдока §5 отданы сессии с записью решений; голден/снапшот-нейтральность — обязательное доказательство. (б) **Платформа P5** `platform/docs/PLATFORM_P5_SESSION_PROMPT.md`: П-9 `POST /books` (+PD-72; ⚠ развилка «кто пишет `book.yaml` при интейке» ГЕЙЧЕНА ратификацией — вопрос в зонный журнал до стройки той половины) + стоп/резюм PD-140 (кандидат-дизайн: намерение стопа своей стороной до SIGTERM — дискриминатор против PD-152) + наблюдаемость П-11 + печать конфигурации PD-114 + DEFECT_REGISTER секциями (остаток 167). -**3. Хвост чужого дерева (повтор D39.127 п.4):** строка «активные промты» `docs/README.md` отстаёт (S3.5→S3.7, эмиттер/P5 не назван) и несёт чужой застейдженный полигонный hunk — актуализирует полигонный лендинг (10.08.2026, оркестратор №16). ✅ +**3. Хвост чужого дерева — повтор D39.127 п.4**, актуализирует полигонный лендинг (10.08.2026, оркестратор №16). ✅ ## D39.129 — ПРИЁМКА ФРОНТА S3.7 ПРИНЯТА И ЗАЛЕНДЕНА (`3e465bd`); канон контракта — 0.2.2; арбитраж 8.1: HIGH приёмки S3.6 снята как ложноположительная (10.08). ✅ @@ -587,7 +587,7 @@ **(б) Долг, живший только внутри зоны автора, вынесен наружу.** Строка в бэклог ДВИЖКА про публикацию причин флагов данными (релей §7в) жила только в регистре платформы, который движок не читает — заведена строка **204** · вопрос платформы К ВЛАДЕЛЬЦУ про норму плотности комментариев (PD-255) был объявлен несуществующим её же хендоффом («вопросов на владельце нет») — вынесен в обязательства CURRENT-STATE · норма «жалуйся владельцу, не обходи молча» для фронтового фрагмента хука жила только в моей прозе — написан пинг в зонный журнал фронта. Плюс сняты три строки бэклога (**176/181/187**), закрытые ещё D39.149: очередь всё это время звала 181 свободной работой, то есть направляла сессию чинить построенное. -**(в) Найден жёсткий блокер ВНЕ пака, которого диффовая линза увидеть не могла по построению** (проверен мной построчно): `Sweep` платформы имеет бюджет прохода 2 минуты (`cmd/tmplatformd/runner.go:189`) при бюджете одного прогона 60 с (`internal/runs/reconcile.go:70`) — **двух медленных прогонов достаточно, чтобы проход кончился до `UnsettledRuns`**, единственного ретрая отложенного расчёта, а живые прогоны ниже по списку не реконсилировались и не спавнились; `ListLiveRuns` сортирует по `started_at`, поэтому заклиненный прогон стоит в голове и голодит остальных детерминированно, а ручки нет — `runs.Config.RunBudget` объявлен и в `startRunner` не присваивается. Цена: холд не возвращается, `runs_one_live_per_book` не даёт запустить новый прогон книги. Код приехал в P6, дифф `Sweep` против HEAD идентичен ⇒ ни одна линза приёмки P7 его видеть не могла. ⚠ **`PD-169` стоит `fixed(P5)` и этим ЛЖЁТ приёмке** — его пин гоняет `Sweep` без дедлайна прохода, то есть доказывает пер-прогонный бюджет, а не выживание прохода; пере-открыть. Носитель — первый пункт фикс-листа в пинге №18. **Тот же класс, что строка 198: композиция двух известных по отдельности фактов.** +**(в) Найден жёсткий блокер ВНЕ пака, которого диффовая линза увидеть не могла по построению** (проверен мной построчно): у `Sweep` платформы бюджет прохода 2 минуты при бюджете одного прогона 60 с — **двух медленных прогонов достаточно, чтобы проход кончился до `UnsettledRuns`**, единственного ретрая отложенного расчёта, а заклиненный прогон детерминированно стоит в голове списка и голодит остальные; ручки нет. Код приехал в P6, дифф `Sweep` против HEAD идентичен ⇒ ни одна линза приёмки P7 его видеть не могла. ⚠ **`PD-169` стоит `fixed(P5)` и этим ЛЖЁТ приёмке** — его пин гоняет `Sweep` без дедлайна прохода, то есть доказывает пер-прогонный бюджет, а не выживание прохода; пере-открыть. Носитель — первый пункт фикс-листа в пинге №18; механизм, цена и лечение целиком — в строке регистра `PD-169` и в D39.154 п.2 ниже. **Тот же класс, что строка 198: композиция двух известных по отдельности фактов.** **(г) Побочно получен ответ на вопрос, который я поставил открытым в фикс-листе:** собранный SQL read-модели извлечён через `go/types` и прогнан `EXPLAIN (GENERIC_PLAN)` против мигрированной схемы — 141 запрос, все планируются чисто, тестом СВОЕГО пакета недостижимы десять. ⚠ **Число «десять» как ответ на вопрос «есть ли запрос, которого не касается ни один тест» — НЕВЕРНО, снято аудитом 21.08:** пере-мер покрытием по батарее ЦЕЛИКОМ даёт семь из десяти покрытыми на 58–87% тестами соседних пакетов (например посадка в `ReleaseUnspawned` ловится `internal/runs/sweep_test.go`), реально не покрыты ТРИ — `DeleteOldLoginEvents`, `UserByIdentity`, `Observe`, и все три лежат в осях «вход/сессии» и «метрики», которые пункт 8 фикс-листа называет не смотренными никем. Замер был верен для узкого вопроса «трогает ли запрос тест ЭТОГО пакета» и записан как ответ на широкий. Ни один из десяти не трогает схему 00016–00024. Дыры в схеме пака нет; гейт нужен как ПОСТОЯННЫЙ, потому что именно он делает этот ответ воспроизводимым. @@ -601,11 +601,11 @@ **(г) Собственная архивация убила четыре `file:line`-якоря, и гейт этого не увидел.** Врезав пятистрочные баннеры в архивируемые доки, оркестратор пере-адресовал ПУТЬ и не пере-считал НОМЕР. Два из четырёх стоят в этой самой ноте и охраняют число «96%» от удаления как фантома — улика, защищающая число, перестала резолвиться. ⚠ **`counts.py --lint` дал зелень на все четыре**, потому что проверяет только существование файла и переполнение номера, а `platform/docs`/`frontend/docs` не сканирует вовсе — носитель находки — новая строка **205**. Инструмент не просто не поймал: он создал ложную уверенность, заменив собой ручную сверку. -**(д) Живая инструкция убита архивацией.** Баннер утверждал, что рецепт стенда «переехал в `STACK_DECISIONS`», тогда как переехали две грабли из четырёх разделов: сборка бинарей, шаблон книги, ОБА гейта батареи с предупреждением «без них `make check` МОЛЧА скипует ~200 тестов» и переменные дев-демона остались единственным экземпляром в доке под баннером «инструкции НЕ исполнять» — при том что `platform/README.md` отсылает за рецептом именно в `STACK_DECISIONS`. Перенесено по-настоящему 21.08. +**(д) Живая инструкция убита архивацией.** Баннер утверждал, что рецепт стенда «переехал в `STACK_DECISIONS`», тогда как часть его разделов осталась единственным экземпляром в доке под баннером «инструкции НЕ исполнять» — при том что `platform/README.md` отсылает за рецептом именно туда. Перенесено по-настоящему 21.08; действующая редакция рецепта — в `STACK_DECISIONS` (греп `МОЛЧА скипует`), и её числа с этой ноты ушли вперёд. **(е) Ложное число в ратифицированной ноте:** «тестом недостижимы ДЕСЯТЬ запросов» — пере-мер покрытием по батарее ЦЕЛИКОМ даёт ТРИ. Клейм снят ПО МЕСТУ, в п.8(г) выше; там же имена трёх, доля покрытия семи и разбор «замер верен для узкого вопроса, записан как ответ на широкий». -**(ж) Две новые дыры пинов, найденные посадками аудита** (пункты 12–13 фикс-листа): снятие изоляции `RepeatableRead`+`ReadOnly` у `inReadTx` проходит ВСЮ батарею, хотя под инвариантом шесть ручек выдачи и PD-163; и оговорка `book_id <> $2` в `CreditHeldBy` не исполняется ни одним пином, потому что в фикстуре у исключаемой книги нет холда. Обе — в коде, приехавшем НОВЫМ в P7, то есть внутри диффа, который читали шесть линз приёмки. +**(ж) Две новые дыры пинов, найденные посадками аудита** (пункты 12–13 фикс-листа): изоляция `inReadTx` и оговорка `book_id <> $2` в `CreditHeldBy` не исполнялись ни одним пином; обе — в коде, приехавшем НОВЫМ в P7, то есть внутри диффа, который читали шесть линз приёмки. Обе с тех пор запинены, и каждый пин называет эту посадку (греп `Mutation caught` в `platform/internal/pgstore/`). **(з) Диагноз, который важнее списка.** Самодиагноз оркестратора («триаж глазами вместо машинной сверки») объясняет три находки из двадцати трёх и уводит от причины: остальные двадцать — это места, где рекомендация БЫЛА исполнена ровно один раз, и машинная сверка их бы не поймала. Настоящая форма: **стандарт держится в КОДЕ и обрушивается в ПРОЗЕ О ФАКТАХ** — единственной среде, где утверждение не опровергнет ни компилятор, ни тест, ни гейт. Все код-якоря оркестратора резолвятся, отказ править `ContractVersion` был верным, дыра `emitFrame` найдена им же — а рядом в прозе рождается «ручка появилась 13.08» со ссылкой на молчащую ноту. ⚠ И форма ЗАРАЗНА: линза-аудитор с чек-листом пометила два самых ложных клейма репозитория как ЗАКРЫТЫЕ, потому что проверила, что ПРАВКА СУЩЕСТВУЕТ, а не что КЛЕЙМ ИСТИНЕН. Отсюда норма, которую эта нота вносит: **«ревью исполнением» значит исполнить САМ КЛЕЙМ** — открыть цитируемую строку, пере-мерить число, дойти до первоисточника ссылки, — а не подтвердить, что редактирование приземлилось; и применять это к прозе о фактах ровно так же строго, как к коду. @@ -655,9 +655,9 @@ **9. Ответ по sqlc (вопрос владельца).** Граница П-19 сходится точно (41 запрос, пере-считано), но описана оптимистичнее: набор НЕ замкнут по транзакции (8 из 41 идут из транзакций неконвертируемого кода), а «11 денежных запросов в чужой транзакции» занижено вдвое — их 20. Главное: **гейт `TestEverySQLStatementParsesAgainstTheMigratedSchema` съел бо́льшую часть ценности** — он закрывает класс «нет такой колонки» для всех 162 операторов, включая 121, куда sqlc не дойдёт никогда и где случились оба реальных падения зоны. Остаётся арность `$n` и целей `Scan`: два запроса из 41 не исполняются ничем, закрывается поведенческим тестом. Рекомендация №18: брать, когда что-то другое заставит тронуть эти пять файлов; решение за владельцем, он сказал «БЕРЁМ». -**10. Мои ошибки этой смены, названные полностью.** (а) Число отпечатков миграций «41» написано из головы — их 25, поймал аудит. (б) Баннер в промте читающего пака утверждал «оси 1, 2 и 4 не тронуты» — тронуты 1 и 4, поймал аудит через час после моей записи. (в) «Добавить новый термин работает» — верно лишь в неважной половине: движок файл примет, но mined-строки исключены из БАЗОВОГО банка, значит термин доедет до редактора и НИКОГДА до черновика. (г) Причинность 203(з), п. 6 выше. (д) Довод склейки контрактного батча, п. 8. **Общее у всех пяти: ни одна не в коде, все в ПРОЗЕ О ФАКТАХ — той единственной среде, где утверждение не опровергнет ни компилятор, ни тест, ни гейт (диагноз D39.153 §9(з) подтверждён на мне ещё раз).** +**10. Мои ошибки этой смены, названные полностью.** (а) Число отпечатков миграций «41» написано из головы — их 25, поймал аудит. (б) Баннер в промте читающего пака утверждал «оси 1, 2 и 4 не тронуты» — тронуты 1 и 4, поймал аудит через час после моей записи. (в) «Добавить новый термин работает» — верно лишь в неважной половине: движок файл примет, но mined-строки исключены из БАЗОВОГО банка, значит термин доедет до редактора и НИКОГДА до черновика. (г) Причинность 203(з), п. 6 выше. (д) Довод склейки контрактного батча, п. 8. **Общее у всех пяти: ни одна не в коде, все в ПРОЗЕ О ФАКТАХ — диагноз D39.153 §9(з), подтверждённый на мне ещё раз.** -**11. Что ловило меня лучше, чем я сам** — новому №19 стоит на это опереться: гейт токенов якорей поймал четыре мёртвых ссылки, три из них сломала МОЯ ЖЕ архивация · `counts.py --check` держал числа очереди при каждом касании · опровергатель-субагент убил 30 находок из 132 и две мои собственные формулировки. Норма отсюда: **посадка мутации обязана называть пакет, где ищется ПИН, а не где лежит правка** — две мои посадки дали ложное «выжила» из-за этого, и необъявленная ошибка харнесса приёмки опаснее пропущенной, потому что выглядит как результат. +**11. Что ловило меня лучше, чем я сам** — новому №19 стоит на это опереться: гейт токенов якорей поймал четыре мёртвых ссылки, три из них сломала МОЯ ЖЕ архивация · `counts.py --check` держал числа очереди при каждом касании · опровергатель-субагент убил 30 находок из 132 и две мои собственные формулировки. Норма о посадке мутации, обязанной называть пакет, где ищется ПИН, — D39.154 п.6 (там же её провенанс). **12. Передача.** Счётчик роли бампнут **№18 → №19** (D39.112 п.6). Очередь, порядок работ по платформе и все блокеры — CURRENT-STATE. На владельце к моменту передачи: развилка владения `book.yaml` (199а) · веса `pro` (172-г, дешёвый вход — вендор-сверка, полигон только что делал такую по Gemini) · санкция на первый прогон с редакторской волной. (22.08.2026, оркестратор №18) ✅ diff --git a/docs/architecture/06-memory-risk-registry.md b/docs/architecture/06-memory-risk-registry.md index 06ab0210..c52d70ff 100644 --- a/docs/architecture/06-memory-risk-registry.md +++ b/docs/architecture/06-memory-risk-registry.md @@ -30,9 +30,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 бюджет заполняется по приоритету, не по точности | -| A2 | **Ошибочная инъекция** (омограф/короткий алиас/низкорелевантный сосед) → модель послушно следует мягкой инструкции, уверенность растёт, точность падает (2510.00829) — **главный источник тихой деградации** | С / 🔴🔇 | Трёхстороннее явное решение **на каждую запись-кандидат**: `CONFIRMED` (точный ключ/лемма, `approved`, спойлер-валидна) → авторитетно; `AMBIGUOUS` (короткий/общий алиас, коллизия поверхности, `auto/draft`) → инъекция с явной пометкой «unverified — проверить» **+ принудительный post-check**; `REJECT` → выкинуть и залогировать. Паттерн CRAG (accept/verify/reject), но каждая ветка наблюдаема | DET | сборщик контекста + `disposition`-запись | 1 | ❌ спроектировать трёхсторонний disposition; сейчас инъекции нет вовсе | +| 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 | 🔶 ключевая гигиена как констрейнт схемы (новое) | -| A4 | **Молчаливо-пустой матч из-за орфографии** (упрощ./трад. 鲁/魯, полу/полноширинные, кандзи↔кана 鈴木/すずき, ruby-чтения) → ключ есть в тексте, но не в той форме → запись не инъектируется | В / 🟠🔇 | Обязательный слой **нормализации перед матчем** (NFKC + OpenCC упрощ./трад. + kana-folding + захват ruby-чтений), симметрично к ключам/алиасам и тексту чанка; версионированный тестируемый артефакт | DET | pre-match нормализация (связать с pre-replace GalTransl); поле `aliases` | 1 | ❌ в research/05 §5.2 нормализация матчинга не описана — самый вероятный баг «тихо пусто» | +| 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 | 🔶 | | A7 | **Эмбеддинг-порог как тихий гейт** (Фаза 2): единый глобальный cosine-порог ведёт себя как эвристика entity-overlap и ломается на сдвиге распределения (репродукция CRAG, 2603.16169); zh/ja→ru литература — и есть сдвиг | С / 🟠🔇 | Эмбеддинг-слой держать **low-trust**: калибровать порог per-книга/язык на held-out чанках; использовать для генерации **кандидатов на ревью** (флешбеки, редкие термины), **не** для тихой инъекции в горячий путь | DET+HUMAN | Фаза-2 retrieval-слой | 2 | 🔶 research/05 подаёт эмбеддинги как безобидный «второй эшелон» без порога/воздержания | @@ -78,8 +78,8 @@ | # | Сценарий отказа | Вер./Тяж. | Механизм защиты | Слой | Где в коде/схеме | Фаза | Статус | |---|---|---|---|---|---|---|---| -| F1 | **`snapshotID` не покрывает память → тихий расходящийся ре-пэй (D5.2)**. Подтверждено кодом: `snapshotID` (`snapshot.go:82 (до пакета №4 — runner.go:145-163)`) хэширует brief/chunker/план-стадий/сэмплинг, но **не** версию approved-глоссария и **не** параметры сборки контекста; `RequestHash` (`render.go:158`) включает контент `msgs`; `render.go:23-29` декларирует рендер «чистой функцией snapshot». Как только Фаза 1 инъектит память в `msgs` (`render.go:133-136`): изменённый глоссарий/STM меняет `request_hash`, но не `snapshotID` → resnapshot-гейт (`bookrun.go:108/stagerun.go:77 (до пакета №4 — runner.go:260)`) молчит → ре-ран старой главы промахивается мимо чекпоинта и **переоплачивает расходящимся переводом**, ломая инвариант Р6 | В / 🔴🔇 | **Свернуть в snapshot ОБА:** (1) состояние памяти (**content-hash материализованного** банка на момент старта джобы — рендер читает **замороженную** версию, не 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 | ❌ политика и лог вытеснения не специфицированы (находка критика) | +| 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 | 🔶 нет строки бэкапа/интеграла (находка критика) | | F5 | **Коррелированный отказ судьи-экстрактора**: адъюдикация конфликтов и подтверждение кандидатов — одна модель на одних и тех же трудных кейсах (редкие имена, неоднозначный смысл) → систематически-неверный судья тихо промоутит плохие approved-ключи → retrieval-state lock-in | С / 🟠🔇 | Независимая проверка (судья чужого семейства / человек) на промоушене approved-ключа; first-encounter имя не промоутится в approved до батч-подтверждения раз в главу | LLM(2-й)+HUMAN | пайплайн подтверждения терминов | 2 | 🔶 (находка критика; смыкается с A2/B1) | @@ -88,23 +88,23 @@ | # | Сценарий отказа | Вер./Тяж. | Механизм защиты | Слой | Где в коде/схеме | Фаза | Статус | |---|---|---|---|---|---|---|---| -| G1 | **Качество автоэкстракции (bootstrap)**: все направления валидируют *retrieval*, но не *популяцию*. Мусор/пропуск главного персонажа на входе → горячий путь верно инъектит мусор / молча опускает — **корневой отказ выше всего измеренного** | С / 🟠🔇 | **Разделить задачу экстракции на две (индикативно замерено, `eval/extract_bench.py`): (а) СПОТ кандидатов-спанов — локаль годится** (qwen3-abliterated:8b recall 1.0 на zh+ja, 0 галлюцинаций, ~15с/чанк — дёшево на стенде); **(б) РЕНДЕРинг dst — локаль НЕ годится** (0.0–0.5: 阿Q→«А Цзы», 羅生門→«Россомаха», 秀才→«шоуцай» — как exp03), dst даёт сильная/облачная модель + человек. First-encounter unknown → `status=auto/unconfirmed`, гейт (батч-судья/человек) **до** промоушена в approved; alarm «имя-подобный токен без записи → неизвестная сущность» (DelTA-паттерн). ⚠ deepseek-v4-flash молча вернул **пустой** ответ на части чанков (祝福 воспроизводимо) — это тот empty-paid-response, что ловят D2/coverage-гейт | DET(алярм)+LLM(спот=локаль / рендер=облако)+HUMAN | pre-пасс NER; статус-машина термина | 1–2 | 🔶 верифицировано (exp06, 13 моделей × 12 кейсов zh/ja/en): спот локальный OK (recall ~0.98 все языки), рендер локали язык-зависим (en 0.82 / ja 0.53 / **zh 0.26**) → спот=8b, рендер dst=облако(gemini-flash value)/человек, на zh + таблица Палладия B6 | +| G1 | **Качество автоэкстракции (bootstrap)**: все направления валидируют *retrieval*, но не *популяцию*. Мусор/пропуск главного персонажа на входе → горячий путь верно инъектит мусор / молча опускает — **корневой отказ выше всего измеренного** | С / 🟠🔇 | **Разделить задачу экстракции на две (индикативно замерено, `eval/extract_bench.py`): (а) СПОТ кандидатов-спанов — локаль годится** (qwen3-abliterated:8b recall 1.0 на zh+ja, 0 галлюцинаций, ~15с/чанк — дёшево на стенде); **(б) РЕНДЕРинг dst — локаль НЕ годится** (0.0–0.5: 阿Q→«А Цзы», 羅生門→«Россомаха», 秀才→«шоуцай» — как exp03), dst даёт сильная/облачная модель + человек. First-encounter unknown → `status=auto/unconfirmed`, гейт (батч-судья/человек) **до** промоушена в approved; alarm «имя-подобный токен без записи → неизвестная сущность» (DelTA-паттерн). ⚠ deepseek-v4-flash молча вернул **пустой** ответ на части чанков (祝福 воспроизводимо) — это тот empty-paid-response, что ловят D2/coverage-гейт | DET(алярм)+LLM(спот=локаль / рендер=облако)+HUMAN | pre-пасс NER; статус-машина термина | 1–2 | 🔶 верифицировано (exp06, 13 моделей × 12 кейсов zh/ja/en): спот локальный OK (recall ~0.98 все языки), рендер локали язык-зависим (en 0.82 / ja 0.53 / **zh 0.26**) ⚠ маршрут «спот=локаль» SUPERSEDED — петля закрыта Go-майнером + reject-set (шапка) | | G2 | **Человеческая ёмкость — недоказанная петля всей safety-аргументации**: почти каждая защита кончается «флаг → редактору/человеку». Объём флагов на главу никто не оценил; при высоком flag-rate «route to human» пусто → деградация тихая на практике | С / 🟠🔇 | Оценить flag-volume на главу на пилоте; alarm-пороги и aggregate «memory-coverage»-сигнал; безлюдный режим: auto→approved с записью в журнал (Р7), но с явной пометкой качества | DET(телеметрия)+HUMAN | `retrieval-state` запись; отчёт «паспорт качества главы» | 1–2 | ❌ flag-rate × throughput не смоделирован (находка критика) | --- ## Контракт горячего пути (снять противоречие до «где в коде») -Направления разошлись в описании несущего компонента; **резолюция**: +**Резолюция** (то же решение — `03-implementation-notes.md` §3.6): -1. **Горячий путь — НЕ FTS5.** impl-notes §3.6 (строки 123-124) уже решает: «FTS5 в горячий путь v1 не тащить (unicode61 не сегментирует CJK; селективной инъекции хватает точных ключей/алиасов по обычным индексам)». То есть горячий путь — **детерминированный multi-pattern матч** (Aho-Corasick/double-array trie по `src`+алиасам над нормализованным чанком; для ru/en — по леммам/`decl`). FTS5/BM25 на горячем пути для zh/ja **молча вернёт ничего** (дефолтный токенайзер не сегментирует CJK) — их туда не ставить. Эмбеддинги на горячем пути — тоже нет (Р3). Это подтверждено эмпирикой (A3). -2. **sqlite-vec: причина отказа — «держим modernc единым драйвером / избегаем WASM-миграции», а НЕ «pure-Go не может»** (рациональ уже переписан в Р3 `01-decisions.md`; `ncruces/go-sqlite3`+`asg017/sqlite-vec-go-bindings` — официально поддерживаемый CGO-free путь). Решение brute-force KNN в MVP остаётся верным: эмпирика Q2 — <20 мс на 100k×1024-d в чистом numpy, sqlite-vec-scalar 81–108 мс на 1M, на порядки выше нужд одной книги. ncruces+sqlite-vec — самый дешёвый триггер миграции, если вектора станут узким местом. +1. **Горячий путь — НЕ FTS5**, а **детерминированный multi-pattern матч** (Aho-Corasick/double-array trie по `src`+алиасам над нормализованным чанком; для ru/en — по леммам/`decl`). FTS5/BM25 на горячем пути для zh/ja **молча вернёт ничего** (дефолтный токенайзер не сегментирует CJK) — их туда не ставить. Эмбеддинги на горячем пути — тоже нет (Р3). Это подтверждено эмпирикой (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 — ИСПОЛНЕНЫ Список из пяти пунктов (F1-снапшот · поля `sense`/ось редакционного времени/`UNIQUE(src,sense,window)`/`min_key_len`/нормализация · обязательный post-check · трёхсторонний disposition + `retrieval-state` · отложенное в v1.1) закрыт стройкой и снят как план: схема — `backend/internal/store/migrate.go` (`sense`, `since_ch/until_ch`, `UNIQUE(book_id,src,sense,since_ch,until_ch)`, `allow_short` как escape-hatch к `min_key_len`), нормализация — `internal/text`, disposition CONFIRMED/AMBIGUOUS/REJECT и `retrieval-state` (`n_exact_hits, n_sticky, n_ambiguous_flagged, n_spoiler_blocked, n_evicted`) — `internal/membank` + `store/glossary.go`, Палладий/Поливанов B6 — `internal/lang` + `configs/langpacks/<пара>/palladius*.txt` (D39.16). Бэкап/интеграл файла книги (F4) тоже построен — `store.BackupSQLite`/`store.IntegrityCheck` + `tmctl backup` (хвост — в бэклоге `../PROGRESS.md`). Из отложенного НЕ построено (греп по `backend/` — 0 хитов): гейт фактичности резюме (D1 — резюме нет вовсе), whole-book эмбеддинг-слой (A7/D2 — горячий путь по-прежнему «no embeddings»), морфо-гейт глагольного рода (C3, Ф2). -### Ruby-seed контракт +### Ruby-seed контракт (форма подтверждена оркестратором 05.07) Исполнен: захват — `ruby_readings(book_id, base, reading, first_chapter, occurrences)` (capture-only), маппинг в кандидаты — `membank.rubyToCandidates` (код ссылается сюда). Инварианты контракта: - `base` (кандзи) → `src`; `first_chapter` → `since_ch`; `occurrences` → **приор уверенности** (не прямой approved). diff --git a/docs/architecture/09-target-architecture.md b/docs/architecture/09-target-architecture.md index dbc4dee5..6b63410f 100644 --- a/docs/architecture/09-target-architecture.md +++ b/docs/architecture/09-target-architecture.md @@ -167,11 +167,9 @@ ## 5. Процесс против «сломанного телефона» (концерн 5) -Постоянный **findings-ledger** как повторяющийся шаг оркестратора (этот аудит — первый экземпляр, `08-*`): -- Каждая находка полигона/ресёрча/аудита получает явную диспозицию (FAITHFUL/DISTORTED/LOST/WORKAROUND_NOT_ROOT/ - UNTESTED_ASSUMPTION/NEVER_CLOSED/CODE_SMELL) и трекается **до закрытия** (fixed / ratified-deferred / retracted). -- Вопросы «к бэкенду» из ресёрча (research/18 §D) обязаны получать ответ, маршрутизируемый обратно (сейчас висят). -- Периодический completeness-critic прогон (как этот) на границе фаз — не разовый. +Постоянный **findings-ledger** — замысел ИСПОЛНЕН и повторяется: первый экземпляр `../archive/architecture/08-sync-audit-ledger.md` (там же словарь диспозиций и правило «трекать до закрытия»), сегодня — `../DOC_REVISION_FINDINGS.md`/`../DOC_CLEANUP_PLAN.md`, `backend/docs/SEAM_PACK_FINDINGS.md`, реестр нот D39.126. + +⚠ **Живой остаток:** вопросы «к бэкенду» из ресёрча маршрута обратно так и не получили (`research/18` §D, п.7 помечен «вопрос бэкенду»). --- diff --git a/docs/architecture/10-prompt-architecture.md b/docs/architecture/10-prompt-architecture.md index 6ccf52da..ebedf918 100644 --- a/docs/architecture/10-prompt-architecture.md +++ b/docs/architecture/10-prompt-architecture.md @@ -25,7 +25,7 @@ | `zh-ru/judge-selector.md` | Ф2 (не исполняется) | — | — | - `analyst.md` снесён паком-1 как сирота. **`terminologist.md` — живая роль пар-пака** (D39.42/45, интерим-текст; финальный — по замерам); рядом `translator-banknote.md` — вариантный шиппинг-файл банкноты (D39.45/53). -Правила, сидящие В ТЕЛЕ промтов (кандидаты на извлечение в пакет пары после exp15): русское тире-оформление +Правила, сидящие В ТЕЛЕ промтов (кандидаты на извлечение в пакет пары): русское тире-оформление диалога; «пиши живым русским»; паратаксис→гипотаксис-блок; чэнъюй-политика; few-shot-примеры (структурные, по-русски). Переменные брифа (`{{transcription}}` и пр.) — уже данные книги, НЕ пакета. @@ -33,7 +33,7 @@ Версионируемый **пакет конвенций пары** `src→tgt[×genre]`, снапшот-folded: дискурс-правила пары + few-shot (в языке пары) + **язык промпта** + нормы транскрипции (Палладий для zh→ru, Поливанов для ja→ru — как выбираемые политики) + лимитеры полноты. Стадия резолвит промпт из пакета по `Book.LangPair()` (сеам уже -работает). Гейты на стройку: exp15 (какие правила реально несут) + research/18 §D-3 (форма пакета). +работает). Гейт на стройку остался один — research/18 §D-3 (форма пакета не разрешена): exp15 отработан (§4 п.2). ## 4. Открытое по теме (маршрутизировано) 1. **Язык промпта** — первый замер Р6/D39.61 отрицателен (см. §1); добор — с реальной не-ru книгой (ja→ru). @@ -43,4 +43,4 @@ ОТВЕРГНУТ для гейт-предикатов (CLDR-инстабильность в вердиктах — D39.16). 3. **Транскрипция per-book** (Палладий/Поливанов vs фандомные формы) — research/19 §E.3, решение владельца НЕ горит (дефолт: политика в пакете пары, слой 2); `{{transcription}}`-переменная уже есть. -4. **Q4c** — где жить структуре (переводчик / редактор / отдельный пасс): единственное неизмеренное плечо. Q4a измерен (D39.9: верность на translate-стадии не покупается), Q4b прогнан и принят (эксп-19, D39.108), топологию решил эксп-21 (D39.117). Границы Q4c — `docs/experiments/19-editor-contract-q4b.md` §«Границы». +4. **Q4c** — где жить структуре (переводчик / редактор / отдельный пасс): единственное неизмеренное плечо; измеренные соседи Q4a/Q4b и топология — в §1, строка «Почему структура абзацев…». Границы Q4c — `docs/experiments/19-editor-contract-q4b.md` §«Границы». diff --git a/docs/architecture/12-go-style-notes.md b/docs/architecture/12-go-style-notes.md index 9cabda6f..fc06a1d8 100644 --- a/docs/architecture/12-go-style-notes.md +++ b/docs/architecture/12-go-style-notes.md @@ -14,7 +14,7 @@ ## §1. Go-ответы (только то, о чём реально спорим) - **Язык кода (владелец 20.07): английский** — комменты, логи, операторские дашборды/error-msg, detail-флаги. **Русским (target-языком) ОСТАЮТСЯ и не трогаются:** wire/инъекц-промпты, которые читает модель (`glossaryBlockHeader`, маркер `⟨проверить⟩`, gender-аннотации; ⚠ снятие маркера с провода — санкционированная правка строкой 134 по D39.104, двигает RequestHash; правило неперевода остальных wire-строк в силе); lang-data таблицы гейтов; тест-данные перевода. Почему: перевод wire-строки = тихая смена инструкций модели → сдвиг вердиктов + `--resnapshot` (переоплата, D30.9); перевод lang-data ломает чекеры (матчат литералом). Проверка нейтральности правки: golden байт-идентичен по content_hash/final_hash. -- **Имена без аббревиатур этапов (владелец 19.07):** ни `W0`/`W1`/`W1.5`/`W2` в идентификаторах, логах и комментариях — пишем `waveDraft`/`waveEdit`, «draft wave started». Аббревиатуры волн жили в разработке и в глоссарий попали как ИСТОРИЯ; в код и в операторский вывод они не возвращаются. +- **Имена без аббревиатур этапов (владелец 19.07):** ни `W0`/`W1`/`W1.5`/`W2` в идентификаторах, логах и комментариях — пишем `waveDraft`/`waveEdit`, «draft wave started». Аббревиатуры волн попали в глоссарий как ИСТОРИЯ и оттуда не возвращаются. - **Комментарий режется по ВОДЕ, а не по длине (владелец 26.07, формулировка уточнена им же 21.08).** ⚠ Счёт строк («пиши одну-две») — негодный гейт и был снят: комментарий на три строки может быть нужен, на одну — достаточен, длиной это не решается. Режем то, что не помогает читателю КОДА: пересказ решений («владелец решил… и поехали»), провенанс, сага о том, как шли, изложение исследования вместо краткой ссылки на него. Остаётся столько, сколько нужно, всё, что из одной функции НЕ выводится: порядок блокировок, инварианты между таблицами, цена забывания, вендор-квирк. Проверочный вопрос — «поможет ли это тому, кто через полгода правит именно эту функцию», а не «сколько тут строк». - **PlantUML: две ловушки activity-синтаксиса, каждая уже стоила реального бага (25.07).** Точка с запятой ВНУТРИ многострочной метки обрывает её; строка метки, начинающаяся с `/ | < > ] }`, читается парсером как спец-терминатор. ⚠ Диаграммы НЕ рендерить в svg/png — владелец смотрит расширением VS Code (гардрейл `CLAUDE.md`); дом диаграмм — `backend/docs/`, правятся одним коммитом с кодом. - **Код группируется логическими папками по назначению, а не свалкой `archive/` (владелец, про КОД).** Архив-метафора законна для доков и промтов; для кода каталог обязан называть предмет. diff --git a/docs/architecture/13-tech-debt-anchors.md b/docs/architecture/13-tech-debt-anchors.md index 8c9d5f22..e273ba35 100644 --- a/docs/architecture/13-tech-debt-anchors.md +++ b/docs/architecture/13-tech-debt-anchors.md @@ -2,49 +2,42 @@ > ⚠ **Освежение 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`. Здесь оставлен только ДЕЙСТВУЮЩИЙ статус. - -**Метод:** 4 адверсариальных верификатора (author≠reviewer к свипу) против backend-кода и D-лога; вердикты CONFIRMED_LOST / ALREADY_BUILT / ALREADY_CLOSED / RESCOPE, evidence обязателен. **Итог: 23 пункта — 20 CONFIRMED_LOST · 3 RESCOPE · 0 ALREADY_CLOSED (передумываний не найдено).** RESCOPE вправлены в бэклог тем же лендингом (строки 81/73/49). +> **Снятая мёртвая половина** (историческая улика ОТСУТСТВИЯ механизмов — снимок свипа 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`. ## Срез: строки 81/83/85 + инфра-дописки -### [RESCOPE] Строка 81 — ja-преп B6-ja: Поливанов-валидатор + kana-омограф POS/known-word гейтинг (D17.1) + чек-лист kana-алиасов сида (D16.4) +### [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` («ruby_reading … bridge to Polivanov dst validation, B6 Phase 2 — NOT a dst»; grep polivanov/Поливанов по backend/*.go даёт только значения конфига в тестах/примерах и комментарий backend/internal/config/book.go:50 — валидирующего кода нет. (2) kana-омограф гейтинг — `backend/internal/membank/memory.go`, греп `KANA and HAN are deliberately NOT boundary-checked`: «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-алиасов сида существует — backend/README.md:38 «## Подготовка ja-книги (чек-лист сида)» с пунктом «Kana-написания имён = matchable … внеси в aliases: руками — иначе „тихо пусто"», а сам механизм D16.4 (ruby-чтение → авто-алиас ручного термина с громким скипом омофонной коллизии) реализован: backend/internal/pipeline/bankmaterialize.go:88-94 (membank.AttachRubyAliasesToManual) — это ровно интерим-фикс из 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` — валидирующего кода нет. (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 + `backend/internal/pipeline/bankmaterialize.go`, греп `AttachRubyAliasesToManual`); в чек-листе остался лишь Ф2-хвост «двойные чтения (強敵→とも) полная дизамбигуация», и он тоже под B6. -**Фикс/скоуп:** Сузить строку 81 до двух реально отложенных работ: «Поливанов-валидатор (translit_policy Phase 2, store/migrate.go:186/194) + kana-омограф POS/known-word гейтинг / B6-токенизатор (memory.go:1048)»; компонент «чек-лист kana-алиасов сида (D16.4)» пометить built (backend/README.md:38 + bankmaterialize.go:92) — в чек-листе остаётся лишь Ф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» — висящее поручение, и 02-mvp-plan.md:34 «пере-съём exp08 v3» как открытый. +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» — висящее поручение, и 02-mvp-plan.md:34 «пере-съём exp08 v3» как открытый. Скоуп — пилот-преп-промт Ф2.5, дельта вписана в docs/POLYGON_PACKAGE4_SESSION_PROMPT.md:4. -**Фикс/скоуп:** Не требуется — занесено правильно (пилот-преп-промт, Ф2.5); дельта уже вписана в docs/POLYGON_PACKAGE4_SESSION_PROMPT.md:4. ### [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) — усечённый по контексту текст принят как годный. +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 без решения, полигон-пакет до МАСШТАБА. -**Фикс/скоуп:** Не требуется — занесено правильно (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). +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). Скоуп: мелкие хвосты качества одним паком. -**Фикс/скоуп:** Не требуется — занесено правильно (мелкие хвосты качества одним паком). ### [CONFIRMED_LOST] Дописка к строке 11 — судьба v1.1 quote-absorption при флипе coverage-гейта (D12-Q1) -Go-гейт стоит на v1 без поглощения кавычек: backend/internal/checks/coverage.go:39 `CoverageGateVersion = "coverage-v1-naive-split-lower-bound"`; grep quote/кавыч/absor/поглощ по coverage.go — 0 вхождений. Python-оракул тоже: eval/refusal_bench.py split_sentences (строка 81) без absorption-логики (grep absorb/quote — 0 содержательных попаданий). Дефер задокументирован в обе стороны: eval/coverage_precision.py:14–16 «naive sentence segmentation can undercount RU sentences vs a CJK source (quote-absorbing §3.7 is deferred to v1.1)» и D-лог (D12 Q1) «§3.7 „поглощение кавычек" → v1.1 (координированно)». Гейт при этом выключен (шапка coverage.go: «opt-in (gates.coverage.enabled)») — решение о судьбе v1.1 реально висит на флипе. +Go-гейт стоит на v1 без поглощения кавычек: backend/internal/checks/coverage.go:39 `CoverageGateVersion = "coverage-v1-naive-split-lower-bound"`; grep quote/кавыч/absor/поглощ по coverage.go — 0 вхождений. Python-оракул тоже: eval/refusal_bench.py split_sentences (строка 81) без absorption-логики (grep absorb/quote — 0 содержательных попаданий). Дефер задокументирован в обе стороны: eval/coverage_precision.py:14–16 «naive sentence segmentation can undercount RU sentences vs a CJK source (quote-absorbing §3.7 is deferred to v1.1)» и D-лог (D12 Q1) «§3.7 „поглощение кавычек" → v1.1 (координированно)». Гейт при этом выключен (шапка coverage.go: «opt-in (gates.coverage.enabled)») — решение о судьбе v1.1 реально висит на флипе (владелец, Python-first лок-степ). -**Фикс/скоуп:** Не требуется — занесено правильно (решение владельца при флипе, Python-first лок-степ). ### [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, строки 409/422; нотация D33.4a встречается в research/18-quality-levers.md:213) — на вердикт не влияет. +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. -**Фикс/скоуп:** Не требуется по существу; опционально при док-пассе поправить ссылку «D33.4б» на фактический носитель решения (серия D33.x в теле D33). ## Срез: строки 80/82/84 + кандидаты 73 @@ -56,7 +49,7 @@ grep sanitiz по backend/configs/pipeline-c2.yaml — 0 вхождений (exi ### [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|''» (store/migrate.go:183; 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), не род глагола. Отложенность зафиксирована 06-memory-risk-registry.md (греп по названию пункта — номера съехали +6 коммитом d2cd30c) («Отложено в v1.1/Фазу 2 … морфо-гейт глагольного рода (C3)») — жива, не закрыта. **Фикс/скоуп:** Строка верна как есть (python-сайдкар/pymorphy, связка с морфопроходом Decl из 73). @@ -66,81 +59,47 @@ grep sanitiz по backend/configs/pipeline-c2.yaml — 0 вхождений (exi **ЖИВОЙ ОСТАТОК — косметика комментария, не поведение:** комментарий схемы БД до сих пор перечисляет `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 достаточно» неверно. -### [RESCOPE] Кандидат 73: ranked-set (инъективность рангов) +### [ЗАКРЫТО D39.69 §1 + D39.71] Кандидат 73: ranked-set (инъективность рангов) -Половина УЖЕ ПОСТРОЕНА: инъективность dst (B2, «два исходных → один целевой») реализована как membank.InjectivityCollisions (membank/memory.go:1101-1126: группировка approved-строк по нормализованному dst, ≥2 разных src = коллизия) и вызывается на загрузке как warning-only диагностика (pipeline/seeding.go:64). НЕ построены две другие части исходного обязательства (04-unhappy-paths.md:19: «тип ranked-set + проверка инъективности … и порядка ступеней»): типа ranked-set нет (type — свободный текст «name|term|title|…», migrate.go:181; grep ranked-set/tier/ступен по backend = 0 кодовых хитов) и проверки ПОРЯДКА ступеней при перечислениях нет. +Инъективность dst построена (`membank.InjectivityCollisions`, warning-only на загрузке); типа ranked-set и проверки ПОРЯДКА ступеней из исходного обязательства (`04-unhappy-paths.md:19`) нет. Улики с file:line — D39.66-пост-сверка (п.2). **Качество закрыто D39.69 §1, hard-режим = Q4 → D39.71 (не строить).** -**Фикс/скоуп:** → **Закрыто D39.69 §1 + D39.71 (Q4 не строить).** - -### [CONFIRMED_LOST] Кандидат 73: STITCH-ретирование инъекции отработанных термов +### [ЗАКРЫТО 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) следит за промахами, но не влияет на подачу. -**Фикс/скоуп:** → **Закрыто D39.69 (реопен-триггеры: бюджет инъекции / измеренный эффект размера).** (Исторически: кандидат занесён правильно; счётная база для «N чанков подряд без промаха» уже есть в retrieval_state/post-check — стройка сводится к политике селекции.) +**Фикс/скоуп:** → **Закрыто D39.69 (реопен-триггеры: бюджет инъекции / измеренный эффект размера).** Счётная база для «N чанков подряд без промаха» уже есть в retrieval_state/post-check — стройка сводится к политике селекции. -### [CONFIRMED_LOST] Кандидат 73: эмбеддинг-второй-эшелон A7/D2 (дать диспозицию) +### [ЗАКРЫТО 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) — живо, не закрыто. **Фикс/скоуп:** → **Закрыто по нужности D39.69 (реопен: измеренный recall-разрыв на масштабе).** -### [CONFIRMED_LOST] Кандидат 73: tmctl «замена термина с главы N» +### [БЕЗ СТРОКИ ТРЕКЕРА] Кандидат 73: tmctl «замена термина с главы N» Команды НЕТ (⚠ список команд здесь НЕ дублируется — снятый снапшот отставал ТРИЖДЫ; единственный носитель — `backend/cmd/tmctl/main.go`, греп `dispatchCommands`, сверяйся с ним, не с этой строкой); RedriveSelector выбирает только ФЛАГНУТЫЕ чанки по chapter/chunk/reason (pipeline/status.go:561-582), не «чанки с термом X». Источник кандидата — research/15-voice-and-state.md:200: одна команда ставит until_ch=N старой записи и since_ch=N новой. При этом СУБСТРАТ построен целиком: оконные строки в схеме (UNIQUE (book_id, src, sense, since_ch, until_ch), migrate.go:202) и $0-пере-пин при bank-only-сдвиге (pipeline/repin.go:14-36, D39.42 п.5/D39.45) — платятся только юниты, где инъекция реально изменилась. -**Фикс/скоуп:** Занесён правильно; в дизайн-паке скоупить как ТОНКУЮ CLI-обёртку над уже построенным (правка двух окон в сиде + штатный repin), не как пайплайн-работу. +⚠ **Строки 73 в трекере больше нет, а этот кандидат D39.69 НЕ закрывал** — держателя, кроме этой ячейки, у него нет (смежные носители: `research/15-voice-and-state.md:200`, `archive/reports/BANK_QUALITY_DESIGN_2026-08-01.md`, греп `замена термина`). Скоуп при стройке — ТОНКАЯ CLI-обёртка над уже построенным (правка двух окон в сиде + штатный `repin`), не пайплайн-работа. ### [ЗАКРЫТО D39.69 §1] Кандидат 86/73: feed_cap терминолога (D39.45) — «бюджет-гейт режет хвост батча» -⚠ **feed_cap ПОСТРОЕН И ЗАКРЫТ ратифицированной D39.69 §1 (испр. 02.09), из строки 86 ИЗЪЯТ:** бюджет режет теперь НАИМЕНЕЕ ЦЕННОЕ, а не лексикографический хвост — value-порядок отреза (частота-desc) живёт в `backend/internal/terminology/terminology.go` (греп `feed_cap`), гвоздь — `TestBatchValueOrder` в `backend/internal/terminology/series_test.go`. **Прежний греп искал не там** (по `backend/` целиком до стройки — 26.07 давал 0, это и было верно НА ТОТ ДЕНЬ). +⚠ **feed_cap ПОСТРОЕН И ЗАКРЫТ ратифицированной D39.69 §1 (испр. 02.09), из строки 86 ИЗЪЯТ:** бюджет режет теперь НАИМЕНЕЕ ЦЕННОЕ, а не лексикографический хвост — value-порядок отреза (частота-desc) живёт в `backend/internal/terminology/terminology.go` (греп `feed_cap`), гвоздь — `TestBatchValueOrder` в `backend/internal/terminology/series_test.go`. -## Срез: строка 25 — дефекты чекеров +## Срез: строка 25 — дефекты чекеров (строка ЗАКРЫТА пакетом-чекеров 02.08, D39.78) -### [ИСПОЛНЕНО D39.78] #3 chevron-речь: детектор опознаёт только форму «Реплика», — сказал +> Шесть дефектов (#3 chevron-речь · #5 数-магнитуды · #6 латиница-детектор · #7 `minLatinResidueLen` · #10 пост-чек банка · #1 K5c-супрессор + Р2-семантика «значение»), их улики, замеры на labels и §6-вопросы владельцу лежат ДОСЛОВНО в [reports/CHECKER_PACKAGE_2026-08-02.md](../archive/reports/CHECKER_PACKAGE_2026-08-02.md) (D39.78); §6-Q1…Q4 РЕШЕНЫ D39.79, довершение — D39.82 (`shichen_re`). Тела нот — слайс `docs/archive/architecture/05-decisions-D39-59-90.md`. Ниже только то, что осталось ЖИВЫМ. -**✅ ИСПОЛНЕНО (пакет-чекеров 02.08):** `chevronSpeechShape` — привязка = `«X», —` (запятая-джойн) ИЛИ `«X!»/«X?»/«X…» —` (sentence-final перед »); плоская цитата `«X» —` ОТВЕРГАЕТСЯ (гвоздь `TestChevronCitationNotFlagged` — «просто опциональная запятая» была первой версией, опровергнутой ревью), глагол-гейт держит точность. K4b recall 0.109→0.217, +5 tp, 0 новых fp. **Р4-потолок ~0.22 записан В КОНТРАКТ правила** (24 безатрибутивные реплики офлайн неотличимы от цитат). +**⚠ Границы, на которые нельзя опираться:** +- **`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». -### [ЗАКРЫТО D39.78] #5 K5a-предохранитель: number_magnitude отсекает 数-префиксные магнитуды (数十万) +**Р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. -`backend/internal/checks/cheapgates.go`, греп `hasDigitBeforeBigMarker` — он требует ЦИФРУ (一-九/两/0-9) до 万; 数 отсутствует в digit-классе lang/data/cjk-section.txt (digit-строки: 一二两兩三四五六七八九) и не является numeral rune вовсе, поэтому ран рвётся на «十万» и гасится. Собственный доккомментарий (греп `bare-unit magnitudes`) признаёт: «It also drops bare-unit magnitudes (十万/百万) — an accepted recall trade». Нюанс: узкий DC2-проб покрывает РОВНО 数十万→«десятки тысяч» (configs/langpacks/zh-ru/dc-checkers.txt:61-63), но 数万/数百万/数千万 и другие рендеры 数十万 слепы для обоих механизмов. +**НЕ построено, диспозиции даны:** 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` («повтор в параллельных позициях оригинала = „не трогать“ … иначе редактор-агент убивает рефрены») и :130 п.5. -**⊘ ЗАКРЫТО (не чинить, пакет-чекеров 02.08):** единственный реальный дефект магнитуды на всём корпусе (`数十万人→«десятки тысяч»`, rerun2-mistral:2:0) УЖЕ пойман DC2 (K5b, recall 1.0). Расширение 数-коэффициента ловит **0 новых единиц** на labels ⇒ нужность = 0. На иных корпусах может понадобиться — текущая эмпирика не оправдывает. - -### [ИСПОЛНЕНО D39.78] #6 латиница-детектор пропускает токены с заглавной буквой (Cultivation, TM-BANK) - -**✅ ИСПОЛНЕНО (пакет-чекеров 02.08):** `lintLatinResidue` — снят reject-по-заглавной; caps/Title латиница флагуется (ловит `BANK`-фрагмент маркера + `Cultivation`), легит-бренды → per-project allowlist (case-insensitive). K2 recall 0.75→0.85, +4 tp; **измеренная precision 0.971** (1 fp «Qidian»=бренд; 1.0 лишь ЕСЛИ бренд занесён в `style_allowlist` — боевой конфиг сейчас не заносит, находка ревью-агента). Гвоздь `checkers_pack13_test.go`. - -### [ЗАКРЫТО D39.78] #7 порог minLatinResidueLen=3 (судьбу решить по labels + Р4) - -`backend/internal/checks/checkers.go`, греп `const minLatinResidueLen = 3` — порог захардкожен константой, токены ≤2 букв («ok», «ai») не флагуются никогда; Р4-потолок теперь ЗАПИСАН ИНЛАЙН в доккомментарии константы (греп `recall CEILING`), второй сайт порога — `repair.go`. - -**⊘ ЗАКРЫТО (пакет-чекеров 02.08):** замер THRESHOLD=2 = **0 изменений** (recall 0.75→0.75). Гомоглиф «гy» — это MIXED-скрипт токен (1 латинская руна), не длина-порог; ловится существующим `tk.mixed` (`detectBrokenWords`, приёмка пройдена — гвоздь `TestHomoglyphDetectorAcceptance`). **3 зафиксирован как Р4-потолок** в контракте правила. - -### [ИСПОЛНЕНО D39.78] #10 пост-чек банка: «src сработал» = подстрочное вхождение, однознаковый 转 даёт ложные - -**✅ ИСПОЛНЕНО пакетом-чекеров 02.08** ([reports/CHECKER_PACKAGE_2026-08-02.md](../archive/reports/CHECKER_PACKAGE_2026-08-02.md); D39.78): `mempostcheck.go` `singleHanKeyFired(p.Via)` — одно-руновый Han-ключ роутит dst-absent-миссы в Unverified observability, не Confirmed (мульти-руновые Han НЕ демотируются). Замер labels: K6 fp 14→6, precision 0.067→0.143, **fn=0 сохранён** (все 6 демотированных = 转 внутри глаголов; ни одного реального промаха не потеряно; ⚠ fn=0 КЛАСС-ВАКУУМЕН — в labels ноль одно-Han-позитивов, recall-цена демоции не измерена, hard-gate строки 12 на него не опираться — D39.78). Демотированный мисс несёт `PostcheckMiss.Demoted` в detail (постфикс §8). Гвозди `mempostcheck_test.go` (вкл. негатив: одно-руновый НЕ-Han остаётся Confirmed). Стеммер-путь `declinedFormPresent` (банк-пак §3) НЕ тронут. Остаточные 6 K6-fp (元石/蛊虫 плюральные формы) = сид-полнота, не код. - -### [ЧАСТИЧНО D39.78] #1 K5c-супрессор гасит по всему юниту + Р2-семантика «значение» не имплементирована - -Обе половины подтверждены. (а) `backend/internal/checks/checkers.go`, греп `ok-suppressor` — «A CORRECT rendering anywhere in the chunk (the ok-suppressor) suppresses the flag»; код там же: `!c.qianwanOKRE.MatchString(final)` и `strings.Contains(final, ...)` — весь чанк, не пер-вхождение; одно верное 千万 маскирует второе неверное. DC1 аналогично берёт только ПЕРВЫЙ матч (греп `c.shichenRE.FindStringSubmatch`). (б) Р2 (D39.63(1): «жёсткий флаг ТОЛЬКО за неверное ЗНАЧЕНИЕ; неконвертированная форма = мягкий счётчик») не имплементирован: lintPercentScale (греп `func (c *Checkers) lintPercentScale`) файрит по ФОРМЕ (нет процентного слова + есть дробный кью), pct вычисляется только для сообщения, сравнения значений нет; доккомментарий cheapgates.go (греп `a design, not a patch`) прямо признаёт: «A correct fix compares the rendered VALUE… a design, not a patch. Left firing». - -**✅ Р2-split ИСПОЛНЕН (пакет-чекеров 02.08):** `CheapGateResult.UnitScaleHard()`={DC1 ruNum≠2n · NumberMagnitude — слово-магнитуда неверного ПОРЯДКА, ошибка значения (→HARD по находке ревью-агента)} / `UnitScaleSoft()`={DC2 гипербола-неоднозначна, PercentScale верное значение в форме-дроби}; `Total()` не тронут (голден-нейтрально). **Пер-вхожденческий супрессор — ⊘ НЕ строил:** под Р2 PercentScale стал SOFT-наблюдаемостью, локальность-window эвристична и низкоценна → Р4-потолок. HARD-value-чек 成/万 требует ru-numeral-word-данных (потолок записан в v5-блоке шапки cheapgates.go §5-A4 + отчёте; inline-записи на самих функциях НЕТ — хвост в строке 93) — → **§6-Q3 РЕШЁН D39.79 п.4: не строить; реопен = флип hard-gate (строка 12) либо поток value-дефектов с добора идеала.** - -### [ИСПОЛНЕНО D39.78] #8 两 отсутствует в классе cheng_re - -**Фикс/скоуп:** → **Подтверждено D39.79 п.3, довершено D39.82 (shichen_re).** — **✅ ИСПОЛНЕНО как ДАННЫЕ (пакет-чекеров 02.08):** 两/兩 в оба класса cheng_re + 兩=2 в cjk_numeral (парс-полнота) — `configs/langpacks/zh-ru/dc-checkers.txt`, греп `cheng_re`. **Нужность на labels = 0** — 两成 в acceptance:10:0/minirun:10:0 замаскировано супрессором #1 (там есть «процент»); правомерно как generality/consistency-фикс. 兩-traditional — §6-Q2 владельцу (0 стоимости, подтвердить или откатить). ⚠ Норма D39.63(3): данные-правки на этой фазе дешёвы (стендовый корпус одноразовый), но resnapshot по той же дисциплине. - -### [ЧАСТИЧНО D39.78] Резидуал R4 пака-11: DC7 grade/role-чекер · omission-бэкстоп · DC2 word↔word дроби - -Определение резидуала: PACK11_CONT_REPORT_2026-07-19.md:195-197 (DC7 grade/role; omission-бэкстоп = «лёгкий Go-ru-стеммер + лемма-матч по {dst,decl.forms,aliases}»; DC2 word↔word дроби q4a rule_b1/b2). ЖИВО отсутствуют два из трёх (omission-бэкстоп с тех пор построен — см. диспозицию ниже): grep DC7 по backend/internal — 0 совпадений при 10 совпадениях DC1/DC2 в том же файле (GradePrefix живёт только в майнере и langpack, не в чекере); DC2 в коде = только два проба qianwan/shushiwan (checkers.go:417-438), word↔word-сравнения числительных нет. DC3-гендер из того же R4 корректно вынесен в строку 82 — скоуп строки 25 точен. - -**Диспозиция (пакет-чекеров 02.08):** (1) **omission-бэкстоп — ✅ УЖЕ построен** стеммером `declinedFormPresent` (лемма-матч {dst,decl.forms}); замер: сам починил 2 K6-fp (凡人/甲等); target-алиасы не заведены (сид-концерн). (2) **DC7 — на владельца (§6-Q1):** approved grade-строки ЕСТЬ (класс А/Б/В/Г), но КОЛЛИЗИЯ с draft «разряд X» — нужна канон-подпись ПРЕЖДЕ стройки (PACK11_CONT:195). (3) **DC2 word↔word — ⊘ ЗАКРЫТО:** 分之-дроби в корпусе есть (8 юнитов), но НИ ОДНОГО размеченного дефекта класса → precision/recall неизмеримы, строить вслепую против мандата; сперва разметить 分之-срез. - -### [ЧАСТИЧНО D39.78] Alignment-защита рефренов: editor.md велит убирать повторы без исключения «повтор есть в оригинале» - -Требование защиты живо: 04-unhappy-paths.md:97 «alignment-защита: повтор в параллельных позициях оригинала = „не трогать“ … иначе редактор-агент убивает рефрены» и :130 п.5. Промпт-половина закрыта (см. ниже); никакого детектора повторов лемм/alignment-механизма в checks/ нет. - -**✅ Минимум ИСПОЛНЕН (пакет-чекеров 02.08):** editor.md + editor-mono.md несут исключение авторского рефрена (двигает боевой PromptSHA256, перекупок нет D39.63; голден на синтет-промтах не двинулся). Полный детектор повторов лемм — НЕ строил (нет размеченного класса; связка с alignment/Bertalign, строка 85). +**Построено, возврата не требует:** omission-бэкстоп = стеммер `declinedFormPresent` (лемма-матч {dst,decl.forms}; сам починил 2 K6-fp 凡人/甲等) — ⚠ target-алиасы к нему НЕ заведены, это сид-концерн, не код. ## Срез: строка 86 + дописки 79/41/24/74/49 @@ -148,43 +107,38 @@ grep sanitiz по backend/configs/pipeline-c2.yaml — 0 вхождений (exi Код реально реализует 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). -**Фикс/скоуп:** Не требуется — строка 86 точна: решение реально отложено и живо, код в заявленном состоянии. ### [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 повторно числит открытым. -**Фикс/скоуп:** Не требуется — строка 86 точна. ### [ПОСТРОЕНО D39.78] (3) lintNumberMagnitude — гейт по письму источника (дописка 79) СТОИТ -⚠ **ГЕЙТ ПО ПИСЬМУ ИСТОЧНИКА ПОСТРОЕН (испр. 02.09):** он внутри `lintNumberMagnitude` — `backend/internal/checks/cheapgates.go`, греп `SOURCE-script gate`; комментарий называет заказ по имени («строка 79, D39.39»), шов — единый `lang.IsDenseScript` (D39.78). **Прежний греп объявлял ноль, потому что искал в `backend/internal/pipeline/`, где файла нет.** ЖИВОЙ ОСТАТОК строки 79 — граница `cjkScriptNames`: она НЕ тронута. +⚠ **ГЕЙТ ПО ПИСЬМУ ИСТОЧНИКА ПОСТРОЕН (испр. 02.09):** он внутри `lintNumberMagnitude` — `backend/internal/checks/cheapgates.go`, греп `SOURCE-script gate`; комментарий называет заказ по имени («строка 79, D39.39»), шов — единый `lang.IsDenseScript` (D39.78). ЖИВОЙ ОСТАТОК строки 79 — граница `cjkScriptNames`: она НЕ тронута. -**Фикс/скоуп:** Не требуется — дописка 79 точна («гейтить по объявленному письму источника», кандидат при ближайшем касании чекеров). ### [CONFIRMED_LOST] (4) Golden-счётчики голоса (дописка 41): в capture.golden voice-счётчиков нет Подтверждено отсутствие: `grep -c -i voice backend/internal/pipeline/testdata/golden/capture.golden` = 0 (ни одного вхождения); в testdata/golden/pipeline.yaml ключа `voice:` нет (grep пуст) — гейт opt-in OFF по умолчанию (backend/internal/config/pipeline.go:279-281), фикстура его не включает, значит golden не пинит ни n_voice_flags/voice_detail, ни VoiceFlags/SpoilerLeaks (quality.go:269-278, 436 — счётчики существуют в коде, но в golden-контур не заведены). Хвост D39.58 реален и жив. -**Фикс/скоуп:** Не требуется — дописка 41 точна. ### [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: «слот инъекции НЕ выбран, оба провода, решит полигон-эксперимент». +Оба провода подтверждены. Провод 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` и инъекции — на следующем живом прогоне. -**Фикс/скоуп:** Не требуется — дописка 24 точна (решение по gates.voice и инъекции — на следующем живом прогоне). -### [CONFIRMED_LOST] (6) Остаток §12.7 (дописка 74): 8 несудимых fidelity-пар P4 существуют в ~/books/gu-zhenren/research15-probes/ +### [ЗАКРЫТО 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/ присутствуют. **Фикс/скоуп:** → **Строка 74 закрыта D39.95, P4-хвост принят D39.61; добор ≈$0.10 — резидуал §12.7 D39.61 (цены записаны там), отдельного носителя не заводилось.** -### [RESCOPE] (7) Протокол гендер-твиста D5.1 (дописка 49): «redrive есть, селективного by-until_ch пути нет» +### [RESCOPE ИСПОЛНЕН] (7) Протокол гендер-твиста D5.1 (дописка 49): «redrive есть, селективного by-until_ch пути нет» Посылка «селективного пути нет» ОПРОВЕРГНУТА: селективная пере-редактура по изменению банка + смета ПОСТРОЕНЫ и живьём проверены. `backend/internal/pipeline/repin.go:14-35`=`POINTWISE re-edit by key` — «POINTWISE re-edit by key (pack-20 point 5, D39.42 п.5)»: bank-only сдвиг снапшота + неизменный content_hash → пере-пин юнита за $0, изменённые инъекции — платно; «The same predicate drives the ESTIMATE: projectRebill uses it» (смета «N units, ~$X»); встроено в штатный резюм — stagerun.go:87 (repinnable); согласие на пере-оплату — rebill.go:11-40 (D20.2-Q2). until_ch-апдейт = правка строки банка → двигается ТОЛЬКО memory_version → ровно этот путь (D39.42 п.5: «поздняя подпись и ЛЮБАЯ правка»; D39.45: «точечная ре-редактура по ключу с $0-пере-пином — построено, живьём проверено... 20 юнитов пере-пинены за $0 при bank-only-сдвиге»). При этом верно: tmctl redrive существует (`cmd/tmctl/main.go:233`=`case "redrive":`), но его селектор — только chapter/chunk/reason по ФЛАГНУТЫМ чанкам (status.go:564-582), until_ch-пути в НЁМ нет — селективность живёт в другом инструменте (translate-резюм + repin + rebill), и это by-design правильный носитель. -**Фикс/скоуп:** Пере-формулировать дописку в строке 49: тех-механизм «until_ch-апдейт → селективная пере-оплата затронутых юнитов + смета» УЖЕ построен (repin.go/rebill.go, D39.42 п.5, D39.45) — слова «селективный redrive» убрать (redrive — инструмент флагнутых чанков, не носитель). Остаток дописки — только операторский ПРОТОКОЛ-документ релиза D5.1 (последовательность: выставить until_ch у gender=hidden-терма → tmctl translate → согласие на rebill-смету; + курация 白凝冰 из строки 24), либо закрыть дописку явной ссылкой на D39.45. +**Живой остаток дописки** (пере-формулировка исполнена — строка 49 бэклога и D39.66-пост-сверка п.3): только операторский ПРОТОКОЛ-документ релиза D5.1 — последовательность «выставить `until_ch` у `gender=hidden`-терма → `tmctl translate` → согласие на rebill-смету», плюс курация 白凝冰 из строки 24. ## Архео-хвосты жирных строк бэклога (выселение докс-паком строки 167, 09.08.2026) @@ -212,7 +166,7 @@ grep sanitiz по backend/configs/pipeline-c2.yaml — 0 вхождений (exi ### Б-108 — тело строки 108 на 09.08.2026 -**Реестр ЗАГЕЙЧЕННЫХ ТРИГГЕРОВ + норма закрытия «по нужности».** ⚠ Первый жилец реестра, найденный тем же лендингом: **сиблинг-угроза экрана целевого языка** — выход на языке, БЛИЗКОМ к целевому (украинский/болгарский для ru): ни одного события не наблюдалось, но если появится, дискриминатор — плотность РУССКО-ЭКСКЛЮЗИВНЫХ букв (ы/э/ё) НИЖЕ ожидания, а НЕ замыкание алфавита (`EFFORT_HANDLE §5.4` шаг 8). Шесть остальных реопенов живут только в телах D-нот и не имеют места, где их поднимут: **МАСШТАБ** (uniformity-пасс D12 · эмбеддинг A7/D2 «реопен = измеренный recall-разрыв, только batch-time лейн» · STITCH «бюджет ИЛИ измеренный эффект размера инъекции» · канон-пин серий) · **вторая пара живьём** (C-триггер softsign-decl · автономная Decl-эмиссия) · **вторая книга того же жанра** (жанровый shared-слой) · **первая traditional-книга** (probe-литералы 时辰/千万/数十万 цельным дата-батчем) · **появление Go-кода платформы** (`go.work` — ⚠ `platform/go.mod` УЖЕ заведён, триггер наступил) · **перед стройкой fix-8** (ёлочный экстрактор атрибуции + корпус-замер). **+Два жильца приёмки D39.91:** Д5 — enum эффорта провайдер-слеп (`medium` на DeepSeek не определён, `max`/`xhigh` недостижимы; пер-модельную таблицу решено НЕ строить — механизм без носителя качества/денег, misconfig ограничен бюджетами и назван в доккомменте `ValidReasoningEffort`; триггер: первый живой инцидент кривого поведения уровня на проводе) · Д9 — аддитивные провайдеры отказываются бэнк/repair-гейтам, блок не несёт `reasoning_max_tokens` (fail-closed в лоадере; триггер: первая потребность гейта в аддитивной модели). **+Вахта D39.92 — СРАБОТАЛА:** changelog вендора 13.08 — у V4-Pro и V4-Flash теперь уровни low/high/max (квирк 3а «low→high, эффорт не настраивается» УСТАРЕЛ, `max` стал достижим — двигает и Д5-жильца выше); тем же днём пик/офф-пик цены с 16.08 16:00 UTC (строка 172); changelog 31.07 официально подтверждает re-post-train флэша под слагом (провенанс D39.61); пере-проба поведением + абсорбция — полигоном по слову владельца (снято оркестратором 14.08).** Норма реестра (D39.66, D39.125 п.3): сверять на КАЖДОМ переходе горизонта (расписан до Ф3, точки известны заранее) · **(D39.96)** тулчейн go1.27 переключит x/text на таблицы Unicode 17.0.0 МОЛЧА (`xTextVersion` пинит go.mod-строку, не таблицы) — триггер: любое движение тулчейна к 1.27 ⇒ строка 119 ПЕРВОЙ · **(D39.96)** CI-воркфлоу Forgejo (удалёнка 10.0.3, раннер не подтверждён; решение владельца 03.08 — не писать) — триггер: появление раннера ⇒ файл workflow; до того точка входа `make battery`. **+Два жильца аудита бэклога D39.140 (16.08):** граница пробы провода строки-однодневки 117 — CONNECT-туннель, CONTINUATION-фреймы и поведение под нагрузкой НЕ проверены, SETTINGS-фингерпринт не абсорбирован в `00-provider-quirks.md` (`archive/reports/ARCHGUARD_DOFIX_2026-08-03.md:173`; триггер: смена транспорта/HTTP-стека ИЛИ провайдер-аномалия класса «зависший стрим») · компонент «перспектива» нарративной гендер-аннотации пака-19 (строка 15 ушла лендингом D39.56 без этого компонента; смежный морфо-гейт рода — строка 82 — ДРУГОЙ предмет; триггер: подписание осей голоса при доборе идеала, строки 24/13б) · эскалационный кап НЕ прицениваает хоп — перелёт ≤1 хопа `escalate_to`-модели, оставлен и запинен D39.131 п.2(д) (триггер реопена: первый живой инцидент перелёта) +**Реестр ЗАГЕЙЧЕННЫХ ТРИГГЕРОВ + норма закрытия «по нужности».** ⚠ Первый жилец реестра, найденный тем же лендингом: **сиблинг-угроза экрана целевого языка** — выход на языке, БЛИЗКОМ к целевому (украинский/болгарский для ru): ни одного события не наблюдалось, но если появится, дискриминатор — плотность РУССКО-ЭКСКЛЮЗИВНЫХ букв (ы/э/ё) НИЖЕ ожидания, а НЕ замыкание алфавита (`EFFORT_HANDLE §5.4` шаг 8). Шесть остальных реопенов живут только в телах D-нот и не имеют места, где их поднимут: **МАСШТАБ** (uniformity-пасс D12 · эмбеддинг A7/D2 «реопен = измеренный recall-разрыв, только batch-time лейн» · STITCH «бюджет ИЛИ измеренный эффект размера инъекции» · канон-пин серий) · **вторая пара живьём** (C-триггер softsign-decl · автономная Decl-эмиссия) · **вторая книга того же жанра** (жанровый shared-слой) · **первая traditional-книга** (probe-литералы 时辰/千万/数十万 цельным дата-батчем) · **появление Go-кода платформы** (`go.work` — ⚠ `platform/go.mod` УЖЕ заведён, триггер наступил) · **перед стройкой fix-8** (ёлочный экстрактор атрибуции + корпус-замер). **+Два жильца приёмки D39.91:** Д5 — enum эффорта провайдер-слеп (`medium` на DeepSeek не определён, `max`/`xhigh` недостижимы; пер-модельную таблицу решено НЕ строить — механизм без носителя качества/денег, misconfig ограничен бюджетами и назван в доккомменте `ValidReasoningEffort`; триггер: первый живой инцидент кривого поведения уровня на проводе) · Д9 — аддитивные провайдеры отказываются бэнк/repair-гейтам, блок не несёт `reasoning_max_tokens` (fail-closed в лоадере; триггер: первая потребность гейта в аддитивной модели). **+Вахта D39.92 — СРАБОТАЛА:** changelog вендора 13.08 — у V4-Pro и V4-Flash теперь уровни low/high/max (квирк 3а «low→high, эффорт не настраивается» УСТАРЕЛ, `max` стал достижим — двигает и Д5-жильца выше); тем же днём пик/офф-пик цены с 16.08 16:00 UTC (строка 172); changelog 31.07 официально подтверждает re-post-train флэша под слагом (провенанс D39.61); пере-проба поведением + абсорбция — полигоном по слову владельца (снято оркестратором 14.08).** Почему реестр вообще существует (замер лендинга 09.08): норма D39.66 «каждое отложено обязано ТЕМ ЖЕ лендингом получить строку или явное закрытие» **нарушена ≥6 раз ПОСЛЕ собственной ратификации**, и класс потерь узкий — теряются именно ЗАГЕЙЧЕННЫЕ РЕОПЕНЫ. Норма реестра (D39.66, D39.125 п.3): сверять на КАЖДОМ переходе горизонта (расписан до Ф3, точки известны заранее) · **(D39.96)** тулчейн go1.27 переключит x/text на таблицы Unicode 17.0.0 МОЛЧА (`xTextVersion` пинит go.mod-строку, не таблицы) — триггер: любое движение тулчейна к 1.27 ⇒ строка 119 ПЕРВОЙ · **(D39.96)** CI-воркфлоу Forgejo (удалёнка 10.0.3, раннер не подтверждён; решение владельца 03.08 — не писать) — триггер: появление раннера ⇒ файл workflow; до того точка входа `make battery`. **+Два жильца аудита бэклога D39.140 (16.08):** граница пробы провода строки-однодневки 117 — CONNECT-туннель, CONTINUATION-фреймы и поведение под нагрузкой НЕ проверены, SETTINGS-фингерпринт не абсорбирован в `00-provider-quirks.md` (`archive/reports/ARCHGUARD_DOFIX_2026-08-03.md:173`; триггер: смена транспорта/HTTP-стека ИЛИ провайдер-аномалия класса «зависший стрим») · компонент «перспектива» нарративной гендер-аннотации пака-19 (строка 15 ушла лендингом D39.56 без этого компонента; смежный морфо-гейт рода — строка 82 — ДРУГОЙ предмет; триггер: подписание осей голоса при доборе идеала, строки 24/13б) · эскалационный кап НЕ прицениваает хоп — перелёт ≤1 хопа `escalate_to`-модели, оставлен и запинен D39.131 п.2(д) (триггер реопена: первый живой инцидент перелёта) ### Б-109 — тело строки 109 на 09.08.2026 diff --git a/docs/architecture/14-api-contract/README.md b/docs/architecture/14-api-contract/README.md index 51a823c9..18abf8bc 100644 --- a/docs/architecture/14-api-contract/README.md +++ b/docs/architecture/14-api-contract/README.md @@ -13,12 +13,9 @@ 20.08.2026: СИНК С ПЛАТФОРМОЙ (запрос platform/docs/archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md, 14 пунктов) — канон 0.3.0 → 0.4.0, разбор и диспозиция КАЖДОГО пункта в §6в, отдельным пунктом §6в п.0 — сверка 0.2.3 → 0.3.0 на молча срезанные при резке прозы правила (найдена одна, восстановлена). -Ратификацию этой редакции контрактная сессия за собой НЕ записывает — это акт оркестратора: -автор и ратификатор одного и того же текста совпадать не должны. Файлы уже несли 0.4.0 к моменту сдачи; в силу -редакция вступила лендингом 20.08 — РАТИФИЦИРОВАНА D39.152 (там же: четыре текстовые правки, -внесённые оркестратором при ратификации, и разбор того, что против 0.3.0 расходится ПЯТЬ мест, -а не одно). Строку в 05-decisions-log сессия тоже не писала по той же причине — готовый текст ноты -был сдан оркестратору вместе с этой редакцией. +В силу редакция вступила лендингом 20.08 — РАТИФИЦИРОВАНА D39.152 (там же: author≠ratifier +исполнен самой сессией, четыре текстовые правки оркестратора при ратификации и разбор того, что +против 0.3.0 расходится ПЯТЬ мест, а не одно). Ломающий батч 0.3.0 исполнен по целостному ревью `docs/research/28-contract-review.md` (ревью принято D39.138, приёмка батча — D39.142, дофикс ФБ-1..10 — D39.143; отчёт исполнения — @@ -318,8 +315,7 @@ drop юнит несёт причину ПЕРВОГО выпавшего чле → `given` (пришло с книгой), `ruby` → `annotated` (сам текст книги сказал, как читать), `mined` → `found` (сервис нашёл в тексте). Проекция трёх пар — работа платформы. -**Правило пустого `kind` — и его проекция** (было в 0.2.3, при резке прозы уцелело в каноне и -пропало здесь; возвращено синком 20.08). `kind` присутствует всегда и допускает `null`; `null` +**Правило пустого `kind` — и его проекция** (провенанс возврата — §6в п.0). `kind` присутствует всегда и допускает `null`; `null` значит «сервис не решил», строка при этом остаётся подписываемой, и клиенту запрещено и выбрасывать её, и додумывать тип за движок (канон, схема `BankTerm.kind`). У движка та же строка несёт `Type: ""` (`membank/memseed.go:323-326`), поэтому **проекция `""` → `null` — работа платформы**; это @@ -395,21 +391,18 @@ every proposed term is promoted or rejected» ОПРОКИНУТА D39.144 — **Кадры соединения не тратят номеров истории.** `id` кадра объявлен позицией в истории событий КНИГИ, строго возрастающей, — но `hello` приходит первым на КАЖДОМ подключении, а `end` и -`resync_required` тоже принадлежат соединению, не книге. Первая редакция батча этого не развела, и у -реализатора оставалось два пути, оба против текста: минтить служебным кадрам книжные номера (тогда два -одновременных зрителя тратят номера друг друга, и `Last-Event-ID` одного указывает на кадры, которых -второй не видел) либо повторять последний номер (тогда «one per frame» ложь). Поймано кросс-модельной -линзой; исправлено: служебные кадры несут id последнего кадра ИСТОРИИ и своего номера не тратят, -повтор id на них легален, а дыра в нумерации легальна из-за склейки — и клиенту прямо запрещено читать -пропуск как потерянный кадр. Последнее правило было в 0.2.3, потерялось при резке прозы и возвращено. +`resync_required` тоже принадлежат соединению, не книге. Разведено 0.3.0: служебные кадры несут id +последнего кадра ИСТОРИИ и своего номера не тратят, повтор id на них легален, а дыра в нумерации +легальна из-за склейки — и клиенту прямо запрещено читать пропуск как потерянный кадр. Обе +альтернативы отвергнуты собственным текстом канона: книжные номера служебным кадрам заставили бы двух +одновременных зрителей тратить номера друг друга, а повтор последнего номера сделал бы «one per frame» +ложью. -**Дельта-чтения ВКЛЮЧИТЕЛЬНЫ (`>=`), а не строго больше.** Первая редакция батча сделала -`?after_version=` строгим — и тем сломала собственное правило `Revision` («catch-up reads `>= R`, not -`> R`»): одна транзакция это одна ревизия, но НЕСКОЛЬКО строк, и строгое сравнение теряет соседей -последней применённой. Хуже: кадр `bank` предписывал читать строки «ревизией этого кадра», что при -строгом сравнении всегда возвращало пустоту. Поймано холодным потребителем, исправлено: чтение -включительно, повторно пришедшая строка безвредна (строка заменяется по `id`), а водяной знак -следующего чтения берётся из КОНВЕРТА, а не выводится из строк. +**Дельта-чтения ВКЛЮЧИТЕЛЬНЫ (`>=`), а не строго больше.** Строгое сравнение ломает собственное +правило `Revision` («catch-up reads `>= R`, not `> R`»): одна транзакция — это одна ревизия, но +НЕСКОЛЬКО строк, и `>` теряет соседей последней применённой; а кадр `bank` предписывает читать строки +«ревизией этого кадра», что при `>` всегда пустота. Повторно пришедшая строка безвредна (заменяется +по `id`), а водяной знак следующего чтения берётся из КОНВЕРТА, а не выводится из строк. ⚠ **Дофикс 16.08 (ФБ-4): у многостраничного обхода конверт не один.** Формулировка «водяной знак — `revision` конверта» была однозначна ровно до тех пор, пока чтение умещалось в одну страницу; на @@ -900,8 +893,7 @@ the original request was never applied». Каждый `POST /books` созда ⚠ **Норма, которую приёмка этого минора вывела и которая держится на следующий:** непрозрачность ПОЛЯ не спасает, если проза рядом прозрачна — граница судит и описания, потому что они -компилируются в исходник клиента (D39.180 п.б; первая редакция минора называла фазу конвейера -открытым текстом дважды и была переформулирована формо-нейтрально тем же лендингом). +компилируются в исходник клиента (D39.180 п.б). **Механика — в зоне платформы:** пара колонок `books.shape_epoch` + `books.epoch_editor` (миграция `00030_shape_epoch.sql`, бэкфилл `epoch_editor = edit_wave`, поэтому первая граница — только реальная @@ -923,13 +915,13 @@ the original request was never applied». Каждый `POST /books` созда | `GET /books`, `GET /books/{id}` | read-модель платформы | ПОСТРОЕНО | — | | `GET /books/{id}/run-options`, `POST /runs` | шкала + холды | ПОСТРОЕНО | — | | `POST /runs/{id}/stop` | реконсилятор | ПОСТРОЕНО (кнопки на экране нет) | зона фронта | -| `POST /runs/{id}/resume` | реконсилятор | ПОСТРОЕНО, но **0.3.0 сменил поведение на паузе по потолку, а 0.4.0 — на ИСЧЕРПАННОМ прогоне**. Пауза: платформа уже отвечает `409` `ceiling_reached` (`runs/reconcile.go`, ветка `case "paused"` в `Resume`) — совпало. Исчерпанность: ⚠ **РАСХОЖДЕНИЕ ЗАКРЫТО (испр. 02.09)** — `Resume` больше не отвечает `202` на исчерпанный прогон. Реконсилятор различает ДВА вердикта, и оба доезжают до клиента кодом 409 `run_not_resumable`: `ceilingSpent` → `cause.code: ceiling_reached` и `creditUnavailable` → `cause.code: credit_unavailable` (`platform/internal/runs/reconcile.go`, греп `ceilingSpent`; `platform/internal/httpapi/v0.go`, греп `run_not_resumable`). Молчаливый `202` на действие, которое ничего не сделало, — ровно то, от чего предупреждает собственный комментарий платформы; клиенту нечем отличить успех от no-op, а на `awaiting_bank` это ещё и не вызывает `ReleaseBankStop`. Полная таблица по статусам — в описании `resumeRun` | **вход P7** ⚠ ИЗРАСХОДОВАН (D39.153) (правка построенного пути, не только читающей поверхности) | +| `POST /runs/{id}/resume` | реконсилятор | ПОСТРОЕНО, но **0.3.0 сменил поведение на паузе по потолку, а 0.4.0 — на ИСЧЕРПАННОМ прогоне**. Пауза: платформа уже отвечает `409` `ceiling_reached` (`runs/reconcile.go`, ветка `case "paused"` в `Resume`) — совпало. Исчерпанность: ⚠ **РАСХОЖДЕНИЕ ЗАКРЫТО (испр. 02.09)** — `Resume` больше не отвечает `202` на исчерпанный прогон. Реконсилятор различает ДВА вердикта, и оба доезжают до клиента кодом 409 `run_not_resumable`: `ceilingSpent` → `cause.code: ceiling_reached` и `creditUnavailable` → `cause.code: credit_unavailable` (`platform/internal/runs/reconcile.go`, греп `ceilingSpent`; `platform/internal/httpapi/v0.go`, греп `run_not_resumable`). Почему молчаливый `202` был дефектом — §6в A. Полная таблица по статусам — в описании `resumeRun` | **вход P7** ⚠ ИЗРАСХОДОВАН (D39.153) (правка построенного пути, не только читающей поверхности) | | `GET /usage` | кредиты | ПОСТРОЕНО, **не читается ни одним экраном** | зона фронта | | `GET /capabilities` | конфигурация деплоя | **ПОСТРОЕНО P7** — маршрут смонтирован безусловно (`platform/internal/httpapi/v0.go`, таблица `contractSurface`), хендлер `capabilities.go`; версия контракта запинена ГЕЙТОМ против ЭТОГО канона (`platform/internal/gates/contract_test.go`) | закрыто D39.153 | | `PATCH`/`DELETE /books/{id}`, `GET /runs/{id}` | колонки есть | НЕ ПОСТРОЕНО (заведено 0.3.0) — факт верен: роутер монтирует 15 операций из 20 | ⚠ носитель «вход P7» ИЗРАСХОДОВАН (пак P7 принят D39.153); живой носитель — `platform/BACKLOG.md` П-17 и очередь CURRENT-STATE | | `GET /books/{id}/chapters`, `/units` | материализация манифеста | **ПОСТРОЕНО P7** — `httpapi/reading.go`, материализатор `internal/readmodel` | закрыто D39.153 | | `GET /books/{id}/notes` | `unit_done` несёт флаг и причину (`runevents.go:126-135`), платформа хранит (`sink.go:227-233`), колонка `notes.reason` заведена под это | канал ЕСТЬ; не хватает карты «причина → код → фраза» (приложение А) и проекции | приложение А + ⚠ носитель «вход P7» ИЗРАСХОДОВАН (D39.153) | -| `GET /books/{id}/bank` | движок пишет сайдкар всего банка (`pipeline/bankexport.go:16-33,72`, D39.122) | ⚠ пере-снято 0.5.0: проекция платформы ПОСТРОЕНА (P7 — маршрут в `contractSurface`, `wireBankPage` в `httpapi/reading.go`, `SaveBank` в `pgstore`; прежняя запись «не хватает проекции» устарела при израсходованном носителе «вход P7 ⚠ ИЗРАСХОДОВАН (D39.153)», D39.153); форма синхронна канону с лендингом P9: счётчики `pending_decisions`/`complete` сняты с проекции (`PD-399`) | закрыто D39.162 | +| `GET /books/{id}/bank` | движок пишет сайдкар всего банка (`pipeline/bankexport.go:16-33,72`, D39.122) | ⚠ пере-снято 0.5.0: проекция платформы ПОСТРОЕНА (P7 — маршрут в `contractSurface`, `wireBankPage` в `httpapi/reading.go`, `SaveBank` в `pgstore`); форма синхронна канону с лендингом P9: счётчики `pending_decisions`/`complete` сняты с проекции (`PD-399`) | закрыто D39.162 | | ~~`POST /bank/decisions`~~ | стоп-механика майнера | ⚠ **НЕ «не построено», а ОТМЕНЕНО**: было построено P7 и СНЯТО 22.08 вместе с пер-термной моделью подписи (D39.144, слово владельца). **0.5.0 снёс и канон-половину — `PD-370` закрыт этим минором**; преемник — строка `POST …/bank/corrections` ниже | отменено D39.144; снесено 0.5.0 | | `POST /books/{bookId}/bank/corrections` | `tmctl bank-apply` — движковая половина ПОСТРОЕНА (D39.158, лендинг `d1eb8a9`) | **ПОСТРОЕНО пакетом P9**: перевод словаря (`platform/internal/ingest/bankdecisions.go`), спавн глагола (`runner/bankapply.go`), раскладка отказов и пер-книжная сериализация (`runs/bank.go`), дверь синхронная. Флаг `bank_corrections_enabled` следует включённости прогонов (`cmd/tmplatformd/runner.go:195`) — дверь спавнит тот же глагол | закрыто D39.162 | | `GET /books/{id}/events` (SSE) | эмиттер шва построен (D39.131) | **ПОСТРОЕНО P7** — `httpapi/stream.go`, поток регистрируется ВНЕ слоя сжатия (сжатие буферизует поток — единственное, что канон запрещает этому маршруту) | закрыто D39.153 | @@ -938,22 +930,16 @@ the original request was never applied». Каждый `POST /books` созда | `Idempotency-Key` | — | **ПОСТРОЕНО P7** — `httpapi/idempotency.go` + `pgstore/idempotency.go`, на двух создающих вызовах; ⚠ живой дефект под конкуренцией — `PD-369` | закрыто D39.153 | | `bearerToken` — чем ВЫДАЁТСЯ токен | вход только ставит HttpOnly-куку (`login.go:338`) | сервер токен ПРИНИМАЕТ, выдать его нечем | носитель: research/28 §2 (Б-15); строки нет | | `Problem.localized` | — | объявлено, ни одним кодом не используется | носитель: research/28 §8 п.4 | -| `Note.code` как enum спеки | карта приложения А | не enum, пока не написаны фразы | ⚠ **прежний носитель «строка 148» МЁРТВ** — строку удалил `a023e39` решением владельца 21.08 (тот же факт этот док уже несёт ниже, в §6в); живой носитель — строки бэклога **203 + 204** (словарь фраз) | +| `Note.code` как enum спеки | карта приложения А | не enum, пока не написаны фразы | ⚠ **прежний носитель «строка 148» МЁРТВ** (`a023e39`, 21.08; разбор — приложение А, п.3); живой носитель — строки бэклога **203 + 204** (словарь фраз) | | Настоящие названия глав (`Chapter.heading` ≠ null) | парсер структуры | НЕ ПОСТРОЕНО | строка 160 (Этап 0) | | `title_raw` / `kind` (глава ↔ фрагмент) | дизайн-пак структуры глав | передано паку, аддитивно | строка 161 | | `ErrorCode.content_refused` (400) **и** `RejectReason.content_refused` | прескрин злоупотреблений | НЕ ПОСТРОЕН ни на одной стороне: в платформе только объявление константы (`httpapi/problem.go:42,94`), `ContractRejectReason` (`ingest/vocabulary.go:59-69`) его не отображает; в движке отказ провайдера живёт как ПРИЧИНА ЗАМЕЧАНИЯ (`disposition.go:60-63` → `Note.code: content_withheld`) и в exit-контракт не выходит — мостá между двумя словарями нет | **строка 94 (ПТ-16)**; там же ограничение числа попыток аккаунта — обязанность падает ВМЕСТЕ с производителем, не раньше | -| `decline` в подписи банка доезжает до работы | ⚠ пере-снято 0.5.0: старый носитель («таблица `bank_decisions`, движок её не читает») умер вместе с моделью — таблица снесена 22.08, предупреждение на `BankDecision.action` снесено вместе со схемой | дверь смонтирована (D39.162), и decline доезжает до следующего прогона ПО ПОСТРОЕНИЮ. ⚠ **Остаток ДВИЖКОВЫЙ, две штуки, обе найдены воркфлоу-ревью P9:** decline не энтити-широк на обратном пути (отклонённая сущность возвращается через свой АЛИАС, `mining.go:548`), и повтор ТОГО ЖЕ документа на одном пути не сходится (`membank/decisions.go:374`) — второе ломает обещание сходимости, на котором стоит синхронная дверь | заказано бэкенд-паку «тихая порча», `../../archive/prompts/BACKEND_SILENT_HARM_SESSION_PROMPT_2026-08-28.md` §3.3 | ⚠ пере-снято 30.08: из двух движковых остатков ВТОРОЙ ЗАКРЫТ — порядок записи документов решений сменён на rejects-first, повтор принятого документа СХОДИТСЯ (D39.164 §3.3). Живым остаётся ОДИН: `decline` не энтити-широк на обратном пути — отклонённая сущность возвращается через свой АЛИАС, тогда как канон обещает «declining a surface removes EVERY window of that surface». Носитель — строка 228 единого бэклога. +| `decline` в подписи банка доезжает до работы | ⚠ пере-снято 0.5.0: старый носитель («таблица `bank_decisions`, движок её не читает») умер вместе с моделью — таблица снесена 22.08, предупреждение на `BankDecision.action` снесено вместе со схемой | дверь смонтирована (D39.162), и decline доезжает до следующего прогона ПО ПОСТРОЕНИЮ. ⚠ **Живой остаток — ДВИЖКОВЫЙ, один:** `decline` не энтити-широк на обратном пути (отклонённая сущность возвращается через свой АЛИАС, `mining.go:548`), тогда как канон обещает «declining a surface removes EVERY window of that surface» | строка 228 единого бэклога; сходимость повтора закрыта D39.164 §3.3 | | Снятие замечания (переход «флаг снят») | движок | **НЕДОСТИЖИМО сегодня, проверено чтением движка** — п. H §6в | **PD-298** регистра платформы (`platform/docs/DEFECT_REGISTER.md`) — там строка и живёт; механизма не строим | | Счёт «сделанного» на деплое без второго прохода | платформа | канон 0.4.0 определил «сделано» = последний проход ЭТОГО деплоя; проекция платформы считает жёстко второй проход | **вход P7** ИЗРАСХОДОВАН (D39.153) (PD-202) | -⚠ **Три прежних предупреждения СНЯТЫ как устаревшие** (Б-7а), и это причина, по которой заведена -таблица выше: - -1. «`GET /bank` — канала нет вообще» — неверно с D39.122: сайдкар пишется. Файл при этом противоречил - сам себе (строка таблицы против абзаца ниже неё), а зона фронта до сих пор учится по старой - версии (Ф-43). -2. «`EventNote` — движок не эмитит пер-юнитных замечаний» — эмиттер приземлился 14.08. -3. «`EventCeiling` — зависит от эмиттера» — то же (кадр при этом снят по §5а, см. §6). +⚠ Три из четырёх протухших предупреждений (Б-7а) сняты молча — они лишь устарели; живой хвост +одного: зона фронта до сих пор учится по старой версии «`GET /bank` — канала нет вообще» (**Ф-43**). ⚠ **Четвёртое было ХУЖЕ устаревшего — оно было НОРМАТИВНЫМ и отнимало работающее лечение.** Спека 0.2.3 писала: механизма поднятия потолка нет, «so the client MUST NOT offer resume as the remedy for @@ -1081,44 +1067,19 @@ the original request was never applied». Каждый `POST /books` созда ## 6б. Дофикс-раунд 16.08 (ФБ-1…ФБ-10): что он изменил в каноне и почему -Заказ — D39.142 п.3, приёмка с перечнем всех десяти закрытых правок — D39.143 п.1; сами правки -живут в каноне. Линза — ХОЛОДНЫЙ ПОТРЕБИТЕЛЬ: только финальная спека и проба генератором, без -ревью, без компаньона, без диффа. Ниже — основания, которых нет ни в каноне, ни в нотах. +Заказ раунда — 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` в каноне). Здесь остаётся только то, чего нет ни там, ни в нотах: -- **ФБ-1, форма кадра была двусмысленна.** `EventEnvelope{event,id,data}` читался и как объект на - проводе, и как описание SSE-фрейминга — оба чтения соответствовали тексту. Это тот класс дефекта, - который не ловится ни линтером, ни генератором: документ валиден в ОБОИХ прочтениях. Теперь на - схеме дословный пример кадра: `event` и `id` — ПОЛЯ SSE, телом кадра является `data` и только оно. -- **ФБ-2, книга в покое могла крутить переподключение вечно.** Служебные кадры несут id последнего - кадра истории — а у книги, которая ещё ничего не производила, такого кадра нет. Лечение самое - дешёвое: история нумеруется с `1`, служебные кадры пустой книги несут `0`, а `Last-Event-ID: 0` - попадает под уже существующее правило `204`. -- **ФБ-5, пустые члены `allOf` давали НЕОБИТАЕМЫЕ типы** (`Record` в пересечении — - значение построить нельзя). `EventEnd` и `EventResyncRequired` — чистый `allOf` из одного члена; - попутно записано, что эти два кадра НЕРАЗЛИЧИМЫ по форме и диспетчеризация только по имени события. -- **ФБ-7, пол под моделью ошибок.** Весь §Errors описывал ответы, которые СООТВЕТСТВУЮТ контракту, а - ответ прокси, HTML-страница или оборванное тело — ровно то место, где у клиента нет ни `code`, ни - `request_id`. Записано: не показывать из такого ответа ни байта, рисовать свою нейтральную фразу. -- **ФБ-9, слова, которые называли не то.** `parser_unavailable` называл наш компонент — переименован - в `processing_failed`, по эффекту: имя значения это то, на что клиент вешает фразу. ⚠ **Живое +- **ФБ-9, шов имён.** `parser_unavailable` переименован на проводе в `processing_failed`. ⚠ **Живое следствие для шва:** проводное имя отличается от внутреннего словаря платформы, где значение по-прежнему зовётся `parser_unavailable` (`platform/internal/books/parse.go:66`), и проекция обязана отобразить одно на другое; рядом там же живут `schema_mismatch` и `storage_unavailable`, - которые на провод не идут вовсе. Тем же ходом из описаний вычищены внутренние ссылки на ревью — - описания компилируются в исходники клиента, и ссылка на чужой репозиторий там мусор. -- **ФБ-8, пачка мелких.** ⚠ Тождество `Idempotency-Key` на multipart считалось «по объявленным - частям» — ПЕРЕКРЫТО 0.4.0, читать по §2.18. Прочее живёт нормами в каноне: `title: null` в - merge-patch — `400`, а не удаление члена по RFC 7386 · `X-TM-Client` `required: true` при живом - исключении для bearer (условной обязательности по схеме безопасности OpenAPI не выражает) · - список отказов интейка неисчерпывающий, авторитет — `code` · правило резолюции `Location` · `408` - не считается состоявшейся попыткой · `min_chapters` при `max_chapters: 0` — не диапазон · порядок - пяти носителей «нет кредита» · `409` у экспорта — ключевой, а не книжный · фраза «carried forward - marked as unverified» СНЯТА как обещание без носителя, наблюдаемое вместо неё — `BankPage.signed` - против `total`. -- **ФБ-3, ФБ-4, ФБ-6** записаны на своих местах: обязанность дельта-чтения `/notes?after_version=…` - после КАЖДОГО переподключения и водяной знак «НАИМЕНЬШАЯ ревизия обхода» — §2.10; таблица - поведения `resume` по всем статусам (новый прогон легален при ЛЮБОМ `paused`, включая `null`; - причина паузы — подсказка о прошлом, а не разрешение на будущее) — канон, без нового значения enum. + которые на провод не идут вовсе. +- **ФБ-8.** ⚠ Тождество `Idempotency-Key` на multipart считалось «по объявленным частям» — + ПЕРЕКРЫТО 0.4.0, читать по §2.18. ## 6в. Синк с платформой 20.08 → канон 0.4.0: что решено и почему @@ -1184,7 +1145,7 @@ A · B · G · H · J · L разобраны ниже полностью — и | **I.** `content_refused` | forward-looking, долг зона не заводит: значение ратифицировано К-9 ДО производителя сознательно. Обязанность ограничивать число попыток аккаунта пере-привязана — падает ВМЕСТЕ с производителем, а не висит на сервере, который отказа не выдаёт | §3, строка `content_refused` (строка 94, ПТ-16); приложение А-2 | | **K.** `--verify-bank` | НЕ контракт, релей в зоны. Контрактно видимая половина закрыта D39.144/145. ⚠ Вторая половина умерла вместе с носителем: схема `BankDecision` снесена 0.5.0, дверь-преемник пишет файлы движка сама, так что «решение не доезжает» перестало быть свойством формы | §2.19-бис; §3, строка `decline`; D39.144 | | **M.** Что зона сделала сама | сверено, возражений нет (восемь пунктов, включая снятие `codeForStatus`) | D39.152 п.2 | -| **N.** Границы сессии; что забирает P7 | шесть релеев зоне (A · D · E · G · J · H) приняты и построены паком P7 | D39.153; статусы — таблица §3 | +| **N.** Границы сессии; что забирает P7 | шесть релеев зоне (A · D · E · G · J · H) приняты и построены паком P7. ⚠ **Граница автора 0.4.0** (его собственное объявление, восстановлено): НЕ проверялось, как экраны фронта рисуют новые ответы (зона заморожена) и как ведёт себя построенный путь `resume` после правки таблицы — это работа P7 | D39.153; статусы — таблица §3 | ### A. Прогон с исчерпанным бюджетом (PD-282 ⚠ ЗАКРЫТО (PD-282 `fixed`, акт 5; разбор — §3)) — ПРАВЛЮ КАНОН; половину мнения отклоняю @@ -1205,8 +1166,7 @@ A · B · G · H · J · L разобраны ниже полностью — и чтобы отличить успех от no-op. И записано разделение, о котором предупреждает сам канон у `AccountHaltReason`: пустота СЧЁТА не сворачивается в `ceiling_reached` — у неё своя причина `credit_unavailable` (аддендум ниже), а состояние аккаунта ЦЕЛИКОМ по-прежнему говорит `Usage`, не -этот вызов. *(Первая редакция раздела писала здесь «пустой счёт — не ответ этого вызова», что -противоречит и аддендуму, и канону; испр. оркестратором при ратификации.)* +этот вызов. **Признак «этот прогон ещё можно продолжить» на `Run` — ОТКЛОНЁН, с оговоркой.** Посылка «платформа знает его точно» верна, посылка «дёшево» — нет: `ReadRun` — один запрос по `books join runs` @@ -1218,8 +1178,7 @@ focus»), то есть цена платится на горячем пути (§RunOptions): `max_chapters == 0` + `blocked` — это ровно «стоит ли предлагать старт сейчас и что мешает», и рисует его тот же экран. Авторитет по-прежнему у мутации, как канон и объявляет. ⚠ Поправка ревью к предыдущему абзацу: сам `Run` в КАДРЕ не едет — ни один payload его не несёт; -горячий путь создаёт не кадр, а предписанная им перечитка карточки. Вывод не меняется, носитель -цены — другой; первая редакция называла его неверно. +горячий путь создаёт не кадр, а предписанная им перечитка карточки. Вывод не меняется, носитель цены — другой. **Триггер пересмотра:** замер, показывающий, что мёртвый клик частый, ЛИБО сворачивание трёх чтений в коррелированные подзапросы того же запроса (агент проверил — возможно). Тогда форма — `Run`, поле, минор. @@ -1393,8 +1352,7 @@ particular version of HTTP (for example, HTTP/2's multiplexing), **this ought be · **обязанность честить `Accept-Encoding` на JSON-ответах и НЕ сжимать `text/event-stream`** · `Vary` на согласованном представлении · `Cache-Control: no-store` · запрет буферизации потока · форма heartbeat · форма `id` кадра. Сжатие как ТРЕБОВАНИЕ живёт в контракте — это прямое указание D39.138 -п.2(д) («сжатие и условные чтения записываются В КОНТРАКТ, не в зонный док»), и первая редакция -батча его нарушила, вынеся сжатие целиком в примечание; поймано опровергателем полноты и исправлено. +п.2(д) («сжатие и условные чтения записываются В КОНТРАКТ, не в зонный док»). В примечании остаётся ТОЛЬКО слой исполнения — где именно сжимать, — потому что вот этого клиент действительно не наблюдает, и вот это Б-16 из контракта и выносит. diff --git a/docs/architecture/15-money-path.md b/docs/architecture/15-money-path.md index d390bff6..4469a516 100644 --- a/docs/architecture/15-money-path.md +++ b/docs/architecture/15-money-path.md @@ -24,17 +24,17 @@ - **`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). -- **Согласие на пере-оплату — ДВИЖКОВЫЙ гейт** (доп. ревизией 02.09: из трёх опор канона §1 у этой не было носителя ни в §2, ни в карте §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), то есть срабатывает позже, чем подсказывает полная проекция. +- **Согласие на пере-оплату — ДВИЖКОВЫЙ гейт**. Прогон, который пере-покупает уже оплаченные юниты дороже порога, ОСТАНАВЛИВАЕТСЯ и требует явного согласия. Порог по умолчанию ратифицирован 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), то есть срабатывает позже, чем подсказывает полная проекция. ## 3. Деньги ПЛАТФОРМЫ по шагам (зона `platform/`) 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: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`=`Движковая поверхность оценки`). 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`). -7. ⚠ **Терминальный вердикт ОПЕРАТОРА — путь холда мимо settle (добавлено 22.08, P8-FIX/D39.154).** Прогон, чей движок не ответит уже никогда, закрывает человек: `tmplatformctl run abandon --run --reason <текст> [--release-hold]`. Команда ОТКАЗЫВАЕТ, если попытка ещё называет юнит или несёт базовую линию траты — над живым движком прогон не закрывают. Холд возвращается ЦЕЛИКОМ в обоих случаях (к abandon допускается только попытка, не дошедшая до движка, значит она ничего не потратила), а флаг решает лишь КОГДА — сразу или на ближайшем свипе. До этого пака такого пути не было вовсе: холд чужого аккаунта висел, пока кто-нибудь не залезет в БД руками. ⚠ **С пака P11 (`PD-385`) ВЕТВЕЙ ДВЕ, и абзац выше — только ЖИВАЯ** (испр. ревизией 02.09; образец — секция «Строка PHASE = settling» в `platform/deploy/README.md`). У прогона, чья попытка уже КОНЧИЛАСЬ, команда идёт второй ветвью: отказ «юнит/базовая линия» к ней НЕ применяется, к abandon допускается попытка, которая ДОШЛА до движка и ПОТРАТИЛА, холд всё равно возвращается ЦЕЛИКОМ по каждой осиротевшей попытке, а флаг `--release-hold` там ИГНОРИРУЕТСЯ; единственная защита — порог `abandonAfter` неудач расчёта (отказ `ErrSettlementNotStuck`). ⚠ **Ветвление идёт по `runs.finished_at`, а НЕ по наличию осиротевшей попытки** — ратифицированная оговорка `PD-418`. ⚠ **И вторая ветвь НЕ лечит живую:** прогон с намертво заблокированной расплатой уходит в ЖИВУЮ ветвь и закрыт отказом по юниту до сих пор — `PD-424` стоит `open` именно на этой половине. +7. ⚠ **Терминальный вердикт ОПЕРАТОРА — путь холда мимо settle (добавлено 22.08, P8-FIX/D39.154).** Прогон, чей движок не ответит уже никогда, закрывает человек: `tmplatformctl run abandon --run --reason <текст> [--release-hold]`. Команда ОТКАЗЫВАЕТ, если попытка ещё называет юнит или несёт базовую линию траты — над живым движком прогон не закрывают. Холд возвращается ЦЕЛИКОМ в обоих случаях (к abandon допускается только попытка, не дошедшая до движка, значит она ничего не потратила), а флаг решает лишь КОГДА — сразу или на ближайшем свипе. ⚠ **С пака P11 (`PD-385`) ВЕТВЕЙ ДВЕ, и абзац выше — только ЖИВАЯ** (испр. ревизией 02.09; образец — секция «Строка PHASE = settling» в `platform/deploy/README.md`). У прогона, чья попытка уже КОНЧИЛАСЬ, команда идёт второй ветвью: отказ «юнит/базовая линия» к ней НЕ применяется, к abandon допускается попытка, которая ДОШЛА до движка и ПОТРАТИЛА, холд всё равно возвращается ЦЕЛИКОМ по каждой осиротевшей попытке, а флаг `--release-hold` там ИГНОРИРУЕТСЯ; единственная защита — порог `abandonAfter` неудач расчёта (отказ `ErrSettlementNotStuck`). ⚠ **Ветвление идёт по `runs.finished_at`, а НЕ по наличию осиротевшей попытки** — ратифицированная оговорка `PD-418`. ⚠ **И вторая ветвь НЕ лечит живую:** прогон с намертво заблокированной расплатой уходит в ЖИВУЮ ветвь и закрыт отказом по юниту до сих пор — `PD-424` стоит `open` именно на этой половине. 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(`). diff --git a/docs/architecture/16-events-emitter.md b/docs/architecture/16-events-emitter.md index a5681673..f028c2af 100644 --- a/docs/architecture/16-events-emitter.md +++ b/docs/architecture/16-events-emitter.md @@ -31,7 +31,7 @@ **Отвергнутые альтернативы** (`25:33-44`; повторены в доккомменте зоны, «so that none of them comes back as a fresh idea» — `events.go:21-23`): платформа-родитель + пайп stdout/fd — **0 из 15** («время жизни движка — подмножество платформы: деплой/рестарт убивает или осиротляет прогон», `25:38`) · выделенный fd 3 — **0** (`25:43`) · stdout/journald как источник событий — **0** («journald молча роняет под всплеском и ротирует сам; людям — да, контракту — нет», `25:44`) · gRPC/HTTP поверх движка — 0 (`25:39`) · push в платформу — 2→0 (`25:40`) · брокер — 0 (`25:41`) · монолит — 0 из ~18 (`25:37`). Пайп-путь `supervisor.go` — ДЕВ-режим и только (D39.106 п.3; `events.go:23`). -**Словарь событий — В КОДЕ, не здесь.** Он родился предложением платформы, записанным кодом («so the engine zone can answer it with a diff»), движок ответил диффом, и с тех пор словарь двигался миноры. Действующий носитель — `backend/internal/runevents/runevents.go` (греп `const StreamVersion`): конверт `{seq, type, time, data}` · типы `hello`/`progress`/`unit_done`/`bank_stop`/`ceiling`/`spend`/`finished` · `Hello{stream_version, engine_run_id, book_id, chunker_version}` · пофазные счётчики `progress` (семантика `done` = «разрешено волной» — D39.122 п.2б) · `Ceiling{halted, scope}` · `Spend{committed_micro_usd}` · `Finished{outcome}` с ледджером объёма. Зеркало-читатель — `platform/internal/ingest/events.go`. ⚠ Версии двух сторон расходятся по построению (минор = ignore-unknown): сверять по коду, а не по этому доку — числа в теле дока не поддерживаются (носитель расхождения — бэклог-строка 243, находка `arch-10`). +**Словарь событий — В КОДЕ, не здесь**, и двигается минорами. Действующий носитель — `backend/internal/runevents/runevents.go` (греп `const StreamVersion`): конверт `{seq, type, time, data}` · типы `hello`/`progress`/`unit_done`/`bank_stop`/`ceiling`/`spend`/`finished` · `Hello{stream_version, engine_run_id, book_id, chunker_version}` · пофазные счётчики `progress` (семантика `done` = «разрешено волной» — D39.122 п.2б) · `Ceiling{halted, scope}` · `Spend{committed_micro_usd}` · `Finished{outcome}` с ледджером объёма. Зеркало-читатель — `platform/internal/ingest/events.go`. ⚠ Версии двух сторон расходятся по построению (минор = ignore-unknown): сверять по коду, а не по этому доку — числа в теле дока не поддерживаются (носитель расхождения — бэклог-строка 243, находка `arch-10`). ## 3. Контракт декодера и дублей (PD-105 · D39.123 п.2(в)) @@ -39,14 +39,14 @@ > «доставка событий шва = at-least-once; ДУБЛЬ `seq` — норма повторного чтения, декодер обязан принимать идемпотентно без фатала; тот же `seq` с ДРУГИМ payload = карантин прогона (research/25)». -⚠ **Расхождение, разрешённое позже**: «карантин прогона» (D39.119 п.3 и `research/25:77-78` «тот же seq с другим payload = карантин прогона, не тихий no-op») уточнён D39.123 п.2(в): «**PD-105-реализация: карантин ПРОЕКЦИИ (попытки), не прогона** — уточнение D39.119; деньги прогона сеттлятся ремонт-каналом». Побеждает D39.123 как более свежая нота. +⚠ **Расхождение, разрешённое позже:** «карантин прогона» — тот же, что процитирован выше (и `research/25:77-78`) — уточнён D39.123 п.2(в): «**PD-105-реализация: карантин ПРОЕКЦИИ (попытки), не прогона** — уточнение D39.119; деньги прогона сеттлятся ремонт-каналом». Побеждает D39.123 как более свежая нота. Как это реализовано читателем (тело — `platform/docs/DEFECT_REGISTER.md`, греп `PD-105`): `ingest.Tail` пропускает `seq <= last_seq` идемпотентно и без ошибки, `pgstore.RunSink.Apply` пере-проверяет тот же high-water mark ВНУТРИ транзакции эффекта, сверка дублей — по sha256 сырой строки (`run_attempts.last_line_sha256`). Пропасть (`seq > last+1`) осталась ошибкой: строки потеряны, читать дальше нечего. - **hello — всегда первая строка потока, seq=1** (`decoder.go:64`: «hello carries seq 1, want 1»); версия — правило terraform, ратифицировано D39.85: «a MINOR bump adds fields and event types — unknown ones are ignored; a MAJOR bump is refused» (`events.go:34-37`); мажор-несовпадение = `ErrUnsupportedVersion` (`events.go:150-163`). - **Дубль строки безопасен, значит строка обязана быть повторимой байт-в-байт** — сверка дублей идёт по sha256 сырой строки (`tail.go:44-49`); тот же seq с другим payload = `ErrPayloadConflict` (`tail.go:20-24, 181`). Эмиттер не должен пере-генерировать уже записанную строку иначе (например, с другим timestamp при реплее). - **Пропуск seq фатален для чтения** (`tail.go:190`, `ErrStreamGap`) — нумерация плотная, без дыр. -- **Недописанная последняя строка — не ошибка**: тейлер «deliberately left alone» строку без `\n` — это строка в процессе записи (`tail.go:51-55`). Это смягчает, но не снимает формат-развилку §5 (битая запись С валидным `\n` остаётся слепым пятном JSONL — `research/25:74-75`). +- **Недописанная последняя строка — не ошибка**: тейлер «deliberately left alone» строку без `\n` — это строка в процессе записи (`tail.go:51-55`). Это смягчает, но не снимает слепое пятно JSONL — битую запись С валидным `\n` (`research/25:74-75`); сама развилка формата решена в пользу одиночного JSONL (⚠-строка в конце §5). - **Ключ — engine_run_id из hello**, не прогон платформы; чужие run id в том же файле тейлер пропускает (`events.go:63-65`, `tail.go:58-60`). ## 4. Деньги и потолок @@ -59,7 +59,7 @@ **Потолочная окрестность — не здесь.** Семантика `--ceiling-usd` (КНИЖНЫЙ потолок в силе, не бюджет прогона; D39.122 п.2в) и формула аргумента потолка `committed + прирост×ставка` БЕЗ reserved (D39.123 п.2б, PD-158) живут одним маршрутом в `15-money-path.md` §2–§3. Для эмиттера важно ОДНО следствие: платформа выставляет потолок впритык к холду, значит стоп по потолку = ровно исчерпание холда — потому событие потолка и различимый exit-код и перестали быть косметикой (D39.123 п.2ж). -**Дефекты-входы, из-за которых форма именно такая** (тела и текущий статус — `platform/docs/DEFECT_REGISTER.md`, греп `PD-79` · `PD-60` · `PD-61` · `PD-99` · `PD-107`): деньги шва едут ЦЕЛЫМИ micro-USD без строковых форм и float (урок PD-79: строковый `"null"` читался как ноль денег) · политика «журнал не пишется» выбирается ЯВНО, молчаливой третьей нет (PD-60) · буфера в эмиттере НЕТ вовсе — это и есть ответ на PD-61(а), потому что `os.Exit`/`log.Fatal`/паника пропускают defer и потеряли бы ровно `finished` и `ceiling` (`backend/internal/runevents/journal.go`, греп `There is no user-space buffer`) · деньги и id книги не текут в INFO и на провод (PD-99, D39.84) · удаление аккаунта против живого холда — гейт перед появлением такой операции (PD-107). +**Дефекты-входы, из-за которых форма именно такая** (тела и текущий статус — `platform/docs/DEFECT_REGISTER.md`, греп `PD-79` · `PD-60` · `PD-61` · `PD-99` · `PD-107`): деньги шва едут ЦЕЛЫМИ micro-USD без строковых форм и float (урок PD-79: строковый `"null"` читался как ноль денег) · политика «журнал не пишется» выбирается ЯВНО, молчаливой третьей нет (PD-60) · буфера в эмиттере НЕТ вовсе — это и есть ответ на PD-61(а), потому что `os.Exit`/`log.Fatal`/паника пропускают defer и потеряли бы ровно `finished` и `ceiling` (`backend/internal/runevents/journal.go`, греп `There is no user-space buffer`; ⚠ имя `/events.ndjson` в ТЕЛЕ PD-61 — до-ратификационное и его закрывающий баннер имени не правит: канон — `events.jsonl` каталога книги, D39.106 п.2) · деньги и id книги не текут в INFO и на провод (PD-99, D39.84) · удаление аккаунта против живого холда — гейт перед появлением такой операции (PD-107). ## 5. Оговорки, которые переживают стройку diff --git a/docs/architecture/17-seam-inbound-law.md b/docs/architecture/17-seam-inbound-law.md index 2585e277..387b91ba 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` — ратифицированная форма и > отвергнутые альтернативы). НАРУЖУ из движка идёт богатый поток — журнал событий по курсору, полоса кодов -> выхода, версионированные артефакты-проекции, — а ВНУТРЬ не шло ничего, кроме запуска с флагами: данными, -> имперсонировать человека-оператора с текстовым редактором. +> выхода, версионированные артефакты-проекции, — а ВНУТРЬ не шло ничего, кроме запуска с флагами: данные, которыми +> владеет пользователь продукта, движок принимать не умел вовсе, и каждый внешний участник был вынужден имперсонировать человека-оператора с текстовым редактором. ## Почему НОРМА, а не каталог команд @@ -23,7 +23,7 @@ строки 199. Против ПОЛНОГО каталога — то, что половина будущих дверей гейтится нерешёнными развилками: строка -**192** прямо запрещена к проектированию до полигонных итогов (D39.144 п.1), **161**/**185** ждут +**192** прямо запрещена к проектированию до полигонных итогов (D39.144 п.1; ⚠ область сужена D39.165 — открыть дверь к построенному ≠ проектировать цикл, см. ⚠-строку под таблицей дверей), **161**/**185** ждут дизайн-пака, **170** — «после беты формы Б». Каталогизировать их сейчас значит выдумывать. Прецедент, разрешающий спор, — исходящее направление: там выиграла ратификация ПОЛОСЫ и ДИСЦИПЛИНЫ, @@ -59,9 +59,9 @@ (`platform/internal/runs/reconcile.go` (греп `202` в обработчике возобновления; ⚠ номер строки снят 30.08 — файл правит живая сессия P12)). Дверь «менять потолок файлом» закрыта; не выдумывать её заново из `research/25`. -3. **Каждый JSON-выход глагола несёт версию документа.** Сегодня асимметрия: `tm-bank-v1` - (`pipeline/bankexport.go:30`=`const bankExportVersion = "tm-bank-v1"`) и `tm-manifest-v2` (`pipeline/manifest.go:46`=`const manifestVersion = "tm-manifest-v2"`) версию несут, - а `status --json` — ⚠ **УЖЕ НЕСЁТ, п. ИСПОЛНЕН** (`backend/internal/pipeline/status.go:155-156`=`const statusVersion = "tm-status-v1"`, проставляется `:485`). Асимметрии больше нет; прежняя редакция требовала «Закрыть» и заставила бы следующий пак заплатить за построенное второй раз — испр. аудитом доков 28.08 (D39.167). +3. **Каждый JSON-выход глагола несёт версию документа — п. ИСПОЛНЕН, асимметрии нет:** `tm-bank-v1` + (`pipeline/bankexport.go:30`=`const bankExportVersion = "tm-bank-v1"`), `tm-manifest-v2` (`pipeline/manifest.go:46`=`const manifestVersion = "tm-manifest-v2"`) + и `status --json` (`backend/internal/pipeline/status.go:155-156`=`const statusVersion = "tm-status-v1"`, проставляется `:485`). 4. **Незнакомый флаг = громкий отказ при спавне.** Сегодня это так по устройству разбора аргументов (`backend/cmd/tmctl/invocation.go:128`=`flag.NewFlagSet(cmd, flag.ContinueOnError)`); зафиксировать законом, а не полагаться на случайность. @@ -102,8 +102,7 @@ **Не установлено, проверить при постановке:** строка **198** (апгрейд стирает замечания) — возможно, подразумевает глагол пере-анонса или бэкфилла, потому что движок анонсирует юнит один раз за жизнь книги -(`backend/internal/pipeline/events.go:404`=`func unitOnceKey(bookID string, k unitWave) string`); направление фикса консилиум НЕ установил. Записано третьей -категорией, чтобы читатель ратификации не счёл свип дырявым. +(`backend/internal/pipeline/events.go:404`=`func unitOnceKey(bookID string, k unitWave) string`); направление фикса консилиум НЕ установил. **Из чего двери НЕ следует** (экономия паков): **202** — потребитель всего набора, своих команд не несёт · **208** — фикс транспорта внутри движка · **210** — развилка данных/промпта, вайр-батч 182 · @@ -115,8 +114,8 @@ границы процессов; единственный мид-ран кандидат закрыт каноном (п.2); инбокс-файл возвращает гонку, ради исключения которой существует flock. ⚠ **Эррата, которую ратифицирующая нота обязана поставить на `research/25`:** там «поднятие потолка файлом через -atomic rename» отнесено к носителям D39.106 — в теле D39.106 этого механизма НЕТ вовсе (проверено по ЖИВОМУ телу ноты **D39.106** («ШОВ: прогон переживает деплой платформы») в `architecture/05-decisions-log.md` — адресуем НОМЕРОМ, а не строкой: прежний line-якорь уже съехал внутрь чужого тела (гейт якорей, 28.08); ⚠ испр. 23.08 — прежняя редакция ссылалась на слайс -`archive/architecture/05-decisions-D39-106-123.md`, где тела D39.106 НЕТ, и греп по нему подтвердил бы эррату вакуумно; первый хит темы — только в D39.110). Строка была КАНДИДАТОМ и +atomic rename» отнесено к носителям D39.106 — в теле D39.106 этого механизма НЕТ вовсе (проверять по ЖИВОМУ телу ноты **D39.106** («ШОВ: прогон переживает деплой платформы») в `architecture/05-decisions-log.md`, адресуя НОМЕРОМ, а не строкой; ⚠ в слайсе +`archive/architecture/05-decisions-D39-106-123.md` тела D39.106 НЕТ — греп по нему подтвердил бы эррату вакуумно). Строка была КАНДИДАТОМ и никогда не ратифицировалась, а живой канон решил ось иначе (п.2). - **Пере-открытие транспорта** (gRPC/сокет/брокер/пуш) — `research/25`, у каждой альтернативы 0 diff --git a/docs/architecture/18-bank-ontology.md b/docs/architecture/18-bank-ontology.md index 5e93055f..7e077062 100644 --- a/docs/architecture/18-bank-ontology.md +++ b/docs/architecture/18-bank-ontology.md @@ -7,9 +7,8 @@ > **Зачем страница.** Вокруг одного понятия — «состояние банка этой книги» — живут десять носителей, > выросших пак за паком. Форма при этом СТРОГАЯ: поток однонаправленный, у каждого источника > единственный писатель, вид пересобирается полностью на каждой границе прогона. Но эта строгость не -> была записана нигде — каждый файл документировал свою роль, ни одно место не документировало поток. -> Из-за этого приёмка сначала прочитала девять носителей как девять заплаток и едва не заказала -> рефактор ради стройности. Страница дешевле рефактора и снимает причину, а не симптом. +> была записана нигде — каждый файл документировал свою роль, ни одно место не документировало поток +> (D39.158 п.8). ## Четыре роли, и они не смешиваются @@ -66,8 +65,7 @@ проверяет. Разделено 27.08 по вычитке старшего: в одном классе они были бы неподсудны — первый же судья отклонил бы членство порядка, и вместе с ним ушёл бы весь класс. -⚠ **Второй ярус КЛАССА A, дописан 27.08 по замечанию платформенной сессии при приёмке -`D39.159`: носитель с ДВУМЯ писателями и НОЛЬ читателей.** Здесь опасность не в отсутствии +⚠ **Второй ярус КЛАССА A (D39.159): носитель с ДВУМЯ писателями и НОЛЬ читателей.** Здесь опасность не в отсутствии потребителя — она в том, что расхождение писателей ничем не судится, пока читателя нет, а в день, когда читатель появится, разница СТАНЕТ семантикой, и разрешать её придётся задним числом по уже накопленной истории. Отсутствие потребителя из симптома делается отсрочкой платежа. Живой член — diff --git a/docs/glossary.md b/docs/glossary.md index add94de9..cb4732fc 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -10,7 +10,7 @@ - **Ф0–Ф3** — фазы: Ф0 скелет · Ф1 инфраструктура · Ф2 качество (судья/гейты) · Ф2.5 пилот · Ф3 продукт (веб-фронт, ридер-IDE). - **S-этапы (S0…) / P-этапы (P0…)** — нумерация кодовых сессий зон: **S** — фронт (S0–S4 приняты; ⚠ зона ЗАМОРОЖЕНА, разморозка отдельным словом владельца и к паку платформы НЕ привязана — D39.136 п.2 + D39.147), **P** — платформа (P0 бутстрап … P12); не путать с фазами Ф0–Ф3, и не всякий пак несёт P-номер (пак `sqlc` не несёт, D39.172). ⚠ Живой перечень принятых паков со статусами — реестр `architecture/05-decisions-index.md` (греп номера: `grep -inE '\bP-?[0-9]+\b' docs/architecture/05-decisions-index.md`); здесь только расшифровка обозначения. ⚠ P-номер этапа платформы не путать с P-номером ПРОБЫ в отчётах полигона (там контекст локален). - **Зонный журнал / зонный бэклог** — `frontend/docs/frontend-PROGRESS.md` · `platform/docs/platform-PROGRESS.md` и BACKLOG зоны: прогресс/пинги фронта и платформы живут ТОЛЬКО там (D39.100); их строки единый бэклог не принимает (D39.84). -- **D-номер с подпунктом** (`D20.4`, `D22.7`, `D39.153 п.9б`) — ПОДПУНКТ внутри тела родительской ноты. Реестр `architecture/05-decisions-index.md` несёт ноты ВЕРХНЕГО уровня, своей строки у подпункта там нет и не должно быть. ⚠ Практическое следствие: греп `^## D20.4` даёт ЛОЖНЫЙ фантом — не нашёл номер, грепни родителя до точки. +- **D-номер с подпунктом** (`D20.4`, `D22.7`, `D39.153 п.9б`) — ПОДПУНКТ внутри тела родительской ноты. Реестр `architecture/05-decisions-index.md` несёт ноты ВЕРХНЕГО уровня, своей строки у подпункта там нет и не должно быть (дисциплина грепа — CLAUDE.md §«Источники истины»). - **Шиппинг-конфиг** — конфиг пайплайна, по которому идёт БОЕВОЙ прогон, в отличие от тестового и от ран-локального. ⚠ Читать строго: «шиппинг-конфиг» = ШАБЛОН в `backend/configs/`; конфиг РЕАЛЬНОГО прогона живёт РЯДОМ С КНИГОЙ, вне git, — он «ран-локальный», и утверждения о нём проверяются в каталоге книги, а не грепом по репозиторию (клейм «гейт не включён ни в одном шиппинг-конфиге» верен про шаблоны и ложен про прогон). - **Полигон** — eval-зона платных/бесплатных экспериментов (`eval/`; отчёты — `docs/experiments/`, статус эксп-а — его баннер/D-лог). @@ -19,7 +19,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, в т.ч. незакрытые владельческие требования. - **Q1–Qn** — нумерованные вопросы КОНКРЕТНОГО пакета/отчёта — контекст локален, Q2 пака-19 ≠ Q2 чекер-пака. -- **V0–V5** — секции идей владельца в `START_PROMT.MD` (живой бриф; разобраны в `product-requirements.md`). +- **V0–Vn** — секции идей владельца в `START_PROMT.MD` (живой бриф; разобраны в `product-requirements.md`). - **Ш-1/Ш-2** — стоячие трипваеры голден-дрейфа стандартной библиотеки; Ш-2 = пересмотр `unicode.Version`-зависимых мест (memnorm/classifier/style + chunker/estimator) до перехода на go1.27 (детали — grep «Ш-2» по D-логу). - **PD-классика** — public-domain тексты из претрейна моделей; эмпирика на них предварительна до вебновелл-среза (CLAUDE.md §Дисциплина). - **Харнесс** — обвязка исполнения (наш пайплайн-транспорт или конкурентные agent-обвязки; калибровка — research/21–22). @@ -27,14 +27,14 @@ - **Пак** — пакет работ одной сессии; **свип** — полная перепроверка обязательств (D39.66: 951 позиция); **добор идеала** — очередь качества после ре-пробы flash; **МАСШТАБ** — прогон целой книги. - **Строка N** — стабильный ID строки единого бэклога (PROGRESS §Бэклог; не перенумеровывается); **вес** — блокер-очереди / скоро / когда-нибудь; **носитель** — артефакт, в котором обязательство живёт; **хвост** — незакрытый остаток; **петля** — вопрос, обязанный получить диспозицию; **слот** — зарезервированное место в будущем пакете/замере. - **Гвоздь** — регрессионный тест, прибивающий контракт (негативный гвоздь — тест на ОТСУТСТВИЕ поведения). -- **Реестр 108 / «жилец реестра»** — строка 108 единого бэклога: реестр ЗАГЕЙЧЕННЫХ ТРИГГЕРОВ (отложенных реопенов с условием «когда вернуться»); «жилец» = такой реопен. «Каждое отложено получает строку бэклога или жильца реестра 108» — норма D39.66/D39.90. -- **Контракт 14 (API v0)** — ратифицированный контракт фронт↔платформа: `architecture/14-api-contract/` — нормативная спека OpenAPI 3.1 + компаньон-README; зонная копия `frontend/docs/api-contract/` — байт-зеркало (D39.99; ⚠ на время фриза фронта зеркало ратифицированно ОТСТАЁТ (D39.142 п.5), синк при разморозке; версии — в самих спеках (`grep '^ version:'`), здесь не пинятся). **Провенанс ✓/◆/○** — классы утверждений компаньона: выведено из кода/ратификации · предложено (подтверждает названная зона) · открыто (К-вопросы). **spectral / openapi-typescript** — линт спеки и генерация типов фронта с дрифт-тестом (⚠ 3.1-условия генератор игнорирует — К-11). +- **Реестр 108 / «жилец реестра»** — строка 108 единого бэклога: реестр ЗАГЕЙЧЕННЫХ ТРИГГЕРОВ (отложенных реопенов с условием «когда вернуться»); «жилец» = такой реопен; норма «каждое отложено получает строку или жильца» — D39.66/D39.90. +- **Контракт 14 (API v0)** — ратифицированный контракт фронт↔платформа: `architecture/14-api-contract/` — нормативная спека OpenAPI 3.1 + компаньон-README; зонная копия `frontend/docs/api-contract/` — байт-зеркало (D39.99; статус зеркала и версий — карта `README.md`, здесь не пинятся). **Провенанс ✓/◆/○** — классы утверждений компаньона: выведено из кода/ратификации · предложено (подтверждает названная зона) · открыто (К-вопросы). **spectral / openapi-typescript** — линт спеки и генерация типов фронта с дрифт-тестом (⚠ 3.1-условия генератор игнорирует — К-11). - **ПТ-N** — стабильный ID требования в `product-requirements.md`; не путать со строками единого бэклога. **paused / лимиты «как Claude Code»** — статус книги при стопе по потолку + страница статуса использования в настройках, сумм на экране нет (ПТ-35, D39.100). ## Пайплайн и код - **`tmctl build`** — $0-глагол ПИСАТЕЛЯ книги: собирает EPUB 3 и чистый txt из `BookExport` (прод-пакет `backend/internal/bookfile`, только stdlib), ОДИН файл на книгу на формат рядом с `ProjectDB`; пути — `StatusArtifacts.book_files` (канал, который читает будущая дверь выдачи платформы), stdout — конверт `tm-build-v1`, отказ — `book_incomplete` (exit 16). D39.175. -- **Состояния честности файла** (писатель книги) — pending · withheld (текст удержан) · incomplete (юнит отгружен с дырой) · **ghost** (остаток источника после укрупнения нарезки: без него книга выглядит «молча полной») · **stale** (финал сделан под исчезнувший исходник; под дрейфом честное `stale_unknown`, никогда не «нет») — все пять ДЫРЫ: по умолчанию отказ с перечнем «глава/юнит/причина», `--partial` — файл с пометкой на титуле и маркером на месте КАЖДОЙ дыры. Шестое, **drift**, — НЕ дыра: носитель `BuildReport`/WARN для оператора, байты файла = байты прогона (слово владельца 30.08, D39.175 п.2). Читательские слова — данные `configs/langpacks/<цель>/reader.txt`, вне `Pack.Version()`; без пака цели — несловесная форма. +- **Состояния честности файла** (писатель книги) — pending · withheld (текст удержан) · incomplete (юнит отгружен с дырой) · **ghost** (остаток источника после укрупнения нарезки: без него книга выглядит «молча полной») · **stale** (финал сделан под исчезнувший исходник; под дрейфом честное `stale_unknown`, никогда не «нет») — все пять ДЫРЫ (поведение отказа и `--partial` — ПТ-44, D39.175). Шестое, **drift**, — НЕ дыра: носитель `BuildReport`/WARN для оператора, байты файла = байты прогона (слово владельца 30.08, D39.175 п.2). Читательские слова — данные `configs/langpacks/<цель>/reader.txt`, вне `Pack.Version()`; без пака цели — несловесная форма. - **Волны** — waveDraft (черновик) → терминолог → waveEdit (редактура); имена только полные, аббревиатуры W0/W1 запрещены (решение владельца 19.07). - **Чанк** — единица нарезки книги; **edit-unit (юнит редактуры)** — member-чанки, схлопнутые редактором в один финальный текст: гранулярность финала и экспорта пар (~1.9 юнита/главу; якорь синхронизации фронта — D39.84; draft-only-пайплайн шипит по чанкам). @@ -46,7 +46,7 @@ - **Эхо-мина** — DeepSeek без thinking эхоит вход вместо перевода; гейт `echoMineViolation` принуждает thinking-ON. - **Langpack / пар-файл** — данные языковой пары (`backend/configs/langpacks/`); книжное в пар-слое = утечка; **общность** — ревью-вопрос «заработает ли пара/вторая книга без правки Go». - **Ведро B/D** — корзины триажа карты общности D39.60 (B «пар-модуль без гейта» · D «удалить»). -- **tmctl** — CLI бэкенда. Полный список глаголов — ОДИН в коде (`backend/cmd/tmctl/main.go`, `dispatchCommands`), и он же печатается в usage (паритет «список ↔ usage ↔ switch» прибит тестом `cmd/tmctl/invocation_test.go`): `translate · report · status · export · **build** · redrive · manifest · backup · migrate · seed-lint · bank-apply`. Порядок здесь = порядок `dispatchCommands`; сверка одной командой: `grep -n -A3 "dispatchCommands = " backend/cmd/tmctl/main.go`. (**build** и **bank-apply** расшифрованы своими строками этого же глоссария). ⚠ Список здесь трижды отставал от кода: добавляешь глагол — правишь ЗДЕСЬ же либо сверяй командой выше. +- **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 по докс-аудиту) @@ -54,9 +54,8 @@ - **Глава** — единица структуры книги: детект `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). - **Лексикон экспериментов:** **жилец** — модель на роли; **арм** — вариант в бейк-оффе; **однопроходка/второй проход** — топологии редактуры; **закон-блок** = доктрина инжекта (D39.104); **пол/floor** — нижний якорь шкалы судьи; **Холм** — поправка Холма на множественные сравнения; **порог различимости** — минимальная дельта, отличимая от шума риге. -- **Входная дверь шва** — половина контракта движок↔платформа, которой не было: наружу поток богатый, - внутрь не шло ничего, кроме запуска с флагами. Закон — D39.156 (`17-seam-inbound-law.md`), построена - и заленджена D39.158. +- **Входная дверь шва** — входная половина контракта движок↔платформа (почему понадобилась — D39.156 + п.2). Закон — D39.156 (`17-seam-inbound-law.md`), построена и заленджена D39.158. - **`tmctl bank-apply`** — $0-глагол входной двери: кладёт правки банка памяти, сделанные пользователем. Проекция `--dry-run`, всё-или-ничего, байтовый no-op идемпотентен, лок проекта неблокирующий. - **Стоп банка** — ФЛАЖОК, а не развилка: движок останавливается на границе майнинга, показывает банк diff --git a/docs/product-requirements.md b/docs/product-requirements.md index 6fb0dee3..9ea032d4 100644 --- a/docs/product-requirements.md +++ b/docs/product-requirements.md @@ -1,6 +1,6 @@ # Реестр продуктовых требований — «что продукт обязан уметь» -> Единый список требований владельца к продукту. Источники: `../START_PROMT.MD` (ЖИВОЙ бриф, идеи V0–**V6**) + владельческие находки H6–H18 (`architecture/09-target-architecture.md` §3). Статусы сверены КОДОМ и D-логом, не прозой; сплошные свипы — D39.80 (02.08.2026) → D39.101 → D39.139/146. **При конфликте с D-логом побеждает D-лог.** Правила: новую V-секцию владельца разбирает сюда оркестратор при первом касании; статус правится при лендинге пака, который его меняет; требование без носителя не оставлять. +> Единый список требований владельца к продукту. Источники: `../START_PROMT.MD` (ЖИВОЙ бриф, идеи V0–**V6**) + владельческие находки H6–H18 (`architecture/09-target-architecture.md` §3). Статусы сверены КОДОМ и D-логом, не прозой; последний сплошной свип — D39.139/146. **При конфликте с D-логом побеждает D-лог.** Правила: новую V-секцию владельца разбирает сюда оркестратор при первом касании; статус правится при лендинге пака, который его меняет; требование без носителя не оставлять. > > Статусы: ✅ построено · 🔶 частично · ⭕ не построено · ❌ снято (отменено владельцем ИЛИ закрыто отрицательным замером — с D-ссылкой) · 🔒 открытый вопрос владельца. @@ -8,7 +8,7 @@ | ID | Требование (источник) | Статус | Носитель / доказательство | |---|---|---|---| -| ПТ-1 | Издательское художественное качество, победить translationese (V0 гл. цель; канон §1) | 🔶 | пайплайн draft→терминолог→editor→гейты→судья построен, адресная эскалация дорогой моделью есть (`pipeline/escalation.go`); качество добирается курсом «добор идеала» (D39.62/67, бэклог 24·65; 16 — непрогнанная edit-волна того же курса). Выводы-п.2 брифа (редкий узкий вызов за смыслами вне книги) — поглощён этим курсом, отдельный механизм не строится без замера | +| ПТ-1 | Издательское художественное качество, победить translationese (V0 гл. цель; канон §1) | 🔶 | пайплайн draft→терминолог→editor→гейты→судья построен, адресная эскалация дорогой моделью есть (`pipeline/escalation.go`); качество добирается курсом «добор идеала» (D39.62/67, бэклог 24·65·16). Выводы-п.2 брифа (редкий узкий вызов за смыслами вне книги) — поглощён этим курсом, отдельный механизм не строится без замера | | ПТ-2 | **ЛЮБЫЕ пары языков, в любую сторону** — движок общий, пара = ДАННЫЕ (канон §2); «бэкенд только под русский» = объявленная антицель. Названные в брифе zh/en/ru/ja (V0-п.11; V4-п.5: в zh→en русский не участвует) — первые, а не полный список: продукт обязан поддержать и языки, которых в репозитории ещё нет (слово владельца 23.08) | 🔶 | построено только →ru: zh→ru боевая; ja→ru безопасна без правки Go, en→ru — нет (карта D39.60); не-ru target = антицель §0.1 в 09; носители: строки 81 (ja-преп) · 35 (не-CJK майнер) · 34 | | ПТ-3 | Книга ЦЕЛИКОМ (эталон 7,78 млн симв., ~2284 раздела) | 🔶 | гоняли ≤10 глав; волны/потолки/ETA на сотнях глав = строка 54 (МАСШТАБ) | | ПТ-4 | Референсы: предыдущие части серии / чужой перевод как контекст (V0-п.13–14) | 🔶 | серийный шаринг банка = строка 48а; импорт «оригинал+чужой перевод» = 48б (юр-сторона — 67) | @@ -21,7 +21,7 @@ | ID | Требование (источник) | Статус | Носитель / доказательство | |---|---|---|---| | ПТ-8 | Банк памяти на всю книгу, «крайне точный» (V0-п.7–8; Выводы-п.1) | ✅ | D39.69/75/77/78; recall банка 0.918/0.980 на холодном прогоне (D39.58). Смежный остаток H6 (running-summary): carryover закрыт замером (D39.7/8), проза-суммарайзер закрыт (D39.69), нарратив-состояние = строка 80 (гейт пилота Ф2.5) | -| ПТ-9 | Глоссарий автосборкой: модель переводит термины с контекстом/жанром (V4-п.4, H15) | ✅ | терминолог пака-20 (D39.41–53), KWIC-контексты, подписной цикл. **Вход владельца 02.08 (D39.89):** банк = центральная ценность, арбитраж перевода термов должен быть консилиумом со скорами уверенности, но не ломать связность системы термов ⇒ качество МЕХАНИЗМА проверено полигоном (research/24, принято D39.102): консилиум закрыт КЛАССОМ (равноправный совет · кросс-модельные веса · self-consistency · селекция не окупаются), остаток строки 5 (рецензент спорных кластеров) гейчен ре-пробой 74; статус ПТ-9 «построено» не меняется | +| ПТ-9 | Глоссарий автосборкой: модель переводит термины с контекстом/жанром (V4-п.4, H15) | ✅ | терминолог пака-20 (D39.41–53), KWIC-контексты, подписной цикл. **Вход владельца 02.08 (D39.89):** банк = центральная ценность, арбитраж перевода термов должен быть консилиумом со скорами уверенности, но не ломать связность системы термов ⇒ качество МЕХАНИЗМА проверено полигоном (research/24, принято D39.102): консилиум закрыт КЛАССОМ (равноправный совет · кросс-модельные веса · self-consistency · селекция не окупаются), остаток строки 5 (рецензент спорных кластеров) гейчен ре-пробой 74 | | ПТ-10 | Веб-фетч для терминов без культурного контекста (V0-п.16, V4-п.4) | ⭕ | гейт action-security = строка 70 (Ф3); до него — сид/бриф | | ПТ-11 | Голоса персонажей консистентны на книгу (V1-п.2; канон §1) | 🔶 | схема голосов построена (пак-19, D39.55/56); оси не подписаны — замер добора (строки 24 · 13б) | @@ -29,7 +29,7 @@ | ID | Требование (источник) | Статус | Носитель / доказательство | |---|---|---|---| -| ПТ-12 | Низкий COGS: дешёвые модели + адресные дорогие вызовы (V0-п.3/12; канон §5) | ✅ | ~$0.85/ранобэ (D30.4); ре-проба исполнена и строка 74 закрыта (замер D39.86/91, закрытие D39.95); пере-калибровка цены — при следующем платном прогоне | +| ПТ-12 | Низкий COGS: дешёвые модели + адресные дорогие вызовы (V0-п.3/12; канон §5) | ✅ | ~$0.85/ранобэ (D30.4); ре-проба исполнена и строка 74 закрыта (замер D39.86/91, закрытие D39.95); статус пере-калибровки цены — `STACK.md` §Примечания·Цена | | ПТ-13 | Телеметрия токенов/стоимости с первого вызова, БД (V0-п.25/31) | ✅ | SQLite `request_log`/леджер/смета; ⚠ леджер = нижняя граница (строка 78) | | ПТ-14 | Потолки бюджета и явное согласие на пере-оплату (канон §5) | 🔶 | reserve/settle и потолки ✅ (траты защищены). ⚠ **Статус понижен с ✅ приёмкой №18 (D39.149): само ЧИСЛО согласия неполно и приблизительно** — пере-прайс по текущей таблице цен исполнен (строка 181 закрыта), но: деньги банковых ролей в число не входят вовсе (194) · при смене модели стадии считается цена ОТСТАВЛЕННОЙ модели (решено 17.08: прайсить по текущей + округлять вверх и называть оговорку — D39.150) · принадлежность вызова поколению ВЫВОДИТСЯ, а не хранится (195). Щель терминолога = строка 38 | @@ -47,21 +47,21 @@ | ПТ-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 [--format epub,txt] [--out path] [--partial]`, пакет `backend/internal/bookfile` (только stdlib), шесть состояний честности (pending·withheld·incomplete·ghost·stale; **drift — отчётом, НЕ дырой файла**), отказ `book_incomplete` = exit 16, пути в `StatusArtifacts.book_files`, `tm-export-v1` расширен аддитивно, читательские слова — данные `configs/langpacks/<цель>/reader.txt`. **НЕ построена дверь платформы** (`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-export-v1` — в теле ноты. **НЕ построена дверь платформы** (`createExport`/`getExport`) — очередь №20 п.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; ⚠ версию канона брать ФАЙЛОМ, не этой ячейкой — она протухала пять раз подряд: `grep '^ version:' docs/architecture/14-api-contract/openapi.yaml`. Каждый минор ратифицирован своей D-нотой, содержание — грепом по реестру нот. Открытыми по контракту остаются хвост строки **203** и строка **241** — самопротиворечие канона на дочитанной книге. Зеркало ФРОНТА ратифицированно отстаёт — D39.135, синк при разморозке); платформа построена до читающей поверхности и денежной двери (паки P0…P12 — реестр нот; ⚠ КВОТ нет ни строки кода, и по D39.176 п.1 не будет — продуктовых квот нет, фри-тир-лимиты не проектируются; ретеншен/свип остаются инженерной гигиеной); фронт — S0–S4 приняты, **зона ЗАМОРОЖЕНА** (D39.136 п.2 + D39.147: сначала движок и платформа до «работает и отдаёт результат», фронт накручивается на готовую функциональность) | +| ПТ-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) | | ПТ-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 в `Progress` снята батчем 0.3.0 (D39.142/143, анти-утечка-греп чист); машинный ГЕЙТ на утечку — фронту при разморозке (пинг 16.08). Полоса прогресса — ОДНА монотонная доля на всю работу прогона через обе волны, считает СЕРВЕР, плюс подпись «что делается сейчас» (`Progress.stage`, ВТОРОЕ и последнее исключение границы — D39.163, словарь ОТКРЫТ, клиент рисует незнакомое нейтрально); остаток владельца 20.08 исполнен, D39.162/D39.163. ⚠ **Остаток, который НЕ закрылся и назван честно:** платформа продаёт ГЛАВЫ, а движку передаёт только денежный потолок — единица продажи не равна единице остановки (`PD-410`, архитектурный стоп; направление лечения — D39.165 §1). И полоса ПЕРЕ-ПРОХОДА гранулярности не имеет вовсе: движок анонсирует работу один раз за жизнь книги, поэтому она объявлена «одной неделимой единицей работы» (D39.166), а не выведена | +| ПТ-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` на проводе) | -| ПТ-36 | Интерфейс МУЛЬТИЯЗЫЧНЫЙ, русский не хардкодится в разметке (слово владельца 10.08; язык интерфейса — отдельная ось от языков перевода). ⚠ До 10.08 требование в реестре отсутствовало — пропуск поймал владелец (D39.127 п.2г) | 🔶 | ПОСТРОЕНО 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 зоны фронта) | +| ПТ-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 зоны фронта) | ## Качество процесса и самоулучшение @@ -79,9 +79,8 @@ ## Архитектура пайплайна — идеи V6 (бриф владельца 18.08.2026) -> ⚠ **Разобрано 23.08 (№19).** Статусы поставлены по КОДУ, а не по докам. V6 предлагает переделку -> пайплайна; часть его пунктов уже наполовину построена, часть не построена вовсе, и один -> измеримо оспорен замером — это названо в строках, а не сглажено. +> ⚠ **Разобрано 23.08 (№19).** V6 предлагает переделку пайплайна; статусы ниже поставлены по КОДУ, +> а не по докам. | ID | Требование (источник) | Статус | Носитель / доказательство | |---|---|---|---|