Take the order about what the bank is made of into the tree: the deterministic miner adds no surface of its own, and the provenance that shows it is already written beside the run

This commit is contained in:
heaven 2026-09-12 00:45:18 +03:00
parent fdc66bc50a
commit da89177600

View file

@ -0,0 +1,263 @@
# Бэкенд-пак: ИЗ ЧЕГО СДЕЛАН БАНК — и почему его состав нельзя ни измерить, ни повторить
> Выдан оркестратором №23 (сессия `textmachine-11`). Пак **$0** — платных вызовов в нём нет.
> Предмет куплен двумя платными прогонами; разбор состава банка сделан старшим коллегой по коду.
## 1. Какая проблема и что решит твой результат
Приоритет №1 владельца — **консистентный перевод длинной книги**. Его несёт банк памяти. И вот что мы
узнали о банке двумя прогонами одной и той же книги:
**Состав банка НЕ ПОВТОРЯЕТСЯ.** Побайтно один исходник, тождественный покупающий конфиг (sha
`pipeline-c1.yaml` совпал), одни и те же шесть чанков — предложений банка **A 98 · B 93 · общих 74,
Жаккар 0.63**. Расходится и состав, и ГРАНУЛЯРНОСТЬ ключа: один прогон предлагает `丙等资质` ·
`族长家老` · `舅父舅母`, другой — их составляющие. `舅父舅母` встречается в срезе **14 раз**, есть в
банке A и отсутствует в B.
⛔ **А ГДЕ ИМЕННО он не повторяется — теперь ИЗМЕРЕНО, и это главный результат двух платных прогонов:**
пересечение детерминированного и стохастического каналов (`both`) даёт **4 поверхности, Жаккар 1.00 —
идеально воспроизводимо**; банкнотный канал даёт 65 и 62 при Жаккаре **0.63**; а строк, предложенных
ТОЛЬКО детерминированным майнером, **НОЛЬ в обоих прогонах**. ⇒ **детерминизм не сломан — его 6 %, а
уникальный вклад майнера пуст.** ⚠ На СТРОКЕ банка этот провенанс теряется (все 69 и 66 несут
`source = "mined"`), и живёт он только в сайдкаре стопа.
**А собирается банк из ТРЁХ источников, и два из них стохастические** (прочитано старшим коллегой по
коду, никем прежде): детерминированный WHICH-майнинг по исходнику против контраста · **банкноты,
собранные ЧЕРНОВЫМИ волнами** (выход модели при `temperature > 0`) · **LLM-пасс терминолога**
(консолидация, классификация, род) — и именно он делает гранулярность.
**Твой результат решает вот что: сегодня нельзя ответить на вопрос «какая доля банка воспроизводима», и
поэтому нельзя ни починить недетерминизм, ни осознанно его принять.**
⛔ **И сразу — чего этот пак НЕ делает, чтобы ты не построила лишнего:**
- **НЕ запирает состав банка в снапшот.** Воспроизводимость там, где она нужна, УЖЕ построена:
`memory_version` входит в снапшот редакторской волны, резюм того же прогона банк не двигает. А
популяцию ПРЕДЛОЖЕНИЙ свежего прогона подписывает человек — ратифицировано владельцем (`D39.144`:
«черновик и черновой банк появляются вместе → один ОК всему банку»). **Запереть предложение = отменить
майнинг.**
- **НЕ строит второй путь кандидата в банк.** Он напрашивается — центральный терм книги `族`
(**29 вхождений**) не попал в банк НИ В ОДНОМ прогоне, и «род ↔ клан» есть крупнейшая находка вычитки.
Но ПОЧЕМУ он выпал — **не установлено**, и у гипотезы есть конкурент с носителем (см. §4.2).
- **НЕ трогает деньги и усилие моделей.** Это отдельный предмет, и он упирается в платный замер.
## 2. Зона записи и git
- Зона — **`backend/`**, и только она.
- **Ты не коммитишь.** Готовое дерево передаёшь мне, я лендлю. `git add -A` запрещён каноном.
- Свою секцию итогов пиши в `docs/PROGRESS.md`. Чужие незакоммиченные файлы в дереве не трогай.
- ⚠ **`/tmp` на этой машине занят на 9697 %** (tmpfs, 5.9 ГБ). Забитый tmpfs маскируется под сломанную
сборку. Уводи `TMPDIR`/`GOTMPDIR` на диск и печатай `df -h /tmp` рядом с итогом любого прогона.
## 3. Карта чтения — ЗАКОН, дальше только по её ссылкам
1. `CLAUDE.md` — целиком.
2. **Тела `D39.144`** (подпись банка целиком — слово владельца) и **`D39.252`** (акт прогона B) в
`docs/architecture/05-decisions-log.md`, плюс **эррата 12.09-а** в шапке того же файла.
3. **Ряды 439 и 440** в `docs/BACKLOG.md` — там оба замера с числами и границами.
4. `backend/internal/pipeline/mining.go` — сборка банка: греп `MineBankStats`, `buildBankCandidates`,
`runTerminologist`, `Source:`.
5. **Ряд 223** в `docs/BACKLOG.md` (потолок эмиссии майнера) — он несёт конкурирующую гипотезу §4.2.
Код-факты добывай сама; `file:line` — отправные точки. **Код первичен.**
## 4. Состав
### 4.1 ⛔ ПРОВЕНАНС УЖЕ ЕСТЬ, И Я ЕГО УЖЕ ПОСЧИТАЛ — читай это ПЕРВЫМ
Первая редакция этого промта заказывала «завести провенанс, чтобы стало что мерить». **Это было неверно:
провенанс пишется в сайдкар банк-стопа с самого начала** (`backend/internal/pipeline/mining.go`, греп
`Origin: string(c.Origin)`), и сайдкары ОБОИХ платных прогонов лежат на диске. Поймал старший коллега,
пере-снял я — **и вот числа, которые меняют предмет пака:**
| канал | прогон A | прогон B | Жаккар A↔B |
|---|---|---|---|
| `both` — предложено И майнером, И банкнотой | **4** | **4** | **1.00** |
| `banknote` — только стохастическим черновиком | **65** | **62** | **0.63** |
| `mined` — только детерминированным майнером | **0** | **0** | — |
⭐ **ЧИТАЙ ЭТО ТАК, И ЭТО ГЛАВНЫЙ РЕЗУЛЬТАТ ДВУХ ПЛАТНЫХ ПРОГОНОВ:**
1. **Детерминизм не сломан — его 6 %.** Пересечение двух каналов воспроизводится ИДЕАЛЬНО: те же четыре
поверхности, оба раза. Весь недетерминизм живёт в банкнотном канале.
2. ⛔ **Детерминированный майнер не даёт НИ ОДНОЙ уникальной поверхности.** Ноль строк `mined` в обоих
прогонах значит: всё, что он предложил, черновик предложил и так. **Его уникальный вклад пуст.**
3. ⇒ **94 % банка книги — стохастический выход модели.**
**ЧТО ТЫ ДЕЛАЕШЬ ВМЕСТО «ЗАВЕСТИ ПРОВЕНАНС»:**
**(а) ⛔ ОТВЕЧАЕШЬ, ПОЧЕМУ УНИКАЛЬНЫЙ ВКЛАД МАЙНЕРА ПУСТ.** Майнер ранжирует тысячи кандидатов, а в стоп
доходят четыре — и все четыре дублируют банкноту. Это либо (i) он предлагает мало, либо (ii) предлагает
много, но всё совпадает с банкнотой, либо (iii) его предложения отсекаются ПОСЛЕ ранжирования. **Напечатай
со знаменателем на каждой ступени:** сколько кандидатов ранжировано · сколько прошло контраст · сколько
вошло в окно эмиссии · сколько дошло до стопа · сколько из дошедших уникальны против банкноты. Материал
есть: обе базы и оба сайдкара (`books/gu-zhenren/door-to-file-b/` и `~/tm-coldrun-a/evidence/bankstop-paid/`).
**(б) ПЕРЕНОСИШЬ провенанс на СТРОКУ банка, но ⛔ НЕ ЧЕРЕЗ `Source`.** Словарь изобретать не надо — он
есть: `mined | banknote | both | alias` (`backend/internal/pipeline/terminology.go`, греп `Origin`).
⛔⛔ **И вот запрет, нарушение которого стоит ПЕРЕ-ОПЛАТЫ КНИГ:** `Source == "mined"` — денежный
дискриминатор в **21 не-тестовом месте**; на нём стоит `excludeMined`, который делит БАЗОВЫЙ и
ОБОГАЩЁННЫЙ банк (`backend/internal/membank/memory.go`, греп `excludeMined`), а базовый банк сворачивается
в черновой снапшот. **Новое ЗНАЧЕНИЕ в `Source` пройдёт мимо фильтра → попадёт в базовый банк → сдвинет
снапшот всех резюмируемых книг → пере-оплата.** ⇒ провенанс едет **НОВЫМ полем**, а `Source` не трогается
вовсе. **Пин обязателен:** значения `Source` не изменились И `excludeMined` исключает ровно то же
множество, что до пака.
⚠ Новое поле = миграция (схема уже на v18 — значит v19) и минор конверта банка; платформа сайдкар
разбирает аллоулистом и новое поле игнорирует — **назови это в отчёте, не молчи**.
### 4.2 ⛔ ДИАГНОЗ: ГДЕ ВЫПАЛ `族` — **и механизм контраста НЕ ТОТ, что я написал в первой редакции**
`族` встречается в срезе **29 раз**, `家族`**9**, и ни один не попал в банк ни в одном прогоне.
⛔ **МОЯ ПЕРВАЯ ФОРМУЛИРОВКА БЫЛА НЕВЕРНА, и, приняв её, ты «подтвердишь» гипотезу грепом и ошибёшься.**
Я написал: «словарь-контраст СОДЕРЖИТ `族` ⇒ отсечён». Контраст в майнере — **не список присутствия, а
ОТНОШЕНИЕ**: над-представленность в книге против общего китайского (`backend/internal/miner`, греп
`wordRel`, `charIndepRel`, `charOverRep`). Присутствие в словаре не отсекает ничего; отсекает **низкий
ratio при `FreqFloor`**.
**Три гипотезы, различай их ЗАМЕРОМ:**
- **(i) ОТНОШЕНИЕ.** Напечатай `wordRel`/`charOverRep` и РАНГ для `族` и `家族` — это и есть прибор.
- **(ii) ПОТОЛОК ЭМИССИИ** — ряд **223**: 2110 ранжированных → 442 годных → **117 в окне потолка 200**,
то есть **325 годных поверхностей невидимы постоянно**.
- **(iii) КОНСОЛИДАЦИЯ ТЕРМИНОЛОГА** — LLM-пасс мог схлопнуть терм в составной ключ или отбросить.
**ЛЕЧЕНИЕ НЕ СТРОИШЬ, и довод сильнее «второго предмета».** Ранг и окно живут в замороженном
откалиброванном конфиге майнера (`backend/internal/miner`, греп `FrozenConfig`, `miner-v1`), и его сдвиг
двигает майнинг-дельту → `memory_version` → снапшот редакторской волны КАЖДОЙ резюмируемой книги. Это
версионируемая правка с пере-оплатой, а не однострочник.
**Но если диагноз окажется (ii), принеси ПРЕДЛОЖЕНИЕ с проекцией в том же паке:** сколько поверхностей
и каких войдёт при окне X, что это сделает с `族`, какова цена снапшота. Это пишется из данных диагноза,
второго захода не стоит.
**И попутно проверь то, чего не знает никто:** версионирован ли САМ майнер — входит ли его версия в
снапшот. Если нет, это ещё одна дыра детерминизма, и она твоя находка, а не мой заказ.
### 4.3 `waves.workers` — **делай РОВНО так**
Прогон B шёл **строго последовательно**: сумма латентностей 18.5 мин при стенных 19.3, перекрытий ноль.
Причина — `Waves.Workers` **по умолчанию 1** (`backend/internal/config/pipeline.go`, греп
`Wave workers default to 1`), и в боевом конфиге ключ **не задан вовсе**. Комментарий у дефолта называет
это «wave-structured but sequential, deterministic run» — **но ратификации у этого нет**, а исполнитель
СТРОИЛСЯ под N: `waverun.go` (греп `result ORDER is deterministic`) прямо говорит, что порядок
результата детерминирован по индексу элемента **независимо от порядка завершения**.
**Что делаешь:** выставляешь `waves.workers` в боевых конфигах — **но число берёшь НЕ с потолка.**
`max_concurrency` задан у **ОДНОЙ модели из десяти** (`models.yaml`, греп `MaxConcurrency`; ноль =
без ограничений), и для deepseek его НЕТ. **Кап берётся из вендорской доки** — норма квирков «идём в
официальную доку, не гадаем», — а не назначается. Пин над боевыми конфигами: **`workers ≤ max_concurrency`
модели стадии**; нет капа у модели — нет и числа воркеров больше единицы, и это пинится.
**И ПИНИШЬ БАЙТ-ИДЕНТИЧНОСТЬ — но у неё ПЯТЬ способов выродиться, а не один.** Я назвал только первый;
остальные четыре дал старший коллега, и каждый делает пин пустым:
1. **Один элемент волне** — единица параллелится сама с собой.
2. **Порядок завершения не разошёлся** — четыре воркера над МГНОВЕННЫМ фейком заканчивают в порядке
старта. Фикстура обязана ЗАСТАВИТЬ порядок разойтись (фейк с латентностью, обратной индексу) и
**напечатать фактический порядок завершения**.
3. ⛔ **Не тот артефакт.** `request_log`, `events_outbox.seq`, `updated_at` расходятся ЗАКОННО при
конкуренции. Пин обязан НАЗВАТЬ множество сравниваемого: чекпойнты по `request_hash` · `chunk_status`
(диспозиция и финальный хеш) · экспорт побайтно · свёртка банка · `retrieval_state` · снапшот-ид — с
нормализацией сортировкой, по прецеденту `backend/internal/pipeline/golden_test.go` (греп там же).
⚠ И «снапшот идентичен» — тривиально: он считается из конфига ДО волны. Несущее — чекпойнты и финалы.
4. **Одна волна вместо двух** — единицы редактора многочанковые, и разойтись может именно там.
5. ⛔ **Пин не мутирован.** Посади зависимость от порядка (общий счётчик в колбэке либо свёртку банкнот по
порядку завершения) и покажи, что пин краснеет **ТЕКСТОМ про предмет**. Иначе он утверждает молчание.
**Гонки под `workers > 1` у нас проверяются** — 14 тестов задают больше одного воркера, 11 из них
четыре, пакет под `-race` чист (пере-снято мною 12.09). Но **ни один живой прогон с N > 1 не шёл**, и
это надо сказать в отчёте прямо.
### 4.4 ДЕНЕЖНАЯ ПОСЫЛКА, КОТОРАЯ ПЕРЕСТАЛА БЫТЬ ВЕРНОЙ — **делай РОВНО так**
`backend/configs/models.yaml`, блок `deepseek-v4-pro`: комментарий утверждает, что **«перебор бюджета
БЕСПЛАТЕН — резервация транзитна, списание идёт по фактическому usage»**. ⛔ **Это ложно с `D39.230`:**
оборванный вызов книжится **ПО ОЦЕНКЕ** (`backend/internal/pipeline/cutcall.go`, греп
`settleUSDForCutCall`), а оценка **пропорциональна `max_tokens`**. На этой посылке стоит решение «флор с
запасом, а не впритык» — и стоит теперь неверно.
**Что делаешь:** исправляешь текст посылки и **называешь в отчёте**, меняет ли это само решение о флоре
(пере-решать флор в этом паке НЕ надо — назови цену и отдай мне).
### 4.5 ПРОТУХШИЕ УТВЕРЖДЕНИЯ В КОДЕ — **реши сама, какие брать, и объяви**
Найдены старшим коллегой при разборе. **Твоя зона — только движковые:**
`config/pipeline.go` (греп `sequential, deterministic`) — против `waverun.go`; `reservegate.go` (греп
`THREE values`) — при четырёх константах, если ещё не чинено; `cutcall.go` (греп `the run was stopped`)
— на обрыве от падения соседа.
**Платформенные НЕ ТРОГАЙ** (`pgstore/credits.go`, `runner/runner.go`, `pgstore/runs.go`,
`ingest/events.go`) — их отнесу я. Назови в отчёте, какие движковые взяла и какие оставила с доводом.
## 5. Где этот пак мягкий — четыре места, назвал я, веер выбираешь ты
Мандат самопроверки — **исполнением**; субагенты разрешены явно. Адверсариальный проход по СВОЕЙ готовой
работе обязателен.
1. ⛔ **Провенанс, схлопывающий множественный источник в один ярлык, ХУЖЕ его отсутствия** — он выглядит
измерением. Кандидат, предложенный и майнером, и банкнотой, обязан быть отличим от однобокого.
2. ⛔ **Диагноз `族` легко получить НЕ ТОТ.** «Ноль после контраста» и «не смотрел контраст» выглядят
одинаково: у каждой ступени печатается ЗНАМЕНАТЕЛЬ. И спроси себя, на ЧЬИХ данных считаешь — банк A и
банк B разные, и ступень, где терм выпал, может отличаться между прогонами.
3. ⛔ **Пин байт-идентичности при 1 и 4 воркерах вырожден, если фикстура даёт ОДИН элемент волне.**
Одна единица параллелится сама с собой. Фикстура обязана дать волне столько элементов, чтобы порядок
завершения МОГ разойтись, и доказать это печатью.
4. ⛔ **Правка комментария — не правка механизма.** Если исправленная посылка §4.4 меняет чьё-то
решение, скажи ЧЬЁ; если не меняет — скажи, почему, и чем это предъявлено.
⚠ И общее, стоившее трёх смен подряд: **зелёная батарея плюс полный мутационный каталог сходимостью НЕ
являются.** Направленный второй читатель находил 6, 7, 9 и 13 дефектов при полной зелени.
## 6. Предметные оси ревью
Выбери 13 и назови какие. Мой приор: **провенанс под множественным источником** · **знаменатель на
каждой ступени диагноза** · **детерминизм под конкуренцией**.
## 7. Записка-план ДО работы
Перед первой правкой — записка в `docs/PROGRESS.md`: что меняешь, чем предъявишь, где ждёшь сопротивления.
## 8. Заявление = команда
Каждое число и каждая категорика — **с командой, которой получены**. Дифф `^func Test` — исполнением.
**Три нормы кодового пака:** сверь КАЖДЫЙ клейм с результатом инструмента ЭТОЙ сессии · последний
абзац отчёта оказался планом — сделай его СЕЙЧАС · в длинной сессии интервальная самоверификация
субагентом против ЯВНЫХ критериев (`D39.121`).
## 9. Эхо-протокол старта
**Порядок двух первых действий:** сперва свой блок в `/tmp/textmachine-channel`, потом эхо.
**Эхо** — ≤10 строк СВОИМИ словами: что поняла · что считаешь опасным · что считаешь неверным. Не
пересказ: дословный пересказ подтверждает канал, но не понимание, и ошибку промта повторяет вместе с ним.
**Адрес бери из файла канала** (блок `role=оркестратор`), сверившись с `ListAgents`.
## 10. Что НЕ удалось — обязательная секция отчёта
И вторая половина: **«где прибор слеп и я это знаю»** — что невидимо · почему не чинила · чем
закрывается. ⭐ Норма: **«в коде названо, в отчёте нет — значит для следующей смены НЕ названо».**
На прошлом паке прямой вопрос дал ПЯТЬ находок сверх отчёта, включая улику, существовавшую в одной
копии. Отвечай на него до того, как я спрошу.
## 11. Канал вопросов и право отказаться
Конфликт промта с кодом — **пинг мне, не интерпретация**. Право сказать «этого делать не надо» с
аргументом у тебя есть, и им пользовались: в двух паках подряд сессия была права, а не я.
**Тесты и гейты под зелень не подгонять.** Правка, вызванная ЗАКАЗАННОЙ сменой поведения, —
обслуживание, и протухший тест держать не нужно; но она **ОБЪЯВЛЯЕТСЯ**: что изменилось, какой тест это
описывал, куда уехала гарантия.
**И слово владельца 12.09, которое сильнее всякой осторожности:** «нам не нужно держать неправильно
работающую функциональность из-за техдолга, тестов каких-то старых». Замерила, что починка дорога, —
это ПЛАН, а не довод держать дефект.
## 12. Прямой канал
Механизм — `CLAUDE.md` §«Связь между сессиями». Впиши свой блок ПЕРВЫМ действием. Нужной роли нет ⇒
канала нет, и это нормальный случай: НЕ опрашивай сессии подряд.
### ⭐ Старший коллега — Fable 5. **Разрешён ОДИН на сессию (слово владельца)**
Поднимаешь **одного** агента на модели **`fable`** и держишь весь пак. Вопросы ДОСЫЛАЕШЬ ему, второго не
поднимаешь: ценность в накопленном контексте. Модель задавай ЯВНО. Он **советчик, а не источник истины**
его посылки проверяются деревом. ⭐ Для калибровки: в этом паке ровно он прочитал, как собирается банк
(чего не сделал никто), и снял два моих пункта из пяти как лечение симптома.
## 13. Критерий завершённости
У каждого пункта — исход (сделано · не делаю с доводом · пинг) · круги СОШЛИСЬ · **таблица мутаций
полная, выжившие названы, КАЖДАЯ новая запись помечена `battery`** · числа сняты ПОСЛЕ последней правки ·
`df -h /tmp` рядом с итогом гейта · всё живое в ДЕРЕВЕ, а не в письме · явное **«работа завершена,
править не планирую»**. Без последнего пак считается идущим.