Files
playbook/antigravity-awesome-skills/tools/local-skill-reviewer/evidence.js
T
2026-07-18 00:02:59 +00:00

46 lines
2.4 KiB
JavaScript

"use strict";
function lineSlice(content, startLine, endLine) {
if (!Number.isInteger(startLine) || !Number.isInteger(endLine) || startLine < 1 || endLine < startLine) {
throw new Error("Evidence line range is invalid");
}
const lines = content.split(/\r?\n/);
if (endLine > lines.length) throw new Error("Evidence line range exceeds snapshot");
return lines.slice(startLine - 1, endLine).join("\n");
}
function verifyEvidenceItem(item, bundleByPath) {
if (!item || typeof item !== "object") throw new Error("Evidence must be an object");
const source = bundleByPath.get(item.path);
if (typeof source !== "string") throw new Error(`Evidence path is outside snapshot: ${item.path}`);
const actual = lineSlice(source, item.start_line, item.end_line);
if (actual !== item.excerpt) throw new Error(`Evidence excerpt mismatch: ${item.path}:${item.start_line}`);
return true;
}
function verifyJudgment(kind, judgment, bundleByPath, dimensions) {
if (!judgment || typeof judgment !== "object") throw new Error(`${kind} judgment missing`);
const actual = Object.keys(judgment.dimensions || {}).sort();
const expected = Object.keys(dimensions).sort();
if (actual.join("\0") !== expected.join("\0")) throw new Error(`${kind} dimension set mismatch`);
for (const name of expected) {
const dimension = judgment.dimensions[name];
if (!Number.isInteger(dimension.score) || dimension.score < 1 || dimension.score > 3) {
throw new Error(`${kind}.${name} score must be an integer in [1, 3]`);
}
if (!Array.isArray(dimension.evidence) || dimension.evidence.length === 0) {
throw new Error(`${kind}.${name} requires evidence`);
}
for (const item of dimension.evidence) verifyEvidenceItem(item, bundleByPath);
const deterministic = typeof dimension.reason_code === "string" && dimension.signals && typeof dimension.signals === "object";
const semantic = ["reasoning", "positive", "suggestion"].every((field) => typeof dimension[field] === "string" && dimension[field].trim());
if (!deterministic && !semantic) throw new Error(`${kind}.${name} requires deterministic signals or semantic reasoning`);
if (deterministic && (!Number.isFinite(dimension.confidence) || dimension.confidence < 0 || dimension.confidence > 1)) {
throw new Error(`${kind}.${name}.confidence must be in [0, 1]`);
}
}
return true;
}
module.exports = { lineSlice, verifyEvidenceItem, verifyJudgment };