@intentset/verification 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/common.d.ts +51 -0
- package/dist/adapters/common.d.ts.map +1 -0
- package/dist/adapters/common.js +95 -0
- package/dist/adapters/common.js.map +1 -0
- package/dist/adapters/node-test.d.ts +3 -0
- package/dist/adapters/node-test.d.ts.map +1 -0
- package/dist/adapters/node-test.js +119 -0
- package/dist/adapters/node-test.js.map +1 -0
- package/dist/adapters/vitest.d.ts +3 -0
- package/dist/adapters/vitest.d.ts.map +1 -0
- package/dist/adapters/vitest.js +71 -0
- package/dist/adapters/vitest.js.map +1 -0
- package/dist/check.d.ts +33 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +95 -0
- package/dist/check.js.map +1 -0
- package/dist/classify.d.ts +69 -0
- package/dist/classify.d.ts.map +1 -0
- package/dist/classify.js +130 -0
- package/dist/classify.js.map +1 -0
- package/dist/coverage.d.ts +88 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/coverage.js +114 -0
- package/dist/coverage.js.map +1 -0
- package/dist/diagnostic.d.ts +21 -0
- package/dist/diagnostic.d.ts.map +1 -0
- package/dist/diagnostic.js +20 -0
- package/dist/diagnostic.js.map +1 -0
- package/dist/fixture.d.ts +43 -0
- package/dist/fixture.d.ts.map +1 -0
- package/dist/fixture.js +42 -0
- package/dist/fixture.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/placeholders.d.ts +39 -0
- package/dist/placeholders.d.ts.map +1 -0
- package/dist/placeholders.js +47 -0
- package/dist/placeholders.js.map +1 -0
- package/dist/records.d.ts +77 -0
- package/dist/records.d.ts.map +1 -0
- package/dist/records.js +354 -0
- package/dist/records.js.map +1 -0
- package/package.json +33 -0
- package/src/adapters/common.ts +139 -0
- package/src/adapters/node-test.ts +139 -0
- package/src/adapters/vitest.ts +82 -0
- package/src/check.ts +137 -0
- package/src/classify.ts +222 -0
- package/src/coverage.ts +181 -0
- package/src/diagnostic.ts +39 -0
- package/src/fixture.ts +64 -0
- package/src/index.ts +15 -0
- package/src/placeholders.ts +51 -0
- package/src/records.ts +482 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type RunRecord, type RunResult, type RunScope, type RunTool } from "../records.ts";
|
|
2
|
+
export interface ParsedTest {
|
|
3
|
+
/** Ancestor titles and the test's own, joined with " > " (Vitest's own `fullName` when it gives one). */
|
|
4
|
+
fullName: string;
|
|
5
|
+
result: RunResult;
|
|
6
|
+
durationMs: number | null;
|
|
7
|
+
}
|
|
8
|
+
export interface ParsedRun {
|
|
9
|
+
tests: ParsedTest[];
|
|
10
|
+
/** Failures the output reports but no test title carries, such as a file that failed to load. */
|
|
11
|
+
problems: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface ToRunRecordsOptions {
|
|
14
|
+
/** Selector -> verification ID, from the graph's automated verifications. */
|
|
15
|
+
verifications: ReadonlyMap<string, string>;
|
|
16
|
+
commit: string;
|
|
17
|
+
graphHash: string;
|
|
18
|
+
environment: string;
|
|
19
|
+
scope: RunScope;
|
|
20
|
+
tool: RunTool;
|
|
21
|
+
/** UTC timestamps of the whole run. */
|
|
22
|
+
startedAt: string;
|
|
23
|
+
finishedAt: string;
|
|
24
|
+
/** Where the run's report lives; each record's uri is this plus `#` and the verification ID. */
|
|
25
|
+
uriBase: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ConvertedRun {
|
|
28
|
+
/** One record per verification at least one test matched, by verification ID. */
|
|
29
|
+
records: RunRecord[];
|
|
30
|
+
/** Selectors no test matched, sorted: their verifications get no record from this run, and read as missing. */
|
|
31
|
+
unmatched: string[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A selector matches a title when it occurs in it as a whole token: the
|
|
35
|
+
* characters either side are not letters, digits, `_` or `-`. So
|
|
36
|
+
* `schedule-review-v1` matches `schedule [schedule-review-v1] accepts` and a
|
|
37
|
+
* title holding the bracketed tag, but `review-v1` does not match it.
|
|
38
|
+
*/
|
|
39
|
+
export declare function selectorMatches(selector: string, title: string): boolean;
|
|
40
|
+
/** `EV-` and the first 16 hex digits of SHA-256 over the verification ID, commit, graph hash and end time, newline-joined. */
|
|
41
|
+
export declare function deriveEvidenceId(verificationId: string, commit: string, graphHash: string, finishedAt: string): string;
|
|
42
|
+
/** The worse of two results: fail, then error, then skip, then pass. */
|
|
43
|
+
export declare function worst(a: RunResult, b: RunResult): RunResult;
|
|
44
|
+
/**
|
|
45
|
+
* One run record per verification whose selector matched at least one test.
|
|
46
|
+
* Several matching tests make one record with the worst result and a
|
|
47
|
+
* rationale that counts them. Throws when the options would make a malformed
|
|
48
|
+
* record, since that is a caller's mistake rather than evidence.
|
|
49
|
+
*/
|
|
50
|
+
export declare function toRunRecords(parsed: ParsedRun, options: ToRunRecordsOptions): ConvertedRun;
|
|
51
|
+
//# sourceMappingURL=common.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/adapters/common.ts"],"names":[],"mappings":"AAQA,OAAO,EAAkB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAE5G,MAAM,WAAW,UAAU;IACzB,yGAAyG;IACzG,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,iGAAiG;IACjG,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,QAAQ,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,iFAAiF;IACjF,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,+GAA+G;IAC/G,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAKD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAYxE;AAED,8HAA8H;AAC9H,wBAAgB,gBAAgB,CAC9B,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,CAER;AAED,wEAAwE;AACxE,wBAAgB,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,CAE3D;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAiD1F"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* From a test runner's results to run records. A verification's `selector`
|
|
3
|
+
* is matched against each test's full title; no test API is invented for it
|
|
4
|
+
* (no `describe.behavior`). The parsers in node-test.ts and vitest.ts reduce
|
|
5
|
+
* their runner's output to `ParsedRun`, and `toRunRecords` does the rest.
|
|
6
|
+
*/
|
|
7
|
+
import { sha256Hex } from "@intentset/core";
|
|
8
|
+
import { compareStrings } from "../diagnostic.js";
|
|
9
|
+
import { readRunRecords } from "../records.js";
|
|
10
|
+
const SEVERITY = { pass: 0, skip: 1, error: 2, fail: 3 };
|
|
11
|
+
const WORD = /[A-Za-z0-9_-]/;
|
|
12
|
+
/**
|
|
13
|
+
* A selector matches a title when it occurs in it as a whole token: the
|
|
14
|
+
* characters either side are not letters, digits, `_` or `-`. So
|
|
15
|
+
* `schedule-review-v1` matches `schedule [schedule-review-v1] accepts` and a
|
|
16
|
+
* title holding the bracketed tag, but `review-v1` does not match it.
|
|
17
|
+
*/
|
|
18
|
+
export function selectorMatches(selector, title) {
|
|
19
|
+
if (selector === "")
|
|
20
|
+
return false;
|
|
21
|
+
const startsWord = WORD.test(selector[0]);
|
|
22
|
+
const endsWord = WORD.test(selector[selector.length - 1]);
|
|
23
|
+
for (let at = title.indexOf(selector); at !== -1; at = title.indexOf(selector, at + 1)) {
|
|
24
|
+
const before = at === 0 ? "" : title[at - 1];
|
|
25
|
+
const after = title[at + selector.length] ?? "";
|
|
26
|
+
if ((!startsWord || before === "" || !WORD.test(before)) && (!endsWord || after === "" || !WORD.test(after))) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
/** `EV-` and the first 16 hex digits of SHA-256 over the verification ID, commit, graph hash and end time, newline-joined. */
|
|
33
|
+
export function deriveEvidenceId(verificationId, commit, graphHash, finishedAt) {
|
|
34
|
+
return `EV-${sha256Hex([verificationId, commit, graphHash, finishedAt].join("\n")).slice(0, 16)}`;
|
|
35
|
+
}
|
|
36
|
+
/** The worse of two results: fail, then error, then skip, then pass. */
|
|
37
|
+
export function worst(a, b) {
|
|
38
|
+
return SEVERITY[a] >= SEVERITY[b] ? a : b;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* One run record per verification whose selector matched at least one test.
|
|
42
|
+
* Several matching tests make one record with the worst result and a
|
|
43
|
+
* rationale that counts them. Throws when the options would make a malformed
|
|
44
|
+
* record, since that is a caller's mistake rather than evidence.
|
|
45
|
+
*/
|
|
46
|
+
export function toRunRecords(parsed, options) {
|
|
47
|
+
const matched = new Map();
|
|
48
|
+
const unmatched = [];
|
|
49
|
+
for (const selector of [...options.verifications.keys()].sort(compareStrings)) {
|
|
50
|
+
const verificationId = options.verifications.get(selector);
|
|
51
|
+
const hits = parsed.tests.flatMap((test, index) => (selectorMatches(selector, test.fullName) ? [index] : []));
|
|
52
|
+
if (hits.length === 0) {
|
|
53
|
+
unmatched.push(selector);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const entry = matched.get(verificationId) ?? { selectors: new Set(), tests: new Set() };
|
|
57
|
+
entry.selectors.add(selector);
|
|
58
|
+
for (const hit of hits)
|
|
59
|
+
entry.tests.add(hit);
|
|
60
|
+
matched.set(verificationId, entry);
|
|
61
|
+
}
|
|
62
|
+
const records = [];
|
|
63
|
+
for (const verificationId of [...matched.keys()].sort(compareStrings)) {
|
|
64
|
+
const { selectors, tests } = matched.get(verificationId);
|
|
65
|
+
const results = [...tests].sort((a, b) => a - b).map((index) => parsed.tests[index].result);
|
|
66
|
+
const result = results.reduce(worst, "pass");
|
|
67
|
+
const counts = ["pass", "fail", "error", "skip"]
|
|
68
|
+
.map((r) => [r, results.filter((x) => x === r).length])
|
|
69
|
+
.filter(([, n]) => n > 0)
|
|
70
|
+
.map(([r, n]) => `${n} ${r}`)
|
|
71
|
+
.join(", ");
|
|
72
|
+
const names = [...selectors].sort(compareStrings).join(", ");
|
|
73
|
+
records.push({
|
|
74
|
+
evidenceId: deriveEvidenceId(verificationId, options.commit, options.graphHash, options.finishedAt),
|
|
75
|
+
verificationId,
|
|
76
|
+
commit: options.commit,
|
|
77
|
+
graphHash: options.graphHash,
|
|
78
|
+
environment: options.environment,
|
|
79
|
+
scope: { product: options.scope.product, release: options.scope.release },
|
|
80
|
+
tool: { name: options.tool.name, version: options.tool.version },
|
|
81
|
+
reviewer: null,
|
|
82
|
+
startedAt: options.startedAt,
|
|
83
|
+
finishedAt: options.finishedAt,
|
|
84
|
+
result,
|
|
85
|
+
uri: `${options.uriBase}#${encodeURIComponent(verificationId)}`,
|
|
86
|
+
rationale: `${results.length} test${results.length === 1 ? "" : "s"} matched ${names}: ${counts}.`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
const check = readRunRecords(records, "adapter output");
|
|
90
|
+
if (check.diagnostics.length > 0) {
|
|
91
|
+
throw new Error(`toRunRecords was given options that make malformed records: ${check.diagnostics[0].message}`);
|
|
92
|
+
}
|
|
93
|
+
return { records, unmatched };
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=common.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/adapters/common.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-test.d.ts","sourceRoot":"","sources":["../../src/adapters/node-test.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,aAAa,CAAC;AAMzD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAiEpD"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const SUBTEST = /^# Subtest: (.*)$/;
|
|
2
|
+
const TEST_POINT = /^(not ok|ok)\b(?:\s+\d+)?(?:\s+-)?\s*(.*)$/;
|
|
3
|
+
const ASSERTION_CODE = "ERR_ASSERTION";
|
|
4
|
+
export function parseNodeTap(text) {
|
|
5
|
+
const lines = text.split(/\r?\n/);
|
|
6
|
+
const titles = [];
|
|
7
|
+
const hasChild = [];
|
|
8
|
+
const tests = [];
|
|
9
|
+
const problems = [];
|
|
10
|
+
let i = 0;
|
|
11
|
+
while (i < lines.length) {
|
|
12
|
+
const line = lines[i];
|
|
13
|
+
const indent = line.length - line.trimStart().length;
|
|
14
|
+
const body = line.slice(indent);
|
|
15
|
+
const depth = Math.floor(indent / 4);
|
|
16
|
+
const subtest = SUBTEST.exec(body);
|
|
17
|
+
if (subtest !== null) {
|
|
18
|
+
titles[depth] = unescapeTap(subtest[1]);
|
|
19
|
+
titles.length = depth + 1;
|
|
20
|
+
hasChild[depth] = false;
|
|
21
|
+
hasChild.length = depth + 1;
|
|
22
|
+
i++;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const point = TEST_POINT.exec(body);
|
|
26
|
+
if (point === null) {
|
|
27
|
+
if (body.startsWith("Bail out!"))
|
|
28
|
+
problems.push(body);
|
|
29
|
+
i++;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
i++;
|
|
33
|
+
const yaml = new Map();
|
|
34
|
+
if (i < lines.length && lines[i].trim() === "---") {
|
|
35
|
+
const blockIndent = lines[i].length - lines[i].trimStart().length;
|
|
36
|
+
i++;
|
|
37
|
+
while (i < lines.length) {
|
|
38
|
+
const current = lines[i];
|
|
39
|
+
const currentIndent = current.length - current.trimStart().length;
|
|
40
|
+
i++;
|
|
41
|
+
if (current.trim() === "..." && currentIndent === blockIndent)
|
|
42
|
+
break;
|
|
43
|
+
if (currentIndent !== blockIndent)
|
|
44
|
+
continue;
|
|
45
|
+
const pair = /^([A-Za-z_][A-Za-z0-9_]*):(?:\s+(.*))?$/.exec(current.slice(blockIndent));
|
|
46
|
+
if (pair !== null)
|
|
47
|
+
yaml.set(pair[1], unquote(pair[2] ?? ""));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const { title, directive } = splitDirective(point[2]);
|
|
51
|
+
const parent = hasChild[depth] === true;
|
|
52
|
+
hasChild[depth] = false;
|
|
53
|
+
if (depth > 0)
|
|
54
|
+
hasChild[depth - 1] = true;
|
|
55
|
+
const failureType = yaml.get("failureType");
|
|
56
|
+
const result = resultOf(point[1] === "ok", directive, failureType, yaml);
|
|
57
|
+
if (parent && (result === "pass" || result === "skip" || failureType === "subtestsFailed"))
|
|
58
|
+
continue;
|
|
59
|
+
const ancestors = titles.slice(0, depth).filter((t) => t !== undefined);
|
|
60
|
+
const duration = Number(yaml.get("duration_ms"));
|
|
61
|
+
tests.push({
|
|
62
|
+
fullName: [...ancestors, title].join(" > "),
|
|
63
|
+
result,
|
|
64
|
+
durationMs: yaml.has("duration_ms") && Number.isFinite(duration) ? duration : null,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return { tests, problems };
|
|
68
|
+
}
|
|
69
|
+
function resultOf(ok, directive, failureType, yaml) {
|
|
70
|
+
if (directive !== null)
|
|
71
|
+
return "skip";
|
|
72
|
+
if (ok)
|
|
73
|
+
return "pass";
|
|
74
|
+
if (failureType === "subtestsFailed")
|
|
75
|
+
return "fail";
|
|
76
|
+
const assertion = yaml.get("code") === ASSERTION_CODE || yaml.get("name") === "AssertionError";
|
|
77
|
+
if (assertion)
|
|
78
|
+
return "fail";
|
|
79
|
+
if (failureType === undefined)
|
|
80
|
+
return "fail";
|
|
81
|
+
return "error";
|
|
82
|
+
}
|
|
83
|
+
/** Split a test point's description at its first unescaped `#` into the title and the directive. */
|
|
84
|
+
function splitDirective(description) {
|
|
85
|
+
for (let i = 0; i < description.length; i++) {
|
|
86
|
+
const c = description[i];
|
|
87
|
+
if (c === "\\") {
|
|
88
|
+
i++;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (c !== "#")
|
|
92
|
+
continue;
|
|
93
|
+
const rest = description.slice(i + 1).trim();
|
|
94
|
+
const directive = /^skip\b/i.test(rest) ? "skip" : /^todo\b/i.test(rest) ? "todo" : null;
|
|
95
|
+
return { title: unescapeTap(description.slice(0, i).trimEnd()), directive };
|
|
96
|
+
}
|
|
97
|
+
return { title: unescapeTap(description.trimEnd()), directive: null };
|
|
98
|
+
}
|
|
99
|
+
const ESCAPES = { b: "\b", f: "\f", n: "\n", r: "\r", t: "\t", v: "\v" };
|
|
100
|
+
/** Undo Node's TAP escaping: `\\`, `\#` and the control-character escapes. */
|
|
101
|
+
function unescapeTap(text) {
|
|
102
|
+
return text.replace(/\\(.)/g, (_, c) => ESCAPES[c] ?? c);
|
|
103
|
+
}
|
|
104
|
+
function unquote(value) {
|
|
105
|
+
const trimmed = value.trim();
|
|
106
|
+
if (trimmed.length >= 2 && trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
107
|
+
return trimmed.slice(1, -1).replace(/''/g, "'");
|
|
108
|
+
}
|
|
109
|
+
if (trimmed.length >= 2 && trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
|
110
|
+
try {
|
|
111
|
+
return JSON.parse(trimmed);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return trimmed.slice(1, -1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return trimmed;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=node-test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-test.js","sourceRoot":"","sources":["../../src/adapters/node-test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest.d.ts","sourceRoot":"","sources":["../../src/adapters/vitest.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,aAAa,CAAC;AAWzD,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,CA4CxD"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const STATUSES = {
|
|
2
|
+
passed: "pass",
|
|
3
|
+
failed: "failed",
|
|
4
|
+
skipped: "skip",
|
|
5
|
+
pending: "skip",
|
|
6
|
+
todo: "skip",
|
|
7
|
+
disabled: "skip",
|
|
8
|
+
};
|
|
9
|
+
export function parseVitestJson(json) {
|
|
10
|
+
if (!isRecord(json) || !Array.isArray(json.testResults)) {
|
|
11
|
+
throw new TypeError("This is not Vitest JSON reporter output: expected an object with a testResults array.");
|
|
12
|
+
}
|
|
13
|
+
const tests = [];
|
|
14
|
+
const problems = [];
|
|
15
|
+
json.testResults.forEach((file, fileIndex) => {
|
|
16
|
+
if (!isRecord(file))
|
|
17
|
+
throw new TypeError(`testResults[${fileIndex}] is not an object.`);
|
|
18
|
+
const name = typeof file.name === "string" ? file.name : `testResults[${fileIndex}]`;
|
|
19
|
+
const assertions = Array.isArray(file.assertionResults) ? file.assertionResults : [];
|
|
20
|
+
if (assertions.length === 0 && file.status === "failed") {
|
|
21
|
+
problems.push(`${name} failed without running a test: ${firstLine(file.message) || "no message"}`);
|
|
22
|
+
}
|
|
23
|
+
assertions.forEach((assertion, index) => {
|
|
24
|
+
if (!isRecord(assertion))
|
|
25
|
+
throw new TypeError(`testResults[${fileIndex}].assertionResults[${index}] is not an object.`);
|
|
26
|
+
const title = typeof assertion.title === "string" ? assertion.title : "";
|
|
27
|
+
const ancestors = Array.isArray(assertion.ancestorTitles)
|
|
28
|
+
? assertion.ancestorTitles.filter((t) => typeof t === "string")
|
|
29
|
+
: [];
|
|
30
|
+
const fullName = typeof assertion.fullName === "string" && assertion.fullName !== ""
|
|
31
|
+
? assertion.fullName
|
|
32
|
+
: [...ancestors, title].join(" > ");
|
|
33
|
+
const status = typeof assertion.status === "string" ? STATUSES[assertion.status] : undefined;
|
|
34
|
+
let result;
|
|
35
|
+
if (status === undefined) {
|
|
36
|
+
problems.push(`${fullName} has the unknown status ${JSON.stringify(assertion.status)}, read as error`);
|
|
37
|
+
result = "error";
|
|
38
|
+
}
|
|
39
|
+
else if (status === "failed") {
|
|
40
|
+
const messages = Array.isArray(assertion.failureMessages) ? assertion.failureMessages : [];
|
|
41
|
+
result = failureKind(typeof messages[0] === "string" ? messages[0] : "");
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
result = status;
|
|
45
|
+
}
|
|
46
|
+
const duration = assertion.duration;
|
|
47
|
+
tests.push({
|
|
48
|
+
fullName,
|
|
49
|
+
result,
|
|
50
|
+
durationMs: typeof duration === "number" && Number.isFinite(duration) ? duration : null,
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
return { tests, problems };
|
|
55
|
+
}
|
|
56
|
+
/** An assertion failure is fail; any other thrown error class is error; a bare message is a failed expectation. */
|
|
57
|
+
function failureKind(message) {
|
|
58
|
+
const head = message.trimStart();
|
|
59
|
+
if (/^AssertionError\b/.test(head))
|
|
60
|
+
return "fail";
|
|
61
|
+
if (/^[A-Za-z]*Error\b/.test(head))
|
|
62
|
+
return "error";
|
|
63
|
+
return "fail";
|
|
64
|
+
}
|
|
65
|
+
function firstLine(value) {
|
|
66
|
+
return typeof value === "string" ? (value.trim().split("\n")[0] ?? "") : "";
|
|
67
|
+
}
|
|
68
|
+
function isRecord(value) {
|
|
69
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=vitest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest.js","sourceRoot":"","sources":["../../src/adapters/vitest.ts"],"names":[],"mappings":"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"}
|
package/dist/check.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The evidence check (Core §8, §11): classification, coverage, and the
|
|
3
|
+
* diagnostics that follow from them. CORE007 joins at L3, where current
|
|
4
|
+
* passing evidence is a conformance requirement; below L3 missing evidence is
|
|
5
|
+
* not a diagnostic, but the coverage report still shows every gap.
|
|
6
|
+
*/
|
|
7
|
+
import { type Diagnostic, type Graph, type Level } from "@intentset/core";
|
|
8
|
+
import { type Classification, type EvidenceSnapshot } from "./classify.ts";
|
|
9
|
+
import { type CoverageReport } from "./coverage.ts";
|
|
10
|
+
import type { RunRecord } from "./records.ts";
|
|
11
|
+
export interface CheckEvidenceOptions {
|
|
12
|
+
level?: Level;
|
|
13
|
+
/**
|
|
14
|
+
* Every repository-relative path in the tree. When given, each
|
|
15
|
+
* verification's locator must name one of them (EVID003); when absent the
|
|
16
|
+
* locators are not checked and each is listed as unresolved.
|
|
17
|
+
*/
|
|
18
|
+
files?: ReadonlySet<string>;
|
|
19
|
+
/** The file the records were read from, for diagnostics about a record. */
|
|
20
|
+
evidencePath?: string | null;
|
|
21
|
+
}
|
|
22
|
+
export interface EvidenceCheck {
|
|
23
|
+
/**
|
|
24
|
+
* EVID001 (graph-aware), EVID002, EVID003 and, at L3 and above, CORE007 (an
|
|
25
|
+
* error for a required claim, a warning for a draft claim with no
|
|
26
|
+
* verification definition); sorted, origin "evidence".
|
|
27
|
+
*/
|
|
28
|
+
diagnostics: Diagnostic[];
|
|
29
|
+
classification: Classification;
|
|
30
|
+
coverage: CoverageReport;
|
|
31
|
+
}
|
|
32
|
+
export declare function checkEvidence(graph: Graph, records: readonly RunRecord[], snapshot: EvidenceSnapshot, options?: CheckEvidenceOptions): EvidenceCheck;
|
|
33
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,KAAK,EAAE,KAAK,KAAK,EAA2B,MAAM,iBAAiB,CAAC;AACnG,OAAO,EAAE,KAAK,cAAc,EAAoB,KAAK,gBAAgB,EAAuB,MAAM,eAAe,CAAC;AAClH,OAAO,EAAE,KAAK,cAAc,EAA+B,MAAM,eAAe,CAAC;AAEjF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;;;OAIG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5B,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAYD,wBAAgB,aAAa,CAC3B,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,SAAS,SAAS,EAAE,EAC7B,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,GAAE,oBAAyB,GACjC,aAAa,CAkFf"}
|
package/dist/check.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The evidence check (Core §8, §11): classification, coverage, and the
|
|
3
|
+
* diagnostics that follow from them. CORE007 joins at L3, where current
|
|
4
|
+
* passing evidence is a conformance requirement; below L3 missing evidence is
|
|
5
|
+
* not a diagnostic, but the coverage report still shows every gap.
|
|
6
|
+
*/
|
|
7
|
+
import { LEVELS, sortDiagnostics } from "@intentset/core";
|
|
8
|
+
import { classifyEvidence } from "./classify.js";
|
|
9
|
+
import { compareUnresolved, coverage } from "./coverage.js";
|
|
10
|
+
import { compareStrings, evidenceDiagnostic } from "./diagnostic.js";
|
|
11
|
+
const PHRASES = {
|
|
12
|
+
"current-pass": "passed at this snapshot",
|
|
13
|
+
"current-fail": "failed at this snapshot",
|
|
14
|
+
stale: "is stale, with runs only at another commit or graph hash",
|
|
15
|
+
skip: "was skipped at this snapshot",
|
|
16
|
+
error: "errored at this snapshot",
|
|
17
|
+
missing: "has no run record",
|
|
18
|
+
unresolved: "could not be classified",
|
|
19
|
+
};
|
|
20
|
+
export function checkEvidence(graph, records, snapshot, options = {}) {
|
|
21
|
+
const level = options.level ?? "L1";
|
|
22
|
+
const classification = classifyEvidence(graph, records, snapshot, { evidencePath: options.evidencePath ?? null });
|
|
23
|
+
const report = coverage(graph, classification, { level });
|
|
24
|
+
const diagnostics = [...classification.diagnostics];
|
|
25
|
+
for (const id of Object.keys(classification.verifications)) {
|
|
26
|
+
const artifact = graph.artifacts.get(id);
|
|
27
|
+
const locator = artifact?.meta.verification?.locator;
|
|
28
|
+
if (artifact === undefined || locator === undefined || artifact.meta.status === "retired")
|
|
29
|
+
continue;
|
|
30
|
+
if (options.files === undefined) {
|
|
31
|
+
report.unresolved.push({ subject: id, reason: `locator ${locator} not checked: no file tree was supplied` });
|
|
32
|
+
}
|
|
33
|
+
else if (!options.files.has(locator)) {
|
|
34
|
+
diagnostics.push(evidenceDiagnostic({
|
|
35
|
+
code: "EVID003",
|
|
36
|
+
severity: "warning",
|
|
37
|
+
artifact: id,
|
|
38
|
+
path: artifact.path,
|
|
39
|
+
field: "/intentset/verification/locator",
|
|
40
|
+
message: `Verification ${id} names the locator ${locator}, which is not a file in the repository tree.`,
|
|
41
|
+
remediation: "Correct the locator to the repository-relative path of the test or review procedure, or add the file.",
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
report.unresolved.sort(compareUnresolved);
|
|
46
|
+
if (LEVELS.indexOf(level) >= LEVELS.indexOf("L3")) {
|
|
47
|
+
for (const claim of report.perClaim) {
|
|
48
|
+
// A draft claim is not required yet, but one with no verification at all
|
|
49
|
+
// is a gap CI output should show (decided 2026-10-03, after the Streamlane
|
|
50
|
+
// pilot reported nothing at L3 while two rules had no test): a warning,
|
|
51
|
+
// never an error, and only for a missing definition, not a missing run.
|
|
52
|
+
if (!claim.required && claim.lifecycle === "draft" && claim.verifications.length === 0) {
|
|
53
|
+
diagnostics.push(evidenceDiagnostic({
|
|
54
|
+
code: "CORE007",
|
|
55
|
+
severity: "warning",
|
|
56
|
+
artifact: claim.id,
|
|
57
|
+
path: claim.path,
|
|
58
|
+
message: `Draft ${claim.type} ${claim.id} has no verification definition naming it in verifies; it is not required while draft, and will fail L3 once approved.`,
|
|
59
|
+
remediation: `Add a verification whose links.verifies names ${claim.id} before the claim leaves draft (Core §8).`,
|
|
60
|
+
}));
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (!claim.required || claim.verified)
|
|
64
|
+
continue;
|
|
65
|
+
const subject = `${capitalize(claim.lifecycle)} ${claim.type} ${claim.id}`;
|
|
66
|
+
if (claim.verifications.length === 0) {
|
|
67
|
+
diagnostics.push(evidenceDiagnostic({
|
|
68
|
+
code: "CORE007",
|
|
69
|
+
artifact: claim.id,
|
|
70
|
+
path: claim.path,
|
|
71
|
+
message: `${subject} has no verification definition naming it in verifies, so it cannot be verified in this snapshot.`,
|
|
72
|
+
remediation: `Add a verification whose links.verifies names ${claim.id}, then record a passing run at the snapshot (Core §8).`,
|
|
73
|
+
}));
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const failing = claim.verifications.filter((v) => v.status !== "current-pass");
|
|
77
|
+
const where = `commit ${snapshot.commit ?? "(unknown)"} and graph hash ${snapshot.graphHash.slice(0, 12)}`;
|
|
78
|
+
diagnostics.push(evidenceDiagnostic({
|
|
79
|
+
code: "CORE007",
|
|
80
|
+
artifact: claim.id,
|
|
81
|
+
path: claim.path,
|
|
82
|
+
message: `${subject} is not verified in this snapshot: ${failing.map((v) => `${v.id} ${PHRASES[v.status]}`).join("; ")}.`,
|
|
83
|
+
remediation: `Record a passing run of ${failing
|
|
84
|
+
.map((v) => v.id)
|
|
85
|
+
.sort(compareStrings)
|
|
86
|
+
.join(", ")} at ${where}, fixing whatever failed first; stale, skipped and errored runs never count (Core §8).`,
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return { diagnostics: sortDiagnostics(diagnostics), classification, coverage: report };
|
|
91
|
+
}
|
|
92
|
+
function capitalize(text) {
|
|
93
|
+
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evidence freshness (Core §8, invariant 3). Only a `pass` at the assessed
|
|
3
|
+
* commit and graph hash is current; everything else is something else, and
|
|
4
|
+
* says which. A failing run at the snapshot stays visible however many older
|
|
5
|
+
* passes there are, because the status is decided by the latest run at the
|
|
6
|
+
* snapshot and every run is kept in the history.
|
|
7
|
+
*/
|
|
8
|
+
import { type Diagnostic, type Graph } from "@intentset/core";
|
|
9
|
+
import { type RunRecord, type RunResult, type RunScope } from "./records.ts";
|
|
10
|
+
export declare const EVIDENCE_STATUSES: readonly ["current-pass", "current-fail", "stale", "skip", "error", "missing", "unresolved"];
|
|
11
|
+
export type EvidenceStatus = (typeof EVIDENCE_STATUSES)[number];
|
|
12
|
+
/** What evidence is assessed against: a commit and graph hash, and the product and release it is for. */
|
|
13
|
+
export interface EvidenceSnapshot {
|
|
14
|
+
/** The assessed commit, or null when none could be read: matching then uses the graph hash alone, and says so. */
|
|
15
|
+
commit: string | null;
|
|
16
|
+
/** The graph hash of the snapshot (ADR 0005). */
|
|
17
|
+
graphHash: string;
|
|
18
|
+
/** The exact product and release under assessment. Absent or null considers records of every scope, and reports that it did. */
|
|
19
|
+
scope?: RunScope | null;
|
|
20
|
+
}
|
|
21
|
+
export type ResultCounts = Record<RunResult, number>;
|
|
22
|
+
export interface VerificationEvidence {
|
|
23
|
+
verificationId: string;
|
|
24
|
+
method: "automated" | "manual";
|
|
25
|
+
status: EvidenceStatus;
|
|
26
|
+
/** Why the status is qualified or what was set aside, when anything was. */
|
|
27
|
+
note?: string;
|
|
28
|
+
/** The record that decided the status: the latest at the snapshot, else the latest in scope; null when there is none. */
|
|
29
|
+
latest: RunRecord | null;
|
|
30
|
+
/** Every in-scope record for this verification, oldest first (finishedAt, then evidenceId). */
|
|
31
|
+
history: RunRecord[];
|
|
32
|
+
/** Results of the records at the snapshot, so a failure followed by a pass is still countable. */
|
|
33
|
+
atSnapshot: ResultCounts;
|
|
34
|
+
/** Records for this verification that named another product or release and were not considered. */
|
|
35
|
+
outOfScope: number;
|
|
36
|
+
}
|
|
37
|
+
export interface RejectedRecord {
|
|
38
|
+
record: RunRecord;
|
|
39
|
+
reason: string;
|
|
40
|
+
}
|
|
41
|
+
export interface Classification {
|
|
42
|
+
snapshot: {
|
|
43
|
+
commit: string | null;
|
|
44
|
+
graphHash: string;
|
|
45
|
+
scope: RunScope | null;
|
|
46
|
+
};
|
|
47
|
+
/** One entry per verification artifact in the graph, keyed and ordered by ID. */
|
|
48
|
+
verifications: Record<string, VerificationEvidence>;
|
|
49
|
+
/** Records whose scope named another product or release, across every verification. */
|
|
50
|
+
ignoredOutOfScope: number;
|
|
51
|
+
/** Records naming an ID that is not a verification in the graph (EVID002), by evidence ID. */
|
|
52
|
+
unknown: RunRecord[];
|
|
53
|
+
/** Records that cannot be evidence for the verification they name (EVID001), by evidence ID. */
|
|
54
|
+
rejected: RejectedRecord[];
|
|
55
|
+
/** EVID001 and EVID002, sorted. */
|
|
56
|
+
diagnostics: Diagnostic[];
|
|
57
|
+
}
|
|
58
|
+
export interface ClassifyOptions {
|
|
59
|
+
/** The file the records were read from, for diagnostics; null when they did not come from one. */
|
|
60
|
+
evidencePath?: string | null;
|
|
61
|
+
}
|
|
62
|
+
/** Core §8: classify every verification in the graph against the snapshot. Deterministic for identical inputs. */
|
|
63
|
+
export declare function classifyEvidence(graph: Graph, records: readonly RunRecord[], snapshot: EvidenceSnapshot, options?: ClassifyOptions): Classification;
|
|
64
|
+
/** True when a record was made at the snapshot: same graph hash, and same commit unless the snapshot's is unknown. */
|
|
65
|
+
export declare function atSnapshot(record: RunRecord, snapshot: {
|
|
66
|
+
commit: string | null;
|
|
67
|
+
graphHash: string;
|
|
68
|
+
}): boolean;
|
|
69
|
+
//# sourceMappingURL=classify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../src/classify.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,KAAK,EAAmB,MAAM,iBAAiB,CAAC;AAE/E,OAAO,EAA2B,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEtG,eAAO,MAAM,iBAAiB,YAC5B,cAAc,EACd,cAAc,EACd,OAAO,EACP,MAAM,EACN,OAAO,EACP,SAAS,EACT,YAAY,CACJ,CAAC;AACX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE,yGAAyG;AACzG,MAAM,WAAW,gBAAgB;IAC/B,kHAAkH;IAClH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,gIAAgI;IAChI,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAErD,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yHAAyH;IACzH,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,+FAA+F;IAC/F,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,kGAAkG;IAClG,UAAU,EAAE,YAAY,CAAC;IACzB,mGAAmG;IACnG,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE;QAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAA;KAAE,CAAC;IAC/E,iFAAiF;IACjF,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IACpD,uFAAuF;IACvF,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8FAA8F;IAC9F,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,gGAAgG;IAChG,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,mCAAmC;IACnC,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,kGAAkG;IAClG,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAID,kHAAkH;AAClH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,SAAS,SAAS,EAAE,EAC7B,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,GAAE,eAAoB,GAC5B,cAAc,CAgFhB;AAED,sHAAsH;AACtH,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAE7G"}
|