textmachine/docs/BACKEND_CONSISTENCY_YOU_CAN_SHOW_SESSION_PROMPT.md

37 KiB
Raw Blame History

Промт: бэкенд-пак «КОНСИСТЕНТНОСТЬ, КОТОРУЮ МОЖНО ПРЕДЪЯВИТЬ»

1. Какая проблема и что решит твой результат

Приоритет №1 владельца — консистентные термины на всю книгу. Сегодня спросить у движка «выполнен ли он» нельзя, и это ощущалось как «меры нет». Мера есть, и она ЧАСТЬЮ уже на поверхности — вот замер.

ЖИВОЙ ПЛАТНЫЙ ПРОГОН 11.09, книга 蛊真人, 3 главы, база retrieval_state:

величина значение
показано неподписанных строк банка (n_unverified_shown) 84
из них модель последовала (n_unverified_followed) 66
разница 18
промахов перечислено поимённо в postcheck_detail 18
счётчик n_postcheck_miss 0при знаменателе 2 — подписанных термов в прогоне ровно два (方源, 古月山寨), и обе их формы отгружены

ИСПР. 11.09 — ЧИСЛО 18 БОЛЬШЕ НЕ ДЕЙСТВИТЕЛЬНО, настоящих СЕМЬ. Замер той же сессии: из восемнадцати одиннадцать ложные — банковская форма доехала до читателя в том же юните СКЛОНЁННОЙ, а SameStem её не признал (стеммер снимает ровно одно окончание; носитель — строка бэклога 419). Ниже читай «18» как «18 записей пост-проверки, из которых 7 настоящих».

Восемнадцать записей найдены и записаны в деталь поимённо; счётчик, который называется «промахи», говорит ноль, потому что промахом считается только ПОДПИСАННЫЙ термин (internal/membank/mempostcheck.go, греп Confirmed), а все восемнадцать — ambiguous. ⚠ Это ЗАМЫСЕЛ, а не баг: комментарий там же прямо говорит, что считать ambiguous промахом значило бы инвертировать контракт. И ноль без знаменателя прочитался бы как сокрытие восемнадцати — поэтому знаменатель стоит в таблице.

ИСПР. по опровергателю: «разница 8466» и «18 в детали» — ОДНО число, а не две улики. В коде Shown++/Followed++ и append(Unverified, …) стоят в одном цикле над одним предметом, поэтому Shown Followed ≡ len(Unverified) по построению. Не выдавай это за схождение двух приборов.

И главное ИСПР.: пара 84/66 УЖЕ ПЕЧАТАЕТСЯ штатным tmctl report — строка UNSIGNED BANK: terms=… · rows-checked=84 · model followed=66 (79%) (backend/cmd/tmctl/render.go:612), со знаменателем и процентом. Не доезжают ИМЕНА восемнадцати, и их держит ОДНА строка: render.go:491if rs.NPostcheckMiss == 0 { continue }. Значит заказ не «построй поверхность», а (а) провести имена мимо этого continue и (б) построить то, чего действительно нет — счёт по ОТГРУЖЕННОМУ тексту КНИГИ ЦЕЛИКОМ.

Что это значит по существу: 家老 доехал до читателя как «старейшины» без «рода», 舅父 стал «дядей», и движок это видел. Ручная сверка прогона по отгруженному файлу дала более широкую картину: движок сам называет ДВЕ популяции вопроса — spread ≥ 2 (9 термов из 69) и INVENTED(no draft proposed it) (11, из них 7 вне девятки), итого 16 из 69; исход — 9 доехали формой банка · 6 отданы НЕ банковской · 1 отдан двумя формами.

Твой результат: после пака у нас есть ОДИН прибор по ОТГРУЖЕННОМУ тексту, отвечающий на два вопроса приоритета №1 числом и главами, и запись, по которой можно отличить «банк не доехал» от «редактор его не послушал». Прибор, а не гейт: решение включать ли гейт владелец отложил, и этот пак его не трогает (§4.6).

