supercov 0.0.44 → 0.0.46
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 +21 -12
- package/docs/agent-loop.md +17 -9
- package/docs/assertion-agent.md +146 -0
- package/docs/assertion-evidence.md +72 -663
- package/docs/assertion-maps.md +236 -0
- package/docs/assertions.md +132 -0
- package/docs/cli.md +40 -8
- package/docs/coverage-model.md +18 -0
- package/docs/evidence.md +28 -0
- package/docs/performance.md +16 -0
- package/docs/supported-suites.md +64 -147
- package/package.json +36 -35
- package/runtime/javascript/launchSupervisor.mjs +5 -0
- package/runtime/javascript/nodeTest.mjs +57 -41
- package/runtime/javascript/provenance.mjs +4 -1
- package/runtime/javascript/register.mjs +9 -5
- package/runtime/javascript/runnerEvidence.mjs +4 -1
- package/runtime/javascript/runtime.mjs +62 -36
- package/schemas/assertions.schema.json +276 -0
- package/analyzers/typescript/README.md +0 -59
- package/analyzers/typescript/bin/compiler-identity.mjs +0 -78
- package/analyzers/typescript/bin/identity.mjs +0 -71
- package/analyzers/typescript/bin/query.mjs +0 -29
- package/analyzers/typescript/dist/analyze.js +0 -5273
- package/analyzers/typescript/dist/archive.js +0 -337
- package/analyzers/typescript/dist/awaited-observations.js +0 -376
- 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/mock-counts.js +0 -2517
- package/analyzers/typescript/dist/native-frontend.js +0 -271
- package/analyzers/typescript/dist/pragmas.js +0 -186
- package/analyzers/typescript/dist/types.js +0 -1
- package/analyzers/typescript/package.json +0 -27
- package/analyzers/typescript/src/analyze.ts +0 -6180
- package/analyzers/typescript/src/archive.ts +0 -471
- package/analyzers/typescript/src/awaited-observations.ts +0 -561
- package/analyzers/typescript/src/compiler.ts +0 -49
- package/analyzers/typescript/src/frontend.ts +0 -136
- package/analyzers/typescript/src/mock-counts.ts +0 -3219
- package/analyzers/typescript/src/native-frontend.ts +0 -315
- package/analyzers/typescript/src/pragmas.ts +0 -284
- package/analyzers/typescript/src/types.ts +0 -45
- package/analyzers/typescript/tsconfig.json +0 -12
- package/docs/code-verification.md +0 -4
|
@@ -36,13 +36,15 @@ export function runnerTestId(identity) {
|
|
|
36
36
|
];
|
|
37
37
|
// Preserve existing top-level, uniquely registered test IDs. Nested tests
|
|
38
38
|
// and repeated registrations need more than a shared source/name identity.
|
|
39
|
+
if (identity.role === "setup")
|
|
40
|
+
parts.push("role", "setup");
|
|
39
41
|
if (identity.parentTestId)
|
|
40
42
|
parts.push("parent", identity.parentTestId);
|
|
41
43
|
if (identity.registrationOrdinal)
|
|
42
44
|
parts.push("registration", identity.registrationOrdinal);
|
|
43
45
|
// Titles can themselves contain separator text. Domain-separate and encode
|
|
44
46
|
// the extended identity structurally so it cannot alias a literal title.
|
|
45
|
-
const key = identity.parentTestId || identity.registrationOrdinal
|
|
47
|
+
const key = identity.role === "setup" || identity.parentTestId || identity.registrationOrdinal
|
|
46
48
|
? JSON.stringify(["registration-v2", ...parts])
|
|
47
49
|
: parts.join("\0");
|
|
48
50
|
return `${identity.runner}:${createHash("sha256").update(key).digest("hex").slice(0, 24)}`;
|
|
@@ -116,6 +118,7 @@ export function writeRunnerEvidence(identity, status, scope, evidenceDirectoryOv
|
|
|
116
118
|
title: identity.name.split(" > ").at(-1) ?? identity.name,
|
|
117
119
|
retry: identity.retry ?? 0,
|
|
118
120
|
status,
|
|
121
|
+
...(identity.role ? { role: identity.role } : {}),
|
|
119
122
|
provenance: inferTestProvenance({
|
|
120
123
|
runner: identity.runner,
|
|
121
124
|
file: testFile,
|
|
@@ -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();
|
|
@@ -758,8 +754,8 @@ function withNodeAssertionPhase(operation, source, callback) {
|
|
|
758
754
|
const existing = context.phaseId && assertionPhaseState(scope).phaseIds.has(context.phaseId);
|
|
759
755
|
if (existing)
|
|
760
756
|
return callback();
|
|
761
|
-
//
|
|
762
|
-
//
|
|
757
|
+
// A lexical occurrence already identifies its source. Stack fallback is lazy
|
|
758
|
+
// and qualified so transformed coordinates cannot impersonate original ones.
|
|
763
759
|
if (typeof source === "function")
|
|
764
760
|
source = source();
|
|
765
761
|
const bridged = (_a8 = runtimeGlobal.__SUPERCOV_ASSERTION_PHASE_BRIDGE__) == null ? void 0 : _a8.call(runtimeGlobal, operation, source, callback);
|
|
@@ -792,15 +788,12 @@ function withNodeAssertionPhase(operation, source, callback) {
|
|
|
792
788
|
throw cleanInstrumentationStack(error);
|
|
793
789
|
}
|
|
794
790
|
}
|
|
795
|
-
//
|
|
796
|
-
//
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
const target = method === void 0 ? receiver : receiver[method];
|
|
802
|
-
const thisArgument = method === void 0 ? void 0 : receiver;
|
|
803
|
-
return (...args) => withNodeAssertionPhase(operation, source, () => Reflect.apply(target, thisArgument, args));
|
|
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));
|
|
804
797
|
}
|
|
805
798
|
function takeNodeAssertionPhases(scope) {
|
|
806
799
|
var _a8, _b;
|
|
@@ -970,15 +963,56 @@ function requestCoverageContext(value) {
|
|
|
970
963
|
const phaseId = typeof rawPhaseId === "string" && rawPhaseId.length > 0 && (!scope || phaseBelongsToAttempt(rawPhaseId, scope.attemptId)) ? rawPhaseId : void 0;
|
|
971
964
|
return __spreadValues(__spreadValues({}, scope ? { scope } : {}), phaseId ? { phaseId } : {});
|
|
972
965
|
}
|
|
973
|
-
|
|
966
|
+
// Keep connection ownership on the emitter, without changing listener
|
|
967
|
+
// identity (removeListener/off and once still see the original callbacks).
|
|
968
|
+
const emitterContextMaps = runtimeGlobal.__SUPERCOV_EMITTER_CONTEXT_MAPS__ ??= new Map();
|
|
969
|
+
const emitterCoverageContexts = emitterContextMaps.get(runtimeInstance) ?? new WeakMap();
|
|
970
|
+
emitterContextMaps.set(runtimeInstance, emitterCoverageContexts);
|
|
971
|
+
const patchedEmitterInstances = runtimeGlobal.__SUPERCOV_EMITTER_PATCHED_INSTANCES__ ??= new Set();
|
|
972
|
+
function installNodeRequestPropagation() {
|
|
973
|
+
if (isBrowser || patchedEmitterInstances.has(runtimeInstance) || typeof process === "undefined") return;
|
|
974
|
+
const EventEmitter = process.getBuiltinModule?.("node:events")?.EventEmitter;
|
|
975
|
+
const Server = process.getBuiltinModule?.("node:http")?.Server;
|
|
976
|
+
const SecureServer = process.getBuiltinModule?.("node:https")?.Server;
|
|
977
|
+
if (!EventEmitter) return;
|
|
978
|
+
const original = EventEmitter.prototype.emit;
|
|
979
|
+
EventEmitter.prototype.emit = function(event, ...args) {
|
|
980
|
+
let context = emitterCoverageContexts.get(this);
|
|
981
|
+
if ((event === "request" || event === "upgrade") &&
|
|
982
|
+
((Server && this instanceof Server) || (SecureServer && this instanceof SecureServer))) {
|
|
983
|
+
// HTTP headers establish ownership even when Express/SDK listeners and
|
|
984
|
+
// the server process were created by a shared before hook.
|
|
985
|
+
const incoming = requestCoverageContext(args[0]);
|
|
986
|
+
if (incoming) context = incoming.scope ? incoming : context ?? currentRequestContext();
|
|
987
|
+
}
|
|
988
|
+
const invoke = () => Reflect.apply(original, this, [event, ...args]);
|
|
989
|
+
try {
|
|
990
|
+
return context ? withCoverageCarrier({ version: 1, ...context }, invoke) : invoke();
|
|
991
|
+
} finally {
|
|
992
|
+
if (event === "close") emitterCoverageContexts.delete(this);
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
patchedEmitterInstances.add(runtimeInstance);
|
|
996
|
+
}
|
|
997
|
+
installNodeRequestPropagation();
|
|
998
|
+
|
|
999
|
+
function withRequestPhase(handler, event) {
|
|
974
1000
|
if (!serverPhaseStorage)
|
|
975
1001
|
return handler;
|
|
1002
|
+
const registeredContext = currentRequestContext();
|
|
976
1003
|
return function coverageRequestPhase(...args) {
|
|
977
1004
|
var _a8, _b, _c, _d;
|
|
978
1005
|
const requestContext = args.map((argument) => requestCoverageContext(argument)).find((context2) => context2 !== void 0);
|
|
979
|
-
|
|
1006
|
+
// An untagged request to a test-owned server must not erase that server's
|
|
1007
|
+
// owner. Shared servers have no captured test scope and stay unattributed.
|
|
1008
|
+
const inheritedContext = requestContext?.scope ? {} : registeredContext.scope ? registeredContext : requestContext === void 0 ? currentRequestContext() : {};
|
|
980
1009
|
const context = __spreadValues(__spreadValues({}, ((_a8 = requestContext == null ? void 0 : requestContext.scope) != null ? _a8 : inheritedContext.scope) ? { scope: (_b = requestContext == null ? void 0 : requestContext.scope) != null ? _b : inheritedContext.scope } : {}), ((_c = requestContext == null ? void 0 : requestContext.phaseId) != null ? _c : inheritedContext.phaseId) ? { phaseId: (_d = requestContext == null ? void 0 : requestContext.phaseId) != null ? _d : inheritedContext.phaseId } : {});
|
|
981
|
-
const invoke = () =>
|
|
1010
|
+
const invoke = () => {
|
|
1011
|
+
if (event === "connection" && context.scope && args[0] &&
|
|
1012
|
+
typeof args[0] === "object" && typeof args[0].emit === "function")
|
|
1013
|
+
emitterCoverageContexts.set(args[0], context);
|
|
1014
|
+
return Reflect.apply(handler, this, args);
|
|
1015
|
+
};
|
|
982
1016
|
return requestContext !== void 0 || context.scope || context.phaseId ? serverPhaseStorage.run(context, () => withProbeV2Context(context, invoke)) : invoke();
|
|
983
1017
|
};
|
|
984
1018
|
}
|
|
@@ -995,31 +1029,25 @@ function recordBrowserEvent(event) {
|
|
|
995
1029
|
state.events.push(event);
|
|
996
1030
|
return true;
|
|
997
1031
|
}
|
|
998
|
-
function testStatement(source) {
|
|
999
|
-
state.testStatement = typeof source === "string" && source.length > 0 ? source : void 0;
|
|
1000
|
-
}
|
|
1001
|
-
function statementFields() {
|
|
1002
|
-
return state.testStatement ? { statementId: state.testStatement } : {};
|
|
1003
|
-
}
|
|
1004
1032
|
function coverageHit(id) {
|
|
1005
1033
|
state.hits.add(id);
|
|
1006
1034
|
const timestampMs = Date.now();
|
|
1007
1035
|
const phaseId = currentPhaseId();
|
|
1008
1036
|
if (isBrowser) {
|
|
1009
|
-
if (recordBrowserEvent(__spreadProps(__spreadValues(
|
|
1037
|
+
if (recordBrowserEvent(__spreadProps(__spreadValues({
|
|
1010
1038
|
type: "hit",
|
|
1011
1039
|
id,
|
|
1012
1040
|
timestampMs
|
|
1013
|
-
}, phaseId ? { phaseId } : {}),
|
|
1041
|
+
}, phaseId ? { phaseId } : {}), {
|
|
1014
1042
|
environment: "browser"
|
|
1015
1043
|
})))
|
|
1016
1044
|
persistBrowser();
|
|
1017
1045
|
} else {
|
|
1018
|
-
appendServer(__spreadValues(
|
|
1046
|
+
appendServer(__spreadValues({
|
|
1019
1047
|
type: "hit",
|
|
1020
1048
|
id,
|
|
1021
1049
|
timestampMs
|
|
1022
|
-
}, phaseId ? { phaseId } : {})
|
|
1050
|
+
}, phaseId ? { phaseId } : {}));
|
|
1023
1051
|
}
|
|
1024
1052
|
}
|
|
1025
1053
|
function registerProbeV2(definition) {
|
|
@@ -1254,22 +1282,22 @@ function mcdcEnd(frame, value) {
|
|
|
1254
1282
|
const timestampMs = Date.now();
|
|
1255
1283
|
const phaseId = currentPhaseId();
|
|
1256
1284
|
if (isBrowser) {
|
|
1257
|
-
if (recordBrowserEvent(__spreadProps(__spreadValues(
|
|
1285
|
+
if (recordBrowserEvent(__spreadProps(__spreadValues({
|
|
1258
1286
|
type: "decision",
|
|
1259
1287
|
id: decision.meta.id,
|
|
1260
1288
|
vector,
|
|
1261
1289
|
timestampMs
|
|
1262
|
-
}, phaseId ? { phaseId } : {}),
|
|
1290
|
+
}, phaseId ? { phaseId } : {}), {
|
|
1263
1291
|
environment: "browser"
|
|
1264
1292
|
})))
|
|
1265
1293
|
persistBrowser();
|
|
1266
1294
|
} else {
|
|
1267
|
-
appendServer(__spreadValues(
|
|
1295
|
+
appendServer(__spreadValues({
|
|
1268
1296
|
type: "decision",
|
|
1269
1297
|
meta: decision.meta,
|
|
1270
1298
|
vector,
|
|
1271
1299
|
timestampMs
|
|
1272
|
-
}, phaseId ? { phaseId } : {})
|
|
1300
|
+
}, phaseId ? { phaseId } : {}));
|
|
1273
1301
|
}
|
|
1274
1302
|
return value;
|
|
1275
1303
|
}
|
|
@@ -1310,13 +1338,12 @@ const directRuntimeApi = {
|
|
|
1310
1338
|
selectionEnd,
|
|
1311
1339
|
selectionRight,
|
|
1312
1340
|
takeNodeAssertionPhases,
|
|
1313
|
-
bindNodeAssertion,
|
|
1314
|
-
testStatement,
|
|
1315
1341
|
tryBegin,
|
|
1316
1342
|
tryCatch,
|
|
1317
1343
|
tryEnd,
|
|
1318
1344
|
withCoverageCarrier,
|
|
1319
1345
|
withNodeAssertionPhase,
|
|
1346
|
+
bindNodeAssertionPhase,
|
|
1320
1347
|
withRequestPhase,
|
|
1321
1348
|
writeExclusiveBackgroundRecord
|
|
1322
1349
|
};
|
|
@@ -1361,13 +1388,12 @@ export {
|
|
|
1361
1388
|
selectionEnd,
|
|
1362
1389
|
selectionRight,
|
|
1363
1390
|
takeNodeAssertionPhases,
|
|
1364
|
-
bindNodeAssertion,
|
|
1365
|
-
testStatement,
|
|
1366
1391
|
tryBegin,
|
|
1367
1392
|
tryCatch,
|
|
1368
1393
|
tryEnd,
|
|
1369
1394
|
withCoverageCarrier,
|
|
1370
1395
|
withNodeAssertionPhase,
|
|
1396
|
+
bindNodeAssertionPhase,
|
|
1371
1397
|
withRequestPhase,
|
|
1372
1398
|
writeExclusiveBackgroundRecord
|
|
1373
1399
|
};
|
|
@@ -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,59 +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/mock-counts.ts` models bounded synchronous console-mock count histories,
|
|
22
|
-
keeping count evidence separate from general value-protection claims.
|
|
23
|
-
- `src/awaited-observations.ts` recognizes bounded native child-capture/poll
|
|
24
|
-
source patterns for hint attachment, without manufacturing runtime witnesses.
|
|
25
|
-
- `src/frontend.ts` and `src/native-frontend.ts` implement the legacy and native
|
|
26
|
-
TypeScript compiler boundaries. `src/pragmas.ts` validates optional hints.
|
|
27
|
-
|
|
28
|
-
There is no converted-input command, on-disk research input, V8 remapping,
|
|
29
|
-
mutation runner or diagnostic-ablation option in the product interface.
|
|
30
|
-
Source files ship to support build-identity verification; tests and research
|
|
31
|
-
tools do not ship. Assertion candidates remain unverified, not safety proofs.
|
|
32
|
-
Only executable JavaScript and its build identity ship from `dist`; there is no
|
|
33
|
-
public SDK declaration surface or generated source-map payload.
|
|
34
|
-
|
|
35
|
-
## Build and test
|
|
36
|
-
|
|
37
|
-
From this directory:
|
|
38
|
-
|
|
39
|
-
```sh
|
|
40
|
-
npm ci --ignore-scripts
|
|
41
|
-
npm test
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
The build uses pinned TypeScript 5.8.3 explicitly. Project analysis uses the
|
|
45
|
-
project's compiler; native 7.0.2 has a separate frontend and identity checks.
|
|
46
|
-
Native compiler processes close after both successful and failed queries.
|
|
47
|
-
|
|
48
|
-
From the repository root, exercise real Node/Vitest archives and the installed
|
|
49
|
-
npm package:
|
|
50
|
-
|
|
51
|
-
```sh
|
|
52
|
-
npm run test:asserted-integration
|
|
53
|
-
npm run test:asserted-package
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Controlled unit fixtures test parser, flow and witness rules. The ordinary-archive
|
|
57
|
-
integration tests execute real suites and explicit behavioral counterexamples.
|
|
58
|
-
Compiler-path and identity regressions run across supported CI platforms.
|
|
59
|
-
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
|
-
}
|