Compress the seam cold review to current findings only: verdicts, confirmed decisions, money gaps, emitter requirements, and the one owner fork
This commit is contained in:
parent
d60cf31d97
commit
51e7d36755
1 changed files with 92 additions and 203 deletions
|
|
@ -1,223 +1,112 @@
|
|||
# 25 · Холодное ревью шва движок↔платформа: независимые панели
|
||||
# 25 · Холодное ревью шва движок↔платформа и топологии сервисов
|
||||
|
||||
> **Что это.** Шов, ратифицированный D39.85 (`research/23`), вынесен на независимую проверку:
|
||||
> абстрактная формулировка задачи отдана панелям чистых агентов, ничего не знающих о проекте.
|
||||
> Вопрос был не «оставить stdout или переехать», а «вот две задачи — как их поженить», без
|
||||
> подсказки пространства решений. Заказ владельца 05.08: «сформулировать максимально абстрактно и
|
||||
> посмотреть, какой механизм предложат сами».
|
||||
> **Метод.** Задача шва (control plane + многочасовой воркер, деньги, standalone-режим) отдана
|
||||
> панелям изолированных агентов в переодетом домене (сборка генома), без доступа к репозиторию.
|
||||
> Три чистых плеча: базовое (`wf_6adb39d7-870`, 5 агентов) · с добавленным фактом «воркер дёшево
|
||||
> резюмится» (`wf_2b45042d-115`, 5) · топологическое «сколько вообще нужно разворачиваемых единиц»,
|
||||
> без постулата разделения, с вебом (`wf_4ac43daf-ec5`, 6, три модели, включая seat-адвоката
|
||||
> монолита). Изоляция проверена поагентно по журналам: ноль файловых вызовов, ноль следов
|
||||
> репозитория. Первый прогон (`wf_b2b954de-e83`) загрязнён чтением репозитория и ОТБРОШЕН;
|
||||
> правило для будущих панелей: запрещать файловые инструменты явно и проверять постфактум.
|
||||
>
|
||||
> **Статус:** фактура. Ничего не ратифицирует и не отменяет; D39.85 в силе. Служит входом для
|
||||
> решения по строке 103 единого бэклога и по П-1/П-3.
|
||||
>
|
||||
> **Кто делал:** оркестратор №14, 05.08.2026. Прогоны — воркфлоу, транскрипты в сессионном
|
||||
> каталоге (`wf_b2b954de-e83` грязный, `wf_6adb39d7-870` чистый, `wf_2b45042d-115` чекпойнт-плечо).
|
||||
> **Статус:** фактура. D39.85 в силе; служит входом для строки 103 единого бэклога, П-1/П-3 и
|
||||
> решения по транспорту. Оркестратор №14, 05.08.2026.
|
||||
|
||||
## ⚠ Первый прогон ЗАГРЯЗНЁН — не цитировать
|
||||
## Вердикты панелей
|
||||
|
||||
Восемь агентов первого прогона получили абстрактную формулировку, но остались с файловыми
|
||||
инструментами в рабочем каталоге: **все восемь** сходили `Bash`/`Read` по репозиторию, узнали
|
||||
проект и прочитали `research/23`, D-решения, `backend/`, `pricing.go`. Запрет сети трое соблюли;
|
||||
запрет файлов я поставить забыл — ошибка постановки, не агентов.
|
||||
|
||||
Поэтому вывод «независимая панель сошлась на нашей схеме шва» из первого прогона **стоит ноль**:
|
||||
они её прочитали. Единственное, что от него остаётся, — большинство проголосовало ПРОТИВ
|
||||
ратифицированного дизайна, а загрязнение толкает к согласию с прочитанным, не против.
|
||||
|
||||
Урок для следующих панелей: запрещать **все** инструменты явно и **проверять постфактум** по
|
||||
`journal.jsonl` (счётчик `tool_use` поагентно). В чистом прогоне проверка дала ноль обращений к
|
||||
файлам и сети и ноль следов репозитория — только тогда результат брался в работу.
|
||||
|
||||
## Метод чистого прогона
|
||||
|
||||
Домен переодет (сборка генома, не перевод), числа изменены, ни одного совпадения с репозиторием.
|
||||
Пять изолированных архитекторов, пять разных линз: холодный архитектор · «отгрузить за три недели
|
||||
вдвоём» · «проектируй от отказов» · «сначала защити самый развязанный вариант, потом самый
|
||||
связанный, потом выбери» · «ты это уже строил, и вышло плохо». Схема ответа требовала перечислить
|
||||
ВСЕ взвешенные механизмы, включая отвергнутые, — census важнее вердикта.
|
||||
|
||||
Сценарий: control plane со счетами, кредитами, очередью и HTTP для SPA, деплоится несколько раз в
|
||||
неделю; воркер обрабатывает одну задачу 4–30 часов, держит эксклюзивный лок на каталоге, тратит
|
||||
деньги на платные API, обязан оставаться запускаемым в одиночку на ноутбуке; одна VM, оркестратора
|
||||
нет.
|
||||
|
||||
## Расклад чистой панели
|
||||
|
||||
**Родитель-ребёнок с потоком на stdout или унаследованном дескрипторе — 0 выбрали, 5 отвергли.**
|
||||
Формулировка повторяется почти дословно: *время жизни воркера не должно быть подмножеством времени
|
||||
жизни control plane*. Названный убийца — `KillMode=control-group`: рестарт control plane убивает
|
||||
весь его cgroup вместе с 22-часовой задачей. Один: «залатать это `setsid` и двойным форком можно,
|
||||
но в этот момент ты руками написал systemd, только хуже».
|
||||
|
||||
| Механизм | выбрали | второй | отвергли |
|
||||
|---|---|---|---|
|
||||
| Процесс-на-задачу под systemd (`Restart=no`, длинный `TimeoutStopSec`, стоп SIGTERM) | **5** | — | 0 |
|
||||
| Append-only журнал в каталоге задачи, control plane тейлит по курсору | **3** | 1 | 1 |
|
||||
| Push из воркера в control plane по unix-сокету (HTTP/JSON) | **2** | 2 | 1 |
|
||||
| Передача конфигурации задачи файлом в каталоге (нет файла = режим ноутбука) | **5** | — | 0 |
|
||||
| SSE в браузер | **5** | — | 0 |
|
||||
| Воркер как библиотека внутри control plane | 0 | 0 | **5** |
|
||||
| Воркер как ребёнок control plane (любой IPC) | 0 | 0 | **5** |
|
||||
| Чтение stdout/journald как источника событий | 0 | 0 | **5** |
|
||||
| gRPC · брокер · общая БД · чтение приватной БД воркера · синхронный запрос авторизации на каждый платный вызов | 0 | 0 | **5** каждый |
|
||||
|
||||
Отдельно: journald отвергнут как контракт всеми пятью (он **молча роняет** под всплеском и ротирует
|
||||
по своему расписанию), но всеми пятью оставлен как человеческий канал отладки.
|
||||
|
||||
## Что совпало с нами вхолодную
|
||||
|
||||
Семь решений панель назвала единогласно, не зная о нас ничего:
|
||||
|
||||
| Назвали 5/5 | У нас |
|
||||
| Вопрос | Результат |
|
||||
|---|---|
|
||||
| Предавторизованный потолок, который воркер держит САМ; синхронной авторизации нет | холд + потолок движку (D39.84) |
|
||||
| Hold → capture → возврат остатка | `Hold`/`Settle`/`Release` |
|
||||
| Идемпотентное применение по `(job_id, seq)` | `(engine_run_id, seq)` |
|
||||
| Control plane НИКОГДА не открывает приватную БД воркера | прямой запрет D39.85 §4 |
|
||||
| Standalone — тот же путь кода, без ветки «есть ли control plane» | так и есть |
|
||||
| `flock` вместо pid-файлов | так и есть |
|
||||
| Целочисленные деньги | на платформе да; ⚠ в движке `float64` |
|
||||
| Запись намерения ДО платного вызова, расчёт после | Р7, есть |
|
||||
| Сколько разворачиваемых единиц | **2 — единогласно (6/6)**, включая seat-адвоката монолита; за монолит 0 |
|
||||
| Платформа — родитель процесса движка + поток на stdout/fd | **0 выбрали, 10 отвергли** (оба плеча) |
|
||||
| Дешёвый резюм воркера меняет расклад? | **Нет.** 5/5: «факт снял ограничения, но выбор не сделал»; при дорогом прерывании ушли бы в ту же сторону сильнее |
|
||||
| Канал воркер→платформа | Append-only журнал в каталоге прогона, тейл по курсору — 8/10; unix-сокет-push упал в обоих плечах по недолговечности через рестарты платформы |
|
||||
| Супервизор воркера | systemd, юнит-на-задачу, `Restart=no`, стоп SIGTERM — 10/10 |
|
||||
| gRPC · брокер · общая БД · чтение приватной БД воркера · stdout/journald как источник событий · синхронная авторизация на каждый платный вызов | отвергнуты почти единогласно (чтение приватной БД: 1 голос «за» из 11 — единственное расхождение с D39.85 §4 за все плечи) |
|
||||
|
||||
Это, а не вердикт по транспорту, — главный результат: несущие решения шва воспроизводятся
|
||||
независимо. Транспорт же, по их же словам, меняется при переезде на вторую машину, а перечисленное
|
||||
переживает без правки.
|
||||
## Подтверждено вхолодную (совпало с нашими решениями)
|
||||
|
||||
## Что назвали обязательным, а у нас нет
|
||||
Названо 5/5 агентами, не знавшими о проекте: предавторизованный потолок, который воркер держит сам
|
||||
(= холд + потолок движку, D39.84) · hold→capture→возврат остатка (`Hold`/`Settle`/`Release`) ·
|
||||
идемпотентное применение по `(run_id, seq)` · запрет читать приватную БД воркера (D39.85 §4) ·
|
||||
standalone тем же путём кода · `flock` вместо pid-файлов · запись намерения ДО платного вызова (Р7)
|
||||
· целочисленные деньги (⚠ у нас — на платформе; в движок float64 входит раньше, см. «Деньги»).
|
||||
|
||||
1. **Реконсилятор мёртвых воркеров** — компонент, не удобство: на старте control plane добрать
|
||||
хвост журнала, пометить прогон прерванным, вернуть остаток холда. Один добавил: «если оставить
|
||||
один тест, оставьте SIGKILL реального воркера, иначе этот код сгниёт».
|
||||
2. **Состояние `uncertain` для окна «упали между платным вызовом и записью расчёта».** Назвали все
|
||||
пятеро, лечат одинаково: смещение в сторону списания, запись по оценке, флаг человеку,
|
||||
**никогда молчаливая бесплатная работа**. У нас такого состояния нет.
|
||||
3. **Сверка с данными провайдера** (3 из 5, ночным прогоном). Совпадает с находкой по коду:
|
||||
платформа считает целочисленно и точно, но на вход арифметики приходит `float64`, посчитанный по
|
||||
руками поддерживаемой таблице цен, и у незнакомого слага есть ненулевой дефолтный якорь
|
||||
(`backend/internal/ledger/pricing.go:27-52`, `CostUSD` на `float64`). Якорь — осознанное решение
|
||||
с хорошим обоснованием ($0 ослепил бы потолки), но следствие остаётся: при незнакомом слаге сумма
|
||||
есть оценка. Спорить о ±1 микродолларе поверх числа с процентной систематикой — инвертированный
|
||||
приоритет.
|
||||
4. **Пиннинг задачи к версионированному пути бинаря на старте** (4 из 5): иначе апгрейд воркера
|
||||
меняет поведение между попытками одной задачи. Прямо в цель «детерминизм» (канон §6).
|
||||
**Два модуля подтверждены, но несущие доводы другие, чем в наших доках.** Всё «процессное»
|
||||
(пиннинг версии, cgroups, независимый рестарт, пер-задачные журналы) даёт и один бинарь,
|
||||
exec-ающий сам себя транзиентным юнитом. До «двух ПОСТАВОК» доживают ровно два довода:
|
||||
**граница как ошибка компиляции** (модульный гард D39.85 — ровно это) и **независимые релизные
|
||||
поезда** (фикс движка не ждёт CI платформы). Лучшая карта монолита — «одна транзакция решает
|
||||
деньги» — фальшива: приватная БД задачи + глобальный леджер + провайдер = **три хранилища при
|
||||
любом числе процессов**, outbox и сверка нужны в любом исходе.
|
||||
|
||||
## Чего у них не было — и естественный эксперимент на этом (плечо 2)
|
||||
## Настоящие драйверы против «платформа — родитель» (не зависят от стоимости прерывания)
|
||||
|
||||
Панель отвергла родителя-ребёнка на посылке «редеплой уничтожает часы оплаченной работы». У нас эта
|
||||
посылка слабее: движок чекпойнтится на уровне chunk×stage и резюмится
|
||||
(`backend/internal/pipeline/resume.go`), поэтому остановка платформы стоит одного чанка, а не
|
||||
прогона. Оркестратор выдвинул это как контраргумент — и проверил его чужими руками, а не оставил
|
||||
своим мнением.
|
||||
1. **Несовпадение времён жизни:** деплой платформы несколько раз в неделю против прогона 4–30 ч.
|
||||
2. **Плановая недоступность платформы делает долговечность требованием к каналу:** любой push-канал
|
||||
требует буфера/ретраев/дедупа — а этот буфер и есть журнал.
|
||||
3. **Атомарность денег:** «юнит сделан» и «юнит стоил $X» — одна транзакция в хранилище воркера.
|
||||
4. **Радиус поражения:** леджер и аутентификация не делят адресное пространство и OOM-цель с
|
||||
часто меняющимся воркером.
|
||||
5. **Standalone не должен быть режимом:** непрогоняемая ветка `--no-server` гниёт.
|
||||
|
||||
**Плечо 2 (`wf_2b45042d-115`, тоже чистое — проверено поагентно):** та же формулировка, тот же
|
||||
переодетый домен, та же изоляция, **изменена ровно одна переменная** — в сценарий добавлено, что
|
||||
воркер чекпойнтится ежеминутно и резюмится, а прерывание стоит минут и центов, никогда не часов.
|
||||
**Наше смягчение, которого у панелей не было:** при остановке платформы движок останавливается
|
||||
тоже (сигнал группе; на stdout — SIGPIPE), окна «пишет без слушателя» нет, события не теряются.
|
||||
Довод №2 бьёт по нам не потерей событий, а тем, что **каждый деплой платформы прерывает все идущие
|
||||
переводы** ценой одного чанка каждый.
|
||||
|
||||
**Расклад не сдвинулся.**
|
||||
## Развилка владельцу
|
||||
|
||||
| | плечо 1 (без факта) | плечо 2 (с фактом) |
|
||||
|---|---|---|
|
||||
| Родитель-ребёнок + поток на stdout/дескрипторе | 0 выбрали, 5 отвергли | **0 выбрали, 5 отвергли** |
|
||||
| systemd, юнит-на-задачу | 5 | **5** |
|
||||
| Append-only журнал с курсором | 3 (+1 вариантом) | **5** (4 файлом, 1 таблицей внутри БД воркера) |
|
||||
| Push по unix-сокету | 2 (+2 вторым) | **0** — упал по причине, к новому факту не относящейся |
|
||||
**Должен ли идущий перевод переживать деплой платформы?**
|
||||
- **Да** → журнал в каталоге прогона + движок отдельным юнитом; платформа перестаёт быть родителем.
|
||||
- **Нет** → нынешняя форма (родитель + stdout) законна, но фиксируется как сознательная ставка с
|
||||
явной ценой; формулировка «переезд не окупается» опровергнута.
|
||||
|
||||
Поле «сколько весил дешёвый резюм» отвечали все пятеро, и все пятеро сказали одно: **факт снял
|
||||
ограничения, но выбор не сделал.** «Весил много, но почти целиком в сторону, обратную очевидной» ·
|
||||
«повлиял на жизненный цикл и почти не повлиял на механизм» · «изменил мою уверенность и число
|
||||
строк куда сильнее, чем выбор». Один прямо опознал постановку: *«свойство вставлено в бриф как
|
||||
приманка к выводу „прерывания дешёвы, значит просто слинкуйте воркер в control plane“»*.
|
||||
Формат событий (NDJSON, hello-хендшейк, `(run_id, seq)`) не меняется ни в одном исходе — меняется
|
||||
только кто спавнит и откуда читает. Решение владельца 05.08: одна машина пока что; при второй
|
||||
машине умирают файловая шина/сокет/`systemctl start`, переживают outbox, денежная модель,
|
||||
идемпотентность, SSE. Цена переезда мала, если платформа тейлит журнал, и велика, если она родитель.
|
||||
|
||||
Контрфактическую сторону тоже проверили: при ДОРОГОМ прерывании они ушли бы в ту же сторону
|
||||
сильнее, а не назад. То есть переменная не является шарниром ни в одну сторону.
|
||||
## Деньги: обязательные механизмы, которых у нас нет
|
||||
|
||||
**Что она реально изменила** — объём механизма при той же форме: не нужен протокол drain/quiesce,
|
||||
не нужно рукопожатие «можно ли тебя останавливать», не нужен интерлок деплоя, `systemctl stop`
|
||||
принимается как полный глагол остановки. Один оценил: «примерно половина механизма, который иначе
|
||||
понадобился бы, этим свойством удаляется». И ещё: факт **сменил основание отказа** от варианта
|
||||
«воркер внутри control plane» — аргумент «деплой убьёт задачу» перестал работать, и отказ переехал
|
||||
на радиус поражения (леджер и аутентификация не должны делить адресное пространство и OOM-цель с
|
||||
еженедельно меняющимся воркером). Вердикт тот же, обоснование другое.
|
||||
1. **Реконсилятор мёртвых воркеров** (компонент, не удобство): на старте платформы добрать хвост,
|
||||
пометить прогон прерванным, вернуть остаток холда. Тестировать SIGKILL'ом реального воркера.
|
||||
2. **Состояние `uncertain`** для окна «упали между платным вызовом и записью расчёта»: смещение в
|
||||
сторону списания, запись по оценке, флаг человеку; молчаливой бесплатной работы не бывает.
|
||||
3. **Сверка с данными/инвойсом провайдера** (ночной прогон). Приоритетнее споров об округлении:
|
||||
в движке суммы считаются в float64 по ручной таблице цен с ненулевым дефолтным якорем для
|
||||
незнакомого слага (`backend/internal/ledger/pricing.go:27-52`) — систематика процентная, а не
|
||||
микродолларовая.
|
||||
4. **Гейт на каждый платный вызов, а не на юнит работы** — «перерасход ≤ один юнит» без этого
|
||||
утверждение, а не механизм. (Наши вызовы синхронные — оценка перерасхода держится, но гейт
|
||||
всё равно пер-вызовный.)
|
||||
|
||||
**Вывод: контраргумент про chunk-резюм не работает.** Настоящие драйверы, названные независимо от
|
||||
стоимости прерывания:
|
||||
## Проектные требования к эмиттеру потока (задать до постройки, строка 103)
|
||||
|
||||
1. **Несовпадение времён жизни** — деплой несколько раз в неделю против задачи на 4–30 часов.
|
||||
Выбирает супервизора раньше, чем вообще заходит речь о протоколе.
|
||||
2. **Плановая недоступность control plane делает ДОЛГОВЕЧНОСТЬ требованием к каналу.** Он лежит
|
||||
несколько раз в неделю ПО ЗАМЫСЛУ, значит любой push-канал нуждается в буфере, ретраях и
|
||||
дедупликации — а буфер, который вы построите, и есть журнал. Это и убивает сокеты, пайпы,
|
||||
journald и localhost-HTTP как ОСНОВНОЙ канал.
|
||||
3. **Атомарность денег** — «юнит сделан» и «юнит стоил $X» обязаны быть одной транзакцией в
|
||||
собственном хранилище воркера.
|
||||
4. **Радиус поражения** — см. выше.
|
||||
5. **Standalone не должен быть режимом** — ветка `--no-server`, которую никто не гоняет, гниёт.
|
||||
- **Outbox правильно:** строка расхода — в БД задачи, в той же транзакции, что чекпойнт;
|
||||
`events.jsonl` ПРОИЗВОДИТСЯ из неё релеем (иначе двойная запись — ловушка, в которую попали
|
||||
3 из 6 агентов, призывая сам паттерн).
|
||||
- **`events` ≠ `status`:** долговечный денежный журнал (fsync, seq) отдельно от косметического
|
||||
снапшота живости (atomic rename, ~2 с, из него никогда не биллить).
|
||||
- **Перекос версий:** прогон может резюмить более новый движок, чем начал. Штамповать версию в
|
||||
каталоге, резюм чужой версией — только по явному флагу. (В канон детерминизма, рядом с
|
||||
`brief_hash`.)
|
||||
- **Живость = растущий `seq`**, а не удерживаемый лок.
|
||||
- **Сброс буфера на всех путях выхода:** `os.Exit`/`log.Fatal` пропускают defer и теряют финальные
|
||||
события.
|
||||
- **Обратное давление:** пайп/канал ограничен; политика на переполнение (блокировать воркер или
|
||||
ронять с маркером `events_dropped`) выбирается явно, молчаливой третьей нет.
|
||||
|
||||
**Оговорка, которой у панели не было и которая касается только нас.** У нас при остановке платформы
|
||||
движок останавливается ТОЖЕ (сигнал группе, а на stdout ещё и SIGPIPE), поэтому окна «движок пишет,
|
||||
слушателя нет» не возникает и события не теряются. Аргумент №2 бьёт по нам не потерей событий, а
|
||||
тем, что **каждый деплой платформы прерывает все идущие переводы**, ценой одного чанка каждый.
|
||||
То есть вопрос сводится к продуктовому: **должен ли четырёхчасовой перевод переживать деплой
|
||||
платформы?** Если да — журнал и отдельный юнит. Если нет — пайп законен, и цена названа явно.
|
||||
## Прочее найденное
|
||||
|
||||
## Что панель 2 добавила сверх первой
|
||||
|
||||
- **Разделять долговечный денежный канал и косметический канал живости:** `events.jsonl`
|
||||
(fsync, append-only, с номерами) отдельно от `status.json` (атомарное переименование, ~2 с, явно
|
||||
НЕдолговечный, из него никогда не биллить). 5/5.
|
||||
- **Рамка outbox:** строка журнала — это ПРОЕКЦИЯ уже закоммиченной строки в БД воркера,
|
||||
побайтово переиздаваемая после краха. Это превращает файл из «второй записи» в производный
|
||||
артефакт и снимает половину возражений про fsync-дисциплину.
|
||||
- **Перекос версий на длинной задаче:** воркер выкатывается еженедельно, задача идёт 30 часов —
|
||||
значит задачу может ПРОДОЛЖИТЬ более новый воркер, чем её начал. Подняли 4 из 5; двое штампуют
|
||||
версию воркера в каталоге задачи и отказываются резюмиться без явного
|
||||
`--allow-version-change`. Для нас это прямо в канон §6 (детерминизм) и рядом с `brief_hash`.
|
||||
- Один из пяти выбрал вариант «control plane читает приватную БД воркера» (в плече 1 его отвергали
|
||||
5/5) — единственное расхождение с D39.85 §4 за три панели. Меньшинство, но зафиксировано.
|
||||
|
||||
## Развилка: одна машина
|
||||
|
||||
Все пять независимо назвали ОДИН и тот же переворачивающий факт: **будет ли воркер когда-нибудь
|
||||
работать на машине, отличной от control plane.** Решение владельца 05.08: **одна машина пока что.**
|
||||
|
||||
Растащить при этом можно, и домен этому не мешает: лок и каталог — пер-книжные, а не пер-системные,
|
||||
поэтому книга пиннится к хосту (это уже записано в `platform/BACKLOG.md`, П-3: сериализация по
|
||||
`book_id`, пиннинг книги к хосту, лизы `book_leases`). Через границу машины не проезжают ровно три
|
||||
вещи, и все три сегодня в конструкции есть: платформа как **родитель** процесса; чтение его потока
|
||||
из пайпа или файла в его каталоге; запуск `tmctl status --json` платформой. Шаг на вторую машину —
|
||||
это «на каждый хост ставится агент», который спавнит движок, читает поток и толкает события
|
||||
платформе; идемпотентность, холд, леджер и SSE переживают без правки.
|
||||
|
||||
**Разница не в «можно или нельзя», а в цене шага:**
|
||||
|
||||
- платформа **родитель** движка → переезд переписывает супервизор: родство процессов, пайп, сигналы
|
||||
группе, вызов `status --json`, плюс разваливается cgroup-аргумент, которым закрыт PD-13;
|
||||
- платформа **тейлит журнал по курсору** → переезд подменяет источник, код приёма не меняется.
|
||||
|
||||
## Открытое
|
||||
|
||||
- **Вопрос владельцу, к которому всё свелось: должен ли идущий перевод переживать деплой
|
||||
платформы?** Три панели, пятнадцать архитекторов, ноль голосов за нынешнюю форму — но их довод
|
||||
упирается именно в это, а у нас есть смягчение (движок останавливается вместе с платформой, и
|
||||
резюм стоит одного чанка). «Да» ⇒ журнал + отдельный юнит, движок перестаёт быть ребёнком.
|
||||
«Нет» ⇒ нынешняя форма законна, и цена записана явно: каждый деплой прерывает все переводы.
|
||||
- Строка 103 единого бэклога: транспорт потока. В ЛЮБОМ исходе ставка должна быть записана как
|
||||
СОЗНАТЕЛЬНАЯ, с названной ценой, а не как «переезд не окупается» — эта формулировка опровергнута
|
||||
плечом 2.
|
||||
- Три денежные дыры выше (реконсилятор · `uncertain` · сверка с провайдером) — строками единого
|
||||
бэклога, зона платформы их одна не закроет: половина работы в движке.
|
||||
- Пиннинг к версионированному бинарю и **отказ резюмиться воркером другой версии** — туда же.
|
||||
- Разделение `events` (долговечный, денежный) и `status` (косметический, не для биллинга) — принять
|
||||
или отклонить при проектировании эмиттера, до его постройки.
|
||||
|
||||
## Что из этого следует методически
|
||||
|
||||
Три панели дали три разных урока о самой процедуре, и они дороже любого вердикта:
|
||||
|
||||
1. **Абстрактная формулировка обязана быть изолированной по-настоящему.** Запрет сети без запрета
|
||||
файлов — не изоляция. Проверять постфактум, поагентно.
|
||||
2. **Слабая аргументация ≠ неверная позиция.** Оркестратор сперва принял предложение зоны по её
|
||||
ссылкам, потом отклонил его же, открыв ссылки и увидев, что они не держат. Обе итерации спорили
|
||||
о качестве ссылок, а не о существе.
|
||||
3. **Свой контраргумент проверять чужими руками.** Довод «chunk-резюм делает нынешнюю форму
|
||||
нормальной» звучал убедительно, был предъявлен как решающий — и не пережил панели, которой этот
|
||||
факт дали прямым текстом. Один из пятерых даже опознал его как приманку в постановке.
|
||||
- **Диск не ограничен нигде:** `ENOSPC` на ФС леджера ломает денежные инварианты разом. Леджер на
|
||||
своей ФС, квота на задачу, проверка места при допуске. (В зону платформы при деплой-слое.)
|
||||
- **Состояние systemd — не истина:** транзиентный юнит выгружается, VM перезагружается; источник
|
||||
истины на старте = каталоги задач + БД платформы.
|
||||
- **Ключи идемпотентности провайдеров протухают** (порядок суток) — replay как оптимизация ретрая,
|
||||
не гарантия.
|
||||
- **SPA из бинаря платформы** (один origin, нет перекоса версий) — 6/6 у панели; у нас не решено,
|
||||
вопрос к П-1/фронту.
|
||||
- SIGPIPE зависит от номера дескриптора (fd 1/2 — смерть процесса, прочие — EPIPE; замерено):
|
||||
нынешний stdout даёт бесплатную остановку осиротевшего движка, переезд на fd 3 её ломает.
|
||||
- Защита stdout от посторонних записей, если канал остаётся: dup-перехват на уровне дескриптора в
|
||||
`main` движка, только в области потоковой команды (безусловный сломал бы `tmctl status --json`).
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue