Починить релизный гейт: манифест, слепые интеграционные тесты, ожидание envelope - #46
Merged
Merged
Conversation
added 3 commits
September 5, 2026 08:41
…ие envelope
Первый полный прогон гейта на GPU показал три дефекта, каждый из которых делал его
непроходимым независимо от качества модели.
Публикуемый eval_manifest и ожидание quality_gate_failures были двумя рукописными
списками ключей. Они разошлись: отчёт не печатал min_verified, и гейт падал на
сравнении с самим собой раньше, чем успевал посмотреть на результат прогона. Теперь
оба берут evidence_dict целиком, и разойтись им больше негде.
pytest -m integration не собирал ни одного теста и выходил с кодом 5: интеграционных
тестов в наборе не осталось. Возвращены три, и ровно на ту границу, которую скриптовый
backend не видит, — Pydantic-схема, ставшая грамматикой сэмплирования. Все дефекты
структурированного вывода в этом проекте жили именно там.
Планировщик писал в expected для json_envelope исходники Lua ("return 5 * 5") вместо
значения, которым envelope вычисляется (25). Валидация честно сообщала расхождение, а
исправить его было нечем: неверен был план, а не код. Правило и пример добавлены в
инструкцию планировщика; туда же — связь nullable с кейсом, ожидающим null.
Наблюдение валидации теперь несёт expected рядом с actual: без него ни ревизия, ни
человек в трассе не видят, чем ответ разошёлся с планом.
…есте Smoke сравнивал имена заголовков с учётом регистра: `dict(response.headers)` теряет регистронезависимость `email.message.Message`, а uvicorn отдаёт имена в нижнем регистре, поэтому X-Trace-Id не находился никогда. Дефект был не виден, пока проверка не дошла до этой строки — раньше smoke падал раньше, на генерации. Заодно: ContextInspector не принимает профиль позиционным аргументом.
Обоснование планки 5 из 6 было написано до того, как причина шестого отказа стала известна: там сказано, что отказ каждый прогон приходится на разный сценарий и систематического дефекта за ним нет. Это оказалось неверно — отказ на json_envelope был воспроизводимым дефектом планировщика. Формулировка исправлена: запас на одну ошибку не отменяет обязанности искать причину. README: бейджи CI, версий Python и лицензии; в локальном запуске docker-free не хватало pull основной модели — раздел требовал Qwen3.8-27B, а тянул только fallback.
Owner
Author
|
Проверка на GPU (RTX 3090, Ollama 0.33.3, Qwen3.8-27B UD-Q4_K_M), коммит
|
Ev0lv3nta
added a commit
that referenced
this pull request
Sep 5, 2026
…ие envelope (#46) * Починить релизный гейт: манифест, слепые интеграционные тесты, ожидание envelope Первый полный прогон гейта на GPU показал три дефекта, каждый из которых делал его непроходимым независимо от качества модели. Публикуемый eval_manifest и ожидание quality_gate_failures были двумя рукописными списками ключей. Они разошлись: отчёт не печатал min_verified, и гейт падал на сравнении с самим собой раньше, чем успевал посмотреть на результат прогона. Теперь оба берут evidence_dict целиком, и разойтись им больше негде. pytest -m integration не собирал ни одного теста и выходил с кодом 5: интеграционных тестов в наборе не осталось. Возвращены три, и ровно на ту границу, которую скриптовый backend не видит, — Pydantic-схема, ставшая грамматикой сэмплирования. Все дефекты структурированного вывода в этом проекте жили именно там. Планировщик писал в expected для json_envelope исходники Lua ("return 5 * 5") вместо значения, которым envelope вычисляется (25). Валидация честно сообщала расхождение, а исправить его было нечем: неверен был план, а не код. Правило и пример добавлены в инструкцию планировщика; туда же — связь nullable с кейсом, ожидающим null. Наблюдение валидации теперь несёт expected рядом с actual: без него ни ревизия, ни человек в трассе не видят, чем ответ разошёлся с планом. * Починить проверку заголовков в smoke и конструктор в интеграционном тесте Smoke сравнивал имена заголовков с учётом регистра: `dict(response.headers)` теряет регистронезависимость `email.message.Message`, а uvicorn отдаёт имена в нижнем регистре, поэтому X-Trace-Id не находился никогда. Дефект был не виден, пока проверка не дошла до этой строки — раньше smoke падал раньше, на генерации. Заодно: ContextInspector не принимает профиль позиционным аргументом. * Поправить README и обоснование порога живого корпуса Обоснование планки 5 из 6 было написано до того, как причина шестого отказа стала известна: там сказано, что отказ каждый прогон приходится на разный сценарий и систематического дефекта за ним нет. Это оказалось неверно — отказ на json_envelope был воспроизводимым дефектом планировщика. Формулировка исправлена: запас на одну ошибку не отменяет обязанности искать причину. README: бейджи CI, версий Python и лицензии; в локальном запуске docker-free не хватало pull основной модели — раздел требовал Qwen3.8-27B, а тянул только fallback. ---------
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Первый полный прогон релизного гейта на GPU (RTX 3090, Qwen3.8-27B UD-Q4_K_M) закончился
ok: false. Слепой набор при этом не запускался — он заблокирован публичными провалами, так что одноразовый прогон цел.Из семи заявленных провалов три оказались дефектами самого гейта и один — дефектом продукта.
Гейт не мог пройти в принципе
quality_manifest_mismatchпоявлялся на любом прогоне. Публикуемыйeval_manifestи ожиданиеquality_gate_failuresбыли двумя рукописными списками ключей; они разошлись — отчёт не печаталmin_verified. Гейт падал на сравнении с самим собой, не дойдя до оценки результата, а вместе с ним валилсяdoctor --judgeи снимок рантайма. Теперь оба берутevidence_dict()целиком.integration_tests_failedпри коде возврата 5:pytest -m integrationне собирал ни одного теста. Интеграционных тестов в наборе не осталось, а гейт продолжал заявлять, что их запускает.Дефект продукта
Кейс
live_envelope_squared_numberпадал сacceptance_result_mismatch, хотя рантайм возвращал ровно то, что нужно:{"num": 5, "squared": 25}. Расходилось ожидание — планировщик писал вexpectedисходники Lua ({"num": "return 5", "squared": "return 5 * 5"}) вместо значения, которым envelope вычисляется. Валидация сообщала расхождение честно, но исправить его было нечем: неверен был план, а не код, и ревизия кода тут бессильна.Тем же классом ошибки объясняется падение smoke: на запрос «верни nil, если массив пустой» планировщик объявлял
nullable: falseи тут же писал acceptance-кейс сnil.Что сделано
eval_manifestи ожидание гейта берутся из одного источника; расхождение закрыто регрессионным тестом.expectedприjson_envelope, и связьnullableс кейсом, ожидающимnull.expectedрядом сactual: без него ни ревизия, ни человек в трассе не видят, чем ответ разошёлся с планом.Проверка
Локально: 211 тестов,
ruff,ruff format --check,mypy --strict— зелено. На GPU проверяются интеграционные тесты, smoke и полный гейт до мержа.