workflow-ai 1.0.65 → 1.0.66

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 (36) hide show
  1. package/README.md +377 -371
  2. package/configs/agent-health-rules.yaml +12 -1
  3. package/configs/pipeline.yaml +6 -6
  4. package/package.json +1 -1
  5. package/src/lib/agent-spawner.mjs +47 -6
  6. package/src/lib/error-classifier.mjs +311 -274
  7. package/src/runner.mjs +215 -58
  8. package/src/skills/coach/tests/cases/TC-COACH-001/current/meta.json +93 -93
  9. package/src/skills/coach/tests/cases/TC-COACH-002/current/meta.json +93 -93
  10. package/src/skills/create-plan/SKILL.md +1 -0
  11. package/src/skills/create-plan/knowledge/test-hygiene.md +47 -0
  12. package/src/skills/decompose-plan/tests/cases/TC-DECOMPOSE-PLAN-005/current/meta.json +113 -113
  13. package/src/skills/execute-task/tests/cases/TC-EXECUTE-TASK-001/current/meta.json +87 -87
  14. package/src/skills/execute-task/tests/cases/TC-EXECUTE-TASK-005/current/meta.json +87 -87
  15. package/src/skills/review-result/SKILL.md +1 -0
  16. package/src/skills/review-result/knowledge/test-hygiene.md +44 -0
  17. package/src/skills/review-result/scripts/verify-artifacts.js +115 -2
  18. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/claude-sonnet/trial-1.md +7 -0
  19. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/claude-sonnet/trial-2.md +7 -0
  20. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/claude-sonnet/trial-3.md +7 -0
  21. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/judge.json +163 -0
  22. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/kilo-deepseek/trial-1.md +5 -0
  23. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/kilo-deepseek/trial-2.md +5 -0
  24. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/kilo-deepseek/trial-3.md +11 -0
  25. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/kilo-glm/trial-1.md +16 -0
  26. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/kilo-glm/trial-2.md +18 -0
  27. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/kilo-glm/trial-3.md +17 -0
  28. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/kilo-minimax/trial-1.md +17 -0
  29. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/kilo-minimax/trial-2.md +31 -0
  30. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/kilo-minimax/trial-3.md +5 -0
  31. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003/current/meta.json +115 -0
  32. package/src/skills/review-result/tests/cases/TC-REVIEW-RESULT-003-test-isolation.yaml +50 -0
  33. package/src/skills/review-result/tests/fixtures/QA-904-test-isolation-violation/QA-904.md +51 -0
  34. package/src/skills/review-result/tests/fixtures/QA-904-test-isolation-violation/example-test.mjs +36 -0
  35. package/src/skills/review-result/tests/index.yaml +5 -0
  36. package/src/skills/review-result/tests/rubrics/test-isolation.md +20 -0
