# Промт: платформа, пак `sqlc` — конверсия свободного от склейки блока `pgstore` ## 0. Что это за работа и почему она отдельной сессией Платформа собирает SQL строками в Go. Класс дефектов, который это порождает, зона ловила дважды рантайм-падениями. Владелец 20.08 решил взять **`sqlc`** — генератор типизированных методов из `.sql`-файлов (**D39.153 п.6а**, «я вообще за»), а 22.08 уточнил: **отдельной сессией, не внутри содержательного пака** (D39.154), потому что правок много и мешать их с другой работой нельзя. Ты — эта сессия. Носитель работы — `platform/BACKLOG.md` строка **П-19**. ⚠ **И сразу главное, чего промт не скрывает: бо́льшую часть ценности sqlc зона уже получила другим механизмом.** Гейт `pgstore.TestEverySQLStatementParsesAgainstTheMigratedSchema` (`internal/pgstore/sqlgate_test.go:36`) планирует ЖИВЫМ Postgres каждый собранный запрос пакета против мигрированной схемы — то есть закрывает класс «нет такой колонки» для ВСЕХ операторов, включая те, куда sqlc не дойдёт никогда, и где случились оба реальных падения зоны. По разбору **D39.155 п.9** остаётся узкий остаток: **арность `$n` и цели `Scan`**. **Что решит твой результат:** снимет остаток, которого гейт не берёт, и уберёт ручную сборку там, где она не нужна. **Чего не решит:** склейки, read-модель и денежные транзакции остаются рукописными. ## 1. Зона записи и git Пишешь только в `platform/`. **Не коммитишь**: дерево готовишь и передаёшь оркестратору, он лендит. Канон git — `CLAUDE.md`, здесь не дублируется. Чужие незакоммиченные файлы не трогать. ## 2. Карта чтения — ПЯТЬ позиций, дальше только по их ссылкам 1. `platform/docs/PLATFORM_DIRECTION.md` §3 — **сначала верхний слой-баннер 22.08**: по `sqlc` действует НЕ то решение, что записано ниже в разделе; отказ пака P7 там — история, а не действующая норма. 2. `platform/BACKLOG.md` строки **П-19** (эта работа) и **П-21** (см. §3.5 — флейк в твоей же зоне). 3. `platform/docs/ENGINEERING_STANDARDS.md` — норматив зоны; отступление от любого пункта = пинг. 4. `platform/internal/pgstore/sqlgate_test.go` — гейт, который уже съел бо́льшую часть ценности, и его экстрактор. **Прочти ДО решения, что строишь** (§3.4 — там ловушка, решаемая до первой строки). 5. `platform/docs/STACK_DECISIONS.md` §«Гейты батареи» — **единственный носитель** числа условий батареи. ## 3. Работа ### 3.0 ⛔ ПЕРВЫМ ДЕЙСТВИЕМ — СИНХРОНИЗАЦИЯ С КОДОМ (делай РОВНО так, слово владельца) Все числа ниже — мои на 29.08, и часть из них уже расходилась с носителями. **Пере-считай сам, до первой правки**, и назови расхождения в отчёте: расхождение — факт, а не твоя ошибка. Заодно сверь, что `git status` чист и в дереве нет чужой незакоммиченной работы. ### 3.1 Затем — ОТВЕТ, а не код (реши сам, аргументируй) **Вопрос: что `sqlc` даёт СВЕРХ существующего гейта?** Ответь ЧИСЛАМИ до первой строки конфигурации: сколько запросов набора не проверяется сегодня ничем, какие классы ошибок это ловит, что из этого не ловится дешевле. ⚠ **Число «два запроса, не исполняемых ничем» взято из D39.155 п.9, НЕ проверено мной и, вероятно, занижено.** Мой опровергатель нашёл статически минимум четыре функции набора без единой ссылки из тестов пакета: `OpenReservations` (`credits.go:142`), `ReleaseUnspawned` (`credits.go:324`), `DeleteOldLoginEvents` (`identity.go:73`), `UserByIdentity` (`identity.go:121`) — их вызовы живут под `cmd/`, где тесты есть, но достигают ли они этих путей, никто не проверял. **Метод определения выбираешь сам** (покрытие живым прогоном / инструментальный анализ), но метод назови: это самое дорогое число пака, и на нём висит развилка «строить или нет». - Ответ «существенно больше остатка» — строй, покажи расчёт. - **Ответ «почти ничего» — СКАЖИ ЭТО и остановись.** Законный исход (см. §7), а не провал: владелец сказал «БЕРЁМ», зная довод про гейт, но твоих чисел на сегодняшнем дереве он не видел. ### 3.2 Граница набора — числа уехали, носители расходятся (делай РОВНО так: считай сам) П-19 называет **41 запрос**. Моя пере-проверка 29.08 даёт **42**: `credits.go` 15 · `identity.go` 13 · `idempotency.go` 7 · **`sessions.go` 6** (было 5; пак P11 добавил `StillLive`, лендинг `e548e5a`) · `observe.go` 1. Операторов в пакете вне тестов — около **168**, то есть набор это примерно **четверть пакета**, а не шестая часть. ⚠ Сам гейт в комментарии (`sqlgate_test.go:21-23`) даёт третью оценку доли склеенного — **носители расходятся, выбери и назови свой метод счёта, а не наследуй чужой**. ⚠ **Граница описана оптимистичнее, чем есть (D39.155 п.9), и это твой главный риск:** - **набор НЕ замкнут по транзакции**: **8 запросов** идут из транзакций неконвертируемого кода — все в `credits.go` (`lockBalance`, `holdTx`, `appendLedger`, `closeReservation`, `lockBook`), достижимы из `runs.go`, `books.go`, `readmodel.go`, `sink.go`. Генерённый метод, вызванный внутри чужой транзакции, обязан её ПРИНИМАТЬ, а не открывать свою. - ⚠ **Поправка к самой ноте, проверенная мной:** её фраза про «занижено вдвое» неверна. Денежных запросов в чужой транзакции — **11 из 15** в `credits.go`, и это точно; **20** — это ВСЕ транзакционные запросы набора (11 денежных + 5 `identity` + 4 `idempotency`). Не ищи девять несуществующих денежных запросов и не расширяй денежную границу на `identity`/`idempotency`. ### 3.3 Стройка (форму выбираешь сам, ограничения жёсткие) - **Инструмент пинится ТОЧНОЙ версией**, как `golangci-lint` в `platform/Makefile:21` с гейтом версии на `:55`. Версию бери ЖИВОЙ проверкой у вендора, не из памяти и не из этого промта. `sqlc` в тулчейне сейчас нет — установка твоя. - **Гейт актуальности генерации — В БАТАРЕЕ (делай РОВНО так).** Не просто цель `Makefile`: цель, которую `make check` не зовёт, гейтом не является, а П-19 заказывает именно гейт «сгенерённое актуально». Прогон на чистом дереве не меняет ни байта. - **Строка в `STACK_DECISIONS.md`** — обязательный деливерабл зоны для любой новой зависимости (`ENGINEERING_STANDARDS.md:12-14`): дата релиза и «зачем». **Ратифицирует оркестратор** — пришли её вместе с деревом, не считай сделанной сама. - **Денежные типы требуют `overrides`**: micro-USD целочисленный, и генерённый слой не имеет права превратить его в float ни на одном шаге (класс PD-15). - ⛔ **Не двигать:** склейки, фрагменты-константы, read-модель (`readmodel.go` — страница, её ревизия, курсор, водяной знак и агрегаты в ОДНОЙ транзакции). - ⚠ **Шов, который надо решить явно:** `lockBook` живёт в конвертируемом `credits.go:481`, но зовётся из `readmodel.go:262` и `books.go:374` — то есть стоит ровно на границе ⛔-зоны и набора. Конвертировать или оставить — **реши и аргументируй**, молча не бери ни то ни другое. ### 3.4 ⛔ РАЗВИЛКА, КОТОРУЮ РЕШАЮТ ДО ПЕРВОЙ СТРОКИ КОНФИГУРАЦИИ **Куда генерировать: в сам `pgstore` или в под-пакет (дефолт `sqlc`)?** У экстрактора гейта жёсткий пол — `if len(stmts) < 140` (`sqlgate_test.go:41`), и глобит он `*.go` только в СВОЁМ каталоге. Уведи 42 оператора в под-пакет — счёт упадёт ниже пола, и **гейт покраснеет по собственному полу**. ⚠ Подвинуть пол ради зелени НЕЛЬЗЯ: это подгонка гейта, запрещённая каноном. Значит либо генерируешь в тот же каталог, либо расширяешь ОХВАТ экстрактора (не пол) так, чтобы генерённые операторы продолжали проверяться живой схемой. Реши, аргументируй, и покажи прогоном, что гейт видит их после конверсии. **Второй носитель схемы.** sqlc нужен вход-схема, а у зоны она уже имеет носителя с гейтом целостности: `internal/pgstore/migrations/` + манифест `migrations.sha256` (`migrations_test.go`). Собственная копия схемы в конфиге заведёт второй носитель факта, которого манифест не видит, — класс «один носитель на факт». **Реши и аргументируй**, как этого избежать. ### 3.5 ⚠ Красное, которое НЕ твоё (знай заранее) В `idempotency_test.go:265` живёт `TestAClaimThatLostARaceToAReleaseIsRetriedAndNotAnError` — известный флейк, `PD-369` / `BACKLOG.md` **П-21**, замерено 1–2 падения на ~80 прогонов, разгоняется `-race`. Файл `idempotency.go` — в твоём наборе. **Увидишь красное — сперва пере-прогони серийно, и не приписывай его конверсии.** ⛔ И не «чини» его ради зелени: править или удалять тест, чтобы он прошёл, недопустимо (D39.121); несогласие с тестом — пинг, а не правка. ## 4. Самопроверка ИСПОЛНЕНИЕМ (без неё работа не принята) Мандат — не «перечитал», а прогон с числами: - **Батарея зоны с полным набором гейтов**, `-race` обязателен. ⚠ Условий у батареи больше, чем помнит большинство доков, и часть требует РУЧНОЙ сборки стенда (движковый бинарь + $0-пайплайн, которого в репо нет; плюс условие про `user@.service`, под WSL не выполняющееся). Рецепт — в карте чтения поз. 5. **Заложи на это время отдельно** и назови в отчёте, какие условия у тебя выполнены, а какие нет. - **Поведенческая эквивалентность:** каждый конвертированный запрос доказывается тем, что его тест проходит ДО и ПОСЛЕ. Дифф генерённого кода — не доказательство. - **Дифф `^func Test` — ИСПОЛНЕНИЕМ, не памятью:** покажи командой, что ни один тест не исчез и не переименовался при переписывании слоя. - **СОБСТВЕННЫЕ мутационные посадки**, не список из промта: сломай арность `$n`, подмени цель `Scan`, поменяй тип денежной колонки — каждая обязана падать АДРЕСНО. Посадка, которую никто не ловит, ценнее трёх пойманных: неси её в отчёт. - **Разрешаю субагентов** (иначе дефолт харнесса тихо запретит). Модель задавай ЯВНО и знай, сколько их работает. Трудный вопрос — старшей модели. - **Интервальная самоверификация** (D39.121): пак длинный, поэтому в середине работы — проход субагента по СВОЕЙ готовой части против явных критериев, не в конце. - ⚠ **Адверсариальный проход по своей готовой работе перед сдачей — ОБЯЗАТЕЛЕН, изменения потенциально опасные (слово владельца).** Направление, что уязвимо здесь: генерённый метод, открывающий свою транзакцию внутри чужой; денежный тип, потерявший целочисленность на границе; запрос, выпавший из-под гейта; **тихо-зелёный тест** — проходящий, ничего не проверив (D39.171). Глубину и веер выбираешь сам. - **Доказательная база — в РЕПОЗИТОРИЙ** (логи посадок, числа прогонов идут в зонный журнал), а не в `/tmp`: что должно пережить рестарт, живёт в дереве. ## 5. Оси ревью **Деньги** (целочисленность micro-USD сквозь генерацию, транзакционные границы) · **шов с гейтом** (ни один запрос не выпал из `sqlgate_test.go`) · **воспроизводимость генерации**. Вправе заменить ось с аргументом. ## 6. Записка-план и комплектность До стройки — короткая **записка-план** в зонный журнал: что берёшь, что не берёшь, чем докажешь. Перед сдачей — **механическая сверка состава против §3**, таблицей: пункт → сделано/нет → чем доказано. Пропуск подписывается пропуском. **Последний абзац отчёта оказался планом или обещанием? Сделай сейчас.** ## 7. Канал вопросов и право отказаться Конфликт промта с кодом или доками — **пинг через владельца, не интерпретация**. Есть право сказать «этого делать не надо» с аргументом; по §3.1 это ожидаемый исход, а не поражение. ## 8. Заявление = команда Любое число и любая категорика в отчёте — **с командой, которой получены**. Приёмка пере-ранит: клейм без пере-прогона записывается как «со слов сессии». «Проверено» без исполнения в этой зоне уже дважды оказывалось ложным. ## 9. Эхо-протокол старта ДО первой правки — ≤10 строк: **скоуп / инварианты / чего не делаешь**. Отправь первым действием по адресу оркестратора из `/tmp/textmachine-channel` (механизм — `CLAUDE.md` §«Связь между сессиями»; впиши туда СВОЙ блок первым делом). Эхо служит и проверкой канала. **Канала нет ⇒ НЕ искать**: вопрос секцией в отчёт, работа продолжается. ## 10. Obstacle reporting Обязательная секция отчёта: **что НЕ удалось и что осталось непроверенным**. Пустой не бывает. Три исхода: «подтверждено» / «опровергнуто» / **«не проверено»** — третье не сваливать во второе. ## 11. Зонный журнал Итоги, пинги и вопросы — `platform/docs/platform-PROGRESS.md`. В `docs/PROGRESS.md` платформа не пишет.