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,64 @@
1
+ # Методички: разработка с агентами
2
+
3
+ > **Что это за папка.** Полный корпус про разработку, когда код пишет агент. Раскладывается в
4
+ > проект командой `aqk init` как `.aqk/docs/`.
5
+ >
6
+ > **Одна документация, без сокращённых копий.** Здесь лежат полные тексты. Если что-то кажется
7
+ > лишним — это удаляется целиком и обоснованно, а не подрезается кусками.
8
+ >
9
+ > **Проверяемое живёт не здесь.** Здесь текст, который агент может проигнорировать. То, что держит
10
+ > машина, — в `kit/gates/` (команда плюс красный и зелёный образец) и в `.aqk.yml` проекта.
11
+
12
+ ## С чего начинать
13
+
14
+ | Если вы… | Читайте |
15
+ |---|---|
16
+ | ведёте проект как **владелец**, а не как программист | [Стратегия разработки приложений](app-owner-strategy.md) |
17
+ | хотите список **что обязано быть на проекте**, без привязки к языку | [Обязательный минимум проекта](project-baseline.md) |
18
+ | поднимаете **новый проект** с нуля | [Плейбук харнеса](agent-harness-playbook.md) |
19
+ | хотите понять, **как работать каждый день** | [Плейбук харнеса](agent-harness-playbook.md), раздел 18 |
20
+ | хотите увидеть **процесс по этапам** | [SDLC эпохи агентов](ai-sdlc.md) |
21
+ | ищете **готовое правило**, прежде чем писать своё | [Готовые правила](../ready-made-rules.md) |
22
+ | ставите **гейты** и хотите отличить работающий от мёртвого | `kit/gates/README.md` — норма записи, храповик, четыре способа вранья |
23
+
24
+ ## 1. Наше — применяется в работе
25
+
26
+ | Документ | О чём | Класс |
27
+ |---|---|---|
28
+ | [`agent-harness-playbook.md`](agent-harness-playbook.md) | чек-лист «День 0»: конфиги, линтеры, хуки, CI, Docker. Раздел 18 — дисциплина в каждой задаче | PORTABLE |
29
+ | [`project-baseline.md`](project-baseline.md) | что обязано быть на любом проекте, чтобы работу можно было отдать машине. Назначение без названий инструментов | PORTABLE |
30
+ | [`ai-sdlc.md`](ai-sdlc.md) | процесс по этапам: от «зачем» до эксплуатации. Отвечает «в каком порядке», а не «каким инструментом» | CURRENT |
31
+ | [`app-owner-strategy.md`](app-owner-strategy.md) | документ владельца: бизнес-ТЗ → ограничения → сайзинг → тех-дизайн | OWNER DOCTRINE |
32
+
33
+ Журнал шишек лежит отдельно, в корне комплекта: `incidents/README.md`. Он общий на все проекты и
34
+ пользователю не раскладывается.
35
+
36
+ ## 2. Чужое — доказательная база со сверкой
37
+
38
+ Датированные снимки. Ресёрч от указанной даты не перестаёт быть правдой о том, что было прочитано,
39
+ но перестаёт быть правдой о том, что есть сейчас. Где свежий файл перебивает старый, это отмечено
40
+ внутри пометкой «⚠️ обновляет».
41
+
42
+ | Документ | О чём | Дата сбора |
43
+ |---|---|---|
44
+ | [`anthropic-ai-native-sdlc-2026-08.md`](anthropic-ai-native-sdlc-2026-08.md) | плейбук Anthropic по перестройке SDLC под агентов, разобранный по шести стадиям | 2026-08-26 |
45
+ | [`ai-native-development.md`](ai-native-development.md) | практики из двух каналов, каждая с отметкой «есть у нас / нет» | 2026-08-25 |
46
+ | [`stream-2026-08-ai-coding-panel.md`](stream-2026-08-ai-coding-panel.md) | панель практиков: 🎙 мнение · 📏 замер · ⚖️ спорно | 2026-08-24 |
47
+ | [`quality-gates-checklist.md`](quality-gates-checklist.md) | снимок 98 гейтов audit_project со статусами — сырьё каталога гейтов | 2026-08-24 |
48
+ | [`harness-best-practices.md`](harness-best-practices.md) | каталог приёмов, снятых с чужих харнесов; устройство собственного агента исключено | 2026-07-13 |
49
+ | [`deep-research-2026-07.md`](deep-research-2026-07.md) | gap-ресёрч: харнес · безопасность · качество кода · платформы | 2026-07-05 |
50
+ | [`sources-building-with-agents.md`](sources-building-with-agents.md) | статьи OpenAI / Anthropic / Manus, с провенансом | 2026-07 |
51
+
52
+ ## 3. Что отсюда убрано и куда
53
+
54
+ Ничего не подрезано кусками. Убраны только настоящие дубли — тексты, существовавшие в двух местах:
55
+
56
+ | Было | Куда ушло целиком |
57
+ |---|---|
58
+ | `how-we-work.md` | `agent-harness-playbook.md`, раздел 18 |
59
+ | `harness-lessons.md` | `incidents/README.md`, запись 2026-08-27 |
60
+ | разделы «Скиллы» из `how-we-work.md` | `agent-harness-playbook.md`, раздел 13 |
61
+ | правила кода и тестов из плейбука | `kit/rules/` — там они источник истины, в плейбуке указатель |
62
+
63
+ Статусы «у нас» внутри чужих файлов относятся к `audit_project` и проверяются по коду, а не по
64
+ этим документам: статусы в документах устаревают молча.
@@ -0,0 +1,261 @@
1
+ ---
2
+ title: Обязательный минимум проекта — что должно быть, чтобы код писала машина
3
+ description: Список того, что обязано существовать на любом проекте, на любом языке, чтобы работу можно было отдать агентам и при этом видеть брак. Без названий инструментов — только назначение.
4
+ tags:
5
+ - topic/ai
6
+ - kind/checklist
7
+ ---
8
+
9
+ # Обязательный минимум проекта
10
+
11
+ > **Зачем этот файл.** Цель владельца — «тёмная фабрика»: цех, где работа идёт круглосуточно и
12
+ > людей у станка нет. Свет не нужен машине — но машине нужно другое: **видеть, что она делает,
13
+ > ловить собственный брак и уметь остановиться**. Здесь перечислено ровно то, что для этого
14
+ > обязано быть на проекте.
15
+ >
16
+ > **Как читать.** Никаких названий библиотек: они разные в каждом языке и устаревают за год.
17
+ > Написано **назначение** — что должно уметь. Подбирать инструмент под язык — отдельная работа,
18
+ > и она простая, когда известно, что именно ищешь.
19
+ >
20
+ > **Проверка себя на любом пункте:** «если это сломается — я узнаю сам, или мне расскажет
21
+ > пользователь?» Второй ответ означает, что пункт не выполнен.
22
+
23
+ ---
24
+
25
+ ## 0. Главный принцип
26
+
27
+ **Тёмная фабрика держится не на умных станках, а на приборах и на упорах.**
28
+
29
+ - **Прибор** — показывает, что происходит: сколько, как быстро, где встало.
30
+ - **Упор** (гейт) — не пускает брак дальше: не собралось, не сошлось, не по правилу — стоп.
31
+ - **Арбитр** — независимо отвечает «правильно или нет», и его нельзя уговорить.
32
+
33
+ Всё, что ниже, — это приборы, упоры и арбитры. Если чего-то из трёх нет, работу нельзя отдать
34
+ машине: она будет производить брак быстро и молча.
35
+
36
+ ---
37
+
38
+ ## 1. Воспроизводимость: одинаково у всех и всегда
39
+
40
+ 1. **Одна команда поднимает проект целиком.** Не «установи, настрой, потом запусти» — одна.
41
+ 2. **Точные версии всего**, что участвует в сборке, записаны в файл и хранятся в репозитории.
42
+ Не «примерно та же версия» — точная.
43
+ 3. **Среда одинакова** на машине разработчика, в конвейере и на сервере. Расхождение сред — это
44
+ класс ошибок, который невозможно поймать тестами: «у меня работает» и есть его симптом.
45
+ 4. **Настройки приходят снаружи** (переменные окружения), а не лежат в коде. Один и тот же
46
+ собранный артефакт должен уметь работать и в тесте, и в бою.
47
+ 5. **Секреты не хранятся в коде вообще.** Ни в истории, ни в примерах, ни в тестах.
48
+
49
+ ---
50
+
51
+ ## 2. Упоры на входе в репозиторий
52
+
53
+ Срабатывают до того, как код попал в общую ветку. Каждый — быстрый, иначе его начнут обходить.
54
+
55
+ 6. **Форматирование** — единый вид кода, применяется автоматически. Спор о пробелах должен быть
56
+ невозможен.
57
+ 7. **Линтер** — ловит подозрительные конструкции и заведомые ошибки без запуска кода.
58
+ 8. **Проверка типов** — если язык её поддерживает. Это самый дешёвый способ поймать «передал не
59
+ то» до запуска.
60
+ 9. **Поиск секретов** — ключ, пароль, токен не должны попадать в историю. Из истории их потом не
61
+ вычистить.
62
+ 10. **Ограничение размера файла** — и продуктового, и тестового. Файл, который не помещается в
63
+ поле внимания, перестают читать: и человек, и машина.
64
+ 11. **Свои инварианты проекта** — то, чего нет в готовых линтерах: «отладочная печать запрещена»,
65
+ «пометки „доделать“ запрещены», «невидимые символы запрещены», «вход разбирается на границе,
66
+ а не по месту», «широкая ловушка ошибок обязана либо записать причину, либо пробросить».
67
+ 12. **Проверка, что структура описана** — если в проекте есть карта («что где лежит»), добавление
68
+ модуля без правки карты не проходит.
69
+
70
+ **Важнее списка — форма сообщения.** Отказ обязан говорить: что нарушено, где, **и как починить**.
71
+ Отказ без инструкции превращается в «обойди меня».
72
+
73
+ ---
74
+
75
+ ## 3. Арбитры правильности
76
+
77
+ 13. **Тест, проверяющий поведение через внешнюю границу** — не внутренности. Вызвал как
78
+ пользователь, проверил ответ и состояние хранилища. Такой тест переживает переписывание кода;
79
+ тест на внутренности — нет.
80
+ 14. **Отдельные быстрые тесты на чистую логику** — расчёты, преобразования, разборы. Их много и
81
+ они дешёвые.
82
+ 15. **Эталон от авторитетного источника** там, где он есть: отчёт, выгрузка, документ. Сверка
83
+ «до копейки» с внешним источником сильнее любого написанного нами теста, потому что источник
84
+ не подстраивается под нас.
85
+ 16. **Прогон на живой системе перед сдачей** — как пользователь, через настоящий вход. Мок-тесты
86
+ структурно слепы на «швах»: сеть, прокси, перезапуски, регистрация фоновых задач, права.
87
+ 17. **Правило про количество:** тестов должно быть столько, сколько нужно для доказательства.
88
+ Мера — не проценты, а вопрос: «если поведение сломается, что покраснеет?» Если ответ «ничего» —
89
+ тестов мало. Если «двести тестов, и все про одно» — их много.
90
+ 18. **Тест на исправленный дефект.** Каждый прод-баг превращается в тест до того, как его чинят.
91
+
92
+ ---
93
+
94
+ ## 4. Конвейер
95
+
96
+ 19. **Собирается один артефакт** и он же едет во все среды. Пересборка под каждую среду означает,
97
+ что проверяли не то, что выкатили.
98
+ 20. **Дешёвое раньше дорогого**: форматирование и линт — секунды, тесты — минуты, тяжёлое — ночью.
99
+ 21. **Ясно, что блокирует, а что советует.** «Советует» допустимо временно и с зафиксированным
100
+ уровнем: не хуже, чем сейчас. Вечный совет — это украшение, его перестают читать.
101
+ 22. **Ветка, из которой выкатывают, защищена**: попасть туда можно только зелёным.
102
+ 23. **Откат дешевле починки.** Предыдущий артефакт лежит рядом и поднимается одной командой.
103
+ 24. ⚠️ **Тишина конвейера — это отказ, а не успех.** Обязательна проверка, что прогон вообще
104
+ случился: правка, не попавшая в список отслеживаемых путей, не запускает проверок — и не
105
+ появляется кнопка выката. Выглядит как «всё хорошо».
106
+
107
+ ---
108
+
109
+ ## 5. Приборы: наблюдаемость
110
+
111
+ 25. **Логи структурные** — не строки для глаз, а записи с полями, по которым можно искать.
112
+ 26. **Сквозной идентификатор запроса** проходит через все части системы. Без него нельзя собрать
113
+ историю одного случая.
114
+ 27. **Логи собираются в одно место** и хранятся столько, сколько нужно, чтобы разобрать
115
+ вчерашний инцидент.
116
+ 28. **Метрики четырёх видов**, минимум: сколько запросов, сколько ошибок, как быстро (по худшим
117
+ случаям, не по среднему), сколько ресурсов занято.
118
+ 29. **Очереди фоновых задач видны**: глубина и **возраст самой старой задачи**. Очередь, которая
119
+ встала, снаружи выглядит как «медленно работает».
120
+ 30. **Ошибки собираются отдельно от логов**, группируются по типу и умеют сообщить о новом типе.
121
+ Лог — это поток, в котором ошибка тонет; трекер ошибок — это список того, что сломалось.
122
+ 31. **Тревога только на то, из-за чего вы готовы встать ночью.** Остальное — отчёт, а не тревога.
123
+ Прибор, который звенит постоянно, выключают.
124
+ 32. **К каждой тревоге — короткая инструкция**, что делать. Иначе разбираться будет тот, кто её
125
+ получил, с нуля и в три часа ночи.
126
+ 33. **PII и секреты в логи не попадают** — ни в поля, ни в тексты ошибок.
127
+
128
+ ---
129
+
130
+ ## 5-бис. Приборы на сам процесс, а не только на продукт
131
+
132
+ Раздел выше — про то, как живёт **система**. Этот — про то, как живёт **производство**. На тёмной
133
+ фабрике это единственный способ понять, что цех работает, а не имитирует работу.
134
+
135
+ Ниже — пять семейств. Мерить всё сразу не нужно; нужно знать, чего у вас нет.
136
+
137
+ **А. Скорость потока (четыре классических)**
138
+ - сколько времени проходит **от правки до боя** — главный показатель, всё остальное его объясняет;
139
+ - **как часто выкатываем** — редкий выкат означает крупные партии, а крупная партия ломается дороже;
140
+ - **какая доля выкатов ломает** прод;
141
+ - **сколько занимает восстановление** после поломки. Быстрое восстановление ценнее редких поломок.
142
+
143
+ **Б. Из чего складывается время** — чтобы знать, что чинить: время до первого коммита у новичка ·
144
+ время сборки · время прогона проверок · доля падений конвейера · время до первого ревью · сколько
145
+ раз изменение возвращается на доработку · размер изменения.
146
+
147
+ **В. Качество проверок** — тот самый раздел, ради которого мы весь день работали: доля
148
+ автоматизированных проверок · **доля пропущенных (`skip`) тестов** · **доля неустойчивых тестов**,
149
+ которые падают через раз. Неустойчивый тест хуже отсутствующего: он приучает перезапускать, не
150
+ глядя.
151
+
152
+ **Г. Качество тревог** — приборы про приборы: сколько тревог приходит на человека · какая доля
153
+ из них не требует действий · сколько тревог **никто не открывал ни разу**. Тревога, на которую
154
+ никто не реагирует, — это выключенный прибор, который выглядит включённым.
155
+
156
+ **Д. Нагрузка на голову** — сложность кода · сколько инструментов нужно тронуть ради одной правки ·
157
+ сколько людей должны договориться. Для тёмной фабрики это переводится так: **сколько мест нужно
158
+ изменить, чтобы поменять одно правило.** Если больше трёх — правило разъедется.
159
+
160
+ **Как этим пользоваться, чтобы не навредить.** Метрика — термометр, а не цель: как только по ней
161
+ начинают отчитываться, её начинают улучшать напрямую, и она перестаёт что-либо показывать. Смотреть
162
+ на них надо парами, где одна сдерживает другую: скорость выката — вместе с долей поломок; число
163
+ тестов — вместе с долей неустойчивых; число тревог — вместе с долей бесполезных.
164
+
165
+ **Минимум, с которого стоит начать:** доля поломанных выкатов, время восстановления, доля
166
+ неустойчивых тестов, доля тревог без действия. Четыре числа отвечают на вопрос «фабрика работает
167
+ или имитирует».
168
+
169
+ ---
170
+
171
+ ## 6. Сохранность
172
+
173
+ 34. **Резервная копия данных по расписанию** — и **проверенное восстановление**. Копия, которую ни
174
+ разу не разворачивали, копией не является.
175
+ 35. **Копия лежит не на том же диске**, что и сама база.
176
+ 36. **Тревога на отсутствие свежей копии.** Бэкап ломается молча: вчера он был, сегодня его нет,
177
+ и узнают об этом в день аварии.
178
+ 37. **Файлы пользователей защищены правами**, а не незнанием адреса. Ссылка, которую нельзя
179
+ угадать, — это не право доступа.
180
+ 38. **Понятно, что делать при потере**: срок, за который данные восстанавливаются, и объём, который
181
+ допустимо потерять, названы числами заранее.
182
+
183
+ ---
184
+
185
+ ## 7. Что нужно именно машине (а не человеку)
186
+
187
+ 39. **Проект читается машиной**: где что лежит, как запустить, как проверить — записано в
188
+ репозитории, а не в голове.
189
+ 40. **У агента есть способ проверить себя**: запустить тесты, поднять приложение, прочитать логи,
190
+ посмотреть метрики. Без этого он вынужден заканчивать словами «готово», и это слово ничего не
191
+ стоит.
192
+ 41. **Сообщение об ошибке — это подсказка агенту.** Инструкция в тексте отказа стоит дешевле, чем
193
+ любые объяснения в документации: она приходит ровно в тот момент, когда нужна.
194
+ 42. **Правила живут в репозитории и версионируются** вместе с кодом. Правило в переписке не
195
+ существует.
196
+ 43. **Знание фиксируется там, где оно понадобится**: решение — рядом с решением, предупреждение —
197
+ рядом с опасным местом.
198
+
199
+ ---
200
+
201
+ ## 8. Дисциплина против самообмана — самое важное
202
+
203
+ Этот раздел отличает работающую фабрику от красивой. Всё выше можно поставить и получить
204
+ **видимость** защиты.
205
+
206
+ 44. **У каждого упора должен быть образец, на котором он обязан сработать.** Файл с нарушением —
207
+ отказ; чистый файл — молчание. Оба образца лежат в репозитории и проверяются на каждом прогоне.
208
+ Упор без образца доказывает лишь то, что он запускается.
209
+ 45. **Ломай упор нарочно и смотри, заметил ли это образец.** Иначе рано или поздно получится
210
+ сторож, который зелен всегда — и никто не узнает.
211
+ 46. **Проверка обязана выносить вердикт словом**, а не пустым выводом. Пустой вывод читается как
212
+ «прошло» и оказывается «не проверялось».
213
+ 47. **Долг записывается поимённо и может только убывать.** Список исключений с причинами — это
214
+ очередь. Список без причин — это индульгенция.
215
+ 48. **Условие внедрения записывается машинно, а не словами.** «Когда появятся такие-то файлы —
216
+ завести проверку» само не сработает: нужен скрипт, который читает репозиторий и говорит
217
+ «условие наступило, сторожа нет».
218
+ 49. **Документ, утверждающий, что защита есть, ничего не доказывает.** Проверяется замером, а не
219
+ чтением. Запись о состоянии устаревает молча.
220
+ 50. **Повторившийся дефект превращается в упор**, а не в напоминание быть внимательнее. Дисциплина
221
+ не масштабируется, механика — да.
222
+
223
+ ---
224
+
225
+ ## 9. Порядок внедрения на новом проекте
226
+
227
+ 1. **Сначала воспроизводимость** (§1). Пока среда разъезжается, всё остальное меряет шум.
228
+ 2. **Потом упоры на входе** (§2) — они дешёвые и дают эффект сразу.
229
+ 3. **Потом один настоящий арбитр** (§3): один сквозной тест «как пользователь», который падает,
230
+ когда сломано. Один настоящий важнее двадцати формальных.
231
+ 4. **Потом конвейер** (§4) — чтобы упоры и арбитр работали без вас.
232
+ 5. **Потом приборы** (§5) — когда есть что наблюдать.
233
+ 6. **Сохранность** (§6) — до того, как появятся данные, которые жалко потерять, а не после.
234
+ 7. **Образцы для упоров** (§8) — вместе с каждым упором, а не «потом».
235
+
236
+ **Чего не делать:** ставить инструмент, которому нечего охранять. Упор без объекта — это шум,
237
+ который приучает игнорировать отказы.
238
+
239
+ ---
240
+
241
+ ## 10. Как проверить, что фабрика правда тёмная
242
+
243
+ Семь вопросов. Ответ «не знаю» равен «нет».
244
+
245
+ 1. Если сломается — я узнаю раньше пользователя?
246
+ 2. Если упор сломается — я узнаю? Чем именно?
247
+ 3. Могу ли я поднять систему заново на чистой машине одной командой?
248
+ 4. Разворачивали ли мы резервную копию хоть раз?
249
+ 5. Могу ли я по одному идентификатору собрать историю одного случая целиком?
250
+ 6. Знаю ли я, где у меня нет арбитра вовсе — то есть где я полагаюсь на слово?
251
+ 7. Что случится, если я не буду смотреть на проект неделю?
252
+
253
+ Последний вопрос — и есть определение тёмной фабрики.
254
+
255
+ ---
256
+
257
+ ## Связанное
258
+
259
+ - Инструменты и конфигурации нашего проекта — [`agent-harness-playbook.md`](agent-harness-playbook.md)
260
+ - Процесс по этапам — [`ai-sdlc.md`](ai-sdlc.md)
261
+ - Наша дисциплина и её история — [`agent-harness-playbook.md` §18](agent-harness-playbook.md)