2. Зона записи и git

Зона: backend/. Расхождения и итоги — своя секция «Бэкенд» в docs/PROGRESS.md (заведи СВОЙ подзаголовок и пиши только под ним; файл общий, чужой текст не трогать). Сессия НЕ коммитит — дерево передаёшь мне. Канон git — CLAUDE.md. .env не читать. Чужие зоны читать можно, править нельзя. books/ — ОТДЕЛЬНЫЙ репозиторий и НЕ твоя зона: досев данных сида туда не входит в пак (§4.5). ⚠ Что должно пережить рестарт — в РЕПОЗИТОРИЙ, а не в скретчпад. Правка ЗАКАЗА на лету доезжает только РЕЛЕЕМ: я пере-передаю её отдельным сообщением, ты эхо-подтверждаешь своими словами и выносишь отдельным пунктом отчёта.

3. Карта чтения — ЗАКОН, дальше только по её ссылкам

  1. CLAUDE.md — цели владельца и гардрейлы.
  2. docs/architecture/18-bank-ontology.md — РАТИФИЦИРОВАНА, обязательное пре-чтение перед всем, что трогает банк.
  3. Строки бэклога 406 · 407 · 417 · 419 (docs/BACKLOG.md, греп ^| N |) — предмет; и 408 только в части, названной §4.5.
  4. docs/research/34-memory-bank-quality-audit.mdчерез ревю-шапку (статус: ФАКТУРА; из 15 находок верификация отвергла 14, почти все за ЗАВЫШЕННЫЙ ВЕС; синтез написан после неё).
  5. docs/experiments/24-door-to-file.md §7 и §13 — что прогон измерил и где его прибор оказался слеп. И ВАЖНОЕ ПРО ДАННЫЕ (испр. по опровергателю): банк ПЕРЕ-КОНСОЛИДИРОВАН между 04:39 и 04:42, и артефакты расходятся. ~/tm-coldrun-a/evidence/bankstop-paid/…bank-stop.txt несёт INVENTED 11, а ~/tm-coldrun-a/stand/books/bk_ROEHZBD46ALFI43E/…bank-stop.txtINVENTED 14 (пере-считано мной обоими файлами). У двух термов формы РАЗНЫЕ: 凤雏 «Молодой Феникс» против «Юный Феникс», 老嬷嬷 «старая мамка» против «старая нянька» — и отгруженный текст согласен со ВТОРЫМ. ⇒ оракул §4.1 сверяется с ЗАМОРОЖЕННОЙ уликой (evidence/bankstop-paid/ + books/gu-zhenren/door-to-file/book.txt), а база из §5 — ДРУГАЯ ревизия банка. Расхождение по 凤雏 и 老嬷嬷 — ИЗВЕСТНОЕ, не находка. Почему банк изменился, не установлено (corrections.json несёт только два approve).

Ратифицированное и замеренное — в теле промта, не искать:

  • D39.104 — закон банка: строка на проводе есть закон для КАЖДОЙ роли и КАЖДОЙ строки независимо от статуса. ⚠ И здесь живёт открытое противоречие, которое пак НЕ решает: пост-проверка считает отказом только ПОДПИСАННЫЙ термин. Вопрос «обязателен ли закон для неподписанного» стоит у владельца (research/34 §4 п.3). ⇒ пак печатает обе популяции РАЗДЕЛЬНО и не выбирает сторону.
  • D39.247 — акт холодного прогона: числа выше, и там же названо, что прибор полигона трижды давал ложный «0», не видя склонённых форм.
  • Ревью-вопрос проекта (CLAUDE.md §Цели п.2): «заработает ли пара, которой в репо ещё НЕТ, без правки Go?» У каждого твоего решения обязан быть на него ответ.
  • Число называет ДЕРЕВО и ПОПУЛЯЦИЮ · рядом с нулём ПЕЧАТАЕТСЯ контрольная величина · мутация засчитывается по ТЕКСТУ падения.

