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,127 @@
1
+ #!/usr/bin/env bash
2
+ # tool/selfcheck/gates.sh — проверка записей каталога. Это фильтр на входе: запись, чей
3
+ # арбитр не краснеет на красном образце или не молчит на зелёном, в каталог не
4
+ # попадает. Отбор делает машина, а не внимательность рецензента, — иначе каталог
5
+ # за полгода превращается в свалку правдоподобных утверждений.
6
+ #
7
+ # bash tool/selfcheck/gates.sh
8
+
9
+ set -uo pipefail
10
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
11
+ CAT="$ROOT/kit/gates"
12
+ PASS=0; FAIL=0; WARN=0; UNVERIFIED=0
13
+
14
+ ok() { printf ' \033[32m✔\033[0m %s\n' "$1"; PASS=$((PASS+1)); }
15
+ bad() { printf ' \033[31m✘\033[0m %s\n' "$1"; FAIL=$((FAIL+1)); }
16
+ warn() { printf ' \033[33m!\033[0m %s\n' "$1"; WARN=$((WARN+1)); }
17
+ # «Условная запись» и «нечем проверить здесь» — разные состояния, и счётчики разные.
18
+ skip() { printf ' \033[33m~\033[0m %s\n' "$1"; UNVERIFIED=$((UNVERIFIED+1)); }
19
+
20
+ field() { sed -n "s/^$2:[[:space:]]*\(.*\)$/\1/p" "$1" | head -1; }
21
+
22
+ printf '\n\033[1mtool/selfcheck/gates.sh\033[0m\n\n'
23
+ [ -d "$CAT" ] || { echo " каталога гейтов нет"; exit 1; }
24
+
25
+ for GATE in "$CAT"/*/; do
26
+ SLUG="$(basename "$GATE")"
27
+ YML="$GATE/gate.yml"
28
+
29
+ [ -f "$YML" ] || { bad "$SLUG: нет gate.yml"; continue; }
30
+
31
+ # --- обязательные поля -----------------------------------------------------
32
+ INTENT="$(field "$YML" intent)"
33
+ PROOF="$(field "$YML" proof)"
34
+ [ -n "$INTENT" ] || bad "$SLUG: пустое поле intent — по нему идёт дедупликация"
35
+
36
+ # Заготовка от `aqk new` не должна проехать как запись: незаполненный гейт — мёртвое
37
+ # правило, а мёртвое правило учит игнорировать и живые.
38
+ if grep -q 'ЗАПОЛНИ' "$YML" "$GATE/README.md" "$GATE/check.sh" 2>/dev/null; then
39
+ bad "$SLUG: заготовка не заполнена — остались метки ЗАПОЛНИ"
40
+ continue
41
+ fi
42
+ [ -n "$PROOF" ] || bad "$SLUG: пустое поле proof — «это хорошая практика» не принимается"
43
+ grep -q '^trigger:' "$YML" || bad "$SLUG: нет trigger — запись показывалась бы всем подряд"
44
+
45
+ # Файл, на который не ссылается ни один recipes, — мёртвый вес: рецепт может дискриминировать
46
+ # red/green совсем другой командой, и проверка образцов этого не увидит. Найдено на разборе
47
+ # чужого репозитория: инструмент семь месяцев никто не запускал, и об этом узнали только
48
+ # прогоном, не чтением.
49
+ if [ -f "$GATE/check.sh" ] && ! grep -q 'check\.sh' "$YML"; then
50
+ bad "$SLUG: check.sh есть, но ни один recipes на него не ссылается — мёртвый файл"
51
+ fi
52
+
53
+ # Два раздела README обязательны нормой каталога. Пока их не проверяла машина, четыре записи
54
+ # из четырнадцати жили без раздела про готовый аналог и четыре — без «чего НЕ ловит».
55
+ # Правило нормы, за которым не следит машина, — это пожелание.
56
+ grep -qiE 'готовы(й аналог|й инструмент|е правил)|готового аналога' "$GATE/README.md" 2>/dev/null \
57
+ || bad "$SLUG: в README нет раздела про готовый аналог — «не искал» и «нет» разные утверждения"
58
+ grep -qiE 'чего НЕ ловит' "$GATE/README.md" 2>/dev/null \
59
+ || bad "$SLUG: в README нет раздела «чего НЕ ловит» — граница записи обязана быть названа"
60
+
61
+ case "$PROOF" in
62
+ *incidents/*) : ;;
63
+ *) warn "$SLUG: доказательство не ссылается на журнал шишек — запись условная" ;;
64
+ esac
65
+
66
+ # --- образцы ---------------------------------------------------------------
67
+ # Проверяем переносимым рецептом, если он есть. Если его нет — берём первый рецепт под язык,
68
+ # чью программу видно в системе: запись, которой нужен готовый инструмент, законна (правило
69
+ # «сперва готовое»), но проверить её можно только там, где инструмент стоит.
70
+ RECIPE="$(sed -n 's/^[[:space:]]*any:[[:space:]]*\(.*\)$/\1/p' "$YML" | head -1)"
71
+ if [ -z "$RECIPE" ]; then
72
+ # Каким рецептом написаны образцы — говорит сама запись. Угадывать нельзя: в системе может
73
+ # стоять npx, и питоновские образцы поедут проверяться фронтовым инструментом. Так и вышло.
74
+ FOR="$(sed -n 's/^samples_for:[[:space:]]*\(.*\)$/\1/p' "$YML" | head -1)"
75
+ if [ -z "$FOR" ]; then
76
+ bad "$SLUG: нет ни рецепта any, ни поля samples_for — нечем проверить образцы"
77
+ continue
78
+ fi
79
+ RECIPE="$(sed -n "s/^[[:space:]]*$FOR:[[:space:]]*\(.*\)\$/\1/p" "$YML" | head -1)"
80
+ if [ -z "$RECIPE" ]; then
81
+ bad "$SLUG: samples_for указывает на «$FOR», а такого рецепта нет"
82
+ continue
83
+ fi
84
+ PROG="$(printf '%s' "$RECIPE" | awk '{print $1}')"
85
+ if ! command -v "$PROG" >/dev/null 2>&1; then
86
+ skip "$SLUG: НЕ ПРОВЕРЕНА здесь — нужен «$PROG»"
87
+ continue
88
+ fi
89
+ fi
90
+ if [ ! -d "$GATE/red" ] || [ ! -d "$GATE/green" ]; then
91
+ bad "$SLUG: нет красного или зелёного образца"; continue
92
+ fi
93
+
94
+ # Прогон арбитра по образцу. Возвращаем и код, и вывод: код возврата в одиночку
95
+ # обманчив — отсутствующий скрипт тоже даёт ненулевой код, и «гейт покраснел»
96
+ # неотличимо от «гейта нет». Урок audit_project 2026-08-27, п. 11.
97
+ probe() {
98
+ local cmd; cmd="$(echo "$RECIPE" | sed "s|{gate}|$GATE|; s|{dir}|$1|")"
99
+ OUT="$(eval "$cmd" 2>&1)"; CODE=$?
100
+ }
101
+
102
+ probe "$GATE/red"; RED_CODE=$CODE; RED_OUT="$OUT"
103
+ probe "$GATE/green"; GRN_CODE=$CODE; GRN_OUT="$OUT"
104
+
105
+ if [ "$RED_CODE" -eq 127 ] || [ "$GRN_CODE" -eq 127 ]; then
106
+ bad "$SLUG: арбитр не запускается — команда не найдена"
107
+ elif [ "$RED_CODE" -eq 0 ]; then
108
+ bad "$SLUG: арбитр промолчал на КРАСНОМ образце — гейт не ловит брак"
109
+ elif [ -z "$RED_OUT" ]; then
110
+ bad "$SLUG: арбитр покраснел на красном молча — по коду возврата не видно, ту ли поломку он нашёл"
111
+ elif [ "$GRN_CODE" -ne 0 ]; then
112
+ bad "$SLUG: арбитр покраснел на ЗЕЛЁНОМ образце — гейт ругается на исправный код"
113
+ else
114
+ ok "$SLUG"
115
+ fi
116
+ done
117
+
118
+ printf '\n'
119
+ if [ "$FAIL" -eq 0 ]; then
120
+ printf ' \033[32mзаписей принято: %s\033[0m' "$PASS"
121
+ else
122
+ printf ' \033[31mотклонено: %s из %s\033[0m' "$FAIL" "$((PASS+FAIL))"
123
+ fi
124
+ [ "$WARN" -gt 0 ] && printf ' \033[33m(условных: %s)\033[0m' "$WARN"
125
+ [ "$UNVERIFIED" -gt 0 ] && printf ' \033[33m(не проверено здесь: %s)\033[0m' "$UNVERIFIED"
126
+ printf '\n\n'
127
+ exit "$FAIL"