textmachine/docs/BACKEND_TRANSPORT_PACK_SESSION_PROMPT.md

38 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Промт бэкенд-сессии: ПАК-12 «транспорт-гигиена» (по research/21)
**Статус: ВЫДАН 23.07.2026, оркестратор №7. ГЕЙТ ОТКРЫТ 23.07 (D39.20): платный путь пере-прогона завершён, чтение принято — можно стартовать на чистом дереве.** Координация: возможен параллельный пак-13 «выпускной QA» — зоны файлов почти не пересекаются (пак-12 = `internal/llm/` + тесты; пак-13 = чекеры/санитайзер/банк), но при одновременном запуске — согласовать через оркестратора, кто первый лендится.
## Рамка
Источник скоупа — `docs/research/21-llm-transport-survey.md` (читать ревью-шапку: там эрратум и поправки применимости). Вердикт обзора ратифицирован: **транспорт НЕ рефакторим** — наш дизайн (Capability-как-данные, единый retryLoop, fail-loud) правильнее SDK-паттернов для детерминизм-критичной системы. Пак — ТОЛЬКО точечные добавки ниже. Любой соблазн «заодно переделать» — стоп и пинг оркестратору.
**Жёсткий инвариант пака: ноль wire-байтов.** Ни одно изменение не трогает тело запроса → snapshot не двигается, `--resnapshot` НЕ требуется, golden байт-идентичен (новые пины — отдельными тестами). Это критерий приёмки №1.
## Онбординг
`CLAUDE.md``docs/README.md` → CURRENT-STATE `PROGRESS.md``research/21` (целиком) → `00-provider-quirks.md``backend/internal/llm/` + `internal/pipeline/{ratelimit,quality,cheapgates}.go` + `configs/models.yaml`.
## Скоуп (10 пунктов, каждый ~1060 строк + тест)
1. **Валидация-тест `models.yaml`** (research/21 §1.12/goose `declarative.rs:396-467`): go-тест — каждый `api_key_env` объявлен у провайдера моделей; reasoning-режим ∈ известного enum; `min_max_tokens` разумен; каждая модель ссылается на объявленного провайдера; цены >0 там, где обязаны. Падает на дрейфе каталога ДО платного прогона.
2. **Quota-429 → terminal** (§1.4): узкий body-маркер (`insufficient_quota`/`quota_exceeded`) + HTTP 402 → терминальная ошибка (не 3 ретрая под USD-резервацией). Тест: обычный 429 остаётся retryable.
3. **`parseRetryAfter`: дробные секунды + `Retry-After-Ms`** (§1.13, `httpllm.go:426`): float-парс + ms-header first. Под существующим 5-мин капом.
4. **HTTP/2 keepalive на общем клиенте** (§1.5, `httpllm.go:161-174`): http2.Transport ReadIdleTimeout/PingTimeout (~15s/5s по образу grok-build). **Гейт внутри пака:** дым-проверка, что фронты наших провайдеров не рвут h2-PING (без платных вызовов — TLS/HEAD-пробы); рвут → h1 для того провайдера, отметить в отчёте.
5. **Пропорциональный джиттер** (§1.18а, `httpllm.go:144`): `rand.Intn(250)ms` → ±25% от backoff. Де-синк N-∥ волн.
6. **xAI reasoning identity-гард** (§1.9, `provider_openai.go:101-102`): additive-фолд только при `total == prompt+completion+reasoning`; иначе считать subset и логировать WARN (кандидат в квирк-реестр). Кап латентного 3044% overcount.
7. **CostSource-маркер** (§1.10): на settle-estimate строках (`stagerun.go:469-473`) — флаг `estimated` в request_log/report (аддитивное поле read-модели, экспорт-контракт №8 не ломать). Estimated-токены display-only, `CostUSD` НЕ трогают. Оценщик — fertility research/20 (1.20·cjk+0.39·other), НЕ char/4 (CJK-мина).
8. **Drift-guard-тесты** (§1.18б): (а) пин полной status→retryable-мапы; (б) finish-классификатор перевести на префикс/substring-матч (композит `content_filter: PROHIBITED_CONTENT` должен классифицироваться) + пин-тест. Незнакомый finish остаётся fail-loud (НЕ litellm-стиль «unknown→stop»).
9. **Кап billed-decode-ре-биллов** (§1.18в): BilledDecodeError ретраится ≤1 раза (не полный MaxAttempts) — платный 2xx-мусор не жжёт бюджет штормом.
10. **Сегмент-луп-гард, observability-only**арх-чтение/crush `loop_detection.go`): нормализованная SHA-сигнатура перевода-сегмента, повтор >N подряд → style-флаг класса наблюдаемости (КАК стиль-гейты: не диспозиция, не wire). Дополняет echoMineViolation по дегенеративной петле (research/15).
## Вендор-сверка (внутри сессии, БЕЗ реализации при неподтверждении)
По правилу 10.07 два кандидата реализуются ТОЛЬКО при подтверждении в офиц. доке: **(а)** GLM finish-словарь `sensitive`/`network_error` — сверить с docs.z.ai (reference finish_reason); подтвердится → добавить в классификатор (`sensitive`→content_filter; `network_error`НЕ маппить в stop, оставить fail-loud) + строка-кандидат в отчёт для 00-provider-quirks; **(б)** kimi reasoning-модели: temperature omit vs force:1 — сверить platform.kimi.ai; подтвердится → capability-твик. Не подтвердится — в отчёт «не подтверждено, не реализовано».
## НЕ делать (явные не-цели)
Рефакторинг транспорта/option-паттерн · стриминг/StreamingLLMClient · assistant-prefill continuation (#17, HIGH-риск детерминизма) · native-Gemini судья (Ф2) · GLM cache_control-маркировка (двигает wire → решение владельца отдельно) · GLM context-overflow гард (ждёт вендор-сверки + estimator-инфры) · дата-фикация каталога провайдеров · `prompt_cache_key` (наши провайдеры не чтут).
## Приёмка (ревью ИСПОЛНЕНИЕМ, мандат 12.07)
`go build/vet/test ./... -race` зелёные · **golden байт-идентичен** (пак wire-нейтрален; сдвиг golden = провал инварианта — стоп, пинг) · новые тесты: №1 валидация, №2 quota-терминал, №3 ms-парс, №6 identity, №8 drift-пины, №9 кап, №10 луп-гард на синтетике · самопроверка: свой код + прогон всех пинов + адверсариальный селф-ревью (author≠reviewer, минимум 3 линзы: детерминизм/деньги/конкурентность). Отчёт — `docs/archive/reports/TRANSPORT_PACK12_REPORT_<дата>.md` (НЕ в backend/), с file:line по каждому пункту. Сессия НЕ коммитит — лендит оркестратор.