mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
Вход агента до первого файла кода стоил ≈ 26 700 слов (аудит 22.09). - docs/process/AUTHOR.md и REVIEWER.md — выжимки PROCESS.md: каждый пункт ссылается на раздел канона, ключевые формулировки дословные; test/process-digests.test.mjs сверяет якоря, ссылки и правила. - scripts/entry-cost.mjs — маршрут чтения по роли и бюджет (автор ≤ 12 000 слов, AC1); AGENTS.md «Read this first» называет те же маршруты. - docs/STATUS.md: блок Snapshot генерирует scripts/status-snapshot.mjs (версии — release-contract, счётчики — inventory, теги — git); feature surface и ранние milestones перенесены дословно в docs/STATUS-FEATURES.md. - docs/TESTING.md — действующая инструкция (684 строки, AC3); ручные чек-листы и приложения по issue перенесены дословно в docs/testing-notes/ с индексом и тестом на полноту. - Промпт ревьюера в process.yml читает конспект вместо пересказа правил; машинные требования (строка вердикта, REVIEW_DOC, запрет fetch, таблица «чем краснеет», разделы повторного раунда) сохранены и закреплены тестом. - PROCESS.md: правила не менялись; добавлены ссылка на конспекты в шапке и уточнение в §10.4, что ревьюер конвейера читает конспект. - 7 мутантов в реестре. Issue: #634 User-Visible: no
44 lines
2.9 KiB
JavaScript
44 lines
2.9 KiB
JavaScript
// #634: docs/TESTING.md — действующая инструкция (AC3: ≤ 800 строк), приложения
|
|
// по issue и ручные чек-листы — в docs/testing-notes/, доступны по индексу.
|
|
import assert from 'node:assert/strict';
|
|
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import test from 'node:test';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { headings, markdownLinks } from '../scripts/md-anchors.mjs';
|
|
|
|
const ROOT = fileURLToPath(new URL('..', import.meta.url));
|
|
const NOTES = 'docs/testing-notes';
|
|
const read = (rel) => readFileSync(join(ROOT, rel), 'utf8').replace(/\r\n?/g, '\n');
|
|
const noteFiles = () => readdirSync(join(ROOT, NOTES)).filter((name) => name.endsWith('.md') && name !== 'README.md').sort();
|
|
|
|
test('#634 TESTING.md: инструкция не длиннее 800 строк и ведёт к индексу приложений (AC3)', () => {
|
|
const testing = read('docs/TESTING.md');
|
|
const lines = testing.split('\n').length - (testing.endsWith('\n') ? 1 : 0);
|
|
assert.ok(lines <= 800, `docs/TESTING.md: ${lines} строк > 800 — приложение по issue кладётся в ${NOTES}/`);
|
|
assert.ok(markdownLinks(testing).some((link) => link.file === 'testing-notes/README.md'), 'ссылка на индекс');
|
|
// Правила для новых тестов остаются в инструкции — их читают все.
|
|
assert.match(testing, /^## Правила для новых тестов \(issue #85\) — обязательны$/m);
|
|
});
|
|
|
|
test('#634 индекс приложений: каждый раздел каждого приложения — строкой, каждая ссылка жива', () => {
|
|
const index = read(`${NOTES}/README.md`);
|
|
const links = markdownLinks(index);
|
|
const listed = new Set(links.map((link) => `${link.file}#${link.anchor}`));
|
|
const files = noteFiles();
|
|
assert.ok(files.length >= 5, 'приложения на месте');
|
|
for (const file of files) {
|
|
assert.ok(links.some((link) => link.file === file && !link.anchor), `${file}: нет заголовка группы в индексе`);
|
|
for (const heading of headings(read(`${NOTES}/${file}`)).filter((h) => h.level >= 2)) {
|
|
assert.ok(listed.has(`${file}#${heading.anchor}`), `${file}: раздел «${heading.text}» не в индексе`);
|
|
}
|
|
}
|
|
for (const link of links) {
|
|
if (link.file.startsWith('../')) { assert.ok(existsSync(join(ROOT, 'docs', link.file.slice(3)))); continue; }
|
|
assert.ok(files.includes(link.file), `индекс ссылается на отсутствующий файл ${link.file}`);
|
|
if (!link.anchor) continue;
|
|
const anchors = new Set(headings(read(`${NOTES}/${link.file}`)).map((heading) => heading.anchor));
|
|
assert.ok(anchors.has(link.anchor), `индекс: нет заголовка ${link.file}#${link.anchor}`);
|
|
}
|
|
});
|