Материал: Приложение D. Калибровка порогов

Урок 1 из 5 в модуле «Приложение D. Калибровка порогов»
Вы просматриваете урок без входа. Войдите, чтобы сохранять прогресс и проходить тесты.

Приложение D. Калибровка порогов

Это справочное приложение. На первом проходе оно не нужно: учебный минимум каждой главы рассчитан на пороги по умолчанию для AgentClinic-production. Этот файл собирает все таблицы «Низкий / По умолчанию / Высокий», упражнения по сдвигу порогов и сигналы, по которым порог нужно пересматривать. Используйте его при переносе процесса в свой проект, когда стандартные значения перестали подходить.

Принцип, общий для всех таблиц: пороги имеют смысл только в паре. Сдвиг одного значения без пересчёта связанного — это не калибровка, а демонтаж контура. У каждого раздела явно перечислены риски такого сдвига.

D.1 Мутационное тестирование (глава 5)

Числа главы 5 — значение по умолчанию для AgentClinic-production со средним потоком инцидентов и зрелым SDD-процессом. В вашем проекте пороги зависят от цены пропуска P0, сложности графа маршрутов, SLA-окна CI и стабильности входящего потока. Сдвиг любой строки должен сопровождаться записью в validation.md с обоснованием.

Параметр проектаНизкийПо умолчанию (AgentClinic)Высокий

| Цена пропуска P0 | strict_reject_rate ≥ 0.92 | **≥ 0.98** | ≥ 0.995 (платежи, здравоохранение) | | Сложность графа маршрутов | depth_of_diagnostics ≥ 2 (≤10 рёбер) | **≥ 3** (10–50 рёбер) | ≥ 5 (>100 рёбер, multi-tenant) | | SLA-окно CI | recovery_time_p95_ms ≤ 800 | **≤ 1200** | ≤ 1500 (>500 PR/день) | | Стабильность потока инцидентов | 1 мутант на класс | 2 мутанта на класс | 5+ мутантов на класс + ротация зерна |

Упражнение

cd book2/examples/stress-mutator

mkdir -p out
cp expected/expected_failures.json out/expected_failures_depth5.json
sed -i 's/"depth_of_diagnostics_min": 3/"depth_of_diagnostics_min": 5/' out/expected_failures_depth5.json

python3 scripts/immunity_score.py \
  --validator-results out/validator_results.json \
  --expected expected/expected_failures.json \
  --out out/immunity_default.json

python3 scripts/immunity_score.py \
  --validator-results out/validator_results.json \
  --expected out/expected_failures_depth5.json \
  --out out/immunity_depth5.json

Первый запуск должен пройти: средняя глубина диагностики равна 4 и превышает порог 3. Второй запуск должен завершиться кодом 1: тот же валидатор уже не проходит искусственно ужесточённый порог depth_of_diagnostics_min = 5. Дельта показывает не новый дефект в мутантах, а цену ужесточения порога.

Когда пересмотреть порог

  • За квартал ни одно слияние не заблокировано порогом — он избыточно низкий.
  • Больше 10 регрессий с одним и тем же mutation_id за неделю — depth_of_diagnostics недостаточен, увеличить.
  • recovery_time_p95 падает к нулю при росте strict_reject_rate — признак Гудхарта.
  • Появился новый класс инцидентов — пересчитать все три порога заново.
  • Одно зерно (seed) повторяет тот же набор mutation_id пять спринтов подряд — нужна ротация зерна.

Риск: если strict_reject_rate растёт, а depth_of_diagnostics одновременно падает, это симптом Гудхарта. Оба параметра двигают только парой.

D.2 Отбор теневых спецификаций (глава 6)

Веса 0.5*mttr_gain + 0.3*early_signal + 0.2*coverage - 0.4*false_escalation и пороги keep/reject — значения по умолчанию для AgentClinic-production. В вашем проекте они зависят от цены ложной эскалации, важности раннего сигнала, размера исторической базы и доступного бюджета на образцы-подсказки.