4. Состав и разметка свободы

4.1 ПРИБОР ПО ОТГРУЖЕННОМУ ТЕКСТУцентральное; форму решаешь сам, два счёта ЗАДАНЫ

Приоритет №1 — это ДВА инварианта, и мерить надо оба по финальному тексту, а не по черновикам:

  • I1 — одна форма на термин по всей книге. Сколько канонических терминов отданы более чем одной формой и в каких главах.
  • I2 — где у банка есть форма, отгружена ОНА (закон D39.104). Сколько терминов отданы формой, которой в банке нет.

Не пиши матчинг заново — переиспользуй банковский. У банка уже есть ключи, алиасы, стеммер и фолд вариантов (⚠ путь испр. по опровергателю: internal/terminology/terminology.go:245, foldVariants; в internal/pipeline/ такого файла НЕТ; плюс internal/membank/mempostcheck.go, греп declinedFormPresent). ⚠ И ещё довод за переиспользование, замеренный опровергателем: оракул воспроизводится только РЕГИСТРОНЕЗАВИСИМЫМ счётом — регистрозависимо «горная крепость Гуюэ» даёт 3 вместо 5. Движок это уже закрыл (internal/text/norm.go, греп NormalizeTargetForm); свой матчер на этом споткнётся. Прибор полигона писался регуляркой «слово с заглавной» и трижды дал ложный ноль, не увидев склонённых строчных форм. Это и есть довод: то, чего не хватало полигону, у движка построено.

ЗНАМЕНАТЕЛИ ПЕЧАТАЮТСЯ, и «не найден» — категория, а не ноль: сколько строк банка судимо · у скольких ключ не сработал в ИСХОДНИКЕ · у скольких dst пуст · сколько вхождений найдено. Прибор, который не смотрит, и прибор, который посмотрел и не нашёл, обязаны быть различимы в выводе.

ОРАКУЛ ЗАДАН, и он обязателен: ручная таблица прогона A (docs/experiments/24-door-to-file.md §7) — 9 доехали формой банка · 6 не банковской · 1 двумя, поимённо, с числами вхождений (高脚吊楼 — «свайный дом» ×4 при «дом на сваях» ×0; 开窍大典 ×9 плюс развёрнутая ×1; 古月山寨 5 из 5). Твой прибор обязан воспроизвести эту таблицу на тех же данных. Расхождение В ЛЮБУЮ сторону — находка, а не подгонка.

Где живёт результат — реши сам, аргументируй: отчёт сборки, строка «глава → расхождения», отдельная команда. Но мерило «попасть на поверхность» для пары 84/66 УЖЕ ВЫПОЛНЕНО (§1): не строй третью поверхность рядом с двумя существующими. Недостающего ровно два: имена неподписанных промахов (сегодня их держит render.go:491) и счёт по отгруженному тексту книги целиком — вот его действительно нет.

4.2 ЗАПИСЬ ВЫБОРА РЕДАКТОРСКОЙ ВОЛНЫ — делай РОВНО так в границе, свободен внутри

Сегодня запись инъекции существует наполовину, и это надо знать до первой строки кода: runEditUnit делает свежий Select по обогащённому банку и сливает результат на строку ЧЕРНОВИКА лидер-чанка (internal/pipeline/waverun.go, греп mergeUnitRetrievalState): промахи и «показано/последовано» пишутся, а injected_ids / n_exact_hits / n_evicted остаются черновыми, и вытеснения редакторской волны не записываются НИКУДА — это сказано в коде прямым текстом (internal/pipeline/chunkrun.go, греп evict). Ключ таблицы — (book_id, chapter, chunk_idx), оси волны нет, и слияние обнуляет черновой пост-чек.

