agent-quality-kit 0.13.0 → 0.15.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.
- package/README.md +46 -8
- package/README.ru.md +49 -9
- package/kit/gates/api-contract-has-arbiter/README.md +16 -1
- package/kit/gates/api-contract-has-arbiter/check.sh +66 -23
- package/kit/gates/entry-commands-exist/README.md +64 -0
- package/kit/gates/entry-commands-exist/check.sh +110 -0
- package/kit/gates/entry-commands-exist/gate.yml +19 -0
- package/kit/gates/entry-commands-exist/green/AGENTS.md +13 -0
- package/kit/gates/entry-commands-exist/green/Makefile +6 -0
- package/kit/gates/entry-commands-exist/green/justfile +2 -0
- package/kit/gates/entry-commands-exist/green/package.json +10 -0
- package/kit/gates/entry-commands-exist/red/AGENTS.md +9 -0
- package/kit/gates/entry-commands-exist/red/Makefile +2 -0
- package/kit/gates/entry-commands-exist/red/package.json +9 -0
- package/llms.txt +5 -1
- package/package.json +1 -1
- package/tool/commands/context.mjs +59 -44
- package/tool/commands/doctor-catalog.mjs +222 -0
- package/tool/commands/doctor.mjs +46 -237
- package/tool/commands/feedback.mjs +157 -0
- package/tool/commands/learn.mjs +119 -19
- package/tool/commands/probe.mjs +4 -2
- package/tool/commands/project.mjs +11 -13
- package/tool/commands/prompt.mjs +70 -0
- package/tool/i18n/en-docs.mjs +1 -0
- package/tool/i18n/en-gates.mjs +27 -0
- package/tool/i18n/en.mjs +70 -3
- package/tool/i18n/index.mjs +42 -3
- package/tool/i18n/ru-docs.mjs +1 -0
- package/tool/i18n/ru-gates.mjs +28 -0
- package/tool/i18n/ru.mjs +81 -3
- package/tool/lib/annotate.mjs +66 -0
- package/tool/lib/ask.mjs +118 -0
- package/tool/lib/brief.mjs +17 -38
- package/tool/lib/cadence.mjs +30 -1
- package/tool/lib/core.mjs +8 -6
- package/tool/lib/gate-worker.mjs +4 -1
- package/tool/lib/repo.mjs +45 -4
- package/tool/lib/run.mjs +140 -9
- package/tool/program.mjs +10 -0
- package/tool/selfcheck/smoke/_fixture.mjs +8 -3
- package/tool/selfcheck/smoke/api-contract.test.mjs +37 -0
- package/tool/selfcheck/smoke/corpus.test.mjs +151 -0
- package/tool/selfcheck/smoke/fail-closed.test.mjs +96 -1
- package/tool/selfcheck/smoke/first-run.test.mjs +39 -0
- package/tool/selfcheck/smoke/verdict.test.mjs +41 -2
- package/tool/selfcheck/smoke.sh +4 -0
- package/tool/selfcheck/units-annotate.mjs +67 -0
- package/tool/selfcheck/units-ask.mjs +85 -0
- package/tool/selfcheck/units-brief.mjs +3 -13
- package/tool/selfcheck/units-cadence.mjs +26 -1
- package/tool/selfcheck/units-context.mjs +2 -1
- package/tool/selfcheck/units-feedback.mjs +137 -0
- package/tool/selfcheck/units-learn.mjs +32 -0
- package/tool/selfcheck/units-level.mjs +21 -1
- package/tool/selfcheck/units-prompt.mjs +106 -0
- package/tool/selfcheck/units-repo.mjs +20 -1
package/README.md
CHANGED
|
@@ -104,15 +104,20 @@ aqk badge --check fail if the badge disagrees with a run
|
|
|
104
104
|
aqk context the repository state in one block, for an agent's context:
|
|
105
105
|
level, what is red now, rules nobody enforces, ratchets,
|
|
106
106
|
the next three steps with commands, and when to run what
|
|
107
|
+
aqk prompt one task to paste into an agent: what to fix, in order, and the
|
|
108
|
+
command that proves each item done
|
|
107
109
|
aqk vitals is what the kit runs on wired up: gate tools, hooks, freshness
|
|
110
|
+
aqk feedback feedback to the author: a report from the last run and probe,
|
|
111
|
+
plus a prefilled link. No paths, no code; nothing is sent for you
|
|
108
112
|
aqk doctor --run --brief one line on success, the whole run on failure — for hooks
|
|
109
113
|
aqk context --full the same plus the command map and the rulebook verbatim (~7000
|
|
110
114
|
tokens against ~500: the price of an agent that does not guess)
|
|
111
115
|
aqk context --install put a SessionStart hook into .claude/settings.json
|
|
112
116
|
(add --full to install the full block)
|
|
113
117
|
|
|
114
|
-
aqk learn rule candidates from local transcripts:
|
|
115
|
-
|
|
118
|
+
aqk learn rule candidates from local transcripts: said out loud, never
|
|
119
|
+
written down — and what you had to repeat ("I told you",
|
|
120
|
+
"again"), first of all a written rule the agent still breaks
|
|
116
121
|
aqk note "..." write a bruise into the journal
|
|
117
122
|
aqk ratchet <name> a debt registry for a declared gate: may only get shorter
|
|
118
123
|
aqk blob every guide as a single file
|
|
@@ -184,7 +189,7 @@ aqk: 1
|
|
|
184
189
|
entry: [AGENTS.md] # what the agent reads first
|
|
185
190
|
rules: .aqk/rules # where the standards live
|
|
186
191
|
docs: .aqk/docs # where the guides live (optional; this is the default)
|
|
187
|
-
lang: en # output language
|
|
192
|
+
lang: en # output language; without it — the language of AGENTS.md/README
|
|
188
193
|
gates: # what must pass — as commands, not as prose
|
|
189
194
|
lint: "npm run lint"
|
|
190
195
|
secrets-not-in-code: "bash gates/secrets-not-in-code/check.sh ."
|
|
@@ -348,7 +353,7 @@ Already using [pre-commit](https://pre-commit.com)? Three lines in the file you
|
|
|
348
353
|
```yaml
|
|
349
354
|
repos:
|
|
350
355
|
- repo: https://github.com/arsen-ask-lx/Agent_Quality_Kit
|
|
351
|
-
rev: v0.
|
|
356
|
+
rev: v0.15.0
|
|
352
357
|
hooks:
|
|
353
358
|
- id: aqk # runs what the repository declares; blocks below AQK-1
|
|
354
359
|
# - id: aqk-doctor # read-only: the level and what is missing, blocks nothing
|
|
@@ -369,7 +374,7 @@ layer AQK adds.
|
|
|
369
374
|
[](https://github.com/marketplace/actions/agent-quality-kit-aqk)
|
|
370
375
|
|
|
371
376
|
```yaml
|
|
372
|
-
- uses: arsen-ask-lx/Agent_Quality_Kit@v0.
|
|
377
|
+
- uses: arsen-ask-lx/Agent_Quality_Kit@v0.15.0
|
|
373
378
|
with:
|
|
374
379
|
min: 1 # the build fails below AQK-1, or if any declared gate failed
|
|
375
380
|
```
|
|
@@ -381,6 +386,12 @@ the same thing in a single line:
|
|
|
381
386
|
- run: npx agent-quality-kit doctor --run --min 1
|
|
382
387
|
```
|
|
383
388
|
|
|
389
|
+
**Findings show up in the pull request itself.** Inside GitHub Actions a failed gate's finding
|
|
390
|
+
that names a file — `src/a.py:12: …` — becomes a red annotation on that line of the diff, with the
|
|
391
|
+
gate's "fix:" advice attached; an advisory gate gives a yellow one. At most ten of each per run
|
|
392
|
+
(the limit GitHub is reported to take per step); the rest are counted in the log. The verdict
|
|
393
|
+
does not change — annotations print what the run already decided.
|
|
394
|
+
|
|
384
395
|
## Without Node at all
|
|
385
396
|
|
|
386
397
|
A Python, Go or Rust project where nobody installed Node and nobody will:
|
|
@@ -422,12 +433,34 @@ files the diff touched:
|
|
|
422
433
|
aqk doctor --run --since main # only what this branch introduced
|
|
423
434
|
```
|
|
424
435
|
|
|
425
|
-
|
|
426
|
-
outside it — green, with the number that was hidden, never a silent "all clear".
|
|
436
|
+
Four outcomes, all of them said out loud. Findings inside the diff — red, as usual. Findings only
|
|
437
|
+
outside it — green, with the number that was hidden, never a silent "all clear". A gate whose
|
|
427
438
|
output carries no paths at all (a commit-message check, a CI-config check) **cannot** be narrowed:
|
|
428
|
-
it stays red, and says why.
|
|
439
|
+
it stays red, and says why. And a gate that **could not run at all** — no tool, an unexpected exit
|
|
440
|
+
code, killed by a signal — is never narrowed by the diff: a failure has no place in the code, only
|
|
441
|
+
itself. Calling either of the last two green because there was nothing to narrow would be exactly
|
|
429
442
|
the silence this tool exists to remove.
|
|
430
443
|
|
|
444
|
+
### The only payment: one answer
|
|
445
|
+
|
|
446
|
+
The kit is free and collects nothing about you: it makes exactly one outgoing request — asking the
|
|
447
|
+
npm registry whether a newer version exists. The payment is different: **one answer to the author**.
|
|
448
|
+
So once per project, and only when there is something to tell, `doctor` or the agent block prints a
|
|
449
|
+
line like "AQK could not check `smoke`; that is the most valuable thing to tell the author". Then:
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
aqk feedback # builds the message and hands you a prefilled link — you send it, not us
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
The message carries: version, level, stack, what went red, what the kit could not check, which
|
|
456
|
+
defect classes nobody catches here. **No paths, no code, no repository name** — you see every
|
|
457
|
+
character you send. No GitHub? Forward the text as is. Not interested at all? `AQK_FEEDBACK=0`.
|
|
458
|
+
|
|
459
|
+
Somewhere to say it in your own words:
|
|
460
|
+
[where the kit was wrong](https://github.com/arsen-ask-lx/Agent_Quality_Kit/discussions/90) ·
|
|
461
|
+
[what check is missing](https://github.com/arsen-ask-lx/Agent_Quality_Kit/discussions/91) ·
|
|
462
|
+
[show your manifest](https://github.com/arsen-ask-lx/Agent_Quality_Kit/discussions/92).
|
|
463
|
+
|
|
431
464
|
Every `doctor --run` rewrites `.aqk/last-run.md` — a short report of what actually ran and how
|
|
432
465
|
long it took. The list of gates in the manifest says nothing about how many of them are alive
|
|
433
466
|
right now; the report does. The file is ephemeral — keep it in your own `.gitignore`.
|
|
@@ -478,6 +511,11 @@ purpose: two gates writing into the same folder (`npm run build` twice into `dis
|
|
|
478
511
|
at random when run together, and a flaky red is worse than a slow one. Output keeps the declared
|
|
479
512
|
order. On this repository, 30 gates: about 110 s one by one, 68 s with `--jobs 3`.
|
|
480
513
|
|
|
514
|
+
**Output is short by default.** A passed gate, an entry the machine already holds and an entry that
|
|
515
|
+
does not apply fold into one counted line each; a failed gate, an advisory one, advice and "what to
|
|
516
|
+
add" always print in full. `aqk doctor --verbose` lists everything by name; in a pipeline whose log
|
|
517
|
+
is read later, set `AQK_VERBOSE=1`.
|
|
518
|
+
|
|
481
519
|
## When a bug slips past the guards
|
|
482
520
|
|
|
483
521
|
```bash
|
package/README.ru.md
CHANGED
|
@@ -106,15 +106,21 @@ aqk badge --check упасть, если значок расходится
|
|
|
106
106
|
aqk context состояние репозитория одним блоком, для контекста агента:
|
|
107
107
|
уровень, что красное сейчас, правила без арбитра, храповики,
|
|
108
108
|
три следующих шага с командами и когда что запускать
|
|
109
|
+
aqk prompt одно задание для агента: что починить, по порядку, и у каждого
|
|
110
|
+
пункта команда, которая докажет «готово»
|
|
109
111
|
aqk vitals подключено ли то, чем комплект работает: инструменты, хуки, свежесть
|
|
112
|
+
aqk feedback отзыв автору: отчёт из последнего прогона и пробы плюс готовая
|
|
113
|
+
ссылка. Без путей и без кода; ничего не отправляет само
|
|
110
114
|
aqk doctor --run --brief одна строка на успехе, весь прогон при провале — для хуков
|
|
111
115
|
aqk context --full то же плюс карта команд и свод правил дословно (≈7000 токенов
|
|
112
116
|
против ≈500 — плата за то, чтобы агент не догадывался)
|
|
113
117
|
aqk context --install поставить хук SessionStart в .claude/settings.json
|
|
114
118
|
(с --full ставится полный блок)
|
|
115
119
|
|
|
116
|
-
aqk learn кандидаты в правила из локальной переписки:
|
|
117
|
-
|
|
120
|
+
aqk learn кандидаты в правила из локальной переписки: что сказано
|
|
121
|
+
вслух и не записано — и что пришлось повторять («я же
|
|
122
|
+
говорил», «опять»), прежде всего записанное правило,
|
|
123
|
+
которое агент всё равно нарушает
|
|
118
124
|
aqk note "..." записать шишку в журнал
|
|
119
125
|
aqk ratchet <имя> реестр долга для объявленного гейта: может только укорачиваться
|
|
120
126
|
aqk blob все методички одним файлом
|
|
@@ -186,7 +192,7 @@ aqk: 1
|
|
|
186
192
|
entry: [AGENTS.md] # что агент читает первым
|
|
187
193
|
rules: .aqk/rules # где стандарты
|
|
188
194
|
docs: .aqk/docs # где методички (необязательно, это и есть умолчание)
|
|
189
|
-
lang: ru # язык
|
|
195
|
+
lang: ru # язык вывода; без поля — язык AGENTS.md/README, потом локаль
|
|
190
196
|
gates: # что обязано пройти — командами, не словами
|
|
191
197
|
lint: "npm run lint"
|
|
192
198
|
secrets-not-in-code: "bash gates/secrets-not-in-code/check.sh ."
|
|
@@ -351,7 +357,7 @@ aqk badge --check # в конвейере: код 1 в тот день, ког
|
|
|
351
357
|
```yaml
|
|
352
358
|
repos:
|
|
353
359
|
- repo: https://github.com/arsen-ask-lx/Agent_Quality_Kit
|
|
354
|
-
rev: v0.
|
|
360
|
+
rev: v0.15.0
|
|
355
361
|
hooks:
|
|
356
362
|
- id: aqk # запускает объявленное; роняет коммит ниже AQK-1
|
|
357
363
|
# - id: aqk-doctor # только осмотр: уровень и чего не хватает, ничего не роняет
|
|
@@ -370,7 +376,7 @@ repos:
|
|
|
370
376
|
[](https://github.com/marketplace/actions/agent-quality-kit-aqk)
|
|
371
377
|
|
|
372
378
|
```yaml
|
|
373
|
-
- uses: arsen-ask-lx/Agent_Quality_Kit@v0.
|
|
379
|
+
- uses: arsen-ask-lx/Agent_Quality_Kit@v0.15.0
|
|
374
380
|
with:
|
|
375
381
|
min: 1 # сборка падает ниже AQK-1 или если упал любой объявленный гейт
|
|
376
382
|
```
|
|
@@ -382,6 +388,12 @@ repos:
|
|
|
382
388
|
- run: npx agent-quality-kit doctor --run --min 1
|
|
383
389
|
```
|
|
384
390
|
|
|
391
|
+
**Находки видны прямо в pull request.** В GitHub Actions находка упавшего гейта, которая называет
|
|
392
|
+
файл, — `src/a.py:12: …` — становится красной пометкой у этой строки дифа, вместе с советом
|
|
393
|
+
«почини» того же гейта; совещательный гейт даёт жёлтую. Не больше десяти каждого вида за прогон
|
|
394
|
+
(столько GitHub, по имеющимся данным, принимает за шаг), остальное — числом в логе. Вердикт от
|
|
395
|
+
пометок не меняется: они печатают то, что прогон уже решил.
|
|
396
|
+
|
|
385
397
|
## Без Node вовсе
|
|
386
398
|
|
|
387
399
|
Проект на Python, Go или Rust, где Node никто не ставил и не поставит:
|
|
@@ -422,11 +434,34 @@ aqk ratchet no-print-in-prod # старое — долг, новое не пу
|
|
|
422
434
|
aqk doctor --run --since main # только то, что внесла эта ветка
|
|
423
435
|
```
|
|
424
436
|
|
|
425
|
-
|
|
426
|
-
снаружи — зелёный, с числом того, что скрыто, а не молчаливое «всё чисто».
|
|
437
|
+
Четыре исхода, и все четыре названы вслух. Находки внутри дифа — красный, как обычно. Находки
|
|
438
|
+
только снаружи — зелёный, с числом того, что скрыто, а не молчаливое «всё чисто». Гейт, в выводе
|
|
427
439
|
которого путей нет вовсе (проверка сообщения коммита, проверка конфига конвейера), сузиться
|
|
428
|
-
**не может**: он остаётся красным и говорит почему.
|
|
429
|
-
|
|
440
|
+
**не может**: он остаётся красным и говорит почему. А гейт, который вообще **не смог
|
|
441
|
+
отработать** — нет инструмента, неожиданный код возврата, убит сигналом, — дифом не сужается
|
|
442
|
+
никогда: у сбоя нет места в коде, есть только сам сбой. Назвать любой из двух последних зелёным
|
|
443
|
+
потому, что сужать было нечего, — ровно та тишина, ради устранения которой этот инструмент и
|
|
444
|
+
написан.
|
|
445
|
+
|
|
446
|
+
### Единственная плата — один ответ
|
|
447
|
+
|
|
448
|
+
Комплект бесплатный и ничего о вас не собирает: исходящий запрос у него ровно один — спросить
|
|
449
|
+
реестр npm, не вышла ли версия свежее. Плата другая: **один ответ автору**. Поэтому один раз на
|
|
450
|
+
проект — и только когда есть что рассказать — `doctor` или блок для агента печатают строку вроде
|
|
451
|
+
«AQK не смог проверить `smoke`; автору это ценнее всего». Дальше:
|
|
452
|
+
|
|
453
|
+
```bash
|
|
454
|
+
aqk feedback # соберёт письмо и даст готовую ссылку — отправляете вы, не мы
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
В письме: версия, уровень, стек, что покраснело, чего комплект не смог проверить, какие классы
|
|
458
|
+
брака здесь не ловит никто. **Ни путей, ни кода, ни имени репозитория** — вы видите глазами всё,
|
|
459
|
+
что отправляете. Не нужен GitHub — перешлите текст как есть. Не нужно вовсе: `AQK_FEEDBACK=0`.
|
|
460
|
+
|
|
461
|
+
Где рассказать словами:
|
|
462
|
+
[где комплект соврал](https://github.com/arsen-ask-lx/Agent_Quality_Kit/discussions/90) ·
|
|
463
|
+
[какой проверки не хватает](https://github.com/arsen-ask-lx/Agent_Quality_Kit/discussions/91) ·
|
|
464
|
+
[покажите свой манифест](https://github.com/arsen-ask-lx/Agent_Quality_Kit/discussions/92).
|
|
430
465
|
|
|
431
466
|
Каждый `doctor --run` перезаписывает `.aqk/last-run.md` — короткий отчёт, что из объявленного
|
|
432
467
|
реально сработало и за сколько. Список гейтов в манифесте молчит о том, сколько из них живы
|
|
@@ -477,6 +512,11 @@ aqk doctor --run --only stack # только стенд, на стенде
|
|
|
477
512
|
падали бы через раз, а плавающее красное хуже медленного. Вывод — в порядке объявления. На этом
|
|
478
513
|
репозитории, 30 гейтов: около 110 с по одному, 68 с с `--jobs 3`.
|
|
479
514
|
|
|
515
|
+
**Вывод короткий по умолчанию.** Прошедший гейт, запись, которую уже держит машина, и
|
|
516
|
+
неприменимая запись сворачиваются в одну строку со счётом; упавший гейт, совещательный, совет и
|
|
517
|
+
«что поставить» печатаются всегда. `aqk doctor --verbose` — всё поимённо; в конвейере, где лог
|
|
518
|
+
читают потом, — `AQK_VERBOSE=1`.
|
|
519
|
+
|
|
480
520
|
|
|
481
521
|
## Поймал ошибку, которую не поймал сторож
|
|
482
522
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
Отсюда обе красные ветки. Замер целиком — `incidents/README.md`, 2026-09-09.
|
|
18
18
|
|
|
19
|
-
**Что именно проверяется.** Записи
|
|
19
|
+
**Что именно проверяется.** Записи три; вторая тоньше первой, третья — тот же договор без файла.
|
|
20
20
|
|
|
21
21
|
1. **Спецификацию не держит ни одна команда.** Файл `openapi*.{yaml,yml,json}` (и `swagger*`,
|
|
22
22
|
`asyncapi*`) в репозитории есть, а ни в конвейере, ни в сборочных файлах, ни в скриптах, ни
|
|
@@ -24,6 +24,14 @@
|
|
|
24
24
|
2. **Арбитр сужен до «не пятисотка».** `schemathesis --checks not_a_server_error` (или `-c`).
|
|
25
25
|
У `schemathesis` по умолчанию включены **все** проверки, включая
|
|
26
26
|
`response_schema_conformance`; сужение до одной — не настройка, а отключение.
|
|
27
|
+
3. **Договор в коде, а проверку типов не запускает никто.** В `package.json` стоит `@trpc/server`,
|
|
28
|
+
`@ts-rest/core`, `@hono/zod-openapi` или провайдер типов Fastify (`@fastify/type-provider-*`,
|
|
29
|
+
`fastify-type-provider-zod`), а `tsc`, `vue-tsc` или `tsgo` не зовёт ни одна команда. У такого
|
|
30
|
+
договора арбитр — типы: разошлись сервер и клиент, краснеет сборка типов. Отзыв с живого
|
|
31
|
+
проекта 2026-09-11: схемы zod в общем пакете, сервер на `@fastify/type-provider-zod` — а
|
|
32
|
+
запись писала «спецификации не видно». Один `zod` договором не считается: им разбирают и
|
|
33
|
+
формы, и конфиги. Файлы блокировки (`package-lock.json`) запуском не считаются — там
|
|
34
|
+
`"bin": { "tsc": … }` у любого проекта на TypeScript.
|
|
27
35
|
|
|
28
36
|
Четыре семьи держателей отвечают на **разные** вопросы, и подменять один другим нельзя:
|
|
29
37
|
|
|
@@ -61,3 +69,10 @@
|
|
|
61
69
|
запись. Красным сделано только то, у чего законного применения нет.
|
|
62
70
|
- **Что спецификация вообще описывает этот сервер.** Файл может описывать чужой API; сверять
|
|
63
71
|
их машина не умеет.
|
|
72
|
+
- **Что договор в коде проверяется ВО ВРЕМЯ РАБОТЫ.** Типы сходятся — а ответ сервер отдаёт
|
|
73
|
+
непроверенным: у tRPC без `.output()`, у ts-rest без `responseValidation` на сервере, у Fastify без
|
|
74
|
+
сериализатора схемы ответа. Это расхождение `tsc` не видит по построению: типы описывают
|
|
75
|
+
намерение, а не то, что ушло по сети. Сверять настройку каждой библиотеки — десять правил
|
|
76
|
+
ради одной записи; запись держит то, что одинаково у всех: проверку типов кто-то запускает.
|
|
77
|
+
- **Договор в коде у других библиотек.** `zod` плюс рукописный клиент, GraphQL-схема в коде,
|
|
78
|
+
gRPC — не опознаются. Список взят с живого проекта и с реестра npm, а не для полноты.
|
|
@@ -40,23 +40,36 @@ SPECS=$(find "$DIR" $(skip_find) -type f \
|
|
|
40
40
|
-o -iname 'swagger*.yaml' -o -iname 'swagger*.yml' -o -iname 'swagger*.json' \
|
|
41
41
|
-o -iname 'asyncapi*.yaml' -o -iname 'asyncapi*.yml' -o -iname 'asyncapi*.json' \) \
|
|
42
42
|
-print 2>/dev/null | own_samples_filter "$DIR" | grep -v '^$')
|
|
43
|
-
[ -z "$SPECS" ] && { echo "спецификации API здесь нет — эта проверка не про тебя"; exit 0; }
|
|
44
43
|
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"
|
|
44
|
+
# ДОГОВОР В КОДЕ — тот же договор без файла. Отзыв с живого проекта 2026-09-11: схемы zod
|
|
45
|
+
# запросов и ответов в общем пакете, сервер на `@fastify/type-provider-zod` — а проверка писала
|
|
46
|
+
# «спецификации нет», потому что знала только имя `openapi*`. Опознаём по зависимости в
|
|
47
|
+
# `package.json`: tRPC, ts-rest, Hono с zod-openapi, провайдеры типов Fastify (официальные
|
|
48
|
+
# `@fastify/type-provider-*` и `fastify-type-provider-zod`). Один `zod` — НЕ договор: им
|
|
49
|
+
# разбирают формы и конфиги. Имена сверены с реестром npm 2026-09-11, а не по памяти: по
|
|
50
|
+
# памяти был назван `fastify-type-provider-zod`, а на живом проекте стоял `@fastify/...`.
|
|
51
|
+
CODE_DEPS='@trpc/server|@ts-rest/core|@hono/zod-openapi|@fastify/type-provider-[a-z0-9-]+|fastify-type-provider-zod'
|
|
52
|
+
CODE=$(find "$DIR" $(skip_find) -type f -name package.json -print 2>/dev/null \
|
|
53
|
+
| own_samples_filter "$DIR" | grep -v '^$' \
|
|
54
|
+
| while IFS= read -r F; do grep -qE "\"($CODE_DEPS)\"[[:space:]]*:" "$F" && printf '%s\n' "$F"; done)
|
|
55
|
+
|
|
56
|
+
[ -z "$SPECS$CODE" ] && {
|
|
57
|
+
echo "договора API здесь нет — ни файла OpenAPI, ни tRPC, ts-rest или провайдера типов"
|
|
58
|
+
echo "Fastify; эта проверка не про тебя"
|
|
59
|
+
exit 0
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Где искать запуск: конвейер, оболочечные скрипты, сборочные файлы, объявления пакета и
|
|
63
|
+
# манифест самого комплекта. Не в коде: упоминание инструмента в исходнике — не его запуск.
|
|
64
|
+
# Файлы блокировки — не запуск тоже: `package-lock.json` держит `"bin": { "tsc": … }` у
|
|
65
|
+
# каждого проекта на TypeScript, и без исключения арбитр находился бы всегда.
|
|
66
|
+
run_grep() {
|
|
67
|
+
grep -rnE "$1" $(skip_grep) --exclude=package-lock.json --exclude=npm-shrinkwrap.json \
|
|
68
|
+
--include=*.yml --include=*.yaml --include=*.sh --include=*.json --include=*.toml \
|
|
69
|
+
--include=*.ini --include=*.cfg --include=*.mk --include=Makefile --include=Justfile \
|
|
70
|
+
--include=justfile --include=Taskfile.yml --include=*.gradle --include=Jenkinsfile \
|
|
71
|
+
"$DIR" 2>/dev/null | own_samples_filter "$DIR" | grep -v '^$' | drop_definitions
|
|
72
|
+
}
|
|
60
73
|
|
|
61
74
|
# ОПРЕДЕЛЕНИЕ ЗАПИСИ КАТАЛОГА — НЕ НАХОДКА, и это касается не только своей записи. Соседняя
|
|
62
75
|
# запись `ci-actually-fails` держит в своём `check.sh` строку со списком запускалок, где
|
|
@@ -66,12 +79,42 @@ FOUND=$(grep -rnE "$HOLDERS" $(skip_grep) \
|
|
|
66
79
|
# Найдено аудитом фич 2026-09-09 — прогоном на настоящем проекте, а не образцами: красный и
|
|
67
80
|
# зелёный образцы лежат по одному, а в проекте записи стоят рядом. Признак определения взят
|
|
68
81
|
# самый надёжный: в той же папке лежит `gate.yml`.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
82
|
+
drop_definitions() {
|
|
83
|
+
while IFS= read -r L; do
|
|
84
|
+
F="${L%%:*}"
|
|
85
|
+
[ -n "$F" ] || continue
|
|
86
|
+
[ -f "$(dirname "$F")/gate.yml" ] && continue
|
|
87
|
+
printf '%s\n' "$L"
|
|
88
|
+
done | grep -v '^$'
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
# Арбитр договора в коде — проверка типов: разошлись сервер и клиент, `tsc` краснеет. Слово
|
|
92
|
+
# целиком: `tsc-alias` и `typescript` запуском проверки типов не являются.
|
|
93
|
+
RC=0
|
|
94
|
+
if [ -n "$CODE" ]; then
|
|
95
|
+
TYPED=$(run_grep '(^|[^a-zA-Z0-9_-])(vue-tsc|tsc|tsgo)([[:space:]]|"|$)')
|
|
96
|
+
if [ -z "$TYPED" ]; then
|
|
97
|
+
printf '%s\n' "$CODE" | while IFS= read -r F; do
|
|
98
|
+
D=$(grep -oE "\"($CODE_DEPS)\"" "$F" | head -1 | tr -d '"')
|
|
99
|
+
echo "$F: договор API в коде ($D) — проверку типов не запускает ни одна команда"
|
|
100
|
+
done
|
|
101
|
+
echo " почини: заведи «tsc --noEmit» (или «tsc --build») в конвейере или в гейтах"
|
|
102
|
+
echo " манифеста. Договор в коде держат типы: разошлись сервер и клиент — краснеет сборка"
|
|
103
|
+
echo " типов. Никто её не запускает — договор расходится молча, как файл OpenAPI без сверки."
|
|
104
|
+
RC=1
|
|
105
|
+
fi
|
|
106
|
+
fi
|
|
107
|
+
[ -z "$SPECS" ] && exit "$RC"
|
|
108
|
+
|
|
109
|
+
# --- кто её держит ------------------------------------------------------------
|
|
110
|
+
# Четыре семьи держателей, и они отвечают на РАЗНЫЕ вопросы — подробности в README:
|
|
111
|
+
# сверка с сервером schemathesis, dredd, portman, newman, pact — «документ не врёт»
|
|
112
|
+
# линт документа spectral, redocly, vacuum, openapi-spec-validator, swagger-cli
|
|
113
|
+
# ломающие правки oasdiff — «вчерашний клиент переживёт сегодняшний выпуск»
|
|
114
|
+
# потребитель openapi-typescript, orval, oapi-codegen, openapi-generator, kubb —
|
|
115
|
+
# типы порождены договором, и расхождение ломает сборку
|
|
116
|
+
HOLDERS='schemathesis|dredd|portman|newman[[:space:]]+run|pact-broker|pact-verifier|can-i-deploy|spectral[[:space:]]+lint|redocly[[:space:]]+(lint|bundle)|vacuum[[:space:]]+(lint|report|html-report)|openapi-spec-validator|swagger-cli|oasdiff|openapi-typescript|orval|oapi-codegen|openapi-generator|kubb'
|
|
117
|
+
FOUND=$(run_grep "$HOLDERS")
|
|
75
118
|
|
|
76
119
|
if [ -z "$FOUND" ]; then
|
|
77
120
|
printf '%s\n' "$SPECS" | sed 's/$/: спецификацию не держит ни одна команда/'
|
|
@@ -121,4 +164,4 @@ if [ -n "$NARROW$LOUD" ]; then
|
|
|
121
164
|
echo " провал, погашенный «|| true» или «continue-on-error», — это ci-actually-fails."
|
|
122
165
|
exit 1
|
|
123
166
|
fi
|
|
124
|
-
exit
|
|
167
|
+
exit "$RC"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Команды из свода существуют
|
|
2
|
+
|
|
3
|
+
**Намерение.** Агент берёт команды из свода дословно. Свод, который велит `npm run lint:cli`,
|
|
4
|
+
когда такого скрипта нет, отправляет агента в «Missing script» — и дальше тот либо чинит не то,
|
|
5
|
+
либо докладывает «проверил» про проверку, которой нет. Соседняя запись `entry-links-exist` ловит
|
|
6
|
+
в своде несуществующие ФАЙЛЫ; эта — КОМАНДЫ.
|
|
7
|
+
|
|
8
|
+
**Какой отказ это поймало.** Выборка 2026-09-11: 99 публичных репозиториев с `AGENTS.md`, где
|
|
9
|
+
упомянут `npm run`. В 9 свод называет скрипт, которого нет ни в одном `package.json`
|
|
10
|
+
репозитория. В двух история показывает механизм:
|
|
11
|
+
|
|
12
|
+
| Репозиторий | Что было | Что осталось |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `notefig/notefig` | `lint:cli` добавлен в `cbb21a4c` вместе со строкой в своде, удалён в тот же день в `ffaf7d8c` | `npm run lint:cli` в `AGENTS.md` |
|
|
15
|
+
| `JonnyKreng/pebble-navi` | `debug` добавлен в `1630de8` вместе со строкой в своде, удалён через два дня в `757c563` | `npm run debug # build + install + logs` |
|
|
16
|
+
|
|
17
|
+
Замер целиком — `incidents/README.md`, 2026-09-11.
|
|
18
|
+
|
|
19
|
+
**Почему машина, а не внимательность.** Скрипт удаляют в одном файле, свод живёт в другом, и
|
|
20
|
+
правка «fix(ci): resolve GitHub Actions failures» о своде не думает. Ровно как у
|
|
21
|
+
`entry-links-exist`: расхождение появляется не при написании свода, а через дни, в другой задаче.
|
|
22
|
+
|
|
23
|
+
**Что именно сверяется.**
|
|
24
|
+
|
|
25
|
+
| В своде | С чем |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `npm run X`, `pnpm run X`, `yarn run X`, `bun run X` | ключи блока `"scripts"` всех `package.json` репозитория, кроме `node_modules` |
|
|
28
|
+
| `make X` (и `make -j4 X`) | цели всех `Makefile`, `makefile`, `GNUmakefile`, `*.mk` |
|
|
29
|
+
| `just X` | рецепты и псевдонимы `justfile` |
|
|
30
|
+
|
|
31
|
+
Скрипты берутся только из блока `"scripts"`: в `pebble-navi` `debug` — ещё и имя зависимости, и
|
|
32
|
+
поиск любого `"debug":` в файле сказал бы «есть». Все `package.json` репозитория, а не только
|
|
33
|
+
корневой: команда из свода часто живёт в пакете рабочего пространства.
|
|
34
|
+
|
|
35
|
+
**Какие файлы.** Только своды агента: `AGENTS.md`, `CLAUDE.md`, `GEMINI.md` в корне (регистр
|
|
36
|
+
имени не важен), `.claude/CLAUDE.md`, `.github/copilot-instructions.md`. README не берётся: там
|
|
37
|
+
пишут и команды для ЧУЖОГО проекта — «в своём проекте запусти `npm run aqk`».
|
|
38
|
+
|
|
39
|
+
**Готовый аналог.** agentlint, правило `cmd-cross-reference`, — только npm-скрипты и только
|
|
40
|
+
корневой `package.json`. На живом проекте, где свод называет шестнадцать целей `make` и ни
|
|
41
|
+
одного `npm run`, оно молчит по построению.
|
|
42
|
+
|
|
43
|
+
**Чего НЕ ловит.**
|
|
44
|
+
|
|
45
|
+
- **`make` и `just` в прозе.** Ищутся только внутри кода — в обратных кавычках и блоках: «make
|
|
46
|
+
sure the tree is clean» — не команда. Свод, где команда написана прозой без кавычек, сверен не
|
|
47
|
+
будет. `npm run` однозначен и ищется везде.
|
|
48
|
+
- **Шаблоны и присваивания.** `npm run build:*`, `npm run cms:<имя>`, `make <цель>`, `make test
|
|
49
|
+
V=1` не называют одну команду и пропускаются. Отсюда же: свод, говорящий «скрипты `dev:local*`
|
|
50
|
+
сняты», находкой не считается.
|
|
51
|
+
- **Команды с каталогом.** `make -C docs html`, `make -f other.mk x`, `npm --prefix web run x`,
|
|
52
|
+
`pnpm --filter web run x` — цель живёт в чужом файле, по одной строке его не определить.
|
|
53
|
+
Пропускаются целиком.
|
|
54
|
+
- **Сокращения и прочие запускалки.** `yarn build` без `run`, `tox -e lint`, `task lint`,
|
|
55
|
+
`cargo xtask`, `uv run x` — не сверяются. Список взят из случаев, а не для полноты.
|
|
56
|
+
- **Цели из шаблонных правил make.** `%.o: %.c` покрывает `make foo.o`; такая цель будет названа
|
|
57
|
+
несуществующей. В своде агента такое встречается редко.
|
|
58
|
+
- **Что команда делает то, что обещает свод.** Скрипт `lint` может ничего не проверять — это
|
|
59
|
+
вопрос уже к нему, а не к своду.
|
|
60
|
+
|
|
61
|
+
**Образцы.** `red/` — свод велит `npm run debug`, а `debug` в `package.json` есть только в
|
|
62
|
+
зависимостях; и `make deploy` при `Makefile` с одной целью `test`: гейт обязан краснеть. `green/`
|
|
63
|
+
— те же имена существуют, `make -j4 lint` с флагом, `just fmt`, «make sure» в прозе, шаблоны
|
|
64
|
+
`npm run gen:*` и `make <target>`, `VERSION := 1.0` в `Makefile`: гейт обязан молчать.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
# Команда, которую свод велит запускать, существует в проекте.
|
|
3
|
+
#
|
|
4
|
+
# ЗАЧЕМ ИМЕННО ЭТО. Агент берёт команды из свода дословно. Скрипт переименовали или удалили —
|
|
5
|
+
# свод продолжает велеть «npm run lint:cli», агент зовёт несуществующее, получает «Missing
|
|
6
|
+
# script» и дальше либо чинит не то, либо сообщает «проверил» про проверку, которой нет.
|
|
7
|
+
# Соседняя запись `entry-links-exist` ловит в своде несуществующие ФАЙЛЫ; эта — КОМАНДЫ.
|
|
8
|
+
#
|
|
9
|
+
# СЛУЧАИ, ИЗ КОТОРЫХ ВЗЯЛАСЬ ЗАПИСЬ (2026-09-11, выборка из 99 публичных репозиториев с
|
|
10
|
+
# AGENTS.md, где упомянут «npm run»; подробности — incidents/README.md):
|
|
11
|
+
# notefig/notefig скрипт lint:cli появился в cbb21a4c вместе со строкой в своде и в тот
|
|
12
|
+
# же день удалён в ffaf7d8c; свод всё ещё велит «npm run lint:cli»
|
|
13
|
+
# JonnyKreng/pebble-navi скрипт debug добавлен в 1630de8 вместе со строкой в своде, удалён
|
|
14
|
+
# через два дня в 757c563; строка «npm run debug» в своде осталась
|
|
15
|
+
# Во втором случае `debug` есть в зависимостях — поэтому скрипты берутся из блока "scripts",
|
|
16
|
+
# а не любым «"debug":» в файле: иначе ложное «есть».
|
|
17
|
+
DIR="${1:-.}"
|
|
18
|
+
SKIP_LIB="$(dirname "$0")/../_skip.sh"
|
|
19
|
+
if [ ! -f "$SKIP_LIB" ]; then
|
|
20
|
+
echo "рядом с проверкой нет _skip.sh — обход не собран, проверка не состоялась"
|
|
21
|
+
echo " почини: скопируй гейт вместе с файлом kit/gates/_skip.sh, он общий на весь каталог"
|
|
22
|
+
exit 2
|
|
23
|
+
fi
|
|
24
|
+
. "$SKIP_LIB"
|
|
25
|
+
# Файл на месте — этого мало: подмена содержимого давала код 0. Метка стоит в КОНЦЕ _skip.sh,
|
|
26
|
+
# поэтому проверка ловит и обрыв файла на середине.
|
|
27
|
+
if [ "${AQK_SKIP_READY:-}" != 1 ]; then
|
|
28
|
+
echo "_skip.sh есть, но обход не собрался — проверка НЕ СОСТОЯЛАСЬ, а не прошла"
|
|
29
|
+
echo " почини: замени kit/gates/_skip.sh целым файлом из каталога"
|
|
30
|
+
exit 2
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# --- своды агента ---------------------------------------------------------------
|
|
34
|
+
# То, что агент читает при запуске. README не берём: там пишут и команды для ЧУЖОГО проекта
|
|
35
|
+
# («в своём проекте запусти npm run aqk»). Регистр имени не важен: `agents.md` встречается.
|
|
36
|
+
ENTRIES=$( { find "$DIR" -maxdepth 1 -type f \( -iname 'agents.md' -o -iname 'claude.md' -o -iname 'gemini.md' \) -print
|
|
37
|
+
for F in .claude/CLAUDE.md .github/copilot-instructions.md; do [ -f "$DIR/$F" ] && printf '%s\n' "$DIR/$F"; done
|
|
38
|
+
} 2>/dev/null | own_samples_filter "$DIR" | grep -v '^$')
|
|
39
|
+
[ -z "$ENTRIES" ] && { echo "свода агента здесь нет — сверять нечего"; exit 0; }
|
|
40
|
+
|
|
41
|
+
# --- что в проекте есть ---------------------------------------------------------
|
|
42
|
+
# Скрипты — только из блока "scripts" каждого package.json (рабочие пространства тоже: команда
|
|
43
|
+
# из свода часто живёт в пакете, а не в корне). Файл склеивается в строку: блок бывает и в одну.
|
|
44
|
+
SCRIPTS=$(find "$DIR" $(skip_find) -type f -name package.json -print 2>/dev/null | own_samples_filter "$DIR" | grep -v '^$' \
|
|
45
|
+
| while IFS= read -r P; do
|
|
46
|
+
tr '\r\n' ' ' < "$P" | sed -n 's/.*"scripts"[[:space:]]*:[[:space:]]*{\([^}]*\)}.*/\1/p' \
|
|
47
|
+
| grep -oE '"[^"]+"[[:space:]]*:' | sed 's/^"//; s/"[[:space:]]*:$//'
|
|
48
|
+
done)
|
|
49
|
+
HAS_PKG=$(find "$DIR" $(skip_find) -type f -name package.json -print 2>/dev/null | own_samples_filter "$DIR" | grep -v '^$' | head -1)
|
|
50
|
+
|
|
51
|
+
# Цели make: строка вне рецепта, слова до двоеточия; «VAR := x» — присваивание, не цель.
|
|
52
|
+
TARGETS=$(find "$DIR" $(skip_find) -type f \( -name Makefile -o -name makefile -o -name GNUmakefile -o -name '*.mk' \) -print 2>/dev/null \
|
|
53
|
+
| own_samples_filter "$DIR" | grep -v '^$' | while IFS= read -r M; do
|
|
54
|
+
awk '/^[^\t#][^=]*:([^=]|$)/ { sub(/:.*/, ""); n = split($0, a, /[ \t]+/); for (i = 1; i <= n; i++) if (a[i] != "") print a[i] }' "$M"
|
|
55
|
+
done)
|
|
56
|
+
|
|
57
|
+
# Рецепты just: «имя:», «@имя арг:», «alias имя := …».
|
|
58
|
+
RECIPES=$(find "$DIR" $(skip_find) -type f \( -name justfile -o -name Justfile -o -name .justfile \) -print 2>/dev/null \
|
|
59
|
+
| own_samples_filter "$DIR" | grep -v '^$' | while IFS= read -r J; do
|
|
60
|
+
awk '/^alias[ \t]+/ { print $2; next }
|
|
61
|
+
/^@?[A-Za-z_][A-Za-z0-9_-]*([ \t][^:=]*)?:([^=]|$)/ { sub(/^@/, ""); sub(/[ \t:].*/, ""); print }' "$J"
|
|
62
|
+
done)
|
|
63
|
+
|
|
64
|
+
has() { printf '%s\n' "$2" | grep -qxF -- "$1"; }
|
|
65
|
+
|
|
66
|
+
# --- что свод велит запускать ---------------------------------------------------
|
|
67
|
+
# «npm run X» однозначен где угодно. «make X» и «just X» — только внутри кода (обратные кавычки,
|
|
68
|
+
# блоки): в прозе «make sure» — не команда. Шаблоны («npm run build:*», «make <цель>») и
|
|
69
|
+
# присваивания («make test V=1») пропускаются: они не называют одну команду.
|
|
70
|
+
MISS=0
|
|
71
|
+
# Список команд — через файл, а не через трубу: цикл в трубе идёт в подоболочке, и отметка
|
|
72
|
+
# о находке из него не возвращается.
|
|
73
|
+
TMP=$(mktemp) || exit 2
|
|
74
|
+
trap 'rm -f "$TMP"' EXIT
|
|
75
|
+
report() {
|
|
76
|
+
echo "$1: «$2» — $3"
|
|
77
|
+
MISS=1
|
|
78
|
+
}
|
|
79
|
+
while IFS= read -r E; do
|
|
80
|
+
[ -n "$E" ] || continue
|
|
81
|
+
# Код свода: строки блоков целиком, вне блоков — только вставки в обратных кавычках.
|
|
82
|
+
CODE=$(awk '/^[ \t]*(```|~~~)/ { f = !f; next }
|
|
83
|
+
f { print; next }
|
|
84
|
+
{ while (match($0, /`[^`]+`/)) { print substr($0, RSTART + 1, RLENGTH - 2); $0 = substr($0, RSTART + RLENGTH) } }' "$E")
|
|
85
|
+
grep -oE '(npm|pnpm|yarn|bun)[[:space:]]+run[[:space:]]+[A-Za-z][A-Za-z0-9_:.-]*[*<{]?' "$E" \
|
|
86
|
+
| grep -v '[*<{:]$' | sed 's/\.$//; s/[[:space:]][[:space:]]*/ /g' | sort -u > "$TMP"
|
|
87
|
+
while IFS= read -r CMD; do
|
|
88
|
+
N=${CMD##* }
|
|
89
|
+
has "$N" "$SCRIPTS" && continue
|
|
90
|
+
if [ -n "$HAS_PKG" ]; then report "$E" "$CMD" "такого скрипта нет ни в одном package.json"
|
|
91
|
+
else report "$E" "$CMD" "package.json в репозитории нет вовсе"; fi
|
|
92
|
+
done < "$TMP"
|
|
93
|
+
for N in $(printf '%s\n' "$CODE" | grep -E '(^|[^A-Za-z0-9_-])make[[:space:]]' | grep -vE -- '-C|--directory|-f[[:space:]]|--file' \
|
|
94
|
+
| grep -oE '(^|[^A-Za-z0-9_-])make([[:space:]]+-[A-Za-z0-9]+)*[[:space:]]+[A-Za-z][A-Za-z0-9_.-]*=?' \
|
|
95
|
+
| grep -v '=$' | sed 's/.*[[:space:]]//' | sort -u); do
|
|
96
|
+
has "$N" "$TARGETS" || report "$E" "make $N" "такой цели нет ни в одном Makefile"
|
|
97
|
+
done
|
|
98
|
+
for N in $(printf '%s\n' "$CODE" | grep -oE '(^|[^A-Za-z0-9_-])just[[:space:]]+[A-Za-z][A-Za-z0-9_-]*' \
|
|
99
|
+
| sed 's/.*[[:space:]]//' | sort -u); do
|
|
100
|
+
has "$N" "$RECIPES" || report "$E" "just $N" "такого рецепта нет в justfile"
|
|
101
|
+
done
|
|
102
|
+
done <<EOF
|
|
103
|
+
$ENTRIES
|
|
104
|
+
EOF
|
|
105
|
+
|
|
106
|
+
if [ "$MISS" = 1 ]; then
|
|
107
|
+
echo " почини: верни команду в проект или исправь свод. Агент берёт команды из свода дословно:"
|
|
108
|
+
echo " несуществующая команда — это «Missing script» у агента и «проверил» про проверку, которой нет."
|
|
109
|
+
fi
|
|
110
|
+
exit "$MISS"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Запись каталога AQK. Норма и все поля — kit/gates/README.md.
|
|
2
|
+
# Читается программой; всё, что нельзя выполнить, живёт в README.md рядом.
|
|
3
|
+
|
|
4
|
+
intent: команды, которые свод велит запускать, существуют в проекте
|
|
5
|
+
intent_en: commands the agent rules tell it to run actually exist in the project
|
|
6
|
+
|
|
7
|
+
# Только там, где агенту вообще пишут свод. Проекту без AGENTS.md/CLAUDE.md сверять нечего.
|
|
8
|
+
trigger:
|
|
9
|
+
has_agent_entry: true
|
|
10
|
+
|
|
11
|
+
# Переносимая проверка — единственный рецепт. Готовое правило есть у agentlint
|
|
12
|
+
# (`cmd-cross-reference`), но оно знает только npm-скрипты; на живом проекте, где свод называет
|
|
13
|
+
# шестнадцать целей make, оно молчит по построению. Разбор — research/competitors/agentlint.md.
|
|
14
|
+
recipes:
|
|
15
|
+
any: bash {gate}/check.sh {dir}
|
|
16
|
+
|
|
17
|
+
proof: incidents/README.md, 2026-09-11 «свод велит команду, которой в проекте больше нет» —
|
|
18
|
+
9 из 99 публичных репозиториев с AGENTS.md называют скрипт, которого нет ни в одном
|
|
19
|
+
package.json; в двух история показывает, как: скрипт удалён, строка в своде осталась
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Rules
|
|
2
|
+
|
|
3
|
+
Make sure the tree is clean, then build and check before every commit:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm run build
|
|
7
|
+
npm run debug # build + install + logs
|
|
8
|
+
make test
|
|
9
|
+
make -j4 lint
|
|
10
|
+
just fmt
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Scripts named like `npm run gen:*` are generated; run `make <target>` for anything else.
|