diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index ed1541c9..6a6011d9 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -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). Здесь только долг и его диспозиции. -> - **СЧЁТ ОЧЕРЕДИ на 10.09 (скриптом по таблице — `python3 docs/scripts/counts.py`; обновлять при каждом лендинге):** всего **269** строк · зона бэкенд **131** строго / **178** широко (⚠ колонки счётчик читает С КОНЦА — испр. D39.116) · **блокеров очереди 0** (236 закрыта D39.175; **371** — актом D39.233, **360** — актом D39.232, обе 10.09), платные прогоны разблокированы · «скоро» **125** (перечень — грепом по таблице, рукописный список снят D39.126) · гейт-строка эксп-22: 153 (плюс 150 — руки владельца; ⚠ 55 из гейтов СНЯТА — D39.198 п.5); строка 5 — остаток гейчен ре-пробой 74, носитель события теперь строка 188 (аудит D39.140); остальное «когда-нибудь». ⚠ Счёт — НИЖНЯЯ граница долга, не потолок (разбор — легенда таблицы ниже). +> - **СЧЁТ ОЧЕРЕДИ на 10.09 (скриптом по таблице — `python3 docs/scripts/counts.py`; обновлять при каждом лендинге):** всего **270** строк · зона бэкенд **131** строго / **178** широко (⚠ колонки счётчик читает С КОНЦА — испр. D39.116) · **блокеров очереди 0** (236 закрыта D39.175; **371** — актом D39.233, **360** — актом D39.232, обе 10.09), платные прогоны разблокированы · «скоро» **125** (перечень — грепом по таблице, рукописный список снят 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; правки — только через оркестратора) @@ -305,3 +305,4 @@ | 381 | ⛔ **ДВУХ ОСТАНОВОК НЕТ: у человека одна кнопка, и она ЖЁСТКАЯ.** Слово владельца 09–10.09 («должно быть два стопа, один жёсткий… и второй мягкий, который не обрывает всё сразу, чтоб деньги зазря не списывались») носителя не получило — ни ноты, ни строки, ни заказа в паке; жило перепиской и умерло вместе с сессией (тот же класс, что `D39.231` п.1). **Замерено 10.09 оркестратором и подтверждено движковой зоной:** единственная регистрация сигнала — `backend/cmd/tmctl/main.go:207` `signal.NotifyContext`, она отменяет контекст прогона ⇒ вызовы в полёте рвутся, доставленные книжатся по оценке и метятся `cancelled`. **Мягкий ГЛАГОЛ уже построен** — `latched` (`backend/internal/pipeline/waverun.go:353-363`, дословно «a different verb from cancel()»: фидер перестаёт раздавать индексы, начатое доигрывается под неотменённым контекстом), но дёргает его только денежный потолок (строка 277), и он ЛОКАЛЕН для одного `runWave` (живых вызовов два: `waverun.go:140`, `:285`) ⇒ кнопке нужен ПРОГОННЫЙ источник, который волна консультирует. **Что ещё названо замером зоны:** (а) мягкий стоп контекст не отменяет ⇒ `errors.Is(err, context.Canceled)` ложно и `exitCode` (`cmd/tmctl/main.go:117`) отдаёт 0/2 — «я остановил» машинно неотличимо от «книга кончилась»; форма для своего кода и поля есть у потолка (`CeilingHalt` → 4 → `events.go:423`), но прецедент против отдельного `outcome` тоже есть (`runevents.go:261-264`); (б) банковые проходы идут ВНЕ волны (`terminologist.go:348`, `:907`, зовутся из `mining.go:166`) и латчем не останавливаются — их естественная точка попартийный приём `terminologist.go:944-970`; (в) резюм уже верен и правки не требует (`waverun.go:449-452`); (г) `--max-units` слотов не тратит, но недоигранный грант должен публиковаться в `Finished.Volume`; (д) ⛔ **второй Ctrl-C сегодня НЕ ДЕЛАЕТ НИЧЕГО** — `stop()` стоит на `defer` (`main.go:208`), горутина `NotifyContext` после первого сигнала вышла, второй сигнал попадает в буфер и никем не читается ⇒ «второе нажатие ужесточает» — НОВОЕ поведение, а не восстановление дефолта. ⚠ **Продуктовая цена, которую владелец должен знать ДО решения:** мягкий стоп доигрывает начатое, а один вызов может держаться до `attempt_max_s` (~20 мин на deepseek) — оператор, не знающий этого, нажмёт второй раз и потеряет ровно те деньги, ради которых мягкий стоп заводился ⛔ **ДОБАВКА 10.09: два носителя УЖЕ обещают мягкий стоп, которого нет.** Контракт — `docs/architecture/14-api-contract/openapi.yaml:762` «The product "stop" action; finished work is kept and not paid for again»: жёсткий стоп это нарушает, летящая единица книжится по оценке и пере-делается на резюме (`backend/internal/pipeline/cutcall.go:208`), то есть покупается ДВАЖДЫ. Платформа — `platform/internal/runner/runner.go:56-58` («the engine … finishes the in-flight chunk before exiting») и `:163-164`: оба утверждения о движке ложны. И числовой конфликт: `stopGrace = 10 * time.Minute` (`runner.go:59`) МЕНЬШЕ потолка ожидания вызова (`attempt_max_s` 1240 с) ⇒ как только SIGTERM станет мягким, systemd будет убивать законное ожидание, а SIGKILL не оставляет ни пометки, ни сеттла. ⇒ пак движка ПАРНЫЙ платформенному, порознь не лендятся | бэкенд | скоро | у человека ДВЕ различимые остановки: мягкая (новое не начинаем, начатое доигрываем, пометок `cancelled` не возникает) и жёсткая; обе различимы машинно — кодом выхода и признаком в кадре `finished`, чтобы платформа не читала остановку как конец книги | слово владельца 09–10.09 + замер оркестратора и движковой зоны 10.09 | | 382 | ⛔ **ПОМЕТКА «ЭТО ОЦЕНКА» — УСЛОВИЕ СЛОВА ВЛАДЕЛЬЦА (`D39.230` п.1) — ПО ШВУ НЕ ЕДЕТ И ПОТРЕБИТЕЛЯ НЕ ИМЕЕТ.** Владелец разрешил списывать с читателя по ОЦЕНКЕ при условии, что пометка стоит. В движке она есть: `backend/internal/pipeline/status.go:321` — `estimated_rows` / `estimated_usd` в `status --json`. Дальше она обрывается. Замер 10.09 с контролем: в кадрах событий шва (`backend/internal/runevents/runevents.go`) слова `estimated` **0 хитов** (контроль: `committed` в том же файле — **6**; денежный кадр несёт один `committed_micro_usd`, `runevents.go:244`); в `platform/internal` вне тестов — **2 хита, оба КОММЕНТАРИИ**, причём `pgstore/credits.go:235` прямо просит эту величину: «publish the count and sum of estimated-price rows beside committed_usd, which is what would let this side say "at most Y"» (контроль: `committed_micro` — 1 хит; go-файлов вне тестов прибор прочёл **81**). ⇒ условие исполнено на ОДНОМ канале из двух, и читателя, ради которого пометка ставилась, у неё нет: платформа не может сказать пользователю «не больше Y». ⚠ Пара к строке **381**: и то и другое — признак, который обязан ехать в кадре `finished`/`spend`, а не только в `status --json` | бэкенд | скоро | платформа ЧИТАЕТ счёт и сумму оценочных строк из потока и может назвать пользователю верхнюю границу списания | акт `D39.233` п.7, замер оркестратора 10.09 по разбору чистого Fable 5 | | 383 | **ПОТОЛОК ОЖИДАНИЯ ЖИВЁТ КОНСТАНТОЙ В ОДНОЙ ЗОНЕ, А ВЫВОДИТСЯ ИЗ КОНФИГА ДРУГОЙ — ФОРМА, КОТОРАЯ ТУХНЕТ МОЛЧА.** Платформенный грейс остановки обязан покрывать законное ожидание движка. Сегодня это число платформа ВЫВОДИТ из движкового каталога и кладёт себе константой (пак «две остановки», `D39.236` п.6): любая правка `backend/configs/models.yaml` — новый провайдер, поднятый `edit_ceiling_out`, изменённый `tok_s_floor` — делает константу ниже правды, и никто об этом не узнает: превышение грейса даёт SIGKILL, а SIGKILL не оставляет ни пометки `cancelled`, ни сеттла оценки. ⛔ **И ловушка уже названа числом, а не гипотезой (замер платформенной сессии 10.09):** `attempt_max_s` инертен у ПЯТИ провайдеров из восьми, и у беcключевых `DeadlineFor` сверху не ограничена вовсе — она растёт с бюджетом линейно. Беcключевой `zai` перерастает сегодняшний максимум 1240 с (deepseek) при бюджете ≥ **43 400** токенов, то есть при `edit_ceiling_out` ≈ **9 900** против сегодняшних **8 000**. ⇒ запас по конфигу — меньше четверти. **Нетухнущая форма, которую надо построить:** движок ПЕЧАТАЕТ свой потолок ожидания сам (он и так умеет считать его `DeadlineFor` — функция экспортирована ровно для вопроса о конфигурации), платформа читает его НА БУТЕ и отказывается стартовать с грейсом ниже. ⚠ В паке «две остановки» этого НЕТ ни в одной половине — там принята сегодняшняя форма (пин на арифметику + строка реестра + комментарий с адресом), и она честно названа тухнущей | бэкенд | скоро | грейс платформы не может молча оказаться ниже законного ожидания движка: число выводится ИЗ ДВИЖКА в рантайме, а расхождение ловится на буте, а не SIGKILL-ом | эхо-протокол платформенной сессии по паку «две остановки», 10.09 (`D39.237` п.5) | +| 384 | **ЛЕНДИНГА НЕТ — А ПРОДУКТ ПО СЛОВУ ВЛАДЕЛЬЦА СОСТОИТ ИЗ ДВУХ ПОВЕРХНОСТЕЙ.** 10.09 владелец назвал модель: «фронт — это скорее IDE для переводов; к нему нужна обёртка в виде ЛЕНДИНГА; модель такая же, как у любого ИИ-продукта — лендинг с продуктом, и IDE отдельно, с аккаунтами, оплатой и всем таким» (`D39.239` п.1). Сегодня в репозитории есть только вторая поверхность, и та наполовину: `frontend/` — две маршрутные точки и витрина компонентов (About · AddBook · Bank), зона ЗАМОРОЖЕНА словом владельца с 15.08 и разморозка — отдельным его словом. Лендинга нет ни кодом, ни требованием в `docs/product-requirements.md`, ни строкой до этой. ⚠ **Практическое следствие, из-за которого строка заведена СЕЙЧАС, а не когда дойдут руки:** когда владелец скажет размораживать фронт, надо будет знать, ЧТО размораживают — витрина относится к IDE, и склейка её с лендингом в один поток была бы ошибкой архитектуры, а не темпа | фронт | когда-нибудь | у продукта названы обе поверхности: что делает лендинг, что IDE, где проходит граница входа и оплаты — и это записано требованием, а не устной моделью | слово владельца 10.09, `D39.239` п.1 | diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index d6ae84a8..f88fe8f6 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -1,6 +1,6 @@ # Журнал прогресса -> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-09-10, голова D39.238 — КУРС: движок и платформа до «работает и отдаёт результат», фронт ЗАМОРОЖЕН и 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-10, голова D39.239 — КУРС: движок и платформа до «работает и отдаёт результат», фронт ЗАМОРОЖЕН и 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 b8b12402..3390fe40 100644 --- a/docs/architecture/05-decisions-index.md +++ b/docs/architecture/05-decisions-index.md @@ -1,4 +1,4 @@ -# Реестр D-нот — карта актуальности v2 (D1–D39.238; титул — носитель головы, бампать при каждом аппенде) +# Реестр D-нот — карта актуальности v2 (D1–D39.239; титул — носитель головы, бампать при каждом аппенде) > ⚠ **Колонку «тело» `counts.py --check` НЕ сторожит по устройству:** он сверяет полноту НОМЕРОВ, а не > место тела, поэтому колонка держится дисциплиной лендинга. Не нашёл тело по колонке — иди в слайсы, @@ -297,3 +297,4 @@ | D39.236 | 10.09 | **ДИСПОЗИЦИИ ПО ЭХО-ПРОТОКОЛАМ обеих сессий пака «две остановки»: шесть возражений, шесть приняты, ТРИ — мои ошибки.** (1) счётчик оценки СИДИРУЕТСЯ из стора, а не копится с нуля — иначе пин равенства двух каналов зелен на пустом сценарии; (2) расширение правила присутствия `Money` формально МАЖОР, везём минором `1.3→1.4` как осознанное исключение (мажор читателем отвергается целиком); (3) «опора готова» для строки оператору — преувеличение, прогонного реестра летящих вызовов нет; (4) платформа поднимает `StreamVersion` и тем же движением пишет, каких полей 1.2/1.3 не читает; (5) «свип встанет на 20 минут» — неверный механизм, настоящий ущерб — ложная тревога `StalledAfter`; (6) 1240 с — свойство ПАРЫ, не константа платформы. ⭐ Все шесть пришли ПОСЛЕ двух кругов ревью: эхо-протокол — третий рубеж, а не формальность | стоп · шов · метод | | D39.237 | 10.09 | **ЗАПИСКА-ПЛАН ПЛАТФОРМЫ.** ⛔ Мой корректирующий минор контракта (`D39.235` п.6) положил гейт ЧУЖОЙ зоны — базовая линия была красной на входе сессии; носитель один (`platform/internal/httpapi/capabilities.go`), правку берёт сессия. **Норма: правка ратифицированного носителя сверяется с ГЕЙТАМИ на него тем же движением** (второй раз за две недели, ср. эрратy 08.09-б). ⭐ Сессия нашла сверх заказа: повторный `stop --no-block` по `deactivating` НЕ шлёт второй SIGTERM — иначе свип давал бы АВТОМАТИЧЕСКУЮ эскалацию в жёсткую остановку; свойство держалось на удаче, теперь пинится. Потолок ожидания — свойство каталога И бюджета: беcключевой `zai` перерастает 1240 с при `edit_ceiling_out` ≈ 9 900 против 8 000 сегодня. Нетухнущая форма — строка **383** | стоп · шов · метод | | D39.238 | 10.09 | ⛔ **ДВА SIGTERM ПОДРЯД GO-ПРОЦЕСС ВИДИТ КАК ОДИН** — замерено дважды независимо: `gap 0` → **0 из 20**, `gap 1 мс` → 20 из 20, контроль `gap 100 мс` → 5 из 5; коалесценция ниже канала (`runtime/sigqueue` держит БИТ, не счётчик), буфер не чинит. ⇒ ратифицированная форма «первый мягкий, второй жёсткий, третий дефолт» (`D39.234` п.1а) стояла на посылке «послать два = получить два», которой НЕТ: `mode: hard` первым нажатием давал бы МЯГКУЮ остановку молча, а пере-выпуск жёсткого сигнала свипом — ТРЕТИЙ SIGTERM, то есть смерть без кадра и сеттла. Контракт: сигналы упорядочены НАБЛЮДЕНИЕМ входа в фазу остановки, факт доставки долговечен. ⭐ Первый замер был неверен из-за прибора и дал противоположное число — сессия починила прибор и назвала это сама | стоп · шов · метод | +| D39.239 | 10.09 | **СЛОВО ВЛАДЕЛЬЦА: у продукта ДВЕ поверхности — ЛЕНДИНГ и IDE** («модель как у любого ИИ-продукта»); лендинга нет ни кодом, ни строкой, а `frontend/` — это IDE, строка **384**. **Замер, где живут учётки:** логин настоящий (OIDC + dev), **учётка создаётся САМА при первом входе**, пригласительного гейта НЕТ вовсе, дверь закрыта только конфигурацией (пустой issuer ⇒ поверхность не монтируется), оплаты нет намеренно. ⚠ Исправление моего же ответа владельцу: **`sqlc` УЖЕ используется** (1232 строки из 5688 в `pgstore`), моё «генератор срезал бы» было ложью из формы файлов. **Мандат владельца: протухшую прозу можно СНОСИТЬ**, диффы окаются у старшего коллеги; границы сноса — п.4 | продукт · учётки · доки | diff --git a/docs/architecture/05-decisions-log.md b/docs/architecture/05-decisions-log.md index 94a359c1..5250ad7b 100644 --- a/docs/architecture/05-decisions-log.md +++ b/docs/architecture/05-decisions-log.md @@ -1,4 +1,4 @@ -# Журнал решений оркестратора — контракт D1–D39.238 (живой файл: карта · эрраты · живые тела · голова D39.124+ (подрезка D39.139); тела закрытых эр — в слайсах `docs/archive/architecture/`, указатель ниже; реестр всех нот — `05-decisions-index.md`) +# Журнал решений оркестратора — контракт D1–D39.239 (живой файл: карта · эрраты · живые тела · голова 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+). @@ -3371,3 +3371,20 @@ bought NOTHING». ⇒ **`tmctl manifest` есть НИЖНЯЯ граница, **5. ⭐ УРОК О ПРИБОРЕ, который дороже самого факта.** Первая серия платформенной сессии дала «2 из 2» и была НЕВЕРНОЙ: она слала `kill` из шелла, и запуск двух процессов сам создавал зазор в миллисекунды. Она починила прибор, число перевернулось на ПРОТИВОПОЛОЖНОЕ, и она это назвала сама. **На неверном приборе вопрос был бы закрыт как несуществующий, и обе половины пака ушли бы в лендинг на посылке, которой нет.** ⇒ норма: замер, чей результат подтверждает УДОБНОЕ, проверяется на прибор прежде, чем на предмет; и «слипание» ловится только тем прибором, который умеет создать нулевой зазор. **6. Границы.** Пункты 1 и 5 — замерены, дважды и независимо. Пункт 2 — вывод из замера плюс ратифицированной формы, не отдельный замер. Пункт 3 — конструкция платформенной зоны, объявленная ею; путь до `deactivating` 0,014 с — её число, я его не воспроизводил. Ответ движковой половины на п.4 ещё не получен. + +## D39.239 — СЛОВО ВЛАДЕЛЬЦА: продукт делится на ЛЕНДИНГ и IDE; плюс замер, где сегодня живут учётки, и мандат на СНОС протухшей прозы (10.09, оркестратор №23) + +**1. ⭐ ПРОДУКТОВАЯ МОДЕЛЬ, названная владельцем 10.09 и до сих пор нигде не записанная.** «Фронт — это скорее IDE для переводов; к этому IDE нужна обёртка в виде ЛЕНДИНГА. Модель такая же, как у любого ИИ-продукта: лендинг с продуктом, и IDE отдельно — с аккаунтами, оплатой и всем таким». ⇒ **поверхностей у продукта ДВЕ, а не одна**, и та, что построена наполовину (`frontend/`), — это ВТОРАЯ из них. Лендинга нет вовсе: ни кода, ни строки в трекере, ни требования в реестре. ⚠ Это не «маркетинг потом»: разделение меняет то, ЧТО именно размораживать, когда владелец скажет размораживать фронт, — сегодняшняя витрина компонентов относится к IDE, а не к лендингу, и склеивать их в один поток было бы ошибкой. Носитель — строка **384**. + +**2. Где живут учётки СЕГОДНЯ — замерено, потому что вопрос владельца был фактическим.** + **(а) Логин настоящий, не заглушка:** OIDC-поток `/auth/login` → провайдер → `/auth/callback`, плюс `/auth/logout` и `/auth/logout-all` (`platform/internal/login/login.go`, греп `func (h *Handler) Routes`); отдельный dev-вход для стенда (`platform/internal/login/dev.go`, греп `/auth/dev-login`). + **(б) Учётка СОЗДАЁТСЯ САМА при первом успешном входе** (`platform/internal/pgstore/identity.go`, греп `case errors.Is(err, pgx.ErrNoRows)`): нет опознанной личности — заводится `users` плюс `identities`. Отдельной формы регистрации нет и не нужно. ⚠ Адрес почты попадает на УЧЁТКУ только если провайдер объявил его подтверждённым; неподтверждённый остаётся на личности и не повышается. + **(в) ⛔ ПРИГЛАСИТЕЛЬНОГО ГЕЙТА НЕТ:** ни списка допущенных, ни инвайтов — грепом по `platform/internal` вне тестов ни одного носителя (хиты слова `allowlist` относятся к другим предметам: список статусов, разрешённые redirect-URI, подмножества ингеста). ⇒ **всякий, кто пройдёт через провайдера входа, получает учётку.** + **(г) Дверь закрыта КОНФИГУРАЦИЕЙ, а не кодом:** пустой `OIDCIssuer` означает, что поверхность логина не монтируется вовсе (`platform/internal/config/config.go`, греп `Empty issuer means no login surface`). Это единственный сегодняшний рубеж, и он бинарный: либо никого, либо все. + **(д) Оплаты нет намеренно** (пополнение из админки, `D39.176` п.1); кредиты на пользователя есть. + +**3. ⚠ ИСПРАВЛЕНИЕ МОЕГО ЖЕ ОТВЕТА ВЛАДЕЛЬЦУ, данного часом раньше.** Я сказал ему, что запросы платформы к базе написаны руками и «генератор вроде `sqlc` срезал бы значительную часть». **Неверно: `sqlc` УЖЕ используется** — `platform/sqlc.yaml`, пять сгенерированных файлов, **1 232** строки кода из **5 688** в `pgstore` (22 %). Рукописного, стало быть, около четырёх с половиной тысяч, и часть его рукописна законно — транзакционная логика, которую генератор не выражает. Верное утверждение: генератор взят и покрывает пятую часть стора; вопрос «что ещё можно на него перевести» открыт, но «мы не взяли генератор» — ложь. ⭐ Класс ошибки мой обычный: вывод из ФОРМЫ файлов (увидел рукописный код и обобщил), а не из вопроса дереву — `platform/sqlc.yaml` лежал в одной команде `find`. + +**4. МАНДАТ НА СНОС, выданный владельцем прямым словом.** «Надо доактуализировать документацию… разрешаю СПИЛИТЬ прозу и воду, которая уже неактуальна — только аккуратно, окай диффы у Fable». ⇒ до сих пор протухшее ПОМЕЧАЛОСЬ (⚠-испр., баннер, эррата); теперь его можно УДАЛЯТЬ. ⛔ Границы, которые ставлю себе сам, потому что владелец сказал «аккуратно»: **(а)** тела D-нот не переписываются и не сносятся (D23.3) — только шапка и эрраты; **(б)** отчёты `docs/research/**` — улика, им баннер, не нож; **(в)** чужие зоны (`docs/experiments/**`, `backend/docs/`, `frontend/docs/`, `platform/docs/`) не трогаю ни при каком мандате; **(г)** каждый снос предъявляется диффом на ревью старшего коллеги ДО коммита — это условие владельца, а не моя осторожность; **(д)** сносится ПРОЗА, объявленная протухшей ЗАМЕРОМ, а не то, что мне кажется лишним. + +**5. Границы.** Пункты 2 и 3 пере-сняты мной на дереве, с адресами. Пункт 1 — прямая речь владельца, не вывод. Пункт 4 — его же мандат, границы (а)–(д) мои и объявлены здесь, чтобы их можно было оспорить.