Задача: сделать выбор редакторской волны отдельно наблюдаемым. Границы:

  • PK существующей таблицы НЕ менять.Основание испр.: оно НЕ в «опасности миграции» — соседняя таблица бампает схему ровно так же. Настоящий разделитель: смена PK ПЕРЕПИСЫВАЕТ существующие строки, новая таблица — нет. Форма, которую я считаю правильной, — соседняя аддитивная таблица с осью волны; видишь лучшую — аргументируй.
  • ЦЕНА, которой я не знал: ЛЮБАЯ новая миграция бампает схему 16 → 17, после чего OpenReadOnly ОТКАЗЫВАЕТ базе прогона A (internal/store/store.go, греп SchemaMismatchError; в базе прогона schema_version = 16), а на ней живут все $0-приборы пака. ⇒ пробы и прибор гоняй на КОПИИ базы, оригинал mode=ro и не трогать; SchemaMismatchError{Found:16, Expected:17} после §4.2 — это ВЕРСИЯ, а не поломка.
  • «Слить сильнее» — запрещено: слияние уже затирает черновой пост-чек, и усиление затрёт больше.
  • ⚠ Это предусловие АТРИБУЦИИ («не доехал» против «не послушал»), а НЕ предусловие измерения: §4.1 меряется и без него. Порядок в паке — §4.1 первым.

4.3 ДЕШЁВАЯ ПОЛОВИНА ВОПРОСА ПОСТ-ПРОВЕРКИ — делай РОВНО так

Пост-проверка спрашивает «есть ли принятая форма ГДЕ-НИБУДЬ в куске» вместо «какой формой отрендерён термин НА МЕСТЕ срабатывания», и про конкурирующую форму рядом не спрашивает никогда (ряд 407). Дешёвая половина: алиас-ключ сверяется с СОБСТВЕННОЙ канонной формой записи. Замерено на копии: ряд 方源 с алиасом 古月方源 пропускает выход «Гу Юэ Фан Юань» при подписанном каноне 古月 → Гуюэ. Дорогая половина — детектор значения по исходнику (ряд 286) — ВНЕ пака. ⚠ И у экземпляра ДВА корня: второй — подавление вложенного ряда равнотрастовым длиннейшим матчем (internal/membank/memory.go, греп suppressContained), и оно МОЛЧИТ. Смена вопроса его не закрывает; ИСПР. — цена пункта названа замером: в прогоне A n_trust_gated_suppress = 0 на всех шести строках (подавитель не срабатывал ни разу), алиасов в базе 0 при 69 рядах, ряда 古月 нет вовсе. ⇒ пример выше на данных прогона A НЕ ВОСПРОИЗВОДИТСЯ — демонстрировать придётся на синтетической фикстуре, и это законно. Знай до того, как потратишь час на поиск носителя.

4.4 ПУНКТ ОТОЗВАН 11.09 — РАСХОЖДЕНИЯ, РАДИ КОТОРОГО ОН ПИСАЛСЯ, НЕ СУЩЕСТВУЕТ

Пункт требовал не заводить «третьего определения spread», потому что «два уже расходятся». Расхождения нет — это была моя ошибка чтения, и поймала её ты же. Движок печатает ДВЕ РАЗНЫЕ величины В ОДНОЙ СТРОКЕ: spread=%d conventions=%d (backend/internal/pipeline/mining.go:542), где Spread() считает Σ сырых форм, а Conventions() = len(Variants) — свёрнутые классы; комментарий у определения (backend/internal/terminology/terminology.go:684-685) говорит это прямым текстом. На 69 термах прогона противоречий ноль: 60×(1,1) · 6×(2,2) · 2×(3,3) · 1×(4,3). Ряд 418 удалён, разбор — эррата в шапке журнала решений.

Что остаётся в силе и почему: твой счёт всё равно идёт тем же foldVariants, что и существующий, и пин равенства ты вешаешь — но не «чтобы не завести третье число», а чтобы объяснение держалось прибором, а не текстом. Пин — на ЗАМОРОЖЕННЫЙ артефакт (~/tm-coldrun-a/evidence/bankstop-paid/).

