89 KiB
АРХИВ: секция «Бэкенд» журнала прогресса, эра 24–28.08.2026
⚠ ИСТОРИЧЕСКОЕ. Инструкции отсюда НЕ ИСПОЛНЯЮТСЯ. Это вынесенная 28.08 прожитая проза зонной секции
docs/PROGRESS.md— пять итогов бэкенд-сессий и их записки-планы. ВСЕ описанные здесь паки ЗАЛЕНДЖЕНЫ, и каждый «дерево готово, НЕ закоммичено» относится к состоянию, которого больше нет.Куда что уехало: входная дверь шва (24–27.08, четыре сессии) —
D39.158, лендингd1eb8a9; пак «тихая порча» (28.08) —D39.164, лендинг7d0c6f2.⚠ Остатки, которые здесь названы, живут СТРОКАМИ единого бэклога, а не этим файлом: 228 (алиас возвращает отклонённую поверхность), 229 (снапшот не фолдит модель внутренних гейтов), 230 (размен сходимости против поучения), 231 (смета пере-прохода), 141 (остаток детектора сносок), 131 (кап инъекции не считает маркер). Вендор-вердикт по Gemini живёт ПИНГОМ ПОЛИГОНУ в живом журнале — здесь его копия, не носитель.
Вынесено аудитом документации 28.08 (D39.167) по слову владельца «пройденную прозу можно сносить».
⟶ Состояние бэкенда — CURRENT-STATE (один носитель, D39.80); здесь только пинги живых сессий.
✅ ИТОГ БЭКЕНД-СЕССИИ 28.08 — ПАК «ТИХАЯ ПОРЧА» (docs/BACKEND_SILENT_HARM_SESSION_PROMPT.md), все три пункта. Дерево готово, НЕ закоммичено.
§6 КОМПЛЕКТНОСТЬ — пункт → что сделано → каким ИСПОЛНЕНИЕМ подтверждено.
| Заказ | Что сделано | Чем подтверждено ИСПОЛНЕНИЕМ |
|---|---|---|
| §3.1 инъекция банка доезжает на каждом провайдере либо громкий отказ | Новая ось llm.Capability.SystemMessages (multi|single, capability.go:87-127,158-165); под single toOpenAIMessages СКЛЕИВАЕТ ведущий системный ряд в одно сообщение (httpllm.go:513-559) и падает громко на системном посреди диалога — зеркально Anthropic; YAML-ось capabilities.system_messages с валидацией enum (config/models.go:101-106,566-578,646-650); квирк объявлен у провайдера gemini с вендор-ссылкой и датой (configs/models.yaml:120-137) |
6 тестов internal/llm/systemmessages_test.go + сквозной на ОБОИХ волнах internal/pipeline/systemmessages_wave_test.go. Мутация «ось игнорируется» → падает TestSingleSystemEndpointCarriesTheBankOnBothWaves обеими под-ветками и …CarriesTheInjection с текстом got 2 (roles [system system user]). Мутация «ось теряется по дороге из YAML» → тот же тест. Каталог: SH1, SH2 |
| §3.2 дыра выдачи видна читателю файла | ⚠ Заказ пере-формулирован по находке (разрешено оркестратором 28.08): маркер уже существовал и ВРАЛ. ChunkOutcome/ChunkExport несут DroppedMembers (bookrun.go:69-75, export.go:45-51, waverun.go:488, export.go:227-230); cmd/tmctl/render.go печатает маркер В ПОТОКЕ ТЕКСТА (gapMarker, :26-63) в обоих рендерах и честные счётчики withheld/incomplete |
Сквозной прогон БОЕВОГО бинаря cmd/tmctl/exportgap_cli_test.go: tmctl translate → tmctl export --plaintext, текст ДО и ПОСЛЕ на ОДНОМ состоянии (ниже). Матрица семи состояний. Мутации SH3 (маркер пуст) и SH4 (счёт выпавших не ведётся) |
| §3.3 повтор принятого документа сходится | refuseSeedConflicts больше не срабатывает, когда отказ УЖЕ на записи (membank/decisions.go:365-393, новый rejectsHoldSurface :690-700); порядок записи в writeDecisionFiles изменён на REJECTS-FIRST с обоснованием (bankdecisions.go:427-441,458-489) |
5 тестов membank/decisions_converge_test.go + 3 дверных pipeline/bankdecisions_converge_test.go (реальные файлы, реальные классы отказа). Мутации SH5 (сужение снято) и SH6 (порядок возвращён) |
РЕШЕНИЯ ПО ПРОПУСКАМ И РОДНЕ — строкой каждое, как просил оркестратор.
- Четвёртая дыра (строка 141) — ВЗЯТА БЕСПЛАТНО, работы не потребовала. Проверено исполнением
(проба по
internal/checks, файл удалён после замера): сноска[1] 蛊真人 — название романа.мимо детектора примечаний идёт, но поднимает классCJKLeak, а онCosmeticOnly(checks/sanitizer.go:161-163) ⇒StripCosmeticвырезает ханьцзы, юнит уходитsanitizer_stripped, и баннер «leak cleaned, verify» для НЕГО правдив. Механизм этого же заказа накрывает класс без правки детектора — граница промта соблюдена буквально. ⚠ Смежное, НЕ взятое и названное строкой: сноска БЕЗ ханьцзы ([1] Название романа.) не поднимает ни одного класса (замер:total=0), едет как есть — но текста при этом НЕ теряет, это лишняя добавка, а не дыра. Маркер на ней дезинформировал бы (⛔ анти-скоуп промта). Ловля таких сносок — работа В ДЕТЕКТОРЕ, промт её прямо запретил. - Д1 — НЕ ВЗЯТ, отдельным предметом. Право §9. Канон определяет decline ПОВЕРХНОСТНО
(«declining a surface removes EVERY window of that surface»,
14-api-contract/openapi.yaml:2051), и расширять его до энтити значило бы менять ратифицированный контракт из бэкенд-сессии. Вторая половина Д1 («память глушит стоп») — уже НАЗВАННЫЙ и принятый двусторонний остаток в комментарииmining.go:308-313, а не необнаруженный дефект. ⚠ Но одна траектория Д1 реальна и требует ЧУЖОГО решения: эмиссия майнера энтити-широка (miner_emit.goclusterTouches), а фильтр авто-банка ключуется только по собственному src строки (mining.go:662), поэтому ОТКЛОНЁННАЯ поверхность может вернуться алиасом уцелевшей строки. Это противоречит канону уже сегодня. Не чиню в этом паке (правильная форма — снять алиас со строки, а не снести строку; это предмет банковой онтологии, а не тихой порчи) — но это заказ, который стоит выдать. - Д3 — НЕ ВЗЯТ, вне моей зоны.
LiftBankStopвbackend/не существует ни в каком написании; символ живёт вplatform/internal/runs/spawn.goиreconcile.go, то есть в зоне, запертой паком P9. Движковая половина при этом здорова: порядок «карта → память» ратифицирован и исполнен (mining.go:191пишет карту,:274метит память), отказ памяти оценён в комментарии:275-276как «one extra stop, nothing lost». ⚠ Поправка к моему же раннему пингу: я сказал «гарда не существует» — точнее «не существует В ДВИЖКЕ». - Сосед 131 — НАЗВАН, не чиню. Кап инъекции считает только
src → dst(membank/memory.go:517-521glossaryLineTokens), а рендер дописывает к КАЖДОЙ строкеtx.UnverifiedMarker(:706) либоgenderConstraintNote(...)(:711), а редакторский блок ещё и префикс-с кавычками-ёлочками (:821). То есть отгружаемая строка строго длиннее той, за которую платит бюджет; на коротких именных строках перерасход велик. Тема денег и качества инъекции — не тихий брак в тексте.
НАХОДКИ, МЕНЯЮЩИЕ ПРОМТ (все три подписаны, ни одна не абсорбирована молча).
- §3.2: маркер существовал и ВРАЛ. Ветка
case ce.FinalText != ""печатала «(leak cleaned, verify)» ЛЮБОМУ флагнутому юниту с текстом, а c-lite member-drop (export.goставитDispFlaggedпри непустом тексте) попадал ровно в неё. Существующий тест не ловил: покрывал ветку только причинойsanitizer_stripped(export_cli_test.go:66). Предмет заказа изменён с «завести маркер» на «перестать врать и покрыть непокрытое» — разрешено оркестратором 28.08 при закрытом гейте. - §3.2: подсказка промта про место правки была опасна. Промт указывал
export.go:237рядом сApplyHeading. Туда нельзя:ChunkExport.FinalText— поле артефактного контракта, а провод судитtranslated/withheldпредикатом «текст непуст» (waverun.go:203-204иevents.go:538-554,runevents.go:130Shipped). Маркер в пустом юните перевернул быwithheld→translated— ровно ⛔(а) промта.ApplyHeadingэтого не делает лишь потому, что на пустом тексте он no-op. Маркер живёт в РЕНДЕР-слое. Проверено:FlagReason-константы до и после ИДЕНТИЧНЫ,exportVersionне двигался,dropped_membersаддитивно иomitempty. - §3.1: посылка «Gemini принимает ровно одно» отозвана автором (оркестратор, 28.08) — вендор-
вердикт со ссылками и датами отправлен ему отдельно, для
00-provider-quirks.md. Кратко: структурная посылка ПОДТВЕРЖДЕНА (systemInstruction— одинobject (Content),Content.role∈ {user, model}), поведение шима вендором НЕ документировано нигде, наш замер даёт «не склеиваются» и «инструкция первого не исполнена»; «выживает одно или ноль» остаётся ОТКРЫТЫМ и для решения безразлично.
ДЕФЕКТ, КОТОРЫЙ Я ВНЁС САМ И ЗАКРЫЛ (называю, потому что он показателен). Первая редакция ветки
маркера срабатывала по DroppedMembers > 0 БЕЗ проверки непустого текста. Юнит, у которого выпали ВСЕ
члены, ship-ит пустоту — и получил бы баннер «(INCOMPLETE)» с фразой «фрагмент отсутствует в тексте
НИЖЕ», указывающей на несуществующий текст. То есть я едва не заменил одну ложь читателю на другую.
Найдено собственным разбором ветвлений до опровергателей, закрыто гардом на обоих сайтах вызова,
покрыто состоянием «выпали все» в матрице и запинено мутацией (снятие гарда → тест падает).
§5 ОСИ РЕВЮ.
- Читатель книги. Все четыре класса проверены на ОТГРУЖЕННОМ ТЕКСТЕ, не на структурах:
(а) c-lite — был помечен ложно, теперь помечен верно и в потоке текста; (б) юнит целиком withheld и
(в)
glossary_miss— помечены верно и раньше, работы не требовали, теперь ещё и не попадают под маркер по ошибке; (г) сноска с ханьцзы — накрыта существующим верным маркером. - Пара, которой в репо нет. Правка не ветвится по паре ни в одном месте: ось
system_messages— свойство ЭНДПОЙНТА, маркер — английский операторский словарь той же поверхности, что и соседние баннеры, поэтому у книги с любымtarget_langи БЕЗ langpack вывод байт-идентичен. Специально НЕ стал класть маркер в langpack:InjectionTextsForдля незнакомой цели возвращает нулевое значение молча (lang/embedded.go:411-423) — маркер бы исчез, и дыра снова стала бы тихой ровно для той пары, ради которой мандат общности и написан. - Детерминизм. Голден зелёный (
go test ./internal/pipeline/ -run TestGolden -count=1), и это сильная улика: голден пинит ПОЛНОЕ тело запроса с обоими системными сообщениями (testdata/golden/capture.golden:110), то есть глобальная свёртка сделала бы его красным, а квирк-свёртка не трогает никого, кто квирк не объявил.omitemptyна новом поле запинен тестом (TestCapabilityWithoutTheAxisMarshalsUnchangedсверяет БАЙТЫ). Снапшот фолдит Capability только праймари иescalate_to(snapshot.go:316-340), а вpipeline-c1.yamlэтоdeepseek-v4-pro(:60) — gemini там лишь третий в цепочке приbudget_usd: 0и SINGLE-HOP раннере ⇒ снапшот боевого конфига не двигается, перекупки нет.
§8 OBSTACLE — что НЕ удалось и что НЕ проверено.
- Живого вызова к Gemini НЕ было (пак платных вызовов не требует, и я их не делал). Что склейка
ПОМОГАЕТ, доказано структурно вендор-докой и логикой «при любом чтении, кроме склеивания, два
системных теряют текст» — но НЕ замерено на проводе. Решающая проба стоит денег и принадлежит
полигону: маркер на ПОСЛЕДНЕЕ системное + user-only контроль закрыли бы открытый вопрос
«выживает одно или ноль». Также: проба полигона гонялась на
gemini-3.1-flash-lite, а в цепочке стоитgemini-3.1-pro-preview— слой тот же, слаг другой, перенос не замерен. - Достижимость §3.1 сегодня НУЛЕВАЯ, и это не смягчение дефекта, а его честная рамка. Раннер
исполняет SINGLE-HOP,
escalate_toбоевого конфига —deepseek-v4-pro,budget_usd: 0. Gemini не достигается ни одним шиппинг-конфигом; дефект ждал первого конфига, который назовёт его вescalate_toили вchain[0]лейбла. Кривая пост-чек-промахов на эскалационном хопе, которую §4.2 просил как второй замер, СНЯТА БЫТЬ НЕ МОЖЕТ по той же причине — мерить нечего. - Ловушка, которую я НЕ чинил и обязан назвать:
capabilitiesу провайдера сkind: anthropicпринимается валидацией и молча игнорируется —clients.goне передаётCapв Anthropic-клиент вовсе. Это ПРЕД-СУЩЕСТВУЮЩИЙ класс (так ведут себя ВСЕ оси:budget_field,temperature,reasoning,min_max_tokens), моя ось лишь наследует его. Чинить правильно — тащитьkindвvalidateCapabilities, что трогает каждую ось; в этом паке это чужой предмет. Практический риск сегодня нулевой: провайдераanthropicвmodels.yamlнет. - Изменён СУЩЕСТВУЮЩИЙ тест — заявляю прямо, не прячу в дифе.
internal/pipeline/bankreport_test.goTestHalfLandedIsNamedPerFileкодировал ПОРЯДОК переименований в своей фикстуре (занимал путь rejects, чтобы упал второй rename). Порядок изменён заказом §3.3, и фикстура пере-нацелена на путь delta. Утверждение НЕ ослаблено: по-прежнему требуется, что ровно одна половина легла, что это ПРОВЕРЕННЫЕ байты и что отчёт называет какая. Сверх того добавленTestTheRenameOrderIsWhatMakesADeclineRecover, который пинит САМ порядок вместе с его причиной, чтобы его нельзя было вернуть как «уборку». Если оркестратор считает это подгонкой — я готов откатить и вынести §3.3-половину с полусостоянием отдельным заказом. - Каталог мутаций: запись
AJ-seed-alias-declineпере-заякорена. Моя правка сдвинула строку, на которую она указывала, и инструмент падал жёсткой ошибкой «the source moved under the catalogue» — это был бы хард-блокер для следующей сессии. Атакуемое свойство сохранено дословно (снять дельта-оговорку, оставить остальное); плюс добавлены шесть СВОИХ посадокSH1…SH6, по две на пункт, чтобы фикс был постоянным гейтом, а не разовым замером. - Не проверено: поведение под реальным параллелизмом двух
bank-apply(лок это исключает, но я не гонял); поведение склейки на провайдере, который принимает одно системное И имеет префиксный кеш (у gemini кеш иной) — довод «склейка кеш не портит» опирается на комментарий самого кода и на то, что префикс сохраняет байты и позицию, живьём не мерен.
§4 ОПРОВЕРГАТЕЛЬ — ЗАКАЗ ИСПОЛНЕН, И ОН ОКУПИЛСЯ. Шесть линз, мандат «опровергни».
Веер шесть, а не «2–4» из §4: численный потолок снят словом владельца 28.08, соразмеряю предмету.
Линзы: Anthropic-путь и кеш · читатель книги · провод withheld/translated · безопасность банковых
решений · пара, которой в репо нет + детерминизм · вырожденность собственных тестов. Пять из шести
вернули вердикт REFUTED или PARTIAL, и это правильный исход: они нашли ШЕСТЬ дефектов, из них ЧЕТЫРЕ
я внёс сам этим паком. Все воспроизведены ИСПОЛНЕНИЕМ на копиях дерева, не чтением.
| Находка | Кто/чем доказано | Что сделано |
|---|---|---|
| MAJOR: маркер называл ЧУЖУЮ причину. Юнит, где редактура флагнулась САМА (косм. чистка) И выпал член, печатал причину ЧИСТКИ как причину дыры: «фрагмент не переведён: sanitizer_stripped». Та же ложь, что убирал пак, перенесённая в поток текста | 2 линзы независимо, боевой бинарь | ИСПРАВЛЕНО: заведены DroppedReason на ChunkOutcome/ChunkExport, маркер несёт причину ЧЛЕНА, баннер — вердикт ЮНИТА. Пин SH7, состояние в матрице обоих рендеров |
| MAJOR: анти-скоуп. В черновично-однофазном конвейере юнит — одиночный чанк, и его СОБСТВЕННЫЙ флаг читался как «выпавший член» ⇒ косметически почищенный чанк, у которого ВЕСЬ текст на месте, объявлялся неполным | боевой бинарь, tmctl translate и tmctl export расходились на одном юните |
ИСПРАВЛЕНО: учёт выпадений только когда финальная волна — редакторская (export.go). Тест TestADraftOnlyStrippedChunkIsNotCalledIncomplete, пин SH8 |
MAJOR: перестановка порядка записи купила сходимость ЦЕНОЙ второго тихого вреда. Rejects-first оставляет строку дельты на диске, а seedGlossary дельту отказами НЕ фильтровал ⇒ в окне между падением и ре-сендом ОПЛАЧЕННЫЙ прогон вливал в глоссарий редактора терм, который владелец отклонил |
2 линзы, исполнение на реальных файлах | ИСПРАВЛЕНО: loadMinedDelta отбрасывает поверхность, стоящую в списке отказов, и говорит об этом WARN'ом. Тест на реальном полусостоянии, пин SH12. Заодно исправлено утверждение в шапке writeDecisionFiles, которое после перестановки стало ложным |
MAJOR: сходимость останавливалась на ОДНОЙ из двух дверей. refuseInertDeclines я решил не трогать — и ошибся: траектория из ОДНИХ ПРИНЯТЫХ вызовов (decline терма-со-своей-строкой → approve терма, который несёт его алиасом) делала повтор стоячего реестра решений отказным навсегда, а всё-или-ничего уносило с ним законный approve |
исполнение, полная трасса | ИСПРАВЛЕНО: та же оговорка на второй двери (по in.Rejects, не res.Rejects — фолд уже отработал). Тест TestTheStandingLedgerConvergesThroughBothDoors + направление-гард на живом алиасе, пин SH13 |
MAJOR: у боевого объявления в configs/models.yaml не было ГЕЙТА вовсе. Две строки — единственное, что доводит фикс до реального эндпойнта, а удаление их оставляло ВЕСЬ модуль зелёным |
опровергатель посадил свою мутацию и получил SURVIVED | ИСПРАВЛЕНО: TestShippedGeminiDeclaresOneSystemMessage над боевым конфигом, пин SH9 (проверено: удаление строк → тест краснеет) |
MINOR: гарды в renderTranslate не были запинены (близнецы в renderExport были), case "multi" не покрыт, счётчики читались как разбиение целого |
исполнение | ИСПРАВЛЕНО: матрица шести состояний для renderTranslate, тест TestExplicitMultiCostsNothing, счётчик переписан как exported=N (of them incomplete=M). Пины SH10, SH11 |
ЧТО ОПРОВЕРГАТЕЛИ АТАКОВАЛИ И НЕ СЛОМАЛИ (чтобы следующий читатель знал, что уже покрыто):
Anthropic-путь (склейка до него не доходит структурно — Cap в него не передаётся; два блока и живой
cache_control на месте) · префиксный кеш (стабильный префикс сохраняет байты и позицию) · провод
translated/withheld (UnitDone.Shipped считается по пустоте текста; ни DroppedMembers, ни
маркер её не трогают) · отсутствие новых причин флага (константы FlagReason до и после ИДЕНТИЧНЫ) ·
exportVersion не двигался · снапшоты боевых конфигов не двигались · арм-конфиги грузятся.
ЧТО НАЙДЕНО, НО СОЗНАТЕЛЬНО НЕ ЧИНИТСЯ — с аргументом.
- Ловушка
capabilitiesнаkind: anthropic— оказалась чинибельной дёшево, и я её ВЗЯЛ: ось теперь отказывается на этом виде по образцуcache_ttl(models.go), с тестом. Пред-существующий класс для ОСТАЛЬНЫХ осей (budget_field,temperature,reasoning,min_max_tokens) остаётся — его правильная форма тащитkindвvalidateCapabilitiesи трогает каждую ось; это чужой предмет. - Снапшот не покрывает модель ГЕЙТА ТЕРМИНОЛОГИИ (
config/pipeline.go— не фолдится сознательно, ратифицированно), а терминолог шлёт ДВА системных. ⇒ флип оси у провайдера, которым пользуется только этот гейт, меняет байты под НЕИЗМЕННЫМRequestHash, и чекпойнты ложно попадают. Дыра НЕ моей оси — по ней ездят все осиcapabilitiesс D3.1 — но моя первая, чей смысл именно в смене этих байтов. Утверждение в комментарии я ослабил до правды и дыру НАЗВАЛ прямо в коде (capability.go); закрытие — фолд модели гейта, как это делаетrepairSnapshot, и это правка снапшот-контракта, принадлежащая владельцу решения «не фолдить», а не провайдерскому квирку. - Сузив отказ по поверхности, я потерял поучение в одном углу: decline, который И записан, И
по-прежнему инертен против подписанного сид-терма, теперь отвечает
already_appliedвместо единственной работающей инструкции «убери из glossary_seed». Сходимость сочтена более тяжёлой обязанностью (у вызывающего, который следует опубликованному ретраю, другого хода нет), но размен реальный: закрывается полем отчёта, несущим стоячий факт, и это форма шва.
ХАРД-БЛОКЕР, НАЙДЕННЫЙ И СНЯТЫЙ (требование владельца «после тебя не осталось хард-блокеров»).
go test ./cmd/tmctl/ строил боевой бинарь в os.MkdirTemp и НИКОГДА не убирал каталог — по 20 МБ за
прогон. За этот пак накопилось 249 брошенных каталогов tmctl-bin*, ~5 ГБ, и /tmp заполнился до
99%: батарея под -race начала падать с link: mapping output file failed: no space left on device,
что читается как сломанная сборка, а не как кончившееся место. Я на это и купился на один прогон —
сообщать «батарея красная» было бы ложью. Причина найдена, место освобождено, харнесс починен:
добавлен TestMain, снимающий каталог (cmd/tmctl/exitcontract_test.go); проверено исполнением —
два прогона подряд, прирост каталогов 0. Дефект пред-существующий, пак его лишь довёл до отказа.
ЧИСЛА, С КОМАНДАМИ (§4.1).
go build ./...·gofmt -l .(пусто) ·go vet ./...·go vet -tags live ./...— все 0.go test ./... -count=1 -timeout=20m→ EXIT 0.go test ./... -race -count=1 -timeout=20m(= строкаmake test) → EXIT 0, real 2m09s.golangci-lint run --timeout=15m ./...(=make lint) → 0 issues.go test ./internal/pipeline/ -run TestGolden -count=1→ ok (голден пинит ПОЛНОЕ тело запроса).go run ./cmd/tmmutate -root <КОПИЯ>→ 73 посадки, 0 неожиданных исходов, EXIT 0 (72 RED + один каталогизированный выжившийG-byte-gate; все 13 моих красны); каталог вырос 60 → 73 (13 новых посадок:SH1…SH13), у каждой из трёх заказанных тем ≥2 своих. ⚠ Каталог гонять ТОЛЬКО на копии — сам инструмент это требует, а я один раз запустил его на рабочем дереве и словил таймаут; дерево спас обработчик сигнала самого инструмента (проверено: мутационного текста не осталось, батарея зелена). Записываю как урок, а не как мелочь.
ФАЙЛЫ (19 правленых + 5 новых; всё в backend/, плюс эта запись в журнале).
cmd/tmctl/render.go · cmd/tmctl/exitcontract_test.go · cmd/tmmutate/mutations.json ·
configs/models.yaml · internal/config/models.go · internal/config/models_catalog_test.go ·
internal/llm/capability.go · internal/llm/httpllm.go · internal/llm/provider_openai.go ·
internal/llm/provider_local.go · internal/membank/decisions.go ·
internal/membank/decisions_fuzz_test.go · internal/pipeline/bankdecisions.go ·
internal/pipeline/bankreport_test.go · internal/pipeline/bookrun.go ·
internal/pipeline/export.go · internal/pipeline/mining.go · internal/pipeline/runner_test.go ·
internal/pipeline/waverun.go.
Новые: cmd/tmctl/exportgap_cli_test.go · internal/llm/systemmessages_test.go ·
internal/membank/decisions_converge_test.go · internal/pipeline/bankdecisions_converge_test.go ·
internal/pipeline/systemmessages_wave_test.go.
⛔ ВОПРОСЫ И ПИНГИ ОРКЕСТРАТОРУ — четыре, каждый требует ЧУЖОГО решения.
- Изменён СУЩЕСТВУЮЩИЙ тест, и я это заявляю, а не прячу.
bankreport_test.goTestHalfLandedIsNamedPerFileкодировал в фикстуре ПОРЯДОК переименований, который заказ §3.3 изменил; фикстура пере-нацелена на второй rename, утверждение сохранено дословно и усилено новымTestTheRenameOrderIsWhatMakesADeclineRecover, пинящим сам порядок с его причиной. Считаешь подгонкой — откачу, и тогда половину §3.3 с полусостоянием надо выносить отдельным заказом. - Вендор-вердикт по Gemini — прислан отдельным сообщением, с URL и датами; три поправки к
00-provider-quirks.md:157(структурная посылка ≠ поведенческий вывод ·Content.parts[]повторяемо · «форум Google» — это два не-сотрудника из 2025). Пишешь ты, зона твоя. - Дыра снапшота у модели гейта терминологии (см. выше, п.2 «не чинится»). Закрытие — правка снапшот-контракта; принадлежит владельцу решения «гейт не фолдится», не мне.
- Д1 достоин собственного заказа. Не «расширить decline до энтити» (это против канона), а узко:
эмиссия майнера энтити-широка (
miner_emit.goclusterTouches), а фильтр авто-банка ключуется только по собственному src строки (mining.go:662), поэтому ОТКЛОНЁННАЯ поверхность возвращается алиасом уцелевшей строки. Канон уже сегодня обещает «declining a surface removes EVERY window of that surface» — то есть движок не держит обещание. Правильная форма — снять алиас со строки, а не снести строку; это банковая онтология, и в «тихую порчу» её тянуть не следует.
ПРАВО §9 ПРИМЕНЕНО ТРИЖДЫ, каждый раз с грунтом: Д3 отклонён (символ живёт в platform/, зона
заперта; движковая половина здорова и порядок «карта → память» исполнен) · Д1 отклонён как отдельный
предмет (выше) · подсказка промта про место маркера отклонена (она перевернула бы withheld →
translated). ⚠ И один раз право §9 я применил ОШИБОЧНО: решил не трогать вторую дверь
refuseInertDeclines, рассудив, что её случай — «устаревший документ, а не ретрай». Опровергатель
показал траекторию из ОДНИХ ПРИНЯТЫХ вызовов. Рассуждение было неверным, исполнение это доказало,
дверь починена.
⚠ ЗАПИСКА НИЖЕ — ПЛАН ДО ПРАВОК (§6), она СОХРАНЕНА как след дисциплины, но её выводы местами ОПРОВЕРГНУТЫ итогом выше. Не наследовать из неё: «сломан только класс (а)» (сломан ещё и стык «редактура флагнулась сама + выпал член»), «фиксация порядка записи безопасна» (она купила второй тихий вред, закрытый фильтром дельты) и «Д3 не существует» (существует, в platform/).
📝 ЗАПИСКА-ПЛАН БЭКЕНД-СЕССИИ 28.08 — ПАК «ТИХАЯ ПОРЧА» (docs/BACKEND_SILENT_HARM_SESSION_PROMPT.md), §6. Правок кода на момент записи НЕТ.
Три заказа: §3.1 инъекция банка не теряется · §3.2 дыра выдачи видна читателю файла · §3.3 повтор
принятого документа сходится. Ниже — что установлено ЧТЕНИЕМ до правок и как из этого следует план.
⚠ Всё, что помечено «проверить исполнением», в план входит как обязательство, а не как факт.
Находка 1 (меняет §3.2). Маркер уже есть — и он ВРЁТ. cmd/tmctl/render.go:499 печатает для
флагнутого юнита с НЕПУСТЫМ текстом баннер «(leak cleaned, verify)», а :38 — «[FLAG … — leak
cleaned, exported cleaned, verify]». Ветка выбирается по ce.FinalText != "", и c-lite member-drop
(export.go:226-230 ставит DispFlagged при непустом тексте) попадает ровно в неё. То есть юнит, у
которого ВЫПАЛ ЦЕЛЫЙ ЧЛЕН, объявляется читателю косметической чисткой санитайзера, которой не было.
Существующий тест это не ловит: cmd/tmctl/export_cli_test.go:66 покрывает ветку только причиной
sanitizer_stripped. ⇒ Предмет §3.2 не «завести маркер», а «перестать врать и покрыть непокрытое»
(пере-формулировка разрешена оркестратором 28.08 при закрытом гейте «что читает человек»).
Гейт §3.2 закрыт чтением: движок НЕ ПИШЕТ ФАЙЛОВ ВООБЩЕ. Все команды рендерят в stdout
(cmd/tmctl/main.go:227-228, :338-349). Читаемых человеком поверхностей у движка две, обе
текстовые и обе уже несут пер-юнитный баннер: tmctl translate (render.go:27-72) и
tmctl export --plaintext (render.go:478-511). Дефолт export — JSON
(export_cli_test.go:24-28), и он же артефакт шва к платформе (research/23 строка 76 —
«артефактный контракт (export-JSON · 101 · 100)»). Читательский файл (epub и пр.) собирает
ПЛАТФОРМА по POST /books/{bookId}/exports (14-api-contract/openapi.yaml:824-870) — чужая зона.
⇒ Адресат моего маркера — человек, читающий plaintext-выгрузку движка; платформенная половина
остаётся за платформой, и провод различение несёт (14-api-contract/README.md:300).
Следствие для места правки, и оно расходится с подсказкой промта. Промт указывал на
export.go:237 (прецедент ApplyHeading). Туда маркер класть НЕЛЬЗЯ: ChunkExport.FinalText — это
поле final_text артефактного контракта, а waverun.go:203-204 кормит провод предикатом
oc.FinalText != "" (shipped). Любой маркер, вклеенный в текст ПУСТОГО юнита, перевернул бы
withheld → translated — ровно ⛔(а) промта. ApplyHeading этого не делает только потому, что на
пустом тексте он no-op (chunk/chunker.go:186-191). Различение: титул — часть КНИГИ и обязан ехать
на провод; маркер дыры — метаданные О тексте, и в поле, по которому провод судит, ему нельзя. ⇒
маркер живёт в РЕНДЕР-слое (cmd/tmctl/render.go), на слой дальше проекции. Это ответ на требование
промта «либо тем же механизмом, либо объясни, почему другое».
Классы дыр — ревизия по коду. (а) c-lite member-drop — помечен, но ЛОЖНО (находка 1); (б) юнит
целиком withheld (waverun.go:496-509) и (в) gate-override glossary_miss (export.go:319-323)
дают пустой текст и попадают в ветку render.go:502-504 «(not translated, flagged for a human)» —
помечены ВЕРНО, работы не требуют; (г) четвёртая, сноска «[1] …» мимо детектора примечаний: детектор
требует заголовочного слова (lang/data/target-ru.txt, sanitizer_trailing_note), но ханьцзы в
сноске поднимают класс CJKLeak, а он CosmeticOnly (checks/sanitizer.go:161-163) ⇒ юнит уходит
как sanitizer_stripped, и баннер «leak cleaned» для НЕГО правдив. То есть класс (г) накрыт
существующим механизмом БЕСПЛАТНО и работы в детекторе не требует — граница промта соблюдена.
Проверить исполнением обязательно: что сноска с ханьцзы действительно даёт CosmeticOnly, а не
подтягивает субстантивный класс.
§3.1 — план и его цена. Свёртки в toOpenAIMessages нет (llm/httpllm.go:513-521, копия
один-в-один); её комментарий :511-513 говорит, что CacheBoundary на этом пути бессмысленна ⇒
свёртка кеш не портит. У Anthropic путь другой и трогать его нельзя
(llm/provider_anthropic.go:169-179: ведущий system-префикс → блоки, CacheBoundary → реальный
cache_control). Ось лечения — llm.Capability + блок capabilities: (провайдерный ИЛИ модельный,
config/models.go:85,:146,:442-450), прецедент безопасного расширения — MinMaxTokens с
json:",omitempty". Детерминизм: снапшот фолдит РАЗРЕШЁННУЮ Capability только для праймари и
единственного escalate_to (pipeline/snapshot.go:316-340,:479,:495); в pipeline-c1.yaml
escalate_to: deepseek-v4-pro (:60), а gemini стоит лишь третьим в цепочке default (:129) при
budget_usd: 0 (:136) и раннере SINGLE-HOP ⇒ объявление квирка у gemini снапшот боевого конфига
НЕ двигает. Проверить исполнением (голдены + снапшот-тесты).
⚠ Честная граница достижимости: при SINGLE-HOP и текущих конфигах gemini не достигается ВООБЩЕ;
дефект латентный и ждёт конфига, который назовёт gemini в escalate_to или в chain[0] лейбла.
⚠ Развилка, которую выношу на опровергателя (§4 заказ): дефолт оси. «Квирк объявляет тот, у кого
он есть» (нулевое значение = сегодняшнее поведение) не двигает ничего, но НОВЫЙ провайдер с той же
ловушкой снова теряет инъекцию молча — тот же класс тихого вреда. «Свёртка по умолчанию, исключение
объявляет проверенный» безопасна для незнакомого провайдера, но меняет провод боевому переводчику без
замера (запрет «эмпирика решает») и двигает снапшот. Решение — после опровергателя, с обоснованием.
⚠ Посылка промта «Gemini принимает ровно одно системное» ОТОЗВАНА автором (оркестратор, 28.08):
это было рассуждение; собственный замер полигона (00-provider-quirks.md:157) даёт 535 токенов ≈ не
выжило НИ ОДНО. Заказу это безразлично, тесту — нет: утверждается пост-фиксный инвариант «системное
РОВНО ОДНО и инъекция ВНУТРИ него», он верен при любом чтении. Вендор-вердикт со ссылкой уходит
оркестратору для 00-provider-quirks.md (его зона).
§3.3 — трасса контрактной сессии ПОДТВЕРЖДЕНА моим чтением, и подтверждено то, что она сама не
читала. Отказ живёт в membank/decisions.go:374-377, бежит ДО фолда (:296-300), и
всё-или-ничего вытирает документ целиком (:302-307). Порядок записи я прочитал сам:
bankdecisions.go:458-473 коммитит ДЕЛЬТУ ПЕРВОЙ, а собственный комментарий функции :436-438
говорит дословно: «delta-first is safe for an approve and NOT for a decline … convergence is what
actually carries both». ⇒ окно застревания реально, и код сам называет допущение, которое ложно.
Идемпотентная ветка уже есть (already_applied, :221-224,:269-272) — вводить понятие не надо.
План: сузить условие отказа так, чтобы оно не срабатывало, когда отказ УЖЕ записан в rejects, плюс
направление-гард (настояще-инертный decline обязан отказывать по-прежнему тем же текстом).
Идентичность документа НЕ вводить — сходимость по СОСТОЯНИЮ.
Д1 и Д3 — беру право §9 и НЕ чиню, оба с грунтом.
· Д3 ОТКЛОНЁН как несуществующий: гард LiftBankStop не найден в коде НИ В КАКОМ написании
(греп по всему backend/); реальный носитель — mining.go:266-277, и он уже реализует
ратифицированный порядок «карта → память»: writeFileAtomic карты на :191, MarkStopPresented
на :274, с комментарием :270-273 «strictly after the map … the reverse order can mark surfaces
presented whose map never reached disk» и с явной оценкой отказа памяти как «one extra stop, nothing
lost» (:275-276). То есть механизм написан ВМЕСТЕ с памятью v16, а не до неё.
· Д1 ОТКЛОНЁН как ратифицированное поведение + названный остаток: канон определяет decline
ПОВЕРХНОСТНО («declining a surface removes EVERY window of that surface» —
14-api-contract/openapi.yaml:2051), и расширение до энтити противоречило бы контракту; а «память
глушит стоп» — уже НАЗВАННЫЙ и принятый двусторонний остаток в комментарии
mining.go:308-313. Оба — строка с причиной, не правка.
Сосед 131 (называю, не чиню, как велит §3.4): кап инъекции считает только «src → dst» и не
считает маркер ⟨проверить⟩ и родовые пометки (lang/data/injection.txt несёт их как отдельные
значения) ⇒ реальная инъекция шире бюджета. Проверю точный носитель при работе в этом коде и назову
file:line в итоге; чинить не буду — тема денег и качества инъекции, а не тихого брака в тексте.
Порядок работы: §3.1 → §3.2 → §3.3, каждый с тестом на ПОСТ-фиксный инвариант; батарея под
-race + линтер; посадки мутаций ≥1 на пункт с вердиктом по ДЕЛЬТЕ и ТОПИЧНОСТИ; опровергатель на
выбор места §3.1 (заказ §4). Веер агентов соразмеряю предмету: численный потолок «2–4» из §4 промта
снят словом владельца 28.08.
✅ ИТОГ БЭКЕНД-СЕССИИ 27.08 (2) — ФИКС3 ПО ФИКС-ЛИСТУ ПРИЁМКИ (docs/BACKEND_SEAM_FIX3_SESSION_PROMPT.md), все 6 пунктов. Дерево готово, НЕ закоммичено; продолжает дерево трёх паков.
Четыре пина, один снос, ноль новых механизмов: пин порядка «карта → память» (мутация приёмки
воспроизведена в трёх пакетах ДО пина; занятый путь карты → ошибка прогона + пустая память) · пин
«отчёт класса 15 мерит подпись по ДИСКУ, не по намерению» (утверждение панели воспроизведено) · оба
носителя старого пола полосы приведены к двух-ярусной букве · отменённая формула «стоп гаснет, когда
решён каждый терм» зачищена ГРЕПОМ — восемь носителей, включая два файла самого пака · снесена
машинная таблица .bank-stop.json вместе с писателем и четырьмя тестами (читателя нет ни в одной
зоне — свой греп; человеческая .bank-stop.txt не тронута) · банк-экспорт получил якорь свежести
as_of+run_id (аддитивно на tm-bank-v1; «может быть устаревшим» больше не живёт только в логе).
Доказательная база — FINDINGS §46; каталог мутаций 58 → 60 (FX23, FX24).
⛔ Пинги:
- Платформе/оркестратору:
.bank-stop.jsonСНЕСЁН (мёртвая публикация упразднённого D39.144 пер-термного экрана) — платформенные журналы (platform-PROGRESS.md,STACK_DECISIONS.md) называют его атомарно-читаемым сайдкаром, упоминания устареют при лендинге. - Потребителям банк-экспорта: документ несёт
as_of(граница прогона) иrun_id(тот же id, что стримevents.jsonl); аддитивно, старые читатели не ломаются; пустойrun_id= «идентичности нет», не «текущий».
✅ ИТОГ БЭКЕНД-СЕССИИ 27.08 — ДОФИКС-2 «ФЛАЖОК СТАНОВИТСЯ ФЛАЖКОМ» (docs/BACKEND_SEAM_FIX2_SESSION_PROMPT.md). Дерево готово, НЕ закоммичено; продолжает дерево паков 24–25.08.
Все 13 пунктов §4 закрыты: движок сам реализует модель D39.144 — стоп банка срабатывает только на
кластер, которого ни один прежний стоп не предъявлял (персистентная память bank_stop_presented,
схема v16); авто-провод неподписанных строк работает и при ПОДНЯТОМ флаге; отчёт двери собирается
ОДНИМ конструктором по явному исходу (проекция · отказ · no-op · прерывание · записано · запись не
удалась), версия отчёта → v2 (written_delta/written_rejects, mode refused/write_incomplete);
полоса отказов получила два яруса и класс write_incomplete (exit 15); оба файла решений готовятся
целиком до первого rename + fsync каталога; ключи mined_delta/mined_rejects СНЯТЫ (пути только
конвенцией — МЕЖКНИЖНАЯ гонка недостижима, ⛔-пинг прошлого пака закрыт; воркфлоу-ревью нашло остаток
той же оси: второй конфиг ТОЙ ЖЕ книги с другим объявленным project_db пишет те же файлы под другим
локом, мимо flock живого прогона — пинг ниже, решение не паку); карта подписи
пишется атомарно и несёт конверт map_version+map_id; шесть слепых пятен гейта закрыты пинами,
проверенными посадкой. Поверх — воркфлоу-ревью (шесть полос × три скептика, FINDINGS §45): его две
кодовые находки закрыты правками с пинами — --dry-run теперь отказ для всех глаголов без проекции
(раньше translate --dry-run МОЛЧА запускал платный прогон), а повтор после отказа синка каталога
держит класс 15, пока долговечность не пере-доказана. Доказательная база —
backend/docs/SEAM_PACK_FINDINGS.md §§36–§45; каталог мутаций 36 → 58 записей, 0 неожиданных
исходов. Здесь — только требующее действия.
⛔ ПОРЯДОК ДЕПЛОЯ/ЛЕНДИНГА — зависимость НАПИСАНА, а не выведена (заказ §4.12):
- Движок первым, платформа второй. Сброс флага
--verify-bankплатформой (её персистентная колонка + особый случай в спавне,platform/internal/runs/spawn.go) может умереть ТОЛЬКО ПОСЛЕ лендинга этого пака: в обратном порядке каждая книга с поднятым флажком в день лендинга перестаёт писать авто-банк и пере-сидироваться ровно в режиме, ради которого флажок существует. tmctl migrateдо прогонов (голова схемы v15 → v16):OpenReadOnlyотказывает классом 13 всем непере-мигрированным книгам — ратифицированный порядок D39.134 п.3 это покрывает, но назван явно.- Миграционная нота: после апгрейда память пуста → ОДИН доброкачественный стоп на первом verify-прогоне каждой книги.
⛔ ПИНГИ ЧУЖИМ ЗОНАМ (правок не делал):
- Платформе: у неё умирает сброс флага при resume (после лендинга движка — п.1 выше) · отчёт двери
теперь v2 (
tm-bank-decisions-report-v2: moderefused/stopped/write_incomplete, пофайловыеwritten_*) — еёreadEngineвыбрасывает stdout при ненулевых кодах, прежний пинг об этом стал острее: класс 15 БЕЗ отчёта неотличим от «ничего не легло» · новый exit 15 в полосе 10–19 читается её ридером как refused по построению полосы — ратификация значения на оркестраторе при лендинге. - Полигону:
eval/bank_autonomy/parse_common.pyпарситmined-signature.yaml— карта теперь несёт верхние ключиmap_version/map_id(лежащие артефакты coldrun не тронуты; новые прогоны будут в новом жанре). - Фронту: экран подписи, читающий
signature.undecidedиз отчёта двери, обязан перестать трактовать его как «стоп не погаснет» — поле информационное (D39.144), контракт поля пере-описан в коде. - Майнерский хвост за потолком структурно недостижим (§4.4, НЕ чинилось по заказу): потолок эмиссии
(200) режет ранжированный пул ДО фильтров пригодности/сида/отказов (
miner_emit.go,ranked[:emitRankCap]доemissionEligible). Пере-замерено своей командой (числа прежнего сплошного читателя в дерево не попали): 2354 ранжированных · 209 годных во всём алфавите · 11 в окне потолка · 198 невидимы постоянно; отклонение всех годных окна не подняло ни одного из хвоста (FINDINGS§38). Первоисточник замера — постоянный якорь-пинinternal/miner/emissioncap_test.go: он утверждает ТЕКУЩЕЕ поведение и покраснеет в день сдвига потолка или порядка фильтров, приведя двигающего к этому пингу. Двигать потолок — трогать фрозен-паритет; отдельное решение. - Гипотеза «подписание промахивается мимо чекпоинтов терминолога и пере-оплачивает роль» механизмом НЕ подтверждена (§4.13): память предъявленного входов чекпоинта не трогает; если перерасход существует — он существовал и до пака, отдельный предмет.
- Остаток оси арбитра (нашло воркфлоу-ревью, воспроизведено живьём): второй конфиг ТОЙ ЖЕ книги
(один каталог, один book_id, другой объявленный
project_db) пишет ту же пару файлов решений под ДРУГИМ локом — в т.ч. мимо flock живого прогона. Межкнижная версия снята конвенцией; эта — второй конфиг одной книги, т.е. рукотворная конфигурация оператора. Выбор лечения (второй арбитр на идентичности файлов решений или отказ при загрузке) трогает закон п.2 — решение не паку, пинг. Довод в коде сужен честно (bankdecisions.go, THE ARBITER).
✅ ИТОГ БЭКЕНД-СЕССИИ 25.08 — ДОФИКС ТОЙ ЖЕ ДВЕРИ по приёмке (docs/BACKEND_SEAM_FIX_SESSION_PROMPT.md). Дерево готово, НЕ закоммичено; продолжает дерево пака 24.08, а не заменяет его.
Все 16 пунктов §4 закрыты: блокер формата (дверь писала байты, которых её же парсер не читает, и любой
следующий вызов по книге — включая проекцию — падал) · пред-существующие поломки чинятся по одной ·
два ключа на один путь · гарды флагов на ПРИСУТСТВИЕ (--decisions= уходил на ПЛАТНЫЙ путь) · кап
документа решений · конверт путей на manifest --json · алиасы судятся по НАБОРУ · перевёрнутое окно
глав · честность отчёта о стопе · SIGTERM · десять слепых пятен гейта · цепь целиком в репозитории.
Доказательная база, замеры, попунктный чек и обе итерации ревью — backend/docs/SEAM_PACK_FINDINGS.md
§§14–30; здесь только то, что требует ДЕЙСТВИЯ.
✅ ⛔-ЗАКАЗ ПРИЁМКЕ ИЗ ПАКА СНЯТ. Цепь «стоп → bank-apply → резюм → стоп ГАСНЕТ» теперь живёт в
репозитории как $0-тест на фейковом провайдере (internal/pipeline/bankchain_test.go), на ОДНОМ проекте
от стопа до погасшего стопа. Довод пака «своими силами невозможно, надо дойти оплаченной черновой волной»
был шире правды: харнесс для этого уже был в репозитории. Мина №1 строки 199 (ливлок на status: auto) закрыта исполнением, а не рассуждением.
⚠ РАТИФИКАЦИЯ КЛАССА 14 — прежнее требование в силе, объём немного шире. Класс decisions_rejected
теперь несёт и отказ по КАПУ (документ больше, чем движок применяет за один акт): это факт о ЗАПРОСЕ, а
не о деплое, поэтому 10 был бы неверен. Носители полосы поднимает оркестратор при лендинге, как и
планировалось.
⛔ ПИНГИ ДОФИКСА (правок не делал):
exit 2при OOM платформа читает как успех — общедвижковый класс; кап удерживаетbank-applyот того, чтобы стать первым, кто до него доедет, но самого класса не снимает.- Каталог книги без права записи даёт
exit 1(вне полосы). Класс движка корректен и одинаков у всех глаголов — чинить надо чтение кода 1 на платформе, которая списывает проблему прав ХОСТА в бюджет попыток КНИГИ. - Проекция отвечает «что применится», а не «почём». Рекомендация — НЕ строить: глагол $0 по построению, поле «$0» было бы шумом. Решать оркестратору.
- Карта подписи не удаляется после погасшего стопа — пред-существующее; зафиксировано тестом как
текущее поведение. Честный ответ на «есть ли что подписать» — новое поле отчёта
signature.undecided. - Цена глагола Θ(N²) по построению — каждый пер-решенческий помощник сканирует весь документ. Именно поэтому кап на КОЛИЧЕСТВЕ стоит на 5 000. Поднимать его без индексации этих сканов нельзя.
- Апстрим-дефект
gopkg.in/yaml.v3 v3.0.1(эмиттер пишет блочный скаляр, который его же парсер не читает) вылечивается по-настоящему только скаляр-типом схемы с явным стилем или переездом наgo.yaml.in/yaml/v4(релиз-кандидат, смена module path в ДВУХ зонах). Мой обход несёт ссылку на исходник библиотеки и характеризационный тест, который покраснеет в день починки апстрима. - Фолд поверхностей Go-резидентный:
internal/text/norm.goдержитtrad2simpи катакана→хирагана в Go, а не в langpack'е. Пара, которой в репо нет, деградирует до NFKC+lowercase — не блокирована, но это ровно тот класс, о котором ревью-вопрос общности. Шире двери, поэтому пингом.
⚠ ЧТО В ЗАПИСИ ПАКА 24.08 (ниже) УСТАРЕЛО — читать её через эту поправку.
- Пинг 2, «таймаут: 1.6с на 5 000 термов, 9.1с на 20 000» — ЧИСЛА НЕВЕРНЫ, и это ровно тот датум,
которым платформенный пак будет мерить свой таймаут. Мой замер той же командой: 5 000
approve→ 5.2 с, 20 000 → 50 с; на минимальныхdecline(самая дешёвая форма, и потому та, которой байтовый кап пускает больше всего) 5 000 → 11.3 с, 12 000 → 58 с, 28 900 → 308 с. Брать надоFINDINGS§18 и §29 п.1, не эти. - Пинг 6 «однострочник при лендинге: документ решений не капирован» — СДЕЛАН. Капов теперь два (1 МиБ на чтение + 5 000 решений на применение), потому что байтовый не ограничивает время.
- Пинг 3 про флейки пере-снят сильнее: изолированный A/B против дерева HEAD даёт побайтно
одинаковое падение с обеих сторон —
FINDINGS§31.
⛔ ПИНГИ, КОТОРЫЕ ЖИЛИ ТОЛЬКО В FINDINGS И НЕ ДОЕЗЖАЛИ ДО ЖУРНАЛА (найдено проверкой согласованности):
карта подписи пишется обычным os.WriteFile мимо атомарной конвенции сайдкаров того же пакета
(пред-существующее) · цена доказывающего рендера ≈5 % времени, плюс notCanonical теперь тоже разбирает
документ · опубликованные пути двух файлов решений не несут версионного конверта (пинг пака §10.5) ·
схема сида без omitempty (пинг пака §10.6).
⚠ Два пред-существующих -race-флейка в internal/store не тронуты (TestKillMinus9LosesAtMostOneCall,
TestTheSeamIsNotChargedToTheStoreOperationBudget). База ДО правок, снятая на нетронутом дереве пака,
уже была красной по первому — это моя собственная атрибуция, а не наследованная.
⛔ ПИНГ, КОТОРЫЙ ТРОГАЕТ РАТИФИЦИРОВАННЫЙ ЗАКОН (п.2) — решать не паку. Арбитр двери — flock на
<project_db>.lock, а пишутся mined_delta/mined_rejects, которые book.yaml может направить куда
угодно. Две книги с РАЗНЫМИ project_db и ОДНИМ delta друг друга не исключают: воркфлоу-ревью
продемонстрировало гонку на 1500 одобрений с каждой стороны — одна сторона потеряла всё, exit 0, отчёт
«применено». Внутрикнижную версию этого §4.3 уже запрещает; межкнижная законна сегодня. Выбор — второй
арбитр или отказ при загрузке на путь вне каталога книги. В корпусе нарушителей нет. В коде стоит явное
«арбитр покрывает проект, а не пути», а не молчаливое допущение.
🔧 В репозиторий добавлен инструмент: backend/cmd/tmmutate — харнесс мутаций с каталогом из 36
посадок, у каждой названо СВОЙСТВО, за которое она отвечает, и записан ожидаемый исход. Три сессии подряд
писали такой инструмент в скретчпад и теряли его; приёмка при этом нашла восемь мест, где гейт был слеп.
⚠ Он дважды подводил и оба раза был починен по следу: сначала подсадил мутацию и прошёл собственную
sha256-самопроверку (эталон второй правки снимался с уже пропатченного файла), затем считал КРАСНЫМ провал
СБОРКИ — из-за чего две записи каталога, сломанные рефакторингом, целую итерацию числились пойманными
тестами, которые не могли отработать. Теперь: одно чтение и запись на файл, отпечаток всего каталога перед
каждой посадкой, зелёная базовая линия пакета ДО первой посадки и третий вердикт NOTHING, роняющий гейт.
FINDINGS §25 и §34.
✅ ИТОГ БЭКЕНД-СЕССИИ 24.08 — ПАК «ВХОДНАЯ ДВЕРЬ ШВА», движковая половина D39.156. Дерево готово, НЕ закоммичено, передаётся на лендинг.
Заказ §4.1–§4.6 выполнен: конвенционные дефолты mined_delta/mined_rejects (ключей не объявляет и
файлов заранее не создаёт никто) · глагол tmctl bank-apply --config <book.yaml> --decisions <doc.json> [--dry-run] ($0, идемпотентен побайтово, всё-или-ничего, занятый flock — ровно 12 неблокирующе, ответ
несёт версию и явное depth: edit_wave) · --keys-file у translate (строка 211) · строгость
сид-загрузчика (212) · status_version + artifacts{} с абсолютными путями (213) · дефолт
стендового корпуса маркерным резолвом (218, критерий оркестратора выполнен буквально).
Вся доказательная база, замеры и попунктный чек промта — backend/docs/SEAM_PACK_FINDINGS.md;
здесь только то, что требует ДЕЙСТВИЯ.
⚠ ТРЕБУЕТ РАТИФИКАЦИИ: заведён класс полосы отказов 14 decisions_rejected. Отвергнутый по существу
набор решений ≠ сломанный деплой: platform/internal/ingest/exit.go DeploymentFault относит 10 к
«условию, общему для всех книг хоста», и по 10 набор решений одного пользователя списался бы на
оператора. Старый читатель деградирует безопасно (Refused(14) ⇒ OutcomeRefused). 10 сохранён для
документа, не прочитавшегося КАК документ решений. Гейт тотальности таблицы добавлен.
⛔ ЗАКАЗ ПРИЁМКЕ — единственный незакрытый замер (согласован со сторонним архитектором). Цепь целиком
не гонялась ни разу: стоп красный → bank-apply → резюм → стоп гаснет. Части доказаны порознь, но
мина №1 строки 199 — livelock уровня ЦЕПИ, которого частичные тесты по построению не видят. Снять не
могу, и это проверено: банк-стоп на машине не воспроизводится (contrast_path → отсутствующий
eval/exp16/data/jieba_dict_general_zh.txt, строка 123), а до стопа надо дойти оплаченной черновой
волной. Команда: на КОПИИ книги на exit 3 скормить bank-apply документ на всю карту подписи, затем
translate --verify-bank. ДЕФЕКТ — стоп снова с ТЕМИ ЖЕ поверхностями; не дефект — свежая пачка
≤200 термов реверс-секции (мина №3 строки 199). До этого прогона вердикт по циклу — PLAUSIBLE.
⛔ ПИНГИ ЗОНАМ И СЛЕДУЮЩИМ ПАКАМ:
rubyToCandidatesмёртв в проде — единственный вызов из теста (memseed_test.go:204);seeding.go:36-38строитmanualSrcsи никуда не передаёт (Go молчит: запись в map = использование). СтрокSource:"ruby"в банке не возникает, а платформа держит для них ветку словаря (ingest/bank.gotermOrigin→OriginAnnotated).- Платформенному паку: первый контакт с непере-мигрированной книгой даёт exit 13 — воркер решений
обязан планировать
13 → migrate → повтор· проекция берёт тот же лок, поэтому правка термина при живом прогоне даёт 12 даже на превью, на всю длину прогона · таймаут: 1.6с на 5 000 термов банка, 9.1с на 20 000, бюджет платформы на вызов движка — 60с (runs/reconcile.go:280) ·bank-applyсоздаёт<project_db>.lockпри первом касании никогда не запускавшегося проекта. - ⚠ БАТАРЕЯ НЕ ДЕТЕРМИНИРОВАННО ЗЕЛЕНА, и это НЕ пак — прочесть ДО пере-рана. Два
пред-существующих
-race-флейка вinternal/storeсрабатывают примерно раз на 2–4 полных прогона (go test ./... -race -count=1×4 → 1 чист, 2-й красный). Красное именно в этих двух тестах ожидаемо; любое другое красное — регрессия. Тесты НЕ трогал (D39.121).TestTheSeamIsNotChargedToTheStoreOperationBudget,TestKillMinus9LosesAtMostOneCall. Чередующийся A/B наgit worktreeHEAD: оба падают на HEAD не реже (kill92/30 против 0/30;seam2/30 против 1/30; без-race0/30). Покрытие:LockProject/Releaseэтими тестами не исполняются вовсе. ⚠ 0/30 против 2/30 НЕ значит «пак улучшает» — на таком числе это шум (Фишер p≈0.5); достаточно того, что флейк живёт на дереве, которого пак не касался. - Гейт
TestDispatchCommandsCoversTheSwitchслеп кcaseс константой (считает только*ast.BasicLit) — команда, объявленная константой, невидима гейту, чей смысл в дефекте строки 176. Я вернулся к литералу (конвенция файла), дыра не эксплуатируется. redrive— платный путь без канала ключей аргументом. Промт: «флаг только уtranslate», сделано ровно так; канал у него есть (конвенционный.env), платформа его не зовёт. Развилка следующему паку.- Однострочник при лендинге (не блокер): документ решений читается неограниченным
os.ReadFile, тогда как платформа свои чтения от движка капает. Документ на 10 000 решений ≈2МБ ⇒ кап 1–16МБ.
⚠ ПРАВИЛА, ВЫНЕСЕННЫЕ ИНЦИДЕНТАМИ — для следующих сессий, не про этот пак. Прогон харнесса мутаций
был убит таймаутом, finally не отработал, и посадка просидела в дереве ~40 минут, выглядя
продакшн-кодом; сторонний ревьюер снял с него замеры и доложил несуществующий дефект. Поймал посадку
собственный пин пака. Отсюда три правила: харнесс мутаций обязан фингерпринтить цели (починено) ·
снимай отпечаток дерева перед сборкой бинаря замера (на этом наступили обе стороны) · одиночный
прогон — не замер (атрибуцию флейков я дважды вывел неверно из одиночных прогонов).
Что НЕ доказано: рантайм-вердикт по платному пути — PLAUSIBLE. Доказано, что ключ из
--keys-file доезжает до заголовка и что без флага прогон отказывает конфигом; не доказано, что
реальный провайдер примет ключ и что SaaS положит файл по этому пути — платформенная половина строки
211, чужая зона. Живой translate не гонялся: санкции на платные вызовы у пака нет. (24.08)
⛔ ПИНГ ОРКЕСТРАТОРА №19 — 23.08, ЗОНЕ БЭКЕНДА. Четыре движковых дефекта, все сверены моими командами.
-
ОТВЕТ НА ПИНГ ПОЛИГОНА: дефект ПОДТВЕРЖДЁН, он ваш. Эскалация на Gemini теряет инъекцию банка памяти (строка 208). Механизм пере-проверен:
pipeline/render.go:256-258=Role: "system", Content: injection, CacheBoundary: falseштатно строит ВТОРОЕ системное сообщение, аllm/httpllm.go(до-паковые строки 517-523, якорь ИСТОРИЧЕСКИЙ — сигнатура сменилась лендингом D39.164: функция приняла осьmode SystemMessagesModeи под квирком СКЛЕИВАЕТ системный ряд, так что описанного здесь «один-в-один» больше нет) копирует сообщения дословно — склейки нет нигде. ⚠ Лекарство того же класса в проекте УЖЕ написано и работает для другого провайдера:llm/provider_anthropic.go:169-179=inSystemPrefix := trueсворачивает ведущий system-префикс в одно поле. Не обобщено на Gemini — это и есть работа. Полигон ждёт ответа с 22.08 и починил у себя по вендор-доке; их находка верна. -
Род не производится авто-путём вовсе (строка 210, дополнена 23.08): замка ДВА и они независимы, а поле
Genderв схеме сида УЖЕ есть — ось мертва в ПИСАТЕЛЯХ, не в формате. -
Выпавший член юнита исчезает из отгружаемых байт БЕЗ внутритекстового маркера —
pipeline/waverun.go:487-490=the flagged member is DROPPED from the edit. Родня строки 193; для читателя это молчаливая дыра в тексте. -
Загрузчик сида НЕстрогий (строка 212): голый разбор YAML без проверки имён ключей, и
seed-lintэтого не видит. Опечатка в имени поля молча теряется — в файлах, которые владелец правит руками чаще всего.
⚠ Плюс строки 211 (движок на SaaS не получает провайдерских ключей — блокер живого прогона) и 213 (платформа дублирует вашу конвенцию пути): обе половинные, движковая часть ваша.
⛔ ПИНГ ОРКЕСТРАТОРА №20 — 22.08, ЗОНЕ БЭКЕНДА: три ваших дока разошлись с деревом (аудит доков, сверено кодом; рукой не лезу — ваша зона).
backend/README.md, карта пакетов объявлена сверенной по коду, а в ней НЕТinternal/runevents— эмиттера журнала прогона, то есть ВСЕГО шва движок↔платформа (D39.131), — и нет второго бинаряcmd/tmvet. Греп:runeventsиtmvetв файле по нулю вхождений, при том что оба каталога в дереве.backend/README.md, «Известный техдолг» держит живыми Cyrillic-хардкоды DC-чекеров, которые сам код называет ПОГАШЕННЫМ долгом (фаза 2 общности, D39.64:isRuTargetудалён,TargetActive/TargetScriptNonLatin), и оба егоfile:line-якоря указывают мимо.- (дописано 24.08)
backend/README.md:47=/home/ubuntu/books/gu-zhenren/зовёт книгу-стенд по МЁРТВОМУ пути/home/ubuntu/books/gu-zhenren/— каталога нет ни там, ни в$HOME: книги переехали в<репозиторий>/booksи версионируются своим git (D39.157 п.2). Там же фраза «тексты и производные ВНЕ git» стала неточной: вне ЭТОГО git. Тем же касанием — три тест-хелпера, резолвящие корпус от$HOME/books(строка 218); они уже в заказе движкового пака шва §4.6, так что дублировать правку не надо, но док обязан сойтись с ними. backend/docs/components.puml— диаграмма, которую карта доков продаёт как правимую «одним коммитом с кодом», отстала примерно на месяц: старый exit-контракт (без 4/5 и полосы 10–19), неполный список глаголов CLI, удалённый паком-17failover.goи ни следа эмиттера. ⚠ Рендерить её в svg/png НЕ надо (гардрейл) — править исходник.
(Пак «честные числа и статусы» — ИСПОЛНЕН, ПРИНЯТ С ФИКС-ЛИСТОМ и ЗАЛЕНДЕН f840867 (17.08; D39.149, ФЧ-5 — D39.150). Отчёт, две волны адверсариального ревью, мутационная приёмка и тело фикс-листа ФЧ-1…ФЧ-8 — в archive/PROGRESS-2026-08-17.md; живой остаток — строка бэклога 197.)
(Пинги закрытых паков — фикс-пак банка D39.118, блокеры контракта D39.122 — в archive/PROGRESS-2026-08-04-09.md, D39.125.)
(Закрытые бэкенд-записи 01–02.08 — общность фаза 2 · качество банка (оба этапа) · фикс-пак банка · finding-1 · пакет-чекеров · мелкая пачка · coldrun-b · ручка эффорта — в archive/PROGRESS-2026-08-01-02.md.)
(Закрытые бэкенд-записи 14–15.08 — эмиттер шва (D39.131) · tmctl migrate (D39.134) · пере-пин цен DeepSeek (D39.137) — в archive/PROGRESS-2026-08-14-15.md; вынесено D39.139.)
(Закрытая хроника пакетов №0–№4 (04–10.07) перенесена в archive/PROGRESS-2026-07-04-10.md — ревизия D31.)
(Хроника пакетов 11–12.07 (пакет-5, D15.2-этап-А, санитайзер-фикс D33) — в archive/PROGRESS-2026-07-10-13.md.) (Трек-A пак-1/1.5 (D39.2/D39.5) — см. записи оркестратора №6 выше.)
(Хроника бэкенд-паков 11–16 (19–25.07, вкл. отчёт-запись пака-15) — в archive/PROGRESS-2026-07-13-25.md; отчёты паков — archive/reports/.)
(Закрытые записи 25–31.07 — пак-18 · мини-прогон · фикс-пак · сквозная проверка · хендофф 26.07 · ресёрч общности фаза 1 — в archive/PROGRESS-2026-07-25-31.md.)