ПараметрНизкийПо умолчанию (AgentClinic)Высокий
Цена ложной эскалацииштраф false_escalation: 0.2–0.3**0.4**0.6–0.8 (здравоохранение, платежи)
Важность раннего сигналавес early_signal: 0.2**0.3**0.4–0.5 (радиус последствий >5 сервисов)
Размер исторической базы20–50 кейсов (дымовая проверка)50+ кейсов200+ кейсов с ротацией окон
Бюджет образцов-подсказокkeep-threshold 0.80, 4 слота**0.70, 8 слотов / 2000 токенов**0.60, 12 слотов / 4000 токенов

Упражнение

Прогоните аукцион с консервативным профилем риска (выше штраф за ложную эскалацию):

cd book2/examples/shadow-auction
python3 scripts/score.py --candidates candidates/candidates.yaml --incidents data/incidents.jsonl --weights "0.3,0.4,0.2,0.8" --out out/scorebook.json

python3 scripts/decide.py --scorebook out/scorebook.json --budget-tokens 2000 --keep-threshold 0.70 --reject-threshold 0.40 --out-auction out/auction.json --out-quarantine out/quarantine.json

При таком профиле shadow.p0.voice_handoff переезжает из winner в disputed, а shadow.alert.red_color_urgency остаётся в rejected. Это проявление нового профиля: команда меньше награждает сокращение MTTR и сильнее штрафует ложную эскалацию.

Когда пересмотреть порог

  • За месяц ни один winner не показал положительного эффекта в пост-мортемах — keep-threshold слишком низкий.
  • Доля disputed устойчиво выше 40% — формула не различает кейсы.
  • В одной фазе выбирается больше 8 победителей — budget-tokens подобран без учёта размера QWEN.md.
  • Появился новый класс инцидентов вне исторических данных.
  • mttr_gain и false_escalation растут вместе — симптом Гудхарта.

Риск: штраф false_escalation и вес mttr_gain двигают только парой. Сдвиг одного без пересмотра другого ломает связь «полезный сигнал ↔ ложный шум».

D.3 Ярусные бюджеты (глава 9)

Бюджет 10M токенов с разбиением 9M/1M (local/frontier) — значение по умолчанию для AgentClinic-production со средним потоком инцидентов. В вашем проекте размер бюджета и пропорции зависят от потока инцидентов, средней стоимости фазы, доли спорных ревью и чувствительности к падению local-coder.

Параметр проектаНизкийПо умолчанию (AgentClinic)Высокий
Поток инцидентов в сутки≤50/день → 2–3M токенов, 90/10200/день → 10M, 9M/1M (90/10)≥500/день → 25–40M, 80/20
Стоимость фазы (токенов)~20K~50K100K+ (многошаговый реплей)
Доля спорных ревью≤5% → frontier 5–7%~10% → 1M (10%)15–25% → 15–20% frontier
Чувствительность к падению local-coder≤1 раз/месяц → резерв 5%2–4 раза/месяц → 7%еженедельно → 15% + дублированный провайдер

Упражнение

cd book2/examples/budget-keeper

python3 scripts/compile.py --budget-spec specs/budget_network_5m.yaml --out out/budget_plan_5m.json
python3 scripts/simulate.py --plan out/budget_plan_5m.json --scenario scenarios/fail_local_45m.json --out out/fail_result_5m.json

python3 scripts/inspect.py --result out/fail_result_5m.json --query "failover_to_frontier==2 && degraded_queue==18 && token_health_min>=0.5"

Проверьте, удержался ли token_health_min выше 0.5 при половинном бюджете. В готовом 5M-варианте пропорции сохранены: local-ярус получает 4.5M, frontier — 0.5M. Если изменить только daily_budget_tokens, но не фазовые квоты, compile.py обязан упасть с ошибкой суммы.

