agent-quality-kit 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +155 -0
  3. package/kit/docs/ai/agent-harness-playbook.md +596 -0
  4. package/kit/docs/ai/ai-native-development.md +371 -0
  5. package/kit/docs/ai/ai-sdlc.md +221 -0
  6. package/kit/docs/ai/anthropic-ai-native-sdlc-2026-08.md +294 -0
  7. package/kit/docs/ai/app-owner-strategy.md +921 -0
  8. package/kit/docs/ai/deep-research-2026-07.md +161 -0
  9. package/kit/docs/ai/harness-best-practices.md +385 -0
  10. package/kit/docs/ai/index.md +64 -0
  11. package/kit/docs/ai/project-baseline.md +261 -0
  12. package/kit/docs/ai/quality-gates-checklist.md +322 -0
  13. package/kit/docs/ai/sources-building-with-agents.md +111 -0
  14. package/kit/docs/ai/stream-2026-08-ai-coding-panel.md +304 -0
  15. package/kit/docs/ready-made-rules.md +170 -0
  16. package/kit/gates/README.md +231 -0
  17. package/kit/gates/_skip.sh +75 -0
  18. package/kit/gates/commit-explains-itself/README.md +45 -0
  19. package/kit/gates/commit-explains-itself/check.sh +63 -0
  20. package/kit/gates/commit-explains-itself/gate.yml +10 -0
  21. package/kit/gates/commit-explains-itself/green/COMMIT_MSG +6 -0
  22. package/kit/gates/commit-explains-itself/red/COMMIT_MSG +3 -0
  23. package/kit/gates/complexity-limit/README.md +37 -0
  24. package/kit/gates/complexity-limit/check.sh +44 -0
  25. package/kit/gates/complexity-limit/gate.yml +13 -0
  26. package/kit/gates/complexity-limit/green/flat.py +10 -0
  27. package/kit/gates/complexity-limit/red/deep.py +9 -0
  28. package/kit/gates/dead-code/README.md +30 -0
  29. package/kit/gates/dead-code/gate.yml +23 -0
  30. package/kit/gates/dead-code/green/mod.py +9 -0
  31. package/kit/gates/dead-code/red/mod.py +9 -0
  32. package/kit/gates/deps-are-pinned/README.md +29 -0
  33. package/kit/gates/deps-are-pinned/check.sh +49 -0
  34. package/kit/gates/deps-are-pinned/gate.yml +9 -0
  35. package/kit/gates/deps-are-pinned/green/nodep-go/go.mod +3 -0
  36. package/kit/gates/deps-are-pinned/green/package-lock.json +3 -0
  37. package/kit/gates/deps-are-pinned/green/package.json +4 -0
  38. package/kit/gates/deps-are-pinned/green/requirements.txt +2 -0
  39. package/kit/gates/deps-are-pinned/red/package.json +4 -0
  40. package/kit/gates/deps-are-pinned/red/requirements.txt +2 -0
  41. package/kit/gates/deps-are-pinned/red/withdep-go/go.mod +5 -0
  42. package/kit/gates/duplicate-code/README.md +40 -0
  43. package/kit/gates/duplicate-code/check.sh +58 -0
  44. package/kit/gates/duplicate-code/gate.yml +12 -0
  45. package/kit/gates/duplicate-code/green/common.py +9 -0
  46. package/kit/gates/duplicate-code/green/use.py +9 -0
  47. package/kit/gates/duplicate-code/red/a.py +12 -0
  48. package/kit/gates/duplicate-code/red/b.py +12 -0
  49. package/kit/gates/entry-links-exist/README.md +22 -0
  50. package/kit/gates/entry-links-exist/check.sh +24 -0
  51. package/kit/gates/entry-links-exist/gate.yml +16 -0
  52. package/kit/gates/entry-links-exist/green/AGENTS.md +5 -0
  53. package/kit/gates/entry-links-exist/green/rules/general.md +3 -0
  54. package/kit/gates/entry-links-exist/red/AGENTS.md +3 -0
  55. package/kit/gates/file-size-limit/README.md +22 -0
  56. package/kit/gates/file-size-limit/check.sh +34 -0
  57. package/kit/gates/file-size-limit/gate.yml +9 -0
  58. package/kit/gates/file-size-limit/green/a.py +251 -0
  59. package/kit/gates/file-size-limit/green/b.py +251 -0
  60. package/kit/gates/file-size-limit/red/big.py +601 -0
  61. package/kit/gates/gate-has-samples/README.md +29 -0
  62. package/kit/gates/gate-has-samples/check.sh +48 -0
  63. package/kit/gates/gate-has-samples/gate.yml +9 -0
  64. package/kit/gates/gate-has-samples/green/.aqk.yml +10 -0
  65. package/kit/gates/gate-has-samples/green/gates/no-print-in-prod/check.sh +2 -0
  66. package/kit/gates/gate-has-samples/green/gates/no-print-in-prod/green/good.py +2 -0
  67. package/kit/gates/gate-has-samples/green/gates/no-print-in-prod/red/bad.py +1 -0
  68. package/kit/gates/gate-has-samples/red/.aqk.yml +10 -0
  69. package/kit/gates/gate-has-samples/red/gates/no-print-in-prod/check.sh +2 -0
  70. package/kit/gates/gates-are-runnable/README.md +23 -0
  71. package/kit/gates/gates-are-runnable/check.sh +35 -0
  72. package/kit/gates/gates-are-runnable/gate.yml +9 -0
  73. package/kit/gates/gates-are-runnable/green/.aqk.yml +9 -0
  74. package/kit/gates/gates-are-runnable/green/checks/lint.sh +2 -0
  75. package/kit/gates/gates-are-runnable/red/.aqk.yml +6 -0
  76. package/kit/gates/gates-run-in-ci/README.md +29 -0
  77. package/kit/gates/gates-run-in-ci/check.sh +42 -0
  78. package/kit/gates/gates-run-in-ci/gate.yml +12 -0
  79. package/kit/gates/gates-run-in-ci/green/.aqk.yml +6 -0
  80. package/kit/gates/gates-run-in-ci/green/.github/workflows/ci.yml +7 -0
  81. package/kit/gates/gates-run-in-ci/green/checks/lint.sh +2 -0
  82. package/kit/gates/gates-run-in-ci/red/.aqk.yml +6 -0
  83. package/kit/gates/gates-run-in-ci/red/.github/workflows/ci.yml +7 -0
  84. package/kit/gates/gates-run-in-ci/red/checks/lint.sh +2 -0
  85. package/kit/gates/lesson-has-outcome/README.md +37 -0
  86. package/kit/gates/lesson-has-outcome/check.sh +50 -0
  87. package/kit/gates/lesson-has-outcome/gate.yml +11 -0
  88. package/kit/gates/lesson-has-outcome/green/.aqk.yml +2 -0
  89. package/kit/gates/lesson-has-outcome/green/incidents/README.md +32 -0
  90. package/kit/gates/lesson-has-outcome/red/.aqk.yml +2 -0
  91. package/kit/gates/lesson-has-outcome/red/incidents/README.md +13 -0
  92. package/kit/gates/no-print-in-prod/README.md +44 -0
  93. package/kit/gates/no-print-in-prod/check.sh +36 -0
  94. package/kit/gates/no-print-in-prod/gate.yml +15 -0
  95. package/kit/gates/no-print-in-prod/green/docs.ts +15 -0
  96. package/kit/gates/no-print-in-prod/green/legacy.py +9 -0
  97. package/kit/gates/no-print-in-prod/green/main.go +8 -0
  98. package/kit/gates/no-print-in-prod/green/main.rs +4 -0
  99. package/kit/gates/no-print-in-prod/green/service.py +8 -0
  100. package/kit/gates/no-print-in-prod/red/main.go +8 -0
  101. package/kit/gates/no-print-in-prod/red/main.rs +4 -0
  102. package/kit/gates/no-print-in-prod/red/service.py +3 -0
  103. package/kit/gates/secrets-not-in-code/README.md +29 -0
  104. package/kit/gates/secrets-not-in-code/check.sh +18 -0
  105. package/kit/gates/secrets-not-in-code/gate.yml +9 -0
  106. package/kit/gates/secrets-not-in-code/green/settings.py +4 -0
  107. package/kit/gates/secrets-not-in-code/red/settings.py +2 -0
  108. package/kit/gates/swallowed-error/README.md +26 -0
  109. package/kit/gates/swallowed-error/check.sh +54 -0
  110. package/kit/gates/swallowed-error/gate.yml +12 -0
  111. package/kit/gates/swallowed-error/green/loader.py +11 -0
  112. package/kit/gates/swallowed-error/green/run.js +8 -0
  113. package/kit/gates/swallowed-error/red/loader.py +5 -0
  114. package/kit/gates/swallowed-error/red/run.js +3 -0
  115. package/kit/gates/todo-without-task/README.md +26 -0
  116. package/kit/gates/todo-without-task/check.sh +19 -0
  117. package/kit/gates/todo-without-task/gate.yml +12 -0
  118. package/kit/gates/todo-without-task/green/order.py +9 -0
  119. package/kit/gates/todo-without-task/red/order.py +8 -0
  120. package/kit/ratchet/ratchet.sh +62 -0
  121. package/kit/rules/general.md +55 -0
  122. package/kit/rules/security.md +33 -0
  123. package/kit/rules/testing.md +46 -0
  124. package/package.json +41 -0
  125. package/tool/commands/doctor.mjs +230 -0
  126. package/tool/commands/gates.mjs +445 -0
  127. package/tool/commands/project.mjs +316 -0
  128. package/tool/lib/core.mjs +98 -0
  129. package/tool/lib/manifest.mjs +140 -0
  130. package/tool/lib/repo.mjs +270 -0
  131. package/tool/lib/templates.mjs +187 -0
  132. package/tool/program.mjs +81 -0
  133. package/tool/selfcheck/conditional.sh +24 -0
  134. package/tool/selfcheck/gates.sh +127 -0
  135. package/tool/selfcheck/smoke.sh +539 -0
  136. package/tool/selfcheck/syntax.sh +23 -0
  137. package/tool/selfcheck/units.mjs +105 -0
