443 lines
66 KiB
Markdown
443 lines
66 KiB
Markdown
# Архив журнала зоны «Платформа» — эра пака P7 (16–20.08.2026)
|
||
|
||
> ⚠ **СРЕЗ, выселен оркестратором №18 при лендинге P7 (20.08, D39.153)** — по образцу срезов `platform-PROGRESS-P0-P3.md` и `-P4-P6.md`. Эра ЗАКРЫТА: пак исполнен пятью актами, принят с фикс-листом и заленден (`9b23e8c`), сессия закрыта владельцем.
|
||
>
|
||
> **Не читать при онбординге.** Живое состояние зоны — шапка `platform-PROGRESS.md`; статус каждого дефекта — `DEFECT_REGISTER.md` (источник истины); правила, пережившие пак, — `STACK_DECISIONS.md` §33–36; фикс-лист приёмки и то, что ушло в единый бэклог, — пинг оркестратора №18 там же в живом журнале.
|
||
|
||
## Сессия P7 (16–17.08): читающая поверхность контракта 0.3.0
|
||
|
||
Промт — `PLATFORM_P7_SESSION_PROMPT.md`. Ниже: записка-план по §4 (каждый пункт с диспозицией),
|
||
команды, живые пробы, находки, obstacle.
|
||
|
||
### Записка-план: пункт → исполнено / отказ → улика
|
||
|
||
| § | Пункт | Статус | Улика |
|
||
|---|---|---|---|
|
||
| 0 | Рантбук деплоя живым `migrate` | **исполнен** | БД проекта отведена на v14 при бинаре v15 → `tmctl status --json` = exit 13, токен `schema_mismatch found=14 expected=15`; `tmctl migrate` → бэкап + v14→v15; тот же `status` = exit 0. Мёртвая цитата вычищена (`deploy/README.md`, П-1 бэклога), пример в `tmplatformctl/runs.go` переписан на ВЕРСИОНИРОВАННЫЙ путь |
|
||
| 0 | `tmplatformctl books --migratable` → `tmctl migrate` end-to-end | **исполнен** | 5 книг стенда, все `MIGRATE=yes`, цикл из деплой-ноты отработал |
|
||
| 1а | Читать `BookIntake.title` | **исполнен** | `books.Intake.Title`; пустая строка = «назови по файлу» (`books.title()`), непустая не перезаписывается разбором |
|
||
| 1б | Проецировать `reject_reason` | **исполнен** | `httpapi.contractRejectReason`; `parser_unavailable` → `processing_failed` (ФБ-9: имя значения — то, на что клиент вешает фразу) |
|
||
| 2 | PD-104: грант → 0 + тест | **исполнен** | `config.go` дефолт 0; пин `config.TestSignupGrantIsParsedNotGuessed` пинит ИМЕННО ноль; протухшие «$5» вычищены из `PLATFORM_DIRECTION.md` §2, `BACKLOG.md` П-7, регистра |
|
||
| 3 | Модель ошибок по карте А-2 | **исполнен** | `httpapi/problem.go`: 16 корневых кодов, статус ВЫВОДИТСЯ из кода (пара «код+статус» непредставима расходящейся), `cause` открытый, `errors[]`, `request_id` из `reqid`; `WWW-Authenticate` на 401; две причины 403 разведены в `cause` при одном корневом `forbidden`; класс 2 — один код без вариации |
|
||
| 4 | `listChapters` · `listUnits` (пер-главно, 410) · `listNotes` · `listBankTerms` · `submitBankDecisions` · дельты · SSE · `structure_version` · gzip · ETag/304 | **исполнен** | `httpapi/{reading,stream,conditional}.go`, `pgstore/{readmodel,events}.go`; ручки «вся книга юнитами» НЕТ; `Unit.notes` массивом; агрегаты банка на ПЕРВОЙ странице; дельты ВКЛЮЧИТЕЛЬНЫЕ; `version_too_old` и `cursor_invalid` — причинами |
|
||
| 4 | Ловушка `heading` | **исполнен** | поле не декодируется ВОВСЕ (`ingest.ManifestChapter`), колонка `chapters.heading` удалена миграцией, проекция отдаёт `null`; пин `readmodel.TestTheManifestsRenderedHeadingHasNowhereToLand` |
|
||
| 4 | Демонтаж построенного гейта полноты банка | **исполнен** | `runs/reconcile.go`: `awaiting_bank` продолжается при ЛЮБОМ состоянии решений; пин `TestResumeLiftsABankStopWithTheDecisionsAsTheyStand`. Граница паузы движка сверена чтением (`pipeline/mining.go`: авто-продолжение с неподписанным банком — дефолт) |
|
||
| 4 | Пофазность у главы НЕ строить | **соблюдён** | у главы один счётчик `units_done`; пин «фазовый счётчик не доехал до строки главы» |
|
||
| 4 | `Note.code` из ◆-карты | **исполнен с ОДНИМ отступлением** | `httpapi/notes.go`; отступление — незнакомая причина проецируется как `unspecified` (в карте колонка кода пуста, а поле обязательно). Заведена строка PD-246, ждёт ратификации вместе с фразами |
|
||
| 5 | `Progress` с книги на `Run`, одна полоса в ГЛАВАХ | **исполнен** | `pgstore.Progress{Done,Total,ETASeconds}`, знаменатель — `ceiling_chapters`; сегмент выбирается `verify_bank && !bank_released` |
|
||
| 5 | `Book`: +`revision`, +`chapters_done`, −`progress`, −`genre` | **исполнен** | `genre` снят и с ПРОВОДА, и из формы интейка, и из колонки: платформа его больше не знает, значение шаблона оператора остаётся его |
|
||
| 5 | `Run`: +`book_id`, +`failure_reason`, `verify_bank`→`stop_for_signing` | **исполнен** | словарь из трёх значений мапится с полосы 10–19 и веток `outcome()` (`runs.failureReason`) |
|
||
| 5 | `Usage`: `halt_reason` со своим словарём | **исполнен** | `httpapi.contractHaltReason`; прогонная причина больше не может доехать до аккаунтного поля |
|
||
| 5 | `GET /capabilities` | **исполнен** | все шесть полей; пары — из конфигурации (`TM_PLATFORM_LANGUAGE_PAIRS`), не список в Go |
|
||
| 5 | `limit` подрезать, а не отвергать | **исполнен** | `pgstore.clampPage`; отвергается только значение, которое не является размером страницы |
|
||
| 5 | Трейлинг-части интейка → 400 | **исполнен, с находкой** | сначала книга ОСТАВАЛАСЬ при 400 (живая проба); теперь часть после файла ПРОВАЛИВАЕТ чтение, и интейк откатывает загрузку своим же путём |
|
||
| 5 | `Location` на 201 | **исполнен** | `/v0/books/<id>` |
|
||
| 5 | `Idempotency-Key` на `createBook` и `startRun` | **исполнен** | таблица 00017, повтор отдаёт ИСХОДНЫЙ ответ, другой запрос — 409 `key_reused`, гонка — `key_in_flight` + `Retry-After`, >255 → 400 |
|
||
| 5 | `blocked {code, book_id}` на run-options и 409 | **исполнен** | `pgstore.CreditHeldBy` + `runs.CreditHeldError` |
|
||
| 5 | Отказ по неподдерживаемой паре на интейке | **исполнен** | `books.ErrUnsupportedPair` → `errors[].code: unsupported_pair`; пустой список пар = деплой не объявляет ничего и пару не проверяет |
|
||
| 5 | `finalizing` вон из словарей | **исполнен** | Go-свитчи и CHECK-констрейнты обеих таблиц |
|
||
| 6 | PD-172/173/174/180/199 привести · PD-201 · PD-241 | **исполнен** | все закрыты либо сужены с уликой; PD-241 — перевёрнутый порядок в `outcome()` с пином |
|
||
| 6 | Кандидаты PD-219/217/162 | **отсуждены** | PD-217 — половина ЗАКРЫТА (paused больше не блокирует апгрейд движка); PD-219 и PD-162 — не брались, с названной причиной |
|
||
| 6 | Находки §9 research/28 | **отсуждены** | три взяты строками (PD-249/250/251/252), две сведены к существующим (PD-203, PD-162/244) |
|
||
| 6 | Инструменты: sqlc / oapi-codegen | **отказ с доводом** | оба НЕ взяты; довод — `PLATFORM_DIRECTION.md` §3, и он опирается на замер этого пака, а не на вкус |
|
||
|
||
### Команды (каждое число отчёта — этой командой)
|
||
|
||
```sh
|
||
# батарея, оба гейта, -race
|
||
export TM_PLATFORM_TEST_DSN='postgres://postgres@/postgres?host=/tmp&port=55433&sslmode=disable'
|
||
export TM_PLATFORM_TEST_ENGINE_BIN=<путь к tmctl> TM_PLATFORM_TEST_BOOK_TEMPLATE=<шаблон>
|
||
make check # EXIT=0, 18 пакетов, скипов 0, линтер 0 issues
|
||
grep -rh '^func Test' --include='*_test.go' . | wc -l # 458 (HEAD: 416)
|
||
git diff --stat platform | tail -1 # 46 файлов, +2329 −646
|
||
python3 docs/scripts/counts.py # регистр: 256 строк, 63 открытых
|
||
```
|
||
|
||
⚠ Стенд Postgres на этой машине пришлось поднять с нуля (его не было): рецепт `STACK_DECISIONS.md`
|
||
§«Postgres без root», micromamba + `postgresql=18.4` в `~/.local/pgsql`, порт 55433 — отработал
|
||
дословно.
|
||
|
||
### Живые пробы на дев-стенде (демон + сид + настоящий `tmctl`)
|
||
|
||
Сид P6 отработал целиком: дев-вход → грант → загрузка через ЖИВОЙ `POST /v0/books` → разбор →
|
||
`not_started, 3 главы`. Дальше — курлом по новым ручкам:
|
||
|
||
- `GET /capabilities` → все шесть полей, `contract_version: 0.3.0`, пары `zh>ru available` +
|
||
`ja>ru unavailable`;
|
||
- `GET /books` → `revision · reject_reason: null · structure_version: 1 · chapters_done: 0 ·
|
||
character_count: 987`, **никакого `progress` и никакого `genre`**;
|
||
- `GET /books/{id}/chapters` → три главы, `heading: null` у каждой;
|
||
- `GET /books/{id}/chapters/{ch}/units` → пара с ИСХОДНЫМ ТЕКСТОМ (канал `tmctl export --pairs`
|
||
работает), `target: ""`, `state: pending`, `notes: []`;
|
||
- `GET /books/{id}/notes`, `/bank` → пустые с агрегатами и `structure_version`;
|
||
- SSE на книге в покое → `hello id=4` → `end id=4` → закрытие; реконнект с `Last-Event-ID: 6` → **204**;
|
||
- `ETag` → `304` на `If-None-Match`; `Accept-Encoding: gzip` → `Content-Encoding: gzip` + `Vary`;
|
||
тот же заголовок на `/events` → **не сжато**;
|
||
- ошибки: 404 → `code: not_found` + `request_id`; 401 → `WWW-Authenticate: Bearer realm="textmachine"`;
|
||
POST без `X-TM-Client` → 403 `forbidden` · `cause.code: client_header_missing`;
|
||
- интейк: пара `ja→ru` → 400 `unsupported_pair` на обоих полях; часть после файла → 400
|
||
`missing_or_late` **и книга не остаётся** (проверено счётом библиотеки до/после);
|
||
- `Idempotency-Key`: тот же ключ дважды → один и тот же `Location`; тот же ключ с другим `title` →
|
||
409 `idempotency_conflict` · `cause.code: key_reused`.
|
||
|
||
### Что нашли ПРОБЫ, чего не нашли тесты
|
||
|
||
**Часть формы после файла оставляла книгу.** Отказ 400 приезжал (правило соблюдалось), но
|
||
`intake.Accept` к тому моменту уже создал строку и каталог — пользователь получал ошибку И книгу в
|
||
библиотеке. Починено не новым кодом отката, а ПРОВАЛОМ чтения: часть после файла возвращает ошибку
|
||
из ридера, и интейк отменяет загрузку тем же путём, которым отменяет оборванную. Пин
|
||
`httpapi.TestAPartAfterTheFileIsRefusedAndTheBookIsNotKept`, пере-проверено живьём.
|
||
|
||
### Адверсариальное селф-ревью финалом: три ревьюера, таблица находок
|
||
|
||
Механизм по §5 промта: три независимых субагента по ФИНАЛЬНОМУ диффу, author≠reviewer, **два из
|
||
трёх — другой модели** (кросс-семейная линза, а не вторая своя). Ноль находок не случился — и это
|
||
хорошо: две HIGH нашли ОБА контрактных ревьюера независимо, что и есть подтверждение.
|
||
|
||
| # | Линза | Находка | Вердикт | Что сделано |
|
||
|---|---|---|---|---|
|
||
| Р-1 | контракт (кросс-модель) · деньги/шов | **Кадр `note` уносил движковую причину** (`glossary_miss`, `hard_refusal`) и не нёс обязательных `severity`/`code`; `unit_id: null` вместо отсутствия | ПОДТВЕРЖДЕНА, HIGH | Карта переехала в `internal/ingest/notes.go` — один дом на оба потребителя; кадр строится через неё; `unit_id` опускается. Пин `TestTheNoteFrameCarriesTheContractsNoteAndNotTheEnginesReason` |
|
||
| Р-2 | контракт (кросс-модель) | **Кадр `status` уносил внутренние словари** (`daily_ceiling`, `parser_unavailable`): та же величина читалась `null` на карточке и внутренним словом в потоке | ПОДТВЕРЖДЕНА, HIGH | Переводы переехали в `internal/ingest/vocabulary.go`, кадр строит `emitStatus`; при ошибке чтения кадр НЕ шлётся (вместо `status: null` вне схемы). Пин `TestTheStatusFrameCarriesTheContractsVocabularyOrNothing` |
|
||
| Р-3 | деньги/шов | **DOWN-путь миграции неисполним при первой же строке банка** (воспроизведено живым PG): три словаря переписывались без перевода данных, а goose гоняет миграцию одной транзакцией | ПОДТВЕРЖДЕНА, HIGH | Порядок drop → перевод → add в ОБЕ стороны (UP тоже: он должен переживать пере-накат после отката). Пин `TestARollbackSurvivesTheDataTheNewVocabulariesWrote` — откат до документированного пола (версия 5) на базе С данными |
|
||
| Р-4 | деньги/шов | **Четыре писателя меняли статус без кадра** (`RestartRun`, `PauseRun`, `FinishUnspawnedStop`, `ReleaseBankStop`); двое из них ставят `finished_at`, то есть книга «в покое» — и следующий реконнект получает **204 «не переподключайся»** при устаревшем статусе у клиента | ПОДТВЕРЖДЕНА, HIGH | Кадр у всех трёх писателей статуса; четвёртый (`ReleaseBankStop`) перестал быть отдельным писателем — см. Р-5 |
|
||
| Р-5 | деньги/шов | **`ReleaseBankStop` коммитился ДО `reopen`**: резюм, который ничего не сделал (расчёт в полёте, бюджет исчерпан), всё равно переключал полосу с N/N на 0/N | ПОДТВЕРЖДЕНА, MED | Снятие стопа перенесено ПОСЛЕ успешного `reopen` |
|
||
| Р-6 | деньги/шов | **`Refresh` тратил бюджет прохода ПЕРЕД `settle`**: на большой книге два полных ре-чанка съедали проход, расчёт уходил в «отложено», холд висел свип | ПОДТВЕРЖДЕНА, MED | Деньги первыми: `settle` → затем `refreshReadModel` на СВОЁМ ограниченном контексте, ошибка громкая |
|
||
| Р-7 | деньги/шов | **`failureReason` игнорировал маркер**, который ему передавали: OOM и kill по стоп-таймауту приезжали `interrupted` («повтори») | ПОДТВЕРЖДЕНА, MED | Читает `m.Result`; пин `TestWhyARunFailedDecidesWhetherARetryIsWorthOffering` (7 веток) |
|
||
| Р-8 | контракт (кросс-модель) | **Квитанции `Run` несли нулевую полосу** (`202` на старт/стоп/резюм) со свежей ревизией — клиентский гард пропускал её и полоса откатывалась к 0/0 | ПОДТВЕРЖДЕНА, MED | `StartRun`/`RequestStop`/`ReadRun` считают ту же полосу, что карточка |
|
||
| Р-9 | контракт (кросс-модель) | **Полоса ВТОРОГО прогона считала главы всей книги**: дробь стартовала выше нуля и могла превысить единицу | ПОДТВЕРЖДЕНА, MED | Колонка `runs.chapters_before` — база сегмента, снимается в том же стейтменте, что создаёт прогон; `least(…, ceiling_chapters)` закрывает второй край. Пин `TestASecondRunsBarStartsAtZeroOverAHalfFinishedBook` |
|
||
| Р-10 | контракт (кросс-модель) | **`Last-Event-ID: 0` после подрезки буфера молча пропускал дыру** — а `0` это легальный id, который сервер сам выдаёт | ПОДТВЕРЖДЕНА, MED | Условие `last+1 < Oldest` вместо `last > 0 && last < Oldest` |
|
||
| Р-11 | контракт (кросс-модель) · скоуп | **Склейка кадров `chapter` шла по имени события**, теряя счётчик соседней главы внутри одного соединения | ПОДТВЕРЖДЕНА, MED | Склейка по (событие, id сущности) |
|
||
| Р-12 | контракт (кросс-модель) | **Порядок банка** был `(src, id)` — то есть по ХЕШУ, а канон объявляет «по поверхности, затем по окну» | ПОДТВЕРЖДЕНА, MED | Порядок и кейсет приведены к канону (`src, since, until, id`) |
|
||
| Р-13 | контракт (кросс-модель) | **`limit` всё ещё отвергался снизу** (0, отрицательный, нечисло), тогда как канон освобождает параметр от отказа | ПОДТВЕРЖДЕНА, MED | Никогда не отвергается: сверху подрезка, всё прочее — дефолт деплоя. Пин переписан |
|
||
| Р-14 | контракт (кросс-модель) | **Неверная пара языков и слишком длинное поле отказывали без `errors[]`** | ПОДТВЕРЖДЕНА, MED | `ErrMalformedLanguage` и `too_long` с указателем на поле |
|
||
| Р-15 | контракт (кросс-модель) | **`SweepIdempotency` не имел вызывающего**: ключи не забывались никогда | ПОДТВЕРЖДЕНА, LOW | Подключён в свип демона, окно 25 часов |
|
||
| Р-16 | контракт (кросс-модель) | **Курсор замечаний нёс движковое слово волны** в открытом виде | ПОДТВЕРЖДЕНА, LOW | Пакуется порядковым номером |
|
||
| Р-17 | скоуп (кросс-модель) | `acceptsGzip` игнорировал `*`; `pump` спал такт даже после полной пачки; `unknownTermPointer` парсил текст ошибки; алиас `itoa` | ПОДТВЕРЖДЕНЫ, LOW | Все четыре починены (типизированная `UnknownTermError` вместо парсинга строки) |
|
||
| Р-18 | скоуп (кросс-модель) | **`sqlc` был привязан к этому паку ратификацией**, а пак от него отказался — это отступление, а не решение зоны | СПРАВЕДЛИВО | Отказ с доводом записан в `PLATFORM_DIRECTION.md` §3 и вынесен ВОПРОСОМ оркестратору (ниже) |
|
||
| Р-19 | скоуп (кросс-модель) | **`unspecified` — изобретённый код** там, где промт требовал пинг | ЧАСТИЧНО: разбор с владельцем 17.08 показал, что находка верна по форме и неверна по существу | Значение отдано ветке, которую канон УЖЕ ратифицировал («нейтральная фраза для незнакомого кода»), а не заводит новое правило; настоящий предмет — рукописная копия чужого словаря без гейта, PD-246 пере-сформулирован, движку — пинг про публикацию причин данными |
|
||
| Р-20 | контракт (кросс-модель) | `410` отвечает и на главу, которой никогда не было: различение 410/404 без надгробий неисполнимо | ПРИНЯТО КАК ЕСТЬ | Лечение у обоих одно (перечитать дерево); строка PD-253 |
|
||
| Р-21 | скоуп (кросс-модель) | **Масса комментариев** выросла против нормы зоны (миграция на 250 строк — половина проза) | ЧАСТИЧНО ПРИНЯТО | Подрезано самое тяжёлое; остальное — предмет пинга, а не тихой правки |
|
||
| Р-22 | скоуп (кросс-модель) | **Два писателя ошибок** (`WriteProblem` + `WriteStatusProblem`/`codeForStatus`), три одинаковых структуры пары | НЕ БРАЛОСЬ | Второй писатель обслуживает НЕконтрактную поверхность (`/auth`, `/readyz`), где кода версии нет; сведение в один требует ратификации формы для 405/429 — вопрос оркестратору |
|
||
|
||
**Что ревьюеры подтвердили как ВЕРНОЕ** (важно не меньше находок): ни одной денежной величины на
|
||
проводе ни в каком виде · порядок блокировок не тронут, `emitFrame` не берёт НОВЫХ локов ни в одной
|
||
из 14 точек · кадр не может быть выпущен для откаченного состояния · демонтаж гейта банка
|
||
соответствует таблице канона дословно · словари шва (шесть значений банка, полоса отказов 10–19,
|
||
все семь типов событий) сверены по коду движка и полны · `finalizing` снят безопасно · оба гейта
|
||
миграций пере-считаны и совпадают.
|
||
|
||
### Живые пробы ПОСЛЕ фикс-раунда (стенд пере-создан)
|
||
|
||
Стенд пришлось пере-создать, и это отдельная улика: миграция 00016 правилась ПОСЛЕ того, как была
|
||
применена, а goose ключуется номером — отредактированный файл не перезапускается никогда. На стенде
|
||
лечится сносом базы; в проде именно от этого стоит гейт `migrations.sha256` (обе строки пере-считаны).
|
||
|
||
- `limit=0 | -3 | abc | 100000` → **200 во всех четырёх** (канон освобождает параметр от отказа);
|
||
- квитанция старта: `status: translating`, `progress {done:0, total:2}`, `book_id`, `failure_reason: null`
|
||
— полоса едет с квитанцией, а не только с карточкой;
|
||
- поток при ЖИВОМ прогоне: `hello id=5` → `status id=7` с `failure_reason: "service_error"` и
|
||
`paused_reason: null` — кадр несёт КОНТРАКТНЫЙ словарь (внутреннего слова в кадре нет);
|
||
- карточка после отказа: книга `failed`, прогон `failed` + `service_error` (на стенде нет ключей
|
||
провайдера — движок отказывает конфигурацией, и это ровно тот класс, который «повтор не лечит»);
|
||
- `resume` упавшего прогона → `run_not_resumable` без `cause` (канон: это не остановленный прогон);
|
||
- неверный код языка → `invalid_request` + `errors[]` на оба поля;
|
||
- `/usage` → `halt_reason: null` (свой словарь, не прогонный).
|
||
|
||
### Obstacle: что НЕ удалось и что не проверено
|
||
|
||
1. **Отложено в P8 явно** (заказ промта): `updateBook` · `deleteBook` · `getRun` · `createExport`
|
||
/`getExport` · эскроу (П-18).
|
||
2. **`Note.code` для незнакомой причины — отступление**, не решение: `unspecified` (PD-246).
|
||
3. **Ни одного живого ЗАМЕЧАНИЯ и ни одного термина банка через настоящий прогон не прошло** —
|
||
прогон стоит денег, а сессия $0. Проекции замечаний и банка проверены тестами на живом PG и
|
||
ручными строками `unit_resolutions`, но не сквозным прогоном движка.
|
||
4. **SSE с ЖИВЫМ прогоном не гонялся** по той же причине: проверены книга в покое, реконнект, 204,
|
||
склейка и `resync_required` — тестами и на стенде, но не под настоящим потоком кадров.
|
||
5. **Стоимость материализации не замерена на большой книге** (PD-248): два полных ре-чанка на
|
||
границу работы; на демо-книге в 3 главы это миллисекунды, на 2283 главах — секунды CPU.
|
||
6. **`structure_version` на РЕАЛЬНОЙ пере-нарезке** проверен тестом (смена ключа манифеста), но не
|
||
настоящей сменой чанкера движка.
|
||
7. **Опрос потока — 2 запроса/с на соединение** (PD-247): `LISTEN/NOTIFY` не строился.
|
||
8. **Кадр `note` живьём не наблюдался**: он рождается только на помеченной единице настоящего
|
||
прогона. Проверен тестом на живом PG через настоящий `RunSink.Apply` (полный путь материализатора),
|
||
но не в потоке под браузером.
|
||
9. **Полоса под настоящей работой не наблюдалась**: `progress {0,2}` — это старт; движения счётчика
|
||
на стенде без ключей провайдера не бывает.
|
||
|
||
### Вопросы оркестратору (канал вопросов промта, НЕ тихая интерпретация)
|
||
|
||
1. **Словарь флаг-причин — рукописная копия чужой зоны без гейта** (PD-246; формулировка исправлена
|
||
после разбора с владельцем 17.08 — прежняя, «в карте контракта дыра», была неверной).
|
||
Проверено чтением движка: локализованных фраз там НЕТ вовсе — `refusal.go` и `status.go` несут
|
||
машинные классы, русских пользовательских строк в продовом коде движка ноль. То есть движок и
|
||
контракт построены на одном принципе, и переделывать под «гугловский словарик в движке» нечего:
|
||
фраза всегда на языке ИНТЕРФЕЙСА, которого не знает ни движок, ни платформа, а движок ОДИН на все
|
||
пары — русская строка в нём была бы таргет-спецификой в общем слое (тот же инвариант, что снял
|
||
`ruby` с провода).
|
||
**Проводу окно закрыто:** причина вне карты едет кодом `unspecified`, а канон уже предписывает
|
||
клиенту нейтральную фразу для незнакомого кода — значение отдано РАТИФИЦИРОВАННОЙ ветке, а не
|
||
изобретено правило. На подпись остаются две строки продуктового текста: фраза для `unspecified` и
|
||
граница ступеней `attention`/`glance` (сегодня — догадка платформы, колонка «Ступень» в
|
||
приложении А пуста у всех 15 строк). Это не блокер.
|
||
**Правка контракта — предлагаю, зона не моя (готовые формулировки, вставить как есть).**
|
||
*Обязательный минимум — КОМПАНЬОН, приложение А, последняя строка (`README.md:899`).* Пустая
|
||
клетка кода в ней и есть то, что заставило платформу выбирать значение самой:
|
||
|
||
> `| незнакомая причина | 8 (по умолчанию) | `unspecified` — стабильный плейсхолдер деплоя: не значение словаря, а ОБЯЗАННОСТЬ сервера ответить одним и тем же кодом на причину, которой его сборка карты не знает (носитель — PD-246 платформы) | ⬜ нейтральная, НЕ «ошибка» | ⬜ |`
|
||
|
||
*Желательное — ОДНА фраза в канон*, к описанию `Note.code` (`openapi.yaml:1693-1700`), после
|
||
абзаца про нейтральную фразу:
|
||
|
||
> A deployment that meets a reason its build of the map cannot name answers the stable placeholder `unspecified` rather than the producer's own word, so the branch above is exercised by a real value in ordinary operation and not only in theory.
|
||
|
||
Форма выбрана намеренно: это ОБЯЗАННОСТЬ СЕРВЕРА, а не запись словаря — канон отказывается
|
||
перечислять `Note.code` («freezing a list in the schema before the words exist would make it a
|
||
second copy»), и перечисление начинать нельзя. Ценность ровно одна и она процессная: без строки в
|
||
нормативном документе значение живёт только в Go платформы, и следующая сессия изобретёт своё.
|
||
**Бампа версии не требует, и вот почему точно:** `Note.code` объявлен `type: string`, не enum, —
|
||
ни один генерённый тип не сужается и не расширяется; а сама фраза описывает поведение, которое
|
||
ЕДИНСТВЕННЫЙ потребитель 0.3.0 (этот пак) уже реализует, то есть сломать клиента, сгенерированного
|
||
по 0.3.0, она не может. ⚠ Прецедент D39.144 (микро-правка канона без бампа) здесь опорой НЕ
|
||
служит: там довод был «спека ещё никем не потреблена», и он больше не верен. Цена, которую надо
|
||
назвать: описания компилируются в исходники клиента, значит фраза доедет до `schema.ts` — то есть
|
||
зеркало фронта и регенерация типов при разморозке. И пара «код нормативен, фраза ⬜» должна
|
||
остаться видимой, иначе следующий читатель решит, что карта опять сломана.
|
||
|
||
**⚠ ПИНГ ОРКЕСТРАТОРУ — строка в бэклог ДВИЖКА (сама зона в чужой бэклог не пишет):** публиковать
|
||
список флаг-причин ДАННЫМИ — артефакт рядом с манифестом либо `tmctl flag-reasons --json` ($0,
|
||
таблица `flagReasonSeverity` уже существует). Тогда тест платформы читает его и ПАДАЕТ, если в
|
||
карте нет строки, и класс «словарь разъехался тихо» закрывается насовсем. Со стороны платформы
|
||
гейт невозможен: импорт `backend/internal` запрещён ревью-гардом модулей (D39.85). Обратный
|
||
вариант — чтобы движок эмитил сразу контрактный код — отвергнут: это зеркальная утечка,
|
||
продуктовое слово поехало бы в движок, который о контракте знать не должен.
|
||
2. **`sqlc` — ОТЛОЖЕН СЛОВОМ ВЛАДЕЛЬЦА 17.08** («отложим»), строка PD-44 дополнена разбором.
|
||
Фиксирую честно, включая довод против себя: пак был обязан его взять (D39.132 п.2б), и sqlc
|
||
поймал бы ровно тот класс, который дважды укусил этот пак в рантайме (`stop_for_signing`,
|
||
`chapters_before`) — батарея его поймала, но на цикл позже компилятора. Что мешает в read-модели:
|
||
запросы собраны склейкой общих фрагментов (одна проекция книги на четыре пути), а sqlc требует
|
||
литерального SQL на запрос, и страница с её ревизией — транзакция, которую он не моделирует.
|
||
Предложение зоны: взять в P8 на отложенных однооператорных ручках, по итогам решить про
|
||
read-модель.
|
||
3. **Поверхность входа: РЕШЕНО контрактной сессией 17.08 (релей владельца), механизм исполнен.**
|
||
Вердикт — вариант A уточнённый: `/auth/*` отвечает тем же конвертом и **без машинного `code`
|
||
вовсе**; клиент показывает одну нейтральную фразу, а единственный пользовательски осмысленный
|
||
случай — `429` — уже машинный без всякого словаря, потому что лечение едет в `Retry-After`
|
||
(платформа его отдаёт: `login.go:173,233`, `dev.go:138`). Отвергнуты: расширение `ErrorCode`
|
||
(значения, недостижимые на поверхности, которую этот словарь описывает, ломают инвариант «код
|
||
называет свой статус») и собственный словарь в компаньоне (сделал бы НЕнормативный документ
|
||
нормативным с чёрного хода — канон в шапке объявляет нормативным для ФОРМЫ только себя).
|
||
**Исполнено в этом дереве:** `codeForStatus` и обратная функция удалены — писатель входа берёт
|
||
статус в точке вызова и кода не эмитит, поэтому инвертировать больше нечего. Пин
|
||
`httpapi.TestTheSignInSurfaceAnswersTheSameEnvelopeWithoutAVersionedCode` (шесть статусов: конверт
|
||
и `request_id` есть, `code` нет ни у одного). PD-254 закрыт.
|
||
**Остаётся зоне контракта (релей, не пере-проектирование):** две фразы — в канон рядом с
|
||
существующей про вход (`:36-37`): поверхность механики сессии отвечает тем же конвертом без
|
||
`code`, клиент диспетчеризует по статусу, особый случай `429` с `Retry-After`, серверный текст не
|
||
показывает никогда; и в компаньон §2.14 — восстановить срезанное правило и таблицу шести статусов.
|
||
Триггер пересмотра назван явно: второй пользовательски осмысленный случай на входе → своя
|
||
маленькая нормативная спека на `/auth/*`, а не рост таблицы в спутнике.
|
||
|
||
4. **⚠ НАХОДКА КОНТРАКТНОЙ СЕССИИ, которая дороже самого вопроса — передать оркестратору отдельно.**
|
||
Правило про вход было РАТИФИЦИРОВАНО и потеряно молча: в компаньоне 0.2.3 §2.14 стояло «Отказ
|
||
входа — problem+json, как везде; **различать причины отказа клиент не может по замыслу**», а в
|
||
сегодняшней редакции осталась только первая половина — вторую срезал коммит лендинга батча 0.3.0
|
||
(`8d82096`, проверено `git log -S`). То есть P7 не переоткрывал спор, а восстанавливал решение,
|
||
которое кто-то выкинул. **Класс потери структурно непроверяем существующей приёмкой:** сверка
|
||
батча шла по мультимножеству модальных глаголов (MUST/SHOULD/MAY), а в этой фразе модального
|
||
глагола нет. Стоит отдельного разбора приёмки — не как дефект контракта, а как дыра в МЕТОДЕ
|
||
проверки резки прозы.
|
||
5. **Плотность комментариев** (PD-255): пак вышел за норму «одна-две строки почему». Часть прозы
|
||
несущая, часть — эссе; прошу решение владельца о норме, а не тихую подрезку в следующем паке.
|
||
|
||
## ⟶ Дослано 22.08 оркестратором №18: записи акта 5, оставшиеся в живом журнале
|
||
|
||
> Заголовок живого журнала «Эра пака P7 — в архиве» утверждал, что выселено всё, а ~185 строк
|
||
> остались на месте. Досылаю их сюда без правки тел.
|
||
|
||
- **P7, акт 5 — ЗАКРЫТ. Дерево готово к приёмке и лендингу.**
|
||
Батарея: 18 пакетов, exit 0, скипов 0, линтер 0 issues, тестовых функций **532** (⚠ было «533» — испр. оркестратором №18 20.08: канонической командой D39.121 `grep -rh '^func Test' platform --include='*_test.go' | wc -l` выходит 532; расхождение на единицу, ни на что не влияет, но число было заявлено без команды). Регистр — 327
|
||
строк, открытых 65 (13 minor, 52 info), **major и BLOCKER нет**. Дерево не закоммичено и не
|
||
застейджено. Миграции пака: **00019–00024**.
|
||
|
||
### Что построено и зачем
|
||
|
||
1. **Долг на материализацию — колонка с арендой** (`books.read_model_owed_at`, 00019).
|
||
Ставится в ТОЙ ЖЕ транзакции, что закрывает границу работы (конец разбора и все три конца
|
||
прогона), гасится сверкой метки, берётся в аренду тем, кто платит. **Зачем:** очередь жила в
|
||
памяти процесса — упавший `Refresh` её терял, рестарт демона терял её всю, и оплаченный текст не
|
||
доезжал до читателя НИКОГДА. Плюс «в покое» для потока теперь значит «и материализация не
|
||
должна» — это Ф-56: книга, только что нарезанная, получала `end` и 204 «не переподключайся»
|
||
ровно в те секунды, пока дерево ещё не легло.
|
||
**Почему отошёл от прежней реализации:** удалены очередь в памяти (`runs.deferRefresh`/
|
||
`DrainRefresh`/`Reader`) и бэкстоп «дерева нет вовсе» (`books.materializeMissingTrees`,
|
||
`pgstore.BooksWithNoTree`) — оба покрывались одним механизмом, а бэкстоп к тому же не видел
|
||
книгу, у которой дерево есть, но на границу старше. Дрейн переехал в `readmodel.Drain` — в
|
||
пакет, чья это работа.
|
||
2. **«Глава сделана» = последний проход, который книга на ЭТОМ деплое реально получает**
|
||
(`books.edit_wave`, 00024). **Зачем:** счёт шёл по волне `edit`, и на деплое без редактора ни
|
||
одна глава не была сделана никогда — шкала покупки не подрезалась, сервис бесконечно предлагал
|
||
купить уже переведённое. Форму объявляет сам движок (пайплайн без редактора даёт волне `edit`
|
||
знаменатель ноль). **Почему на КНИГЕ, а не на прогоне:** прочитанная с последнего прогона, она
|
||
роняла `chapters_done` в ноль в момент допуска нового прогона — счётчик ходил назад, что канон
|
||
запрещает. Флаг монотонный: книга, прошедшая редактирующий пайплайн, остаётся такой.
|
||
3. **У клейма идемпотентности появился владелец** (`claim_token`, 00020) и **тождество интейка
|
||
решается дайджестом файла** (`content_sha256`, 00023). **Зачем:** строка ключа не несла, какая
|
||
попытка её держит — застрявшая попытка удаляла строку преемника (пользователь получал вторую
|
||
книгу) или писала свою квитанцию поверх чужой (клиент реплеил `Location` несуществующей книги);
|
||
а тождество по `Content-Length` не различало две РАЗНЫЕ книги с одинаковым объявлением.
|
||
4. **Остановка АККАУНТА читается с аккаунта**, а не с потолка одного прогона; `resume` различает
|
||
«прогон закончен, нужен новый» (`ceiling_reached`) и «пополните счёт» (`credit_unavailable`);
|
||
`blocked` называет холд, который реально освободит шкалу. **Зачем:** всё это — «у вас нет
|
||
денег» пользователю, у которого деньги есть, и отправка его делать не то.
|
||
5. **Счётчик замечаний вернулся на главу** (`chapters.note_count`, 00022), `chapters.units_done`
|
||
снесён (00021). **Почему это разворот решения 00016 того же пака:** 00016 снёс колонку с
|
||
доводом «её никто не пишет» — здесь она возвращается ВМЕСТЕ с писателем, которого ей не
|
||
хватало. Основание замерено: джойн, которым её заменяли, стоил 83% времени страницы библиотеки
|
||
(16.8 мс против 3.4 мс на корпусе 40 книг × 500 глав, ВАКУУМИРОВАННОМ); со счётчиком — 6.6 мс.
|
||
⚠ Условие замера названо здесь и при каждом другом числе про него (P8-FIX, PD-336): на ХОЛОДНОМ
|
||
корпусе тот же джойн даёт 96%, и это не противоречие, а другой замер. Нормативный носитель
|
||
вакуумированных цифр — миграция 00022, остальные на неё указывают. Бенчмарк оставлен
|
||
в дереве: `go test ./internal/pgstore/ -bench LibraryPage -run xxx`.
|
||
|
||
### Что форсировано и почему
|
||
|
||
- **Работа по канону 0.4.0 лежит в дереве до его ратификации.** Основание: ответ контрактной
|
||
сессии на записку зоны плюс слово владельца 20.08 про «кончились деньги → сообщить и дать
|
||
продолжить». Ломающая правка ровно одна — `Run.stop_requested` (0.3.0 такого поля не объявляет);
|
||
`cause.code: credit_unavailable` легален и по 0.3.0, второй уровень там открыт. Зависимость
|
||
записана строкой **PD-327** и закрывается лендингом канона, а не работой зоны. Если форма
|
||
сдвинется словом владельца — правки отделимы, карта в `archive/P7_ACT5_FIX_PLAN_2026-08-20.md` §5б.
|
||
- **Тесты на АТОМАРНОСТЬ сверяют `xmin`** (транзакцию, последней писавшей строку). Это не
|
||
экзотика ради экзотики: два пина акта проходили под мутацией «вынести метку из транзакции во
|
||
второй оператор» — конечное состояние она не меняет, меняет окно, и утверждать про окно иначе
|
||
тест не может.
|
||
|
||
### Что осталось, названо и не спрятано
|
||
|
||
- **PD-327** — ждёт лендинга канона 0.4.0 (не работа зоны).
|
||
- **PD-297** — round-trip на строку в `SaveStructure` под эксклюзивной блокировкой книги. Не взят
|
||
осознанно: путь самый опасный на запись, инструмент штатный (`tx.SendBatch`), но правку надо
|
||
мерить на корпусной книге до и после.
|
||
- **Четыре оси не смотрел никто и никогда:** деньги и леджер целиком · вход/сессии/CSRF · очередь
|
||
и джобы · метрики. Пак их не менял, а все приёмки смотрели дифф. Это отдельный пак.
|
||
- **Живого перевода на стенде не было ни разу** — движку нужны ключи провайдера и деньги. Всё
|
||
после «прогон стартовал и остановился» (подпись банка, halt на потолке, резюм после пополнения)
|
||
покрыто батареей против живого Postgres, а не живым движком.
|
||
|
||
### Как это проверялось
|
||
|
||
`make check` с гейтами (скипов 0) · каждая правка проверена ПОСАДКОЙ МУТАЦИИ: код испорчен именно
|
||
так, как называет комментарий пина, пин обязан упасть, код возвращён (40 проб, все поймались) ·
|
||
живые пробы по ручкам на стенде: интейк и реплей, `409 key_reused` на другой файл под тем же
|
||
ключом, часть после файла на реплее, `/chapters` `/units` `/notes` `/bank`, ETag→304 и разные теги
|
||
у страниц, 410 на чужой id главы, `after_version` из прошлой жизни, `unsupported_pair`, `/usage`
|
||
на пустом счету и после `adjust`, старт и стоп прогона со `stop_requested` на проводе, SSE в
|
||
покое и SSE с непогашенным долгом (Ф-56 на проводе), 400 вместо 413 на длинном теле.
|
||
|
||
### Самопроверка
|
||
|
||
Акт закрыт адверсариальным ревью СОБСТВЕННОГО диффа (9 линз × 2 рефутера + критик полноты, 84
|
||
агента, 0 ошибок): **37 находок, 18 пережили рефутеров**, и почти все — дефекты, внесённые
|
||
правками самого акта. Строки **PD-315…PD-327**, каждая с механизмом и пином. Два из них —
|
||
собственные пины акта, проходившие под мутацией, которую сами называют (PD-318): это третье
|
||
появление класса в паке, и он назван в плане §3 п.2 ещё до того, как повторился.
|
||
|
||
- **P7, акт 5 (начало) — исполнение фиксов по ревью акта 4 + ответ контрактной сессии.**
|
||
План и рабочий список — **`platform/docs/archive/P7_ACT5_FIX_PLAN_2026-08-20.md`** (читать первым; §5а — что пришло из
|
||
контракта).
|
||
⚠ **Контрактная сессия ответила 20.08 на записку зоны `archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md`: канон стал
|
||
0.4.0** (лежит в дереве контрактной зоны, НЕ ратифицирован — до лендинга в силе 0.3.0). Все три
|
||
вопроса, висевшие на владельце, закрыты. Зоне пришла работа: `resume` исчерпанного прогона — 409 с
|
||
двумя РАЗНЫМИ причинами (`ceiling_reached` против нового `credit_unavailable`); «глава сделана» =
|
||
последний реально пройденный проход, и это ДЕНЬГИ — `ChaptersLeft` на деплое без волны редактора не
|
||
подрезается вовсе, сервис бесконечно предлагает купить уже переведённое; отпечаток интейка — по
|
||
содержимому, `Content-Length` из нормы вышел, а невозможность установить тождество обязана давать
|
||
409, а не реплей; `Run.stop_requested` обязательным булевым (единственная ломающая правка).
|
||
Отклонены: слово под суточный потолок движка (решение владельца 15.08) и предложенный зоной признак
|
||
«прогон продолжаем» (три лишних чтения на карточке, которую перечитывают на каждый кадр).
|
||
Акт 4 закрылся адверсариальным ревью СОБСТВЕННОГО диффа (9 линз × 2 рефутера, 75 агентов):
|
||
**33 находки, 27 пережили рефутеров**, и часть из них внесли сами правки акта 4. Тяжелейшая —
|
||
четыре независимые линзы сошлись на том, что **реконсилятор снимал стоп подписи банка, которого
|
||
никто не подписывал**, и доспавнивал движок без `--verify-bank`: складывая снятие стопа внутрь
|
||
общего `reopen`, акт 4 не проверил, что `reopen` зовёт не только `resume`, но и свип. Нарушение
|
||
согласия пользователя; починено ключом на вызывающего, пин проверен посадкой мутации.
|
||
⚠ **Первый написанный на это пин ПРОШЁЛ под мутацией** — фикстура не доходила до кода, потому что
|
||
часы сервиса захвачены при конструировании и `f.now` их не двигает. Урок в плане, §3.
|
||
Закрыто также: загрузочная проверка пар — на ДОСТУПНОЙ половине (деплой с одними `:unavailable`
|
||
больше не стартует), интейк не трактует пустой список как «пускать всё», теги сравниваются
|
||
регистронезависимо. Батарея: 18 пакетов, exit 0, скипов 0, тестов **503**.
|
||
|
||
- **P7, акт 4 — доработка 20.08: сверка ВСЕХ находок против дерева + триаж §8.2.**
|
||
(Пакет релеев `archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md` §7; три вопроса владельцу §8.1а; вопросы контракта
|
||
вынесены в `platform/docs/archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md` для отдельной контрактной сессии.)
|
||
Все 74 позиции обеих приёмок сверены поштучно с ТЕКУЩИМ деревом — каждая с цитатой живого кода,
|
||
исход «не проверено» отдельно от «опровергнуто».
|
||
⚠ **Три места числились закрытыми и закрыты не были — правка не закрывала собственный сценарий:**
|
||
(1) подрезка буфера потока сверялась ПОСЛЕ того, как водяной знак перепрыгнул дыру, поэтому
|
||
условие не срабатывало никогда и кадры `note` терялись молча (PD-283); (2) `CompleteIdempotency`
|
||
писала квитанцию в строку, которая попытке уже не принадлежит — воспроизведено живым PG, клиент
|
||
получал квитанцию ЧУЖОГО запроса (PD-284); (3) пин на снятие `--verify-bank` был ПУСТЫМ: фикстура
|
||
стартовала прогон без `stop_for_signing` (PD-285). Все три «подтверждались» зелёной батареей.
|
||
**Ещё закрыто:** HEAD на потоке больше не держит горутину и ошибка `Flush` не выдаётся за
|
||
отправленный кадр (PD-286) · `blocked` называет чужую книгу только когда её холд укорачивает шкалу
|
||
(PD-287, пина не было вовсе) · `note_count` и `GET /notes` описывают одно множество (PD-288) ·
|
||
устаревшая доставка не рождает кадр (PD-289) · чтения на одном снапшоте (PD-290) · флаг «текст
|
||
прочитан» переехал на ПАРУ (PD-291) · снятие стопа банка внутри транзакции переоткрытия, отдельного
|
||
писателя больше нет (PD-292) · проход материализации подрезается своим бюджетом (PD-293) ·
|
||
блокировка книги в решениях банка (PD-294) · дубликат индекса снят (PD-295) · маршруты и коды
|
||
ошибок — по ОДНОЙ таблице, тесты ходят по ней (PD-296) · бэкстоп-свип для книги без дерева
|
||
(PD-276 дозакрыт) · интейк не платит за третью ре-нарезку (PD-248 актуализирован).
|
||
**Триаж §8.2:** 17 сделано, 5 отклонено с причиной, 1 релей. Батарея: 18 пакетов, exit 0, скипов 0,
|
||
линтер 0 issues, тестов **458 → 501**; каждая правка проверена посадкой мутации, не рассуждением.
|
||
⚠ **Осознанно НЕ сделано, с причиной:** PD-297 (round-trip на строку под блокировкой книги —
|
||
мерить прежде правки) · PD-202 (draft-only, вопрос владельцу) · PD-282 (канон §resumeRun не
|
||
покрывает «денег не осталось») · PD-298 (сперва сверка у движка) · PD-299.
|
||
**Осей, которых не смотрел никто:** деньги и леджер · вход/сессии/CSRF · очередь и джобы · метрики.
|
||
|
||
- **P7: приёмка → правки → приёмка правок (17.08).**
|
||
⚠ Полный хендофф под сессию без контекста — **`platform/docs/archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md`** (читать §0–§3,
|
||
дальше по нужде). Там же: принципы приёмки, сверка с исходным промтом, техдолг, план следующей сессии.
|
||
Категорийное ревью по 12 осям с адверсариальной верификацией: 80 находок, **54 подтверждено, 16
|
||
правдоподобно, 10 опровергнуто**; после дедупа **46 уникальных дефектов** — 3 блокирующих класса,
|
||
15 HIGH, 17 MEDIUM. Батарея была зелёная, потому что все три блокирующих дефекта живут в путях,
|
||
которые тесты проходили только в безопасной форме.
|
||
**Починено в зоне** (регистр PD-257…PD-281): пере-нарезка книги больше не валит читающую модель
|
||
навсегда (отложенный констрейнт, миграция 00018) · упавший `tmctl export` больше не затирает текст
|
||
пустотой · весь блок идемпотентности (гонка первых попыток 500→409, область ключа, отпечаток с
|
||
размером файла, закрытие ключа вне контекста запроса) · база полосы прогресса считает тот же
|
||
проход, что числитель · SSE (подрезанные кадры → `resync_required`, дедлайн записи, id из
|
||
будущего) · материализация не голодает свип · банк читается на штатном деплое · деплой-нота больше
|
||
не включает обратно грант, который PD-104 выключил. Батарея: 18 пакетов, exit 0, скипов 0,
|
||
линтер 0 issues, тестов **458 → 490**.
|
||
⚠ **Приёмка ПРАВОК (9 осей + fable-5) нашла, что восемь дефектов внесли сами правки** — батарея не
|
||
увидела ни одного, три были запинены под ошибку автора. Все исправлены; разбор — хендофф §0.
|
||
**Б-1 ПОЧИНЕН разбором с владельцем 17.08 (PD-277).** Рамка приёмки была неверна: это не «нужен
|
||
новый канал в движок», а невыполненная половина строки единого бэклога **191(в)** (слово владельца
|
||
16.08, D39.144) — «проводка `resume = снятие стопа` до движка». Движок при выключенном
|
||
`--verify-bank` уже делает модель владельца: неподписанное едет авто-строками с пометкой
|
||
⟨проверить⟩ (`mining.go:211-231`, D39.42 п.3), а платформа передавала флаг обратно и роняла прогон
|
||
в тот же стоп. Снято: `l.VerifyBank && !l.BankReleased`; пин `TestAResumedRunIsSpawnedWithoutTheSigningStop`.
|
||
⚠ Остаток: `decline` пользователя до движка не доезжает (движок читает `mined_rejects`) — строка
|
||
бэклога **192**, отложена владельцем.
|
||
**PD-273 закрыт решением владельца 17.08:** статус остаётся `awaiting_bank`, лечение — признак
|
||
«стоп был запрошен» в контракте; готовая строка для единого бэклога — хендофф §7(и), вставляет
|
||
оркестратор (зона `docs/` не наша).
|
||
**Разбор, план, обязательства через оркестратора и команды воспроизведения —
|
||
`platform/docs/archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md`.**
|
||
⚠ Заявки раздела «Сессия P7» ниже приёмку НЕ прошли — читать их вместе с хендоффом, не вместо.
|
||
|
||
- **P7 ПОСТРОЕН — заявка САМОЙ сессии написания (17.08).** ⚠ **Приёмку эта заявка НЕ прошла** — см.
|
||
верхнюю запись и `archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md`: 46 уникальных дефектов, три блокирующих класса, из них
|
||
ни один батарея не видела. Читать ниже как исходную позицию, а не как состояние дерева.
|
||
Читающая поверхность контракта **0.3.0**:
|
||
главы · пары с текстом · замечания · банк и подпись · SSE на КНИГЕ · `GET /capabilities` ·
|
||
машинная модель ошибок (`code` + `request_id`) · условные чтения и сжатие · `Idempotency-Key` ·
|
||
`structure_version`. Плюс форварды (`title`, `reject_reason`), PD-104 (грант → 0), демонтаж
|
||
построенного гейта полноты банка (D39.144), PD-241, конформность построенного по §5 промта и
|
||
рантбук деплоя, прогнанный ЖИВЫМ `migrate`. Батарея на стенде `~/.local/pgsql` (порт 55433) под
|
||
`-race` с ОБОИМИ гейтами: **EXIT=0, 18 пакетов, скипов 0, линтер 0 issues**, тестовых функций
|
||
**416 → 458**. Дифф: 46 файлов, +2329/−646. Селф-ревью финалом — ТРИ независимых ревьюера, два из
|
||
них другой модели: **22 находки, 17 подтверждены и починены** (две HIGH нашли оба контрактных
|
||
ревьюера независимо), 5 — диспозиция с аргументом. Разделы ниже — записка-план, живые пробы,
|
||
таблица селф-ревью, obstacle, вопросы оркестратору.
|
||
|