Rocko-authored, Filbert-reviewed inspector (r6 manifest a4a44930...) with full review/build/verdict evidence under docs/plans/reviews. 43/0 selftests, oracle zero-disagreement, foundation checker PASS. Owner A9 acceptance recorded separately.
72 lines
3.0 KiB
JavaScript
72 lines
3.0 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Test-only differential bridge for scripts/foundation/verify-schema.py.
|
|
*
|
|
* node scripts/foundation/validate-record.mjs <corpus.json>
|
|
*
|
|
* Input: a JSON array of {name, raw} where raw is the exact JSON text of one
|
|
* candidate record. Output (stdout): a JSON array, same order, of
|
|
* {name, parse: "ok" | <strict-json error code>, byteOffset,
|
|
* schemaValid: true|false|null, profileValid: bool, verdict, rule, path}
|
|
*
|
|
* schemaValid is the inspector's record-schema verdict (null when the strict
|
|
* parser rejected the text, or when the kind is unsupported and therefore not
|
|
* judged beyond the kind gate); it reproduces the pinned checker's verdict,
|
|
* including its end-of-string newline tolerance on id/runtimeId/digest patterns.
|
|
* profileValid is the strict bundle/profile verdict: strict lexical parse AND
|
|
* shape-valid AND a supported kind AND the strict typed-string profile (addendum
|
|
* FI-C2-1: the whole value satisfies the grammar). A schema-valid, profile-invalid
|
|
* record reports rule "profile-pattern-mismatch" with its first violating path.
|
|
* The two columns are deliberately separate (charter §8, §10.5).
|
|
*
|
|
* This bridge is not part of the inspector and may read the named file; the
|
|
* inspector itself never imports it.
|
|
*/
|
|
|
|
import { readFileSync } from "node:fs";
|
|
import { parseStrict, StrictJsonError, utf8Encode } from "./strict-json.mjs";
|
|
import { validateRecordShape } from "./resolve.mjs";
|
|
|
|
export function judgeRaw(raw) {
|
|
let value;
|
|
try {
|
|
value = parseStrict(utf8Encode(raw));
|
|
} catch (e) {
|
|
if (e instanceof StrictJsonError) {
|
|
return { parse: e.code, byteOffset: e.byteOffset, schemaValid: null, profileValid: false, verdict: "unparsed", rule: null, path: null };
|
|
}
|
|
throw e;
|
|
}
|
|
const v = validateRecordShape(value);
|
|
// Unsupported kinds are refused at the kind gate; their envelope/payload is not
|
|
// judged, so the schema column is "not assessed" (null), never "valid".
|
|
const schemaValid = v.verdict === "unsupported-kind" ? null : v.verdict === "valid";
|
|
const violations = v.verdict === "valid" ? v.profileViolations : [];
|
|
return {
|
|
parse: "ok",
|
|
byteOffset: null,
|
|
schemaValid,
|
|
profileValid: v.verdict === "valid" && violations.length === 0,
|
|
verdict: v.verdict,
|
|
rule: v.rule ?? (violations.length > 0 ? "profile-pattern-mismatch" : null),
|
|
path: v.path ?? (violations.length > 0 ? violations[0] : null),
|
|
};
|
|
}
|
|
|
|
function main() {
|
|
const file = process.argv[2];
|
|
if (!file || process.argv.length !== 3) {
|
|
process.stderr.write("usage: validate-record.mjs <corpus.json>\n");
|
|
process.exit(2);
|
|
}
|
|
const corpus = JSON.parse(readFileSync(file, "utf8"));
|
|
if (!Array.isArray(corpus)) throw new Error("corpus must be an array");
|
|
const out = corpus.map((c) => {
|
|
if (typeof c.name !== "string" || typeof c.raw !== "string") throw new Error("corpus entry needs {name, raw}");
|
|
return { name: c.name, ...judgeRaw(c.raw) };
|
|
});
|
|
process.stdout.write(`${JSON.stringify(out)}\n`);
|
|
}
|
|
|
|
main();
|