@nitra/cursor 5.3.3 → 5.4.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 (157) hide show
  1. package/.claude-template/settings.template.json +2 -2
  2. package/.pi-template/extensions/n-cursor-adr/docs/index.md +13 -24
  3. package/CHANGELOG.md +17 -0
  4. package/bin/n-cursor.js +43 -22
  5. package/lib/docs/llm.md +23 -12
  6. package/lib/docs/models.md +29 -18
  7. package/lib/docs/omlx-trace.md +51 -0
  8. package/lib/docs/omlx.md +31 -15
  9. package/lib/omlx.mjs +2 -5
  10. package/package.json +1 -1
  11. package/rules/abie/docs/fix.md +17 -11
  12. package/rules/adr/docs/fix.md +25 -140
  13. package/rules/bun/docs/fix.md +18 -151
  14. package/rules/capacitor/docs/fix.md +16 -13
  15. package/rules/capacitor/js/docs/platforms.md +31 -43
  16. package/rules/changelog/docs/fix.md +25 -169
  17. package/rules/ci4/docs/fix.md +11 -14
  18. package/rules/doc-files/doc-files.mdc +60 -0
  19. package/rules/doc-files/docs/fix.md +31 -0
  20. package/rules/doc-files/fix.mjs +19 -0
  21. package/{skills → rules}/doc-files/js/docgen-extract.mjs +42 -19
  22. package/{skills → rules}/doc-files/js/docgen-ignore.mjs +2 -1
  23. package/{skills → rules}/doc-files/js/docgen-scan.mjs +9 -1
  24. package/{skills → rules}/doc-files/js/docs/docgen-crc.md +1 -1
  25. package/rules/doc-files/js/docs/docgen-extract-anchors.md +45 -0
  26. package/rules/doc-files/js/docs/docgen-extract.md +39 -0
  27. package/rules/doc-files/js/docs/docgen-files-batch.md +35 -0
  28. package/rules/doc-files/js/docs/docgen-gen.md +46 -0
  29. package/rules/doc-files/js/docs/docgen-ignore.md +37 -0
  30. package/rules/doc-files/js/docs/docgen-prompts.md +39 -0
  31. package/rules/doc-files/js/docs/docgen-scan.md +54 -0
  32. package/rules/doc-files/js/docs/lint.md +36 -0
  33. package/rules/doc-files/js/docs/units-js.md +31 -0
  34. package/rules/doc-files/js/docs/units-rs.md +35 -0
  35. package/rules/doc-files/js/docs/units.md +30 -0
  36. package/rules/doc-files/js/lint.mjs +96 -0
  37. package/{skills → rules}/doc-files/js/units-rs.mjs +37 -17
  38. package/rules/doc-files/lint/docs/lint.md +37 -0
  39. package/rules/doc-files/lint/lint.mjs +105 -0
  40. package/rules/doc-files/meta.json +1 -0
  41. package/rules/docker/docs/fix.md +21 -161
  42. package/rules/efes/docs/fix.md +23 -194
  43. package/rules/feedback/docs/fix.md +10 -8
  44. package/rules/ga/docs/fix.md +10 -5
  45. package/rules/graphql/docs/fix.md +23 -119
  46. package/rules/hasura/docs/fix.md +19 -5
  47. package/rules/hasura/js/docs/internal_urls.md +34 -307
  48. package/rules/image-avif/docs/fix.md +16 -127
  49. package/rules/image-compress/docs/fix.md +20 -141
  50. package/rules/image-compress/js/docs/package_setup.md +22 -182
  51. package/rules/js-bun-db/docs/fix.md +23 -139
  52. package/rules/js-bun-db/js/docs/safety.md +33 -221
  53. package/rules/js-bun-redis/docs/fix.md +25 -114
  54. package/rules/js-bun-redis/js/docs/imports.md +18 -166
  55. package/rules/js-lint/docs/fix.md +30 -108
  56. package/rules/js-lint/js/docs/lint-findings.md +37 -17
  57. package/rules/js-lint/js/docs/lint.md +22 -238
  58. package/rules/js-lint/js/docs/tooling.md +34 -331
  59. package/rules/js-lint-ci/docs/fix.md +16 -149
  60. package/rules/js-lint-ci/js/docs/lint.md +16 -136
  61. package/rules/js-mssql/docs/fix.md +18 -123
  62. package/rules/js-mssql/js/docs/deps.md +28 -251
  63. package/rules/js-run/docs/fix.md +23 -138
  64. package/rules/js-run/js/docs/runtime.md +24 -378
  65. package/rules/k8s/docs/fix.md +18 -123
  66. package/rules/nginx-default-tpl/docs/fix.md +22 -118
  67. package/rules/nginx-default-tpl/js/docs/template.md +38 -360
  68. package/rules/npm-module/docs/fix.md +27 -89
  69. package/rules/npm-module/js/docs/header_doc_pointer.md +15 -15
  70. package/rules/npm-module/js/docs/package_structure.md +36 -258
  71. package/rules/npm-module/js/docs/rule_meta.md +25 -127
  72. package/rules/npm-module/js/docs/skill_meta.md +18 -180
  73. package/rules/php/docs/fix.md +21 -98
  74. package/rules/php/js/docs/tooling.md +20 -143
  75. package/rules/python/docs/fix.md +25 -157
  76. package/rules/python/js/docs/applies.md +20 -98
  77. package/rules/python/js/docs/tooling.md +27 -144
  78. package/rules/rego/docs/fix.md +24 -112
  79. package/rules/rego/js/docs/applies.md +20 -164
  80. package/rules/rego/js/docs/lint.md +15 -110
  81. package/rules/release/docs/fix.md +16 -114
  82. package/rules/rust/docs/fix.md +24 -119
  83. package/rules/rust/js/docs/applies.md +20 -129
  84. package/rules/security/docs/fix.md +21 -78
  85. package/rules/security/js/docs/sample_secret.md +23 -182
  86. package/rules/security/js/docs/trufflehog.md +19 -128
  87. package/rules/style-lint/docs/fix.md +16 -150
  88. package/rules/style-lint/js/docs/lint.md +21 -172
  89. package/rules/style-lint/js/docs/tooling.md +19 -184
  90. package/rules/tauri/docs/fix.md +26 -152
  91. package/rules/tauri/js/docs/cargo_mutants_config.md +21 -159
  92. package/rules/tauri/js/docs/tooling.md +20 -217
  93. package/rules/test/docs/fix.md +19 -127
  94. package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +15 -127
  95. package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +17 -153
  96. package/rules/test/js/docs/cargo_mutants_config.md +24 -164
  97. package/rules/test/js/docs/location.md +24 -126
  98. package/rules/test/js/docs/no-process-chdir.md +20 -151
  99. package/rules/test/js/docs/no-relative-fs-path.md +24 -261
  100. package/rules/test/js/docs/stryker_config.md +48 -148
  101. package/rules/test/js/docs/vitest-config-pool-forks.md +21 -164
  102. package/rules/text/docs/fix.md +25 -113
  103. package/rules/text/js/docs/forbidden-prettier.md +21 -132
  104. package/rules/text/js/docs/formatting.md +60 -251
  105. package/rules/text/js/docs/lint.md +17 -114
  106. package/rules/vue/docs/fix.md +25 -118
  107. package/rules/vue/js/docs/packages.md +25 -323
  108. package/rules/worktree/docs/fix.md +31 -150
  109. package/scripts/coverage-classify/docs/index.md +23 -209
  110. package/scripts/coverage-classify/docs/verdict-schema.md +14 -159
  111. package/scripts/dispatcher/docs/trace.md +35 -0
  112. package/scripts/docs/auto-rules.md +37 -361
  113. package/scripts/docs/lint-cli.md +12 -13
  114. package/scripts/docs/post-tool-use-fix.md +16 -15
  115. package/scripts/docs/skills-cli.md +26 -23
  116. package/scripts/docs/sync-claude-config.md +94 -34
  117. package/scripts/docs/worktree-cli.md +11 -34
  118. package/scripts/lib/docs/assert-project-root.md +14 -16
  119. package/scripts/lib/docs/changed-files.md +24 -139
  120. package/scripts/lib/docs/discover-check-rules-from-cursor.md +14 -146
  121. package/scripts/lib/docs/rule-predicates.md +20 -17
  122. package/scripts/lib/docs/run-rule-cli.md +14 -18
  123. package/scripts/lib/docs/run-rule.md +13 -20
  124. package/scripts/lib/docs/run-standard-rule.md +12 -15
  125. package/scripts/lib/docs/sync-gitignore-worktree.md +15 -18
  126. package/scripts/lib/rule-predicates.mjs +1 -1
  127. package/scripts/sync-claude-config.mjs +4 -1
  128. package/scripts/utils/docs/with-lock.md +19 -12
  129. package/scripts/utils/with-lock.mjs +4 -2
  130. package/skills/doc-aggregate/SKILL.md +2 -2
  131. package/skills/doc-aggregate/js/docgen-ignore.mjs +6 -6
  132. package/skills/doc-aggregate/js/docs/docgen-ignore.md +1 -1
  133. package/skills/doc-aggregate/js/docs/docgen-scan.md +78 -0
  134. package/skills/doc-files/.changes/260612-0012.md +5 -0
  135. package/skills/doc-files/.changes/260612-0031.md +5 -0
  136. package/skills/doc-files/.changes/260612-0036.md +5 -0
  137. package/skills/doc-files/.changes/260612-0114.md +5 -0
  138. package/skills/doc-files/SKILL.md +6 -6
  139. package/skills/fix/js/docs/llm-worker.md +17 -15
  140. package/skills/fix/js/docs/orchestrator.md +30 -23
  141. package/skills/fix/js/docs/t0.md +26 -16
  142. package/skills/start-check/js/docs/check.md +26 -22
  143. package/skills/taze/js/docs/diff.md +44 -20
  144. package/skills/doc-files/js/docs/docgen-extract-anchors.md +0 -27
  145. package/skills/doc-files/js/docs/docgen-extract.md +0 -29
  146. package/skills/doc-files/js/docs/docgen-files-batch.md +0 -25
  147. package/skills/doc-files/js/docs/docgen-gen.md +0 -30
  148. package/skills/doc-files/js/docs/docgen-prompts.md +0 -32
  149. package/skills/doc-files/js/docs/docgen-scan.md +0 -25
  150. package/skills/doc-files/js/docs/units-rs.md +0 -35
  151. /package/{skills → rules}/doc-files/js/docgen-crc.mjs +0 -0
  152. /package/{skills → rules}/doc-files/js/docgen-extract-anchors.mjs +0 -0
  153. /package/{skills → rules}/doc-files/js/docgen-files-batch.mjs +0 -0
  154. /package/{skills → rules}/doc-files/js/docgen-gen.mjs +0 -0
  155. /package/{skills → rules}/doc-files/js/docgen-prompts.mjs +0 -0
  156. /package/{skills → rules}/doc-files/js/units-js.mjs +0 -0
  157. /package/{skills → rules}/doc-files/js/units.mjs +0 -0