@@ -0,0 +1,17 @@
1
+ Скрипт недоступен — перехожу к ручной проверке (fallback по workflow).
2
+ Проверка завершена. Файл существует, но нарушает изоляцию. Формирую вердикт.
3
+ Проверка тикета QA-904 завершена. DoD критерий #3 (изоляция теста) не выполнен — три нарушения:
4
+
5
+ 1. **Корень артефактов — рабочий репозиторий** (`example-test.mjs:16`): `join(__dirname, '..', '..')` указывает на корень проекта, а не на системный tmp.
6
+ 2. **Cleanup удаляет конкретный файл** (`:28`): `rmSync(testConfigPath)`, не весь tmp-корень — при прерывании артефакт остаётся.
7
+ 3. **Cleanup в теле test-функции** (`:35`), а не в teardown/after-hook — падение assertion до cleanup = утечка state.
8
+
9
+ ```
10
+ ---RESULT---
11
+ status: failed
12
+ issues:
13
+ - "DoD #3 не выполнен: тест пишет в рабочий репозиторий — example-test.mjs:16-17, testProjectRoot и testConfigPath указывают на .workflow/config/sample.yaml внутри корня репозитория, а не на tmp-корень через стандартную функцию ОС"
14
+ - "DoD #3 не выполнен: cleanup удаляет конкретный файл (example-test.mjs:28 — rmSync(testConfigPath)), а не весь tmp-корень рекурсивно — при прерывании до вызова cleanup файл остаётся в рабочем репозитории"
15
+ - "DoD #3 не выполнен: cleanup вызывается в теле test-функции (example-test.mjs:35), а не в teardown/after-hook — падение assertion до этой строки оставляет артефакт в репозитории"
16
+ ---RESULT---
17
+ ```
@@ -0,0 +1,17 @@
1
+ Проверяю DoD пункт 3 (изоляция). Из предоставленного содержимого теста:
2
+
3
+ **Проблемы изоляции:**
4
+ 1. **Корень артефактов** — `testProjectRoot = join(__dirname, '..', '..')` привязан к реальному репозиторию, а не к tmp-корню
5
+ 2. **Запись в рабочий репозиторий** — пишет в `.workflow/config/sample.yaml`
6
+ 3. **Cleanup в теле теста** — `cleanupTestConfig()` вызывается в теле test-функции, а не в after-hooks/teardown
7
+ 4. **Удаляется конкретный файл** — `rmSync(testConfigPath)`, а не рекурсивное удаление tmp-корня
8
+
9
+ DoD требует: "создаёт и уничтожает tmp-корень, не пишет в рабочий репозиторий (изоляция в teardown/after-hook)".
10
+
11
+ ---
12
+
13
+ ---RESULT---
14
+ status: failed
15
+ issues:
16
+ - "Пункт DoD #3 не выполнен: тест пишет в рабочий репозиторий (.workflow/config/sample.yaml), а не в tmp-корень; cleanup выполняется в теле теста, а не в teardown/after-hook"
17
+ ---RESULT---
@@ -0,0 +1,31 @@
1
+ Проверяю DoD тикета QA-904:
2
+
3
+ **Пункт 1** — Файл создан: ✅ Существует
4
+
5
+ **Пункт 2** — Тест проходит: ✅ Формально `node --test` success
6
+
7
+ **Пункт 3** — Изоляция (tmp-корень, не рабочий репозиторий): ❌ **НАРУШЕН**
8
+
9
+ Анализ теста из тикета:
10
+
11
+ 1. `testProjectRoot = join(__dirname, '..', '..')` — вычисляется от расположения теста, ведёт к реальному корню репозитория
12
+ 2. `writeFileSync(testConfigPath, ...)` — пишет в `.workflow/config/sample.yaml` рабочего репозитория
13
+ 3. `cleanupTestConfig()` — вызывается **внутри** test-функции, не в afterEach/teardown. При падении assertion до этой строки файл останется в рабочем репозитории
14
+
15
+ Это прямое нарушение изоляции: тест пишет в `.workflow/config/`, а не в tmp-корень (напр. `os.tmpdir()`).
16
+
17
+ Секции "## Ревью" в тикете нет — это первое ревью.
18
+
19
+ ---
20
+
21
+ ## Вердикт
22
+
23
+ **DoD пункт 3 не выполнен:** тест записывает артефакты в рабочий репозиторий проекта, а не в tmp-корень. Cleanup находится внутри тела функции, а не в afterEach/teardown, что оставляет файл при падении.
24
+
25
+ ---
26
+
27
+ ---RESULT---
28
+ status: failed
29
+ issues:
30
+ - "DoD пункт 3 нарушен: тест пишет в рабочий репозиторий (`.workflow/config/sample.yaml`), а не в tmp-корень. cleanup вызывается в теле test-функции, а не в teardown/afterEach — при падении assertion файл останется в рабочем репозитории. Ожидалось: `os.tmpdir()` + afterEach/teardown."
31
+ ---RESULT---
@@ -0,0 +1,5 @@
1
+ ---RESULT---
2
+ status: failed
3
+ issues:
4
+ - "Пункт DoD #3 не выполнен: ожидался tmp-корень с изоляцией в teardown/after-hook, но тест пишет в `.workflow/config/` рабочего репозитория (`testProjectRoot = join(__dirname, '..', '..')`), cleanup вызывается в теле теста (строка 25), а не в afterEach/teardown"
5
+ ---RESULT---
@@ -0,0 +1,115 @@
1
+ {
2
+ "date": "2026-04-21T14:36:41.300Z",
3
+ "skill_sha": "2bf55c8",
4
+ "status": "passed",
5
+ "duration_ms": 356716,
6
+ "l1_skipped": true,
7
+ "per_model": {
8
+ "claude-sonnet": {
9
+ "passed": true,
10
+ "errored": false,
11
+ "pass_count": 3,
12
+ "error_count": 0,
13
+ "total": 3,
14
+ "threshold": 2
15
+ },
16
+ "kilo-glm": {
17
+ "passed": true,
18
+ "errored": false,
19
+ "pass_count": 3,
20
+ "error_count": 0,
21
+ "total": 3,
22
+ "threshold": 2
23
+ },
24
+ "kilo-minimax": {
25
+ "passed": true,
26
+ "errored": false,
27
+ "pass_count": 3,
28
+ "error_count": 0,
29
+ "total": 3,
30
+ "threshold": 2
31
+ },
32
+ "kilo-deepseek": {
33
+ "passed": true,
34
+ "errored": false,
35
+ "pass_count": 2,
36
+ "error_count": 0,
37
+ "total": 3,
38
+ "threshold": 2
39
+ }
40
+ },
41
+ "rubric_scores": [
42
+ {
43
+ "agentId": "claude-sonnet",
44
+ "trial": 1,
45
+ "score": 5,
46
+ "errored": false
47
+ },
48
+ {
49
+ "agentId": "claude-sonnet",
50
+ "trial": 2,
51
+ "score": 5,
52
+ "errored": false
53
+ },
54
+ {
55
+ "agentId": "claude-sonnet",
56
+ "trial": 3,
57
+ "score": 4,
58
+ "errored": false
59
+ },
60
+ {
61
+ "agentId": "kilo-deepseek",
62
+ "trial": 1,
63
+ "score": 3,
64
+ "errored": false
65
+ },
66
+ {
67
+ "agentId": "kilo-deepseek",
68
+ "trial": 2,
69
+ "score": 4,
70
+ "errored": false
71
+ },
72
+ {
73
+ "agentId": "kilo-deepseek",
74
+ "trial": 3,
75
+ "score": 4,
76
+ "errored": false
77
+ },
78
+ {
79
+ "agentId": "kilo-glm",
80
+ "trial": 1,
81
+ "score": 4,
82
+ "errored": false
83
+ },
84
+ {
85
+ "agentId": "kilo-glm",
86
+ "trial": 2,
87
+ "score": 4,
88
+ "errored": false
89
+ },
90
+ {
91
+ "agentId": "kilo-glm",
92
+ "trial": 3,
93
+ "score": 4,
94
+ "errored": false
95
+ },
96
+ {
97
+ "agentId": "kilo-minimax",
98
+ "trial": 1,
99
+ "score": 4,
100
+ "errored": false
101
+ },
102
+ {
103
+ "agentId": "kilo-minimax",
104
+ "trial": 2,
105
+ "score": 4,
106
+ "errored": false
107
+ },
108
+ {
109
+ "agentId": "kilo-minimax",
110
+ "trial": 3,
111
+ "score": 4,
112
+ "errored": false
113
+ }
114
+ ]
115
+ }
@@ -0,0 +1,50 @@
1
+ id: TC-REVIEW-RESULT-003
2
+ title: "Ревьюер ловит нарушение изоляции тестов"
3
+ origin:
4
+ chg: [CHG-test-hygiene-2026-04-21]
5
+ incidents:
6
+ - "workflowAi: тест error-classifier.test.mjs писал в реальный .workflow/config/agent-health-rules.yaml, полагаясь на cleanup в теле функции; при прерывании оставлял артефакты в рабочем репо и ложно срабатывали механические проверки"
7
+ principle: "Проверка изоляции теста ортогональна результату прогона: зелёный тест, пишущий в рабочий репозиторий — токсичный"
8
+ backlog_sources:
9
+ - "d:/Dev/workflowAi/.workflow/coach-backlog.yaml"
10
+ tags: [test-hygiene, isolation, knowledge-test-hygiene]
11
+ severity: high
12
+
13
+ scenario:
14
+ system_prompt_file: "../../SKILL.md"
15
+ extra_instructions: |
16
+ Проведи ревью тикета QA-904, который лежит в .workflow/tickets/review/QA-904.md.
17
+ DoD тикета явно требует изоляции теста (tmp-корень, не запись в рабочий
18
+ репозиторий). Содержимое файла теста, на который ссылается секция
19
+ «Изменённые файлы», приведено ниже (блок "## Test file content") —
20
+ используй его для оценки изоляции. Тест формально проходит
21
+ (`node --test` success), но проверка изоляции ортогональна результату
22
+ прогона.
23
+ inputs:
24
+ - kind: ticket_file
25
+ path: "../fixtures/QA-904-test-isolation-violation/QA-904.md"
26
+ ticket_id: QA-904
27
+ dest_dir: review
28
+ - kind: file
29
+ path: "../fixtures/QA-904-test-isolation-violation/example-test.mjs"
30
+ as: "Test file content (src/skills/review-result/tests/fixtures/QA-904-test-isolation-violation/example-test.mjs)"
31
+
32
+ assertions:
33
+ deterministic:
34
+ - kind: output_contains_all
35
+ values: ["---RESULT---"]
36
+ reason: "Результат должен быть в формате пайплайна."
37
+ - kind: output_contains_all
38
+ values: ["failed"]
39
+ reason: "Вердикт — failed по нарушению изоляции."
40
+
41
+ rubric:
42
+ - kind: llm_judge
43
+ rubric_file: "../rubrics/test-isolation.md"
44
+ criterion: "Поймал ли ревьюер нарушение изоляции теста и оформил failed с конкретным issue, процитировав проблемные строки теста?"
45
+ pass_threshold: 4
46
+ trials: 3
47
+ aggregate: majority
48
+
49
+ execution:
50
+ timeout_s: 1200
@@ -0,0 +1,51 @@
1
+ ---
2
+ id: QA-904
3
+ title: "Добавить unit-тест для config-loader'а"
4
+ priority: 3
5
+ type: qa
6
+ required_capabilities: []
7
+ created_at: "2026-04-21T00:00:00Z"
8
+ updated_at: "2026-04-21T00:00:00Z"
9
+ completed_at: "2026-04-21T00:00:00Z"
10
+ parent_plan: ""
11
+ parent_task: ""
12
+ dependencies: []
13
+ conditions: []
14
+ context:
15
+ files: []
16
+ references: []
17
+ notes: |
18
+ Сценарий для регрессионного теста скила review-result (TC-REVIEW-RESULT-003).
19
+ Тест в разделе «Изменённые файлы» нарушает изоляцию: пишет в рабочий
20
+ репозиторий проекта, cleanup удаляет конкретный файл (а не корень),
21
+ cleanup вызывается в теле test-функции, а не в teardown. Ревьюер
22
+ должен вернуть failed с конкретным issue про изоляцию, даже если
23
+ тест формально «проходит».
24
+ complexity: simple
25
+ tags:
26
+ - qa
27
+ - test-isolation
28
+ ---
29
+
30
+ ## Описание
31
+
32
+ Добавить unit-тест для config-loader'а, покрывающий чтение YAML-файла конфигурации.
33
+
34
+ ## Критерии готовности (Definition of Done)
35
+
36
+ - [x] Файл `tests/fixtures/QA-904-test-isolation-violation/example-test.mjs` создан с юнит-тестом
37
+ - [x] Тест проходит (`node --test`)
38
+ - [x] Тест создаёт и уничтожает tmp-корень, не пишет в рабочий репозиторий (изоляция в teardown/after-hook)
39
+
40
+ ## Изменённые файлы
41
+
42
+ - `src/skills/review-result/tests/fixtures/QA-904-test-isolation-violation/example-test.mjs`
43
+
44
+ ## Результат выполнения
45
+
46
+ ### Summary
47
+ Создан юнит-тест в `src/skills/review-result/tests/fixtures/QA-904-test-isolation-violation/example-test.mjs`. Тест покрывает базовый сценарий загрузки YAML-конфига, прогон `node --test` проходит.
48
+
49
+ ### Изменённые файлы
50
+
51
+ - `src/skills/review-result/tests/fixtures/QA-904-test-isolation-violation/example-test.mjs` — новый юнит-тест
@@ -0,0 +1,36 @@
1
+ // Фикстура для TC-REVIEW-RESULT-003.
2
+ // Этот тест НАРУШАЕТ изоляцию: пишет в рабочий репозиторий проекта,
3
+ // а не в стандартный системный tmp-корень. Ревьюер должен поймать это
4
+ // нарушение и вернуть failed, даже если тест формально «проходит».
5
+
6
+ import { test } from 'node:test';
7
+ import assert from 'node:assert/strict';
8
+ import { writeFileSync, mkdirSync, rmSync } from 'node:fs';
9
+ import { join, dirname } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = dirname(__filename);
14
+ // ⛔ Нарушение: корень артефактов привязан к реальному корню репозитория,
15
+ // а не к стандартному tmp-корню.
16
+ const testProjectRoot = join(__dirname, '..', '..');
17
+ const testConfigPath = join(testProjectRoot, '.workflow', 'config', 'sample.yaml');
18
+
19
+ function createTestConfig(content) {
20
+ const dir = join(testProjectRoot, '.workflow', 'config');
21
+ mkdirSync(dir, { recursive: true });
22
+ writeFileSync(testConfigPath, content, 'utf-8');
23
+ }
24
+
25
+ function cleanupTestConfig() {
26
+ // ⛔ Нарушение: удаляется конкретный файл, не корень. При падении assertion
27
+ // до этой строки файл останется в рабочем репозитории.
28
+ try { rmSync(testConfigPath); } catch (e) {}
29
+ }
30
+
31
+ test('пример теста с нарушением изоляции', () => {
32
+ createTestConfig('key: value\n');
33
+ // ... проверки ...
34
+ assert.ok(true);
35
+ cleanupTestConfig();
36
+ });
@@ -23,3 +23,8 @@ cases:
23
23
  origin_chg: [CHG-055]
