restore: run-test-json конфиг от корня репо через resolveVitestConfig plus тест buildVitestJsonArgs plus GUIDE Уроки 9 формат плана
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -351,3 +351,27 @@ Verify-шаги под стеной сдвигают указатель, но GR
|
||||
|
||||
**Мета-урок.** «SyntaxError без позиции» + «статика чистая, vitest красный» = почти всегда
|
||||
CRLF/кодировка, а не логика. Проверь байты и переносы ПЕРВЫМ делом, а не последним.
|
||||
|
||||
## Уроки сессии №9 (2026-06-17) — формат ПЛАНА: verified-context-json + ref=якорь (не проза)
|
||||
|
||||
**Симптом (частая ошибка новой сессии).** Спека опечатана, план содержательно отличный, но печать
|
||||
не встаёт — наставник/судья вроде не против, а seal не приходит.
|
||||
|
||||
**Причина — нарушен ФОРМАТ плана, не суть:**
|
||||
|
||||
1. в плане НЕТ блока ` ```verified-context-json``` ` — а он обязателен и для ПЛАНА (≥1 `EXTRACTED` с
|
||||
реальным якорём-подстрокой), иначе печать не встаёт;
|
||||
2. в `steps-json` поле `ref` несёт ПРОЗУ-описание («Task1 RED: …») вместо якоря спеки. `ref` обязан
|
||||
быть НЕПУСТЫМ якорем секции спеки (`{#u3}` → `ref:"u3"`; `D1..Dn`/`u1..un`).
|
||||
3. навык в `skills-json` — БЕЗ плагин-префикса (`test-driven-development`, не
|
||||
`superpowers:test-driven-development`).
|
||||
|
||||
**Лечение:** добавить в план блок `verified-context-json` (готовый рабочий якорь: ref
|
||||
`tools/cost-pricing.mjs`, anchor `export const PRICING = Object.freeze(`) + заменить все `ref` на
|
||||
якоря секций спеки.
|
||||
|
||||
**Прецедент (параллель-сессия трек 2c, 2026-06-17).** План r1 не имел `verified-context-json` и нёс
|
||||
прозу в `ref` → печать не вставала; контроллер переписал план трижды (r1→r2→r3), на r3 добавил
|
||||
`verified-context-json` EXTRACTED + якорные `ref` → наставник GO, судья GO, церемония пройдена. Суть
|
||||
фичи была верной с r1 — итерации терялись ТОЛЬКО на ритуальном формате. **Вывод:** сверь план с
|
||||
«Рецептом церемонии» (выше, п.2) ДО первой записи — экономит 2-3 круга наставника/судьи.
|
||||
|
||||
+11
-5
@@ -6,7 +6,7 @@
|
||||
* mutate-runner трактует как inconclusive (не «убит»). Чистый parseVitestJson + I/O runVitestJson.
|
||||
*/
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { join } from 'node:path';
|
||||
import { resolveVitestConfig } from './produce-verify-receipt.mjs';
|
||||
|
||||
/** Разобрать stdout vitest --reporter json. Битый/пустой → loadError. */
|
||||
export function parseVitestJson(jsonText) {
|
||||
@@ -23,14 +23,20 @@ export function parseVitestJson(jsonText) {
|
||||
return { allGreen, numTests, numPassed, numFailed, loadError: false };
|
||||
}
|
||||
|
||||
/** Аргументы `npx` для прогона одного тест-файла. Корень и конфиг сюиты — ОТ КОРНЯ репозитория
|
||||
* через общий resolveVitestConfig (есть app/ → app-режим, иначе корень); без хардкода app/.
|
||||
* `exists` инъектируется (для теста); по умолчанию resolveVitestConfig берёт existsSync. */
|
||||
export function buildVitestJsonArgs(testFile, gitCwd, exists) {
|
||||
const { root, config } = resolveVitestConfig(gitCwd, exists);
|
||||
return ['vitest', 'run', testFile, '--root', root, '--config', config, '--reporter', 'json'];
|
||||
}
|
||||
|
||||
/** I/O: прогнать testFile через vitest json. exit≠0 (упавшие тесты) — это нормально, парсим stdout. */
|
||||
export function runVitestJson(testFile, gitCwd) {
|
||||
let stdout = '';
|
||||
try {
|
||||
stdout = execFileSync('npx', ['vitest', 'run', testFile,
|
||||
'--root', join(gitCwd, 'app'),
|
||||
'--config', join(gitCwd, 'app', 'vitest.config.tools.mjs'),
|
||||
'--reporter', 'json'], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
|
||||
stdout = execFileSync('npx', buildVitestJsonArgs(testFile, gitCwd),
|
||||
{ encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
|
||||
} catch (e) {
|
||||
// Упавшие тесты → execFileSync бросает с ненулевым кодом; stdout всё равно несёт json.
|
||||
stdout = (e && e.stdout) ? String(e.stdout) : '';
|
||||
|
||||
@@ -22,3 +22,21 @@ describe('parseVitestJson (анти-вакуум SE-LB-1/11)', () => {
|
||||
expect(parseVitestJson('')).toEqual({ allGreen: false, numTests: 0, numPassed: 0, numFailed: 0, loadError: true });
|
||||
});
|
||||
});
|
||||
|
||||
import { buildVitestJsonArgs } from './run-test-json.mjs';
|
||||
|
||||
describe('buildVitestJsonArgs (конфиг от корня репо, без хардкода app/)', () => {
|
||||
const norm = (s) => String(s).replace(/\\/g, '/');
|
||||
it('есть app/vitest.config.tools.mjs → root=app', () => {
|
||||
const a = buildVitestJsonArgs('t.mjs', '/repo', (p) => norm(p).endsWith('app/vitest.config.tools.mjs'));
|
||||
expect(norm(a[a.indexOf('--root') + 1])).toBe('/repo/app');
|
||||
expect(norm(a[a.indexOf('--config') + 1])).toBe('/repo/app/vitest.config.tools.mjs');
|
||||
});
|
||||
it('нет app/-конфига → root=корень репо + базовая форма аргументов', () => {
|
||||
const a = buildVitestJsonArgs('t.mjs', '/repo', () => false);
|
||||
expect(a[a.indexOf('--root') + 1]).toBe('/repo');
|
||||
expect(a[0]).toBe('vitest');
|
||||
expect(a).toContain('t.mjs');
|
||||
expect(a).toContain('json');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user