@@ -1,218 +1,32 @@
1
- # `coverage-classify/index.mjs`
1
+ ---
2
+ docgen:
3
+ source: npm/scripts/coverage-classify/index.mjs
4
+ crc: 06249ac8
5
+ score: 100
6
+ ---
2
7
 
3
- ## Огляд
4
-
5
- Модуль `coverage-classify/index.mjs` — це **публічна точка входу** (Public API) класифікатора survived-мутантів за допомогою Claude API від Anthropic. Він відповідає за оркестрацію LLM-класифікації мутантів, які пережили mutation-testing раунд (тобто не були вбиті жодним тестом), і повертає для кожного з них вердикт у форматі `{ verdict, confidence, reason, suggestedTest? }`.
6
-
7
- Призначення модуля — допомогти автоматичним інструментам типу `/n-coverage-fix` ухвалювати рішення, чи варто дописувати тест на конкретний survived-мутант, чи можна його ігнорувати як equivalent / not-worth-testing.
8
-
9
- Ключові архітектурні характеристики:
10
-
11
- - **Graceful degradation:** відсутність змінної `ANTHROPIC_API_KEY` або непрацездатний dynamic import пакета `@anthropic-ai/sdk` не приводить до краху — функція мовчки повертає порожній масив `[]`, попередньо вивівши попередження у `console.warn`.
12
- - **Persistent cache:** результати класифікації кешуються на диск через утиліти з `./cache.mjs`. При зміні `MODEL` кеш повністю інвалідується (entries чистяться, поле `model` оновлюється). Це гарантує консистентність вердиктів між запусками за умови незмінного контексту мутанта.
13
- - **Prompt caching на стороні API:** системний промпт передається з `cache_control: { type: 'ephemeral' }` — усі мутанти одного прогону reuse кешований префікс на стороні Anthropic API (економія токенів).
14
- - **Retry з експоненційним backoff:** кожен мутант отримує до `MAX_RETRIES + 1 = 3` спроб; між спробами — затримка `retryDelayMs * 2 ** attempt`. Після вичерпання спроб — повертається **conservative fallback** `worth-testing/confidence=0`, щоб не втратити мутант з виду.
15
-
16
- Модуль не виконує мережевих викликів самостійно — він делегує їх в `client.messages.create(...)` (за замовчуванням це інстанс `new Anthropic()` з SDK).
17
-
18
- ## Експорти / API
19
-
20
- | Експорт | Тип | Опис |
21
- | ---------- | -------- | ------------------------------------------------------------------------------------------------ |
22
- | `classify` | function | Іменований async-експорт. Класифікує всіх survived-мутантів і повертає масив `{ key, verdict }`. |
23
-
24
- Інші ідентифікатори файлу (`MODEL`, `MAX_RETRIES`, `DEFAULT_RETRY_DELAY_MS`, `FALLBACK_VERDICT`, `classifyOne`) — **внутрішні**, не експортуються.
25
-
26
- ### Сигнатура `classify`
27
-
28
- ```js
29
- export async function classify(survived, cwd, opts = {})
30
- ```
31
-
32
- **Параметри:**
33
-
34
- - `survived` — `Array<{ file: string, mutants: Array<object>, exampleTest?: object|null, recommendationText?: string|null }>` — список survived-груп. Структура аналогічна до використовуваної в `COVERAGE.md` (звіт mutation-testing). Кожна група відповідає одному файлу та містить масив мутантів.
35
- - `cwd` — `string` — абсолютний шлях кореня проєкту. Використовується для:
36
- - формування дефолтного шляху кешу (`<cwd>/npm/reports/coverage-classify.cache.json`);
37
- - резолвінгу шляхів до файлів-джерел мутантів (для побудови юзер-промпта та cache key).
38
- - `opts` — `{ cachePath?: string, client?: object, retryDelayMs?: number }` — опціональні ін'єкції для тестування:
39
- - `cachePath` — кастомний шлях до файлу кешу.
40
- - `client` — підставний Anthropic SDK client (для unit-тестів без реальних мережевих викликів). Має мати метод `messages.create(...)`.
41
- - `retryDelayMs` — базова затримка для exp-backoff у мс. `0` фактично вимикає sleep між retries (зручно для тестів).
42
-
43
- **Повертає:** `Promise<Array<{ key: string, verdict: object }>>`
44
-
45
- - `key` — рядок формату `<file>:<line>:<col>:<replacement>`, який однозначно ідентифікує мутант для зовнішнього коду.
46
- - `verdict` — об'єкт з полями `{ verdict, confidence, reason, suggestedTest? }` (формат описаний у `./verdict-schema.mjs`).
47
-
48
- При відсутності API-ключа або SDK — повертає `[]`.
49
-
50
- ## Функції
51
-
52
- ### `classify(survived, cwd, opts)` — публічна
53
-
54
- **Сигнатура:** `async function classify(survived, cwd, opts = {}) -> Promise<Array<{key, verdict}>>`
55
-
56
- **Параметри:** див. розділ «Експорти / API» вище.
57
-
58
- **Повертає:** `Promise<Array<{ key: string, verdict: object }>>` — плаский список вердиктів по всіх мутантах усіх груп (порядок: group-by-group, mutant-by-mutant у межах групи).
59
-
60
- **Кроки виконання (orchestration):**
61
-
62
- 1. Резолвить `cachePath` (дефолт: `<cwd>/npm/reports/coverage-classify.cache.json`) та `retryDelayMs` (дефолт: `DEFAULT_RETRY_DELAY_MS = 1000`).
63
- 2. Перевіряє `env.ANTHROPIC_API_KEY`. Якщо відсутній — `console.warn` + `return []`.
64
- 3. Виконує `await import('@anthropic-ai/sdk')`. Якщо пакет не встановлено — `console.warn` + `return []`.
65
- 4. Створює клієнт: `opts.client ?? new Anthropic()`.
66
- 5. Завантажує кеш через `readCache(cachePath)`. Якщо `cache.model !== MODEL` — повністю чистить `cache.entries` і виставляє `cache.model = MODEL` (інвалідація при зміні моделі).
67
- 6. Ітерує `survived.mutants`:
68
- - Будує `lookupKey = "<group.file>:<line>:<col>:<replacement>"`.
69
- - Обчислює `cacheKey = deriveCacheKey(join(cwd, group.file), mutant)`.
70
- - Якщо в кеші є запис — повертає його (нормалізуючи поля, опціонально розгортаючи `suggestedTest`).
71
- - Інакше викликає `classifyOne(client, group, mutant, cwd, retryDelayMs)` і записує результат у `cache.entries[cacheKey]` з полем `classifiedAt: new Date().toISOString()` (якщо `cacheKey` truthy).
72
- 7. Зберігає кеш на диск через `writeCache(cachePath, cache)`.
73
- 8. Повертає накопичений `verdicts`.
74
-
75
- **Side effects:**
76
-
77
- - **Disk I/O:** читання і запис файлу кешу (`<cwd>/npm/reports/coverage-classify.cache.json` за замовчуванням).
78
- - **Мережа:** виклики `client.messages.create(...)` до Anthropic API (через делегування в `classifyOne`).
79
- - **stdout/stderr:** `console.warn(...)` при відсутності ключа / SDK / при фатальних retry-фейлах окремих мутантів.
80
- - **Час:** функція **очікує** мережеві запити послідовно (no parallelism між мутантами) — у гіршому випадку загальна тривалість = `N × (MAX_RETRIES+1) × API_latency + sum(backoff)`.
81
- - **Стан системи:** мутації `cache` на місці (об'єкт переписується), потім дамп на диск.
82
-
83
- ### `classifyOne(client, group, mutant, cwd, retryDelayMs)` — внутрішня
84
-
85
- **Сигнатура:** `async function classifyOne(client, group, mutant, cwd, retryDelayMs) -> Promise<object>`
8
+ # index.mjs
86
9
 
87
- **Параметри:**
88
-
89
- - `client` — `{ messages: { create: Function } }` — Anthropic SDK client (реальний або mock).
90
- - `group` — `{ file: string }` — група для контексту (з неї потрібно лише `.file` — повний шлях до файлу-джерела).
91
- - `mutant` — `object` — дані мутанта (передаються в `buildUserPrompt` як `{ ...mutant, file: group.file }`).
92
- - `cwd` — `string` — корінь проєкту, потрібний для resolving шляхів у `buildUserPrompt`.
93
- - `retryDelayMs` — `number` — базова затримка для exp-backoff (`0` у тестах вимикає sleep).
94
-
95
- **Повертає:** `Promise<object>` — розпарсений вердикт (через `parseVerdict(text)`) або копія `FALLBACK_VERDICT`.
96
-
97
- **Кроки виконання:**
98
-
99
- 1. Будує юзер-промпт: `userPrompt = buildUserPrompt({ ...mutant, file: group.file }, cwd)`.
100
- 2. Цикл `for (attempt = 0; attempt <= MAX_RETRIES; attempt++)`:
101
- - Виконує `client.messages.create({ model: MODEL, max_tokens: 1024, system: [{ type:'text', text: SYSTEM_PROMPT, cache_control:{ type:'ephemeral' } }], messages: [{ role:'user', content: userPrompt }] })`.
102
- - Дістає текст з `response?.content?.[0]?.text ?? ''`.
103
- - Повертає `parseVerdict(text)`. Якщо `parseVerdict` кидає — це впаде як виключення і потрапить в `catch` цієї ж ітерації (тобто буде ще одна retry-спроба).
104
- 3. На `catch`: запам'ятовує `lastError`. Якщо `attempt < MAX_RETRIES && retryDelayMs > 0` — `await setTimeout(retryDelayMs * 2 ** attempt)`.
105
- 4. Після вичерпання спроб: `console.warn` з деталями (file:line:col, кількість спроб, повідомлення останньої помилки) і `return { ...FALLBACK_VERDICT }` (копія, щоб уникнути shared mutation на константі).
106
-
107
- **Side effects:**
108
-
109
- - Мережевий виклик до Anthropic API (1..MAX_RETRIES+1 разів).
110
- - `setTimeout` з `node:timers/promises` (async sleep).
111
- - `console.warn` при фатальному фейлі.
112
-
113
- ## Залежності
114
-
115
- ### Внутрішні (relative imports)
116
-
117
- | Шлях | Що використовується | Призначення |
118
- | ---------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
119
- | `./cache.mjs` | `deriveCacheKey`, `readCache`, `writeCache` | Робота з персистентним кешем класифікацій (deriving детермінованого ключа з мутанта + читання/запис JSON). |
120
- | `./prompt.mjs` | `buildUserPrompt`, `SYSTEM_PROMPT` | Побудова промптів для LLM: системний (статичний, кешується) та юзер-промпт (динамічний, per-mutant). |
121
- | `./verdict-schema.mjs` | `parseVerdict` | Парсинг та валідація JSON-відповіді LLM у структурований об'єкт вердикту. |
122
-
123
- ### Зовнішні
124
-
125
- | Пакет/модуль | Що використовується | Як підключено |
126
- | ---------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------- |
127
- | `node:path` | `join` | Статичний `import`. Збирання шляхів до cache file та source file. |
128
- | `node:process` | `env` | Статичний `import`. Читання `ANTHROPIC_API_KEY`. |
129
- | `node:timers/promises` | `setTimeout` | Статичний `import`. Async sleep для exp-backoff між retries. |
130
- | `@anthropic-ai/sdk` | `Anthropic` (default export) | **Dynamic** `await import(...)` всередині `classify` — graceful degradation, якщо пакет не встановлено. |
131
-
132
- ### Зовнішні артефакти середовища
133
-
134
- - **Змінна оточення `ANTHROPIC_API_KEY`** — обов'язкова. Без неї модуль не робить мережевих викликів.
135
- - **Файл кешу** — за замовчуванням `<cwd>/npm/reports/coverage-classify.cache.json`. Структура: `{ model: string, entries: { [cacheKey]: { verdict, confidence, reason, suggestedTest?, classifiedAt } } }`.
136
-
137
- ### Константи модуля
138
-
139
- | Константа | Значення | Призначення |
140
- | ------------------------ | ------------------------------------------------------------ | --------------------------------------------------------------------------- |
141
- | `MODEL` | `'claude-sonnet-4-6'` | ID моделі Anthropic для класифікації. Зміна → автоматична інвалідація кешу. |
142
- | `MAX_RETRIES` | `2` | Кількість **повторних** спроб (всього спроб: `MAX_RETRIES + 1 = 3`). |
143
- | `DEFAULT_RETRY_DELAY_MS` | `1000` | Базова затримка для exp-backoff (мс). Реальні delays: 1000, 2000, 4000. |
144
- | `FALLBACK_VERDICT` | `{ verdict: 'worth-testing', confidence: 0, reason: '...' }` | Консервативний вердикт при фатальному фейлі (мутант ще не відкидається). |
145
-
146
- ## Потік виконання / Використання
147
-
148
- ### Типовий сценарій виклику
149
-
150
- Модуль викликається з вищерівневого pipeline (наприклад, `/n-coverage-fix` або інший CLI поверх mutation-testing звіту):
151
-
152
- ```js
153
- import { classify } from '<repo>/npm/scripts/coverage-classify/index.mjs'
154
-
155
- // survived зазвичай парситься з COVERAGE.md
156
- const survived = [
157
- {
158
- file: 'src/utils/foo.mjs',
159
- mutants: [
160
- { line: 10, col: 5, replacement: '=== 0', original: '!== 0', mutator: 'EqualityOperator' }
161
- // ...
162
- ],
163
- exampleTest: null,
164
- recommendationText: null
165
- }
166
- // ...
167
- ]
168
-
169
- const verdicts = await classify(survived, process.cwd())
170
-
171
- for (const { key, verdict } of verdicts) {
172
- if (verdict.verdict === 'worth-testing' && verdict.confidence > 0.5) {
173
- // дописати тест
174
- }
175
- }
176
- ```
177
-
178
- ### Стани виходу та граничні випадки
179
-
180
- | Стан | Поведінка |
181
- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------ |
182
- | `ANTHROPIC_API_KEY` не виставлений | `console.warn` + `return []` (порожній масив, не помилка). |
183
- | Пакет `@anthropic-ai/sdk` не встановлено | `console.warn` + `return []`. |
184
- | Кеш hit для мутанта | Мережевий виклик не виконується, повертається cached verdict. |
185
- | Кеш miss, успішна класифікація | Виклик API, парсинг, запис у кеш, push у verdicts. |
186
- | Кеш miss, всі retry-спроби впали | `console.warn` з деталями + `FALLBACK_VERDICT` push у verdicts (мутант не пропадає). |
187
- | Зміна `MODEL` у коді | На наступному запуску `cache.entries` повністю обнуляється. |
188
- | `cacheKey === null/undefined` (наприклад, неможливо derive) | Класифікація виконується, але **не** кешується (запис у кеш пропускається). |
189
-
190
- ### Послідовність всередині одного прогону (timeline)
10
+ ## Огляд
191
11
 
192
- 1. Читання `survived` (відповідальність caller'а).
193
- 2. `classify(...)` запускається → preflight перевірки (API key, SDK).
194
- 3. Завантаження дискового кешу → можливе очищення при зміні моделі.
195
- 4. **Послідовно** (не паралельно) для кожного `(group, mutant)`:
196
- - Cache lookup (за `cacheKey`).
197
- - Якщо miss — `classifyOne` з retry-логікою.
198
- - Запис у кеш-об'єкт у пам'яті.
199
- 5. Після обходу всіх мутантів — атомарний `writeCache` на диск.
200
- 6. Повернення `verdicts` caller'у.
12
+ Файл забезпечує класифікацію записів через послідовну спробу отримання результату з кешу, первинного моделі та хмарного сервісу. Якщо кеш не містить даних, відбувається перехід до наступного рівня, доки не буде досягнуто консервативного запасного варіанту. Результати класифікації записуються у кеш. Код спирається на конфіги з файлу coverage-classify.cache.json.
201
13
 
202
- ### Особливості та інваріанти
14
+ ## Поведінка
203
15
 
204
- - **Послідовність викликів API:** немає паралелізму між мутантами. Це навмисно — обмеження по rate-limits Anthropic API та для стабільної взаємодії з prompt cache.
205
- - **Prompt cache reuse:** оскільки системний промпт ідентичний для всіх мутантів і помічений `cache_control: ephemeral`, Anthropic API повторно використовує кешований префікс — суттєва економія input-токенів на великих прогонах.
206
- - **Ідемпотентність:** повторний запуск з тим же `cachePath` і незмінним `survived` дає той же `verdicts` без додаткових мережевих викликів (повний cache hit).
207
- - **Conservative fallback:** при фейлі класифікації мутант **не** відкидається — він отримує `worth-testing/confidence=0`, що змушує caller свідомо вирішувати, чи приймати такий вердикт. Це усуває ризик «непомітної втрати» мутанта через мережеву помилку.
208
- - **Defensive copy fallback:** повертається `{ ...FALLBACK_VERDICT }`, а не сам об'єкт щоб caller'и не могли випадково замутувати константу.
16
+ 1. Пошук результату в кеші.
17
+ 2. Якщо результат знайдено, використовується збережений вердикт.
18
+ 3. Якщо результат не знайдено, намагається отримати вердикт через перший рівень.
19
+ 4. Якщо перший рівень не вдається, намагається отримати вердикт через другий рівень.
20
+ 5. Якщо другий рівень не вдається, використовується консервативний запасний варіант.
21
+ 6. Результати класифікації записуються в кеш.
209
22
 
210
- ### Тестування
23
+ ## Публічний API
211
24
 
212
- Для unit-тестів зручно ін'єктувати:
25
+ classify Класифікує survived мутанти, перенаправляючи їх до CLOUD_MIN, якщо результат resolveModel дорівнює CLOUD_MIN, інакше до fallback.
213
26
 
214
- - `opts.client = { messages: { create: async () => ({ content: [{ text: '...' }] }) } }` — підставний клієнт.
215
- - `opts.cachePath = '/tmp/test-cache.json'` — ізольований кеш.
216
- - `opts.retryDelayMs = 0` — миттєві retries без `setTimeout`-блокувань.
27
+ ## Гарантії поведінки
217
28
 
218
- Файл `index.mjs` спроєктований так, що жодних інших залежностей мокати **не потрібно** — `cache.mjs`/`prompt.mjs`/`verdict-schema.mjs` мають детерміновану поведінку для тестів.
29
+ - Read-only: файл не виконує операцій запису у файлову систему.
30
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
31
+ - Кешує результати в межах одного прогону.
32
+ - Не звертається до мережі.
@@ -1,175 +1,30 @@
1
1
  ---
2
2
  docgen:
3
3
  source: npm/scripts/coverage-classify/verdict-schema.mjs
4
- crc: 8a2c0df1
4
+ crc: ecf5dfe1
5
+ score: 100
5
6
  ---
6
7
 
7
8
  # verdict-schema.mjs
8
9
 
9
10
  ## Огляд
10
11
 
11
- Модуль `verdict-schema.mjs` визначає контракт даних для відповіді LLM-класифікатора в межах інструменту `coverage-classify`. Класифікатор приймає рішення про те, як трактувати вцілілого мутанта (surviving mutant) після прогону мутаційного тестування: чи варто на нього писати тест, чи він поведінково еквівалентний, чи це захисна гілка для неможливого стану, чи це склейка/обгортка, що покривається інтеграційними тестами.
12
+ Файл надає схему `VerdictSchema` для валідації вердиктів LLM-класифікатора. Функція `parseVerdict` витягує JSON-об'єкт з сирої текстової відповіді моделі та перевіряє його відповідність визначеній схемі.
12
13
 
13
- Файл розв'язує дві задачі:
14
+ ## Поведінка
14
15
 
15
- 1. Декларує **Zod-схему** `VerdictSchema`, якій має відповідати JSON-об'єкт-вердикт від LLM.
16
- 2. Надає утиліту `parseVerdict`, яка приймає сирий текст відповіді LLM, витягує з нього перший знайдений JSON-блок, парсить його і валідовує за схемою.
16
+ VerdictSchema
17
+ Визначає схему для валідації вердикту LLM-класифікатора
17
18
 
18
- Призначення схеми — стабілізувати взаємодію з LLM: навіть якщо LLM повертає вердикт у вигляді тексту з преамбулою чи поясненнями, модуль робить «liberal-in, strict-out» — толерантно витягує JSON-острівець, а далі застосовує жорстку валідацію (категорія, межі впевненості, мінімальна осмисленість пояснення).
19
+ parseVerdict
20
+ Витягує JSON-об'єкт з текстової відповіді LLM і валідує його за схемою
19
21
 
20
- Категорії вердикту (`verdict`):
22
+ ## Публічний API
21
23
 
22
- - `worth-testing` pure logic / реальні гілки, варто писати юніт-тест.
23
- - `equivalent` мутант поведінково еквівалентний оригіналу, він не killable.
24
- - `defensive` — гілка для impossible state (захисний код), не killable.
25
- - `glue` — CLI entry / обгортка `runStandardRule` тощо; покривається інтеграційними тестами.
26
- - `wrapper` — тонкий `spawn`/`fetch`-обгортка; покривається інтеграційними тестами.
24
+ VerdictSchemaСхема для структури вердикту.
25
+ parseVerdictВитягує JSON з тексту LLM і перевіряє його за схемою VerdictSchema.
27
26
 
28
- ## Експорти / API
27
+ ## Гарантії поведінки
29
28
 
30
- Модуль експортує два символи (обидва іменовані експорти ES modules):
31
-
32
- | Символ | Тип | Призначення |
33
- | --------------- | --------------------------- | ---------------------------------------------------- |
34
- | `VerdictSchema` | `ZodObject` | Схема валідації для verdict-об'єкта LLM. |
35
- | `parseVerdict` | `function(rawText: string)` | Парсер raw-text відповіді LLM у валідований verdict. |
36
-
37
- ### `VerdictSchema`
38
-
39
- Z-об'єкт зі строго визначеними полями:
40
-
41
- - `verdict` — `z.enum(['worth-testing', 'equivalent', 'defensive', 'glue', 'wrapper'])`. Обов'язкове. Будь-яке інше значення відхиляється.
42
- - `confidence` — `z.number().min(0).max(1)`. Обов'язкове. Дробове число в діапазоні `[0, 1]`, де `0` — повна невпевненість, `1` — повна впевненість LLM у вердикті.
43
- - `reason` — `z.string().min(20).max(500)`. Обов'язкове. Текстове пояснення довжиною від 20 до 500 символів — мінімум змушує LLM аргументувати, максимум — обмежує балакучість.
44
- - `suggestedTest` — `z.string().max(300).optional()`. Опціональне. Текстова підказка/начерк тесту довжиною до 300 символів; за домовленістю заповнюється переважно для категорії `worth-testing`.
45
-
46
- Поля поза цим переліком не описано як заборонені на рівні схеми; за замовчуванням Zod пропускає невідомі ключі без помилки, але вони не з'являться в результаті типізації, що використовує цей модуль. Якщо в майбутньому потрібен strict-режим, його можна додати через `.strict()`.
47
-
48
- ### `parseVerdict(rawText)`
49
-
50
- Високорівнева функція-фасад: «витягни JSON з тексту LLM і провалідуй».
51
-
52
- ## Функції
53
-
54
- ### `parseVerdict(rawText)`
55
-
56
- Сигнатура:
57
-
58
- ```js
59
- function parseVerdict(rawText: string): {
60
- verdict: 'worth-testing' | 'equivalent' | 'defensive' | 'glue' | 'wrapper',
61
- confidence: number,
62
- reason: string,
63
- suggestedTest?: string
64
- }
65
- ```
66
-
67
- Параметри:
68
-
69
- - `rawText` — `string`. Сирий текст, повернений LLM. Може містити довільний preamble/postamble навколо JSON-блоку (пояснення, markdown-загортки тощо). Очікується, що в тексті є рівно один корисний JSON-об'єкт-вердикт.
70
-
71
- Повертає:
72
-
73
- - Обʼєкт verdict, який пройшов валідацію `VerdictSchema`. Тип повернення відповідає схемі (див. вище).
74
-
75
- Side effects:
76
-
77
- - Жодних. Функція чиста: не пише в файлову систему, не звертається до мережі, не модифікує параметри.
78
-
79
- Алгоритм:
80
-
81
- 1. Знайти позицію першого символу `{` через `rawText.indexOf('{')` → `jsonStart`.
82
- 2. Знайти позицію останнього `}` через `rawText.lastIndexOf('}')` → `jsonEnd`.
83
- 3. Якщо хоча б один з індексів дорівнює `-1` — кинути `Error('No JSON object found in LLM response')`.
84
- 4. Інакше — вирізати підрядок `rawText.slice(jsonStart, jsonEnd + 1)` (включно з обома фігурними дужками) та віддати у `JSON.parse`.
85
- 5. Результат парсингу передати у `VerdictSchema.parse(...)` і повернути.
86
-
87
- Виключення / помилки:
88
-
89
- - `Error('No JSON object found in LLM response')` — якщо в тексті немає жодної з фігурних дужок (`{` або `}`).
90
- - `SyntaxError` (від `JSON.parse`) — якщо вирізаний фрагмент не є валідним JSON. Наприклад, через зайвий текст усередині `{...}`, який LLM могла додати між дужками.
91
- - `ZodError` (від `VerdictSchema.parse`) — якщо JSON валідний, але не відповідає схемі: невідома категорія `verdict`, `confidence` поза `[0, 1]`, `reason` коротший за 20 символів або довший за 500, `suggestedTest` довший за 300 символів, відсутнє обов'язкове поле тощо.
92
-
93
- Поведінкові нюанси, важливі для викликача:
94
-
95
- - Стратегія «перший `{` … останній `}`» свідомо толерантна: дозволяє LLM писати щось ось так: `Here's the verdict: { ... } Hope it helps.` Однак якщо LLM повертає **кілька** JSON-обʼєктів, функція ризикує склеїти їх у невалідний фрагмент — це очікувано і впирається у валідацію JSON.
96
- - Функція не намагається «латати» некоректний JSON (немає trailing-comma-cleanup, немає markdown-fence-strip). Помилки прокидаються догори викликача — там і місце для retry / fallback-логіки.
97
- - У разі `ZodError` повідомлення зазвичай містить читабельний шлях до невалідного поля, що зручно для логування при debug LLM-промпта.
98
-
99
- ## Залежності
100
-
101
- Зовнішні:
102
-
103
- - [`zod`](https://www.npmjs.com/package/zod) — рантайм-валідатор схем. Імпортується як `import { z } from 'zod'`. Версія керується кореневим `package.json` робочого простору `npm/`.
104
-
105
- Внутрішні:
106
-
107
- - Немає. Модуль не імпортує нічого з власного проєкту і не залежить від інших файлів `coverage-classify`.
108
-
109
- Стандартна бібліотека / середовище:
110
-
111
- - `JSON.parse` — глобальний API JavaScript runtime.
112
- - `String.prototype.indexOf` / `lastIndexOf` / `slice` — стандартні методи рядків.
113
-
114
- Цільове середовище: Node-сумісний рантайм (Node.js / Bun) із підтримкою ES Modules — файл написано як `.mjs`.
115
-
116
- ## Потік виконання / Використання
117
-
118
- ### Як модуль вписується в `coverage-classify`
119
-
120
- Інструмент `coverage-classify` працює за такою послідовністю (типова):
121
-
122
- 1. Зчитати список вцілілих мутантів із результатів мутаційного тестування.
123
- 2. Для кожного мутанта зібрати контекст (фрагмент коду, місце змін) та згенерувати промпт для LLM.
124
- 3. Виконати запит до LLM і отримати raw-text відповідь.
125
- 4. **Викликати `parseVerdict(rawText)`** із цього модуля, щоб отримати типізований verdict.
126
- 5. Зберегти verdict у кеш / звіт (`apply.mjs`, `cache.mjs`) і застосувати дії: для `worth-testing` згенерувати TODO/тести, для решти — позначити мутант відповідною категорією.
127
-
128
- Таким чином, `verdict-schema.mjs` — це межа між «світом LLM» (нечіткий текст) і «світом інструменту» (структуровані дані).
129
-
130
- ### Приклад використання
131
-
132
- ```js
133
- import { parseVerdict, VerdictSchema } from './verdict-schema.mjs'
134
-
135
- // 1) Парсимо raw-відповідь LLM
136
- const rawLLM = `
137
- The mutant is in a defensive branch. Here is the verdict:
138
- {
139
- "verdict": "defensive",
140
- "confidence": 0.92,
141
- "reason": "The condition guards an impossible state when the input list is empty.",
142
- "suggestedTest": ""
143
- }
144
- Thanks!
145
- `
146
-
147
- try {
148
- const verdict = parseVerdict(rawLLM)
149
- // verdict.verdict === 'defensive'
150
- // verdict.confidence === 0.92
151
- console.log(verdict)
152
- } catch (err) {
153
- // 'No JSON object found in LLM response' | SyntaxError | ZodError
154
- console.error('LLM verdict invalid:', err.message)
155
- }
156
-
157
- // 2) Якщо в нас уже є об'єкт (наприклад, з кешу) — валідуємо безпосередньо через схему
158
- const cached = { verdict: 'glue', confidence: 1, reason: 'CLI entry point only, integration covers.' }
159
- const ok = VerdictSchema.parse(cached) // кине ZodError, якщо не відповідає
160
- ```
161
-
162
- ### Граничні випадки
163
-
164
- - Порожній рядок → `indexOf('{') === -1` → кидаємо `'No JSON object found in LLM response'`.
165
- - Рядок без `}` (LLM обірвалась) → `lastIndexOf('}') === -1` → та сама помилка.
166
- - LLM повернула markdown-fence (` ```json ... ``` `) навколо JSON → `parseVerdict` витягне саме JSON-острів між першим `{` і останнім `}`, fence ігнорується.
167
- - LLM повернула `confidence: 1.5` → `ZodError` (порушено `max(1)`).
168
- - LLM повернула `verdict: 'unknown'` → `ZodError` (не входить у `z.enum([...])`).
169
- - LLM повернула `reason` коротшим за 20 символів → `ZodError` (`min(20)`). Це навмисний захист від відповідей-однословів типу `"ok"`.
170
-
171
- ### Рекомендації для викликача
172
-
173
- - Обгортайте виклик `parseVerdict` у `try/catch` і за помилки робіть retry з посиленим промптом (наприклад, з нагадуванням про схему) або падайте у fallback-категорію.
174
- - Не зберігайте у кеш `rawText` як вердикт — зберігайте лише провалідований об'єкт (результат `parseVerdict`); це підтримує інваріант «у кеші тільки валідні дані».
175
- - Якщо в майбутньому з'являться нові категорії — оновлюйте `z.enum` тут, інакше LLM-вердикти з новими значеннями будуть відхилятися.
29
+ - Read-only: файл не виконує операцій запису у файлову систему.
30
+ - Не звертається до мережі.
@@ -0,0 +1,35 @@
1
+ ---
2
+ docgen:
3
+ source: npm/scripts/dispatcher/trace.mjs
4
+ crc: 8d541669
5
+ score: 100
6
+ ---
7
+
8
+ # trace.mjs
9
+
10
+ ## Огляд
11
+
12
+ Файл забезпечує наскрізну простежуваність артефактів. Він читає front-matter з директорій `docs/{tasks,specs,plans,adr}`, будує ланцюг за лінками та позначає розриви. Функції генерують аналіз, який потім рендериться у текстовий вивід, а трасування виконується для зчитування артефактів.
13
+
14
+ ## Поведінка
15
+
16
+ parseFrontMatter Парсить плаский YAML-front-matter. Не обробляє вкладеність. Відрізає інлайн-коментарі.
17
+
18
+ analyze Будує аналіз. Для кожного артефакту генерує лінки з позначкою про розрив.
19
+
20
+ render Текстовий рендер аналізу. Форматує вивід для читання.
21
+
22
+ runTraceCli Виконує трасування. Зчитує артефакти з директорій. Будує аналіз. Повертає код виходу.
23
+
24
+ ## Публічний API
25
+
26
+ parseFrontMatter — Парсить плаский YAML-front-matter (key: value). Обробляє лише основні поля spec/plan/task-record. Видаляє інлайн-коментарі.
27
+ analyze — Створює аналіз: для кожного артефакту — зв'язок його лінків зі статусом ok/розрив. `breaking` означає відсутність лінка, що руйнує ланцюг.
28
+ render — Відображає текстовий вивід аналізу.
29
+ runTraceCli — Виконує команду CLI `n-cursor trace [--json]`. Повертає 1, якщо виявлено розриви ланцюга.
30
+
31
+ ## Гарантії поведінки
32
+
33
+ - Read-only: файл не виконує операцій запису у файлову систему.
34
+ - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
35
+ - Не звертається до мережі.