11 KiB
План дофикса «входная дверь шва» (по промту docs/BACKEND_SEAM_FIX_SESSION_PROMPT.md)
Бэкенд-сессия 25.08.2026, продолжает незакоммиченное дерево пака. Заказ — 16 пунктов §4
(grep -cE '^### 4\.' → 16). Записка обязана быть комплектной механически, поэтому таблица ниже
перечисляет ВСЕ шестнадцать, включая те, которые заканчиваются аргументированным отказом.
Базовая точка (снята ДО правок)
make battery на нетронутом дереве пака: EXIT=2, красен ровно
TestKillMinus9LosesAtMostOneCall — один из двух названных промтом пред-существующих -race-флейков
(internal/store). То есть флейк воспроизвёлся на дереве, к которому я ещё не прикасался; это моя
собственная атрибуция, а не наследованная.
Что уже замерено до кода (§4.1, корень)
gopkg.in/yaml.v3 v3.0.1, проба вне рабочего дерева, матрица «значение → рендер → разбор» на обоих
документах. Итог шире, чем говорит промт, и шире, чем говорила записка прошлой сессии:
| значение поля | что рендерится | round-trip |
|---|---|---|
"\nтекст" |
note: |4- + строка |
не разбирается (did not find expected key) |
"\n\nтекст" |
|4- + пустая строка |
не разбирается |
"\n\tx" |
|4- + таб |
не разбирается |
"\n" |
|4+ |
разбирается, но значение "" — тихая потеря |
"\n x" |
|4- + 10 пробелов |
разбирается, но значение "x" — тихая потеря |
"текст\n", "a\nb", " x", "\tx", "\r\nx" |
скаляр/блок | ок |
Два вывода, оба несущие:
- Клейм промта «бьёт по ЛЮБОМУ свободному текстовому полю» ВЕРЕН, а поправка записки прошлой
сессии («
dstиsenseне ломаются») — НЕТ: ломается любое строковое поле обоих документов (проверено наsrc/dst/sense/noteи наrejects[].note). Триггер — ведущий\n, а не поле. - «Документ разбирается» — недостаточный инвариант. Две формы разбираются и МЕНЯЮТ значение.
Заказанная §4.1 проверка
render → parseих пропустит: дверь отчитаетсяapplied, файл загрузится, а заметка владельца будет другой. Инвариант обязан быть «прочиталось И совпало».
Механика (тоже замерена): дефект — рассогласование индикатора отступа блочного скаляра с реальным
отступом родителя внутри элемента последовательности; на глубине 1 ({note: "\nx"} без - ) тот же
вход рендерится и читается корректно, а SetIndent(2) случайно попадает в согласие. Путь «починить
рендер стилями yaml.Node» закрыт: (*yaml.Node).Encode внутри сам гоняет marshal→unmarshal и
падает на том же входе — узел построить нельзя.
Порядок работ
Волнами, снизу вверх: формат → чистая семантика → конфиг/CLI → обвязка → пины. Батарея после каждой
волны, make battery-stand в конце.
| № | что делаю | где |
|---|---|---|
| 4.1 | нормализация текстовых полей документа (TrimSpace, ОДНО правило на все поля обеих схем) + рендер, ДОКАЗЫВАЮЩИЙ себя: parse(render(A)) обязан совпасть с нормализованным A, иначе ошибка. Проверка распространяется на ОБА документа; байты, которые дверь проверила, она же и пишет (рендер один, не два). Фаззер пути ДВЕРИ: произвольные строки полей Decision → ApplyDecisions → рендер → разбор |
seed, membank |
| 4.2 | пред-существующая проблема опознаётся по СУБЪЕКТУ: многосубъектный вердикт загружаемости раскладывается по термам до сравнения до/после |
membank |
| 4.3 | config.LoadBook отказывает при совпадении путей. Шире буквы заказа на одну строку: попарно различны должны быть четыре пути, которые движок пишет или читает как РАЗНЫЕ форматы (project_db, glossary_seed, mined_delta, mined_rejects) — project_db == mined_delta сегодня означало бы YAML поверх sqlite. Проверю на всех book.yaml репозитория и стенда, что живых нарушителей нет |
config |
| 4.4 | оба гарда — на ПРИСУТСТВИЕ флага через fs.Visit (прецедент ceilingGiven в том же файле) |
cmd/tmctl |
| 4.5 | кап на размер документа решений + строка отказа полосой. Число выбираю после СВОЕГО замера памяти (методика будет названа); хвост про exit 2 при OOM — пингом | pipeline |
| 4.6 | конверт путей на поверхности, которую потребитель читает (manifest --json). Компромисс назову вслух: манифест — про дерево глав, путь артефакта там гость |
pipeline |
| 4.7 | правило алиасов судит НАБОР: одобряемые тем же вызовом термы участвуют в проверке aliasOwner |
membank |
| 4.8 | перевёрнутое окно глав (until < since, оба ненулевые) — отказ |
membank |
| 4.9 | вероятно отклоню как предсказание и заменю на факт. Дверь не знает, сколько поверхностей осталось за капом реверс-секции — это знает майнер на следующем проходе. Кандидат: отчёт называет, что решил ЭТОТ вызов, и не читается как «стоп погас». Решу замером, видит ли дверь остаток вообще | pipeline |
| 4.10 | обработчик SIGTERM: бросить работу, отпустить лок, не записать ничего. Сначала замерю длительность вызова ПОСЛЕ капа §4.5 — если максимум по капу это десятки миллисекунд, скажу это аргументом |
pipeline/cmd |
| 4.11 | десять посадок (строка (д) — три), пин на каждую, каждый краснеет на своей мутации. Харнесс мутаций пишу заново с отпечатком целей до/после; кладу его в репозиторий — приёмка сажает мутации тоже, а инструмент каждый раз пишется с нуля | все |
| 4.12 | тест цепи на фейковом провайдере (miningstop_join_test.go-харнесс): стоп → bank-apply → резюм → стоп погас, редакторская волна пошла. Плюс явная фиксация, что карта подписи после погасшего стопа остаётся на диске |
pipeline |
| 4.13 | восемь мелочей: по каждой решение и довод, чиню или отклоняю — списком в отчёте, без «кажется» | разные |
| 4.14 | довод отказа --keys-file покрывает всех, кого ветка отвергает (redrive — платный, backup/migrate — деплой-шаги). Развилку про канал ключей redrive НЕ решаю |
cmd/tmctl |
| 4.15 | три существующих пина: вердикт Preexisting исполнить всеми четырьмя проверками · четвёртый оракул фаззера снять с тавтологии · TestDecisionByBankID сверять с НЕЗАВИСИМО посчитанным id |
тесты |
| 4.16 | платных вызовов ноль. Рантайм по платному пути остаётся PLAUSIBLE | — |
Развилки, которые понесу владельцу/оркестратору (§11)
- §4.1 шире заказа. Заказанный round-trip
render → parseне ловит две тихие потери значения; делаю строже («прочиталось И совпало») и говорю об этом прямо, потому что это меняет ответ двери на входы, которые заказ считал безопасными. - §4.3 шире буквы на одну проверку — см. таблицу.
- §4.9 — скорее всего отказ от предсказания в пользу факта.
- §4.10 — возможен ответ «механизм без носителя после §4.5»; решит замер, не рассуждение.
- §4.6 — сделаю, компромисс назову.
Чего НЕ делаю
Пинги приложения «дофикс НЕ исполняет» (exit 2 при OOM, readEngine платформы, канал ключей
redrive, rubyToCandidates, слепота TestDispatchCommandsCoversTheSwitch к константам, схема сида
без omitempty, лок на проекции, карта подписи после стопа) — не «допиливаю попутно». Механизм против
капа реверс-секции не строю. Пере-именование банк-экспорта не трогаю. Словарь решений не расширяю.