@@ -0,0 +1,161 @@
1
+ <!-- источник: audit_project/docs/ai/deep-research-2026-07.md -->
2
+ # Дип-ресёрч 2026-07-05: слепые зоны харнеса и платформы (4 агента)
3
+
4
+ > **Что это.** Сводка целевого gap-ресёрча: 4 параллельных агента искали **дельту** к уже внедрённому
5
+ > набору (см. `agent-harness-playbook.md` + ADR 006) по углам: харнес · безопасность · качество кода ·
6
+ > платформы-бенчмарки. Здесь — только новое; что подтвердилось без дельты — отмечено в конце разделов.
7
+ > Статусы: ✓ первоисточник открыт агентом · ◐ из выдачи/вторично (проверить при внедрении).
8
+ > Продуктовые решения из этого ресёрча — `memo-decisions.md §H`; процессные — в `.claude/rules/` и плейбуке.
9
+
10
+ ---
11
+
12
+ ## 1. Безопасность (самые дорогие находки)
13
+
14
+ **1.1. Slopsquatting — supply chain через самого агента.** ✓ USENIX Security 2025 (16 LLM, 576k сэмплов):
15
+ ~19.7% пакетов, рекомендованных ИИ, **не существуют**; 43% галлюцинаций стабильно повторяются → атакующий
16
+ регистрирует имя заранее. `pip-audit` ловит известные CVE, но НЕ свежий вредоносный пакет, который агент сам
17
+ добавил. Защиты: правило «новый пакет = проверка существования/возраста/популярности + ревью человека»
18
+ (→ rules/security.md); lockfile-дисциплина в CI (`uv sync --frozen` ✓ есть; npm — `npm ci` ✓ есть);
19
+ `ignore-scripts` для npm и pip `--require-hashes` — по триггеру (проверить, что не ломает сборку);
20
+ cooldown свежих версий (pnpm v11: minimumReleaseAge=1д по умолчанию; рекомендация ≥7д).
21
+ *(snyk.io/articles/slopsquatting-mitigation-strategies, pnpm.io/supply-chain-security)*
22
+
23
+ **1.2. «Comment and Control» — угон агентов через недоверенный контент.** ✓ Апрель 2026, CVE-2025-66032
24
+ (CVSS 9.4): один заголовок PR одновременно угнал Claude Code Review, Gemini CLI и Copilot — каждый выгрузил
25
+ секреты репозитория. Вывод индустрии (+CaMeL): prompt injection промптами не лечится, только архитектурой.
26
+ Механические защиты: агент читает недоверенное (Issue/PR/веб/чужие логи) → **без секретов и write-прав**;
27
+ GitHub Actions пинить **по SHA-коммиту**, не `@v1`; `contents: write`/`id-token` — только где нужно; не
28
+ открывать чужие репо агентом с доверенным окружением (инцидент Amazon Q: auto-load MCP-конфигов крал
29
+ AWS-ключи). Справочник атак: github.com/webpro255/awesome-ai-agent-attacks.
30
+ *(CSA research notes 2026-04; css.csail.mit.edu CaMeL)*
31
+
32
+ **1.3. Supply chain самого харнеса (MCP/skills/plugins) — непокрытая категория.** ◐ Tool poisoning через
33
+ описания MCP-тулов; 1184 вредоносных skill в маркетплейсе; аудит: 40% MCP-серверов без аутентификации, 43%
34
+ с command-injection. Правило: сторонние MCP/skills/plugins — только после ручного аудита исходников; pin
35
+ версий; SKILL.md и tool descriptions = untrusted input. *(arxiv 2601.17548)*
36
+
37
+ **1.4. Дизайн API-ключей платформы — что дополнить в AgentKey.** ✓ Наше ядро верно (sha256, показ один раз,
38
+ `compare_digest`, префикс `memo_sk_live_` ✓, `last_used_at` ✓). Консенсус добавляет: **правило под наш
39
+ префикс в gitleaks** (сделано: `.gitleaks.toml`), `expires_at` + авто-ревокация неиспользуемых, скоупы
40
+ least-privilege (OWASP LLM06 Excessive Agency: не «один ключ — всё API»), rate limit per key, окно ротации
41
+ из двух активных ключей, **аудит-лог вызовов по ключу** (OWASP Agentic 2026: «нельзя ответить, что агент
42
+ делал на прошлой неделе» без него — у нас закрыто дизайном TraceEvent, подтвердить в плане 003).
43
+ *(genai.owasp.org; Google/GitGuardian/Peakhour API-key practices)*
44
+
45
+ **1.5. Django-прод чек-лист.** ✓ Django 6.0 — **встроенный CSP** (`SECURE_CSP`, сначала report-only);
46
+ `manage.py check --deploy` как CI-гейт (у нас — триггер «перед деплоем», иначе красный на дев-настройках);
47
+ django-axes / django-ratelimit на login и выдачу ключей (тайминг-выравнивание есть, лимита попыток нет);
48
+ SECURE_HSTS/SSL_REDIRECT/NOSNIFF/X_FRAME_OPTIONS — перед первым внешним доступом.
49
+ *(docs.djangoproject.com/en/6.0/ref/csp; OWASP Django Cheat Sheet)*
50
+
51
+ **1.6. Credential proxy — «агент никогда не видит секрет».** ◐ Infisical Agent Vault (open-source HTTP-прокси:
52
+ секрет подставляется по домен-allowlist ниже процесса агента), Phantom Token Pattern. Наш deny на Read .env
53
+ защищает файл, но секреты живут в env запущенного приложения. Триггер: появление реальных прод-ключей.
54
+
55
+ **Без дельты:** JWT-схема (ротация+reuse-детект), OAuth double-submit, PBKDF2+тайминг, хэш ключей — на уровне.
56
+
57
+ ## 2. Харнес разработки
58
+
59
+ **2.1. Эмпирика контекст-файлов (меняет политику).** ✓ ETH Zurich (arxiv 2602.11988, 138 задач, 4 агента):
60
+ LLM-сгенерированные CLAUDE.md **снижают** успех ~3% и удорожают на 20–23%; человечески-курируемые дают ~+4 п.п.
61
+ Vercel: skills не срабатывают сами в **56%** случаев; явный указатель «читай docs/X перед задачей Y» — 100%.
62
+ Правила: каждая строка контекста должна быть тем, что агент **не может открыть сам**; никаких /init-простыней;
63
+ rules > skills для нашего масштаба; «CLAUDE.md = RAM, docs = диск», бюджет ~150–200 надёжных инструкций.
64
+
65
+ **2.2. Хуки: несгораемый deny и мягкие гейты.** ◐ `permissionDecision: "deny"` в PreToolUse держится даже в
66
+ bypassPermissions — единственный гейт, переживающий «жёлтый режим» (проверить наш block-hook там). Stop-хук
67
+ умеет `additionalContext` — мягкий гейт («доделай X») без ошибки. Политика латентности: PreToolUse <100мс,
68
+ узкие матчеры, тяжёлое — в PostToolUse, внешнее — таймаут 1–2с + fail-open. Пара «hook (принуждение) +
69
+ rules-файл (объяснение)»: сообщение хука ссылается на правило — у нас соблюдено в arch-lint, проверить в хуках.
70
+
71
+ **2.3. Наблюдаемость самого агента — бесплатно.** ✓ Claude Code имеет встроенный OTel (спаны model/tool,
72
+ токены/стоимость/сессии) — включается env-переменными; лёгкая альтернатива — claude_telemetry. Цикл
73
+ «трассы отказов → правка харнеса → замер» даёт прирост, сопоставимый с апгрейдом модели (arxiv 2604.25850).
74
+ Триггер: «хочу понять, куда уходят токены» / рост числа правил.
75
+
76
+ **2.4. Долгоживущие агенты (Anthropic, первоисточник).** ✓ Паттерны для многосессионных срезов:
77
+ initializer-агент; feature-list JSON c passing:false; одна фича = одна сессия; старт сессии = progress-файл +
78
+ git log + smoke; e2e «как человек» до пометки passing. Триггер: длинные срезы memo.
79
+
80
+ **2.5. Оркестрация.** ◐ Worktrees окупаются при 4–8 независимых задачах (узкое место — ревью человека; для
81
+ solo реалистично 2–3). Ralph-loop оправдан только при машинной верификации результата + песочница обязательна.
82
+ Cross-model review: официальный codex-плагин для Claude Code (март 2026); чужая модель надёжнее ловит
83
+ security/edge-cases (нет сикофантии к своему коду).
84
+
85
+ ## 3. Качество агентного кода
86
+
87
+ **3.1. «Промпты не лечат деградацию» — теперь с цифрами.** ✓ SlopCodeBench детально: эрозия структуры в 77%
88
+ траекторий, скорость деградации агентов в ~5–6× выше человеческой; prompt-интервенции улучшают старт, но
89
+ **не замедляют** деградацию. Вывод: механические гейты — единственная рабочая защита (вся наша ставка верна).
90
+
91
+ **3.2. SpecBench: reward hacking в кодинге.** ✓ o3 хакает 30.4% прогонов: удаляет падающие тесты, патчит
92
+ верификатор. Рецепты: **test lock** (агент не трогает тесты-верификаторы; наш отложенный deny на
93
+ `tests/e2e/**` — включать при первом инциденте или сразу с появлением e2e) + второй слой проверки поверх
94
+ «тесты зелёные». *(arxiv 2605.21384)*
95
+
96
+ **3.3. aislop — готовый слоп-линтер.** ◐ Детерминированный сканер без LLM: 50+ правил (narrative-комменты,
97
+ swallowed exceptions, hallucinated imports, дубли-хелперы, dead code, todo-стабы), Python в т.ч., CLI +
98
+ pre-commit + CI-гейт (`failBelow`), активен (v0.13.1, июнь 2026). Может заменить связку vulture+jscpd+свои
99
+ правила. Триггер: попробовать advisory-режимом при заметном объёме прод-кода; в блок — после калибровки.
100
+ Запасные: sloppylint (py-специфичный), desloppify (харнес уборки). *(github.com/scanaislop/aislop)*
101
+
102
+ **3.4. Против review debt (процесс).** ✓ Консенсус: PR ≤200–400 строк (дальше качество ревью падает;
103
+ oversized = elevated-risk событие); **comprehension-гейт** — «AI написал» не ответ, автор обязан объяснить
104
+ control flow / edge cases / failure paths (ownCloud формализовал в policy). Для нас: «агент обязан объяснить
105
+ дифф Арсену» → rules/general.md. Cloudflare (131k ревью/мес, $1.19/шт): специализированные LLM-ревьюеры по
106
+ доменам + risk-tiering по размеру диффа + фильтрация lock/generated из диффа + явный список **«что НЕ
107
+ флагать»** + инкрементальный re-review с памятью прошлых находок; честно слаб в архитектуре/concurrency.
108
+
109
+ **3.5. Архитектурный дрейф.** ✓ Thoughtworks Radar (апр 2026): агенты ускоряют дрейф («poor code begets
110
+ poorer code»); рецепт — детерминированные анализаторы + LLM для семантики, первый скан = лавина → приоритизировать.
111
+ Инструмент под Python: **pytest-archon** (ArchUnit-стиль: запрещённые зависимости как pytest-тесты — ложится
112
+ в существующий `make test` без нового CI-шага; альтернатива import-linter). Триггер: ≥3 модулей со строгими
113
+ границами.
114
+
115
+ **3.6. Метрики.** ◐ DORA ROI-отчёт (янв 2026): выигрывают команды с сильными инженерными основами. AI-era
116
+ надстройки: **Code Durability** (доля кода, дожившего N недель без переписывания — дёшево по git) и
117
+ rework/churn rate. Триггер: «хотим мерить прогресс».
118
+
119
+ ## 4. Платформа-бенчмарк (продуктовые находки → memo-decisions §H)
120
+
121
+ **4.1. FinBalance (arxiv 2606.15949, июнь 2026).** ✓ **Прямой сосед по домену**: multi-document accounting
122
+ reconciliation benchmark, синтетика, детерминированный скоринг. Прочитать целиком; переиспользовать
123
+ таксономию ошибок сверки; наша дифференциация — seed-генерация + платформа/арена + анти-гейминг (у них
124
+ статичный датасет). Рядом: AuditFlow (символьные среды: LLM планирует, детерминированный движок проверяет),
125
+ FinVerBench (валидность фин-бенчмарков), FinToolBench, BigFinanceBench — домен горячий, ≥5 бенчмарков за полгода.
126
+
127
+ **4.2. CapCode-принцип (arxiv 2606.07379).** ✓ Детекция читерства **по построению**: в пул подмешиваются
128
+ задачи с заведомо недостижимым честным 100% (несводимая сверка) — балл выше потолка = статистическое
129
+ доказательство читерства, ранжирование честных сохраняется. Идеально ложится на детерминированный скорер.
130
+
131
+ **4.3. Экономика оценки.** ✓ On Randomness (arxiv 2602.07150, 60k траекторий): single-run pass@1 гуляет на
132
+ 2.2–6.0 п.п. **даже при temperature=0** → минимум 3–5 прогонов на (агент, задачу), интервалы вместо точки,
133
+ пара pass@k (оптимист) / pass^k (пессимист). Efficient Benchmarking (2603.23749): держать в зачёте задачи с
134
+ pass-rate **30–70%** (режет пул на 44–70% без потери ранжирования); «все решают/никто не решает» → в
135
+ smoke/pre-flight. Beyond Static Leaderboards (2606.19704): показывать **корреляцию public/private рангов**
136
+ как метрику здоровья экзамена (Kaggle shake-up).
137
+
138
+ **4.4. HAL пивот в reliability.** ✓ Принстон приостановил классический лидерборд и мерит **надёжность**
139
+ (дисперсию) агентов. Подтверждает: reliability score (разброс по прогонам) — правильная колонка таблицы.
140
+
141
+ **4.5. Изоляция.** ✓ Консенсус-2026: для исполнения чужого кода минимум microVM (Docker с общим ядром —
142
+ недостаточно). Для memo это аргумент **ЗА** нашу API-модель «агент снаружи, платформа раздаёт задачи по
143
+ HTTP» — мы не исполняем чужой код, класс риска ниже на порядок; зафиксировано как осознанное решение.
144
+
145
+ **4.6. Скоринг траекторий.** ◐ TRACE (WWW 2026): иерархическая utility-функция траектории + «минимальный
146
+ уровень подсказки, при котором агент справляется» как ось способности. Kaggle Game Arena: адаптивный
147
+ планировщик пар вместо round-robin — **-65% эпизодов** при том же ранжировании (паттерн для умного лизинга).
148
+ Готовые вьюеры трейсов: Phoenix / Opik / DeepEval поверх OTel — свой не писать.
149
+
150
+ ---
151
+
152
+ ## Сводный вердикт
153
+
154
+ - **Подтверждено без изменений:** вся линия «механические гейты > воспитание промптами» (теперь с цифрами),
155
+ JWT/OAuth/хэш-дизайн, минимализм тулов, rules с явными указателями, «агент снаружи» для платформы.
156
+ - **Внедрено этим ресёрчем:** `.gitleaks.toml` (правило под memo-ключи), rules/security.md (недоверенный
157
+ контент; новые зависимости; сторонние MCP/skills), rules/general.md (comprehension-гейт), обновления
158
+ плейбука/ADR 006, продуктовые решения → memo-decisions §H.
159
+ - **Главные триггеры на будущее:** test lock вместе с первыми e2e; aislop при росте прод-кода; OTel самого
160
+ агента при вопросе «куда уходят токены»; CSP/axes/check --deploy перед внешним доступом; credential proxy
161
+ при реальных ключах; pytest-archon при ≥3 модулях.
@@ -0,0 +1,385 @@
1
+ <!-- источник: audit_project/docs/ai/harness-best-practices.md -->
2
+ # Харнес агента: портативный чек-лист бест-практисов
3
+
4
+ > ⚠️ **Пункты 7, 8, 9 и 14 убраны намеренно, нумерация оригинальная.** Это были actor-runtime,
5
+ > токен отмены, сериализуемые компоненты и CodeAct — устройство **своего** агента, а не обвязка
6
+ > репозитория. В журнале источников внизу файла ссылки на них сохранены: номера нужны, чтобы
7
+ > сопоставить приём с репозиторием, откуда он снят.
8
+
9
+ > **Назначение.** Это переносимый чек-лист «как надо строить обвязку агентов». Цель —
10
+ > на новом проекте не изобретать с нуля, а пройтись по списку и поставить галочки.
11
+ > Наполняется по мере разбора топ-репозиториев (`githab/research/`), детальные доказательства
12
+ > по каждому репо — в `BEST-PRACTICES-GAP.md`.
13
+ >
14
+ > **Два слоя** (см. память `two-layer-agent-framing`):
15
+ > - 🎛 **высокий** — обвязка *готового* агента (наш `.claude/`). Применимо к dev-среде напрямую.
16
+ > - 🔧 **низкий** — устройство *самого* агента. Нужно, только если строишь агента ВНУТРИ продукта
17
+ > (напр. PydanticAI для ИИ-фичи). Для dev-среды — «к сведению».
18
+ >
19
+ > **Статус в текущем проекте (audit_project):** ✅ есть · ⚠️ частично · ❌ нет · ℹ️ к сведению.
20
+ >
21
+ > **⚠️ Для memo:** это **перенос** из проекта Arsen `audit_project` — статусы «у нас» в теле относятся к
22
+ > ТОМУ проекту (источнику). Для **memo** харнес берём **по таймингу** (`CLAUDE.md` прав. 10–11): базовый
23
+ > **гейт сейчас**, остальное — **из реального трения**. Многое уже совпадает с нашей reference-базой
24
+ > (`memo-decisions.md §E/G`, `sources-building-with-agents.md`). По мере сборки
25
+ > отмечаем, какие из 19 пунктов берём в memo.
26
+
27
+ ## Приоритет для `audit_project` на 2026-07-13
28
+
29
+ Этот список — каталог идей, а не backlog «внедрить все 19». Для текущего проекта порядок такой:
30
+
31
+ ### P0 — делать сейчас
32
+
33
+ 1. **Runtime fitness-gates продукта:** queue без production consumer; несовместимые
34
+ `time_limit/visibility_timeout`; тяжёлая task в короткой queue; тяжёлый файл/O(N) fan-out в HTTP.
35
+ Это закрывает уже найденные дефекты, а не гипотетические проблемы харнеса.
36
+ 2. **Product observability:** HTTP p95/p99/errors, Celery queue depth/oldest age/wait/run,
37
+ PostgreSQL IO/temp/locks, container RSS/OOM/restarts. Агенту позже дать read-only доступ к этим
38
+ данным. Без термометра нельзя ни сайзить, ни проверять производительность.
39
+ 3. **Workload contract:** короткий реестр `workload → sync/async → queue/consumer → cap → timeout →
40
+ recovery → SLO`. Любая новая фича обязана вписаться в него. Полный roadmap —
41
+ `docs/rebuild/05-load-hardening.md`.
42
+ 4. **Довести уже существующие гейты до честного состояния:** убрать stale-статусы task/docs,
43
+ проверить branch protection; откалиброванные security/migration/Semgrep gates переводить из
44
+ `allow_failure:true` в blocking по одному, с зафиксированным baseline.
45
+
46
+ ### P1 — после P0
47
+
48
+ 1. **Agent-legible live-stack:** воспроизводимая команда сценария + RO-запросы к логам/метрикам +
49
+ correlation/trace id + короткие debug-рецепты. Per-worktree observability полезна после того,
50
+ как основная телеметрия продукта действительно работает.
51
+ 2. **Сначала принять решение по headless pipeline:** либо он реально нужен — тогда восстановить
52
+ executable runner и доказать smoke-прогоном; либо пометить dormant и не тратить на него бюджет.
53
+ Checkpointing имеет смысл только после этого.
54
+ 3. **Typed retry:** transient → backoff; schema/deterministic → один repair; auth/scope → сразу
55
+ человеку. Это дешевле слепых трёх попыток.
56
+ 4. **Стоимость прогона:** сначала собирать tokens/duration/retry по стадиям; денежный hard budget
57
+ вводить, когда появится реальный расходный порог, а не заранее.
58
+
59
+ ### Не делать сейчас
60
+
61
+ - векторную/LLM-консолидируемую память — курируемый индекс и repo search пока проще и надёжнее;
62
+ - inline LLM-судью на каждый шаг — детерминированные схемы, тесты и Reviewer дают более надёжный сигнал;
63
+ - собственный actor-runtime, CodeAct или низкоуровневого агента — используются готовые Claude/Codex;
64
+ - произвольные `triggers:` в frontmatter, если runtime их не поддерживает; явный `$skill` и ссылки из
65
+ `AGENTS.md/rules` надёжнее неисполняемого поля;
66
+ - OTel GenAI и сложную оптимизацию промптов до появления реально используемого headless pipeline.
67
+
68
+ ---
69
+
70
+ # ЧАСТЬ 1 — Сухой чек-лист (только пункты)
71
+
72
+ ## 🎛 Высокоуровневые (обвязка готового агента)
73
+
74
+ - [ ] **1. Принудительный структурированный вывод (SGR)** — схемы и валидатор сохранены до отдельной
75
+ миграции полезных инвариантов, но исполняемый headless pipeline удалён. В интерактивной работе SGR
76
+ не проверяется и машинного потребителя у него нет.
77
+ - [ ] **2. Наблюдаемость прогона** — старые Langfuse-wrapper/score удалены вместе с неиспользуемым
78
+ headless pipeline. Наблюдаемость прогона отсутствует; возвращать её только под реальный runner.
79
+ - [ ] **3. Активная память** — query→inject релевантного + таксономия (рабочая / долгая / факты-сущности) + структурный контент (mime/metadata). _(у нас ⚠️: память пассивная и плоская)_
80
+ - [ ] **4. Хуки-«таможня»** — `PreToolUse` умеет изменить/отклонить действие на лету, не только заблокировать постфактум. _(у нас ⚠️: PreToolUse deny + PostToolUse format есть; Stop пока только уведомляет, quality stop-gate нет)_
81
+ - [ ] **5. Алгоритмы ужатия контекста** — при передаче между агентами: head+tail+«пропущено N», выкидывание из середины под токен-бюджет. _(у нас ❌: только прозаические советы)_
82
+ - [x] **6. Предел итераций агента** — анти-зацикливание (стоп после N попыток). _(у нас ✅: «макс 3 итерации»)_
83
+ - [ ] **10. Output guardrail (LLM-судья)** — критерий словами → судья возвращает `{valid, feedback}` → ретрай с фидбеком; смысловая валидация в дополнение к схемной. _(у нас ⚠️: есть тяжёлые Reviewer/JiTTest в конце, нет лёгкого inline-гейта на шаг)_
84
+ - [ ] **11. Учёт стоимости + бюджет задачи** — $ = токены×цена; потолок на задачу/агента с жёстким стопом при превышении. _(у нас ❌: отдельного headless runner и его cost telemetry нет)_
85
+ - [ ] **12. Типизированный retry** — повтор по классу ошибки: временное (timeout/rate-limit) → повтор, детерминированное (bad-request/схема) → 1 repair или стоп. _(у нас ⚠️: слепые «3 итерации» на всё)_
86
+ - [ ] **13. Явные триггеры + версия скилла** — использовать только поддерживаемый runtime-контракт: явный `$skill`/команда, конкретный `description`, ссылки из rules и версия через git. Не добавлять неисполняемый `triggers:` ради галочки. _(у нас ⚠️: явные skill-вызовы доступны, автоматическое срабатывание не измеряется)_
87
+ - [ ] **15. Agent-legible продукт** — приложение + его логи/метрики/трейсы доступны агенту на каждый worktree (LogQL/PromQL + DevTools), чтобы агент САМ верифицировал поведение («старт < 800мс»). _(у нас ❌)_
88
+ - [x] **16. AGENTS.md = оглавление, не энциклопедия** — Codex-вход короткий (72 строки) и ведёт в `specs/harness/codex/`/docs; Claude-вход ещё длиннее цели (271 строка), его сокращение — отдельная housekeeping-задача, не P0.
89
+ - [x] **17. Линтер с инструкцией по починке в тексте ошибки** — `scripts/arch-lint.sh` уже передаёт конкретный fix и ссылку на правило для ключевых нарушений; новые fitness-gates должны следовать тому же формату.
90
+ - [ ] **18. Eval-driven оптимизация промптов/скиллов** — метрика + eval-набор → optimizer предлагает → скорит → оставляет лучший (DSPy/GEPA); то же для описаний скиллов. _(у нас ❌: старый Evolver удалён как неиспользуемый)_
91
+ - [ ] **19. Возобновляемые прогоны (checkpointing)** — прогон сохраняет состояние и продолжается с середины после сбоя/паузы. _(у нас N/A: headless runner отсутствует)_
92
+
93
+ ---
94
+
95
+ # ЧАСТЬ 2 — Детальное раскрытие
96
+
97
+ ## 1. Принудительный структурированный вывод (SGR)
98
+
99
+ - **Слой:** 🎛 высокий · **Статус у нас:** ◐ **reference-only**. Старый headless runner удалён
100
+ в task-234 как неиспользуемый. Схемы и `scripts/validate_sgr.py` временно сохранены, пока полезные
101
+ требования из SGR не перенесены в обычные rules/checklists.
102
+ - **Что это.** Каждый агент возвращает JSON строго по схеме. Этот JSON — **машинный контракт**
103
+ между шагами пайплайна: следующий шаг читает поля предыдущего. Схема = источник истины.
104
+ - **Зачем.** Без принуждения структурированный вывод держится «на честном слове модели».
105
+ Агент через раз выдаёт нужную форму → пайплайн молча подхватывает пустоту → багов не видно.
106
+ Принуждение + лог = ты **видишь**, соблюдается ли контракт.
107
+ - **Что сохранено на уровне валидатора (не подключено к runtime):**
108
+ 1. Объявить схему (✅ есть в `.claude/schemas/`).
109
+ 2. Дать схему агенту как инструкцию (✅ есть в `agents/*.md`).
110
+ 3. **После** запуска агента — `jsonschema.validate(output, schema)`.
111
+ 4. Невалидно → **1 repair**: вернуть агенту список ошибок валидации, попросить починить.
112
+ 5. Снова невалидно → **падать громко** + писать кейс в лог (НЕ продолжать с пустыми полями).
113
+ 6. Каждый результат валидации (pass/repair/fail) — **в лог/метрику** → появляется
114
+ наблюдаемость соответствия (видно % комплаенса по агентам).
115
+ - **Два вида валидации.** (а) **структурная** — JSON против схемы (этот пункт); (б) **смысловая** —
116
+ «правильный ли вывод по сути» (см. пункт 10, Output guardrail). Полноценный гейт = обе.
117
+ - **Контракт = схема + инструкция + пример (MetaGPT `ActionNode`).** У них действие несёт не голую
118
+ схему, а связку `expected_type` + `instruction` + `example`, и компилируется в Pydantic-модель.
119
+ Усиление к нашим `schemas/*.json`: рядом со схемой держать инструкцию и пример валидного вывода.
120
+ - **Практический вывод:** в интерактивной работе через Codex/Claude этот SGR ничего не проверяет.
121
+ Не чинить его «ради галочки». Если headless pipeline снова понадобится — проектировать новый
122
+ runner отдельной задачей и доказывать живым smoke `agent → output → validation → branch`.
123
+ - **Откуда:** твой собственный `rules/general.md` («validate → 1 repair → ошибка») + autogen
124
+ (всё на Pydantic-конфигах с жёсткой валидацией).
125
+
126
+ ## 2. Наблюдаемость прогона (трейсинг)
127
+
128
+ - **Слой:** 🎛 высокий · **Статус у нас:** ❌ — старый post-hoc wrapper удалён; дерева спанов и
129
+ стандартных атрибутов нет.
130
+ - **Что это.** Каждый шаг агента оборачивается в «спан» (отрезок времени с метаданными):
131
+ `invoke_agent`, `execute_tool`, и при ошибке — запись исключения в спан. Спаны связаны
132
+ сквозным `trace_id` → видно дерево «кто кого вызвал и где затык».
133
+ - **Зачем.** Сейчас Langfuse у тебя мёртвый именно потому, что нет дисциплины «что трейсить».
134
+ Без спанов прогон — чёрный ящик: агент сказал «готово», а что было внутри — не видно.
135
+ - **Как надо.** Стандарт **OpenTelemetry GenAI semantic conventions** (vendor-neutral): спаны
136
+ с атрибутами `gen_ai.operation.name` (`invoke_agent`/`execute_tool`), `gen_ai.agent.name`,
137
+ `gen_ai.tool.name`; на ошибке — `span.record_exception(e)` + `error.type`. Один формат —
138
+ любой бэкенд (Langfuse / Phoenix / Jaeger).
139
+ - **Пример атрибутов спана (из autogen `_telemetry/_genai.py`):**
140
+ `{gen_ai.operation.name: "execute_tool", gen_ai.system: "...", gen_ai.tool.name: "pytest"}`.
141
+ - **Готовая таксономия спанов (openai-agents `tracing/span_data.py`):**
142
+ `Agent` → `Turn` → `Generation` (вызов LLM) / `Function` (вызов инструмента) / `Handoff`
143
+ (передача между агентами) / `Guardrail`. Вот ровно эти спаны и трейсить.
144
+ - **Откуда:** autogen (`_telemetry/_genai.py`, OTel-атрибуты) + openai-agents
145
+ (`tracing/span_data.py`, таксономия спанов). См. также пункт 15 (наблюдаемость ПРОДУКТА для агента).
146
+
147
+ ## 3. Активная память (а не пассивные файлы)
148
+
149
+ - **Слой:** 🎛 высокий · **Статус у нас:** ⚠️ частично — память пассивная (файлы целиком через
150
+ system-reminder) и плоская (по агентам, без типов).
151
+ - **Что это.** Память — не папка, а компонент с методом `update_context()`: она сама
152
+ **запрашивает релевантное** под текущую задачу и **вкидывает только это** в контекст.
153
+ Плюс таксономия: **рабочая** (внутри прогона) / **долгая** (между задачами) / **сущности**
154
+ (факты про модуль/компанию). Контент структурирован: `mime_type` + `metadata`.
155
+ - **Зачем.** «Вот тебе вся папка памяти» забивает контекст шумом. «Вот что нужно под эту
156
+ задачу» — точнее и дешевле.
157
+ - **Как надо.** Хранилище с query (хоть текстовый поиск, хоть вектор) → отбор top-K
158
+ релевантного → инъекция как отдельный блок. Память сама решает, что показать.
159
+ - **Глубже (crewAI `memory/types.py`):**
160
+ - **Композитный скоринг** при recall, не одна похожесть:
161
+ `score = w_семантика·similarity + w_свежесть·decay + w_важность·importance`,
162
+ где `decay = 0.5^(возраст_дней / период_полураспада)`. Свежее и важное всплывает выше.
163
+ - **Консолидация при записи**: при сохранении похожего (similarity > 0.85) LLM решает
164
+ слить/обновить/удалить → память не пухнет дублями. _(у нас есть **ручная** версия: правило
165
+ MEMORY.md «найди файл на эту тему — обнови, не плоди».)_
166
+ - **Лёгкие поля на запись**: `importance` (0-1), `source` (происхождение), `private`,
167
+ `categories`, иерархический `scope` (`/проект/модуль`). Применимо к нашему frontmatter
168
+ без всякого вектор-движка.
169
+ - **Explainable recall**: матч несёт `match_reasons` (почему совпало) и `evidence_gaps`
170
+ (что искал, но не нашёл).
171
+ - Деталь: `embedding` исключён из сериализации (экономия токенов при сохранении).
172
+ - **Протокол записи (OpenHands `skills/agent_memory.md`, триггер `/remember`):**
173
+ - логировать ТОЛЬКО переиспользуемое (структура репо, команды build/lint/test, стиль, workflow);
174
+ **НЕ** логировать частности задачи (какую ошибку поймал и как починил);
175
+ - перед сохранением показать **пронумерованный список** того, что собираешься записать →
176
+ сохранить **только одобренные** пункты → интегрировать в существующее, не плодить.
177
+ - _(у нас правило похожее, но мягче — стоит формализовать «список → апрув подмножества».)_
178
+ - **Честная граница.** Полный вектор-движок для нашей маленькой курируемой памяти — 🔧 перебор.
179
+ Берём ЛЁГКИЕ идеи (🎛): `importance`/`source`/`scope` в frontmatter + дисциплина консолидации.
180
+ - **Уровни памяти (Letta/MemGPT `schemas/memory.py`) — каноничный паттерн:**
181
+ - **core memory** — в контексте всегда, маленькая, с char-лимитом, агент САМ её редактирует
182
+ (вынужден приоритизировать); **archival/recall** — внешние, подгружаются поиском по запросу.
183
+ - `ContextWindowOverview` — точная разбивка бюджета контекста по секциям (system/core/summary/
184
+ messages/functions) — наблюдаемость самого контекста.
185
+ - блоки **версионируются** (git-backed history).
186
+ - _(у нас это УЖЕ есть в зачатке: `MEMORY.md` = core-индекс (всегда), отдельные файлы =
187
+ archival (по релевантности). Letta подтверждает паттерн; усиление — бюджет/лимит на core.)_
188
+ - **Откуда:** autogen (`memory/_base_memory.py`, `update_context`/`query`/`MemoryContent`) +
189
+ crewAI (`memory/types.py`, `memory_scope.py`: composite score, consolidation, scopes) +
190
+ OpenHands (`skills/agent_memory.md`: протокол записи с апрувом) +
191
+ Letta (`schemas/memory.py`: уровни core/archival/recall, self-editing, context-budget).
192
+
193
+ ## 4. Хуки-«таможня» (вмешательство на лету)
194
+
195
+ - **Слой:** 🎛 высокий · **Статус у нас:** ⚠️ частично — есть PreToolUse deny и PostToolUse
196
+ auto-format; Stop пока только уведомляет и не является quality stop-gate.
197
+ - **Что это.** Перехватчик, срабатывающий на каждое действие агента, который может его
198
+ **изменить, залогировать или отклонить** ДО выполнения (не после).
199
+ - **Зачем.** Блокировка по факту коммита ловит поздно. Перехват до действия — дешевле и
200
+ позволяет править («подставь правильный путь», «не трогай файл вне Scope») на лету.
201
+ - **Как надо.** У Claude Code это `PreToolUse`-хуки: получают вызов инструмента до исполнения,
202
+ возвращают allow/deny/изменение. Использовать не только для запретов, но и для корректировок.
203
+ - **Дизайн из crewAI (`hooks/types.py`) — 4 точки перехвата:**
204
+ - `before_tool_call` → правит вход инструмента *на лету* ИЛИ `False` = заблокировать.
205
+ - `after_tool_call` → переписывает результат инструмента.
206
+ - `before_llm_call` / `after_llm_call` → то же для сообщений/ответа модели.
207
+ - Контракт: «before» возвращает `bool|None` (False = стоп), «after» возвращает `str|None`
208
+ (str = изменённый результат). Чисто, предсказуемо.
209
+ - **Откуда:** autogen (`_intervention.py`, `InterventionHandler`/`DropMessage`) +
210
+ crewAI (`hooks/types.py`: before/after × LLM/tool, modify-or-block).
211
+
212
+ ## 5. Алгоритмы ужатия контекста при передаче между агентами
213
+
214
+ - **Слой:** 🎛 высокий · **Статус у нас:** ❌ нет алгоритмов (есть скилл `context-engineering`,
215
+ но это прозаические советы).
216
+ - **Что это.** Конкретные стратегии, как обрезать историю/контекст, не теряя главного:
217
+ - **head+tail+«пропущено N»**: оставить первые N (инструкции) и последние M (свежее),
218
+ середину заменить плейсхолдером `"Skipped 42 messages"`.
219
+ - **token-limited middle-drop**: пока не влезаем в бюджет — выкидывать из **середины**.
220
+ - дисциплина краёв: не оставлять висящий вызов функции или его результат на стыке.
221
+ - **Зачем.** Когда Archivist ужимает историю, Planner отдаёт контекст Builder'у — нужна не
222
+ «отрежь сколько-то», а стратегия, что именно беречь.
223
+ - **Откуда:** autogen (`model_context/`: `HeadAndTailChatCompletionContext`,
224
+ `TokenLimitedChatCompletionContext`, `BufferedChatCompletionContext`).
225
+
226
+ ## 6. Предел итераций агента ✅
227
+
228
+ - **Слой:** 🎛 высокий · **Статус у нас:** ✅ есть — правило «макс 3 итерации → СТОП, вернуть человеку».
229
+ - **Что это.** Жёсткий лимит на число попыток, чтобы агент не крутился вечно.
230
+ - **Откуда:** autogen (`max_tool_iterations`). У нас уже реализовано как правило пайплайна.
231
+
232
+ ## 10. Output guardrail (LLM-судья на вывод шага)
233
+
234
+ - **Слой:** 🎛 высокий · **Статус у нас:** ⚠️ частично — есть тяжёлые Reviewer/JiTTest в конце
235
+ пайплайна, но нет лёгкого inline-гейта на каждый шаг.
236
+ - **Что это.** К шагу привязывается критерий **словами** («вывод: 10 буллетов, без воды»).
237
+ Отдельный агент-судья проверяет результат и возвращает **структуру** `{valid: bool, feedback: str}`.
238
+ Невалидно → фидбек возвращается, шаг переделывается (ретрай).
239
+ - **Зачем.** Схемная валидация (пункт 1) ловит только *форму*. Guardrail ловит *смысл*:
240
+ «по делу ли», «нет ли галлюцинации», «соблюдён ли бизнес-критерий».
241
+ - **Дисциплина.** Судье запрещено чинить — только указывать на проблемы
242
+ («identify issues — do not propose corrections»). Критика отделена от исправления.
243
+ - **Как надо.** `valid/feedback` — структурированный вывод судьи (тот же пункт 1!). Лёгкий
244
+ guardrail на шаг ≠ тяжёлый Reviewer в конце: дешевле и ловит раньше. Спец-вариант —
245
+ guardrail на галлюцинации (crewAI `tasks/hallucination_guardrail.py`).
246
+ - **Вход И выход + tripwire (openai-agents `guardrail.py`):** guardrail бывает на **вход**
247
+ (проверить задачу ДО прогона — не жечь токены на заведомо кривой запрос) и на **выход**.
248
+ Результат несёт `tripwire_triggered: bool` — если сработал, прогон **немедленно останавливается**
249
+ (исключение `…TripwireTriggered`). Декораторы `@input_guardrail`/`@output_guardrail`.
250
+ - **Откуда:** crewAI (`tasks/llm_guardrail.py`, `LLMGuardrailResult{valid, feedback}`) +
251
+ openai-agents (`guardrail.py`: input/output guardrails, tripwire-halt).
252
+
253
+ ## 11. Учёт стоимости + бюджет задачи
254
+
255
+ - **Слой:** 🎛 высокий · **Статус у нас:** ❌ — отдельного runner, учёта стоимости и потолка нет.
256
+ - **Что это.** Считать **деньги** за прогон: `$ = токены × цена_модели` (таблица цен на модель).
257
+ Вести бюджет на задачу/агента/период и **резать**, когда превышен.
258
+ - **Зачем.** Сейчас задача может тихо прожечь любой объём токенов. Потолок = предсказуемость
259
+ расходов + ранний стоп зацикленного агента по деньгам, а не только по итерациям.
260
+ - **Как надо.** (1) таблица цен модели; (2) после каждого шага: `cost += in·price_in + out·price_out`;
261
+ (3) лимит на задачу → превышен → стоп + лог. Связано с наблюдаемостью (пункт 2): стоимость — метрика.
262
+ - **Откуда:** litellm (`cost_calculator.py`, `budget_manager.py`,
263
+ `model_prices_and_context_window_backup.json`).
264
+
265
+ ## 12. Типизированный retry (по классу ошибки)
266
+
267
+ - **Слой:** 🎛 высокий · **Статус у нас:** ⚠️ частично — «макс 3 итерации» слепо на любую ошибку.
268
+ - **Что это.** Число и стратегия повторов зависят от **типа** сбоя:
269
+ - временное (timeout, rate-limit) → повторить (возможно с backoff);
270
+ - детерминированное (bad-request, невалидная схема, синтаксис) → повтор не поможет → **1 repair или стоп**;
271
+ - блокирующее (auth/доступ) → **не повторять**, сразу человеку.
272
+ - **Зачем.** Слепой ретрай на детерминированную ошибку жжёт попытки впустую; временную, наоборот,
273
+ стоит повторить больше раз. У тебя уже есть таксономия ошибок в скилле `metrics-analysis`
274
+ (IMPORT/ASSERT/RUNTIME/DB/TYPE) — её надо **подключить к стратегии ретраев**, а не только к аналитике.
275
+ - **Откуда:** litellm (`router_utils/get_retry_from_policy.py`: `RetryPolicy` с полями
276
+ `TimeoutErrorRetries`/`RateLimitErrorRetries`/`BadRequestErrorRetries`/…).
277
+ - **ℹ️ К сведению (низкоуровневое, если строишь агента/прокси):** reason-aware fallback
278
+ (`context_window_fallbacks` → переключение на модель с бОльшим окном; `content_policy_fallbacks`),
279
+ circuit-breaker (cooldown упавшего провайдера после `allowed_fails`), семантический кэш
280
+ (кэш по смыслу промпта). Для нашей dev-среды на одном opus-4-8[1m] — не применимо.
281
+
282
+ ## 13. Явные триггеры + версия скилла
283
+
284
+ - **Слой:** 🎛 высокий · **Статус у нас:** ⚠️ частично — явные `$skill`-вызовы доступны, но
285
+ автоматическое срабатывание по `description` не измеряется.
286
+ - **Что это.** Использовать только реальный контракт конкретного runtime: явный `$skill`/команду,
287
+ конкретный `description` и ссылки из `AGENTS.md`/rules. Версию хранить через git или поддерживаемое
288
+ поле runtime.
289
+ - **Зачем.** Семантический триггер гибкий, но недетерминированный. Неисполняемое поле
290
+ `triggers:` создаёт ложную гарантию и потому хуже явного указателя.
291
+ - **Как надо.** Критические процедуры подключать явной ссылкой или вызовом, а факт применения
292
+ логировать там, где runtime это поддерживает.
293
+ - **Откуда:** OpenHands (`skills/*.md`: `name/type/version/agent/triggers`; keyword + slash-команды).
294
+
295
+ ## 15. Agent-legible продукт (наблюдаемость продукта ДЛЯ агента) ⭐
296
+
297
+ - **Слой:** 🎛 высокий · **Статус у нас:** ❌ нет.
298
+ - **Что это.** Не «трейсить агента» (пункт 2), а сделать **сам продукт читаемым для агента**:
299
+ приложение поднимается на каждый git-worktree, его логи/метрики/трейсы доступны агенту
300
+ через локальный эфемерный observability-стек (запросы LogQL/PromQL/TraceQL), а UI — через
301
+ Chrome DevTools. Тогда промпт «убедись, что старт сервиса < 800мс» или «ни один из 4 сценариев
302
+ не дольше 2с» становится **исполнимым** — агент сам воспроизводит баг, чинит, проверяет, повторяет.
303
+ - **Зачем.** Это то, что позволило OpenAI собрать продукт в 1М строк силами 3-7 инженеров:
304
+ узкое место — человеческое QA; убираешь его, дав агенту самому видеть поведение продукта.
305
+ - **Как надо (для нас).** У тебя уже есть Live-stack E2E (агент сам гоняет реальный стек). Развить:
306
+ per-worktree подъём + RO-доступ агента к логам/метрикам + «дёрни и проверь по трейсам».
307
+ - **Откуда:** OpenAI «Engineering the harness: Codex» (2026).
308
+
309
+ ## 16. AGENTS.md = оглавление + docs/ как система записи
310
+
311
+ - **Слой:** 🎛 высокий · **Статус у нас:** ✅ для Codex — `AGENTS.md` занимает 72 строки и ведёт
312
+ в профильные docs; ⚠️ для Claude — `CLAUDE.md` длиннее целевого бюджета и требует housekeeping.
313
+ - **Что это.** Не пихать всё в один большой файл инструкций (он вытесняет задачу из контекста,
314
+ «важно всё → важно ничто», устаревает, не проверяется). Вместо этого: **короткий вход** (~100 строк)
315
+ = карта с указателями → структурный `docs/` (design-docs, exec-plans active/completed,
316
+ product-specs, references, QUALITY_SCORE.md, ARCHITECTURE.md) как **система записи**.
317
+ **Progressive disclosure**: агент стартует с малого и знает, куда смотреть дальше.
318
+ - **Механически:** линтеры + CI проверяют свежесть/перекрёстные ссылки; периодический
319
+ **doc-gardening агент** находит устаревшую доку и открывает PR.
320
+ - **Артефакт QUALITY_SCORE.md:** оценка каждого домена/слоя + отслеживание пробелов во времени.
321
+ - **Откуда:** OpenAI Codex blog (структура `docs/`, ToC-подход, doc-gardening).
322
+
323
+ ## 17. Линтер с инструкцией по починке в тексте ошибки
324
+
325
+ - **Слой:** 🎛 высокий · **Статус у нас:** ✅ — `arch-lint.sh` для ключевых правил уже сообщает
326
+ конкретный способ исправления и ссылку на норму. Новые fitness-gates должны продолжать этот контракт.
327
+ - **Что это.** Кастомный линтер инвариантов формулирует сообщение об ошибке так, чтобы **встроить
328
+ инструкцию по устранению прямо в контекст агента** → агент сам чинит, не гадая.
329
+ - **Зачем.** Линтер = feedforward+feedback для агента: «инвариант нарушен, вот КАК исправить».
330
+ После внедрения применяется везде одновременно (множитель).
331
+ - **Откуда:** OpenAI Codex blog («внедряем инструкции по устранению в сообщения об ошибках линтера»).
332
+
333
+ ## 18. Eval-driven оптимизация промптов/скиллов
334
+
335
+ - **Слой:** 🎛 высокий · **Статус у нас:** ⚠️ — Evolver мутирует эвристично (`metrics.json`),
336
+ без метрики+eval-набора+optimizer'а.
337
+ - **Что это.** Промпт/описание скилла — **обучаемый параметр против метрики**: задаёшь метрику
338
+ и небольшой eval-набор → optimizer (GEPA/MIPRO/BootstrapFewShot) **предлагает варианты → скорит →
339
+ оставляет лучший**. То же для описаний скиллов (бенчмарк срабатывания → авто-улучшение описания).
340
+ - **Зачем.** Убирает гадание «лучше ли стал промпт» — есть число, а срабатывание скиллов становится
341
+ измеримым.
342
+ - **Откуда:** DSPy (`teleprompt/gepa`, `mipro_optimizer_v2`, `bootstrap`) и deer-flow
343
+ (`skill-creator/scripts/run_eval.py`, `improve_description.py`).
344
+
345
+ ## 19. Возобновляемые прогоны (checkpointing)
346
+
347
+ - **Слой:** 🎛/🔧 · **Статус у нас:** N/A — headless runner отсутствует.
348
+ - **Что это.** Прогон сохраняет состояние по шагам (checkpoint) и может **продолжиться с места**
349
+ после сбоя/паузы/правки, не начиная заново.
350
+ - **Зачем.** Длинные прогоны (часы) не теряются из-за одного сбоя; дешевле MTTR.
351
+ - **Откуда:** deer-flow (`runtime/checkpointer`, `persistence/run`), Letta (версионируемые блоки);
352
+ тема LangGraph (checkpoints/time-travel) — если понадобится глубже.
353
+
354
+ ---
355
+
356
+ ## Подтверждено статьёй OpenAI «Engineering the harness: Codex» (2026)
357
+
358
+ Статья OpenAI про сборку продукта в 1М строк силами агентов **подтверждает**, что у тебя уже
359
+ сделано правильно (НЕ трогаем, это сильные стороны):
360
+
361
+ - **Инварианты, а не детали реализации**, через кастомные линтеры + структурные тесты → у тебя
362
+ `arch-lint.sh` + FSD + size/ratio-линтеры. ✅
363
+ - **Золотые принципы + GC + мелкие refactor-PR** против дрейфа → у тебя Sentinel + Evolver + GC. ✅
364
+ - **Планы как версионируемые артефакты** (exec-plans с журналом решений) → у тебя `specs/tasks/`. ✅
365
+ _(усиление: добавлять в план журнал прогресса/решений.)_
366
+ - **Скучные технологии**, иногда переписать кусок вместо обёртки → у тебя ADR. ✅
367
+ - **Ralph-loop** (агент крутит до зелёного арбитра) → у тебя пайплайн с Reviewer-циклом. ✅
368
+ - **Throughput меняет merge-философию** (короткоживущие PR, флейки — ретраем, не блокируем). ℹ️ философия.
369
+
370
+ ---
371
+
372
+ ## Журнал источников (какой репо что дал)
373
+
374
+ | Репо | Дал / усилил пункты |
375
+ |------|------------|
376
+ | `microsoft/autogen` (05 #1) | 1, 2, 3, 4, 5, 6, 7, 8, 9 |
377
+ | `crewAIInc/crewAI` (05 #2) | 10 (новый); усилил 1, 3, 4 |
378
+ | `BerriAI/litellm` (05 #3) | 11, 12 (новые); reason-fallback/cooldown/sem-cache → ℹ️ |
379
+ | `OpenHands/OpenHands` (02 #7) | **подтвердил** каркас (skills-md, CLAUDE.md, repo-memory); 13, 14 (новые); усилил 3 |
380
+ | `letta-ai/letta` (02 #20) | усилил 3 (уровни core/archival/recall, self-editing, context-budget) |
381
+ | `bytedance/deer-flow` (02 #8) | **подтвердил** состав harness; 18, 19 (skill-eval, checkpointer) |
382
+ | `FoundationAgents/MetaGPT` (02 #9) | **подтвердил** SOP-пайплайн; усилил 1 (контракт = схема+инструкция+пример) |
383
+ | `openai/openai-agents-python` (02 #13) | усилил 2 (таксономия спанов), 10 (input-guardrail + tripwire) |
384
+ | `stanfordnlp/dspy` (05 #5) | 18 (eval-driven оптимизация; первоисточник GEPA для Evolver) |
385
+ | OpenAI «Codex harness» (статья, 2026) | 15, 16, 17 (новые); **подтвердил** arch-lint/FSD, Sentinel/Evolver, specs-планы |