Когда пересмотреть порог

  • За месяц ни одного срабатывания degraded_mode — бюджет избыточен либо реальный поток ниже ожидаемого.
  • token_health_min уходит ниже 0.5 чаще раза в неделю — локального яруса недостаточно.
  • failover_to_frontier устойчиво равно 0 при отказах локального яруса — шлюз слишком жёсткий, frontier не работает как страховка.
  • Доля manual_queue после ручного тайм-аута растёт два месяца подряд — manual_timeout_sec слишком короткий.
  • В сутки тратится менее 60% daily_budget_tokens — пора сжимать бюджет.

Риск: разделение 9M/1M связано с SLA по фазам. Сдвигать его без обновления budget_plan_phases в спецификации нельзя — frontier перестанет вмещать «спорные» кейсы.

D.4 Защита метрик от Гудхарта (глава 10)

Пороги silent_p0 ≤ 5%, manual_review_rate ≥ 15%, edge_drift ≤ 0.12, audit_trace_coverage = 1.0 — значения по умолчанию для AgentClinic-production. В вашем проекте они зависят от цены пропущенного P0, доступности ручных рецензентов, динамики входящего потока и регуляторных требований к аудиту.

Параметр проектаНизкийПо умолчанию (AgentClinic)Высокий
Цена пропущенного P0silent_p0 ≤ 8%**≤ 5%**≤ 1–2% (платежи)
Доступность ручных рецензентовmanual_review_rate ≥ 8%**≥ 15%**≥ 25% (регуляторно)
Динамика входаedge_drift ≤ 0.20**≤ 0.12**≤ 0.05 (сезонные пики)
Регуляторика аудитаaudit_trace_coverage ≥ 0.95**= 1.00**= 1.00 + подписанная трассировка

Упражнение

cd book2/examples/goodhart-validator

mkdir -p out

# Скопировать spec в локальный out/ и ослабить silent_p0_cap до 0.08
cp specs/validation.yaml out/validation_loose.yaml
sed -i 's/threshold: 0.05/threshold: 0.08/' out/validation_loose.yaml

python3 scripts/run_validation.py \
  --validation out/validation_loose.yaml \
  --metrics fixtures/new_metrics_bad.json

# Опасный вариант: ослабить сразу две независимые защиты
cp specs/validation.yaml out/validation_unsafe.yaml
sed -i 's/threshold: 0.15/threshold: 0.10/' out/validation_unsafe.yaml
sed -i 's/threshold: 0.05/threshold: 0.20/' out/validation_unsafe.yaml

python3 scripts/run_validation.py \
  --validation out/validation_unsafe.yaml \
  --metrics fixtures/new_metrics_bad.json

Первый прогон должен остаться красным: плохой релиз с silent_p0=0.18 всё ещё нарушает silent_p0_cap. Второй, опасный, вариант проходит только потому, что одновременно ослаблены две независимые защиты. Это показывает, почему guard-метрики нельзя калибровать по одной строке YAML.

Когда пересмотреть порог

  • За квартал ни один релиз не заблокирован silent_p0_cap — либо команда не делает рискованных изменений, либо порог избыточно мягкий.
  • manual_review_rate падает три спринта подряд при росте mttr_gain — симптом Гудхарта, ручные рецензенты перестали быть страховкой.
  • edge_drift стабильно колеблется около 0.10–0.11 — реальная динамика входа близка к порогу.
  • audit_trace_coverage опустился ниже 1.0 хоть в одном прогоне — нарушение регуляторного инварианта, hot-fix, не калибровка.
  • Появился новый класс инцидентов, который не попадает в silent_p0, — нужны новые инварианты, не пересмотр старых.

Риски: silent_p0 и manual_review_rate двигают только парой. edge_drift имеет смысл только при audit_trace_coverage=1.0, иначе дрейф вычисляется по частичной выборке. Все четыре порога образуют единый контракт риска: ослабить один в отрыве от остальных — значит сломать его, а не настроить.

Полная сеть метрик

В тексте главы используется упрощённая mermaid-схема с тремя метриками и одним сторожем. Полная сеть зависимостей выглядит так:

