agent-quality-kit 0.9.0 → 0.10.1

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 (68) hide show
  1. package/README.md +69 -10
  2. package/README.ru.md +68 -11
  3. package/kit/docs/ai/index.md +1 -0
  4. package/kit/docs/api-e2e.md +214 -0
  5. package/kit/docs/ready-made-rules.md +85 -0
  6. package/kit/gates/README.md +22 -0
  7. package/kit/gates/api-contract-has-arbiter/README.md +63 -0
  8. package/kit/gates/api-contract-has-arbiter/check.sh +117 -0
  9. package/kit/gates/api-contract-has-arbiter/gate.yml +15 -0
  10. package/kit/gates/api-contract-has-arbiter/green/.github/workflows/ci.yml +12 -0
  11. package/kit/gates/api-contract-has-arbiter/green/openapi.yaml +18 -0
  12. package/kit/gates/api-contract-has-arbiter/red/.github/workflows/ci.yml +11 -0
  13. package/kit/gates/api-contract-has-arbiter/red/openapi.yaml +18 -0
  14. package/kit/gates/ci-actually-fails/check.sh +9 -1
  15. package/kit/gates/commit-explains-itself/check.sh +15 -0
  16. package/kit/gates/complexity-limit/red/deep.go +17 -0
  17. package/kit/gates/complexity-limit/red/deep.rs +17 -0
  18. package/kit/gates/gate-not-weakened/red/suppress.go +5 -0
  19. package/kit/gates/gate-not-weakened/red/suppress.rs +3 -0
  20. package/kit/gates/protection-not-removed/README.md +67 -0
  21. package/kit/gates/protection-not-removed/check.sh +101 -0
  22. package/kit/gates/protection-not-removed/gate.yml +10 -0
  23. package/kit/gates/protection-not-removed/green/.aqk.yml +7 -0
  24. package/kit/gates/protection-not-removed/green/gates-declared.txt +4 -0
  25. package/kit/gates/protection-not-removed/red/.aqk.yml +7 -0
  26. package/kit/gates/protection-not-removed/red/gates-declared.txt +4 -0
  27. package/kit/gates/secrets-not-in-code/red/leak.go +9 -0
  28. package/kit/gates/secrets-not-in-code/red/leak.rs +5 -0
  29. package/kit/gates/todo-without-task/red/later.go +6 -0
  30. package/kit/gates/todo-without-task/red/later.rs +4 -0
  31. package/llms.txt +10 -4
  32. package/package.json +2 -1
  33. package/tool/commands/context.mjs +36 -1
  34. package/tool/commands/doctor.mjs +56 -2
  35. package/tool/commands/gates.mjs +2 -0
  36. package/tool/commands/probe.mjs +228 -0
  37. package/tool/commands/vitals.mjs +11 -3
  38. package/tool/i18n/en-docs.mjs +10 -0
  39. package/tool/i18n/en-gates.mjs +309 -0
  40. package/tool/i18n/en.mjs +10 -281
  41. package/tool/i18n/ru-docs.mjs +10 -0
  42. package/tool/i18n/ru-gates.mjs +311 -0
  43. package/tool/i18n/ru.mjs +10 -280
  44. package/tool/lib/cadence.mjs +57 -0
  45. package/tool/lib/core.mjs +1 -0
  46. package/tool/lib/evidence.mjs +15 -2
  47. package/tool/lib/execution.mjs +67 -0
  48. package/tool/lib/history.mjs +82 -0
  49. package/tool/lib/manifest.mjs +1 -1
  50. package/tool/lib/protection.mjs +52 -0
  51. package/tool/lib/prove.mjs +40 -13
  52. package/tool/lib/repo.mjs +12 -2
  53. package/tool/program.mjs +7 -0
  54. package/tool/selfcheck/smoke/_fixture.mjs +89 -0
  55. package/tool/selfcheck/smoke/api-contract.test.mjs +79 -0
  56. package/tool/selfcheck/smoke/commit-report.test.mjs +47 -0
  57. package/tool/selfcheck/smoke/protection.test.mjs +101 -0
  58. package/tool/selfcheck/smoke/release-tools.test.mjs +55 -0
  59. package/tool/selfcheck/smoke/verdict.test.mjs +40 -0
  60. package/tool/selfcheck/smoke.sh +194 -7
  61. package/tool/selfcheck/units-cadence.mjs +69 -0
  62. package/tool/selfcheck/units-context.mjs +24 -0
  63. package/tool/selfcheck/units-evidence.mjs +34 -0
  64. package/tool/selfcheck/units-execution.mjs +88 -0
  65. package/tool/selfcheck/units-level.mjs +32 -1
  66. package/tool/selfcheck/units-probe.mjs +100 -0
  67. package/tool/selfcheck/units-repo.mjs +31 -1
  68. package/tool/selfcheck/units-vitals.mjs +19 -0
