agent-quality-kit 0.10.1 → 0.12.0

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 (67) hide show
  1. package/README.md +10 -3
  2. package/README.ru.md +10 -3
  3. package/kit/gates/_native.sh +4 -0
  4. package/kit/gates/_skip.sh +7 -0
  5. package/kit/gates/api-contract-has-arbiter/check.sh +7 -0
  6. package/kit/gates/color-from-token/check.sh +7 -0
  7. package/kit/gates/commit-explains-itself/check.sh +8 -2
  8. package/kit/gates/complexity-limit/check.sh +22 -4
  9. package/kit/gates/complexity-limit/gate.yml +7 -2
  10. package/kit/gates/complexity-limit/red/deep.js +15 -0
  11. package/kit/gates/dead-code/gate.yml +5 -0
  12. package/kit/gates/duplicate-code/check.sh +7 -0
  13. package/kit/gates/duplicate-code/gate.yml +10 -1
  14. package/kit/gates/file-size-limit/check.sh +7 -0
  15. package/kit/gates/file-size-limit/red/big.js +600 -0
  16. package/kit/gates/gate-not-weakened/check.sh +7 -0
  17. package/kit/gates/gate-not-weakened/green/suppress.js +4 -0
  18. package/kit/gates/gate-not-weakened/red/suppress.js +5 -0
  19. package/kit/gates/mcp-server-resolves/check.sh +7 -0
  20. package/kit/gates/no-phantom-package/check.sh +7 -0
  21. package/kit/gates/no-print-in-prod/gate.yml +8 -3
  22. package/kit/gates/personal-config-not-shared/check.sh +7 -0
  23. package/kit/gates/secrets-not-in-code/check.sh +7 -0
  24. package/kit/gates/secrets-not-in-code/gate.yml +20 -0
  25. package/kit/gates/secrets-not-in-code/green/config.js +4 -0
  26. package/kit/gates/secrets-not-in-code/red/leak.js +6 -0
  27. package/kit/gates/swallowed-error/gate.yml +8 -3
  28. package/kit/gates/test-has-assertion/check.sh +7 -0
  29. package/kit/gates/test-has-assertion/green/checkout.test.js +5 -0
  30. package/kit/gates/test-has-assertion/red/checkout.test.js +8 -0
  31. package/kit/gates/test-not-adjusted/check.sh +8 -2
  32. package/kit/gates/todo-without-task/check.sh +7 -0
  33. package/kit/gates/todo-without-task/gate.yml +7 -2
  34. package/kit/gates/todo-without-task/green/app.js +2 -0
  35. package/kit/gates/todo-without-task/red/later.js +4 -0
  36. package/llms.txt +4 -2
  37. package/package.json +1 -1
  38. package/tool/commands/badge.mjs +1 -1
  39. package/tool/commands/context.mjs +3 -1
  40. package/tool/commands/doctor.mjs +94 -152
  41. package/tool/commands/gates.mjs +3 -2
  42. package/tool/commands/probe.mjs +284 -44
  43. package/tool/commands/report.mjs +1 -1
  44. package/tool/commands/vitals.mjs +6 -1
  45. package/tool/i18n/en-docs.mjs +2 -1
  46. package/tool/i18n/en-gates.mjs +23 -5
  47. package/tool/i18n/en.mjs +16 -0
  48. package/tool/i18n/ru-docs.mjs +2 -1
  49. package/tool/i18n/ru-gates.mjs +24 -6
  50. package/tool/i18n/ru.mjs +16 -0
  51. package/tool/lib/adopt.mjs +98 -0
  52. package/tool/lib/cadence.mjs +36 -1
  53. package/tool/lib/execution.mjs +50 -1
  54. package/tool/lib/history.mjs +89 -8
  55. package/tool/lib/prove.mjs +2 -2
  56. package/tool/lib/repo.mjs +47 -0
  57. package/tool/lib/run.mjs +194 -0
  58. package/tool/selfcheck/gates.sh +42 -4
  59. package/tool/selfcheck/smoke/_fixture.mjs +24 -2
  60. package/tool/selfcheck/smoke/fail-closed.test.mjs +112 -0
  61. package/tool/selfcheck/smoke/own-samples.test.mjs +131 -0
  62. package/tool/selfcheck/units-cadence.mjs +37 -1
  63. package/tool/selfcheck/units-execution.mjs +78 -1
  64. package/tool/selfcheck/units-level.mjs +24 -0
  65. package/tool/selfcheck/units-probe.mjs +385 -22
  66. package/tool/selfcheck/units-repo.mjs +123 -1
  67. package/tool/selfcheck/units.mjs +34 -1
