@nitra/cursor 5.3.4 → 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.
- package/.claude-template/settings.template.json +2 -2
- package/.pi-template/extensions/n-cursor-adr/docs/index.md +13 -24
- package/CHANGELOG.md +11 -0
- package/bin/n-cursor.js +43 -22
- package/lib/docs/models.md +29 -18
- package/lib/docs/omlx-trace.md +51 -0
- package/lib/docs/omlx.md +31 -15
- package/lib/omlx.mjs +2 -5
- package/package.json +1 -1
- package/rules/abie/docs/fix.md +17 -11
- package/rules/adr/docs/fix.md +25 -140
- package/rules/bun/docs/fix.md +18 -151
- package/rules/capacitor/docs/fix.md +16 -13
- package/rules/capacitor/js/docs/platforms.md +31 -43
- package/rules/changelog/docs/fix.md +25 -169
- package/rules/ci4/docs/fix.md +11 -14
- package/rules/doc-files/doc-files.mdc +60 -0
- package/rules/doc-files/docs/fix.md +31 -0
- package/rules/doc-files/fix.mjs +19 -0
- package/{skills → rules}/doc-files/js/docgen-extract.mjs +42 -19
- package/{skills → rules}/doc-files/js/docgen-ignore.mjs +2 -1
- package/{skills → rules}/doc-files/js/docgen-scan.mjs +9 -1
- package/{skills → rules}/doc-files/js/docs/docgen-crc.md +1 -1
- package/{skills → rules}/doc-files/js/docs/docgen-extract-anchors.md +1 -1
- package/{skills → rules}/doc-files/js/docs/docgen-extract.md +2 -2
- package/{skills → rules}/doc-files/js/docs/docgen-files-batch.md +1 -1
- package/{skills → rules}/doc-files/js/docs/docgen-gen.md +1 -1
- package/{skills → rules}/doc-files/js/docs/docgen-ignore.md +4 -4
- package/rules/doc-files/js/docs/docgen-prompts.md +39 -0
- package/rules/doc-files/js/docs/docgen-scan.md +54 -0
- package/rules/doc-files/js/docs/lint.md +36 -0
- package/rules/doc-files/js/docs/units-js.md +31 -0
- package/rules/doc-files/js/docs/units-rs.md +35 -0
- package/rules/doc-files/js/docs/units.md +30 -0
- package/rules/doc-files/js/lint.mjs +96 -0
- package/{skills → rules}/doc-files/js/units-rs.mjs +37 -17
- package/rules/doc-files/lint/docs/lint.md +37 -0
- package/rules/doc-files/lint/lint.mjs +105 -0
- package/rules/doc-files/meta.json +1 -0
- package/rules/docker/docs/fix.md +21 -161
- package/rules/efes/docs/fix.md +23 -194
- package/rules/feedback/docs/fix.md +10 -8
- package/rules/ga/docs/fix.md +10 -5
- package/rules/graphql/docs/fix.md +23 -119
- package/rules/hasura/docs/fix.md +19 -5
- package/rules/hasura/js/docs/internal_urls.md +34 -307
- package/rules/image-avif/docs/fix.md +16 -127
- package/rules/image-compress/docs/fix.md +20 -141
- package/rules/image-compress/js/docs/package_setup.md +22 -182
- package/rules/js-bun-db/docs/fix.md +23 -139
- package/rules/js-bun-db/js/docs/safety.md +33 -221
- package/rules/js-bun-redis/docs/fix.md +25 -114
- package/rules/js-bun-redis/js/docs/imports.md +18 -166
- package/rules/js-lint/docs/fix.md +30 -108
- package/rules/js-lint/js/docs/lint-findings.md +37 -17
- package/rules/js-lint/js/docs/lint.md +22 -238
- package/rules/js-lint/js/docs/tooling.md +34 -331
- package/rules/js-lint-ci/docs/fix.md +16 -149
- package/rules/js-lint-ci/js/docs/lint.md +16 -136
- package/rules/js-mssql/docs/fix.md +18 -123
- package/rules/js-mssql/js/docs/deps.md +28 -251
- package/rules/js-run/docs/fix.md +23 -138
- package/rules/js-run/js/docs/runtime.md +24 -378
- package/rules/k8s/docs/fix.md +18 -123
- package/rules/nginx-default-tpl/docs/fix.md +22 -118
- package/rules/nginx-default-tpl/js/docs/template.md +38 -360
- package/rules/npm-module/docs/fix.md +27 -89
- package/rules/npm-module/js/docs/header_doc_pointer.md +15 -15
- package/rules/npm-module/js/docs/package_structure.md +36 -258
- package/rules/npm-module/js/docs/rule_meta.md +25 -127
- package/rules/npm-module/js/docs/skill_meta.md +18 -180
- package/rules/php/docs/fix.md +21 -98
- package/rules/php/js/docs/tooling.md +20 -143
- package/rules/python/docs/fix.md +25 -157
- package/rules/python/js/docs/applies.md +20 -98
- package/rules/python/js/docs/tooling.md +27 -144
- package/rules/rego/docs/fix.md +24 -112
- package/rules/rego/js/docs/applies.md +20 -164
- package/rules/rego/js/docs/lint.md +15 -110
- package/rules/release/docs/fix.md +16 -114
- package/rules/rust/docs/fix.md +24 -119
- package/rules/rust/js/docs/applies.md +20 -129
- package/rules/security/docs/fix.md +21 -78
- package/rules/security/js/docs/sample_secret.md +23 -182
- package/rules/security/js/docs/trufflehog.md +19 -128
- package/rules/style-lint/docs/fix.md +16 -150
- package/rules/style-lint/js/docs/lint.md +21 -172
- package/rules/style-lint/js/docs/tooling.md +19 -184
- package/rules/tauri/docs/fix.md +26 -152
- package/rules/tauri/js/docs/cargo_mutants_config.md +21 -159
- package/rules/tauri/js/docs/tooling.md +20 -217
- package/rules/test/docs/fix.md +19 -127
- package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +15 -127
- package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +17 -153
- package/rules/test/js/docs/cargo_mutants_config.md +24 -164
- package/rules/test/js/docs/location.md +24 -126
- package/rules/test/js/docs/no-process-chdir.md +20 -151
- package/rules/test/js/docs/no-relative-fs-path.md +24 -261
- package/rules/test/js/docs/stryker_config.md +48 -148
- package/rules/test/js/docs/vitest-config-pool-forks.md +21 -164
- package/rules/text/docs/fix.md +25 -113
- package/rules/text/js/docs/forbidden-prettier.md +21 -132
- package/rules/text/js/docs/formatting.md +60 -251
- package/rules/text/js/docs/lint.md +17 -114
- package/rules/vue/docs/fix.md +25 -118
- package/rules/vue/js/docs/packages.md +25 -323
- package/rules/worktree/docs/fix.md +31 -150
- package/scripts/coverage-classify/docs/index.md +23 -209
- package/scripts/coverage-classify/docs/verdict-schema.md +14 -159
- package/scripts/dispatcher/docs/trace.md +35 -0
- package/scripts/docs/auto-rules.md +37 -361
- package/scripts/docs/lint-cli.md +12 -13
- package/scripts/docs/post-tool-use-fix.md +16 -15
- package/scripts/docs/skills-cli.md +26 -23
- package/scripts/docs/sync-claude-config.md +94 -34
- package/scripts/docs/worktree-cli.md +11 -34
- package/scripts/lib/docs/assert-project-root.md +14 -16
- package/scripts/lib/docs/changed-files.md +24 -139
- package/scripts/lib/docs/discover-check-rules-from-cursor.md +14 -146
- package/scripts/lib/docs/rule-predicates.md +20 -17
- package/scripts/lib/docs/run-rule-cli.md +14 -18
- package/scripts/lib/docs/run-rule.md +13 -20
- package/scripts/lib/docs/run-standard-rule.md +12 -15
- package/scripts/lib/docs/sync-gitignore-worktree.md +15 -18
- package/scripts/lib/rule-predicates.mjs +1 -1
- package/scripts/sync-claude-config.mjs +4 -1
- package/scripts/utils/docs/with-lock.md +19 -12
- package/scripts/utils/with-lock.mjs +4 -2
- package/skills/doc-aggregate/SKILL.md +2 -2
- package/skills/doc-aggregate/js/docgen-ignore.mjs +6 -6
- package/skills/doc-aggregate/js/docs/docgen-ignore.md +1 -1
- package/skills/doc-aggregate/js/docs/docgen-scan.md +78 -0
- package/skills/doc-files/.changes/260612-0031.md +5 -0
- package/skills/doc-files/.changes/260612-0036.md +5 -0
- package/skills/doc-files/.changes/260612-0114.md +5 -0
- package/skills/doc-files/SKILL.md +6 -6
- package/skills/fix/js/docs/llm-worker.md +17 -15
- package/skills/fix/js/docs/orchestrator.md +30 -23
- package/skills/fix/js/docs/t0.md +26 -16
- package/skills/start-check/js/docs/check.md +26 -22
- package/skills/taze/js/docs/diff.md +44 -20
- package/skills/doc-files/js/docs/docgen-prompts.md +0 -32
- package/skills/doc-files/js/docs/docgen-scan.md +0 -25
- package/skills/doc-files/js/docs/units-rs.md +0 -35
- /package/{skills → rules}/doc-files/js/docgen-crc.mjs +0 -0
- /package/{skills → rules}/doc-files/js/docgen-extract-anchors.mjs +0 -0
- /package/{skills → rules}/doc-files/js/docgen-files-batch.mjs +0 -0
- /package/{skills → rules}/doc-files/js/docgen-gen.mjs +0 -0
- /package/{skills → rules}/doc-files/js/docgen-prompts.mjs +0 -0
- /package/{skills → rules}/doc-files/js/units-js.mjs +0 -0
- /package/{skills → rules}/doc-files/js/units.mjs +0 -0
|
@@ -1,218 +1,32 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
16
|
+
1. Пошук результату в кеші.
|
|
17
|
+
2. Якщо результат знайдено, використовується збережений вердикт.
|
|
18
|
+
3. Якщо результат не знайдено, намагається отримати вердикт через перший рівень.
|
|
19
|
+
4. Якщо перший рівень не вдається, намагається отримати вердикт через другий рівень.
|
|
20
|
+
5. Якщо другий рівень не вдається, використовується консервативний запасний варіант.
|
|
21
|
+
6. Результати класифікації записуються в кеш.
|
|
209
22
|
|
|
210
|
-
|
|
23
|
+
## Публічний API
|
|
211
24
|
|
|
212
|
-
|
|
25
|
+
classify — Класифікує survived мутанти, перенаправляючи їх до CLOUD_MIN, якщо результат resolveModel дорівнює CLOUD_MIN, інакше до fallback.
|
|
213
26
|
|
|
214
|
-
|
|
215
|
-
- `opts.cachePath = '/tmp/test-cache.json'` — ізольований кеш.
|
|
216
|
-
- `opts.retryDelayMs = 0` — миттєві retries без `setTimeout`-блокувань.
|
|
27
|
+
## Гарантії поведінки
|
|
217
28
|
|
|
218
|
-
|
|
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:
|
|
4
|
+
crc: ecf5dfe1
|
|
5
|
+
score: 100
|
|
5
6
|
---
|
|
6
7
|
|
|
7
8
|
# verdict-schema.mjs
|
|
8
9
|
|
|
9
10
|
## Огляд
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
Файл надає схему `VerdictSchema` для валідації вердиктів LLM-класифікатора. Функція `parseVerdict` витягує JSON-об'єкт з сирої текстової відповіді моделі та перевіряє його відповідність визначеній схемі.
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
## Поведінка
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
VerdictSchema
|
|
17
|
+
Визначає схему для валідації вердикту LLM-класифікатора
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
parseVerdict
|
|
20
|
+
Витягує JSON-об'єкт з текстової відповіді LLM і валідує його за схемою
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
## Публічний API
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- `defensive` — гілка для impossible state (захисний код), не killable.
|
|
25
|
-
- `glue` — CLI entry / обгортка `runStandardRule` тощо; покривається інтеграційними тестами.
|
|
26
|
-
- `wrapper` — тонкий `spawn`/`fetch`-обгортка; покривається інтеграційними тестами.
|
|
24
|
+
VerdictSchema — Схема для структури вердикту.
|
|
25
|
+
parseVerdict — Витягує JSON з тексту LLM і перевіряє його за схемою VerdictSchema.
|
|
27
26
|
|
|
28
|
-
##
|
|
27
|
+
## Гарантії поведінки
|
|
29
28
|
|
|
30
|
-
|
|
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
|
+
- Не звертається до мережі.
|