Re-aim the consistency rows at the axis the product actually has: a bank is signed whole, and the code decides by a per-term state the model does not carry

This commit is contained in:
heaven 2026-09-11 10:56:51 +03:00
parent 7046d88730
commit 545a8b200a
3 changed files with 4 additions and 2 deletions

View file

@ -3,7 +3,7 @@
> **Единственный трекер проекта.** Здесь живут строки, на которые доки, промты и D-ноты ссылаются словами «строка N» / «строка бэклога N»: **ID строки стабилен навсегда**, не перенумеровывается и не переиспользуется (D39.80). Правки — только через оркестратора; каждая петля обязана иметь диспозицию: решено / отложено-с-записью / отклонено.
> ⚠ **Это НЕ бэклог зоны `docs/`, а бэклог ПРОЕКТА.** У зон свои, с другими неймспейсами ID, и единый их строк не принимает (D39.84): платформа — [../platform/BACKLOG.md](../platform/BACKLOG.md) (`П-N`) и её регистр дефектов `platform/docs/DEFECT_REGISTER.md` (`PD-N`); фронт — [../frontend/docs/BACKLOG.md](../frontend/docs/BACKLOG.md) (`Ф-N`).
> ⚠ **Состояние проекта — не здесь.** Очередь, курс, CURRENT-STATE, состояние паков и живая хроника — шапка [PROGRESS.md](PROGRESS.md). Здесь только долг и его диспозиции.
> - **СЧЁТ ОЧЕРЕДИ на 11.09 (скриптом по таблице — `python3 docs/scripts/counts.py`; обновлять при каждом лендинге):** всего **304** строк · зона бэкенд **146** строго / **198** широко (⚠ колонки счётчик читает С КОНЦА — испр. D39.116) · **блокеров очереди 0** (236 закрыта D39.175; **371** — актом D39.233, **360** — актом D39.232, обе 10.09), платные прогоны разблокированы · «скоро» **150** (перечень — грепом по таблице, рукописный список снят D39.126) · гейт-строка эксп-22: 153 (плюс 150 — руки владельца; ⚠ 55 из гейтов СНЯТА — D39.198 п.5); строка 5 — остаток гейчен ре-пробой 74, носитель события теперь строка 188 (аудит D39.140); остальное «когда-нибудь». ⚠ Счёт — НИЖНЯЯ граница долга, не потолок (разбор — легенда таблицы ниже).
> - **СЧЁТ ОЧЕРЕДИ на 11.09 (скриптом по таблице — `python3 docs/scripts/counts.py`; обновлять при каждом лендинге):** всего **304** строк · зона бэкенд **146** строго / **198** широко (⚠ колонки счётчик читает С КОНЦА — испр. D39.116) · **блокеров очереди 0** (236 закрыта D39.175; **371** — актом D39.233, **360** — актом D39.232, обе 10.09), платные прогоны разблокированы · «скоро» **149** (перечень — грепом по таблице, рукописный список снят D39.126) · гейт-строка эксп-22: 153 (плюс 150 — руки владельца; ⚠ 55 из гейтов СНЯТА — D39.198 п.5); строка 5 — остаток гейчен ре-пробой 74, носитель события теперь строка 188 (аудит D39.140); остальное «когда-нибудь». ⚠ Счёт — НИЖНЯЯ граница долга, не потолок (разбор — легенда таблицы ниже).
> - ⚠ **Переезд 06.09 (D39.218):** таблица вынесена из `PROGRESS.md` ДОСЛОВНО и ни один ID не сдвинут — **с единственным исключением: две ячейки (строки 220 и 306) тронуты РОВНО в номере якоря `docs/scripts/counts.py:566`→`:569` и `:592`→`:595`**, потому что цель сдвинул этот же коммит; текст ячеек не менялся, длины равны. В `PROGRESS.md` на прежнем месте оставлен заголовок-указатель, поэтому ссылки «секция „Бэклог“» доезжают в один хоп.
## Бэклог (ЕДИНЫЙ, собран 26.07, актуализация 04.08 D39.99/D39.101; правки — только через оркестратора)
@ -328,7 +328,7 @@
| 404 | ⚠ **СТРОКА ПЕРЕ-ПИСАНА 11.09: её центральное утверждение было МОЕЙ ОШИБКОЙ.** Первая редакция говорила, что мутация с уехавшим якорем «не краснеет, перестаёт сажаться, и в отчёте „не посадилась“ неотличимо от „пережила“», и что механизма против этого НЕТ. **Механизм есть, и он в самом `tmmutate`:** запись с уехавшим якорем получает вердикт `rotted`, печатается отдельной строкой и **засчитывается как неожиданный исход — прогон завершается ненулевым кодом**; довод записан в самом инструменте (`backend/cmd/tmmutate/main.go`, греп `an entry whose anchor moved guards nothing`). Пере-снято мной по возражению движковой сессии, которая в этот класс наступила и была поймана СВОИМ ЖЕ прибором: `make mutations` дал `MAKE-EXIT=2 · RED 151 · SURVIVED 0 · ROTTED 1`, и протухшей оказалась ЧУЖАЯ запись, сломанная её правкой. ⛔ **ЖИВОЙ ОСТАТОК КЛАССА — не мутации, а ДОКИ И КАТАЛОГИ, где такого счётчика нет.** Линтер доков сверяет ПО СОДЕРЖИМОМУ только якоря опт-ин токен-формы; голый `файл:строка` он не видит по построению, и его протухание не даёт ни красноты, ни строки в выводе (замер 10.09: из 19 голых якорей живых секций реестра долга съехали 10, при 9 из 9 целых токен-формных). ⭐ И побочный урок, названный сессией: знаменатель проверки якорей надо брать ИЗ КАТАЛОГА, а не из своих правок — она проверила три свои записи и не проверила чужую, которую сломала | доки | скоро | у голых `файл:строка` в живых доках есть счётчик, дающий ненулевой выход, — либо они переведены в токен-форму | находка движковой сессии 11.09, пере-снята оркестратором |
| 405 | **РАЗМЕН ПО СТРОКЕ 375 ИМЕЕТ НАЗВАННУЮ ЦЕНУ: проекция расходится с леджером на оборванной попытке.** Починка «обрыв не стирает уже заработанный вердикт» (заландена `3084766`) оставляет позиции прежний `cost_usd`, поэтому деньги ОБОРВАННОЙ попытки в попозиционную проекцию не добавляются: **леджер полон, проекция нет**. Названо самой движковой сессией при сдаче, а не найдено потом. ⇒ тот, кто будет сверять проекцию с леджером на книге, где были обрывы поверх отгруженных позиций, увидит расхождение и не должен принять его за потерю денег — деньги в леджере. ⚠ Заведено ОТДЕЛЬНОЙ строкой намеренно: это цена размена, который оркестратор утвердил осознанно (потеря отгруженного текста хуже неточности отчёта), и она обязана стоять рядом с ним, а не всплыть через месяц | бэкенд | когда-нибудь | попозиционная проекция и леджер сходятся на книге с обрывами поверх отгруженных позиций, либо расхождение объявлено в самой проекции | сдача движковой сессии 11.09 |
| 406 | ⛔ **КОНСИСТЕНТНОСТЬ КНИГИ НИКТО НЕ СПРАШИВАЕТ — ПРИБОРА ПО ОТГРУЖЕННОМУ ТЕКСТУ НЕТ ВОВСЕ.** Мера «сколько РАЗНЫХ передач дал один термин» ПОСТРОЕНА (`Spread`/`Variants`, `backend/internal/pipeline/mining.go:383-384`), но считается по ЧЕРНОВИКУ, на стопе майнинга, ДО редакторской волны, и читает её только человеческая таблица подписи. По ФИНАЛЬНОМУ тексту такой меры не существует ни одной. ⇒ приоритет №1 владельца («консистентные термины на всю книгу») сегодня НЕПРОВЕРЯЕМ в принципе: все четыре A/B, показавшие пользу банка, меряли ПРИСУТСТВИЕ инъектированной формы в чанке, а не отсутствие конкурирующей. **Лечение $0 и переиспользует готовое:** тот же счёт по отгружаемому тексту + строка отчёта сборки «термин X отдан тремя формами в главах 12, 340, 901». Предмет не пуст: полигонный прибор на стенде дал 1316 % терминов с более чем одной передачей. ⚠ Это ЕДИНСТВЕННАЯ работа, которая делает качество ПРЕДЪЯВИМЫМ; без неё кривую деградации по главам снять не с чего | бэкенд | **скоро** | счёт расхождения форм по отгруженному тексту + строка отчёта сборки | аудит банка 11.09, `research/34` §2.1 | ⛔ **ИСПОЛНЕНО ЧАСТЬЮ 11.09 ПРОГОНОМ A, и первый же результат снял мою же формулировку слепого пятна.** Прибор построен полигоном и дал по отгруженному тексту «0 терминов из 40 отданы более чем одной формой». ⚠ **Ноль держался на том, что прибор НЕ СМОТРЕЛ:** кандидаты искались регуляркой, требующей ЗАГЛАВНОЙ буквы (`[А-ЯЁ][а-яёА-ЯЁ-]+`), и склонённые строчные формы («гу-мастера», «наложницей») отпадали ДО правила сравнения. Я заказал переписать правило сравнения пословно — **заказ бил мимо**: критик применил этот рецепт к прибору на боевых данных, и не вернулся НИ ОДИН из 29 потерянных термов. Починка ГЕНЕРАЦИИ кандидатов на тех же данных даёт **48 найденных вместо 40 и шесть строк со `spread ≥ 2`** там, где печатался ноль. ⚠ И заголовочный «0» неустойчив к порогу складывания: под пословным правилом `沈翠` распадается на «Шэнь»/«Шэнь Цуй» и число становится 1. ⇒ остаток ряда: прибор по ФИНАЛЬНОМУ тексту с (а) генерацией кандидатов без регистрового фильтра, (б) названным порогом складывания, (в) замеренной чувствительностью к нему.
| 407 | **ПОСТ-ПРОВЕРКА БАНКА СПРАШИВАЕТ НЕ ТО: присутствие формы ГДЕ-НИБУДЬ в чанке вместо формы НА МЕСТЕ срабатывания, и про конкурирующую передачу не спрашивает никогда.** `backend/internal/membank/mempostcheck.go` — вопрос bag-of-words по всему чанку ⇒ дрейф ВНУТРИ составного имени невидим по построению. Замерено исполнением на копии: ряд `方源`→«Фан Юань» с алиасом `古月方源`, выход «Гу Юэ Фан Юань» даёт 0 промахов при подписанном каноне `古月 → Гуюэ`; контроль рядом (форма реально отсутствует) даёт 1 промах, то есть прибор спрошен и отвечает. ⚠ **У экземпляра ДВА корня, и смена вопроса закрывает только один:** ряд `古月` съеден равнотрастовым длиннейшим матчем (`memory.go` `suppressContained`) МОЛЧА. Дешёвая половина — проверять алиас-ключ на СОБСТВЕННУЮ канонную форму (день); дорогая (детектор значения по исходнику) — ряд **286**, загейчен замером. ⚠ Класс объявлен в дереве с 06.09 (`experiments/23-editor-tier.md` §Д50.3) — новизна нулевая, ряд заводится как НОСИТЕЛЬ, которого у него не было | бэкенд | скоро | вопрос пост-проверки + видимость подавления вложенного ряда | аудит банка 11.09, находка `K3` (единственная пережившая верификацию) |
| 407 | **ПОСТ-ПРОВЕРКА БАНКА СПРАШИВАЕТ НЕ ТО: присутствие формы ГДЕ-НИБУДЬ в чанке вместо формы НА МЕСТЕ срабатывания, и про конкурирующую передачу не спрашивает никогда.** `backend/internal/membank/mempostcheck.go` — вопрос bag-of-words по всему чанку ⇒ дрейф ВНУТРИ составного имени невидим по построению. Замерено исполнением на копии: ряд `方源`→«Фан Юань» с алиасом `古月方源`, выход «Гу Юэ Фан Юань» даёт 0 промахов при подписанном каноне `古月 → Гуюэ`; контроль рядом (форма реально отсутствует) даёт 1 промах, то есть прибор спрошен и отвечает. ⚠ **У экземпляра ДВА корня, и смена вопроса закрывает только один:** ряд `古月` съеден равнотрастовым длиннейшим матчем (`memory.go` `suppressContained`) МОЛЧА. Дешёвая половина — проверять алиас-ключ на СОБСТВЕННУЮ канонную форму (день); дорогая (детектор значения по исходнику) — ряд **286**, загейчен замером. ⚠ Класс объявлен в дереве с 06.09 (`experiments/23-editor-tier.md` §Д50.3) — новизна нулевая, ряд заводится как НОСИТЕЛЬ, которого у него не было | бэкенд | скоро | вопрос пост-проверки + видимость подавления вложенного ряда | аудит банка 11.09, находка `K3` (единственная пережившая верификацию) |**ИСПР. 11.09 ПО СЛОВУ ВЛАДЕЛЬЦА — РЯД БЫЛ НАПИСАН ПО НЕСУЩЕСТВУЮЩЕЙ ОСИ.** Слово: «нет такого понятия [подписанный термин], подписан либо ВЕСЬ банк, либо он в неконсистентном состоянии; есть вариант поставить галочку скипать подпись с фронта — тогда автоподписывание». Это ратифицировано `D39.144`: подписывается банк ЦЕЛИКОМ, пер-термная подпись прямо названа НЕ моделью продукта, дефолт движка — авто-продолжение с неподписанным банком, строки едут С ПОМЕТКОЙ. ⇒ **настоящий дефект глубже, чем «прибор не видит дрейфа»: в коде живёт пер-термный автомат `auto|draft|approved` (`backend/internal/store/migrate.go:192`), и пост-проверка считает нарушением ТОЛЬКО `approved` — то есть принимает решение по ЕДИНИЦЕ, КОТОРОЙ В ПРОДУКТОВОЙ МОДЕЛИ НЕТ.** Это и есть причина нуля при 18 найденных (строка **419**): сломана не поверхность, а ОСЬ решения. Закон `D39.104` на проводе один для всех строк; состояние книги — «подписана целиком» либо «авто-продолжение», и мерить надо им.
| 408 | **ДАННЫЕ БАНКА НЕ ДОСЕЯНЫ, И ИМЕННО ИЗ-ЗА ЭТОГО ГЕЙТ КОНСИСТЕНТНОСТИ НЕЛЬЗЯ ВКЛЮЧИТЬ.** Точность глоссарного класса чекера — **0,067: одно верное срабатывание на 14 ложных (n=258)**, и ложные сконцентрированы: `转` ×6, `蛊虫` ×4, `元石` ×2 (`books/gu-zhenren/labels/metrics.json`). Три дыры, все в ДАННЫХ, не в Go: (а) глагольные и многословные термины засеяны с пустыми формами — один `炼化` дал 7 ложных промахов; (б) односимвольный ханьский ключ структурно вне автомата без `allow_short` (порог 2 знака, `membank/memory.go:71`), а это самый частый класс канона в китайском ранобэ (蛊, 道, 气); (в) сид-линт об этом молчит. ⚠ Владелец 05.09 отложил гейт до замера ложных срабатываний («если он ложно положительно будет стрелять — это плохо, очень плохо») — вот их источник, и он лечится досевом, а не кодом | бэкенд+полигон | **скоро** | досев форм · `allow_short` у односимвольных · линт сида, который об этом кричит | аудит банка 11.09, `research/34` §2.3 |
| 409 | **РЕДАКТОР — ИСТОЧНИК РАЗНОБОЯ, А НЕ СТРАХОВКА ПОВЕРХ БАНКА, и это замерено дважды.** Без закон-блока редактор ломает 512 из 20 уже ВЕРНЫХ клеток черновика (`experiments/18-editor-wire-probe.md` §A.1); с подключённым банком боевой редактор держит ХУДШЕЕ покрытие канона в панели — 0.882 против 0.909 у черновика, который он правит (`experiments/22` §6.2, 1124 упоминания). Два механических носителя: черновая волна выбирает по БАЗОВОМУ банку с исключением намайненного (`bankmaterialize.go:329`) ⇒ на первом прогоне книги черновик идёт вообще без добытого банка; редакторская волна, единственная с полным банком, теряет липкость МЕЖДУ правочными единицами внутри главы (`waverun.go:717`) при **86 % многоединичных глав (1962 из 2283)**. ⇒ закон-блок обязан стать инвариантом конфига, а не следствием выбора модели редактора. ⚠ Инцидентов дрейфа от потери липкости — НОЛЬ наблюдений, замерена только экспозиция: правка без замера была бы стрельбой вслепую, замер снимается прогоном A | бэкенд | скоро | закон-блок инвариантом конфига + решение по липкости между правочными единицами | аудит банка 11.09, `research/34` §2.4 |
| 410 | **ГОЛОСА — УЗЕЛ БЕЗ ПРОВОДА: мёртв в четырёх местах сразу, и ни одного числа за всю историю проекта.** Нет данных (0 непустых секций `voices:` из 47 сид-файлов дерева, 21 пустая из 22), нет производителя (майнер профили не эмитит), нет инъекции (`InjectVoice` — константа `false` без ручки, `bankmaterialize.go:295`), проверка не запущена (`gates.voice` — 0 в конфигах, флаггер объявлен «PURE observability»). ⚠ **И это ВОПРОС ВЛАДЕЛЬЦУ, а не задача:** ратифицированный список 05.09 ставит в приоритет №1 ТОЛЬКО термины (голос — №3), а канон проекта говорит «термины/голоса» — пока это не одно требование, сессия, собранная по такой формулировке, будет строить от неверной цели. Второй вопрос в связке: подпись профилей владелец снял, а реестр физически заполняла только она — если не подпись, то кто | бэкенд/владелец | скоро | ⚠ сначала СЛОВО ВЛАДЕЛЬЦА о месте голоса в приоритете, форма после него | аудит банка 11.09, `research/34` §2.5 и §4 п.2 |

View file

@ -106,6 +106,7 @@ API не было: 04.09 упёрлось в потолок (`PD-440`, с тех
на факт, а в дереве её не было ни строкой — «известное со слов» не носитель.
- ✅ **Остановка остаётся ЖЁСТКОЙ, деньги терять ДОПУСТИМО, но остановка обязана быть КОРРЕКТНОЙ** — без
гонок, без половинчатых состояний, с верным возобновлением (`D39.240`).
- ✅ **ГОЛОС ВХОДИТ В ПРИОРИТЕТ №1** (слово 11.09: «Входит»). Прежнее расхождение канона проекта («термины/голоса») и ратифицированного списка 05.09 (голос №3) снято. ⛔ **Форма работы задана тем же словом: проектирует и контролирует голос FABLE, исполняет ОПУС** — сессии обсуждают имплементацию с агентом Fable 5, а не решают сами. Носитель предмета — строка бэклога **410** (голос мёртв в четырёх местах и не имеет ни одного числа за историю проекта).
- ✅ **Автономия смены (11.09):** решения принимаю сам, советуясь со старшим коллегой; мерило — главные
ценности продукта (качественный консистентный перевод длинных книг), затем архитектура и чистый код,
необходимый рефакторинг и отсутствие велосипедостроения.

View file

@ -88,6 +88,7 @@
> ⚠ **Эррата 04.09-а (D39.189 п.2б) — «обязательный `--ceiling-usd` на движковом вызове» верно для ПРЯМОГО прогона движка и НЕИСПОЛНИМО на пути через API платформы.** Там флаг никто не ставит руками: платформа выводит число сама — `bookCap = committed + increment` (`platform/internal/runs/spawn.go`, греп `func (m meter) bookCap`), ⚠ **ИСПР. 06.09: механизм СПИЛЕН** (`2812dd6`) — ставки за главу больше нет ни константой, ни ручкой, `increment` приходит из ПРОЕКЦИИ ДВИЖКА, а сама формула `bookCap` жива дословно. Прежняя редакция: где `increment` считается по ставке `DefaultPerChapter = 30_000` ($0.03, `platform/internal/pricing/pricing.go`), заниженной ×4.47 (D39.179 п.1). Сессия, исполняющая букву ноты, полезла бы крутить `TM_PLATFORM_USD_PER_CHAPTER` — хак под тест, запрещённый каноном. **Читать так:** потолок платного пака на API-пути задаётся ГРАНТОМ тест-аккаунту на объявленную сумму (`tmplatformctl grant --user <id> --usd <N>`) — холд делает перерасход невозможным по построению, — а путь до завершённой книги идёт цепочкой «покупка → пауза по потолку → пополнение → новый прогон», что и есть третий сценарий строки 216 и D39.176 п.3. Тело ноты не переписано (D23.3). Найдено контролёром при сверке плана, пере-проверено оркестратором по коду.
> ⚠ **Эррата 11.09-б (D39.247 п.1 и п.4) — «18 РАСХОЖДЕНИЙ» ЗАВЫШЕНО В 2.5 РАЗА, настоящих СЕМЬ.** Замерено бэкенд-сессией пака консистентности 11.09 по-юнитно: из восемнадцати промахов **11 ложные** — банковская форма доехала до читателя в том же юните СКЛОНЁННОЙ, а `SameStem` её не признал, потому что стеммер снимает ровно одно окончание и стеммы выходят разной длины (во всех одиннадцати один — строгий префикс другого с разницей в ОДИН знак). Пять из одиннадцати — намеренно исключённый мягкий знак (`D39.71`), и записка в дереве сама называет лечение — «anchor-gated match». ⇒ **акт остаётся верен в направлении и неверен в величине:** механизм консистентности работает и работает не везде, но НЕ-мест семь, а не восемнадцать. Носитель — строка бэклога **419**. ⚠ Класс: я опубликовал число, снятое ОДНИМ прибором, не спросив, что этот прибор не видит.
> ⚠ **Эррата 11.09-в (D39.247 п.4 и вопрос владельцу) — Я ПИСАЛ ПО ОСИ, КОТОРОЙ В ПРОДУКТЕ НЕТ.** Акт называл «подписанный/неподписанный ТЕРМИН» и ставил владельцу вопрос «закон ли для неподписанного». Владелец 11.09: «нет такого понятия, подписан либо ВЕСЬ банк, либо он в неконсистентном состоянии; есть галочка скипать подпись — тогда автоподписывание». Это ратифицировано `D39.144` (подписывается банк ЦЕЛИКОМ; пер-термная подпись — НЕ модель продукта; дефолт — авто-продолжение с неподписанным банком, строки едут с пометкой). ⇒ **вопрос был сформулирован неверно и снят.**Но под ним лежит РЕАЛЬНАЯ находка, и она дороже: в коде есть пер-термный автомат `auto|draft|approved`, и пост-проверка считает нарушением только `approved`**механизм решает по единице, которой в продуктовой модели не существует.** Носители — строки **407** (исправлена) и **419**. Мерить надо состоянием КНИГИ (подписана целиком либо авто-продолжение), а не статусом отдельного терма.
> ⚠ **Эррата 11.09-а (D39.247 п.4, ряд 418) — РАСХОЖДЕНИЯ ДВУХ ЧИСЕЛ ДВИЖКА НЕ СУЩЕСТВУЕТ, это была моя ошибка ЧТЕНИЯ.** Акт завёл ряд на «`spread=4` при трёх формах в списке» и «`other proposals` 2 против `drafts` 3». Пере-снято бэкенд-сессией и пере-проверено мной: движок печатает ДВЕ РАЗНЫЕ величины В ОДНОЙ СТРОКЕ`spread=%d conventions=%d` (`backend/internal/pipeline/mining.go:542`), где `Spread()` = Σ сырых форм, `Conventions()` = len(свёрнутых классов); комментарий у определения говорит прямо: «Spread 3 with Conventions 3 is a real contest, and the two must not read the same at the stop». Распределение по 69 термам прогона: 60×(1,1) · 6×(2,2) · 2×(3,3) · 1×(4,3) — противоречий ноль. Второй «экземпляр» того же класса: `other proposals` печатает `props[1:]`, то есть ИСКЛЮЧАЕТ текущий `dst`, поэтому 3 черновика дают «other proposals: 2». **Ряд 418 удалён из таблицы; работы он не несёт.** ⚠ Класс ошибки — тот, что эта же смена записала нормой: сравнил число с длиной списка, меряющего ДРУГУЮ величину, и обе половины по отдельности были верны. Пин равенства вешает пак консистентности, чтобы объяснение держалось не текстом.
> ⚠ **Эррата 03.09-а (D39.170) — формула «покупатель платит за N юнитов и получает ровно N» БОЛЬШЕ НЕ ВЕРНА.** Пак «число согласия на пути второй покупки» (лендинг 03.09) закрыл вторую половину строки 232: юнит, который прежний прогон НАЧАЛ и не отгрузил по оси `finalStageWave`, дописывается ВНЕ гранта. Отсюда грант `--max-units N` оплачивает ДО **2N** выходных юнитов — замерено приёмкой на живом раннере (грант 2 → `Paid()=4`, шесть вызовов провайдера), и тем же замером подтверждено, что в перенос попадает даже юнит, ФЛАГНУВШИЙСЯ без текста, то есть каждая следующая покупка платит за его пере-атаку заново. ⛔ **Семантика НЕ ратифицирована: слово владельца 03.09 — «подумаем на этот счёт», решение отложено.** До него `--max-units` держит не деньги, а слоты; деньги держит только `--ceiling-usd`. Тело D39.170 не переписано (D23.3); живой носитель формулировки — `15-money-path.md`, пункт про `--max-units`.