package/README.md CHANGED
@@ -14,13 +14,18 @@ Your `AGENTS.md` says what the project promises. Nothing checks that those promi
14
14
  that the commands it lists even run. AQK is that missing layer: one command reads the repository,
15
15
  reports a level from AQK-0 to AQK-3, and names every guard that is missing.
16
16
 
17
+ And one step further than the tools next door: `probe` plants a known defect into a copy of your
18
+ project and checks whether your **declared** guards actually go red. "Tests exist" and "tests
19
+ catch" are different claims — readiness scores measure the first one.
20
+
17
21
  ```bash
18
22
  npx agent-quality-kit doctor # code already exists: your level and what to install
19
23
  npx agent-quality-kit start # no code yet: day-zero guards, right away
20
24
  ```
21
25
 
22
26
  `doctor` only reads. It writes no file and sends nothing anywhere — safe to point at a repository
23
- you have decided nothing about yet. Nothing to install: `npx` fetches the package (230 KB).
27
+ you have decided nothing about yet. Nothing to install: `npx` fetches the package (574.1 kB, measured 2026-09-10 — nothing guards this number, so check it
28
+ when it matters).
24
29
 
25
30
  The one exception, named here because it is the only one: with `--brief` (how the hooks run it)
26
31
  `doctor` asks the npm registry for its own latest version — **at most once a day, never in CI**,
@@ -41,6 +46,8 @@ Go, Rust, Java, Ruby, PHP, C#, Kotlin, Swift, Scala. Where the project already h
41
46
  says so out loud when it falls back.
42
47
 
43
48
  **Requirements:** Node 18+ and an `sh` shell. Present on macOS, Linux and WSL; Git Bash on Windows.
49
+ On Windows the gates run through Git Bash even when `bash` on your PATH is the WSL stub in
50
+ `System32` — it is found next to `git.exe`; set `AQK_BASH` to point elsewhere.
44
51
 
45
52
  ### One movement, and everything follows from it
46
53
 
