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,322 @@
1
+ # Снимок гейтов audit_project (2026-08-24)
2
+
3
+ > **Это не ваш чек-лист.** Это состояние гейтов одного конкретного проекта — Django + React,
4
+ > около года работы с агентами — на 24 августа 2026 года. Читать его как список «что мне надо
5
+ > внедрить» нельзя: половина пунктов привязана к Django, DRF и 1С.
6
+ >
7
+ > **Зачем он здесь.** Это сырьё каталога: 98 пунктов, каждый со статусом и историей. Из них
8
+ > вырастают записи `gates/`, когда у пункта находится команда-арбитр, переносимая на любой стек,
9
+ > и доказательство отказом.
10
+ >
11
+ > **Метод чтения — в `gates/README.md`:** пять полей записи, четыре способа вранья гейта,
12
+ > триггер как запрос к репозиторию. Раньше он жил в шапке этого файла.
13
+ >
14
+ > Статусы: ✅ внедрено · 🟡 частично, необязательное или спит · ❌ нет · ⛔ не применимо.
15
+ > Числа проверены прогоном по репозиторию 2026-08-24, а не переписаны с прошлой версии.
16
+
17
+ ---
18
+
19
+ ## Статика Python
20
+
21
+ - [x] ✅ ruff (`ruff.toml`: E,F + extend `I,B,UP,DJ,SIM,RUF,PERF,FURB,PLR0402/1711/5501`) — pre-commit + CI blocking
22
+ - [x] ✅ ruff-format `--check` — pre-commit + CI blocking
23
+ - [x] ✅ mypy lite — pre-commit + CI blocking, **15 приложений**: `core users companies contacts requisites projects integrations tracker vouching teams workdocs notifications documents retain timesheets`
24
+ - [x] ✅ bandit (`bandit.yaml`) — pre-commit + CI blocking
25
+ - [x] ✅ PERF + FURB + мелкие PLR — 98 фиксов, onec money-safe. `PERF401`/`PLR2004` в ignore (шум)
26
+ - [x] ✅ **`import-linter` — границы модулей монолита** (task-336, 2026-08-25). CI blocking +
27
+ `make verify`. Два контракта, оба зелёные: «`core` — фундамент и не зависит от доменных
28
+ приложений» и «верхушку (`nextcloud`, `questionnaires`, `tools`) не импортирует никто».
29
+ Проверен подсадкой нарушения: импорт `projects.models` в `core/checks.py` красит гейт.
30
+ **Чего НЕ ловит (важнее того, что ловит):** 18 взаимных зависимостей между доменными
31
+ приложениями (`projects ⇄ tracker` и другие). Слоистую модель включить нельзя, пока их не
32
+ разорвут; записано долгом в реестре. Исключения в `.importlinter` названы поимённо и
33
+ помечены: `seed_demo` — законное, `automation_access` — ДОЛГ.
34
+ 📏 История: инструмент лежал в `pyproject.toml` неиспользуемым. Первым порывом было снести
35
+ его вместе с тремя другими «зомби»; владелец возразил — «может, их надо включить, а не
36
+ сносить». Проверка по факту показала, что он прав: из четырёх один включён, один оставлен
37
+ как библиотека, по двум решение открыто. **Списывать инструменты скопом — плохая привычка;
38
+ «не используется» и «не применим» — разные утверждения.**
39
+ - [ ] 🟡 **mypy не покрывает новые приложения**: `nextcloud`, `questionnaires`, `analytics` — их просто нет в списке CI (не «осознанный ignore», а дрейф: приложение завели после того, как список зафиксировали)
40
+ - [ ] ⏸️ `ignore_errors` осознанно: `onec` (последним), `integrations` (Bitrix-legacy), `tools`, `tools.processors`; file-level `projects.serializers`
41
+ - [ ] ❌ mypy `--disallow-untyped-defs` (strict)
42
+ - [ ] ❌ ruff-группы — **разбить по ценности, а не одной строкой** (см. «Кандидаты», п. A)
43
+
44
+ ## Frontend
45
+
46
+ - [x] ✅ eslint + FSD-boundaries + no-any (на **error**) — CI blocking
47
+ - [x] ✅ tsc strict (`tsc -b`) + прод-сборка `npm run build` — CI blocking
48
+ - [x] ✅ frontend-guards (`check:rq` / `check:themes` / `check:styles`) — вшиты в `npm run lint` → pre-commit + CI
49
+ - [x] ✅ knip (мёртвый TS / экспорты / зависимости / дубли) — CI **advisory**, `frontend/knip.json`. Чистка сделана: −20 файлов, −8 пакетов, −6 дублей (осталось 46 unused exports — tree-shaken, косметика)
50
+ - [x] ✅ size-limit (JS 1.1 МБ / CSS 80 КБ gzip) — CI **advisory**
51
+ - [x] ✅ npm audit `--audit-level=high` — CI **advisory**
52
+ - [ ] 🟡 vitest — скрипты есть (`test`, `test:coverage`), в CI **не подключён** (осознанно, «фронт без тестов»)
53
+ - [ ] ❌ prettier `--check` (конфига нет) · eslint `--max-warnings 0`
54
+
55
+ ## API-контракт / OpenAPI ← НОВЫЙ РАЗДЕЛ (раньше в чек-листе отсутствовал)
56
+
57
+ **Схема у нас есть и она рабочая — но дырявая, и это не было видно, т.к. раздела не существовало.**
58
+
59
+ - [x] ✅ `drf-spectacular>=0.28` в зависимостях + `INSTALLED_APPS` + `DEFAULT_SCHEMA_CLASS: AutoSchema`
60
+ - [x] ✅ `SPECTACULAR_SETTINGS` (TITLE / VERSION 1.0.0 / TAGS) — `_config/settings/base.py:289`
61
+ - [x] ✅ Эндпоинты `/api/v1/schema/` + `/api/v1/docs/` (Swagger UI) — `api/v1/urls.py:19-20`
62
+ - [x] ✅ schemathesis фаззит схему в CI — **advisory**, только `GET`, `--hypothesis-max-examples=5`
63
+ - [ ] 🔴 **Схема неполная.** Прогон `manage.py spectacular` (2026-07-27): **Warnings 46 (28 уникальных), Errors 202 (39 уникальных)**; на выходе 219 путей / 303 операции / 201 компонент. Из них **37 вьюх выброшены целиком** (`unable to guess serializer` → «Ignoring view for now»):
64
+ - весь `timesheets` (MyTimeSheet, TimeSheetSummary, TimeSheetDayDetail, UserTimeSheet, TimesheetAnalytics, TimesheetDrillDown)
65
+ - весь `nextcloud` (NcFolderBrowse, NcFolderBrowseGlobal, NcProjectFolder, NextcloudAttachment)
66
+ - auth-контур: `MeAPIView`, `CookieTokenRefreshView`, `CookieTokenLogoutView`, `CentrifugoConnectTokenView`
67
+ - `onec` DirectPG (OneCConnection*, OneCDirectPgOverview, TestDirectPg*), аналитика (ExecutiveDashboard, NativeExecutive, ResourcePlanning, BonusMetrics), CBU forex, все Bitrix
68
+ - **Следствие:** фаззинг API покрывает заметно меньше, чем кажется по галочке «schemathesis ✅»
69
+ - [ ] 🟡 Untyped path-параметры в nested-роутах (`contacts`, `documents`) → `id` уезжает в `"string"` вместо `integer`
70
+ - [ ] 🟡 Enum-коллизии не разрулены: в схеме живут `StatusFdfEnum`, `Status88eEnum`, `Status88aEnum`, `Status13aEnum`, `Status560Enum`, `Mode24bEnum`, `Stage611Enum`, `KindAf8Enum` — `ENUM_NAME_OVERRIDES` пуст
71
+ - [ ] ❌ **Фронт не потребляет схему**: ни `openapi-typescript`, ни `orval` в `frontend/package.json`. Типы API написаны руками → дрейф бек↔фронт ничем не ловится
72
+ - [ ] ❌ **Схема не коммитится** → нет diff-гейта на breaking changes (кандидат: `oasdiff`)
73
+ - [ ] 🟡 `/api/v1/schema/` и `/api/v1/docs/` отдают **200 анонимно** (проверено curl на :8180). `SERVE_PERMISSIONS`/`SERVE_AUTHENTICATION` не заданы, nginx не режет. В dev нормально, в проде — публичная карта всей API-поверхности
74
+
75
+ **План внедрения (порядок):**
76
+ 1. `@extend_schema` / `serializer_class` на 37 выброшенных вьюх → Errors к нулю (даёт эффект сразу на schemathesis).
77
+ 2. `ENUM_NAME_OVERRIDES` + типизация path-параметров (`<int:pk>`) → чистые Warnings.
78
+ 3. Закрыть `/schema/` + `/docs/` в проде (`SERVE_PERMISSIONS: IsAdminUser` либо nginx-allowlist).
79
+ 4. Гейт «схема генерится без Errors» в CI blocking (`spectacular --fail-on-warn` после чистки).
80
+ 5. `openapi-typescript` → генерация TS-типов фронта из схемы; дрейф ловится `tsc`.
81
+ 6. Коммитить `schema.yml` + `oasdiff` на breaking changes в MR.
82
+ 7. Снять с schemathesis ограничение `^GET$` и поднять `--hypothesis-max-examples`, когда схема станет честной.
83
+
84
+ ## БД / миграции
85
+
86
+ - [x] ✅ `makemigrations --check --dry-run` — CI blocking
87
+ - [x] ✅ django-migration-linter — blocking pre-push hook; wrapper проверен task-232:
88
+ diff считается из `/app`, текущие новые миграции `3/3 valid`; отдельного CI job нет
89
+ - [x] ✅ query-budget тесты `assertNumQueries` / `django_assert_max_num_queries` (`projects/tests/test_query_budgets.py`) — N+1-гейт по правилу в `rules/backend/database.md`
90
+ - [x] ✅ django-zen-queries — пилот `AuditProjectViewSet` + `core.query_guard.QueryGuardMixin`, активен в тестах (prod no-op), ловит N+1 (проверено)
91
+ - [ ] 🟡 django-silk — **стоит в dev-зависимостях, 0 упоминаний в коде** (мёртвая зависимость: либо подключить в dev-compose, либо выкинуть)
92
+ - [ ] 🟡 zen-queries раскатан на **один** ViewSet — остальные list-эндпоинты держатся на дисциплине + point-тестах
93
+ - [ ] 🟡 inline-snapshot-django — снапшот точных SQL вью («N+1 на стероидах»); не внедрено
94
+ - [ ] ❌ SQL-линт для `dbt/` — **дыра**: модели dbt есть, `sqlfluff` (или dbt-линт) нет вообще
95
+
96
+ ## Секьюрити / SCA
97
+
98
+ - [x] ✅ gitleaks (секреты, `.gitleaks.toml`) — pre-commit + CI blocking (по диапазону коммитов)
99
+ - [x] ✅ detect-private-key (PEM) — pre-commit
100
+ - [x] ✅ pip-audit (CVE Python) — CI **advisory**
101
+ - [x] ✅ npm audit (CVE фронт) — CI **advisory**
102
+ - [x] ✅ прод-хедеры HSTS/SSL/cookies/NOSNIFF/X-Frame (`check --deploy` = 0 warning)
103
+ - [x] ✅ hadolint (5 Dockerfile) — CI blocking, `.hadolint.yaml` игнор DL3008
104
+ - [ ] 🟡 semgrep (`.semgrep/rules.yml`) — CI blocking, **правил всего 2** (money-точность), и
105
+ **у самих правил нет тестов**. 📏 2026-08-24: правило `decimal-from-float-literal` ругалось
106
+ на `Decimal("111.00")` — на предписанное им же написание; срабатывало не всегда, а в
107
+ зависимости от соседнего кода в файле (`metavariable-regex` у semgrep местами отдаёт
108
+ содержимое строки без кавычек). Починено структурно (`pattern-not: Decimal("...")`), но
109
+ **штатный режим `semgrep --test` с файлом-образцом `# ruleid:` / `# ok:` не подключён** —
110
+ значит починка ничем не защищена от возврата. Наполнять правилами имеет смысл только
111
+ вместе с этим режимом, иначе каждое новое правило — лотерея
112
+ - [x] ✅ **rate limiting уже есть** (было отмечено как ❌): DRF-throttling в `REST_FRAMEWORK` — `anon 100/min`, `user 1000/min`, `auth_login 5/min`, `auth_refresh 20/min`
113
+ - [ ] 🟡 django-axes (блокировка перебора на уровне аккаунта) — нет; частично закрыто throttling'ом `auth_login`
114
+ - [ ] ❌ **CSP-заголовков нет вообще** (`django-csp` не стоит, grep = 0)
115
+ - [ ] ❌ shellcheck (25+ bash-скриптов)
116
+ - [ ] ❌ Renovate/Dependabot · trivy / SBOM / OSV-Scanner
117
+
118
+ ## Тесты
119
+
120
+ - [x] ✅ pytest + coverage (fail-under 85% master / 80% MR) — CI blocking
121
+ - [x] ✅ schemathesis (API-фаззинг на 5xx) — CI advisory *(см. оговорку в разделе OpenAPI: фаззит неполную схему)*
122
+ - [x] ✅ анти-паттерны тестов под гейтом (`scripts/arch-lint.sh`): observer-тесты, silent skip, `test_fix_*`, эфемерные contracts, лимиты моков/caplog, размер файла ≤800 LOC / ≤30 тестов
123
+ - [x] ✅ `scripts/test-ratio-check.sh` (test:code ratio, цель ≤2.0x)
124
+ - [ ] 🟡 coverage мерит **6 модулей** (`companies core projects requisites users _config` — `.coveragerc`); прочие тестируются, но не мерятся
125
+ - [x] ✅ `questionnaires` включён в `pytest.ini testpaths`; общий invariant-тест
126
+ автоматически требует включать каждое Django-приложение, где есть тесты (task-234)
127
+ - [ ] 🟡 стоят, но фактически не используются: `freezegun` (0 упоминаний), `vulture` (0 вызовов), `import-linter` (контрактов нет), `pytest-randomly` (отключён `-p no:randomly` осознанно), `hypothesis` (1 файл)
128
+ - [x] 🟢 mutmut backend — ручной advisory-профиль `casts`: CLI 3.5, точный scope, stats/parser;
129
+ доказательный baseline 45 total / 29 killed / 16 survived (task-236). Frontend Stryker
130
+ решением человека не входит в этот срез и не считается доказанным.
131
+
132
+ ### Пройдена полная батарея (mypy 0 + coverage ≥90%, reuse+fresh-db)
133
+
134
+ `core · companies · contacts · projects · requisites · users · tracker · vouching · teams · workdocs ·
135
+ notifications · documents · retain · timesheets`.
136
+ **Осталось:** `onec` (последним, e2e-first) · `analytics`/`integrations` (Bitrix, под удаление) ·
137
+ `nextcloud` и `questionnaires` (заведены позже, в батарею не заходили).
138
+
139
+ ## Не-код линтеры
140
+
141
+ - [x] ✅ check-yaml / check-toml / check-json — pre-commit
142
+ - [x] ✅ semgrep — см. «Секьюрити» (гейт стоит, правил 2)
143
+ - [ ] ❌ codespell · GitLab CI lint (`.gitlab-ci.yml`) · markdownlint / lychee
144
+
145
+ ## Хуки / DX / свои гейты
146
+
147
+ - [x] ✅ block-dangerous-commands · auto-format · permissions-deny — `.claude/hooks`
148
+ - [x] ✅ project-map + `@import` в CLAUDE.md + `check-map` (анти-деградация карты) — pre-commit
149
+ - [x] ✅ `arch-lint` (console.log, TODO, NBSP, raw request, анти-паттерны тестов,
150
+ `no_silent_except`) — blocking pre-commit + change-based backend CI; process-контракт
151
+ защищён тестом. Полный raw-request inventory честно содержит 3 legacy Bitrix-находки
152
+ - [x] ✅ **`check-queue-consumers.py`** — dev↔prod parity очередей Celery — CI blocking *(не было в чек-листе)*
153
+ - [x] ✅ **`check-celery-timeout-invariant.py`** — инвариант таймаутов задач — CI blocking *(не было в чек-листе)*
154
+ - [x] ✅ **`logs-evidence-reminder`** — напоминание «готово = тесты + логи + метрики» (task-222) *(не было в чек-листе)*
155
+ - [x] ✅ pre-push git-hook **установлен**; автоматически запускает `lint-migrations`;
156
+ `pytest-in-docker` имеет stage `manual` и в pre-push не входит
157
+ - [x] ✅ Codex-harness: короткий `AGENTS.md` + 3 нативных repo-skills
158
+ (`plan-template`, `tdd-workflow`, `review-checklist`); целостность путей и metadata
159
+ проверяет blocking `scripts/tests/test_codex_harness.py` (task-237)
160
+ - [ ] 🟡 Автоматическое срабатывание Codex-skills не измеряется: гарантирован только явный
161
+ `$skill`; для implicit activation нужен отдельный fresh-session eval
162
+ - [ ] 🟡 Stop-гейт — только `wsl-notify.sh` (уведомление), не блок качества
163
+ - [ ] ❌ `verify.sh` — одна команда = зеркало CI локально
164
+
165
+ ## Наблюдаемость / Ops
166
+
167
+ - [x] ✅ **Централизованные логи: Loki + Alloy** (task-221) — `observability/loki`, `observability/alloy`, `docker-compose.observability.yml`; labels `{service, level, environment}`, `request_id` в structured metadata, PII-redact вне Django. Закрывает то, ради чего в списке стоял `django-structlog`
168
+ - [x] ✅ **Prometheus + Grafana + Alertmanager** + postgres-exporter (`observability/`, `bootstrap-postgres-exporter.sh`, `alerts.yml`)
169
+ - [x] ✅ Правило «готово = доказательства» (тест + live-stack + запрос в Loki + метрика) — `docs/operations/observability.md`, зеркало в `.claude/rules/observability.md`
170
+ - [x] ✅ `request_id` в каждом запросе (`core/logging.py`, RequestIDMiddleware) + `PIIRedactingFilter`
171
+ - [ ] 🔴 **error tracking (Sentry / self-hosted GlitchTip)** — по-прежнему НЕТ (grep по `pyproject.toml` + settings = 0). Логи в Loki есть, но нет группировки/дедупа/алерта «новый тип исключения», нет стектрейс-контекста. **Дыра №1**
172
+ - [ ] 🔴 **бэкап БД + проверенное восстановление** — в `scripts/` нет ни одного backup/restore-скрипта. **Дыра №2** (финансовые данные)
173
+ - [ ] 🟡 PgHero — медленные запросы / неиспользуемые+отсутствующие индексы. Частично перекрыт postgres-exporter'ом; UI над `pg_stat_statements` нет
174
+ - [ ] ❌ langfuse — в чек-листе значился «пустой каркас»; **фактически зависимости нет**, остались только `scripts/langfuse_*.py`
175
+ - [ ] ❌ OTel-трейсинг (крупный лифт)
176
+ - [ ] ❌ django-structlog — **закрывать не нужно**, потребность снята Loki/Alloy (оставлено как «не берём»)
177
+
178
+ ## AI-ревью ← НОВЫЙ РАЗДЕЛ
179
+
180
+ **Что уже работает у нас:**
181
+ - [ ] 🔴 **Запись сгнила — исправлено 2026-08-24.** Здесь стояло `✅ Tester(+contracts) →
182
+ Auditor(holdout) → Builder(isolated) → JiTTest → Reviewer` с пометкой «Builder не видит
183
+ полные тесты». **Ничего из этого не работает с 2026-08-03:** изоляция Builder'а и генерация
184
+ контрактов отключены решением владельца (`scripts/extract-contracts.py` ломает файлы —
185
+ переносит импорт из тела функции на верхний уровень вместе с отступом), Auditor и JiTTest
186
+ подключаются только явным решением на конкретную задачу. Фактически работает:
187
+ **Tester ≠ Builder** (железно) + `scripts/test-lock.sh` (снимок тестов до/после Builder) +
188
+ независимый прогон Reviewer'ом + внешний неподгоняемый арбитр + ручная приёмка.
189
+ Класс ошибки — «устаревшая запись»: документ утверждал защиту, которой нет, четыре недели.
190
+ - [x] ✅ `Sentinel` (`/sentinel`) — периодический прогон по всей кодовой базе: мёртвый код, дублирование, архитектурные нарушения, устаревшие зависимости. Это ровно «repo-mode»-режим ревьюера, а не PR-режим
191
+ - [x] ✅ `/code-review ultra` — встроенное мульти-агентное ревью Claude Code (то самое «коробочное решение от Claude Code»): кастомизация, калибровка severity. Запускается человеком, платно
192
+ - [x] ✅ Детерминированный слой под ревью: `arch-lint.sh`, `semgrep`, `frontend-guards`, `check-map`, `check-queue-consumers`
193
+
194
+ **Вывод из внешнего опыта (CodeRabbit / Qodo / Claude Code Review / nitpicker):** узкое место AI-ревью —
195
+ не полнота, а **шум**: на одно полезное срабатывание много ложных, и это выжигает доверие ревьюеров.
196
+ Отсюда наш рабочий контур: **AI ищет паттерн → подтверждённый паттерн кодируется в детерминированный гейт**
197
+ (`semgrep` / `arch-lint`), и дальше ловится бесплатно и без ложных. Сейчас в `.semgrep/rules.yml` **2 правила** —
198
+ это и есть недоиспользованный канал (см. Приоритет 2).
199
+
200
+ - [ ] 🟡 **AI-находки не конвертируются в правила** — главный разрыв: Sentinel/Reviewer находят, но находка живёт в отчёте, а не в гейте
201
+ - [ ] ❌ Пилот nitpicker-подхода (несколько узких дешёвых прогонов под конкретные цели, разные модели, детерминированная глубина) — как advisory-канал рядом с Sentinel, а не вместо него
202
+ - [ ] ⚪ CodeRabbit / Qodo — **не берём**: файловый уровень, архитектуру игнорируют; у нас этот слой уже закрыт линтерами
203
+
204
+ ## Кандидаты — чего у нас нет (ранжировано по ROI)
205
+
206
+ **A. Ruff-группы — самый дешёвый выигрыш (одна строка в `ruff.toml`), но разные по ценности:**
207
+ - `LOG` + `G` — корректность логирования. **Прямо под нашу observability-конституцию** (ADR-017): ловит f-строки в логах, потерянные `exc_info`. Брать первым
208
+ - `DTZ` — наивные `datetime` без таймзоны. У нас даты/периоды в отчётах и таймшитах — это класс реальных багов
209
+ - `C90` (mccabe) — сложность функций; дешёвая замена «xenon/radon», порог настраивается
210
+ - `T20` (`print`) · `RET` · `PT` (стиль pytest) — косметика, можно пачкой
211
+ - `S` (bandit-правила внутри ruff) — потенциально **заменяет отдельный bandit** и ускоряет CI
212
+ - `PLR too-many-*` — SOLID-метрика (~180 срабатываний) — это рефакторинг-заход, **не гейт**
213
+
214
+ **B. Дублирование кода — у нас нет ничего:**
215
+ - `jscpd` — copy-paste detector, умеет **и Python, и TS** одним прогоном, порог/игноры конфигом, есть npx. Ставить advisory-секцией рядом с knip
216
+ - `pylint --duplicate-code` (R0801) — только Python и тяжело тянуть весь pylint ради одной проверки → не брать
217
+ - Knip уже ловит дубли **экспортов** на фронте (найдено −6), но не дублирование тел функций
218
+
219
+ **C. N+1 и производительность — есть база, есть чем усилить:**
220
+ - Подключить уже оплаченный `django-silk` в dev-compose (сейчас мёртвая зависимость) либо выкинуть из `pyproject.toml`
221
+ - Раскатать `zen-queries` за пределы `AuditProjectViewSet`
222
+ - `inline-snapshot-django` — снапшот SQL вью (наследник django-perf-rec)
223
+ - `nplusone` — **не брать**: перекрывается zen-queries + query-budget тестами
224
+
225
+ **D. Мёртвый код / зависимости:**
226
+ - `vulture` уже стоит и ни разу не вызывается → включить advisory или удалить
227
+ - `deptry` — «knip для Python»: неиспользуемые/недекларированные зависимости. У нас на фронте это закрыто (knip), на беке — нет
228
+ - `import-linter` стоит, контрактов нет → написать 2-3 контракта (`core ⊥ onec`, `views ⊥ прямой ORM в шаблонах`) либо удалить
229
+
230
+ **E. SQL / dbt:**
231
+ - `sqlfluff` (+ dbt templater) — линт моделей `dbt/`. Сейчас SQL-слой вне любого гейта
232
+
233
+ **F. Секьюрити:**
234
+ - `django-csp` — CSP-заголовков нет вообще
235
+ - `django-axes` — блокировка перебора по аккаунту (throttling закрывает частично)
236
+
237
+ ---
238
+
239
+ ## 📏 Найдено 2026-08-24 (день выпуска карточки счёта)
240
+
241
+ Всё измерено в тот же день, не пересказано.
242
+
243
+ **Про сами гейты:**
244
+
245
+ - [ ] 🔴 **Нет локального зеркала CI.** `scripts/tests` (251 тест), `check-celery-timeout-invariant.py`,
246
+ `check-openapi-debt.py`, semgrep, gitleaks живут **только** в CI-задаче `quality:backend`; в
247
+ pre-commit их нет. Цена измерена: за день **четыре красных круга конвейера**, три из четырёх
248
+ ловились локально за секунды. Один круг = 15–18 минут ожидания. Кандидат: `verify.sh`
249
+ (в чек-листе уже числился как ❌ и оказался самым дорогим пропуском)
250
+ - [ ] 🔴 **Ни у одного гейта нет пары «красный / зелёный» образец**, кроме трёх: `arch-lint`
251
+ (защищён тестом процесса), `check-celery-timeout-invariant` (свой тест),
252
+ сторож копии предела времени рендера (доказан мутацией 2026-08-24). У semgrep и
253
+ schemathesis — ноль. Мера здоровья набора гейтов = сколько имеют такую пару
254
+ - [ ] 🔴 **Триггеры записаны словами → не срабатывают.** Раздел «Кандидаты» ниже — список
255
+ пожеланий: условие наступает, никто не замечает. 📏 `sqlfluff`: модели dbt в проекте есть,
256
+ линтера нет, запись «когда появятся модели» лежит. Лечение — `check-triggers.sh`, который
257
+ читает репозиторий и печатает «условие наступило, сторожа нет»
258
+ - [ ] 🔴 **Зомби-зависимости не под гейтом.** `silk` / `vulture` / `freezegun` / `import-linter` —
259
+ по 0 упоминаний в `.py` (проверено grep 2026-08-24). Это не беспорядок, а поверхность
260
+ атаки: чужой код в образе без потребителя. Кандидат: `deptry` (числится в «Кандидатах, D»)
261
+ либо свои 10 строк. Рекомендация по самим четырём — **удалить**, вернуть с образцами, когда
262
+ реально понадобятся
263
+ - [x] ✅ **Конфиг гейта обязан быть в белом списке путей `.gitlab-ci.yml`** — исправлено
264
+ 2026-08-24. До этого правка `.semgrep/` **не создавала пайплайн вовсе** (не «упал» — его не
265
+ было), и вместе с ним не появлялось кнопки выката: `deploy:production` гейтится тем же
266
+ списком. Добавлены `.semgrep/**`, `.semgrepignore`, `bandit.yaml`, `.coveragerc`
267
+
268
+ **Про API-контракт (пересчитано 2026-08-24, цифры сдвинулись с 07-27):**
269
+
270
+ - 📏 схема: **240 путей / 326 операций**; в реестре долга — **29 вьюх** (было 37 выброшенных)
271
+ - [ ] 🔴 **Схему никто не потребляет.** Ни `openapi-typescript`, ни `orval` в
272
+ `frontend/package.json` (проверено). Типы фронта написаны руками → схема остаётся
273
+ документацией, а не договором. Класс ошибки уже прожит дважды (конверт прочитали как
274
+ массив, список молча пуст). Самый дешёвый ход всего списка
275
+ - [ ] 🔴 **`response_schema_conformance` не включён** — schemathesis проверяет только «не 500».
276
+ То есть врёт ли схема — не проверяет никто. Без этого генерация типов стоит на песке
277
+
278
+ **Про нагрузку (спрошено владельцем 2026-08-24):**
279
+
280
+ - [ ] 🔴 **Нагрузочного тестирования нет вообще** — ни k6, ни Locust, ни каталога тестов
281
+ - [ ] 🔴 **Пик памяти отчётов не мерян.** ОСВ по счёту и зарплата строятся `openpyxl` в памяти
282
+ целиком при потолке контейнера 4 ГБ; карточка счёта потоковая. Заказ-гигант падает поздно
283
+ (после минут работы и гигабайта черновиков) — ранняя оценка объёма отсутствует
284
+ - [ ] 🔴 **Очередь не наблюдаема**: глубина и возраст старейшего задания не видны нигде
285
+ - [x] ✅ Снято как ложная тревога: грация остановки `worker_report` — **960 с** против жёсткого
286
+ лимита рендера 900 с (task-252b AC-8). Деплой во время сборки её не добивает
287
+
288
+ ---
289
+
290
+ ## 🎯 Приоритеты (ревизия 2026-07-27)
291
+
292
+ **🔴 Приоритет 1 — реальные дыры с ценой ошибки:**
293
+ 1. **Error tracking (Sentry / GlitchTip)** — прод-исключения не группируются и не алертят. Логи в Loki ≠ трекинг ошибок
294
+ 2. **Бэкап БД + проверенное восстановление** — скриптов нет вообще, данные финансовые
295
+ 3. **`questionnaires` в `pytest.ini testpaths`** — тесты написаны и не запускаются (однострочный фикс, класс ошибки — ложное чувство покрытия)
296
+ 4. **OpenAPI: убрать 37 выброшенных вьюх из Errors** — иначе schemathesis фаззит четверть API вхолостую
297
+
298
+ **🟡 Приоритет 2 — гейты и масштаб данных:**
299
+ 5. **ruff `LOG` + `G` + `DTZ`** — дешёво, ловит класс реальных багов, ложится на observability-правила
300
+ 6. **Наполнить semgrep** (сейчас 2 правила) — канал «AI-находка → детерминированное правило»
301
+ 7. **Закрыть `/api/v1/docs/` и `/schema/` в проде** + `openapi-typescript` для типов фронта
302
+ 8. **`jscpd`** — дублирование кода (не покрыто ничем)
303
+ 9. **PgHero** либо дашборд над `pg_stat_statements` в уже стоящей Grafana
304
+ 10. **`nextcloud` / `questionnaires` / `analytics` в mypy-скоуп** — дрейф списка при заведении новых приложений
305
+
306
+ **🟢 Приоритет 3:**
307
+ 11. Разобрать оставшиеся «зомби-зависимости»: `silk`, `vulture`, `freezegun`, `import-linter` —
308
+ подключить или удалить. `mutmut` закрыт backend-профилем task-236.
309
+ 12. `sqlfluff` для `dbt/` · `deptry` · `verify.sh` (зеркало CI локально) · GitLab CI lint
310
+ 13. Пилот nitpicker-подхода как advisory-канала рядом с Sentinel
311
+ 14. Очистить advisory-baseline (`pip/npm audit`, knip, size-limit, API fuzz) и сделать секции blocking
312
+
313
+ ## ⚪ Осознанно НЕ берём (низкий ROI для нас)
314
+
315
+ code-split (500 внутренних юзеров) · shellcheck · codespell · OTel-трейсинг · trivy/SBOM/OSV ·
316
+ dependency-cruiser / type-coverage / xenon / import-linter-без-контрактов · `PLR too-many-*` (рефакторинг, не гейт) ·
317
+ **django-structlog** (потребность закрыта Loki+Alloy) · **nplusone** (перекрыт zen-queries) ·
318
+ **CodeRabbit / Qodo** (файловый уровень уже закрыт линтерами) · vitest в CI («фронт без тестов»).
319
+
320
+ ## ⛔ Не применимо (мы на GitLab, не GitHub)
321
+
322
+ zizmor · CodeQL workflow-анализ · actionlint — линтеры безопасности **GitHub Actions**.
@@ -0,0 +1,111 @@
1
+ <!-- источник: audit_project/docs/ai/sources-building-with-agents.md -->
2
+ # Источники: как строят софт С агентами (OpenAI + Anthropic + Manus)
3
+
4
+ > **Что это.** Сжатый объединённый разбор статей о разработке с ИИ-агентами. Наши **выводы** — в
5
+ > `memo-decisions.md`; здесь — суть источников с провенансом. Статусы: ✓ первоисточник прочитан · ◐ вторично.
6
+ > Корпус практиков (BitGN) — отдельно в `practitioner-insights.md`.
7
+
8
+ ---
9
+
10
+ ## 1. Харнес-инжиниринг: OpenAI (фев) + Anthropic Managed Agents (апр, новее)
11
+
12
+ **OpenAI «Harness Engineering»** (Ryan Lopopolo, 11.02.2026; ✓ текст у нас, ◐ часть цифр через InfoQ) —
13
+ внутренний продукт **~1М строк, 0 строк руками**, пишет Codex; люди управляют, агенты действуют. Главное:
14
+ - **Среда важнее кода:** «какой возможности не хватает и как сделать её **понятной (legible) и обязательной
15
+ (mandatory)** для агента?» DFS-декомпозиция; цикл Ральфа Виггама (крутить до зелёного).
16
+ - **Agent-legibility:** приложение поднимается **per git-worktree**; Chrome DevTools в рантайме агента (DOM/
17
+ скриншоты) → воспроизводит баг, проверяет фикс; **наблюдаемость per-worktree** (Vector→Victoria, LogQL/
18
+ PromQL/TraceQL) → промпты «старт < 800 мс». Запуски **>6 ч**.
19
+ - **Знания репо = система учёта:** НЕ один толстый AGENTS.md (4 провала: контекст дефицитен / «важно всё» =
20
+ неважно ничего / гниёт / непроверяемо), а **оглавление (~100 строк) + дерево `docs/`** (design-docs,
21
+ exec-plans, generated/db-schema, references/*-llms.txt, QUALITY_SCORE/RELIABILITY/SECURITY); прогрессивное
22
+ раскрытие; линтеры/CI на свежесть; **doc-gardening агент** открывает PR на устаревшее.
23
+ - **«Чего нет в контексте — нет»** → весь контекст кодировать в репо как версионируемые артефакты.
24
+ - **Слоистая архитектура «под агента»:** `Types→Config→Repo→Service→Runtime→UI` + сквозное через `Providers`;
25
+ инварианты держат **кастомные линтеры + структурные тесты** (ошибка линтера **встраивает инструкцию по
26
+ починке**); «обеспечиваем инварианты, не детали»; «архитектура на 100 инженеров — раннее предусловие».
27
+ - **Мерж:** минимум блокирующих гейтов, PR недолговечны, flaky — перезапуском; «фиксы дёшевы, ожидание дорого».
28
+ - **Энтропия/GC:** ручная уборка по пятницам **не прижилась** → «золотые принципы» в репо + фоновые Codex-
29
+ задачи на дрейф (refactor-PR < 1 мин, авто-мерж); техдолг = кредит с высокой ставкой, гасить понемногу.
30
+ - Вывод: **дисциплина — в структуре, а не в коде.**
31
+
32
+ **Anthropic «Managed Agents: Decoupling brain from hands»** (08.04.2026; ✓) — ⚠️ **новее, развивает OpenAI:**
33
+ - Разделить **«мозг» (Claude+харнес)** и **«руки» (песочницы)** за стабильными интерфейсами (`execute()`,
34
+ `getEvents()`); инфра как **«cattle, not pets»** — падает/заменяется независимо.
35
+ - **Харнес кодирует быстро-протухающие допущения о слабостях модели** (логика reset под «context anxiety»
36
+ Sonnet 4.5 стала мёртвым грузом на Opus 4.5) → **виртуализировать**, держать **model-version-agnostic**.
37
+ - **Durable session log ВНЕ контекстного окна** (расследовать прошлое без необратимой обрезки); credentials
38
+ изолированы от генеримого кода; stateless-харнес срезал **p50 TTFT ~60%**.
39
+
40
+ → **для memo:** дерево `docs/` (есть) + QUALITY_SCORE/doc-gardening; agent-legibility = наш трейс + RO-
41
+ телеметрия; жёсткие границы слоёв + линтеры с подсказкой-в-ошибке (когда пойдёт код); brain/hands + session-
42
+ log-вне-контекста; харнес model-agnostic.
43
+
44
+ ---
45
+
46
+ ## 2. Anthropic: дизайн агентов и Claude Code (✓ eng-статьи + доки)
47
+
48
+ **Workflow vs agent:** workflow — заранее заданные пути; agent — «LLM в цикле использует тулы на обратной
49
+ связи из среды». **Начинай просто** (augmented LLM); сложность — только когда измеримо лучше; фреймворки
50
+ скрывают промпты — начинай с сырых API. **Три принципа:** простота · прозрачность · тщательный **ACI**
51
+ (agent-computer interface).
52
+
53
+ **Subagents vs agent teams:** subagent — свой контекст/тулы, **только отчитывается** (дёшево; лучшее —
54
+ ресёрч + **верификация со свежим контекстом**, без confirmation bias); teams (экспериментально) — общаются
55
+ mailbox'ом, общий task-list; дорого (линейно). Старт **3–5**, **5–6 задач** на участника; «три
56
+ сфокусированных > пяти разбросанных»; сильно — **дебаг конкурирующих гипотез** (адверсариально опровергают).
57
+
58
+ **Контекст-инжиниринг:** цель — **«наименьшее множество высокосигнальных токенов»**; context rot (растёт
59
+ число токенов → падает recall); just-in-time retrieval (лёгкие идентификаторы, грузить тулами); три стратегии
60
+ для долгого: **compaction** (саммари у лимита, сохранять решения/баги), **structured note-taking**, **саб**
61
+ (исследует десятки тыс → отдаёт 1–2 тыс саммари).
62
+
63
+ **CLAUDE.md:** читается в начале сессии как **user-сообщение** (влияет, но **не енфорсится** — жёсткое через
64
+ **hook**); порядок широкое→специфичное, конкатенация; вложенные грузятся **по требованию**; корневой
65
+ **переживает `/compact`**, вложенные нет; цель **<200 строк** («раздутый → Claude игнорирует инструкции»).
66
+ `.claude/rules/` с `paths:`-глобами грузятся только при касании файла. Auto-memory: `MEMORY.md` индекс,
67
+ первые 200 строк/25KB.
68
+
69
+ **5 принципов тул-API** (для нашего Runtime API!): (1) **консолидировать** домен-операции, не оборачивать
70
+ эндпоинты (`get_customer_context`, не три геттера); (2) **namespacing** (`asana_search`); (3) **высокосигнальный
71
+ вывод** — естественные имена, не uuid; опц. `response_format` (~⅓ экономии); (4) **токен-эффективность** —
72
+ пагинация/кап (Claude Code 25000 токенов), при усечении говорить как уточнить; (5) **промпт-инжиниринг
73
+ описаний тулов** + **направляющие ошибки** («ожидалось high|medium|low; ты дал 'critical'»). **Тест выбора
74
+ тула:** «если человек не скажет, какой тул применить — агент тем более». **Poka-yoke** (абсолютные пути).
75
+
76
+ **Workflow Claude Code:** Explore→Plan→Code→Commit; **дать способ верификации** (тесты/сборка/линтер/скриншот-
77
+ дифф) + гейты (промпт→`/goal`→**Stop hook**→свежий саб-ревьюер); **показывать доказательство**;
78
+ `AskUserQuestion`→`SPEC.md`→свежая сессия. **5 паттернов провалов:** kitchen-sink (`/clear`) · бесконечные
79
+ коррекции (после 2 — `/clear`+лучший промпт) · переспецифицированный CLAUDE.md · trust-then-verify gap («не
80
+ можешь проверить — не выкатывай») · бесконечный explore.
81
+
82
+ → **для memo:** Runtime API строить по 5 принципам (но для бенчмарка **дозировать «помощь» ошибок** — влияет
83
+ на сложность); анти-чит — хуками/правами, **не текстом промпта** (CLAUDE.md лишь советует); компакшен/auto-
84
+ memory — вектор **утечки между задачами** → для чистых прогонов отключать.
85
+
86
+ ---
87
+
88
+ ## 3. KV-кэш и экономика контекста (Manus + provider-docs; ✓)
89
+
90
+ **«KV-cache hit rate — самая важная метрика продакшн-агента».** Агент в цикле: input:output ≈ **100:1** →
91
+ почти весь расход на input, кэш бьёт ~99% счёта. Кэшированный токен ~**10×** дешевле (Sonnet: $0.30 vs
92
+ $3/MTok) + пропускает prefill (падает TTFT).
93
+
94
+ **Анти-паттерны (и фиксы):**
95
+ - **Нестабильный префикс (#1):** «1 токен инвалидирует кэш с этого места»; **таймстемп-в-секундах в начале
96
+ системного промпта** → 0% hit. Фикс: префикс байт-стабилен, время — в конец/огрубить.
97
+ - **Не-append-only / нестабильный порядок JSON-ключей** → `json.dumps(sort_keys=True)`, особенно для **схем
98
+ тулов**.
99
+ - **Динамика рано** → `tools → system → long-lived → variable` (динамика в конец).
100
+ - **Round-robin роутинг** убивает кэш (кэш локален машине) → **sticky по session-id** / `prompt_cache_key`.
101
+ - Anthropic: 4 брейкпоинта, читать 0.1×/писать 1.25×–2×, минимум ~1024 токена (иначе тихо не кэшируется),
102
+ прогрев `max_tokens:0`.
103
+
104
+ **6 уроков Manus:** проектируй вокруг кэша · **маскируй тулы логитами, не удаляй** (удаление спереди
105
+ инвалидирует кэш) · **файловая система как контекст** (обратимое сжатие: оставлять URL/путь) · **рецитация**
106
+ (`todo.md` толкает цель в недавнее внимание; ~50 вызовов/задача) · **держи ошибки в контексте** («без
107
+ доказательства модель не адаптируется») · **не зафьюшоть себя** (вносить разнообразие).
108
+
109
+ → **для memo:** KV-cache hit rate — кандидат в **метрику качества оцениваемого агента**; наш тул/рантайм-API —
110
+ **байт-стабильный + детерминированно сериализованный** (sorted keys), динамику платформы (task_id, seed) — в
111
+ конец, sticky-роутинг, прогрев общего префикса.