4.5 ЛИНТ СИДА — только Go-половина; данные НЕ трогать

Точность глоссарного класса чекера — 0.067 (одно верное срабатывание на 14 ложных, n=258; books/gu-zhenren/labels/metrics.json, ключ k6), и ложные сконцентрированы: ×6, 蛊虫 ×4. ИСПР. — МОЙ МОТИВ ОПРОВЕРГНУТ ДАННЫМИ, и это надо знать до работы. Я написал «причина в ДАННЫХ: пустые формы и односимвольный ключ». Опровергатель просканировал все три сид-файла за размеченными прогонами: термов с ПУСТЫМИ decl.forms0, без decl0 (49 · 58 · 57 термов). 蛊虫 — ДВУХсимвольный, то есть порог minKeyLenHan = 2 к нему не относится, и у него 45 склонённых форм; уже стоит с allow_short: false и авторской пометкой «не стреляет», и прикрыт вторым рубежом. ⇒ причина ложных срабатываний НЕ УСТАНОВЛЕНА, и заказ ниже — гипотеза, а не следствие. Досев данных — НЕ твой пак (books/ — другой репозиторий и другая зона). Твоё — правила SeedLint, и они СОВЕЩАТЕЛЬНЫЕ, а не обвиняющие: пустые формы у многословного/глагольного термина · односимвольный ханьский ключ без allow_short. Формулировка правила — «не выстрелит → подтверди умысел», а не «ошибка». У каждого — фикстура, где оно ОБЯЗАНО сработать. ⚠ Предупреждение: существующая фикстура TestSeedLintCleanPasses несёт 方源 → Фан Юань — двусловный dst без decl; при наивной формулировке «многословный» она ПОКРАСНЕЕТ. Это обслуживание по заказанной смене поведения — ОБЪЯВИ его, а не подгоняй тест. И раз причина не установлена — первым делом назови, ЧТО на самом деле даёт 14 ложных. Это дешевле любого правила: данные размечены, fp_ids в metrics.json перечисляет их поимённо. ⚠ SeedLint зовётся только из tmctl seed-lint и на путь translate не выходит — ужесточение существующие книги не ломает; проверь это утверждение сам прежде, чем на него опереться. Пере-замер точности 0.067 — работа ПОЛИГОНА после досева, не твоя.

4.6 ЧЕГО В ПАКЕ НЕТне делай, и это объявленные сужения

  • Флип gates.glossary.postcheck_gate — владелец отложил его до замера ложных срабатываний (D39.205), а 0.067 и есть их источник. Гейт не включать, значения по умолчанию не трогать.
  • Ряд 409 целиком (выбор черновой волны по БАЗОВОМУ банку с исключением намайненного; потеря липкости между правочными единицами при 86 % многоединичных глав). Обе правки двигают провод/снапшот ⇒ пере-покупка книги; инцидентов ноль наблюдений, замерена только экспозиция. Прибор из §4.1 — именно то, чем это мерить, поэтому сперва прибор.
  • Актуатор точечной перегенерации (ряд 296).
  • Решение «считать ли законом неподписанный термин» — вопрос владельца, см. §3.
  • Всё должно быть $0 и СНАПШОТ-НЕЙТРАЛЬНО — но ⚠ ИСПР.: «докажи байт-равенством снапшотов» было ВЫРОЖДЕННЫМ требованием. В полезной нагрузке снапшота банковых строк НЕТ вовсе (internal/pipeline/snapshot.go, греп snapshotPayload) — прибор в отчёте их физически не двинет, и «доказательство» было бы пустой процедурой. Настоящий рычаг назван опровергателем: в снапшот входит PostcheckGate — то есть флип гейта И ЕСТЬ пере-покупка книги, и это механическое основание запрета выше, которого у меня не было.
  • И ИСПР. про Select: запрещено МЕНЯТЬ ПОВЕДЕНИЕ Select и рендереров. Звать Select из офлайн-прибора внутри internal/membankНОРМА, так делают существующие пины (греп postcheckdenominator_test). Прежняя формулировка «не в Select» читалась как «не звать», и это отрезало единственный легальный путь: PickedEntry несёт неэкспортированное поле, и накормить Bank.Postcheck извне пакета нечем.