flowchart LR
    MTTR[MTTR]
    silent_p0[silent_p0]
    manual_review_rate[manual_review_rate]
    escalation_rate[escalation_rate]
    postmortem_regression[postmortem_regression]
    audit_trace_coverage[audit_trace_coverage]
    silent_p0 -->|положительная_взаимозависимость| MTTR
    escalation_rate -->|положительная_взаимозависимость| MTTR
    manual_review_rate -->|отрицательная_взаимозависимость| MTTR
    manual_review_rate -->|отрицательная_взаимозависимость| escalation_rate
    audit_trace_coverage -->|отрицательная_взаимозависимость| escalation_rate

audit_trace_coverage -->|отрицательная_взаимозависимость| silent_p0
    postmortem_regression -->|положительная_взаимозависимость| audit_trace_coverage
    postmortem_regression -->|отрицательная_взаимозависимость| manual_review_rate

Логика та же, что в упрощённой версии: красная зона — MTTR и silent_p0; путь к её ослаблению идёт через сокращение ручной проверки и потерю аудит-следа.

D.5 Production-готовность (глава 11)

Порог 23/25 — значение по умолчанию для AgentClinic-production со средней зрелостью SDD-процесса и смешанным типом действий. В вашем проекте порог зависит от цены ошибки переключения (cutover), зрелости процесса, нагрузки на ручное ревью и характера действий (stateless / stateful).

Параметр проектаНизкийПо умолчанию (AgentClinic)Высокий
Цена ошибки переключениявнутренний инструмент: 21–22/25 только полуручносмешанный production: auto ≥23/25платежи/здравоохранение: auto ≥24/25
Зрелость SDD-процесса3 месяца → только полуручной 20–226+ месяцев → полуручной 20–22, auto 23+12+ месяцев + 50+ реплеев → auto 23+, меньше ручных остановок

| Нагрузка ручного ревью | каждый пулл-реквест (~5/неделю) → можно держать 21–22 полуручно | 20–30% пулл-реквестов → auto 23+ | редко → auto 24/25 | | Тип действия | stateless → 22/25 только canary/полуручно, auto 23+ | смешанный → auto 23+ | stateful → auto 24+ и backup_verified |

Упражнение

Скрипт check_readiness.py хардкодит THRESHOLD = 23. Прогоните с другим значением через копию:

cd book2/examples/real-api && mkdir -p out
cp scripts/check_readiness.py out/check_readiness_t22.py
sed -i 's/THRESHOLD = 23/THRESHOLD = 22/' out/check_readiness_t22.py
python3 out/check_readiness_t22.py --readiness fixtures/readiness_block_audit.json

При THRESHOLD = 22 readiness_block_audit.json всё равно блокируется из-за audit_trace_coverage=0.7 < 1.0, хотя сумма 22/25 проходит. Это показывает, что audit_trace_coverage — независимый блокирующий инвариант, а не часть суммы. Упражнение про чувствительность порога, а не рекомендация снижать auto-допуск.

Когда пересмотреть порог

  • За квартал ни одна готовность не заблокирована порогом — он слишком низкий для текущей зрелости команды.
  • Доля полуручных инцидентов растёт три спринта подряд — порог 23/25 не достигается из-за системного пробела в Verification или Process.
  • Появился класс действий с stateful=true — требуйте backup_verified и поднимите порог по этому классу до 24/25.
  • Все провалы готовности в течение месяца идут по одной оси — это пробел в шаблонах SDD; исправлять шаблоны, а не двигать порог.
  • Время сборки артефактов готовности превышает SLA на переключение — пересмотрите, какие баллы можно автоматизировать, а не снижайте порог.

Риск: порог 23/25 несовместим с нулевым баллом по Security при любой сумме — такой провал блокирует слияние независимо от итога. Снижение ниже 23/25 меняет режим эксплуатации: это уже не auto-допуск, а полуручной или canary-режим. Даже «low» (21/25) — это остановка после каждого implement-шага и явное подтверждение оператора, а не право агента выполнить ремедиацию самостоятельно.

Мои заметки
0 / 10000

Заметки сохраняются в этом браузере. На другом устройстве они не появятся.

Меню курса

Курс

Production SDD для Qwen Code CLI. Часть 2
Прогресс 0 / 100