@7n/rules 1.43.1 → 1.44.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/CHANGELOG.md +15 -0
- package/docs/vitest.config.md +14 -19
- package/package.json +1 -1
- package/rules/abie/lib/docs/index.md +0 -2
- package/rules/abie/lib/http-route.mjs +1 -0
- package/rules/abie/lib/yaml.mjs +2 -0
- package/rules/ci4/marksman_config/docs/index.md +10 -0
- package/rules/ci4/marksman_config/main.mjs +2 -0
- package/rules/doc-files/docgen-prompts/docs/index.md +9 -0
- package/rules/doc-files/docgen-prompts/main.mjs +5 -0
- package/rules/hasura/internal_urls/docs/index.md +0 -2
- package/rules/hasura/internal_urls/docs/main.md +27 -15
- package/rules/hasura/internal_urls/main.mjs +1 -0
- package/rules/image-avif/avif_generation/docs/index.md +10 -0
- package/rules/image-avif/avif_generation/main.mjs +2 -0
- package/rules/rego/vscode_settings/docs/fix-vscode_settings.md +12 -10
- package/rules/rego/vscode_settings/fix-vscode_settings.mjs +5 -0
- package/rules/tauri/cargo_mutants_config/docs/index.md +0 -2
- package/rules/tauri/cargo_mutants_config/docs/main.md +38 -12
- package/rules/tauri/cargo_mutants_config/main.mjs +5 -1
- package/rules/tauri/core_test_isolation/docs/main.md +19 -16
- package/rules/tauri/core_test_isolation/main.mjs +3 -1
- package/rules/tauri/linux_deps/docs/main.md +25 -18
- package/rules/tauri/linux_deps/main.mjs +2 -1
- package/rules/tauri/release/docs/main.md +20 -12
- package/rules/tauri/release/main.mjs +2 -0
- package/rules/tauri/updater/docs/main.md +31 -14
- package/rules/tauri/updater/main.mjs +4 -0
- package/rules/test/coverage/concern.json +9 -0
- package/rules/test/coverage/fix-worker.mjs +111 -0
- package/rules/test/coverage/lib/classify/apply.mjs +67 -0
- package/rules/test/coverage/lib/classify/cache.mjs +77 -0
- package/rules/test/coverage/lib/classify/docs/apply.md +28 -0
- package/rules/test/coverage/lib/classify/docs/cache.md +34 -0
- package/rules/test/coverage/lib/classify/docs/index.md +37 -0
- package/rules/test/coverage/lib/classify/docs/prompt.md +30 -0
- package/rules/test/coverage/lib/classify/docs/verdict-schema.md +30 -0
- package/rules/test/coverage/lib/classify/index.mjs +140 -0
- package/rules/test/coverage/lib/classify/prompt.mjs +136 -0
- package/rules/test/coverage/lib/classify/verdict-schema.mjs +163 -0
- package/rules/test/coverage/lib/llm.mjs +100 -0
- package/rules/test/coverage/main.mjs +161 -0
- package/rules/test/main.json +1 -0
- package/rules/test/main.mdc +140 -0
- package/rules/test/package_json/concern.json +11 -0
- package/rules/test/package_json/package_json.mdc +18 -0
- package/rules/test/package_json/package_json.rego +25 -0
- package/rules/test/package_json/template/package.json.contains.json +6 -0
- package/rules/text/oxfmtrc/fix-oxfmtrc.mjs +5 -0
- package/rules/text/vscode_settings/fix-vscode_settings.mjs +5 -0
- package/rules/worktree/vscode_settings/docs/fix-vscode_settings.md +10 -7
- package/rules/worktree/vscode_settings/fix-vscode_settings.mjs +5 -0
- package/rules/worktree/zed_settings/fix-zed_settings.mjs +5 -0
- package/schemas/n-rules.json +18 -1
- package/scripts/lib/adr/docs/index.md +0 -2
- package/scripts/lib/adr/docs/normalize-pipeline.md +44 -28
- package/scripts/lib/adr/normalize-pipeline.mjs +11 -0
- package/scripts/lib/docs/inline-template-links.md +17 -8
- package/scripts/lib/docs/plugin-api.md +1 -1
- package/scripts/lib/inline-template-links.mjs +5 -0
- package/scripts/lib/lint-surface/docs/run-detectors.md +25 -22
- package/scripts/lib/lint-surface/docs/tier-sampling-experiment.md +30 -14
- package/scripts/lib/lint-surface/run-detectors.mjs +1 -1
- package/scripts/lib/lint-surface/tier-sampling-experiment.mjs +1 -0
- package/scripts/lib/plugin-api.mjs +46 -0
- package/scripts/utils/docs/walkDir.md +26 -15
- package/scripts/utils/docs/worktree-fingerprint.md +16 -15
- package/scripts/utils/walkDir.mjs +9 -5
- package/scripts/utils/worktree-fingerprint.mjs +5 -0
- package/skills/storybook/SKILL.md +4 -4
- package/skills/taze/js/migration-cache.mjs +1 -1
|
@@ -3,42 +3,58 @@ type: JS Module
|
|
|
3
3
|
title: normalize-pipeline.mjs
|
|
4
4
|
resource: npm/scripts/lib/adr/normalize-pipeline.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
7
|
-
model:
|
|
6
|
+
crc: 7840afd7
|
|
7
|
+
model: openai-codex/gpt-5.5
|
|
8
|
+
tier: cloud-avg
|
|
9
|
+
score: 100
|
|
10
|
+
issues: judge-refine:kept-original,judge:inaccurate:0.99
|
|
11
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
8
12
|
---
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
## Огляд
|
|
15
|
+
|
|
16
|
+
Файл готує ADR-чернетки до застосування як `operations[]` у тому самому контракті, що й single-shot-пайплайн, сумісному з `apply-ops`: створення нового MADR, доповнення наявного ADR або пропуск. Він існує як локально-орієнтована альтернатива для малої LLM `omlx/gemma-4b`, де JS керує retrieval, кластерами, датами, MADR-каркасом і після кластеризації призначає `op`, а модель дає лише вузькі перевірювані судження та фрагменти змісту.
|
|
11
17
|
|
|
12
18
|
## Поведінка
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
normalizePipeline виконує повний конвеєр: ідентифікує кластери чернеток, визначає операції (delete, rewrite, merge-anchor тощо) та ініціює виклики LLM для генерації контенту та додатків.
|
|
20
|
+
`normalizePipeline` приймає батч ADR-чернеток і список уже чистих ADR, після чого веде їх через послідовність дрібних перевірюваних рішень. Глобальні рішення про зв’язки, кластери, цільові документи й фінальні operations залишаються в JS; LLM використовується лише для вузьких локальних суджень і генерації контрольованих фрагментів.
|
|
21
|
+
|
|
22
|
+
На початку потоку `draftTitle` дістає робочу назву кожної чернетки, а `isNoDecision` відсікає записи, де рішення явно не прийняте. Для решти `buildEdges` створює кандидатні зв’язки між чернетками та між чернетками і clean ADR: назви й слаги проходять через `tokenize`, а близькість кандидатів оцінює `jaccard`. Це retrieval-етап: він лише звужує простір порівнянь, а не приймає остаточне рішення про злиття.
|
|
23
|
+
|
|
24
|
+
Далі `normalizePipeline` перевіряє кандидатні зв’язки через LLM-судження «те саме рішення чи ні», консервативно об’єднує підтверджені зв’язки в кластери й призначає для кожної чернетки дію: створити новий ADR, доповнити наявний або пропустити як тривіальну/непридатну. Ізольовані чернетки додатково класифікуються як standalone або trivial, щоб не створювати ADR без достатньої змістовної ваги.
|
|
25
|
+
|
|
26
|
+
Коли потрібен новий ADR, `genMadr` перетворює одну чернетку на MADR-документ. Дату для канонічного каркаса визначає `madrDate`; модель повертає лише зміст секцій, який приводить до стабільної форми `normalizeSections`. Після цього `assembleMadr` збирає повний MADR із контрольованим заголовком, датою, статусом, назвами секцій, fallback-текстами й bullet-структурою. `validateMadr` є фінальним quality gate: невалідний документ не потрапляє в operations як готовий вміст.
|
|
27
|
+
|
|
28
|
+
Коли чернетка має доповнити наявний ADR, `normalizePipeline` генерує лише новий зміст оновлення, а службовий заголовок оновлення та дата лишаються під контролем JS через ту саму політику дат. Це зберігає однаковий формат для створення нових ADR і для merge-доповнень.
|
|
29
|
+
|
|
30
|
+
Результатом `normalizePipeline` є operations у тому самому контракті, що й single-shot-пайплайн, разом зі статистикою та діагностичним trace. Подальше застосування змін виконується спільною apply-логікою поза цим файлом; цей конвеєр лише готує перевірені наміри змін і не покладається на кешування.
|
|
26
31
|
|
|
27
32
|
## Публічний API
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
- tokenize — Токенізує назву/слаг у множину значущих токенів (kebab + пробіли, без стоп-слів).
|
|
35
|
+
- jaccard — Jaccard-схожість двох множин токенів.
|
|
36
|
+
- draftTitle — Витягує заголовок драфта. Капчер пише `## ADR <title>` — він у пріоритеті
|
|
37
|
+
(чернетка може мати контент-заголовки раніше або взагалі не мати ADR-рядка).
|
|
38
|
+
Fallback-и: перший h1, що не є MADR-секцією, інакше '' (caller бере імʼя файлу).
|
|
39
|
+
- isNoDecision — Детермінований no-decision гейт (харднінг #1). Чернетка, де у `Decision Outcome`
|
|
40
|
+
рішення явно НЕ прийняте (transcript обірвався) — не варта окремого ADR: gold
|
|
41
|
+
(sonnet) такі видаляє. Ловимо без LLM, щоб не покладатися на kind-judge малої моделі.
|
|
42
|
+
- buildEdges — Будує кандидати-ребра за лексичною схожістю.
|
|
43
|
+
- validateMadr — Детермінований гейт якості згенерованого MADR.
|
|
44
|
+
- madrDate — Детермінована ISO-дата для поля **Date:**. Пріоритет — `captured` frontmatter
|
|
45
|
+
(перші 10 символів ISO-стемпа); fallback — timestamp-префікс імені файлу
|
|
46
|
+
(`YYMMDD-…` → `20YY-MM-DD`). Каркас MADR не повинен залежати від LLM навіть тут.
|
|
47
|
+
- normalizeSections — Нормалізує сирий JSON-вивід gen-моделі у строгу форму секцій. Толерантна до
|
|
48
|
+
дрібних відхилень малої моделі: рядок замість масиву → масив із одного елемента,
|
|
49
|
+
число/null → рядок/порожньо, обрізає пробіли й порожні елементи.
|
|
50
|
+
- assembleMadr — Детермінована збірка канонічного MADR 4.0.0 з заголовка, дати й секцій-контенту.
|
|
51
|
+
Увесь каркас (Status, назви секцій, шаблон "Chosen option…", fallback-фрази,
|
|
52
|
+
bullets) — тут, не в моделі. Заголовок і дата — JS-власність (draftTitle/captured),
|
|
53
|
+
модель їх не торкається.
|
|
54
|
+
- genMadr — Stage 2: перетворює одну чернетку на валідний MADR-документ. Модель лише
|
|
55
|
+
витягує зміст секцій як JSON; каркас збирає JS, результат проганяється через
|
|
56
|
+
валідатор із ретраями каскаду. При невдачі повертає `valid: false` без вмісту.
|
|
57
|
+
- normalizePipeline — Головний конвеєр. Повертає operations[] (контракт single-shot) + stats.
|
|
42
58
|
|
|
43
59
|
## Гарантії поведінки
|
|
44
60
|
|
|
@@ -459,6 +459,17 @@ export function assembleMadr({ title, date, sections: s }) {
|
|
|
459
459
|
].join('\n')
|
|
460
460
|
}
|
|
461
461
|
|
|
462
|
+
/**
|
|
463
|
+
* Stage 2: перетворює одну чернетку на валідний MADR-документ. Модель лише
|
|
464
|
+
* витягує зміст секцій як JSON; каркас збирає JS, результат проганяється через
|
|
465
|
+
* валідатор із ретраями каскаду. При невдачі повертає `valid: false` без вмісту.
|
|
466
|
+
* @param {string} title заголовок рішення
|
|
467
|
+
* @param {string} body тіло чернетки (обрізається до безпечного розміру)
|
|
468
|
+
* @param {string} captured момент фіксації чернетки (для дати MADR)
|
|
469
|
+
* @param {{allowCloud: boolean, stats: object}} cfg конфіг каскаду й лічильники
|
|
470
|
+
* @param {string} [file] шлях чернетки — fallback-джерело дати
|
|
471
|
+
* @returns {Promise<{content: string | null, slug: string, valid: boolean, error?: string}>} зібраний документ або позначка невдачі
|
|
472
|
+
*/
|
|
462
473
|
export async function genMadr(title, body, captured, cfg, file = '') {
|
|
463
474
|
const date = madrDate(captured, file)
|
|
464
475
|
const slug = slugify(title)
|
|
@@ -3,23 +3,32 @@ type: JS Module
|
|
|
3
3
|
title: inline-template-links.mjs
|
|
4
4
|
resource: npm/scripts/lib/inline-template-links.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
7
|
-
model:
|
|
6
|
+
crc: dde8124c
|
|
7
|
+
model: openai-codex/gpt-5.4-mini
|
|
8
|
+
tier: cloud-min
|
|
8
9
|
score: 100
|
|
10
|
+
issues: judge-refine:kept-original,judge:inaccurate:0.96
|
|
11
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
9
12
|
---
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
## Огляд
|
|
15
|
+
|
|
16
|
+
Перетворює markdown-лінки на файли з `template/` у fenced-блоки з фактичним вмістом цих файлів і додає знайдені `.mdc`-правила, щоб зібраний `.mdc` лишався самодостатнім для подальшого використання без відносних шляхів. Поведінку реалізують `inlineTemplateLinks` і `appendDiscoveredMdcFiles`.
|
|
12
17
|
|
|
13
18
|
## Поведінка
|
|
14
19
|
|
|
15
|
-
inlineTemplateLinks
|
|
16
|
-
|
|
20
|
+
inlineTemplateLinks спочатку підбирає лише ті markdown-лінки, що ведуть у template-піддерево, і замінює їх самодостатнім вбудованим фрагментом із фактичним вмістом файлу; так правило перестає залежати від відносних посилань. Для вкладених прикладів і слот-файлів відновлюється читабельна назва цілі, зокрема для `package.json.snippet.json` і `package.json`, а формат fenced-блока обирається за розширенням вмісту. Якщо ціль не знайдено, обробка зупиняється з помилкою, щоб згенерований `.mdc` не містив битих посилань.
|
|
21
|
+
|
|
22
|
+
appendDiscoveredMdcFiles далі доповнює вже оброблений текст усіма знайденими `.mdc`-файлами з піддиректорій, які позначені через `concern.json`; це дає змогу зібрати повний пакет правил без ручного перелічення допоміжних файлів. Порядок стабільний: спочатку директори сортуються, потім файли всередині кожного каталогу, а результати додаються в кінець як один суцільний блок. Якщо таких директорій немає, початковий текст лишається без змін.
|
|
17
23
|
|
|
18
24
|
## Публічний API
|
|
19
25
|
|
|
20
|
-
inlineTemplateLinks —
|
|
21
|
-
|
|
26
|
+
- inlineTemplateLinks — Finds markdown links whose path contains /template/ and replaces them with
|
|
27
|
+
inline fenced blocks. Reads file from join(ruleDir, rel-path).
|
|
28
|
+
Throws Error if a matched link target doesn't exist (fail loud — user must know).
|
|
29
|
+
- appendDiscoveredMdcFiles — Appends all *.mdc files from concern subdirectories (those with concern.json).
|
|
30
|
+
Concerns ordered alphabetically; files within each concern ordered alphabetically.
|
|
22
31
|
|
|
23
32
|
## Гарантії поведінки
|
|
24
33
|
|
|
25
|
-
-
|
|
34
|
+
- Власних операцій запису (ФС/БД) у файлі немає; виклики імпортованих модулів можуть писати.
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Інлайн template-посилань у .mdc-правилах: markdown-лінки на файли з тек
|
|
3
|
+
* template/ замінюються fenced-блоками з фактичним вмістом файлу, щоб
|
|
4
|
+
* згенероване правило було самодостатнім без відносних шляхів.
|
|
5
|
+
*/
|
|
1
6
|
import { existsSync } from 'node:fs'
|
|
2
7
|
import { readFile } from 'node:fs/promises'
|
|
3
8
|
import { basename, extname, join } from 'node:path'
|
|
@@ -3,42 +3,45 @@ type: JS Module
|
|
|
3
3
|
title: run-detectors.mjs
|
|
4
4
|
resource: npm/scripts/lib/lint-surface/run-detectors.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
7
|
-
model:
|
|
6
|
+
crc: e9224e37
|
|
7
|
+
model: openai-codex/gpt-5.4-mini
|
|
8
|
+
tier: cloud-min
|
|
8
9
|
score: 100
|
|
9
|
-
issues: judge:inaccurate:0.
|
|
10
|
+
issues: judge-refine:kept-original,judge:inaccurate:0.99
|
|
10
11
|
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
12
|
---
|
|
12
13
|
|
|
13
14
|
## Огляд
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
Файл формує єдину поверхню для `n-rules lint --no-fix`: від discovery правил і вибору меж запуску до виконання `lint` для кожного concern та збору нормалізованих violations. Його результатом є список порушень, який використовує fix-pipeline для подальшої обробки, тоді як сам detect не змінює дерево файлів.
|
|
16
17
|
|
|
17
18
|
## Поведінка
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
DEFAULT_RULES_DIR визначає шлях до стандартної директорії з правилами.
|
|
21
|
-
buildDetectPlan створює впорядкований план прогону лінтера, збираючи всі відповідні концерни та визначаючи область їх сканування.
|
|
22
|
-
detectAll виконує прохід лінтера у режим детекції, збираючи всі виявлені порушення та повертаючи код виходу.
|
|
20
|
+
DEFAULT_RULES_DIR задає базовий корінь правил, від якого стартує discovery, коли споживач не передав власні каталоги.
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
buildDetectPlan спочатку визначає набір rules-каталогів, потім відбирає лише доступні concern-и з урахуванням capability, далі будує план виконання за режимом прогону: scoped, delta, full або repo-wide. Сам план фіксує, які concern-и запускаються whole-repo, а які лише по перетину з файлами, щоб detect і fix-pipeline працювали з однаковою картиною.
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
* DEFAULT_RULES_DIR — Містить набір стандартних правил для перевірок.
|
|
29
|
-
* buildDetectPlan — Створює план виконання перевірок, охоплюючи визначені області.
|
|
30
|
-
* detectAll — Виконує повний прохід пошуку проблем і повертає всі виявлені порушення та код виходу.
|
|
31
|
-
* loadEnabledLintRules — Discovery-фасад для споживачів поза detect/fix-конвеєром (`ci plan`): concerns за rule-id + set активних правил.
|
|
32
|
-
* computeActiveDomains — Активність доменів для файлового набору (лише per-file concerns) — єдине джерело правди для `ci plan`: «plan сказав true» ⇔ «lint щось запустить».
|
|
24
|
+
loadEnabledLintRules використовує той самий discovery-ланцюжок, але повертає не план, а повну мапу concern-и за rule-id разом із множиною активних правил. Це потрібно зовнішнім споживачам, які мають знати, що реально доступно для прогону, не запускаючи сам detector-цикл.
|
|
33
25
|
|
|
34
|
-
|
|
26
|
+
computeActiveDomains дає скорочений зріз цієї ж моделі: для заданого набору файлів показує, які rule-id справді активуються хоча б одним per-file concern-ом. Full-scope перевірки тут навмисно не враховуються, бо їхня зона відповідає repo-wide прогону.
|
|
35
27
|
|
|
36
|
-
|
|
28
|
+
detectAll бере готовий план, виконує його, збирає normalized violations і повертає ще й derived exitCode. Увесь шлях read-only: нічого не записує в дерево, не змінює конфіг і не покладається на мутації поза межами збирання результатів. Фільтрація та видимість правил спираються на .n-rules.json, тож саме він визначає, які rules каталоги й concern-и вважаються активними.
|
|
37
29
|
|
|
38
|
-
|
|
30
|
+
## Публічний API
|
|
39
31
|
|
|
40
|
-
|
|
32
|
+
- DEFAULT_RULES_DIR — Цей файл: npm/scripts/lib/lint-surface/run-detectors.mjs → PACKAGE_ROOT = npm (4 dirname угору).
|
|
33
|
+
- buildDetectPlan — Будує план прогону для заданих опцій (discovery + scope-table).
|
|
34
|
+
Спільне джерело для detect-only і fix-pipeline.
|
|
35
|
+
- loadEnabledLintRules — Discovery-фасад для споживачів поза detect/fix-конвеєром (`ci plan`):
|
|
36
|
+
concerns за rule-id (ядро + плагіни, capability-фільтр) і set активних правил.
|
|
37
|
+
- computeActiveDomains — Активність доменів (rule-id) для заданого файлового набору — єдине джерело
|
|
38
|
+
правди для `ci plan`: домен «активний», якщо хоч один його **per-file**
|
|
39
|
+
concern тригериться на цих файлах (та сама таблиця planConcernForDelta, що
|
|
40
|
+
й `lint <domain> --path` → «plan сказав true» ⇔ «lint щось запустить»).
|
|
41
|
+
Правила без жодного per-file concern не потрапляють у результат (їхні
|
|
42
|
+
full-scope перевірки — справа `--repo-wide`).
|
|
43
|
+
- detectAll — Запускає detect-only прохід. Повертає всі violations і похідний exitCode.
|
|
41
44
|
|
|
42
|
-
|
|
45
|
+
## Гарантії поведінки
|
|
43
46
|
|
|
44
|
-
|
|
47
|
+
- Власних операцій запису (ФС/БД) у файлі немає; виклики імпортованих модулів можуть писати.
|
|
@@ -3,32 +3,48 @@ type: JS Module
|
|
|
3
3
|
title: tier-sampling-experiment.mjs
|
|
4
4
|
resource: npm/scripts/lib/lint-surface/tier-sampling-experiment.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
7
|
-
model:
|
|
6
|
+
crc: 959712b3
|
|
7
|
+
model: openai-codex/gpt-5.5
|
|
8
|
+
tier: cloud-avg
|
|
8
9
|
score: 100
|
|
9
|
-
issues: judge:
|
|
10
|
+
issues: judge:error
|
|
10
11
|
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
12
|
---
|
|
12
13
|
|
|
13
14
|
## Огляд
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
Експериментальний harness моделює isolated sampling для окремого tier-а lint fix ladder: будує experiment-only rung-и, проганяє sampling-кандидатів із відкотом до S1 і лишає лише candidate, що пройшов canonical detect. Файл існує, щоб перевіряти sampling/consensus поза production `runFixPipeline`, залишаючи judge/consensus тільки джерелом feedback, а не рішенням про patch.
|
|
17
|
+
|
|
18
|
+
Публічні точки входу: `EXPERIMENT_TIER_ORDER`, `buildExperimentLadder`, `samplingProfilesForTier`, `chooseCleanCandidate`, `runTierSamplingExperiment`.
|
|
19
|
+
|
|
20
|
+
Модуль працює fail-safe: перехоплює помилки й не кидає винятків назовні.
|
|
16
21
|
|
|
17
22
|
## Поведінка
|
|
18
23
|
|
|
19
|
-
EXPERIMENT_TIER_ORDER
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
`EXPERIMENT_TIER_ORDER` задає порядок експериментальних tier-ів, за яким формується ladder для isolated sampling поверх lint fix pipeline.
|
|
25
|
+
|
|
26
|
+
`buildExperimentLadder` створює окремий experiment-only ladder із підтримкою `cloud-max`, не змінюючи production-послідовність `runFixPipeline`. Дані про моделі й timeouts перетворюються на набір rung-ів, які далі використовуються як сценарії окремих випробувань.
|
|
27
|
+
|
|
28
|
+
`samplingProfilesForTier` визначає набір sampling-кандидатів для конкретного tier-а. Якщо для tier-а передані перевизначення, вони стають джерелом профілів; інакше використовується стандартний набір для цього рівня.
|
|
29
|
+
|
|
30
|
+
`runTierSamplingExperiment` бере violations, базовий контекст, rung і sampling-кандидатів, після чого послідовно тестує кожного кандидата в ізольованому стані S1. Для кожної спроби робоче дерево відкочується до початкового snapshot, запускається worker, фіксуються змінені файли, виконується canonical detect і записується результат спроби разом із telemetry та latency.
|
|
31
|
+
|
|
32
|
+
Після всіх спроб `chooseCleanCandidate` обирає лише чистий candidate: пріоритет має менша кількість змінених файлів, менший patch і коротша latency. Якщо чистого кандидата немає, експеримент завершується без застосування patch до робочого дерева.
|
|
33
|
+
|
|
34
|
+
Якщо чистий candidate знайдено, `runTierSamplingExperiment` застосовує саме його зміни як фінальний результат tier sampling. Judge/consensus не приймає рішення про застосування patch: його відповідь повертається тільки як feedback поруч із attempts, selected candidate, фінальними violations і clean-статусом.
|
|
35
|
+
|
|
36
|
+
Модуль працює fail-safe: помилки окремих кандидатів або допоміжних етапів перетворюються на результати спроб і не викидаються назовні. Кешування між запусками або кандидатами не використовується.
|
|
24
37
|
|
|
25
38
|
## Публічний API
|
|
26
39
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
- EXPERIMENT_TIER_ORDER — Порядок tier-ів експериментального ladder — від локальної моделі до найсильнішої хмарної.
|
|
41
|
+
- buildExperimentLadder — Будує experiment-only ladder із `cloud-max`. Production ladder це не змінює.
|
|
42
|
+
- samplingProfilesForTier — Повертає можливі sampling profiles для заданого tier-а.
|
|
43
|
+
- chooseCleanCandidate — Дефолтний вибір найкращого (clean) кандидата серед усіх спроб.
|
|
44
|
+
Вибір відбувається за критеріями: менша кількість змінених файлів, менший розмір patch, менша латентність.
|
|
45
|
+
- runTierSamplingExperiment — Виконує послідовність випробувань (sampling) для одного tier.
|
|
46
|
+
Для кожного кандидата виконується rollback до S1, запускається worker,
|
|
47
|
+
оцінюється чистота, і якщо кандидат обраний, застосовується його patch.
|
|
32
48
|
|
|
33
49
|
## Гарантії поведінки
|
|
34
50
|
|
|
@@ -25,7 +25,7 @@ import { renderViolations, renderDiagnostics } from './render.mjs'
|
|
|
25
25
|
import { createProgressReporter } from './progress.mjs'
|
|
26
26
|
import { runPlanConcurrently } from './scheduler.mjs'
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
/** Цей файл: npm/scripts/lib/lint-surface/run-detectors.mjs → PACKAGE_ROOT = npm (4 dirname угору). */
|
|
29
29
|
export const DEFAULT_RULES_DIR = join(dirname(dirname(dirname(dirname(fileURLToPath(import.meta.url))))), 'rules')
|
|
30
30
|
|
|
31
31
|
/**
|
|
@@ -10,6 +10,7 @@ import { dirname } from 'node:path'
|
|
|
10
10
|
|
|
11
11
|
import { createSnapshot } from './snapshot.mjs'
|
|
12
12
|
|
|
13
|
+
/** Порядок tier-ів експериментального ladder — від локальної моделі до найсильнішої хмарної. */
|
|
13
14
|
export const EXPERIMENT_TIER_ORDER = Object.freeze(['local-min', 'cloud-min', 'cloud-avg', 'cloud-max'])
|
|
14
15
|
|
|
15
16
|
const DEFAULT_LOCAL_TIMEOUT_MS = 300_000
|
|
@@ -78,6 +78,52 @@ export const PLUGIN_API_VERSION = 1
|
|
|
78
78
|
const REQUIRED_PROVIDER_FUNCTIONS = ['detect', 'available', 'backup', 'bump', 'diff', 'promptFor', 'cleanup']
|
|
79
79
|
const REQUIRED_PROVIDER_STRINGS = ['id', 'title', 'manifestNoun', 'skillSection']
|
|
80
80
|
|
|
81
|
+
/**
|
|
82
|
+
* @typedef {object} CoverageRow
|
|
83
|
+
* Агрегований вимір однієї області (`JS`, `Vue (Storybook)`, `Rust`, …).
|
|
84
|
+
* @property {string} area назва рядка звіту
|
|
85
|
+
* @property {{lines:{covered:number,total:number}, functions:{covered:number,total:number}}} coverage line/function coverage
|
|
86
|
+
* @property {{caught:number, total:number}} mutation вбиті/всі мутанти (0/0 — мутаційне тестування не вимірювалось)
|
|
87
|
+
* @property {Array<{file:string, mutants:Array<object>, exampleTest?:object|null, recommendationText?:string|null}>} survived вцілілі мутанти по файлах (шляхи relative до cwd)
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @typedef {object} CoverageProvider
|
|
92
|
+
* Порт мовної екосистеми для концерну `coverage` правила `test` (spec
|
|
93
|
+
* 2026-07-22 absorb-7n-test). Ядро викликає: `detect` → повний вимір
|
|
94
|
+
* `collect` (full/`lint test`) АБО делта-вимір `collectPerFile` (делта-lint,
|
|
95
|
+
* без мутаційного тестування). Реєстрація — `contributes.handlers.coverage`
|
|
96
|
+
* у маніфесті плагіна, default-експорт handler-модуля.
|
|
97
|
+
* @property {string} id стабільний ідентифікатор екосистеми (напр. `js`)
|
|
98
|
+
* @property {string} title заголовок для звітів/повідомлень
|
|
99
|
+
* @property {(cwd: string) => Promise<boolean>} detect чи застосовний вимір у проєкті (false → тихий skip виміру)
|
|
100
|
+
* @property {(cwd: string, opts?: {changedFiles?: string[], base?: string|null, runner?: object}) => Promise<CoverageRow[]>} collect повний вимір: coverage + мутаційне тестування по всіх workspaces
|
|
101
|
+
* @property {(cwd: string, opts: {files: string[], runner?: object}) => Promise<Array<{file:string, pct:number, linesFound:number, linesCovered:number, reason?:string}>>} collectPerFile легкий делта-вимір per-file line coverage змінених файлів (без мутаційного тестування)
|
|
102
|
+
*/
|
|
103
|
+
|
|
104
|
+
const REQUIRED_COVERAGE_FUNCTIONS = ['detect', 'collect', 'collectPerFile']
|
|
105
|
+
const REQUIRED_COVERAGE_STRINGS = ['id', 'title']
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Валідує форму coverage-провайдера з модуля плагіна.
|
|
109
|
+
* @param {unknown} candidate default-експорт handler-модуля плагіна
|
|
110
|
+
* @param {string} source ім'я плагіна/шлях модуля для повідомлення
|
|
111
|
+
* @returns {CoverageProvider} той самий обʼєкт, якщо валідний
|
|
112
|
+
*/
|
|
113
|
+
export function assertCoverageProvider(candidate, source) {
|
|
114
|
+
if (!candidate || typeof candidate !== 'object') {
|
|
115
|
+
throw new TypeError(`plugin-api: ${source} — default-експорт не є обʼєктом CoverageProvider`)
|
|
116
|
+
}
|
|
117
|
+
const missing = [
|
|
118
|
+
...REQUIRED_COVERAGE_STRINGS.filter(k => typeof candidate[k] !== 'string' || candidate[k] === ''),
|
|
119
|
+
...REQUIRED_COVERAGE_FUNCTIONS.filter(k => typeof candidate[k] !== 'function')
|
|
120
|
+
]
|
|
121
|
+
if (missing.length > 0) {
|
|
122
|
+
throw new TypeError(`plugin-api: ${source} — CoverageProvider без обовʼязкових полів: ${missing.join(', ')}`)
|
|
123
|
+
}
|
|
124
|
+
return /** @type {CoverageProvider} */ (candidate)
|
|
125
|
+
}
|
|
126
|
+
|
|
81
127
|
/**
|
|
82
128
|
* Валідує форму провайдера з модуля плагіна — зрозуміла помилка замість
|
|
83
129
|
* «undefined is not a function» глибоко в оркестраторі.
|
|
@@ -3,31 +3,42 @@ type: JS Module
|
|
|
3
3
|
title: walkDir.mjs
|
|
4
4
|
resource: npm/scripts/utils/walkDir.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
7
|
-
model:
|
|
6
|
+
crc: 1bbc24bc
|
|
7
|
+
model: openai-codex/gpt-5.5
|
|
8
|
+
tier: cloud-avg
|
|
8
9
|
score: 100
|
|
10
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
9
11
|
---
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
## Огляд
|
|
14
|
+
|
|
15
|
+
Файл описує правила пропуску службових і агентських шляхів під час читання репозиторію. `WORKTREE_CHECKOUT_GLOBS` задає шаблони агентських worktree-копій, `ALWAYS_IGNORE` фіксує завжди ігноровані `.git` і `node_modules`.
|
|
16
|
+
|
|
17
|
+
`isWorktreeCheckoutPath` перевіряє вже відомий відносний шлях на належність до агентського worktree. `walkDir` виконує fail-safe обхід файлового дерева: перехоплює помилки читання і не передає винятки назовні.
|
|
12
18
|
|
|
13
19
|
## Поведінка
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
`WORKTREE_CHECKOUT_GLOBS` задає спільне правило безпеки для агентських worktree-копій, щоб обхід не сприймав дублікати репозиторію як робочий код.
|
|
22
|
+
|
|
23
|
+
`ALWAYS_IGNORE` розширює це правило постійними пропусками `.git` і `node_modules`; ці винятки застосовуються під час повного обходу незалежно від налаштувань репозиторію.
|
|
24
|
+
|
|
25
|
+
`walkDir` приймає корінь обходу, додає до спільних правил додаткові локальні винятки, читає файлове дерево з урахуванням `.gitignore` і передає знайдені файли далі як абсолютні шляхи. Якщо обхід неможливий, він завершується без помилки назовні, щоб перевірки залишались fail-safe.
|
|
26
|
+
|
|
27
|
+
`isWorktreeCheckoutPath` використовує те саме смислове правило пропуску worktree-чекаутів для уже наявних відносних шляхів, які не проходять через `walkDir`, наприклад зі списків git.
|
|
22
28
|
|
|
23
29
|
## Публічний API
|
|
24
30
|
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
- WORKTREE_CHECKOUT_GLOBS — Сесійні git-worktree чекаути (Claude/агенти): повні копії репо, не робочий код.
|
|
32
|
+
Споживацькі репо часто не мають цих шляхів у .gitignore, тож без safety net
|
|
33
|
+
lint-обхід бачив би дубль усього дерева.
|
|
34
|
+
- ALWAYS_IGNORE — .git ніколи не потрапляє в .gitignore — пропускаємо завжди.
|
|
35
|
+
node_modules — safety net: проєкт може не мати .gitignore або запускатись поза git-репо.
|
|
36
|
+
- isWorktreeCheckoutPath — Чи лежить відносний posix-шлях усередині worktree-чекаута (`.worktrees/` або
|
|
37
|
+
`.claude/worktrees/`). Для фільтрації git-списків, що не проходять через walkDir.
|
|
38
|
+
- walkDir — Рекурсивно обходить каталог, поважаючи .gitignore (включно з вкладеними).
|
|
28
39
|
|
|
29
40
|
## Гарантії поведінки
|
|
30
41
|
|
|
31
|
-
-
|
|
42
|
+
- Власних операцій запису (ФС/БД) у файлі немає; виклики імпортованих модулів можуть писати.
|
|
32
43
|
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
33
|
-
- Свідомо пропускає шляхи: `.git`, `node_modules
|
|
44
|
+
- Свідомо пропускає шляхи: `.git`, `node_modules`.
|
|
@@ -3,29 +3,30 @@ type: JS Module
|
|
|
3
3
|
title: worktree-fingerprint.mjs
|
|
4
4
|
resource: npm/scripts/utils/worktree-fingerprint.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 38831a93
|
|
7
|
+
model: openai-codex/gpt-5.4-mini
|
|
8
|
+
tier: cloud-min
|
|
9
|
+
score: 100
|
|
10
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
7
11
|
---
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
## Огляд
|
|
14
|
+
|
|
15
|
+
`worktreeFingerprint` формує стабільний fingerprint git-робочого дерева з `HEAD`, diff і `untracked`-файлів. Це потрібно, щоб розпізнавати той самий стан дерева й дедуплікувати повторні `lint --full` прогони без змін.
|
|
10
16
|
|
|
11
17
|
## Поведінка
|
|
12
18
|
|
|
13
|
-
1.
|
|
14
|
-
2.
|
|
15
|
-
3.
|
|
16
|
-
4.
|
|
17
|
-
5.
|
|
18
|
-
6.
|
|
19
|
-
7. Повертає отриманий SHA256 хеш у форматі 64-значної шестнадцяткової строки.
|
|
20
|
-
8. Якщо виникає помилка під час виконання будь-якої з операцій, повертає `null`.
|
|
19
|
+
1. worktreeFingerprint визначає, чи поточне git-робоче дерево вже має унікальний стан для повторного повного lint-прогону.
|
|
20
|
+
2. Якщо дерево не належить git-репо або перевірку неможливо виконати, повертає `null`.
|
|
21
|
+
3. Інакше бере базовий стан з `HEAD`, додає різницю від `HEAD` і враховує всі untracked-файли, щоб зміна вмісту або набору нових файлів впливала на результат.
|
|
22
|
+
4. Для untracked-файлів формує впорядковану сукупність «шлях + вміст», щоб однаковий набір файлів давав той самий fingerprint незалежно від порядку їх виявлення.
|
|
23
|
+
5. На основі цього зводить весь стан дерева в один SHA-256 fingerprint у вигляді hex-рядка.
|
|
24
|
+
6. Використовується як стабільний маркер незміненого дерева для відсікання повторних повних lint-прогонів.
|
|
21
25
|
|
|
22
26
|
## Публічний API
|
|
23
27
|
|
|
24
|
-
worktreeFingerprint —
|
|
28
|
+
- worktreeFingerprint — Fingerprint поточного стану git-робочого дерева.
|
|
25
29
|
|
|
26
30
|
## Гарантії поведінки
|
|
27
31
|
|
|
28
|
-
-
|
|
29
|
-
- Функція повертає `null`, якщо обчислення відбитка дерева робіт не вдалося.
|
|
30
|
-
- Функція не викликає винятків.
|
|
31
|
-
- Функція не використовує кеш.
|
|
32
|
+
- (специфічних машинно-виведених гарантій немає)
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
import { join, relative, resolve, sep } from 'node:path'
|
|
3
3
|
import { globby } from 'globby'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Сесійні git-worktree чекаути (Claude/агенти): повні копії репо, не робочий код.
|
|
7
|
+
* Споживацькі репо часто не мають цих шляхів у .gitignore, тож без safety net
|
|
8
|
+
* lint-обхід бачив би дубль усього дерева.
|
|
9
|
+
*/
|
|
8
10
|
export const WORKTREE_CHECKOUT_GLOBS = ['**/.worktrees/**', '**/.claude/worktrees/**']
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
/**
|
|
13
|
+
* .git ніколи не потрапляє в .gitignore — пропускаємо завжди.
|
|
14
|
+
* node_modules — safety net: проєкт може не мати .gitignore або запускатись поза git-репо.
|
|
15
|
+
*/
|
|
12
16
|
export const ALWAYS_IGNORE = ['.git/**', 'node_modules/**', ...WORKTREE_CHECKOUT_GLOBS]
|
|
13
17
|
|
|
14
18
|
const WORKTREE_CHECKOUT_RE = /(?:^|\/)(?:\.worktrees|\.claude\/worktrees)\//u
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fingerprint git-робочого дерева (HEAD + diff + untracked-файли) —
|
|
3
|
+
* використовується для дедуплікації повторних lint --full прогонів на
|
|
4
|
+
* незміненому дереві.
|
|
5
|
+
*/
|
|
1
6
|
import { spawnSync } from 'node:child_process'
|
|
2
7
|
import { createHash } from 'node:crypto'
|
|
3
8
|
|