5. Мандат самопроверки ИСПОЛНЕНИЕМ — «перечитал сам» не считается

Механизм НАЗВАН: make battery целиком (не подмножество -run) · make mutations с посадками на СВОИ новые пины · выброшенные пробы на данных прогона A (база ~/tm-coldrun-a/stand/books/bk_ROEHZBD46ALFI43E/project.db, читать mode=ro, НЕ править). Субагентов спавнить РАЗРЕШЕНО и требуется, модель задавать ЯВНО. Интервальная самопроверка субагентом примерно на середине против явных критериев §4.

Где у ЭТОГО пака мягко — четыре места; адверсариальный проход веди по ним:

  1. ПРИБОР, КОТОРЫЙ НЕ СМОТРИТ. Три «нуля» подряд у полигона были артефактом невидения, и последний нашёл не он. Твой прибор обязан печатать знаменатели (§4.1) и воспроизвести ОРАКУЛ; «0 расхождений» без знаменателя — не результат, а отсутствие вопроса.
  2. ПОРЯДОК СЛОВ И ПАДЕЖИ. Сверка идёт окном в порядке слов со стеммером: «горная крепость Гуюэ» против «Гуюэ, горная крепость» и трёхсловные формы дадут и ложные промахи, и ложные попадания. Единственный оракул — размеченный корпус с точностью 0.067, и его нельзя подгонять: печатай precision ДО и ПОСЛЕ на ОДНИХ И ТЕХ ЖЕ метках.
  3. СЛИЯНИЕ НА СТРОКУ ЧЕРНОВИКА. Любая «маленькая» правка слияния рискует затереть ещё что-то черновое — оно уже затирает пост-чек. Посадка, ломающая запись редакторского выбора, обязана краснеть ТЕКСТОМ про незаписанную инъекцию редакторской волны, а не про соседнее поле.
  4. ТРЕТЬЕ ОПРЕДЕЛЕНИЕ spread (§4.4): пин равенства обязателен, иначе пак добавит число к двум расходящимся.

Плюс общее для кодового пака: пин на УСЛОВНОЕ сообщение обязан иметь фикстуру, где оно ОБЯЗАНО прозвучать · перед отчётом сверь каждый клейм с результатом инструмента ЭТОЙ сессии · дифф ^func Test — исполнением, не памятью · править или удалять тест ради зелени НЕДОПУСТИМО; правка от ЗАКАЗАННОЙ смены поведения — обслуживание, и она ОБЪЯВЛЯЕТСЯ.

Слово владельца, оно же отдельная ось приёмки: никаких велосипедов, воркэраундов и хаков ВОКРУГ проблемы. Нужно логически правильное решение задачи. Для этого пака оно звучит буквально: не строй второй матчер рядом с банковским — переиспользуй построенное, а где форма не тянет, скажи это и назови цену.

6. Предметные оси ревью

Код — тест утверждает не то, что думает: часы как способ синхронизации там, где предмет НЕ время; ассерт по подстроке в буфере, куда пишет кто-то ещё. Обе формы дают тихо-зелёное, а оно дороже ложно-красного. И вторая ось, купленная сегодня: комментарий, описывающий ГАРАНТИЮ, обязан иметь посадку, которая эту гарантию ломает — иначе он документирует замысел, а не код. Замеры — пере-вывод чисел из СЫРЬЯ, а не из чужой сводки; вывод на агрегате до вскрытия единиц запрещён. ⚠ Ты вправе заменить ось с аргументом — это право канона, и оно здесь действует.

