textmachine/docs/archive/prompts/BACKEND_ARCHGUARD_DOFIX_SESSION_PROMPT.md

8.7 KiB
Raw Blame History

Промт бэкенд-сессии: дофикс паритета анализаторов + живая проба провода (строки 121-п.0 · 117; хвост пака стандартов)

ИСПОЛНЕН И ПРИНЯТ (D39.97, 04.08): шесть дыр закрыто (3 промта + 3 сверх, вкл. блокер type-param), 9/9 мутаций, проба PASS 3/3 с прямым клеймом reasoning_content на проводе, $0.0053 из $0.50. Заленден в составе пака стандартов. Отчёт: ../reports/ARCHGUARD_DOFIX_2026-08-03.md. Инструкции отсюда не исполнять.

Мандат: приёмка пака стандартов D39.96 (03.08): пак принят по качеству кода, но пасс-2 приёмки нашёл регрессию egress-паритета против снесённого байт-гарда — снос гардов в текущем виде нарушает условие исходного промта «только после доказанного паритета». Владелец выбрал дофикс ДО лендинга. Твой предшественник сделал качественный пак — ты закрываешь три конкретные дыры, найденные посадками приёмки, и добиваешь единственный неисполненный пункт (живую пробу провода).

Онбординг: CLAUDE.md → docs/README.md → CURRENT-STATE в docs/PROGRESS.md → D39.96 в 05-decisions-log.md (вся фактура приёмки там) → отчёт archive/reports/REPO_STANDARDS_2026-08-03.md (ревью-шапка = сводка находок). Код-факты бери из кода — file:line ниже это отправные точки, код первичен.

§0. Скоуп и правила

  • Зона записи: backend/ ТОЛЬКО. НЕ коммитить — лендит оркестратор. .env НЕ ЧИТАТЬ (для этапа 2 сорсить шеллом — ключи в контекст/отчёт не тащить).
  • Деньги: этап 1 = $0. Этап 2 = живая проба, потолок $0.50 (санкция D39.92 п.2), каждый цент в отчёт.
  • Эхо-протокол: первый деливерабл — ≤10 строк «что понял: скоуп / инварианты / не-делать» ДО работы.
  • Канал вопросов: непонятно / конфликт промта с кодом или доками → пинг оркестратору через владельца, НЕ интерпретация.
  • Дерево содержит незакоммиченный пак стандартов — это ТВОЯ база, поверх неё и работаешь. Чужого в дереве быть не должно, но git status перед началом сверь.

Этап 1 ($0): три дыры анализаторов — фикс + посадки

Все три доказаны исполнением при приёмке (посадки exit=0 там, где обязан быть флаг). Форма фикса — «реши сам»; приоры ниже опровергаются аргументом.

A. egressseam пропускает пакетную функцию llm.Complete(...). archguard.go:240-242: у qualified identifier (функция пакета, не метод) pass.TypesInfo.Selections[sel] = nil → анализатор молча выходит. Пакет internal/llm исключён целиком, так что хелпер func Complete(...) в llm + вызов откуда угодно = второй egress, невидимый ничем. Приор фикса: fallback на pass.TypesInfo.Uses[sel.Sel]*types.Func с Pkg() = llm.

B. egressseam пропускает интерфейс, прячущий llm-типы ВНУТРИ композита. touchesPkg (archguard.go:76-92) разворачивает один уровень указателя и не смотрит внутрь элементов: Complete(ctx context.Context, reqs []llm.LLMRequest) ([]*llm.LLMResponse, error) проходит молча. Приор: рекурсия по Slice/Map/Chan/Array/Signature (+указатель уже есть).

C. requestseam ловит только литералы. runRequestSeam обходит один узел *ast.CompositeLit (archguard.go:197) против четырёх у stage-сеама (:140-165): var r pipeline.Request + пополевое присваивание и new(pipeline.Request) из чужого пакета проходят молча (дыра общая со старым гардом — не регрессия, но и не задокументирована). Приор: симметрия ValueSpec/CallExpr со stage-сеамом.

D. Честные комменты. «that is what cannot be hidden» (archguard.go:250-253) и клейм фикстуры (testdata/.../egresssites/egresssites.go:33) фальсифицированы посадками — переписать по фактическому охвату. Если что-то из AC решишь осознанно НЕ ловить — это легитимно, но пропуск ОБЯЗАН быть назван в doc-комменте пакета и негативной фикстурой (молчащий пропуск = как раз то, что приёмка вскрыла).

E. Посадки. Каждая закрытая форма — кейс analysistest в testdata (формы из A/B/C выше) + негативные контроли (легитимный вызов через шов; Complete чужого пакета с не-llm сигнатурой; var в exempt-местах). Плюс мутационная самопроверка: сломай каждый фикс — соответствующий кейс обязан упасть.

F. Батарея. make battery EXIT=0; четыре поведенческих теста pipeline (BankProbe/ReasoningIsPart/RepairStage/InternalCallDecidesEveryStageField) живы.

Этап 2: живая проба провода (строка 117 — гейт платных прогонов)

ГЕЙТ: слово владельца по бампу @latest (D39.96 п.6-iii) — спроси ДО этапа 2, если он не передал с промтом.

  • Confirm @latest → проба на текущем дереве.
  • Deny → сначала минимальный пере-бамп (приор, доказан ревьюером исходного пака; опровергается замером): go get golang.org/x/tools@v0.45.0 (тянет x/net v0.54.0, x/text НЕ двигается) + откат modernc.org/sqlite на v1.53.0 + откат x/text-пинов (norm.go:69 → v0.38.0, зеркала enclosure_test.go и memory_f1_test.go) + голден обязан пройти БЕЗ пере-захвата (вернётся к HEAD-версии). Затем проба.

Команда (ключи грузит шелл; вывод фильтруй от ключей):

cd backend && set -a && . ./.env && set +a && TM_LIVE=1 go test -tags live -run TestLiveAdapterConformance -v ./internal/pipeline/

Кроет deepseek/zai/kimi (grok закомментирован — clean-prod гигиена, НЕ включать). Сверять против docs/experiments/00-provider-quirks.md: finish=stop · reasoning_content непустой где ожидается · нет новых отказов/фреймингов. Контекст риска: после бампа x/net у клиента новый SETTINGS_MAX_FRAME_SIZE=16384 (семантически инертен, но меняет h2-фингерпринт для WAF). Любое расхождение = СТОП-пинг с сырьём, откатов без слова владельца не делать.

Отчёт

docs/archive/reports/ARCHGUARD_DOFIX_<дата>.md, компактный: эхо-шапка · дифф этапа 1 с таблицей «форма × ловится» · итог мутационной самопроверки · результат пробы по провайдерам (finish/usage/цена; тел с ключами НЕ вставлять) · найдено-не-починено. Каждое число — с командой. СТОП — приёмка оркестратора.