@@ -340,7 +347,7 @@ Already using [pre-commit](https://pre-commit.com)? Three lines in the file you
340
347
  ```yaml
341
348
  repos:
342
349
  - repo: https://github.com/arsen-ask-lx/Agent_Quality_Kit
343
- rev: v0.10.1
350
+ rev: v0.12.0
344
351
  hooks:
345
352
  - id: aqk # runs what the repository declares; blocks below AQK-1
346
353
  # - id: aqk-doctor # read-only: the level and what is missing, blocks nothing
@@ -361,7 +368,7 @@ layer AQK adds.
361
368
  [![on the GitHub Marketplace](https://img.shields.io/badge/GitHub%20Marketplace-Agent%20Quality%20Kit-2ea44f?logo=github)](https://github.com/marketplace/actions/agent-quality-kit-aqk)
362
369
 
363
370
  ```yaml
364
- - uses: arsen-ask-lx/Agent_Quality_Kit@v0.10.1
371
+ - uses: arsen-ask-lx/Agent_Quality_Kit@v0.12.0
365
372
  with:
366
373
  min: 1 # the build fails below AQK-1, or if any declared gate failed
367
374
  ```
package/README.ru.md CHANGED
@@ -14,6 +14,10 @@
14
14
  вообще перечисленные там команды. AQK — тот самый недостающий слой: одна команда читает
15
15
  репозиторий, называет ступень от AQK-0 до AQK-3 и перечисляет каждого недостающего сторожа.
16
16
 
17
+ И один шаг дальше, чем соседние инструменты: `probe` подсаживает заведомый дефект в копию вашего
18
+ проекта и смотрит, покраснеет ли **объявленная** защита. «Тесты есть» и «тесты ловят» — разные
19
+ утверждения, и оценки готовности меряют первое.
20
+
17
21
  ```bash
18
22
  npx agent-quality-kit doctor # код уже есть: уровень и что поставить
19
23
  npx agent-quality-kit start # кода ещё нет: сторожа дня 0 сразу
@@ -21,7 +25,8 @@ npx agent-quality-kit start # кода ещё нет: сторожа дня
21
25
 
22
26
  `doctor` только читает: ни одного файла не пишет и никуда ничего не отправляет — его можно
23
27
  направить на репозиторий, о котором ещё ничего не решено. Ставить ничего не нужно, `npx` скачает
24
- пакет сам (230 КБ).
28
+ пакет сам (574.1 kB, замер 2026-09-10 — это число не сторожит никто, так что при случае
29
+ перемерьте).
25
30
 
26
31
  Единственное исключение, и названо оно здесь именно потому, что единственное: с `--brief`
27
32
  (так его запускают хуки) `doctor` спрашивает у реестра npm свою последнюю версию — **не чаще
@@ -43,6 +48,8 @@ TypeScript, Go, Rust, Java, Ruby, PHP, C#, Kotlin, Swift, Scala. Там, где
43
48
  сообщает, когда откатилась на переносимый.
44
49
 
45
50
  **Требуется:** Node 18+ и оболочка `sh`. Есть на macOS, Linux и в WSL; на Windows — Git Bash.
51
+ На Windows гейты идут через Git Bash, даже если `bash` в PATH — заглушка WSL из `System32`:
52
+ он ищется рядом с `git.exe`; другой путь задаётся `AQK_BASH`.
46
53
 
47
54
  ### Одно движение, из которого следует всё остальное
48
55
 
@@ -343,7 +350,7 @@ aqk badge --check # в конвейере: код 1 в тот день, ког
343
350
  ```yaml
344
351
  repos:
345
352
  - repo: https://github.com/arsen-ask-lx/Agent_Quality_Kit
346
- rev: v0.10.1
353
+ rev: v0.12.0
347
354
  hooks:
348
355
  - id: aqk # запускает объявленное; роняет коммит ниже AQK-1
349
356
  # - id: aqk-doctor # только осмотр: уровень и чего не хватает, ничего не роняет
@@ -362,7 +369,7 @@ repos:
362
369
  [![в GitHub Marketplace](https://img.shields.io/badge/GitHub%20Marketplace-Agent%20Quality%20Kit-2ea44f?logo=github)](https://github.com/marketplace/actions/agent-quality-kit-aqk)
363
370
 
364
371
  ```yaml
365
- - uses: arsen-ask-lx/Agent_Quality_Kit@v0.10.1
372
+ - uses: arsen-ask-lx/Agent_Quality_Kit@v0.12.0
366
373
  with:
367
374
  min: 1 # сборка падает ниже AQK-1 или если упал любой объявленный гейт
368
375
  ```
@@ -21,6 +21,10 @@ shift || true
21
21
  [ "$#" -gt 0 ] || { echo "нечего запускать: не передана команда инструмента"; exit 2; }
22
22
 
23
23
  . "$(dirname "$0")/_skip.sh" 2>/dev/null || { echo "не найден _skip.sh рядом с _native.sh"; exit 2; }
24
+ if [ "${AQK_SKIP_READY:-}" != 1 ]; then
25
+ echo "_skip.sh есть, но обход не собрался — проверка НЕ СОСТОЯЛАСЬ, а не прошла"
26
+ exit 2
27
+ fi
24
28
 
25
29
  # Два фильтра, а не один: own_samples_filter прячет образцы гейтов и то, что назвал проект
26
30
  # в .aqkignore, а skip_paths_filter — общий список каталогов, который переносимые проверки
@@ -182,3 +182,10 @@ drop_comments() { grep -vE '^[^:]*:[0-9]+:[[:space:]]*(//|\*|#|/\*|--)' ; }
182
182
  # `sh` в списке нет намеренно: печать в скрипте — его способ говорить с человеком, и запрет
183
183
  # отладочной печати покрасил бы каждый из них.
184
184
  only_code() { grep -E "\.($(printf '%s' "$CODE_EXT" | tr ' ' '|'))$"; }
185
+
186
+ # Метка собранности. Ставится ПОСЛЕДНЕЙ строкой намеренно: она подтверждает, что файл дочитан
187
+ # до конца, а не только начат. Подключающий обязан её проверить — до 2026-09-10 он проверял
188
+ # лишь НАЛИЧИЕ файла, и подмена содержимого давала код 0: гейт печатал «command not found» и
189
+ # объявлял проект чистым. Библиотеку подключает каждая запись каталога, то есть одним
190
+ # испорченным файлом гасился весь набор защит.
191
+ AQK_SKIP_READY=1
@@ -21,6 +21,13 @@ if [ ! -f "$SKIP_LIB" ]; then
21
21
  exit 2
22
22
  fi
23
23
  . "$SKIP_LIB"
24
+ # Файл на месте — этого мало: подмена содержимого давала код 0. Метка стоит в КОНЦЕ _skip.sh,
25
+ # поэтому проверка ловит и обрыв файла на середине.
26
+ if [ "${AQK_SKIP_READY:-}" != 1 ]; then
27
+ echo "_skip.sh есть, но обход не собрался — проверка НЕ СОСТОЯЛАСЬ, а не прошла"
28
+ echo " почини: замени kit/gates/_skip.sh целым файлом из каталога"
29
+ exit 2
30
+ fi
24
31
 
25
32
  # --- есть ли договор ----------------------------------------------------------
26
33
  # По имени файла, а не по расположению: спецификацию кладут в корень, в `docs/`, рядом с
@@ -18,6 +18,13 @@ if [ ! -f "$SKIP_LIB" ]; then
18
18
  exit 2
19
19
  fi
20
20
  . "$SKIP_LIB"
21
+ # Файл на месте — этого мало: подмена содержимого давала код 0. Метка стоит в КОНЦЕ _skip.sh,
22
+ # поэтому проверка ловит и обрыв файла на середине.
23
+ if [ "${AQK_SKIP_READY:-}" != 1 ]; then
24
+ echo "_skip.sh есть, но обход не собрался — проверка НЕ СОСТОЯЛАСЬ, а не прошла"
25
+ echo " почини: замени kit/gates/_skip.sh целым файлом из каталога"
26
+ exit 2
27
+ fi
21
28
 
22
29
  # Расширения, где живёт ТЕМИЗИРУЕМЫЙ интерфейс. Своё, а не общий CODE_EXT: там нет ни css, ни
23
30
  # vue — они не код в смысле «отладочная печать», но именно в них живёт цвет.
@@ -15,8 +15,14 @@ if [ -f "$DIR/.aqk-commit-msg" ]; then
15
15
  MSG=$(cat "$DIR/.aqk-commit-msg")
16
16
  else
17
17
  if ! (cd "$DIR" 2>/dev/null && git rev-parse --git-dir >/dev/null 2>&1); then
18
- echo "не git-репозиторий проверять нечего"
19
- exit 0
18
+ # НЕ «проверять нечего», а «проверить нечем»: без истории свидетель слеп, и код 0 здесь
19
+ # неотличим от «проверено и чисто». Договор комплекта: 0 — чисто, 1 — находка, остальное —
20
+ # не смогли. Тот же довод уже записан ниже про мелкий клон и в protection-not-removed:
21
+ # когда свидетель слеп, зеленеть нельзя.
22
+ echo "не git-репозиторий — историю смотреть нечем, проверка НЕ СОСТОЯЛАСЬ"
23
+ echo " почини: запусти проверку в репозитории, либо убери запись из манифеста —"
24
+ echo " почини: гейт, который не может посмотреть, не защищает ничего."
25
+ exit 2
20
26
  fi
21
27
  # Мелкий клон: у коммита не видно родителя, и git выдаёт всё дерево как изменённое. Состав
22
28
  # коммита в этом случае не определить, а требовать отчёт вслепую нельзя — конвейер краснел бы
@@ -19,6 +19,13 @@ if [ ! -f "$SKIP_LIB" ]; then
19
19
  exit 2
20
20
  fi
21
21
  . "$SKIP_LIB"
22
+ # Файл на месте — этого мало: подмена содержимого давала код 0. Метка стоит в КОНЦЕ _skip.sh,
23
+ # поэтому проверка ловит и обрыв файла на середине.
24
+ if [ "${AQK_SKIP_READY:-}" != 1 ]; then
25
+ echo "_skip.sh есть, но обход не собрался — проверка НЕ СОСТОЯЛАСЬ, а не прошла"
26
+ echo " почини: замени kit/gates/_skip.sh целым файлом из каталога"
27
+ exit 2
28
+ fi
22
29
  MAX="${AQK_MAX_DEPTH:-5}"
23
30
 
24
31
  # Тесты исключены намеренно — тем же списком, что и в duplicate-code. Глубокая вложенность в
@@ -36,8 +43,19 @@ find "$DIR" $(skip_find "$DIR") $TESTS -type f \
36
43
  # Разметка вложена по природе: пять уровней тегов — это не сложная логика, а обычная
37
44
  # вёрстка. Меряя её тем же пределом, гейт краснеет на нормальном коде и его выключают.
38
45
  function limit() { return (wf ~ /\.(jsx|tsx|vue|svelte)$/) ? MAX + 3 : MAX }
39
- function flush() { if (worst > limit()) print wf ":" wl ": вложенность " worst ", предел " limit() }
40
- FNR == 1 { flush(); worst = 0; wl = 0; wf = FILENAME }
46
+ # Шаг отступа берётся ИЗ ФАЙЛА, а не считается равным четырём. Пока он был прибит к
47
+ # четырём, проверка видела ВДВОЕ МЕНЬШУЮ вложенность в javascript и typescript, где
48
+ # общепринятый отступ — два пробела: шесть уровней давали «три» и проходили предел
49
+ # молча. Замечено 2026-09-10, когда в каталог впервые добавили образец на .js: go и
50
+ # python отступают на четыре, и на них дефекта не видно в принципе.
51
+ # Минимум зажат снизу двойкой: файл с одиночным пробелом в продолжении строки иначе
52
+ # вчетверо завысил бы вложенность и дал ложную тревогу.
53
+ function unit() { return (step >= 2 && step <= 8) ? step : 4 }
54
+ function flush() {
55
+ if (wf != "" && int(worstN / unit()) > limit())
56
+ print wf ":" wl ": вложенность " int(worstN / unit()) ", предел " limit()
57
+ }
58
+ FNR == 1 { flush(); worstN = 0; wl = 0; step = 0; wf = FILENAME }
41
59
  /^[[:space:]]*$/ { next }
42
60
  {
43
61
  # ширина отступа: табуляция считается за четыре пробела. Отступ берётся ОДНИМ
@@ -45,8 +63,8 @@ find "$DIR" $(skip_find "$DIR") $TESTS -type f \
45
63
  # символ отступа и стоил больше, чем весь остальной разбор. Замер 2026-09-08 на uv.
46
64
  match($0, /^[ \t]*/); ind = substr($0, 1, RLENGTH)
47
65
  n = gsub(/\t/, "", ind) * 4 + length(ind)
48
- depth = int(n / 4)
49
- if (depth > worst) { worst = depth; wl = FNR }
66
+ if (n > 0 && (step == 0 || n < step)) step = n
67
+ if (n > worstN) { worstN = n; wl = FNR }
50
68
  }
51
69
  END { flush() }
52
70
  ' > /tmp/.cplx.$$ 2>/dev/null
@@ -4,11 +4,16 @@ intent_en: a function does not grow past the complexity you can hold in your hea
4
4
  trigger:
5
5
  always: true
6
6
 
7
+ # Домашние страницы готовых инструментов, которые зовут рецепты ниже. Адреса сверены
8
+ # по реестру github 2026-09-10, а не написаны по памяти: три выдуманных адреса чужих
9
+ # репозиториев — записанная шишка комплекта.
10
+ tool: https://github.com/astral-sh/ruff · https://github.com/eslint/eslint
11
+
7
12
  recipes:
8
13
  # Переносимая мера грубая — глубина вложенности. Готовые правила считают ветвления и
9
14
  # инструкции, это точнее; см. kit/docs/ready-made-rules.md
10
15
  any: bash {gate}/check.sh {dir}
11
- python: ruff check --select C901,PLR0912,PLR0915 {dir}
12
- typescript: eslint --rule '{"complexity":["error",10],"max-depth":["error",4]}' {dir}
16
+ python: ruff check -q --output-format=concise --select C901,PLR0912,PLR0915 {dir}
17
+ typescript: eslint --no-config-lookup --ignore-pattern 'gates/*/red/**' --ignore-pattern 'gates/*/green/**' --rule '{"complexity":["error",10],"max-depth":["error",4]}' {dir}
13
18
 
14
19
  proof: incidents/README.md — «2026-08-27 ревизия гейтов», п. 6: 75 функций сложнее нормы, худшая с 29 ветвлениями
@@ -0,0 +1,15 @@
1
+ export function route(a, b, c, d) {
2
+ if (a > 0) {
3
+ if (b > 0) {
4
+ for (let i = 0; i < c; i++) {
5
+ switch (d) {
6
+ case 1:
7
+ if (a > b) {
8
+ return 1;
9
+ }
10
+ }
11
+ }
12
+ }
13
+ }
14
+ return 0;
15
+ }
@@ -10,6 +10,11 @@ trigger:
10
10
  # Переносимого рецепта здесь нет намеренно: чтобы понять, вызывают ли функцию, нужен граф
11
11
  # вызовов, а не поиск по тексту. Это тот случай, когда без готового инструмента не обойтись —
12
12
  # и он есть под каждый распространённый стек.
13
+ # Домашние страницы готовых инструментов, которые зовут рецепты ниже. Адреса сверены
14
+ # по реестру github 2026-09-10, а не написаны по памяти: три выдуманных адреса чужих
15
+ # репозиториев — записанная шишка комплекта.
16
+ tool: https://github.com/jendrikseipp/vulture · https://github.com/webpro-nl/knip
17
+
13
18
  recipes:
14
19
  python: vulture --min-confidence 60 {dir}
15
20
  typescript: npx --yes knip@6 --directory {dir}
@@ -18,6 +18,13 @@ if [ ! -f "$SKIP_LIB" ]; then
18
18
  exit 2
19
19
  fi
20
20
  . "$SKIP_LIB"
21
+ # Файл на месте — этого мало: подмена содержимого давала код 0. Метка стоит в КОНЦЕ _skip.sh,
22
+ # поэтому проверка ловит и обрыв файла на середине.
23
+ if [ "${AQK_SKIP_READY:-}" != 1 ]; then
24
+ echo "_skip.sh есть, но обход не собрался — проверка НЕ СОСТОЯЛАСЬ, а не прошла"
25
+ echo " почини: замени kit/gates/_skip.sh целым файлом из каталога"
26
+ exit 2
27
+ fi
21
28
  WIN="${AQK_DUP_LINES:-8}"
22
29
 
23
30
  # Тесты исключены намеренно. Повтор в тестах часто осознанный: читаемость там важнее сухости,
@@ -4,6 +4,11 @@ intent_en: the same code does not multiply into copies across the project
4
4
  trigger:
5
5
  files_gt: 20
6
6
 
7
+ # Домашние страницы готовых инструментов, которые зовут рецепты ниже. Адреса сверены
8
+ # по реестру github 2026-09-10, а не написаны по памяти: три выдуманных адреса чужих
9
+ # репозиториев — записанная шишка комплекта.
10
+ tool: https://github.com/kucherenko/jscpd · https://github.com/pylint-dev/pylint
11
+
7
12
  recipes:
8
13
  any: bash {gate}/check.sh {dir}
9
14
  # jscpd умеет и Python, и TypeScript одним прогоном и считает похожесть, а не совпадение.
@@ -25,6 +30,10 @@ recipes:
25
30
  # Родной инструмент стека, а не jscpd: питоновскому проекту незачем ставить Node ради одной
26
31
  # проверки. R0801 сравнивает не байты, а разобранный код — переименованная переменная его
27
32
  # не обманет, в отличие от переносимого рецепта.
28
- python: pylint --disable=all --enable=R0801 --min-similarity-lines=8 {dir}
33
+ # `--ignore-paths` исключение на ВХОДЕ, а не фильтром вывода. `aqk add` кладёт красные
34
+ # образцы в проект, и они по построению дублируют друг друга: без исключения pylint
35
+ # предъявлял пользователю НАШИ ЖЕ файлы как его дубликаты. Найдено 2026-09-10 табличной
36
+ # проверкой own-samples в тот час, когда pylint появился на машине.
37
+ python: pylint --disable=all --enable=R0801 --min-similarity-lines=8 --ignore-paths='.*gates/[^/]+/(red|green)(/|$).*' {dir}
29
38
 
30
39
  proof: incidents/README.md — «2026-08-25 разбор 1069 коммитов»: число моделей захардкожено в четырёх местах четырьмя разными значениями
@@ -18,6 +18,13 @@ if [ ! -f "$SKIP_LIB" ]; then
18
18
  exit 2
19
19
  fi
20
20
  . "$SKIP_LIB"
21
+ # Файл на месте — этого мало: подмена содержимого давала код 0. Метка стоит в КОНЦЕ _skip.sh,
22
+ # поэтому проверка ловит и обрыв файла на середине.
23
+ if [ "${AQK_SKIP_READY:-}" != 1 ]; then
24
+ echo "_skip.sh есть, но обход не собрался — проверка НЕ СОСТОЯЛАСЬ, а не прошла"
25
+ echo " почини: замени kit/gates/_skip.sh целым файлом из каталога"
26
+ exit 2
27
+ fi
21
28
 
22
29
  # Один обход и один wc на все файлы разом: на проекте в 36 тысяч файлов цикл с wc на каждый
23
30
  # не укладывался в две минуты.