textmachine/docs/PLATFORM_SQLC_PACK_SESSION_PROMPT.md

19 KiB
Raw Blame History

Промт: платформа, пак 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, замерено 12 падения на ~80 прогонов, разгоняется -race. Файл idempotency.go — в твоём наборе. Увидишь красное — сперва пере-прогони серийно, и не приписывай его конверсии. И не «чини» его ради зелени: править или удалять тест, чтобы он прошёл, недопустимо (D39.121); несогласие с тестом — пинг, а не правка.

4. Самопроверка ИСПОЛНЕНИЕМ (без неё работа не принята)

Мандат — не «перечитал», а прогон с числами:

  • Батарея зоны с полным набором гейтов, -race обязателен. ⚠ Условий у батареи больше, чем помнит большинство доков, и часть требует РУЧНОЙ сборки стенда (движковый бинарь + $0-пайплайн, которого в репо нет; плюс условие про user@<uid>.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 платформа не пишет.