7. Записка-план ДО работы

До первой строки кода пришли мне ≤15 строк: что берёшь по каждому пункту §4 · где ждёшь сопротивления · что считаешь спорным в самом заказе. Канала нет — записка идёт первой секцией твоей части журнала.

8. Заявление = команда

Каждое число и каждая категорика — с командой и её выводом. Рядом с НУЛЁМ ПЕЧАТАЕТСЯ контрольная величина. go test ./... без -v скипы не печатает: печатай счёт скипов рядом с числом ok и называй условие.

9. Эхо-протокол старта

ДО первой правки пришли мне первым действием, по адресу из /tmp/textmachine-channel (SendMessage, роль ОРКЕСТРАТОР) ≤10 строк: скоуп · инварианты · не-делать — СВОИМИ словами, плюс что считаешь в заказе опасным и что неверным. Дословный пересказ подтверждает канал, но не понимание.

10. Что НЕ удалось — обязательная секция отчёта

Что не проверено · что не воспроизвелось · где данных не хватило. «Не измерено» вместо догадки.

11. Канал вопросов и право отказаться

Конфликт промта с кодом — пинг мне, НЕ интерпретация. Право сказать «этого делать не надо» с аргументом есть, и такие развилки поощряются: за смену три сессии принесли по возражению, и все три были приняты.

12. Прямой канал

CLAUDE.md §«Связь между сессиями»: /tmp/textmachine-channel, свой блок первым делом, живость — ListAgents. Нужной роли в файле нет, файла нет или имя не отвечает ⇒ КАНАЛА НЕТ, и это НОРМАЛЬНЫЙ случай: НЕ опрашивай сессии подряд. Вопрос — секцией в отчёт, работа продолжается.

13. Критерий завершённости

Работа завершена, когда: у каждого пункта §4 есть исход (сделано · не делаю с доводом · пинг) · прибор воспроизвёл ОРАКУЛ прогона A НА ЗАМОРОЖЕННОМ АРТЕФАКТЕ (§3 п.5), и расхождения названы — ⚠ кроме двух ИЗВЕСТНЫХ (凤雏, 老嬷嬷), которые объясняются пере-консолидацией банка, а не прибором · круги самопроверки СОШЛИСЬ — последний не дал НОВЫХ находок, прежние закрыты таблицей «находка → что сделано → чем предъявлено» · таблица мутаций полная, выжившие названы поимённо · снапшот-нейтральность доказана байт-равенством · числа сняты ПОСЛЕ последней правки · ⚠ ряды бэклога НЕ ПЕРЕВОДИШЬ — docs/BACKLOG.md моя зона (испр.: прежняя редакция противоречила §2 этого же пака); назови их в отчёте, перевод мой · всё живое в ДЕРЕВЕ, а не в письме · явное «работа завершена, править не планирую». ⚠ Сходимость не достигнута — говори это прямо, не выдавай круг за сходимость. За эту смену два пака из трёх закрыты БЕЗ сходимости, правилом остановки, и оба приняты: честное «не сошлось» с доводом лучше объявленного «сошлось». Пак доводишь до конца ТЫ. Владельца не беспокоить, меня не тегать «просто так».

Деньги

Пак — $0. Платных вызовов нет: пост-проверка, отчёт и пробы на уже оплаченной базе прогона A. Упрёшься в «это предъявляется только платным прогоном» — пинг за санкцией, не своё решение.

Отчёт

Секция «Бэкенд» в docs/PROGRESS.md под своим подзаголовком + сообщение мне: что сделано по каждому пункту · чем предъявлено (команда и вывод) · таблица прибора против ОРАКУЛА · таблица «находка → что сделано → чем предъявлено» · что сказал твой адверсариальный проход · секция §10 · что ты сам считаешь слабым местом. Последний абзац отчёта — план или обещание? Значит работа не кончена: сделай сейчас.