supercov 0.0.43 → 0.0.45
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/README.md +23 -14
- package/docs/agent-loop.md +128 -39
- package/docs/assertion-agent.md +156 -0
- package/docs/assertion-evidence.md +9 -135
- package/docs/assertion-maps.md +252 -0
- package/docs/assertions.md +82 -0
- package/docs/cli.md +38 -23
- package/docs/coverage-model.md +18 -6
- package/docs/evidence.md +6 -6
- package/docs/getting-started.md +60 -72
- package/docs/performance.md +4 -4
- package/docs/troubleshooting.md +8 -8
- package/docs/verification.md +2 -2
- package/docs/workspace-isolation.md +1 -1
- package/package.json +34 -33
- package/runtime/javascript/nodeAssertAdapter.mjs +32 -8
- package/runtime/javascript/nodeTest.mjs +13 -5
- package/runtime/javascript/runnerEvidence.mjs +33 -11
- package/runtime/javascript/runtime.mjs +27 -23
- package/schemas/assertions.schema.json +276 -0
- package/analyzers/typescript/README.md +0 -55
- package/analyzers/typescript/bin/compiler-identity.mjs +0 -78
- package/analyzers/typescript/bin/identity.mjs +0 -67
- package/analyzers/typescript/bin/query.mjs +0 -29
- package/analyzers/typescript/dist/analyze.js +0 -3972
- package/analyzers/typescript/dist/archive.js +0 -309
- package/analyzers/typescript/dist/build-identity.json +0 -1
- package/analyzers/typescript/dist/compiler.js +0 -32
- package/analyzers/typescript/dist/frontend.js +0 -75
- package/analyzers/typescript/dist/native-frontend.js +0 -271
- package/analyzers/typescript/dist/pragmas.js +0 -143
- package/analyzers/typescript/dist/types.js +0 -1
- package/analyzers/typescript/package.json +0 -27
- package/analyzers/typescript/src/analyze.ts +0 -4538
- package/analyzers/typescript/src/archive.ts +0 -438
- package/analyzers/typescript/src/compiler.ts +0 -49
- package/analyzers/typescript/src/frontend.ts +0 -136
- package/analyzers/typescript/src/native-frontend.ts +0 -315
- package/analyzers/typescript/src/pragmas.ts +0 -218
- package/analyzers/typescript/src/types.ts +0 -45
- package/analyzers/typescript/tsconfig.json +0 -12
- package/docs/code-verification.md +0 -182
|
@@ -27,13 +27,24 @@ function localFile(file) {
|
|
|
27
27
|
return relative(process.cwd(), absolute).split(sep).join("/");
|
|
28
28
|
}
|
|
29
29
|
export function runnerTestId(identity) {
|
|
30
|
-
const
|
|
30
|
+
const parts = [
|
|
31
31
|
identity.runner,
|
|
32
32
|
localFile(identity.file) ?? "unknown",
|
|
33
33
|
identity.line ?? 0,
|
|
34
34
|
identity.column ?? 0,
|
|
35
35
|
identity.name,
|
|
36
|
-
]
|
|
36
|
+
];
|
|
37
|
+
// Preserve existing top-level, uniquely registered test IDs. Nested tests
|
|
38
|
+
// and repeated registrations need more than a shared source/name identity.
|
|
39
|
+
if (identity.parentTestId)
|
|
40
|
+
parts.push("parent", identity.parentTestId);
|
|
41
|
+
if (identity.registrationOrdinal)
|
|
42
|
+
parts.push("registration", identity.registrationOrdinal);
|
|
43
|
+
// Titles can themselves contain separator text. Domain-separate and encode
|
|
44
|
+
// the extended identity structurally so it cannot alias a literal title.
|
|
45
|
+
const key = identity.parentTestId || identity.registrationOrdinal
|
|
46
|
+
? JSON.stringify(["registration-v2", ...parts])
|
|
47
|
+
: parts.join("\0");
|
|
37
48
|
return `${identity.runner}:${createHash("sha256").update(key).digest("hex").slice(0, 24)}`;
|
|
38
49
|
}
|
|
39
50
|
export function runnerExecutionScope(identity) {
|
|
@@ -50,24 +61,35 @@ export function runnerExecutionScope(identity) {
|
|
|
50
61
|
testId,
|
|
51
62
|
testKey,
|
|
52
63
|
retry,
|
|
53
|
-
|
|
64
|
+
// Different processes/worker threads can execute the same registration.
|
|
65
|
+
// Their files must not collide even though the stable test ID is shared.
|
|
66
|
+
attemptId: `${testKey}-${retry}-${processInstanceToken()}`,
|
|
54
67
|
};
|
|
55
68
|
}
|
|
56
|
-
export function callerLocation(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
69
|
+
export function callerLocation(boundary = callerLocation) {
|
|
70
|
+
// Omit the registration wrapper by identity. A user file may have the same
|
|
71
|
+
// basename as a runtime adapter. Parse the location suffix, not individual
|
|
72
|
+
// path segments: spaces, parentheses and Unicode are valid filenames.
|
|
73
|
+
try {
|
|
74
|
+
const error = {};
|
|
75
|
+
Error.captureStackTrace(error, boundary);
|
|
76
|
+
if (typeof error.stack !== "string")
|
|
77
|
+
return {};
|
|
78
|
+
const entry = error.stack.split("\n")[1]?.trim();
|
|
79
|
+
const match = entry && /(?:^at (?:async )?| \()((?:file:\/\/|\/|[A-Za-z]:[\\/]|\\\\).*):(\d+):(\d+)\)?$/.exec(entry);
|
|
62
80
|
if (!match)
|
|
63
|
-
|
|
81
|
+
return {};
|
|
64
82
|
return {
|
|
65
83
|
file: match[1],
|
|
66
84
|
line: Number(match[2]),
|
|
67
85
|
column: Number(match[3]),
|
|
68
86
|
};
|
|
69
87
|
}
|
|
70
|
-
|
|
88
|
+
catch {
|
|
89
|
+
// Custom formatters must not prevent registration. Missing provenance
|
|
90
|
+
// is explicit, never replaced with an unrelated deeper caller.
|
|
91
|
+
return {};
|
|
92
|
+
}
|
|
71
93
|
}
|
|
72
94
|
export function readScopedServerEvidence(scope, evidencePath = serverEvidencePath(scope)) {
|
|
73
95
|
try {
|
|
@@ -144,9 +144,6 @@ function createState() {
|
|
|
144
144
|
decisions: /* @__PURE__ */ new Map(),
|
|
145
145
|
hits: /* @__PURE__ */ new Set(),
|
|
146
146
|
events: [],
|
|
147
|
-
// Position of the test-file statement currently executing ("file:line:column"), set by the
|
|
148
|
-
// instrumented test module; production hits recorded meanwhile are attributed to it.
|
|
149
|
-
testStatement: void 0,
|
|
150
147
|
// Per value-position logical expression (`a && b`, `a || b`, `a ?? b`): the distinct
|
|
151
148
|
// (right operand evaluated?, result truthy?) pairs seen, keyed by branch id.
|
|
152
149
|
logicals: /* @__PURE__ */ new Map(),
|
|
@@ -317,7 +314,6 @@ function resetCoverage(testId2) {
|
|
|
317
314
|
state.decisions.clear();
|
|
318
315
|
state.hits.clear();
|
|
319
316
|
state.events.length = 0;
|
|
320
|
-
state.testStatement = void 0;
|
|
321
317
|
state.logicals.clear();
|
|
322
318
|
state.eventKeys.clear();
|
|
323
319
|
state.probeV2ContextEpochs.clear();
|
|
@@ -721,9 +717,11 @@ function withCoverageCarrier(carrier, callback) {
|
|
|
721
717
|
function assertionPhaseState(scope) {
|
|
722
718
|
const key = attemptKey(scope);
|
|
723
719
|
const existing = state.assertionPhases.get(key);
|
|
724
|
-
if (existing)
|
|
720
|
+
if (existing) {
|
|
721
|
+
existing.phaseIds ??= new Set(existing.phases.filter(phase => phase.kind === "assertion").map(phase => phase.id));
|
|
725
722
|
return existing;
|
|
726
|
-
|
|
723
|
+
}
|
|
724
|
+
const created = { counter: 0, phases: [], phaseIds: new Set() };
|
|
727
725
|
state.assertionPhases.set(key, created);
|
|
728
726
|
return created;
|
|
729
727
|
}
|
|
@@ -753,9 +751,13 @@ function withNodeAssertionPhase(operation, source, callback) {
|
|
|
753
751
|
const scope = context.scope;
|
|
754
752
|
if (!scope)
|
|
755
753
|
return callback();
|
|
756
|
-
const existing = context.phaseId
|
|
754
|
+
const existing = context.phaseId && assertionPhaseState(scope).phaseIds.has(context.phaseId);
|
|
757
755
|
if (existing)
|
|
758
756
|
return callback();
|
|
757
|
+
// A lexical occurrence already identifies its source. Stack fallback is lazy
|
|
758
|
+
// and qualified so transformed coordinates cannot impersonate original ones.
|
|
759
|
+
if (typeof source === "function")
|
|
760
|
+
source = source();
|
|
759
761
|
const bridged = (_a8 = runtimeGlobal.__SUPERCOV_ASSERTION_PHASE_BRIDGE__) == null ? void 0 : _a8.call(runtimeGlobal, operation, source, callback);
|
|
760
762
|
if (bridged == null ? void 0 : bridged.handled)
|
|
761
763
|
return bridged.value;
|
|
@@ -768,6 +770,7 @@ function withNodeAssertionPhase(operation, source, callback) {
|
|
|
768
770
|
startedAtMs: Date.now()
|
|
769
771
|
});
|
|
770
772
|
attempt.phases.push(phase);
|
|
773
|
+
attempt.phaseIds.add(phase.id);
|
|
771
774
|
try {
|
|
772
775
|
const result = withCoverageCarrier({ version: 1, scope, phaseId: phase.id }, callback);
|
|
773
776
|
if (result && typeof result.then === "function")
|
|
@@ -785,6 +788,13 @@ function withNodeAssertionPhase(operation, source, callback) {
|
|
|
785
788
|
throw cleanInstrumentationStack(error);
|
|
786
789
|
}
|
|
787
790
|
}
|
|
791
|
+
// Callee binding preserves receiver, getter/evaluation order, spreads and the
|
|
792
|
+
// original await/yield placement. Only the matcher call opens the phase.
|
|
793
|
+
function bindNodeAssertionPhase(operation, source, target, property = null) {
|
|
794
|
+
const callback = property === null ? target : target[property];
|
|
795
|
+
const receiver = property === null ? undefined : target;
|
|
796
|
+
return (...args) => withNodeAssertionPhase(operation, source, () => Reflect.apply(callback, receiver, args));
|
|
797
|
+
}
|
|
788
798
|
function takeNodeAssertionPhases(scope) {
|
|
789
799
|
var _a8, _b;
|
|
790
800
|
const key = attemptKey(scope);
|
|
@@ -978,31 +988,25 @@ function recordBrowserEvent(event) {
|
|
|
978
988
|
state.events.push(event);
|
|
979
989
|
return true;
|
|
980
990
|
}
|
|
981
|
-
function testStatement(source) {
|
|
982
|
-
state.testStatement = typeof source === "string" && source.length > 0 ? source : void 0;
|
|
983
|
-
}
|
|
984
|
-
function statementFields() {
|
|
985
|
-
return state.testStatement ? { statementId: state.testStatement } : {};
|
|
986
|
-
}
|
|
987
991
|
function coverageHit(id) {
|
|
988
992
|
state.hits.add(id);
|
|
989
993
|
const timestampMs = Date.now();
|
|
990
994
|
const phaseId = currentPhaseId();
|
|
991
995
|
if (isBrowser) {
|
|
992
|
-
if (recordBrowserEvent(__spreadProps(__spreadValues(
|
|
996
|
+
if (recordBrowserEvent(__spreadProps(__spreadValues({
|
|
993
997
|
type: "hit",
|
|
994
998
|
id,
|
|
995
999
|
timestampMs
|
|
996
|
-
}, phaseId ? { phaseId } : {}),
|
|
1000
|
+
}, phaseId ? { phaseId } : {}), {
|
|
997
1001
|
environment: "browser"
|
|
998
1002
|
})))
|
|
999
1003
|
persistBrowser();
|
|
1000
1004
|
} else {
|
|
1001
|
-
appendServer(__spreadValues(
|
|
1005
|
+
appendServer(__spreadValues({
|
|
1002
1006
|
type: "hit",
|
|
1003
1007
|
id,
|
|
1004
1008
|
timestampMs
|
|
1005
|
-
}, phaseId ? { phaseId } : {})
|
|
1009
|
+
}, phaseId ? { phaseId } : {}));
|
|
1006
1010
|
}
|
|
1007
1011
|
}
|
|
1008
1012
|
function registerProbeV2(definition) {
|
|
@@ -1237,22 +1241,22 @@ function mcdcEnd(frame, value) {
|
|
|
1237
1241
|
const timestampMs = Date.now();
|
|
1238
1242
|
const phaseId = currentPhaseId();
|
|
1239
1243
|
if (isBrowser) {
|
|
1240
|
-
if (recordBrowserEvent(__spreadProps(__spreadValues(
|
|
1244
|
+
if (recordBrowserEvent(__spreadProps(__spreadValues({
|
|
1241
1245
|
type: "decision",
|
|
1242
1246
|
id: decision.meta.id,
|
|
1243
1247
|
vector,
|
|
1244
1248
|
timestampMs
|
|
1245
|
-
}, phaseId ? { phaseId } : {}),
|
|
1249
|
+
}, phaseId ? { phaseId } : {}), {
|
|
1246
1250
|
environment: "browser"
|
|
1247
1251
|
})))
|
|
1248
1252
|
persistBrowser();
|
|
1249
1253
|
} else {
|
|
1250
|
-
appendServer(__spreadValues(
|
|
1254
|
+
appendServer(__spreadValues({
|
|
1251
1255
|
type: "decision",
|
|
1252
1256
|
meta: decision.meta,
|
|
1253
1257
|
vector,
|
|
1254
1258
|
timestampMs
|
|
1255
|
-
}, phaseId ? { phaseId } : {})
|
|
1259
|
+
}, phaseId ? { phaseId } : {}));
|
|
1256
1260
|
}
|
|
1257
1261
|
return value;
|
|
1258
1262
|
}
|
|
@@ -1293,12 +1297,12 @@ const directRuntimeApi = {
|
|
|
1293
1297
|
selectionEnd,
|
|
1294
1298
|
selectionRight,
|
|
1295
1299
|
takeNodeAssertionPhases,
|
|
1296
|
-
testStatement,
|
|
1297
1300
|
tryBegin,
|
|
1298
1301
|
tryCatch,
|
|
1299
1302
|
tryEnd,
|
|
1300
1303
|
withCoverageCarrier,
|
|
1301
1304
|
withNodeAssertionPhase,
|
|
1305
|
+
bindNodeAssertionPhase,
|
|
1302
1306
|
withRequestPhase,
|
|
1303
1307
|
writeExclusiveBackgroundRecord
|
|
1304
1308
|
};
|
|
@@ -1343,12 +1347,12 @@ export {
|
|
|
1343
1347
|
selectionEnd,
|
|
1344
1348
|
selectionRight,
|
|
1345
1349
|
takeNodeAssertionPhases,
|
|
1346
|
-
testStatement,
|
|
1347
1350
|
tryBegin,
|
|
1348
1351
|
tryCatch,
|
|
1349
1352
|
tryEnd,
|
|
1350
1353
|
withCoverageCarrier,
|
|
1351
1354
|
withNodeAssertionPhase,
|
|
1355
|
+
bindNodeAssertionPhase,
|
|
1352
1356
|
withRequestPhase,
|
|
1353
1357
|
writeExclusiveBackgroundRecord
|
|
1354
1358
|
};
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "AssertionMap",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"schemaVersion": {
|
|
7
|
+
"type": "integer",
|
|
8
|
+
"format": "uint32",
|
|
9
|
+
"minimum": 2,
|
|
10
|
+
"maximum": 2
|
|
11
|
+
},
|
|
12
|
+
"assertions": {
|
|
13
|
+
"type": "array",
|
|
14
|
+
"items": {
|
|
15
|
+
"$ref": "#/$defs/Assertion"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"changeAssessments": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"items": {
|
|
21
|
+
"$ref": "#/$defs/ChangeAssessment"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"retiredAssertions": {
|
|
25
|
+
"type": "array",
|
|
26
|
+
"items": {
|
|
27
|
+
"$ref": "#/$defs/Retired"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"additionalProperties": false,
|
|
32
|
+
"required": [
|
|
33
|
+
"schemaVersion",
|
|
34
|
+
"assertions"
|
|
35
|
+
],
|
|
36
|
+
"$defs": {
|
|
37
|
+
"Assertion": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"properties": {
|
|
40
|
+
"id": {
|
|
41
|
+
"type": "string"
|
|
42
|
+
},
|
|
43
|
+
"at": {
|
|
44
|
+
"$ref": "#/$defs/Anchor"
|
|
45
|
+
},
|
|
46
|
+
"questions": {
|
|
47
|
+
"type": "array",
|
|
48
|
+
"items": {
|
|
49
|
+
"type": "string"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"observes": {
|
|
53
|
+
"type": "array",
|
|
54
|
+
"items": {
|
|
55
|
+
"type": "string"
|
|
56
|
+
},
|
|
57
|
+
"default": []
|
|
58
|
+
},
|
|
59
|
+
"flows": {
|
|
60
|
+
"type": "array",
|
|
61
|
+
"items": {
|
|
62
|
+
"$ref": "#/$defs/Flow"
|
|
63
|
+
},
|
|
64
|
+
"default": []
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"additionalProperties": false,
|
|
68
|
+
"required": [
|
|
69
|
+
"id",
|
|
70
|
+
"at"
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"Anchor": {
|
|
74
|
+
"description": "One-based lines and UTF-8 byte columns, for every language. Text is exact.",
|
|
75
|
+
"type": "object",
|
|
76
|
+
"properties": {
|
|
77
|
+
"file": {
|
|
78
|
+
"type": "string"
|
|
79
|
+
},
|
|
80
|
+
"line": {
|
|
81
|
+
"type": "integer",
|
|
82
|
+
"format": "uint",
|
|
83
|
+
"minimum": 0
|
|
84
|
+
},
|
|
85
|
+
"column": {
|
|
86
|
+
"type": "integer",
|
|
87
|
+
"format": "uint",
|
|
88
|
+
"minimum": 0
|
|
89
|
+
},
|
|
90
|
+
"text": {
|
|
91
|
+
"type": "string"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"additionalProperties": false,
|
|
95
|
+
"required": [
|
|
96
|
+
"file",
|
|
97
|
+
"line",
|
|
98
|
+
"column",
|
|
99
|
+
"text"
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
"Flow": {
|
|
103
|
+
"type": "object",
|
|
104
|
+
"properties": {
|
|
105
|
+
"id": {
|
|
106
|
+
"type": "string"
|
|
107
|
+
},
|
|
108
|
+
"basis": {
|
|
109
|
+
"type": [
|
|
110
|
+
"string",
|
|
111
|
+
"null"
|
|
112
|
+
],
|
|
113
|
+
"pattern": "^scov2:[0-9a-f]{64}$"
|
|
114
|
+
},
|
|
115
|
+
"explanation": {
|
|
116
|
+
"type": "string"
|
|
117
|
+
},
|
|
118
|
+
"appliesTo": {
|
|
119
|
+
"type": "array",
|
|
120
|
+
"items": {
|
|
121
|
+
"$ref": "#/$defs/TestSelector"
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"nodes": {
|
|
125
|
+
"type": "array",
|
|
126
|
+
"items": {
|
|
127
|
+
"$ref": "#/$defs/Node"
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"edges": {
|
|
131
|
+
"type": "array",
|
|
132
|
+
"items": {
|
|
133
|
+
"$ref": "#/$defs/Edge"
|
|
134
|
+
},
|
|
135
|
+
"default": []
|
|
136
|
+
},
|
|
137
|
+
"countsAsAsserted": {
|
|
138
|
+
"type": "array",
|
|
139
|
+
"items": {
|
|
140
|
+
"type": "string"
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"watch": {
|
|
144
|
+
"type": "array",
|
|
145
|
+
"items": {
|
|
146
|
+
"type": "string"
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
"questions": {
|
|
150
|
+
"type": "array",
|
|
151
|
+
"items": {
|
|
152
|
+
"type": "string"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"additionalProperties": false,
|
|
157
|
+
"required": [
|
|
158
|
+
"id",
|
|
159
|
+
"basis",
|
|
160
|
+
"explanation",
|
|
161
|
+
"appliesTo",
|
|
162
|
+
"nodes",
|
|
163
|
+
"countsAsAsserted",
|
|
164
|
+
"watch"
|
|
165
|
+
]
|
|
166
|
+
},
|
|
167
|
+
"TestSelector": {
|
|
168
|
+
"type": "object",
|
|
169
|
+
"properties": {
|
|
170
|
+
"file": {
|
|
171
|
+
"type": "string"
|
|
172
|
+
},
|
|
173
|
+
"name": {
|
|
174
|
+
"type": "string"
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
"additionalProperties": false,
|
|
178
|
+
"required": [
|
|
179
|
+
"file",
|
|
180
|
+
"name"
|
|
181
|
+
]
|
|
182
|
+
},
|
|
183
|
+
"Node": {
|
|
184
|
+
"type": "object",
|
|
185
|
+
"properties": {
|
|
186
|
+
"id": {
|
|
187
|
+
"type": "string"
|
|
188
|
+
},
|
|
189
|
+
"at": {
|
|
190
|
+
"$ref": "#/$defs/Anchor"
|
|
191
|
+
},
|
|
192
|
+
"role": {
|
|
193
|
+
"type": "string"
|
|
194
|
+
},
|
|
195
|
+
"meaning": {
|
|
196
|
+
"type": "string"
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
"additionalProperties": false,
|
|
200
|
+
"required": [
|
|
201
|
+
"id",
|
|
202
|
+
"at"
|
|
203
|
+
]
|
|
204
|
+
},
|
|
205
|
+
"Edge": {
|
|
206
|
+
"type": "object",
|
|
207
|
+
"properties": {
|
|
208
|
+
"from": {
|
|
209
|
+
"type": "string"
|
|
210
|
+
},
|
|
211
|
+
"to": {
|
|
212
|
+
"type": "string"
|
|
213
|
+
},
|
|
214
|
+
"kind": {
|
|
215
|
+
"type": "string"
|
|
216
|
+
},
|
|
217
|
+
"basis": {
|
|
218
|
+
"type": "string"
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
"additionalProperties": false,
|
|
222
|
+
"required": [
|
|
223
|
+
"from",
|
|
224
|
+
"to",
|
|
225
|
+
"kind"
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
"ChangeAssessment": {
|
|
229
|
+
"type": "object",
|
|
230
|
+
"properties": {
|
|
231
|
+
"id": {
|
|
232
|
+
"type": "string"
|
|
233
|
+
},
|
|
234
|
+
"basis": {
|
|
235
|
+
"type": [
|
|
236
|
+
"string",
|
|
237
|
+
"null"
|
|
238
|
+
],
|
|
239
|
+
"pattern": "^scov2:[0-9a-f]{64}$"
|
|
240
|
+
},
|
|
241
|
+
"affectedFlows": {
|
|
242
|
+
"type": "array",
|
|
243
|
+
"items": {
|
|
244
|
+
"type": "string"
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
"explanation": {
|
|
248
|
+
"type": "string"
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
"additionalProperties": false,
|
|
252
|
+
"required": [
|
|
253
|
+
"id",
|
|
254
|
+
"basis",
|
|
255
|
+
"affectedFlows",
|
|
256
|
+
"explanation"
|
|
257
|
+
]
|
|
258
|
+
},
|
|
259
|
+
"Retired": {
|
|
260
|
+
"type": "object",
|
|
261
|
+
"properties": {
|
|
262
|
+
"assertion": {
|
|
263
|
+
"$ref": "#/$defs/Assertion"
|
|
264
|
+
},
|
|
265
|
+
"reason": {
|
|
266
|
+
"type": "string"
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"additionalProperties": false,
|
|
270
|
+
"required": [
|
|
271
|
+
"assertion",
|
|
272
|
+
"reason"
|
|
273
|
+
]
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# JS/TS assertion analyzer (internal)
|
|
2
|
-
|
|
3
|
-
This private package is the post-run analysis component used by Supercov's
|
|
4
|
-
`runs <run> assertions` command. It is bundled in the npm distribution, not
|
|
5
|
-
published as a separate CLI or SDK.
|
|
6
|
-
|
|
7
|
-
See [Assertion evidence](../../docs/assertion-evidence.md) for public commands,
|
|
8
|
-
pragma syntax, report interpretation and supported scope.
|
|
9
|
-
|
|
10
|
-
## Product boundary
|
|
11
|
-
|
|
12
|
-
- `bin/query.mjs` is the CLI-to-analyzer JSON transport. It accepts an ordinary
|
|
13
|
-
archive representation prepared by Rust, validates identities and returns facts.
|
|
14
|
-
- `bin/identity.mjs` checks the analyzer source/build identity; its direct
|
|
15
|
-
invocation writes that identity during the build.
|
|
16
|
-
- `bin/compiler-identity.mjs` fingerprints the project's compiler implementation.
|
|
17
|
-
- `src/archive.ts` validates the archive protocol, source positions and attempt
|
|
18
|
-
ownership, then constructs query-local evidence in memory.
|
|
19
|
-
- `src/analyze.ts` extracts source-flow facts and exact assertion witnesses.
|
|
20
|
-
The Rust engine joins those facts into candidate classifications.
|
|
21
|
-
- `src/frontend.ts` and `src/native-frontend.ts` implement the legacy and native
|
|
22
|
-
TypeScript compiler boundaries. `src/pragmas.ts` validates optional hints.
|
|
23
|
-
|
|
24
|
-
There is no converted-input command, on-disk research input, V8 remapping,
|
|
25
|
-
mutation runner or diagnostic-ablation option in the product interface.
|
|
26
|
-
Source files ship to support build-identity verification; tests and research
|
|
27
|
-
tools do not ship. Assertion candidates remain unverified, not safety proofs.
|
|
28
|
-
Only executable JavaScript and its build identity ship from `dist`; there is no
|
|
29
|
-
public SDK declaration surface or generated source-map payload.
|
|
30
|
-
|
|
31
|
-
## Build and test
|
|
32
|
-
|
|
33
|
-
From this directory:
|
|
34
|
-
|
|
35
|
-
```sh
|
|
36
|
-
npm ci --ignore-scripts
|
|
37
|
-
npm test
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
The build uses pinned TypeScript 5.8.3 explicitly. Project analysis uses the
|
|
41
|
-
project's compiler; native 7.0.2 has a separate frontend and identity checks.
|
|
42
|
-
Native compiler processes close after both successful and failed queries.
|
|
43
|
-
|
|
44
|
-
From the repository root, exercise real Node/Vitest archives and the installed
|
|
45
|
-
npm package:
|
|
46
|
-
|
|
47
|
-
```sh
|
|
48
|
-
npm run test:asserted-integration
|
|
49
|
-
npm run test:asserted-package
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Controlled unit fixtures test parser, flow and witness rules. The ordinary-archive
|
|
53
|
-
integration tests execute real suites and explicit behavioral counterexamples.
|
|
54
|
-
Compiler-path and identity regressions run across supported CI platforms.
|
|
55
|
-
Historical external-cohort research is not part of the default suite or product.
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { readFileSync, readdirSync } from "node:fs";
|
|
3
|
-
import { dirname, resolve } from "node:path";
|
|
4
|
-
import { createRequire } from "node:module";
|
|
5
|
-
import { pathToFileURL } from "node:url";
|
|
6
|
-
import { projectCompilerPath } from "../dist/compiler.js";
|
|
7
|
-
|
|
8
|
-
/** Hash the native implementation as well as its JS client; version.cjs alone is not the compiler. */
|
|
9
|
-
export function compilerIdentity(projectRoot) {
|
|
10
|
-
return compilerIdentityFromEntry(projectCompilerPath(projectRoot));
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function compilerIdentityFromEntry(entry) {
|
|
14
|
-
const require = createRequire(pathToFileURL(entry));
|
|
15
|
-
const { version } = require(entry);
|
|
16
|
-
const entrySha256 = createHash("sha256")
|
|
17
|
-
.update(readFileSync(entry))
|
|
18
|
-
.digest("hex");
|
|
19
|
-
if (version !== "7.0.2")
|
|
20
|
-
return { backend: "typescript-legacy", version, sha256: entrySha256 };
|
|
21
|
-
const packageRoot = dirname(require.resolve("typescript/package.json"));
|
|
22
|
-
const platform = `@typescript/typescript-${process.platform}-${process.arch}`;
|
|
23
|
-
let nativeRoot;
|
|
24
|
-
try {
|
|
25
|
-
nativeRoot = dirname(require.resolve(`${platform}/package.json`));
|
|
26
|
-
} catch (cause) {
|
|
27
|
-
throw new Error(
|
|
28
|
-
`TypeScript 7's native compiler dependency ${platform} is missing. Install the project's optional TypeScript dependencies before recapturing tests.`,
|
|
29
|
-
{ cause },
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
const nativeMetadata = JSON.parse(
|
|
33
|
-
readFileSync(resolve(nativeRoot, "package.json"), "utf8"),
|
|
34
|
-
);
|
|
35
|
-
if (nativeMetadata.name !== platform || nativeMetadata.version !== version)
|
|
36
|
-
throw new Error(
|
|
37
|
-
`TypeScript native package identity mismatch: expected ${platform}@${version}`,
|
|
38
|
-
);
|
|
39
|
-
const executable = resolve(
|
|
40
|
-
nativeRoot,
|
|
41
|
-
"lib",
|
|
42
|
-
process.platform === "win32" ? "tsc.exe" : "tsc",
|
|
43
|
-
);
|
|
44
|
-
const nativeSha256 = createHash("sha256")
|
|
45
|
-
.update(readFileSync(executable))
|
|
46
|
-
.digest("hex");
|
|
47
|
-
const hash = createHash("sha256");
|
|
48
|
-
let files = 0;
|
|
49
|
-
function walk(root, relative = "") {
|
|
50
|
-
for (const file of readdirSync(resolve(root, relative), {
|
|
51
|
-
withFileTypes: true,
|
|
52
|
-
}).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
53
|
-
if (file.name === "node_modules") continue;
|
|
54
|
-
const path = relative ? `${relative}/${file.name}` : file.name;
|
|
55
|
-
if (file.isDirectory()) walk(root, path);
|
|
56
|
-
else if (file.isFile()) {
|
|
57
|
-
hash
|
|
58
|
-
.update(path)
|
|
59
|
-
.update("\0")
|
|
60
|
-
.update(readFileSync(resolve(root, path)))
|
|
61
|
-
.update("\0");
|
|
62
|
-
files++;
|
|
63
|
-
} else throw new Error(`Unsupported compiler package entry: ${path}`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
hash.update("typescript-package\0");
|
|
67
|
-
walk(packageRoot);
|
|
68
|
-
hash.update("native-package\0");
|
|
69
|
-
walk(nativeRoot);
|
|
70
|
-
return {
|
|
71
|
-
backend: "typescript-native-7",
|
|
72
|
-
version,
|
|
73
|
-
sha256: hash.digest("hex"),
|
|
74
|
-
nativePackage: platform,
|
|
75
|
-
nativeSha256,
|
|
76
|
-
files,
|
|
77
|
-
};
|
|
78
|
-
}
|