Files
brain/tools/coverage-wiring.mjs
T

62 lines
3.3 KiB
JavaScript
Raw Normal View History

#!/usr/bin/env node
/**
* coverage-wiring — тонкий мост между списком рекомендованных навыков и машиной охвата.
* Заменяет реестр цепочек L механической проверкой полноты: грузит контракты с замком
* словаря (D5), выбирает рекомендованные, считает readinessChecklist и отдаёт карточки +
* вердикт готовности для живого гейта судьи. Без LLM (set/graph-операции).
*
* `ready` (спека D3/D4) = НЕТ ДЫР покрытия И НЕТ ЦИКЛА: твёрдый стоп печати — на дыре
* (нужда, которую никто в наборе не производит и которой нет в данностях). Сироты
* (scope-creep) и непокрытые просьбы — мягкие сигналы в `items`, печать не стопорят.
*/
import fsDefault from 'node:fs';
import { loadRegistry, dispatchContract } from './skill-contract-registry.mjs';
import { loadVocabulary } from './capability-vocabulary.mjs';
import { readinessChecklist } from './coverage-machine.mjs';
import { loadInitialInputs } from './registry-initial-inputs.mjs';
const HOLES_POINTER = '§A findHoles';
const CYCLE_POINTER = '§A topoOrder';
/**
* Построить вход охвата для гейта по рекомендованным навыкам.
* 1) loadRegistry с vocabTokens (D5 — замок словаря на живом пути);
* 2) выбрать контракты рекомендованных навыков (dispatchContract, mode 'exact');
* 3) readinessChecklist({ выбранные, requests, initialInputs:данности });
* 4) → { cards, ready (нет дыр && нет цикла), holes, cycle, items, errors }.
* fsImpl/dir/vocabPath инъектируются (тесты — синтетические контракты).
*/
export function buildCoverageInput({
recommendedSkills = [],
dir = 'docs/registry/contracts',
vocabPath = 'docs/registry/capability-vocabulary.json',
requests = [],
fsImpl = fsDefault,
} = {}) {
const vocab = loadVocabulary({ path: vocabPath, fsImpl });
const registry = loadRegistry({ dir, fsImpl, vocabTokens: vocab.tokens }); // D5: замок на живом пути
const initialInputs = loadInitialInputs({ path: vocabPath, fsImpl });
const selected = [];
for (const skill of recommendedSkills || []) {
const d = dispatchContract(registry, skill);
if (d.mode === 'exact' && d.contract) selected.push(d.contract);
}
const cards = selected.map((c) => ({
skill: c.skill,
needs: c.needs || [],
produces: c.produces || [],
}));
const checklist = readinessChecklist({ contracts: selected, requests, initialInputs });
const items = checklist.items || [];
const holes = (items.find((i) => i && i.pointer === HOLES_POINTER) || {}).detail || [];
const cycle = (items.find((i) => i && i.pointer === CYCLE_POINTER) || {}).detail || null;
// Спека D3/D4: стоп только на дыре/цикле (полнота+корректность), не на сироте/scope-creep.
const ready = holes.length === 0 && cycle === null;
return { cards, ready, holes, cycle, items, errors: registry.errors };
}