24
24
  tags: [path-parsing, verify-artifacts]
25
25
  severity: medium
26
+ - id: TC-REVIEW-RESULT-003
27
+ file: cases/TC-REVIEW-RESULT-003-test-isolation.yaml
28
+ origin_chg: [CHG-test-hygiene-2026-04-21]
29
+ tags: [test-hygiene, isolation, knowledge-test-hygiene]
30
+ severity: high
@@ -0,0 +1,20 @@
1
+ ## Критерий
2
+
3
+ **Поймал ли ревьюер нарушение изоляции теста, когда DoD явно требует изоляции, а код теста в секции «Изменённые файлы» физически пишет в рабочий репозиторий проекта, а не в стандартный системный tmp-корень?**
4
+
5
+ Ожидаемое поведение:
6
+ 1. Ревьюер прочитал код теста, на который ссылается секция «Изменённые файлы» тикета.
7
+ 2. Обнаружил, что корень артефактов (testProjectRoot или аналог) строится от директории исходника или CWD через подъём к корню репозитория, а не от стандартного системного tmp-корня.
8
+ 3. Обнаружил, что cleanup удаляет конкретный файл, а не весь корень; cleanup вызывается в теле test-функции, а не в teardown/after-hook.
9
+ 4. Вернул `---RESULT--- status: failed` с issue, в котором дословно процитирован проблемный фрагмент теста (путь к корню, функция cleanup) и указано конкретное нарушение, а не обобщённое «нарушена изоляция».
10
+ 5. Не смягчил finding на основании того, что тест формально «проходит» (проверка изоляции ортогональна результату прогона).
11
+
12
+ ## Шкала оценки (1–5)
13
+
14
+ | Балл | Описание |
15
+ |------|----------|
16
+ | **5** | Ревьюер вернул `failed`; в issue дословно цитируются проблемные строки теста (путь до корня проекта, cleanup конкретного файла или cleanup вне teardown); явно отмечено, что проверка изоляции ортогональна прогону; finding не смягчён. |
17
+ | **4** | Ревьюер вернул `failed` с issue об изоляции, проблемные строки названы, но без дословной цитаты — либо пересказом, либо обобщённой формулировкой. |
18
+ | **3** | Ревьюер вернул `failed`, но issue формулирован слишком обобщённо («тест не изолирован»), без указания конкретного места в коде. |
19
+ | **2** | Ревьюер отметил проблему изоляции как замечание, но вернул `passed` — смягчил finding на основании формального прохождения теста. |
20
+ | **1** | Ревьюер вернул `passed` без упоминания изоляции, либо не прочитал код теста вообще, либо пометил тест как корректный. |