397777089e
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
49 lines
2.2 KiB
JavaScript
49 lines
2.2 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* card-coverage — мост покрытия «узлы реестра ↔ карточки-контракты» (H, R-11/R-12).
|
|
* Чистые функции (данные инъектируются): пропущенные контракты, пустые карточки,
|
|
* нерезолвящиеся и асимметричные конфликт-рёбра. Без LLM, без диска.
|
|
*/
|
|
import { resolveNode } from './node-graph.mjs';
|
|
|
|
/** Узлы, у которых нет карточки с skill === node.slug. Возвращает id|slug. */
|
|
export function missingContracts(nodes, contracts) {
|
|
const skills = new Set((contracts || []).map((c) => c && c.skill).filter(Boolean));
|
|
return (nodes || [])
|
|
.filter((n) => n && n.slug && !skills.has(n.slug))
|
|
.map((n) => n.id || n.slug);
|
|
}
|
|
|
|
/** Пустые карточки: ни needs, ни produces (бесполезна всем потребителям). Возвращает skill. */
|
|
export function emptyCards(contracts) {
|
|
return (contracts || [])
|
|
.filter((c) => (c.needs || []).length === 0 && (c.produces || []).length === 0)
|
|
.map((c) => c.skill);
|
|
}
|
|
|
|
/** Конфликт-ссылки, не резолвящиеся в узел графа. {from, ref}. */
|
|
export function unresolvedConflicts(graph) {
|
|
const out = [];
|
|
for (const n of (graph && graph.nodes) || []) {
|
|
const refs = (n.attributes && n.attributes.conflicts_with) || [];
|
|
for (const r of refs) if (!resolveNode(graph, r)) out.push({ from: n.id || n.slug, ref: r });
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/** Односторонние рёбра: A→B, но B не ссылается обратно на A. {from, to}. */
|
|
export function asymmetricConflicts(graph) {
|
|
const out = [];
|
|
for (const n of (graph && graph.nodes) || []) {
|
|
const refs = (n.attributes && n.attributes.conflicts_with) || [];
|
|
for (const r of refs) {
|
|
const t = resolveNode(graph, r);
|
|
if (!t) continue; // unresolved — отдельной функцией
|
|
const back = (t.attributes && t.attributes.conflicts_with) || [];
|
|
const resolvesBack = back.some((b) => resolveNode(graph, b) === n);
|
|
if (!resolvesBack) out.push({ from: n.id || n.slug, to: t.id || t.slug });
|
|
}
|
|
}
|
|
return out;
|
|
}
|