#!/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 }; }