Files
brain/tools/coverage-wiring.mjs
T
Дмитрий a5d30f38a3 feat(registry): живой охват 2c — данности, граф, coverage-wiring, врезка в гейт
Этап 2c эпика роутер-реестр: оживление машины охвата как замена цепочкам L.
- registry-initial-inputs.mjs: токены-данности (category:given) для initialInputs.
- registry-graph-health.test.mjs: граф ацикличен, рёбра producer-consumer.
- coverage-wiring.mjs: мост recommended skills -> readinessChecklist -> {cards, ready, holes}; ready=нет-дыр.
- enforce-judge-gate.mjs: coverageCardsFor/coverageGate — карточки + стоп при дыре (инъекция-выкл).
- замок словаря (vocabTokens) на живом пути; гайд по стене: автономность + уроки сессии.
Регрессия: 4375 passed (канонический свод владельца).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 15:18:22 +03:00

62 lines
3.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 };
}