Files
brain/docs/superpowers/specs/2026-06-17-tools-app-path-split-legacy-fix-design.md
T

5.4 KiB

Фикс наследия сплита: хардкод app/ в инструментах прогона тестов

Цель

После разделения управляющего слоя из проекта Лидерра часть инструментов прогона тестов осталась с жёстко прописанным путём app/ — это подпапка layout'а Лидерры. В этом репозитории папки app/ нет: конфиг сюиты лежит в корне (vitest.config.tools.mjs). Из-за хардкода прогон одного тест-файла через tools/run-test-json.mjs не находит конфиг, возвращает loadError, и по-критерийный зелёный (produce-criterion-greens) выходит никогда не зелёным. Цель — выбирать корень и конфиг сюиты ОТ КОРНЯ репозитория (как уже делает tools/produce-verify-receipt.mjs), единым источником истины, и эмпирически проверить, подписывает ли производитель verify-расписки расписку при дочернем прогоне сюиты в этом окружении.

Контракт buildVitestJsonArgs

Новая чистая экспортируемая функция в tools/run-test-json.mjs: buildVitestJsonArgs(testFile, gitCwd, exists) → массив аргументов для npx: ['vitest', 'run', testFile, '--root', <root>, '--config', <config>, '--reporter', 'json'], где <root> и <config> берутся из resolveVitestConfig(gitCwd, exists). Параметр exists инъектируется (для теста), по умолчанию — existsSync. Функция чистая: никакого исполнения, никакого fs кроме инъектируемого предиката.

Алгоритм

  1. resolveVitestConfig импортируется из tools/produce-verify-receipt.mjs — единый источник выбора: есть app/vitest.config.tools.mjs → app-режим (root=<repo>/app); иначе корень репозитория (root=<repo>, config=<repo>/vitest.config.tools.mjs).
  2. buildVitestJsonArgs строит массив аргументов на основе результата (1).
  3. I/O-функция runVitestJson вызывает buildVitestJsonArgs(testFile, gitCwd) и передаёт результат в execFileSync('npx', args, …) вместо захардкоженного app/. Разбор stdout (parseVitestJson) — без изменений.

Крайние случаи

  • Есть app/vitest.config.tools.mjs (layout Лидерры) → root=<repo>/app, config из app — обратная совместимость сохранена.
  • Нет app/-конфига (этот репозиторий) → root=<repo>, config из корня.
  • exists инъектируем — выбор детерминирован и тестируем без файловой системы.

Конвенция заголовка

Шапка-комментарий модуля run-test-json сохраняет существующий стиль (назначение, анти-вакуум SE-LB-1/11). Новая функция документируется одной строкой назначения над сигнатурой.

Диагностика производителя расписки

Эмпирически проверить под текущим окружением: запуск node tools/produce-verify-receipt.mjs печатает signed GREEN (дочерний прогон сюиты отработал — выбор пути достаточен) либо NOT signed: suite-not-passed (дочерний прогон не отработал — выбор пути верен, но нужна отдельная стратегия прогона). Наблюдаемый исход фиксирует, достаточно ли одного выбора пути.

Граница задачи

В границах: миграция выбора конфига в run-test-json на resolveVitestConfig (через TDD) и наблюдение исхода производителя расписки. ВНЕ границ: если дочерний прогон не отрабатывает — сама стратегия прогона (чтение готового результата вместо своего прогона / неколлапсирующая конфигурация пула воркеров) — отдельная задача; здесь не реализуется.

Критерий приёмки

  • В построении аргументов прогона в tools/run-test-json.mjs нет литерала 'app'.
  • buildVitestJsonArgs покрыт тестами: app-режим и корневой режим (через инъекцию exists).
  • Полная сюита (vitest.config.tools.mjs) зелёная.
[
  {"id":"ax1","kind":"EXTRACTED","ref":"tools/run-test-json.mjs","anchor":"export function runVitestJson"},
  {"id":"ax2","kind":"EXTRACTED","ref":"tools/produce-verify-receipt.mjs","anchor":"export function resolveVitestConfig"}
]