mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-28 19:01:34 +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
47 lines
2.6 KiB
JavaScript
47 lines
2.6 KiB
JavaScript
// #634: цена входа агента измерима и ограничена (AC1: автор ≤ 12 000 слов).
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import test from 'node:test';
|
|
import { ROUTES, countWords, measureAll, measureRoute } from '../scripts/entry-cost.mjs';
|
|
|
|
const read = (rel) => readFileSync(new URL(`../${rel}`, import.meta.url), 'utf8');
|
|
|
|
test('#634 entry-cost: вход автора и ревьюера в бюджете (AC1)', () => {
|
|
const results = measureAll();
|
|
assert.equal(ROUTES.author.budget, 12000, 'бюджет автора — AC1 #634');
|
|
for (const [name, result] of Object.entries(results)) {
|
|
if (result.budget == null) continue;
|
|
assert.equal(result.over, false, `${name}: ${result.total} слов > бюджета ${result.budget}`);
|
|
assert.ok(result.total <= result.budget);
|
|
}
|
|
// Маршрут автора не содержит полного канона — иначе бюджет держится случайно.
|
|
assert.ok(!ROUTES.author.files.includes('PROCESS.md'));
|
|
assert.ok(ROUTES.author.files.includes('docs/process/AUTHOR.md'));
|
|
assert.ok(ROUTES.reviewer.files.includes('docs/process/REVIEWER.md'));
|
|
});
|
|
|
|
test('#634 entry-cost: превышение бюджета краснит замер', () => {
|
|
const files = { 'a.md': 'one two three', 'b.md': 'четыре пять\nшесть\t семь' };
|
|
const reader = (rel) => files[rel];
|
|
assert.equal(countWords(files['b.md']), 4);
|
|
const within = measureRoute({ budget: 7, files: ['a.md', 'b.md'] }, reader);
|
|
assert.deepEqual([within.total, within.over], [7, false]);
|
|
const over = measureRoute({ budget: 6, files: ['a.md', 'b.md'] }, reader);
|
|
assert.deepEqual([over.total, over.over], [7, true]);
|
|
assert.equal(measureRoute({ budget: null, files: ['a.md'] }, reader).over, false);
|
|
});
|
|
|
|
test('#634 entry-cost: AGENTS.md называет те же маршруты в том же порядке', () => {
|
|
const agents = read('AGENTS.md');
|
|
const section = agents.slice(agents.indexOf('**Reading order by role**'), agents.indexOf('The two digests'));
|
|
assert.ok(section.length > 0, 'раздел порядка чтения в AGENTS.md');
|
|
const route = (prefix) => {
|
|
const item = section.split('\n- ').find((chunk) => chunk.startsWith(prefix));
|
|
assert.ok(item, `AGENTS.md: нет пункта «${prefix}»`);
|
|
return [...item.matchAll(/`([^`]+\.md)`/g)].map((match) => match[1]);
|
|
};
|
|
assert.deepEqual(route('author'), ROUTES.author.files);
|
|
assert.deepEqual(route('reviewer'), ROUTES.reviewer.files);
|
|
assert.deepEqual(route('changing the pipeline'), ROUTES.canon.files);
|
|
});
|