@@ -29,6 +29,7 @@ const ruDocs = {
29
29
  sessionOk: "хук SessionStart отдаёт состояние агенту",
30
30
  sessionNo: (cmd) => `агент не получает состояние: ${cmd}`,
31
31
  versionOk: (v) => `${v}, свежая`,
32
+ versionUnknown: (v) => `${v}, до реестра не дозвонились — свежая ли, неизвестно`,
32
33
  versionOld: (l, cur) => `есть ${l}, у вас ${cur}`,
33
34
  },
34
35
  // Блок краткого вывода переехал сюда 2026-09-09: терминальный каталог снова перерос
@@ -68,6 +69,15 @@ const ruDocs = {
68
69
  runRed: (when, names) => `Последний прогон ${when} — КРАСНЫЕ: ${names}.`,
69
70
  andMore: (n) => `и ещё ${n}`,
70
71
  skipped: (n) => `Не запускались: ${n} — инструмента нет на этой машине, их состояние неизвестно.`,
72
+ probeNever: "Проба покрытия не делалась — что здесь не прикрыто ничем, НЕИЗВЕСТНО. Это не «прикрыто»: `aqk probe`.",
73
+ probeOff: "Проба покрытия выключена в манифесте (`probe: 0`) — что здесь не прикрыто ничем, никто не считает.",
74
+ probeUnknown: "Пробу покрытия провести не удалось — что здесь не прикрыто ничем, НЕИЗВЕСТНО. Это не «прикрыто».",
75
+ probeBlind: (n, behind) =>
76
+ `Не прикрыто ничем: ${n} классов брака в местах, куда чаще всего возвращаются с починкой` +
77
+ (behind ? ` (проба отстала на ${behind} коммитов)` : "") + ". Подробно: `aqk probe`.",
78
+ probeClean: (behind) =>
79
+ "Проба покрытия: в проверенных местах каждый применимый класс кто-то ловит" +
80
+ (behind ? ` (отстала на ${behind} коммитов)` : "") + ".",
71
81
  ratchets: (list) => `Храповики: ${list}. Список может только укорачиваться, увеличивать нельзя.`,
72
82
  where: (entry) => `Свод правил: ${entry}. Чем доказан диф: \`aqk report --since main\`.`,
73
83
  mapTitle: "ЧТО УМЕЕТ ЭТОТ ИНСТРУМЕНТ. Полный список команд — не пересказ, а тот же список,\nиз которого собрана справка:",
@@ -0,0 +1,311 @@
1
+ // tool/i18n/ru-gates.mjs — то, что программа говорит про ЗАПИСИ КАТАЛОГА: постановка,
2
+ // заготовка, храповик, сверка по намерению, разбор отказа, доказательство, проба, значок.
3
+ //
4
+ // ПОЧЕМУ ОТДЕЛЬНЫМ ФАЙЛОМ. Не ради размера: делить пополам запрещает наш же гейт
5
+ // `file-size-limit` («раздели по смыслу, а не пополам»). Здесь настоящий шов — команды про
6
+ // РЕПОЗИТОРИЙ (осмотр, уровень, состояние, обвязка) и команды про ЗАПИСИ КАТАЛОГА живут разной
7
+ // жизнью и правятся в разные дни. Разделено 2026-09-09, когда строки `probe` перевели файл
8
+ // за собственный предел в 500 строк.
9
+ export const ruGates = {
10
+ add: {
11
+ noSuchGate: (slug, cmd) => `Нет такого гейта: ${slug}\nСписок применимых — ${cmd}`,
12
+ toolMissing: (slug, missing) =>
13
+ `Записи ${slug} нужен ${missing.join(" и ")}, а его нет на этой машине.\n почини: поставь ${missing.join(" и ")} и повтори — запись делегирует готовому инструменту по устройству, своей проверки у неё нет.`,
14
+ noRecipe: (slug, stack, missing) =>
15
+ `У записи ${slug} нет команды ни под ${stack}, ни общей.` +
16
+ (Array.isArray(missing) && missing.length
17
+ ? `\n почини: поставь ${missing.join(" или ")} и повтори — запись делегирует готовому инструменту по устройству, своей проверки у неё нет.`
18
+ : `\n почини: добавь рецепт под свой стек в gate.yml этой записи либо возьми другую.`),
19
+ thisStack: "этот стек",
20
+ needName: (cmd, doctor) => `Укажи имя гейта: ${cmd}. Список — ${doctor}`,
21
+ noManifest: (cmd) => `Нет .aqk.yml — сначала ${cmd}`,
22
+ notApplicable: (why) => `Этот гейт к репозиторию не применим: ${why}`,
23
+ installAnyway: "Ставлю всё равно — решение твоё, но сторожить ему нечего.",
24
+ copied: (n) => `${n} файлов: проверка и образцы`,
25
+ declared: (cmd) => `гейт объявлен: ${cmd}`,
26
+ notDeclared: (why, slug, cmd) => `не тронут (${why}). Впиши сам: ${slug}: "${cmd}"`,
27
+ nextTitle: "Дальше:",
28
+ next1: "Проверь, что он краснеет и молчит там, где должен:",
29
+ expectFail: "→ ожидается отказ",
30
+ expectSilence: "→ ожидается тишина",
31
+ next2: "Впиши команду в хук коммита и в конвейер.",
32
+ next2Why: "Гейт, который никто не запускает, — не гейт.",
33
+ next3: (cmd) => `Прогон всех объявленных: ${cmd}`,
34
+ },
35
+
36
+ gnew: {
37
+ needName: (cmd) => `Укажи имя: ${cmd}`,
38
+ badName: (slug) => `Имя «${slug}» не годится: латиница через дефис, например secrets-not-in-code.\nИмя читают в чужих проектах — оно часть словаря.`,
39
+ looksExisting: (slug) => `Похоже, такое уже есть: ${slug}`,
40
+ recipeNotGate: "Рецепт под другой стек — это строка в recipes существующей записи.",
41
+ forceHint: (cmd) => `Всё равно завести новую: ${cmd}`,
42
+ exists: (path) => `${path} уже существует.`,
43
+ nextTitle: "Дальше — по порядку:",
44
+ n1: "Проверь, нет ли готового правила",
45
+ n1Where: "в ruff, eslint, semgrep.",
46
+ n1Why: "Готовое точнее, подробнее и его поддерживают без тебя. Своя проверка — запасная.",
47
+ n2: "Положи образцы.",
48
+ n2Red: "— код, на котором проверка обязана сработать.",
49
+ n2Green: "— тот же код, но правильный.",
50
+ n2Why: "Зелёный важнее: он ловит проверку, которая краснеет на исправном коде.",
51
+ n3: "Напиши проверку",
52
+ n3Where: "в check.sh. В тексте отказа — что именно сделать.",
53
+ n4: "Заполни gate.yml:",
54
+ n4What: "намерение, триггер, доказательство отказом.",
55
+ n5: "Прогони:",
56
+ n5Why: "Арбитр обязан покраснеть на red/ и промолчать на green/. Не прошло — не запись.",
57
+ },
58
+
59
+ ratchet: {
60
+ needName: (cmd) => `Укажи гейт: ${cmd}. Он должен быть уже объявлен в .aqk.yml`,
61
+ noManifest: (cmd) => `Нет .aqk.yml — сначала ${cmd}`,
62
+ notDeclared: (slug, cmd) => `Гейт «${slug}» не объявлен в .aqk.yml. Сначала: ${cmd}`,
63
+ already: (slug) => `На гейте «${slug}» храповик уже стоит.`,
64
+ notRunnable: (slug, cmd) =>
65
+ `Гейт «${slug}» не запускается: ${cmd}\n` +
66
+ `Снимать долг с несуществующего сторожа нельзя — в реестр попадут его же сообщения\n` +
67
+ `об ошибке, и он станет разрешением. Сначала почини команду.`,
68
+ registryHead: (slug, stamp) =>
69
+ `# Реестр долга: ${slug}\n` +
70
+ `# Снят ${stamp}. Список разрешается ТОЛЬКО укорачивать.\n` +
71
+ `# Новое нарушение красит гейт; исправленное вычёркивается автоматически.\n` +
72
+ `#\n` +
73
+ `# Долг без цели и срока не кончается. Цель — сколько нарушений считать погашенным долгом;\n` +
74
+ `# по достижении храповик скажет убрать обёртку. Срок необязателен, но если он есть,\n` +
75
+ `# после этой даты непогашенный долг красит гейт — срок без последствия не срок.\n` +
76
+ `# aqk-goal: 0\n` +
77
+ `# aqk-deadline:\n`,
78
+ recorded: (n) => `${n} нарушений записано долгом`,
79
+ libCopied: "обёртка скопирована в проект",
80
+ wrapped: "команда завёрнута в храповик",
81
+ changesTitle: "Что это меняет:",
82
+ fromToday: "со дня установки",
83
+ changes1: (fromToday) => `Правило действует ${fromToday}. Старый код трогать не надо, но новое`,
84
+ changes2: "нарушение того же класса гейт не пропустит.",
85
+ test1: "Проверка, что это храповик, а не советчик: «может ли новый код добавить нарушение",
86
+ test2: "и пройти?» Может — значит гейта нет.",
87
+ run: (cmd) => `Прогнать: ${cmd}`,
88
+ },
89
+
90
+ find: {
91
+ needQuery: (cmd) => `Опиши намерение словами: ${cmd}`,
92
+ example: 'find "отладочная печать не доезжает до прода"',
93
+ exists: "Такое уже есть — новую запись заводить не надо:",
94
+ match: (pct) => `совпадение ${pct}%`,
95
+ recipes: (langs) => `рецепты: ${langs}общий`,
96
+ existsWhy1: "Если у тебя рецепт под другой стек — это строка в recipes существующей",
97
+ existsWhy2: "записи, а не новый гейт. Намерение одно, исполнителей может быть много.",
98
+ near: "Точного совпадения нет, но рядом лежит:",
99
+ nearWhy: "Прочитай их README. Если намерение то же — дополняй, а не заводи новое.",
100
+ none: "Такого намерения в каталоге нет.",
101
+ journal: "В журнале есть шишка на эту тему:",
102
+ journalWhy: "Шишка записана — значит доказательство для новой записи уже есть.",
103
+ howTitle: "Как добавить свой гейт:",
104
+ how1: "Назови отказ.",
105
+ how1What: "Какой конкретный брак он поймал в живом проекте, чего это стоило.",
106
+ how1Why: "«Это хорошая практика» не принимается: так каталог набирает сотни пунктов и умирает.",
107
+ how2: "Заведи папку",
108
+ how2What: "— gate.yml, red/, green/, README.md.",
109
+ how2Why: "Норма записи со всеми полями — kit/gates/README.md",
110
+ how3: "Проверь машиной:",
111
+ how3Why: "Арбитр обязан покраснеть на red/ и промолчать на green/. Не прошло — не запись.",
112
+ how4: "Пришли изменением",
113
+ how4What: "в репозиторий комплекта.",
114
+ },
115
+
116
+ why: {
117
+ needQuery: (cmd) => `Опиши, что пропустили: ${cmd}`,
118
+ example: 'why "файл вырос до девяти тысяч строк"',
119
+ ciAtOnce: "разом: doctor --run",
120
+ ciOwnStep: "отдельным шагом",
121
+ unsure: "Уверенного совпадения нет. Похоже на эти записи:",
122
+ unsureByName: (cmd) => `Назови запись именем: ${cmd}`,
123
+ unsureNone: (cmd) => `Ни одна не подходит — значит сторожа не было: ${cmd}`,
124
+ decideTitle: "Дальше решаешь ты:",
125
+ decideQ: "это твоя частность или общий случай?",
126
+ decideWhy: "Общий — идёт в каталог и достаётся всем. Частный — остаётся у тебя.",
127
+ decideNote: (cmd) => `Урок в общий журнал в любом случае: ${cmd}`,
128
+ fix: "Почини так:",
129
+ noGuard: "Сторожа не было.",
130
+ noGuardWhy: "В каталоге нет записи с таким намерением.",
131
+ noGuardFix: (cmd) => `заведи запись — ${cmd}`,
132
+ noGuardHint: "Красный образец бери прямо из этой поломки: она уже случилась, выдумывать нечего.",
133
+ closest: (slug, pct) => `Ближайшая запись каталога: ${slug} совпадение ${pct}%`,
134
+ notInstalled: "Сторож есть в каталоге, но в этом проекте не поставлен.",
135
+ notInstalledHint1: "Он покраснеет на старом коде — это нормально: старое закрывается храповиком,",
136
+ notInstalledHint2: (cmd) => `новое ловится со дня установки. ${cmd}`,
137
+ declaredAs: (cmd) => `Объявлен: ${cmd}`,
138
+ notRunning: "Сторож объявлен, но не запускается.",
139
+ notRunningWhy: "Худший случай: тишина читается как успех.",
140
+ notRunningFix: "путь или программа из команды не существуют — проверь их.",
141
+ notRunningHint: "Отсутствие сигнала неотличимо от успеха, поэтому это не «мелочь в конфиге».",
142
+ bypassed: "Сторож есть и эту поломку ловит — значит его обошли.",
143
+ noCiFix: "конвейера нет. Проверка, которую гоняет только человек,",
144
+ noCiHint: "работает ровно до первого «забыл».",
145
+ notInCiFix: "конвейер есть, но этот гейт в нём не запускается.",
146
+ notInCiHint: (cmd) => `Дешевле всего одним шагом: ${cmd} — он гоняет всё объявленное.`,
147
+ inCiFix: (how) => `конвейер его гоняет (${how}) — значит красный прогон`,
148
+ inCiHint1: "кто-то пропустил или обошёл. Перенеси правило из текста в механику:",
149
+ inCiHint2: "блокирующий шаг, а не необязательный; запрет слияния при красном.",
150
+ blind: "Сторож есть, стоит и запускается — но этой поломки не видит.",
151
+ blindFix: (dir) => `положи в ${dir} кусок кода из этой поломки`,
152
+ blindHint1: "и доведи проверку до красного на нём. Порядок обратный привычному: сначала",
153
+ blindHint2: "образец, потом правка — иначе непонятно, что именно починено.",
154
+ blindCheck: "Проверить после правки: bash tool/selfcheck/gates.sh",
155
+ },
156
+
157
+ init: {
158
+ noDocs: (dir) => `Не найден корпус методичек: ${dir}\nПохоже, пакет установлен не полностью.`,
159
+ docsRu:
160
+ "методички в .aqk/docs/ остаются на русском — решение, а не недоделка.",
161
+ created: (n) => `создано (${n}):`,
162
+ andMore: (n) => `… и ещё ${n}`,
163
+ kept: (n) => `уже были на месте, не тронуты (${n}):`,
164
+ overwrite: (cmd) => `перезаписать: ${cmd}`,
165
+ nextTitle: "Что дальше — по порядку:",
166
+ n1a: "Открой",
167
+ n1b: "и заполни раздел «Команды». Команда, которую нельзя",
168
+ n1c: "скопировать и выполнить, — не команда, а пожелание.",
169
+ n2a: "Прочитай",
170
+ n2b: "— это обязательный минимум",
171
+ n2c: "проекта без привязки к языку. Пройди сверху вниз и отметь, чего нет.",
172
+ n3a: "Заполни",
173
+ n3b: "— гейты, образцы, журнал. Уровень соответствия AQK",
174
+ n3c: (cmd) => `считается по нему: ${cmd}.`,
175
+ n4a: "Поднимайся по ступеням",
176
+ n4b: "по одной",
177
+ n4c: ". Гейт стережёт существующий артефакт:",
178
+ n4d: "проверка на код, которого ещё нет, — мёртвое правило.",
179
+ burned: (cmd) => `Обжёгся на чём-то — запиши: ${cmd}`,
180
+ hookHint: (cmd) => `Claude Code: ${cmd} — состояние проекта будет попадать в контекст агента\n само, до первого действия. Для других агентов хука нет, и это не недоделка.`,
181
+ },
182
+
183
+ feedback: {
184
+ title: "Если пригодилось:",
185
+ star: (url) => `Поставь звезду — ${url}`,
186
+ issue: "Нашёл баг или не подошло — заведи Issue, самая полезная обратная связь: и то и другое.",
187
+ notRemembered: "запомнить не удалось (дом недоступен для записи) — сообщение появится снова",
188
+ once: "Это разовое сообщение: больше не покажется на этой машине.",
189
+ },
190
+
191
+ note: {
192
+ journalTitle: "Журнал шишек",
193
+ needTitle: (cmd) => `Нужен заголовок: ${cmd}`,
194
+ noJournal: (url) => `Клон журнала не найден.\nСделай один раз:\n git clone ${url}.git ~/projects/aqk\nили укажи путь: export AQK_HOME=/путь/к/aqk`,
195
+ journalMissing: (path) => `Журнал не найден: ${path}`,
196
+ emptyBody: `Тело записи пустое. Передай его на стандартный ввод, например:\n\n aqk note "заголовок" <<'EOF'\n **Что случилось.** ...\n **Чем это стоило.** ...\n **Вывод.** 🔧 ...\n EOF`,
197
+ noOutcome:
198
+ "В записи нет отметки решения. Урок без вывода — это история, а не урок.\n" +
199
+ "Припиши одну из трёх:\n" +
200
+ " ✅ **Стало гейтом:** <имя записи каталога>\n" +
201
+ " 🔧 **Стало правкой оснастки:** <что именно изменено>\n" +
202
+ " 👤 **Гейтом не станет:** <почему>",
203
+ unknownProject: "неизвестно",
204
+ projectField: "Проект",
205
+ pushed: (title) => `Записано и отправлено: ${title}`,
206
+ localOnly: (cmd) => `Записано локально, push не прошёл. Отправить: ${cmd}`,
207
+ },
208
+
209
+ blob: {
210
+ noDocs: (dir) => `Не найдены методички: ${dir}`,
211
+ header: (stamp) =>
212
+ `<!-- СОБРАНО КОМАНДОЙ aqk blob ${stamp} из kit/docs. Не править руками:\n` +
213
+ ` правки затрёт следующая сборка. Источник — отдельные файлы. -->\n\n` +
214
+ `# AQK — методички одним файлом\n`,
215
+ source: (path) => `источник: ${path}`,
216
+ done: (n, kb) => `GOD_AI.md — ${n} файлов, ${kb} КБ`,
217
+ rebuilt: "Собирается заново каждой командой. Править надо оригиналы в kit/docs.",
218
+ },
219
+
220
+ start: {
221
+ noRecipeHere: "нужен инструмент, которого нет на этой машине",
222
+ initFailed: (cmd) => `Не получилось разложить комплект. Начни с ${cmd}`,
223
+ tooManyFiles: (n) => `В репозитории уже ${n} файлов кода — это другой сценарий.`,
224
+ useDoctor: (cmd) => `${cmd} осмотрит, что есть, и разделит записи на три списка:`,
225
+ threeLists: "держит машина · применимо и не поставлено · не применимо и почему.",
226
+ anyway: (cmd) => `Всё равно поставить сторожей дня 0: ${cmd}`,
227
+ expectRed: "Готовься к красному: сторож, поставленный на живой код, краснеет на нём весь.",
228
+ expectRedFix: (cmd) => `Это лечится храповиком — ${cmd}, — а не отключением.`,
229
+ installed: (n) => `Поставлено сторожей дня 0: ${n}`,
230
+ noDebt1: "Долга нет: на пустом проекте им нечего пропускать. Тот же сторож, поставленный",
231
+ noDebt2: "через полгода, покраснел бы на всём старом коде — и его бы выключили.",
232
+ allDeclared: "Все применимые записи уже объявлены.",
233
+ notYet: "Не применимо пока:",
234
+ notYetWhy: "Появится признак — запись покажется сама.",
235
+ orderTitle: "Порядок, в котором это делают:",
236
+ o1: "Задача словами.",
237
+ o1What: "Что и кому, без единого технического слова.",
238
+ o1Why: "Пока задача не описана словами, любая архитектура защищает неизвестно что.",
239
+ o2: "Ограничения.",
240
+ o2What: "Сроки, деньги, нагрузка, чем нельзя пользоваться.",
241
+ o2Why: "Ограничения выбирают решение куда чаще, чем вкус: без них выбирают вкусом.",
242
+ o3: "Сайзинг.",
243
+ o3What: "Сколько данных, запросов, людей — числами, хотя бы порядком.",
244
+ o3Why: "Число отделяет «нужна очередь» от «хватит таблицы». Без него спорят словами.",
245
+ o4: "Архитектура.",
246
+ o4What: "И только теперь — из первых трёх, а не до них.",
247
+ softNote1: "Этот порядок программа не проверяет: он в .aqk/docs/, и агент может его",
248
+ softNote2: "проигнорировать. Машина держит другое — сторожей выше. Разница между",
249
+ softNote3: "мягким и жёстким тут ровно такая: текст просят, команду выполняют.",
250
+ next: "Дальше:",
251
+ nextWhy: "— прогнать всё, что объявлено",
252
+ },
253
+
254
+
255
+ probe: {
256
+ shallow: "клон мелкий (git clone --depth) — истории здесь нет, и это НЕ «починок не было». Полный клон: git fetch --unshallow",
257
+ badEvery: (v) => `в манифесте probe: «${v}» — это не число коммитов. Проба НЕ делается: подставить умолчание значило бы делать не то, что написано.`,
258
+ autoFirst: "пробы покрытия здесь ещё не делали — делаю её сам. Выключить: AQK_PROBE=0",
259
+ auto: (n) => `прошло ${n} коммитов с прошлой пробы — делаю её сам. Выключить: AQK_PROBE=0`,
260
+ title: "aqk probe — чего объявленные проверки не видят",
261
+ method: (files, entries) =>
262
+ `метод: в копию каждого файла подсаживается красный образец записи каталога, ` +
263
+ `по нему прогоняются ОБЪЯВЛЕННЫЕ гейты. Файлов: ${files}, применимых записей: ${entries}. ` +
264
+ `Рабочее дерево не трогается.`,
265
+ fixes: (n) => `починок в истории: ${n}`,
266
+ caught: (names) => `ловит: ${names}`,
267
+ blind: "НЕ ЛОВИТ НИКТО",
268
+ unknown: "проверить нечем — гейт не состоялся (нет делегированной программы)",
269
+ install: (cmd) => `закрыть: ${cmd}`,
270
+ noSampleFor: (ext) => `в каталоге нет красного образца под «${ext}» — проверить нечем`,
271
+ noGates: (cmd) => `гейтов не объявлено — пробовать нечем. Сначала: ${cmd}`,
272
+ noGit: "это не репозиторий git — истории починок взять неоткуда",
273
+ noFixes: "в истории не нашлось коммитов-починок: тема начинается с fix / исправ / почин",
274
+ summaryBlind: (n) =>
275
+ `не прикрыто классов: ${n}. Это не оценка кода: это места, куда возвращаются с починкой, ` +
276
+ `и брак, которого там не увидит ни одна ваша проверка.`,
277
+ summaryClean: "в проверенных местах каждый применимый класс кто-то ловит.",
278
+ },
279
+ prove: {
280
+ title: "aqk prove — доказательство гейтов",
281
+ running: "доказываю гейты по их образцам…",
282
+ proven: (n) => `доказано: ${n}`,
283
+ broken: (n) => `не ловят: ${n}`,
284
+ unprovable: (n) => `нечем доказать: ${n}`,
285
+ okRed: "краснеет на красном, молчит на зелёном",
286
+ redPassed: "промолчал на КРАСНОМ образце — гейт не ловит брак",
287
+ greenFailed: "покраснел на ЗЕЛЁНОМ образце — гейт ругается на исправный код",
288
+ empty: "команда пустая — объявление без команды защиты не даёт",
289
+ noSamples: "нет образцов — доказать нечем",
290
+ noTarget: "не видно, куда подставить каталог образца — команда написана руками",
291
+ otherRecipe: (lang) => `образцы написаны под рецепт «${lang}», а стоит другой — доказать нечем`,
292
+ noGates: "гейтов не объявлено — доказывать нечего",
293
+ needsProgram: (progs) => `НЕ ПРОВЕРЕНА здесь — нужен «${progs}»`,
294
+ noSamplesDir: "в .aqk.yml не заполнено поле samples — образцы искать негде",
295
+ nothingProven:
296
+ "ни один гейт не доказан. Уровень выше AQK-1 означал бы доверие к автору, а не факт:\n проект с гейтом «true» прошёл бы его так же, как проект с настоящей защитой.",
297
+ fix: (cmd) => `почини: поставь запись каталога вместе с образцами — ${cmd}`,
298
+ heading: "Доказательство гейтов",
299
+ },
300
+ badge: {
301
+ noManifest: (cmd) => `Нет .aqk.yml — уровня ещё нет. Начни с ${cmd}`,
302
+ notReached: (cmd) => `AQK-0 не достигнут — значок выдавать не за что. Чего не хватает: ${cmd}`,
303
+ redGates: (n, names) =>
304
+ `Красных гейтов: ${n} (${names}). Значок при красном гейте — заявление автора, а не факт машины.`,
305
+ hint: (n) => `Проверено прогоном. Зелёных гейтов: ${n}. Строку выше — в README.`,
306
+ keepTrue: (cmd) => `Чтобы значок не превратился во враньё, поставь в конвейер: ${cmd}`,
307
+ checkMissing: (places) => `Значка AQK нет ни в одном из файлов: ${places}. Вставить нужно этот:`,
308
+ checkMismatch: (where, level) => `Значок врёт: ${where}, а прогон говорит AQK-${level}. Заменить на:`,
309
+ checkOk: (level, where) => `Значок совпал с прогоном: AQK-${level} — ${where}`,
310
+ },
311
+ };