56 lines
11 KiB
Markdown
56 lines
11 KiB
Markdown
# Промт бэкенд-сессии: индустриальные стандарты репозитория — линтер · CI · бамп зависимостей · гарды-в-analyzer (строки 107 · 112 · Д7)
|
||
|
||
**Мандат:** решение владельца 02.08 (D39.92): «делаем по стандартам индустрии: CI, линтер, бамп x/net и всех библиотек; осторожный, затем полный подход; спилить самописные AST-тест-гарды в пользу штатной формы». Ограничение владельца, равное по силе самому мандату: **стандарты не должны мешать разрабатывать, тормозить и приводить модели к хакам.**
|
||
|
||
**Онбординг:** CLAUDE.md → `docs/README.md` → CURRENT-STATE в `docs/PROGRESS.md` → голова D39.91–92 в `05-decisions-log.md` → `backend/README.md` + `12-go-style-notes.md`. Контекст предмета: отчёт `archive/reports/EFFORT_HANDLE_2026-08-02.md` §1.3(2), §5.5, Д7; D39.90 п.7; строка 107 трекера.
|
||
|
||
## §0. Скоуп, деньги, стоп-правила
|
||
|
||
- Зона записи: `backend/` ТОЛЬКО. НЕ коммитить — лендит оркестратор. `git add`/`commit` не запускать вовсе; `.env` не читать.
|
||
- Деньги: этапы 0–C и E — **$0**. Этап D (бамп зависимостей) включает живую мини-пробу провода: потолок **$0.50**, каждый цент в леджер, тела предъявить.
|
||
- **Анти-хак-правило (владелец):** запрещено «зеленить» линтер обходами — переименованиями без смысла, пустыми обёртками, дроблением функций ради метрики, гашением через рефактор-мусор. Спорное правило линтера → ВЫКЛЮЧИТЬ правило в конфиге с одной строкой причины — это честнее, чем хак в коде. Голый `//nolint` без причины запрещён (включить `nolintlint`).
|
||
- **СТОП-пинги оркестратору:** этап A даёт >1000 находок → пинг с числами ДО любых правок · этап B требует правок >30 файлов разом → пинг с планом · этап D меняет поведение провода (красный квирк-тест, флейк пробы, новый заголовок/фрейминг) → СТОП, откат бампа, пинг. Молча продавливать нельзя ни одно из трёх.
|
||
- Мандат самопроверки (CLAUDE.md 12.07): ревью ИСПОЛНЕНИЕМ своего кода и конфигов; адверсариальные посадки для этапа E обязательны; спорное — author≠reviewer.
|
||
|
||
## Этап 0 (15 минут, независим от остального): строка 112 — санкционированная правка пяти шиппинг-конфигов
|
||
|
||
`stages[draft].reasoning: "off"` → `"low"` в: `configs/pipeline-c1.yaml:49` · `pipeline-c2.yaml:26,39` · `pipeline-arm-mistral.yaml:30` · `pipeline-arm-glm.yaml:34` · `pipeline-arm-deepseek-pro.yaml:34`. Санкция владельца 02.08 (D39.92); перекупка снапшотов старых книг принята, новые книги $0.
|
||
|
||
- ⚠ **НЕ ТРОГАТЬ** `reasoning: "off"` на РЕДАКТОРСКИХ/финальных стадиях (`c1:77` · `c2:51` · `arm-glm:43` · `arm-deepseek-pro:43`) — они осознанные (D39.91 Д11: на glm это живой thinking-off от таймаутов ×3, на dspro — no-op-страховка эхо-мины).
|
||
- ⚠ У arm-mistral черновик — проверь МОДЕЛЬ стадии прежде чем править: ключ имеет смысл только там, где стадия резолвится в reasoning-модель; no-op на не-reasoning модели можно оставить `"off"` с комментарием, но реши ЯВНО и запиши.
|
||
- После правки: `tmctl status --config` на каждом из пяти + полная батарея. В отчёт: дифф построчно, что не тронуто и почему.
|
||
|
||
## Этап A ($0-замер, НИЧЕГО не чинить): объём находок стандартного набора
|
||
|
||
1. `golangci-lint` ПИНОВАННОЙ версией (бинарь вне репо, версию в отчёт) — дефолтный набор + `staticcheck, errcheck, unused, ineffassign, misspell, nolintlint` в **report-only** на `./backend/...`.
|
||
2. Отчёт ЧИСЛАМИ: находки по правилам × по пакетам × prod/test раздельно. Ни одной правки на этом этапе — это замер, санкционированный владельцем как первый шаг (D39.90 п.7).
|
||
|
||
## Этап B (состав и режим — предложение, решение с оркестратором)
|
||
|
||
- Предложить `.golangci.yml`: каждое правило ВКЛ/ВЫКЛ с обоснованием ЧИСЛОМ из этапа A (не вкусом). База: `go vet` уже чист — зафиксировать.
|
||
- Режим внедрения: baseline «только новый/правленый код» (`--new-from-rev`) против big-bang по правилам с малым хвостом (например, всё с ≤20 находками — big-bang, остальное — baseline). Предложить, НЕ исполнять до ответа на СТОП-пинг, если хвост большой.
|
||
- `exhaustruct` НЕ включать глобально (16 находок, 15 в тестах — замерено §5.5); точечно на `config.Stage`/`pipeline.Request` рассмотреть — это ровно класс исходного бага.
|
||
|
||
## Этап C (CI + Makefile: одна команда для всех)
|
||
|
||
- `Makefile` (или `make.go`): цели `build · vet · lint · test · battery` — где `battery` = ровно текущая ручная батарея (`build && vet && vet -tags live && gofmt -l && test -race -count=1` + голден/парити/labels/K6 по env-флагам). Сессии перестают собирать её руками.
|
||
- CI-воркфлоу: проверь `git remote -v`; если удалёнки/раннера нет — файл workflow подготовить (`go build/vet/lint/test`), обязательной точкой входа до его оживления становится `make battery`. Пины версий тулчейна и линтера в конфиге, не latest.
|
||
- Прекоммит: у фронта уже стоит самоустанавливающийся гейт (`7832be7`, `frontend/scripts/githooks/`) — НЕ ломать и НЕ дублировать; если расширяешь на backend-пути, только согласованной правкой через оркестратора (это смежная зона).
|
||
|
||
## Этап D (бамп зависимостей — осторожно: x/net это наш транспорт)
|
||
|
||
- Бамп прямых зависимостей `go.mod` (включая `x/net` 0.26 → текущий, `x/tools` под этап E). Go toolchain — только если требуется, отдельной строкой в отчёте.
|
||
- ⚠ `x/net/http2` — транспорт ко ВСЕМ провайдерам. После бампа обязательны: полная батарея · голден (PASS без пере-захвата — вердикты не двигаются) · **живая мини-проба провода на КАЖДЫЙ провайдер** из `models.yaml` (1 короткий вызов; потолок $0.50 суммарно; сверить: тела, ключи запроса, `reasoning_content`, finish_reason, отсутствие новых заголовков/фреймингов против `00-provider-quirks.md`). Любое расхождение = СТОП-пинг, откат.
|
||
|
||
## Этап E (гарды → analyzer; снос тест-гардов ТОЛЬКО после доказанного паритета)
|
||
|
||
Предмет: `synthetic_stage_seam_test.go` (два AST-гарда + пол числа файлов) и давний байтовый `TestProviderEgressSeamIsSingle` (Д7) → ОДИН обход на `x/tools/go/analysis` с `types.Info` (алиасы/дот-импорты закрываются по построению), запуск через `go vet -vettool=` из `make battery`/CI.
|
||
|
||
- **Инварианты — предмет контракта, не форма:** (i) `config.Stage` строится вне лоадера только швом `InternalCall.Stage()`; (ii) `pipeline.Request` собирается только в `attemptRequest`; (iii) egress-инвариант старого гарда — перенести его словарь исключений осознанно, не копипастой; (iv) рефлексионный `TestInternalCallDecidesEveryStageField` — НЕ трогать, он не про обход дерева и в analyzer не нуждается.
|
||
- **Паритет посадками:** все 12 известных обходов (5 байтовых + алиас + `[]config.Stage{{…}}` из отчёта §1.3; `var`-форма, `new()`, hoisted `Request` + алиас-литерал + слайс — посадки приёмки D39.91) воспроизвести как тест-кейсы АНАЛИЗАТОРА (`analysistest`). Analyzer обязан ловить все 12 + иметь эквивалент пола «я реально видел файлы».
|
||
- ⚠ **Известная слепая зона `go/packages`:** старый гард ходил и по `eval/` ВНЕ Go-модуля (исторически там жил четвёртый сайт дефекта). Реши явно: гонять analyzer и на eval-модуле, или закрыть этот класс иначе — и запиши решение.
|
||
- Снос `_test.go`-гардов — ПОСЛЕДНИМ коммитом пака, только при 12/12 у analyzer. До того оба механизма живут параллельно.
|
||
|
||
## Отчёт
|
||
|
||
`docs/archive/reports/REPO_STANDARDS_<дата>.md`: эхо-шапка · числа этапа A · состав+режим B с обоснованиями · что даёт `make battery` · дифф бампа и предъявление живой пробы D · паритет-таблица 12 посадок E · снесённое/оставленное · найдено-не-починено с носителями · «заявление = команда» на каждое число. **СТОП — приёмка оркестратора.**
|