42 KiB
Промт сессии: ПЛАТФОРМА, пак P13 — «шов возврата оплаченного прогона»
⚠⚠ АРХИВ. ПРОМТ ОТРАБОТАН — ИНСТРУКЦИИ ОТСЮДА НЕ ИСПОЛНЯЮТСЯ. Выдан 02.09, сдан 03.09, принят с дофиксом (
D39.188). Исход: шесть пунктов состава исполнены, заказ пункта 3 оказался НЕДОСТАТОЧЕН и зона это доказала (PD-438, major), дофикс по шести пунктам отработан, приёмка второго круга оставила одну правку записки о хосте. ⚠ Часть якорей этого файла МЕРТВА по построению: пак переписал цели (строка рантбука,Quarantine). Живые носители:D39.188·docs/PLATFORM_P13_DOFIX_2026-09-03.md·platform/docs/platform-PROGRESS.md.
Роль: платформа. Зона записи:
platform/. Чужие зоны читаешь, не правишь. Не коммитишь и вообще не трогаешь индекс и историю — почему именно, и полный список запретов:CLAUDE.md, «Git-координация мультисессий». Обязателен к ссылке:platform/docs/ENGINEERING_STANDARDS.md; отступление — пинг, не самовольство. Направление зоны —platform/docs/PLATFORM_DIRECTION.md.
Какая проблема и что изменит твой результат
Оплаченный прогон сегодня может подорожать, зависнуть или замереть на экране — без вины пользователя и без единого сигнала оператору. Четыре независимых пути ведут к одному и тому же: человек заплатил, а получил либо не то, либо ничего, и вывести его из этого состояния нечем, кроме psql. После пака оплаченный прогон возвращается на те деньги, за которые был продан, оператор перестаёт начислять кредиты дважды, а чужая строка в общем журнале книги перестаёт замораживать проекцию чужого прогона.
Карта чтения — пять позиций, дальше только по их ссылкам
platform/README.md— устройство зоны ·platform/docs/ENGINEERING_STANDARDS.md(обязателен).platform/docs/platform-PROGRESS.md— зонный журнал: текущее состояние и пинги оркестратора (там же ПИНГ №21 про гейт батареи и ПИНГ №22 про заниженную ставку и снятый сайдкар).- Ряды регистра, названные ниже поимённо:
PD-168·PD-89·PD-426·PD-214·PD-374—platform/docs/DEFECT_REGISTER.md, греп по номеру. docs/architecture/15-money-path.md§3 — деньги платформы по шагам (холд, расплата,run abandon).docs/architecture/14-api-contract/— канон контракта; зеркало фронта НЕ норматив.
⚠ Ратифицированное вложено в тело этого промта; код-факты добываешь САМ — указатели ниже отправные точки, код первичен. Числа ниже даны С КОМАНДОЙ ПОЛУЧЕНИЯ: пере-ранишь — сойдётся; не сошлось — это находка, неси её пингом, а не подгоняй под текст.
⚠ ПРЕДУСЛОВИЕ, НЕ ПУНКТ РАБОТЫ — прочти прежде всего
Условий хоста у батареи ЧЕТЫРЕ, и все четыре на этом хосте выполнимы. Выставь их до первой команды — иначе половина зоны молча не гоняется:
| условие | как выставить | что откроет |
|---|---|---|
TM_PLATFORM_TEST_DSN |
стенд уже поднят (/tmp/.s.PGSQL.55433); DSN — platform/docs/STACK_DECISIONS.md, раздел стенда разработчика, греп port=55433 |
денежный путь runs, pgstore, books, cmd/tmplatformctl |
TM_PLATFORM_TEST_ENGINE_BIN + TM_PLATFORM_TEST_BOOK_TEMPLATE |
движковый бинарь и шаблон деплоя | 3 теста internal/runner + internal/books |
| достижимый пользовательский systemd | на этом хосте /run/user/1000 жив, ставить нечего |
systemdOrSkip, internal/runner/systemd_test.go |
export PATH=$HOME/go/bin:$PATH |
⚠ без него make check НЕ ЗАПУСКАЕТСЯ ВОВСЕ: tools-check падает на sqlc («got: none»), хотя нужный v1.31.1 лежит в ~/go/bin |
весь make check |
Проверка последнего одной командой: cd platform && make tools-check → Error 1 на sqlc;
cd platform && PATH=$HOME/go/bin:$PATH make tools-check → выход 0. Сети нет — ничего не ставь,
бинарь уже на диске, вопрос только в PATH.
Замер 02.09 на этом хосте, без DSN (числа — с командами; голый go test ./... печатает ровно
18 строк «ok» и НИ ОДНОГО из этих чисел, поэтому команда счёта — verbose):
cd platform && go test ./... -count=1 -v > /tmp/battery_v.txt 2>&1; echo "exit=$?"
grep -cE '^=== RUN [^/]+$' /tmp/battery_v.txt # 661 верхнеуровневых тестов
grep -c '^--- PASS' /tmp/battery_v.txt # 342
grep -c '^--- SKIP' /tmp/battery_v.txt # 319 верхнеуровневых скипов
grep -c '^--- FAIL' /tmp/battery_v.txt # 0
grep -c '^ok ' /tmp/battery_v.txt # 18 пакетов
grep -c -- '--- SKIP' /tmp/battery_v.txt # 330 — ТО ЖЕ САМОЕ вместе с подтестами
⚠ Снимаю кажущееся противоречие заранее: ПИНГ №21 в зонном журнале пишет про пустое окружение
330 скипов, здесь стоит 319. Это ОДИН И ТОТ ЖЕ прогон: make check грепает -- '--- SKIP',
то есть считает подтесты вместе с верхнеуровневыми. Оба числа верны, расходиться тут не о чем.
Среди пропущенных — 110 тестов денежного пути реконсилятора (верхнеуровневых; вхождений сообщения вместе с подтестами — 112):
cd platform
go test ./internal/runs/ -count=1 -v 2>&1 \
| awk '/reconciler.s money path/{p=1;next} p&&/^--- SKIP/{n++} {p=0} END{print n+0}' # 110
go test ./internal/runs/ -count=1 -v 2>&1 | grep -c "reconciler's money path" # 112
⚠ make check про скипы ЧЕСТЕН — печатает строку «did NOT run …» и имена скипнутых тестов.
Молчит именно голый go test ./....
Цена, которую ты обязан не повторить: в регистре 21 ряд заведён с формулировкой «мутация
пережила ПОЛНУЮ батарею», и восемь из них открыты — PD-433 · PD-375 · PD-382 · PD-383 ·
PD-386 · PD-388 · PD-389, плюс PD-423 (там фраза в смысле «пин ЗЕЛЁН в полной батарее со
скипами 0»). Ни один не называет DSN, то есть «полная батарея» этих вердиктов могла быть той
самой, где тёмно 319 тестов.
cd platform && awk -F'|' '/^\| PD-/{l=tolower($0);
if(l~/полную батарею|полной батарее|всю батарею/){st=$(NF-2);gsub(/^ +| +$/,"",st);
if(st=="open")o++;else f++}}END{print "OPEN="o,"FIXED="f,"TOTAL="o+f}' docs/DEFECT_REGISTER.md
# OPEN=8 FIXED=13 TOTAL=21
⇒ Каждая посадка мутации в твоём отчёте обязана нести строку «гонялось при DSN = да». Иначе пак проверит себя ровно тем способом, каким заводились ряды, которые он чинит.
Состав пака — четыре правки, гейт и одна строка рантбука
1. ГЛАВНОЕ — денежный бюджет прогона ЧИТАТЬ, а не пере-выводить из ставки
internal/runs/reconcile.go, функция reopen (:1350). Ставка читается там ДВАЖДЫ, и оба места
денежные:
cd platform && grep -n 'Pricing' internal/runs/reconcile.go
# 1363: budget := s.Pricing.Ceiling(l.CeilingChapters)
# 1397: consent = s.Pricing.Ceiling(l.CeilingChapters)
:1363— бюджет перезапуска:remaining = budget - spent, отсюдаCeilingвRestartInput.:1397— funded consent на пере-оплату приbook.BankMoved, уезжает вRestartInput.AcceptRebill. Стоит в веткеif from == fromAFinishedRun, то есть только на пользовательскомResume— ровно на том пути, который и опасен. Комментарий:1384-1386подтверждает денежный смысл: «funded consent, the same figure Start grants».
Вызывающих у reopen двое: свиповый restart (:1224, вызов :1244, fromALiveRun) и контрактный
Resume (:1481, вызов :1548, fromAFinishedRun). Смена TM_PLATFORM_USD_PER_CHAPTER
(internal/config/config.go:485=TM_PLATFORM_USD_PER_CHAPTER) между покупкой и продолжением молча пере-оценивает уже оплаченный
прогон в обе стороны; при удвоении ставки на тонком счёте он становится невозобновляемым. Носитель —
PD-168 (стоит minor, вес занижен; замер ряда: холд 5.500000 вместо 2.500000).
Задача (делай РОВНО так, отступление = пинг):
⚠ Первая половина УЖЕ построена, строить нечего. PD-168 дословно: «Исходная сумма восстановима
без пересчёта — она лежит в холде первой попытки (reservations.ceiling_micro_usd /
run_attempts.ceiling_micro_usd)». Обе колонки в схеме есть:
cd platform && grep -n 'ceiling_micro_usd' internal/pgstore/migrations/*.sql
# ЧЕТЫРЕ хита, из них колонки — две:
# 00007_credits.sql:72 — reservations.ceiling_micro_usd
# 00009_runner.sql:36 — run_attempts.ceiling_micro_usd (:70 — её же `drop` в Down-миграции)
# 00011_ceiling_argument.sql:5 — КОММЕНТАРИЙ-предупреждение, не колонка
Значит задача не «завести хранение», а «заставить reopen ЧИТАТЬ уже хранимое вместо
s.Pricing.Ceiling(...)». Схему хранилища платформы при этом не трогаем — миграция не нужна и не
заказана. Понадобилась вопреки этому — стоп и пинг, а не «сделаю аккуратно».
⚠ Лечение обязано закрыть ОБА места, :1363 и :1397. Закрыт один — это половина, и в отчёте так
и объявляется: путь остаётся под «согласием, которого пользователь не давал».
⚠ Не спутай с третьей колонкой: run_attempts.ceiling_arg_micro_usd (00011_ceiling_argument.sql) —
это КНИЖНЫЙ аргумент --ceiling-usd для движка, а не бюджет попытки; миграция прямо предупреждает
«It is NOT ceiling_micro_usd».
Решаешь сам и аргументируешь: какую именно из двух колонок читать, как быть, если холда первой попытки нет (старые прогоны), и нужен ли отдельный аккуратный фолбэк.
2. PD-89 — печатать ключ идемпотентности НА ПУТИ ОШИБКИ
cmd/tmplatformctl/main.go, функция write() (:184; ⚠ якорь ряда :143-150 дрейфанул и указывает
теперь на вызывающего grant). id = newKey() чеканится на :189, applied, err := op(id, now) —
на :191, и if err != nil { return err } (:192-194) возвращает ошибку, не напечатав ключ.
Неоднозначный обрыв на коммите → оператор повторяет без --key → newKey() чеканит новый →
второе начисление. Комментарий :195-198 описывает ровно эту ловушку, но только для пути чтения
баланса («a failed BALANCE READ would have bought a double credit»).
Задача (делай РОВНО так): на пути ошибки ключ обязан быть виден оператору. Посадка мутации
обязательна. Форма печати (куда, каким текстом, out или stderr) — решаешь сам и
аргументируешь.
3. PD-426 + PD-214 — чужая строка не должна карантинить НАШУ проекцию
internal/ingest/tail.go, функция apply (:145). Четыре отказа стоят выше ветки, решающей
принадлежность: :150 декод payload · :153 checkVersion · :156 пустой EngineRunID · :162
Seq != 1. Ошибка любого из них терминальна для проекции: quarantines()
(internal/runs/reconcile.go:770-781=func quarantines(err error) bool) пропускает только context.Canceled/DeadlineExceeded и
pgstore.IsTransient, всё прочее едет в Store.Quarantine. Снятия карантина в дереве НЕТ
(grep -rniE 'unquarantine|clearquarantine|quarantine_reason *= *null|dequarantine' по .go/.sql
— пусто при живом положительном контроле internal/pgstore/runs.go:1470=func (s *Store) Quarantine),
операторской ручки нет, а гейдж tm_platform_quarantined_attempts (internal/metrics/metrics.go:80=Name: "quarantined_attempts")
это видит и молчит о том, что делать.
⚠ ПОСЫЛКА, КОТОРУЮ НАДО ЗНАТЬ ТОЧНО — иначе живая проба будет искать несуществующее.
Полностью ЗАКОННЫЙ чужой hello сегодняшней сборки (мажор потока тот же, engine_run_id непустой,
seq == 1) НЕ карантинит — он уходит в default и молча пропускается, и это защищено ЗЕЛЁНЫМ
пином:
cd platform && go test ./internal/ingest/ -count=1 -run TestAnotherAttemptsStreamInTheSameJournalIsSkipped -v
# --- PASS (тело пина — tail_test.go:185-187: hello(1,"eng-1") … hello(1,"eng-2"), ошибки нет)
Карантинит чужая ИЛИ БИТАЯ hello-строка, и условий ровно четыре — они же перечислены в PD-214
(«ручной tmctl оператора в каталоге книги, старый мажор, баг чужой сборки»):
другой МАЖОР потока (checkVersion сравнивает ТОЛЬКО мажор, internal/ingest/events.go:196-208=func checkVersion(got string) error;
у платформы StreamVersion = "1.1", у движка "1.2" — обе стороны на мажоре 1, поэтому сегодня
проходит) · пустой engine_run_id · seq != 1 · нераспарсиваемый payload.
⚠ Формулировка PD-426 («попасть можно по чужому ЗАКОННОМУ handshake'у») — переупрощение, ряд
описывает класс шире, чем воспроизводится; читай PD-214, он точнее.
Задача — СВОЙСТВО, а не перестановка (делай РОВНО так, отступление = пинг):
строка, которая не наша, не должна карантинить нашу проекцию.
Что это значит по букве, чтобы ты не внёс дефект буквальным исполнением:
- ⚠ Отказ по ДЕКОДУ (
:150) остаётся ВЫШЕ и не двигается.EngineRunIDживёт ВНУТРИ payloadHello(internal/ingest/events.go:82-92=EngineRunID string), вEnvelope(:71-79) его нет — значит без успешного декода принадлежность просто НЕИЗВЕСТНА. Переставляемы только три отказа, не четыре. - Понижаются только
checkVersion, пустойEngineRunIDиSeq != 1— и ТОЛЬКО в ветке, гдеwantуже известен (want != ""): там принадлежность решается сравнениемh.EngineRunID == want, и чужая строка обязана уходить в «не наше, пропустить» ДО валидации. - ⛔ При
want == ""валидация обязана остаться полной. Веткаcase want == "":(:166) УСЫНОВЛЯЕТ поток — зовётsink.Beginи ставитwant, mine = h.EngineRunID, true. Снять валидацию там значит принять поток ЧУЖОГО МАЖОРА как свой. Это ровно тот дефект, который пак чинит, только с другой стороны. - Зелёный пин
TestAnotherAttemptsStreamInTheSameJournalIsSkippedобязан остаться зелёным: он описывает уже правильную половину поведения. - Курсорная семантика (
heldпротивpos, движение курсора на hello) — не предмет правки; тронул — объясни зачем.
Вторая половина ряда — ручка снятия карантина. Что она есть — «делай РОВНО так»; форма
(подкоманда tmplatformctl, аргументы, что именно сбрасывается, кто имеет право) — решаешь сам и
аргументируешь.
Посадка мутации обязательна на обе половины.
4. МЕЛКОЕ, закрывающее урок пака: гейт батареи печатает ВСЕ условия хоста, а не одно
⚠ Дефектов тут ДВА, и они в РАЗНЫХ целях. Заказывается (а), не (б).
(а) — заказ. Цель check печатает над списком скипов жёстко зашитый литерал:
cd platform && sed -n '91,100p' Makefile
# if grep -q -- '--- SKIP' .check.log; then \
# echo "--- did NOT run (set TM_PLATFORM_TEST_DSN for the schema tests) ---"; \
Строка ни от чего не зависит: она печатается и когда DSN ВЫСТАВЛЕН, а скипы дал совсем другое
условие, — то есть отправляет читателя к ручке, которая уже включена. Демонстрация: с выставленным
DSN go test ./internal/books/ ./internal/runner/ -count=1 -v даёт 3 скипа, причина у них
TM_PLATFORM_TEST_ENGINE_BIN, а рецепт всё равно советует DSN. Это PD-374 («отправляя читателя к
ручке, которая тут ни при чём») и ПИНГ оркестратора №21 в зонном журнале с таблицей пусто 330 /
DSN 3 / +ENGINE_BIN 0.
(б) — НЕ заказ, не путай. Поведение «останавливается на первом недостающем» принадлежит цели
tools-check (Makefile:60-66): там каждая проверка делает exit 1, поэтому при живом
golangci-lint и отсутствующем sqlc печатается только про sqlc. Это отдельная история; тронешь —
объяви отдельно.
Задача (делай РОВНО так): цель check печатает ВСЕ условия хоста и что каждое включает.
Решаешь сам и аргументируешь: форма. Приор ПИНГа №21 — выводить перечень из тех же переменных,
которые читают хелперы тестов, чтобы список не разъехался с реальностью третий раз; довод против
«просто дописать вторую строку» — он чинит сегодняшний счёт, а не механизм. Условий сегодня четыре
(таблица в предусловии), и systemdOrSkip с PATH-до-sqlc в подсказке сегодня не названы вовсе.
5. ГЕЙТ ПРОТИВ КЛАССА, а не против ряда
Колонка серьёзности регистра разъехалась с сутью: открытых рядов 94, из них major — 2,
и следующая разведка снова доложит «major всего два», хотя тревожных рядов на порядок больше.
cd platform && awk -F'|' '/^\| PD-/{st=$(NF-2);gsub(/^ +| +$/,"",st);w=$4;gsub(/^ +| +$/,"",w);
if(st=="open"){t++; if(w~/major/)m++}}END{print "open="t,"major="m}' docs/DEFECT_REGISTER.md
# open=94 major=2
⚠ Предикат «слова тревоги» задаю дословно, потому что от его прочтения число прыгает вдвое.
Список маркеров (стеммы): деньг · холд · молча · блокир · невидим · 500 · паник.
cd platform && for M in any distinct; do printf "%s: " "$M"; awk -F'|' -v mode="$M" '
/^\| PD-/{st=$(NF-2);gsub(/^ +| +$/,"",st);w=$4;gsub(/^ +| +$/,"",w);
if(st=="open" && w !~ /major/){l=tolower($0); n=split("деньг холд молча блокир невидим 500 паник",m," "); c=0;
for(i=1;i<=n;i++){ if(mode=="distinct"){ if(l~m[i]) c++ } else { t2=l; c+=gsub(m[i],"",t2) } }
if(c>=2) k++}}END{print k+0}' docs/DEFECT_REGISTER.md; done
# any: 21 (≥2 ВХОЖДЕНИЯ любого маркера)
# distinct: 13 (≥2 РАЗНЫХ маркера)
То есть 21 — это счёт по «≥2 вхождения», а не по «два разных слова»; по «двум разным» их 13 (а по буквальным словоформам — 11 и 18 соответственно). Обе величины настоящие, но гейт обязан знать, какую он считает.
Задача (делай РОВНО так): гейт зоны печатает открытые не-major ряды, несущие маркеры тревоги.
Решаешь сам и аргументируешь: место, предикат и порог — и объявляешь выбранный предикат в отчёте
командой, дающей его число. Приор по месту: platform/internal/gates/ — там уже есть прецедент
чтения канона выше модуля (contract_test.go, константа zoneRoot + "/../docs/...").
⛔ docs/scripts/counts.py НЕ ТРОГАТЬ — это единственное, что сегодня читает
platform/docs/DEFECT_REGISTER.md (grep -rn 'DEFECT_REGISTER' --include=*.go --include=Makefile --include=*.py --include=*.sh platform/ docs/scripts/ → один хит, counts.py:51), и его шапка прямо
запрещает правку чужим сессиям: «скрипт — зона ОРКЕСТРАТОРА». Красный --check/--lint не обходить
и не «чинить» подгонкой — это тот же запрет, что подгонка тестов; непонятно или кажется неправым →
пинг.
6. МЕЛКОЕ, найденное при сборке промта: рантбук ТВОЕЙ зоны советует деструктивный порядок деплоя
platform/deploy/README.md:213=сначала платформа, потом движок — «Правило то же, что у схемы
хранилища: сначала платформа, потом движок». По коду безопасного порядка у формы манифеста НЕТ:
гейт интейка — строгое равенство ОДНОЙ константе, окна двух версий нет (обе ссылки — в разделе
ПОРЯДОК ДЕПЛОЯ ниже). Платформа, выкаченная первой со знанием новой формы, отправит в
parser_unavailable КАЖДУЮ книгу ещё не обновлённого движка — ровно тот симптом, который абзац
рантбука строкой выше описывает как беду ОБРАТНОГО порядка.
Делай РОВНО так: ряд в docs/DEFECT_REGISTER.md (класс doc) + правка строки рантбука.
Решаешь сам и аргументируешь: формулировка — назвать бамп формы стоп-миром или описать временное
окно двух версий как условие, при котором безопасный порядок вообще появляется.
⚠ Увидишь в коде окно версий, которого я не нашёл, — это находка, а не твоя ошибка: скажи и не чини.
Границы — что НАМЕРЕННО не берём
PD-412/PD-413(LATERAL в полосном агрегате). Находки настоящие и замеренные (1.359 мс → 0.307 мс на книге 2283 глав — числа принадлежатPD-412), но это переписывание запроса в горячем read-модельном пути, а арифметика полосы в этом паке не трогается. Контенция, а не корректность денег.PD-162(клин на удалённом каталоге). Настоящий и денежный, но его АВТОМАТИЧЕСКАЯ терминальность — это эскроу (platform/BACKLOG.mdП-18/П-20), а строить половину эскроу рядом с проектируемым целым зона уже отказывалась: пере-диспозиция P6 поPD-154(грепполовину эскроувplatform/docs/— единственный хит,DEFECT_REGISTER.md:101). ⚠ Ряд называет и ВТОРОЕ, дешёвое лечение — «либо проверкой каталога при допуске». Этим паком оно тоже НЕ берётся: пак закрывает денежный шов возврата, а валидация каталога на допуске — это правка входной двериStart, отдельный предмет с собственной ценой на ложных отказах. Операторская ручка на этот класс уже построена (run abandon [--release-hold], P8-FIX; строка П-20 фиксирует, что «пока эскроу нет, ручка остаётся ручной»). ⚠ Считаешь границу неверной — скажи аргументом, право такое у тебя есть (см. «Канал вопросов»).- Дверь выдачи — отдельный пак:
createExport/getExportв каноне 0.9.0 есть, платформой не смонтированы (grep -rn 'createExport\|getExport' platform/internal/ --include=*.go— пусто), но дверь требует минора канона и сводит на себя все точки столкновения.
⚠ ПОРЯДОК ДЕПЛОЯ — почему пак безопасен параллельно бэкенду
Зоны независимы по коду (разные модули, перекрёстных импортов нет в обе стороны, go.work в корне
отсутствует), но НЕ по деплою, и сцеплений ДВА.
- Форма манифеста БЕЗОПАСНОГО ПОРЯДКА НЕ ИМЕЕТ. Гейт интейка — строгое равенство ОДНОЙ константе
(
internal/ingest/manifest.go:112=if m.Version != KnownManifestVersion; сама константа —:88=KnownManifestVersion = "tm-manifest-v2"). Окна из двух версий нет, поэтому «платформа первой» ровно так же смертельно, как «движок первым»: односторонняя выкатка отправляет КАЖДУЮ книгу вparser_unavailable, который жжёт бюджет попыток. Бамп формы = стоп-мир либо специально построенное временное окно двух версий. - Схема хранилища ДВИЖКА ⇒ «движок первым →
tmctl migrateпо каждой книге → и только потом платформа снимает свой обход» (D39.158 п.6). Голова схемы сегодня 16 (backend/internal/store/migrate.go:485=func SchemaHead() int,len(migrations)) — это персистентная память ДВИЖКА, а не Postgres платформы.
Поэтому пак НЕ меняет: форму манифеста · схему хранилища ДВИЖКА · версию контракта. Понадобилось — стоп и пинг, не «сделаю аккуратно». Платформенная миграция этим абзацем НЕ запрещена: по пункту 1 она не нужна (сумма уже персистится) и потому не заказана; понадобилась — тоже пинг, но по другому основанию.
Свобода и её разметка
«Делай РОВНО так» (отступление = пинг):
- предусловие хоста (четыре условия) · строка «DSN = да» у каждой посадки;
- ФАКТ каждой из шести правок — что именно закрывается: (1)
reopenчитает хранимую сумму в ОБОИХ местах,:1363и:1397, схему платформы не трогая; (2) ключ печатается на пути ошибки; (3) свойство «чужая строка не карантинит нашу проекцию» с тремя оговорками пункта 3 (декод остаётся выше · понижение только при известномwant· приwant == ""валидация полная); (4) цельcheckпечатает ВСЕ условия; (5) гейт против класса живёт в зоне платформы; (6) ряд регистра и правка строки рантбука; - обязательные посадки у пунктов 2 и 3;
- границы выше · три запрета из порядка деплоя · запрет трогать
docs/scripts/counts.py.
«Решаешь сам и аргументируешь» — ФОРМА и только она: какую колонку холда читать и как быть без
холда · форма печати ключа · форма ручки снятия карантина · форма печати условий в Makefile ·
место, предикат и порог гейта пункта 5 · формулировка правки рантбука в пункте 6 · остальной состав
посадок · порядок работ внутри пака.
⚠ Катч-олла «всё остальное — сам» больше нет: если чего-то нет ни в одном списке — это пинг, а не твоё усмотрение.
Мандат самопроверки — исполнением, не перечитыванием
Батарея зелёная — это НЕ отчёт. Обязательны все три:
- Живая проба каждого пункта состава. Поимённо, с пометкой про DSN:
- п.1
reopen— DSN нужен (денежный путьinternal/runs, 110 тестов тёмных без него); - п.2
write()— юнит-посадки идут без DSN, но сквознойTestCommandsAgainstALiveDatabaseвcmd/tmplatformctl/main_test.goDSN-гейчен (без DSN в./cmd/...скипается 6 тестов); - п.3
ingest/tail.go— DSN не нужен, пакет гоняется целиком (0 скипов); - п.4
Makefile— DSN не нужен, но проба обязана гоняться при РАЗНЫХ окружениях, иначе она не видит того самого дефекта; - п.5 гейт — DSN не нужен;
- п.6 рантбук — кода не касается, «проба» это ряд регистра и
counts.py --checkзелёным.
- п.1
- Собственные адверсариальные посадки ВНЕ списка выше.
- Отдельный проход по СВОЕЙ ГОТОВОЙ работе свежим контекстом. ⚠ Класс, купленный прошлой сменой: веер по исходным уликам находит втрое меньше, чем веер, читающий готовый результат.
Субагенты разрешены явно. Модель задавай ИМЕНЕМ и знай, сколько их у тебя работает; обычно хватает одного-двух, но веер под предмет выбираешь ты.
Предметные оси ревью — под характер ЭТОЙ работы
(1) ШОВ — инвентарь каналов другой стороны чтением ЧУЖОГО кода, не по памяти (D39.132). Пункт 3
живёт целиком на шве с движком, и спроектировать порядок проверок по своей половине шва нельзя.
Открой и прочитай: backend/internal/runevents/ (что движок реально пишет в общий events.jsonl,
словарь типов, StreamVersion, комментарий Envelope — «a resumed run is a NEW process that appends
a second hello to the same file and numbers from 1 again») и backend/internal/pipeline/events.go
(греп hello at seq 16 — отказ Seq != 1 наблюдался НА РЕАЛЬНОМ БИНАРЕ, 33 строки, 15 байт-в-байт
дублей). Вопросы, на которые обязан быть ответ ЧТЕНИЕМ: с какого seq нумерует второй процесс ·
какие мажоры потока сегодня возможны в одном журнале · что происходит при дозаписи. ⛔ Читаешь —
не правишь: backend/ чужая зона.
(2) ДЕНЬГИ — пере-вывод сумм из холда первой попытки. Не «код компилируется», а «на живой БД при
изменённой TM_PLATFORM_USD_PER_CHAPTER резервируется та сумма, на которую человек согласился» —
и по пути Resume, и по пути свипа, и в AcceptRebill.
⚠ ПРОВЕРЯЕМЫЙ АРТЕФАКТ находок — обязателен
Тест на вырожденность, применяй к каждой строке своего отчёта: если её букву удовлетворяет НИЧТО — строка дефектна. «Батарея зелёная», «перечитал сам», «субагент ответил: находок нет» — это не отчёт, это его отсутствие. В журнал идут ТРИ таблицы:
- Посадки: строка на посадку — что мутировано (
file:line+ сама мутация) · какой тест покраснел (ИМЕНЕМ) ·DSN = да/нет. ⚠ Если по посадке НЕ покраснел ни один тест — так и пиши: это находка (дыра в покрытии), а не провал отчёта, и она сама становится строкой регистра. - Живые пробы: путь · команда · наблюдённый выход цитатой, не пересказом · вердикт.
- Веер: на каждого агента — модель ИМЕНЕМ · что он читал · находки с
file:line. «Находок нет» принимается ТОЛЬКО со списком того, что проверялось; голое «находок нет» означает, что веер не отработал — задание переформулируй и гоняй заново.
⚠ Запрет подгонки тестов и гейтов — CLAUDE.md (D39.183). Здесь важен один его край: заказанность
решает ЗАКАЗ, а не ты, и этот промт заказывает смену поведения в пунктах 1–4 — протухший под неё
тест правится как обслуживание, но правка ОБЪЯВЛЯЕТСЯ в отчёте (что изменилось, какой тест это
описывал, куда уехала гарантия).
Отчёт
Записка-план ДО работы (эхо-протокол: скоуп · инварианты · что НЕ делаю, ≤10 строк) — в
platform/docs/platform-PROGRESS.md, и тем же текстом первым действием по каналу (см. ниже).
Итог — туда же. ⛔ В docs/PROGRESS.md платформа НЕ пишет (канон, таблица ролей).
Каждое число и каждая категорика — с КОМАНДОЙ ПОЛУЧЕНИЯ, которая это число реально печатает. Приёмка пере-ранит. ⚠ Команда, печатающая «ok» вместо числа, командой получения не является.
Обязательная секция «Что НЕ удалось и что НЕ проверено»: исходов ТРИ, третий законен, и молчание об упёршемся пункте дороже самого упора.
Канал вопросов и право отказаться
Конфликт промта с кодом — пинг через владельца, не интерпретация. Если число выше не сошлось, если факт о коде не воспроизводится, если два места этого промта говорят разное — это находка, неси её, а не подгоняй работу под текст.
Право сказать «этого делать не надо» с аргументом у тебя есть — включая пункты состава и границы выше. Сессия, приносящая развилку вместо тихой девиации, делает правильно.
Прямой канал
Механизм целиком — CLAUDE.md, «Связь между сессиями»: впиши свой блок в /tmp/textmachine-channel,
сверься с ListAgents перед отправкой, канала нет — это нормально и опрашивать сессии подряд не надо.
Что добавляет этот пак: эхо-записку отправь ПЕРВЫМ действием по адресу оркестратора — это и есть
проверка канала; и знай, что в файле прямо сейчас лежат блоки закрытых смен, один с пометкой
«⚠ СМЕНА СДАНА 31.08 … по адресу не писать».