diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 20448190..21a7d0fa 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -1,6 +1,6 @@ # Журнал прогресса -> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-09-11, голова D39.243 — КУРС: движок и платформа до «работает и отдаёт результат», фронт ЗАМОРОЖЕН и P7 его НЕ размораживает (D39.147). **ОЧЕРЕДЬ №23** (единственный носитель — здесь; роль передана 06.09, №22 закрыт нотой передачи D39.217; ⚠ испр. 06.09: коммит передачи `c992ee5` бампнул голову и НЕ тронул номер — гейта на номер очереди нет вовсе, `counts.py` сверяет только голову, поэтому носитель разошёлся молча). ⚠ **ЗАКАЗ ВЛАДЕЛЬЦА 01.09 — ИСПОЛНЕН, испр. 08.09 (висел как «первым» неделю после исполнения):** (0а) ревизия документации на протухшее ОТРАБОТАНА 01.09 воркфлоу `docs-staleness-revision-A` (15 срезов), провенанс находок — `D39.185`; (0б) планы доработок в бэкенд и платформу — исполняются ПАКАМИ, за 07–08.09 закрыты два движковых (`D39.225`, `D39.226`); (0в) вынос неактуального в архив идёт батчами `DOC_CLEANUP_PLAN.md` (Б14/Б15/Б17 живы). ⇒ строка ниже — не заказ, а история: (0а) ревизия документации на ПРОТУХШЕЕ — по всем зонам; (0б) планы доработок в БЭКЕНД и ПЛАТФОРМУ; (0в) вынос неактуального в АРХИВ (`docs/archive/`, `platform/docs/archive/`) — за сутки 31.08 закрыто много, и часть носителей стала историей. ⚠ Трезвость по масштабу (пере-считано 02.09): **94** живых дока в `docs/` (пере-счёт 04.09: `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`), 8 в `platform/docs`, 9 в `backend/docs` — ⚠ из 94 ВРЕМЕННЫЙ остался ОДИН (`DOC_CLEANUP_PLAN`, живой до закрытия батчей Б14/Б15/Б17); два прежних временных уехали в `archive/reports/` 02.09; счёт бэклога — бюллетенем ниже, открытых рядов регистра платформы — 109 (major 1), всего рядов 465 (пере-счёт `python3 docs/scripts/counts.py`; с 04.09 оба числа под гардом `--check`, прежние 95/3 разошлись молча) ⚠ (ревизией 02.09 ряды **154** и **157** переведены из «скоро» в «когда-нибудь»: их гейтом стоял первый холодный прогон, он ОТРАБОТАЛ 31.08 и оба предусловия оказались другими — разбор в самих ячейках, ни одна НЕ закрыта). ⚠ Числа доков `counts.py` НЕ сторожит — при переносе файлов пере-считывать руками командой `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`. ⚠ И предупреждение о МЕТОДЕ, купленное сменой №21: «выглядит протухшим» ≠ «протухло». Три факта оркестратора опровергнуты ЗАМЕРОМ сессий, а якоря `15-money-path.md` в девяти случаях из двенадцати РОДИЛИСЬ верными и сгнили дрейфом — то есть ревизия обязана быть исполнением, а не чтением. ⚠ **ОЧЕРЕДЬ, унаследованная от №21** (три лендинга 31.08 — секция «СОСТОЯНИЕ ПАКОВ» ниже): **(1) ~~РАЗРЫВ ЦИКЛА~~ ЗАМКНУТ ЖИВЬЁМ 04.09** — пользователь получил EPUB настоящего ПЛАТНОГО перевода ЧЕРЕЗ API, `epubcheck` 5.3.0 на СКАЧАННОМ файле 0/0/0/0 (книга `bk_SS5VES2JELESJSTR`, потрачено $0.278319 из гранта $0.60 при потолке пака $1.5, санкция D39.189). Дверь выдачи построена и проверена исполнением: `202`+`Location`, поллинг с `Retry-After`, Range 206 · второй клиент 200 · аноним 401 · чужая книга 404, TTL с GC, идемпотентность третьего создающего вызова. Все ТРИ сценария строки 216 предъявлены живьём (подпись банка · halt на потолке с exit 4 · `409 run_not_resumable/ceiling_reached` и лечение новым прогоном). +> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-09-11, голова D39.244 — КУРС: движок и платформа до «работает и отдаёт результат», фронт ЗАМОРОЖЕН и P7 его НЕ размораживает (D39.147). **ОЧЕРЕДЬ №23** (единственный носитель — здесь; роль передана 06.09, №22 закрыт нотой передачи D39.217; ⚠ испр. 06.09: коммит передачи `c992ee5` бампнул голову и НЕ тронул номер — гейта на номер очереди нет вовсе, `counts.py` сверяет только голову, поэтому носитель разошёлся молча). ⚠ **ЗАКАЗ ВЛАДЕЛЬЦА 01.09 — ИСПОЛНЕН, испр. 08.09 (висел как «первым» неделю после исполнения):** (0а) ревизия документации на протухшее ОТРАБОТАНА 01.09 воркфлоу `docs-staleness-revision-A` (15 срезов), провенанс находок — `D39.185`; (0б) планы доработок в бэкенд и платформу — исполняются ПАКАМИ, за 07–08.09 закрыты два движковых (`D39.225`, `D39.226`); (0в) вынос неактуального в архив идёт батчами `DOC_CLEANUP_PLAN.md` (Б14/Б15/Б17 живы). ⇒ строка ниже — не заказ, а история: (0а) ревизия документации на ПРОТУХШЕЕ — по всем зонам; (0б) планы доработок в БЭКЕНД и ПЛАТФОРМУ; (0в) вынос неактуального в АРХИВ (`docs/archive/`, `platform/docs/archive/`) — за сутки 31.08 закрыто много, и часть носителей стала историей. ⚠ Трезвость по масштабу (пере-считано 02.09): **94** живых дока в `docs/` (пере-счёт 04.09: `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`), 8 в `platform/docs`, 9 в `backend/docs` — ⚠ из 94 ВРЕМЕННЫЙ остался ОДИН (`DOC_CLEANUP_PLAN`, живой до закрытия батчей Б14/Б15/Б17); два прежних временных уехали в `archive/reports/` 02.09; счёт бэклога — бюллетенем ниже, открытых рядов регистра платформы — 109 (major 1), всего рядов 465 (пере-счёт `python3 docs/scripts/counts.py`; с 04.09 оба числа под гардом `--check`, прежние 95/3 разошлись молча) ⚠ (ревизией 02.09 ряды **154** и **157** переведены из «скоро» в «когда-нибудь»: их гейтом стоял первый холодный прогон, он ОТРАБОТАЛ 31.08 и оба предусловия оказались другими — разбор в самих ячейках, ни одна НЕ закрыта). ⚠ Числа доков `counts.py` НЕ сторожит — при переносе файлов пере-считывать руками командой `find docs -name '*.md' -not -path 'docs/archive/*' | wc -l`. ⚠ И предупреждение о МЕТОДЕ, купленное сменой №21: «выглядит протухшим» ≠ «протухло». Три факта оркестратора опровергнуты ЗАМЕРОМ сессий, а якоря `15-money-path.md` в девяти случаях из двенадцати РОДИЛИСЬ верными и сгнили дрейфом — то есть ревизия обязана быть исполнением, а не чтением. ⚠ **ОЧЕРЕДЬ, унаследованная от №21** (три лендинга 31.08 — секция «СОСТОЯНИЕ ПАКОВ» ниже): **(1) ~~РАЗРЫВ ЦИКЛА~~ ЗАМКНУТ ЖИВЬЁМ 04.09** — пользователь получил EPUB настоящего ПЛАТНОГО перевода ЧЕРЕЗ API, `epubcheck` 5.3.0 на СКАЧАННОМ файле 0/0/0/0 (книга `bk_SS5VES2JELESJSTR`, потрачено $0.278319 из гранта $0.60 при потолке пака $1.5, санкция D39.189). Дверь выдачи построена и проверена исполнением: `202`+`Location`, поллинг с `Retry-After`, Range 206 · второй клиент 200 · аноним 401 · чужая книга 404, TTL с GC, идемпотентность третьего создающего вызова. Все ТРИ сценария строки 216 предъявлены живьём (подпись банка · halt на потолке с exit 4 · `409 run_not_resumable/ceiling_reached` и лечение новым прогоном). > ⛔ **ПЯТЬ ПОТОКОВ РАБОТЫ — состояние на 07.09 (пере-снято лендингами смены №23).** > **(1) ПОЛИГОН — «ремонт прибора»** (`docs/POLYGON_INSTRUMENT_REPAIR_SESSION_PROMPT.md`, строки 319 · 300 · 265 · 143): > ⚠ **ЕДИНСТВЕННЫЙ ПОТОК, НЕ СДВИНУВШИЙСЯ ЗА СМЕНУ — сессия по промту так и не стартовала.** Блокирующая линза diff --git a/docs/architecture/05-decisions-index.md b/docs/architecture/05-decisions-index.md index 7b6b28df..8931ed74 100644 --- a/docs/architecture/05-decisions-index.md +++ b/docs/architecture/05-decisions-index.md @@ -1,4 +1,4 @@ -# Реестр D-нот — карта актуальности v2 (D1–D39.243; титул — носитель головы, бампать при каждом аппенде) +# Реестр D-нот — карта актуальности v2 (D1–D39.244; титул — носитель головы, бампать при каждом аппенде) > ⚠ **Колонку «тело» `counts.py --check` НЕ сторожит по устройству:** он сверяет полноту НОМЕРОВ, а не > место тела, поэтому колонка держится дисциплиной лендинга. Не нашёл тело по колонке — иди в слайсы, @@ -302,3 +302,4 @@ | D39.241 | 11.09 | **АКТ ЗАКРЫТИЯ обеих сессий пака «две остановки».** Движок ОТКАЧЕН полностью (18 путей + 6 файлов; батарея вернулась к входной строке: 19 `ok` · 0 FAIL · 4 скипа). ⛔ Откат не смогла сделать НИ ОДНА сессия, включая оркестраторскую — запрет сработал одинаково, обходить его не стала ни одна, дерево снял владелец одной командой. Платформа сдала `--no-block` **с пином**: три мутации засчитаны по ТЕКСТУ, живой пин ×5 зелёный, argv-пин отдельно — чтобы флаг не остался непроверенным на хосте без systemd. ⭐ Куплен пин на ЧУЖОЕ поведение: «повторный стоп бесплатен и идемпотентен» держалось на недокументированном systemd. От отменённого пака осталось 7 нот и 23 строки трекера; одна МОЯ строка (399) была ложной и пере-написана до заказа | приёмка · стоп · метод | | D39.242 | 11.09 | **АКТ: доработка по инварианту `D39.240` ПРИНЯТА обеими зонами** (`3084766`+`f8a968e` движок, `560ca20`+`00d590e` платформа). Батарея вернулась к входной строке, мутации **152 · RED 151 · SURVIVED 0 · ROTTED 1**, после починки якоря сверка 373 якорей — протухших 0. ⛔ Подтверждающего перепрогона «152 одной строкой» НЕТ — дважды убит сторожем памяти, третьей попытки не делали ОСОЗНАННО (косметика, ни одной новой проверки). ⭐ Почти всё дорогое нашли САМИ сессии и у СЕБЯ: выживший мутант вскрыл дефект в собственном пине · непримени́вшаяся собственная правка · знаменатель 8 сайтов против моих 2 · три класса вырожденности за заход · три опровержения СВОИХ находок. ⚠ И ПЯТЬ моих ошибок, снятых сессиями, — все названы в п.6, четыре нормы куплены | приёмка · стоп · метод | | D39.243 | 11.09 | **АУДИТ БАНКА ПАМЯТИ против приоритета №1 владельца** (`research/34`: банк держит инъекцию, но КНИЖНОГО вопроса не задаёт ни один прибор ⇒ приоритет непроверяем; строки **406–410**) · полигонный слот сведён к ОДНОМУ промту (два припаркованы баннерами) · два пака выданы после опровергателей, шесть классов их находок · ⛔ санкция владельца «со слов» носителем не является · три мои ошибки о прогоне A и его деньги ДВУМЯ числами · эррата к атрибуции `D39.108` п.1 | процесс/качество | +| D39.244 | 11.09 | **КОНТРАКТНЫЙ МИНОР 0.14.0** — `Blocked.code` получает `run_in_flight`: форма заказа перестаёт обещать старт, в котором допуск откажет из-за уже идущего прогона ЭТОЙ книги (`PD-455`). `verdict` не трогается — он закрытый enum и правда про ДЕНЬГИ; расширен смысл `Blocked`. Форма выведена зоной, ратифицирована ДО стройки; провенанс — §2.25 README канона | контракт | diff --git a/docs/architecture/05-decisions-log.md b/docs/architecture/05-decisions-log.md index fedd4abf..93f0dc7c 100644 --- a/docs/architecture/05-decisions-log.md +++ b/docs/architecture/05-decisions-log.md @@ -1,4 +1,4 @@ -# Журнал решений оркестратора — контракт D1–D39.243 (живой файл: карта · эрраты · живые тела · голова D39.124+ (подрезка D39.139); тела закрытых эр — в слайсах `docs/archive/architecture/`, указатель ниже; реестр всех нот — `05-decisions-index.md`) +# Журнал решений оркестратора — контракт D1–D39.244 (живой файл: карта · эрраты · живые тела · голова D39.124+ (подрезка D39.139); тела закрытых эр — в слайсах `docs/archive/architecture/`, указатель ниже; реестр всех нот — `05-decisions-index.md`) > **⟶ КАРТА АКТУАЛЬНОСТИ (ревизия D31, продлена до D38.2 [12.07]; исторические записи ниже НЕ переписываются — дисциплина D23.3).** Работая с контрактом (греп номера: живой файл → слайсы, целиком НЕ читать — D39.125), держи под рукой, что чем перекрыто: > ⚠ **Эррата 09.08 (D39.125):** D39.111 п.1 предписывал промту S3 «максимум = баланс МИНУС открытые холды» — формула ОШИБОЧНА (вычитание дважды), исправлена D39.115 п.2(а): максимум = Balance КАК ЕСТЬ; тело D39.111 — в слайсе `../archive/architecture/05-decisions-D39-106-123.md` (испр. 05.09: прежнее «живёт ниже в этом файле» протухло подрезкой D39.139) (голова D39.106+). @@ -3476,3 +3476,15 @@ bought NOTHING». ⇒ **`tmctl manifest` есть НИЖНЯЯ граница, **7. ЭРРАТА К РОЛЕВОМУ ПРОМТУ.** Норма «не влезает в бюджет — стоп и пинг» приписана в нём `D39.108` п.1; в теле ноты этой формулировки НЕТ (нота — приёмка экспов 18/19/20). Норма верна, атрибуция снята, носитель — сам ролевой промт. **8. ⛔ И ПЕРЕ-ОПРЕДЕЛЁН ПРЕДМЕТ «ВХОДА», который я числил дырой из трёх частей.** Замер: пригласительного гейта действительно нет, но грант новичку 0 — РЕШЕНИЕ владельца (`D39.176` п.1), а байтовый потолок загрузки ПОСТРОЕН (64 МиБ на маршруте интейка). Живой остаток — операционная гигиена, и та же нота называет её инженерной; её гейт — открытая регистрация, которой в закрытой бете нет, поэтому из платформенного пака она снята подписанным пропуском. + +## D39.244 — КОНТРАКТНЫЙ МИНОР 0.14.0: `Blocked.code` получает `run_in_flight`; форма выведена платформенной сессией и ратифицирована ДО стройки (11.09, оркестратор №23). ✅ + +**Основание.** Контрактный пинг платформенной сессии по паку «ПРАВДА У ДВЕРИ» (`PD-455`): форма заказа отвечает «хватает на всю книгу» над книгой, по которой уже идёт прогон, и молчит о том, что клик получит отказ. Промт задавал точку роста (`Blocked.code`, не `verdict`), сессия вывела форму и прислала её мне — правка канона моя, не её. + +**1. Что решено.** `Blocked.code` получает второе значение **`run_in_flight`**. `verdict` НЕ трогается: он остаётся закрытым enum из трёх значений и правдой ПРО ДЕНЬГИ; клиент читает `verdict` и `blocked` вместе. Вместе со значением расширен СМЫСЛ схемы: было «что держит шкалу КОРОЧЕ», стало «почему старт не предлагается так, как обещал бы один баланс» — с двумя формами внутри (шкала короче доступного · старт невозможен вовсе). `book_id` при `run_in_flight` — ЭТА ЖЕ книга: место, где пользователь может действовать, — карточка её собственного прогона. + +**2. Почему не четвёртое значение `verdict`.** Он ЗАКРЫТЫЙ, и новое значение ломает генерённых клиентов. `Blocked.code` — предавторизованная точка роста: его собственное описание требует от клиента терпеть неизвестное значение под минором. Тот же класс, что купил `D39.226`: расширяемость живёт не там, где кажется, и её спрашивают у канона ПРЕЖДЕ, чем заводят новый член. + +**3. Порядок — форма ратифицирована ДО стройки** (как `D39.235` п.6 для кадра остановки). Иначе сессия зоны либо ставит константу версии и красит собственный гейт (`gates.TestTheAnnouncedContractVersionIsTheOneTheCanonRatified` читает канон ВЫШЕ корня модуля), либо строит механизм, объявляя старую версию. Константа `httpapi.ContractVersion` уезжает ТЕМ ЖЕ лендингом, что и код зоны. + +**4. Провенанс и носители.** `docs/architecture/14-api-contract/openapi.yaml` (`version: 0.14.0`, схема `Blocked`) + §2.25 README канона. ⚠ Байт-зеркало фронта не синкается: на время фриза зоны его отставание ратифицировано (`D39.142` п.5). diff --git a/docs/architecture/14-api-contract/README.md b/docs/architecture/14-api-contract/README.md index e3109645..d2ef3401 100644 --- a/docs/architecture/14-api-contract/README.md +++ b/docs/architecture/14-api-contract/README.md @@ -3,7 +3,7 @@ батч 0.3.0 — D39.138, 16.08.2026, оркестратор №17; синк с платформой 0.4.0 — 20.08.2026, контрактная сессия; РАТИФИЦИРОВАН D39.152, 20.08.2026, оркестратор №18) -СТАТУС: РАТИФИЦИРОВАН как контракт API v0 по **0.13.1** включительно (0.13.1 — `D39.235` п.6: корректирующий минор, `Run.required` требовал отставленный член) (0.11.0 — D39.208 · 0.12.0 — D39.211 · **0.13.0 — D39.221: четыре исхода `POST /v0/books` после синхронного разреза на приёме**; перечень миноров и их +СТАТУС: РАТИФИЦИРОВАН как контракт API v0 по **0.14.0** включительно (0.14.0 — `D39.244`: `Blocked.code` получает `run_in_flight`, форма выведена платформенной сессией и ратифицирована ДО стройки — провенанс §2.25; 0.13.1 — `D39.235` п.6: корректирующий минор, `Run.required` требовал отставленный член) (0.11.0 — D39.208 · 0.12.0 — D39.211 · **0.13.0 — D39.221: четыре исхода `POST /v0/books` после синхронного разреза на приёме**; перечень миноров и их провенанс — ниже по файлу, здесь НЕ дублируется). Нормативная поверхность — openapi.yaml РЯДОМ. ⚠ Зонная копия frontend/docs/api-contract/ ВРЕМЕННО ОТСТАЁТ (0.2.3 при каноне 0.13.0 — ОДИННАДЦАТЬ миноров) — ратифицировано D39.142 п.5 на время фриза фронта; синк байт-в-байт + перегенерация типов = @@ -57,7 +57,12 @@ cmp-сверка обязательна (D39.138 п.3). > капабилити, которой никто не строил; третий адрес двери получает `operationId` `downloadExport` — > до этого единственная поверхность, по которой браузер НАВИГИРУЕТ, жила в каноне только прозой; > шестнадцатая причина замечания `off_target_lang` получает код `wrong_language` (Приложение А). -> Провенанс — §2.23**. +> Провенанс — §2.23** · +> **0.14.0 (D39.244, 11.09; ратифицирован ДО стройки, форма выведена платформенной сессией) — +> `Blocked.code` получает второе значение `run_in_flight`: форма заказа перестаёт обещать старт, +> в котором допуск откажет из-за уже идущего прогона ЭТОЙ книги. `verdict` НЕ трогается — он остаётся +> правдой про деньги, и четвёртого значения у него нет; расширяется смысл `Blocked`, потому что +> живой прогон шкалу не укорачивает, а делает старт невозможным. Провенанс — §2.25**. > Дом канона — этот каталог; > `frontend/docs/api-contract/openapi.yaml` — байт-зеркало ⚠ НА ФРИЗЕ ЗОНЫ РАВЕНСТВО ПРИОСТАНОВЛЕНО (D39.142 п.5): зеркало 0.2.3, канон **0.13.0** (⚠ число испр. 10.09 — здесь стояло 0.10.0, отставшее на два минора: 0.12.0 — `D39.211`, 0.13.0 — `D39.221`; шапка файла и `openapi.yaml` всё это время несли верное). Прежний текст: канон 0.10.0. > @@ -952,6 +957,29 @@ first built format»), и условие наступило. Набор — то **Шестнадцатая причина замечания.** `off_target_lang` → `wrong_language`; разбор и ⚠ о ранге — в Приложении А. +### 2.25. `run_in_flight` — форма заказа перестаёт обещать то, в чём дверь откажет (0.14.0) — ✓ форма выведена зоной, ратифицирована ДО стройки + +**Дефект (`PD-455`).** Вердикт формы считается из остатка и баланса и про ЖИВОЙ прогон по книге не +спрашивает; допуск же вторую покупку отвергает. Человек видит «хватает на всю книгу», жмёт и получает отказ, +причину которого форма знала до клика. Денег это не теряет — отказ случается ДО взятия холда, — ломается +ровно обещание формы «вердикт ДО клика», ради которого пак и писался. + +**Почему НЕ четвёртое значение `verdict`.** `verdict` — ЗАКРЫТЫЙ enum (`covers_all` · `covers_part` · +`covers_none`), и новое значение в нём ломает генерённых клиентов. `Blocked.code` — наоборот, +ПРЕДАВТОРИЗОВАННАЯ точка роста: его собственное описание требует от клиента терпеть неизвестное значение под +минором. Это тот же урок, что купил `D39.226` про корневой `code` против `cause.code`: расширяемость живёт +не там, где кажется, и её надо спросить у канона прежде, чем заводить новый член. + +**Что расширено вместе со значением.** Смысл `blocked` был «почему шкала КОРОЧЕ, чем аккаунт мог бы себе +позволить», и живой прогон в него не влезает: он шкалу не укорачивает, он делает старт невозможным. Поэтому +минор правит и описание схемы — «почему старт не предлагается так, как обещал бы один баланс», с двумя +формами внутри. `book_id` при `run_in_flight` — ЭТА ЖЕ книга: место, где пользователь может действовать, — +карточка её собственного прогона, а не чужой. + +**Порядок.** Форма ратифицирована ДО стройки (как `D39.235` п.6 для кадра остановки): иначе сессия зоны либо +ставит константу версии и красит собственный гейт, либо строит механизм, объявляя старую версию. Константа +`httpapi.ContractVersion` уезжает ТЕМ ЖЕ лендингом, что и код. + ### 2.24. ⛔ ЗАПРЕТ «ДЕНЕГ В ИНТЕРФЕЙСЕ НЕТ» ОТОЗВАН ВЛАДЕЛЬЦЕМ (05.09, прозой — не минор) **Что случилось.** Норма «оплат в MVP нет, денежных полей в UI нет вовсе» месяц определяла форму diff --git a/docs/architecture/14-api-contract/openapi.yaml b/docs/architecture/14-api-contract/openapi.yaml index 477354fb..21513a41 100644 --- a/docs/architecture/14-api-contract/openapi.yaml +++ b/docs/architecture/14-api-contract/openapi.yaml @@ -2,7 +2,7 @@ openapi: 3.1.0 info: title: TextMachine API - version: 0.13.1 + version: 0.14.0 summary: Ratified contract between the frontend and the TextMachine platform. description: | **RATIFIED contract.** Canonical copy: `docs/architecture/14-api-contract/`; @@ -2845,21 +2845,30 @@ components: Blocked: type: object description: | - What is holding the scale down, and which book is doing it. + Why a start is not offered the way the balance alone would promise, and which book is the + reason. Two shapes of that: the scale is SHORTER than the credit could buy, or a start is + impossible right now however much credit there is. `verdict` stays the truth about MONEY; a + client reads the two together (§RunOptions). required: [code, book_id] properties: code: type: string description: | `credit_held` — another book of this account has a run holding the credit, released when - that run settles. A client MUST tolerate an unknown value under a minor bump and show a - neutral "something else is using the balance" state. - enum: [credit_held] + that run settles; the scale is shorter than the balance suggests. + `run_in_flight` — THIS book already has a run in flight, so admission will refuse a + second purchase whatever the scale says. The form knew it before the click, and saying + nothing was the defect this value closes (PD-455). + A client MUST tolerate an unknown value under a minor bump and show a neutral + "something else is using the balance" state. + enum: [credit_held, run_in_flight] book_id: $ref: '#/components/schemas/Id' description: | - The book that holds it — an id, so a client that wants to name it reads that book's - card, which is also where the user can act. + The book that is the reason — an id, so a client that wants to name it reads that book's + card, which is also where the user can act. For `credit_held` that is ANOTHER book of the + account; for `run_in_flight` it is THIS book, and its own card is where the running job + can be watched or stopped. CeilingBounds: type: object