@mmnto/cli 1.64.1 → 1.65.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/commands/run-compiled-rules.d.ts.map +1 -1
- package/dist/commands/run-compiled-rules.js +21 -8
- package/dist/commands/run-compiled-rules.js.map +1 -1
- package/dist/commands/run-compiled-rules.test.js +114 -0
- package/dist/commands/run-compiled-rules.test.js.map +1 -1
- package/dist/commands/spine-windtunnel.d.ts +76 -0
- package/dist/commands/spine-windtunnel.d.ts.map +1 -0
- package/dist/commands/spine-windtunnel.js +421 -0
- package/dist/commands/spine-windtunnel.js.map +1 -0
- package/dist/commands/spine-windtunnel.test.d.ts +2 -0
- package/dist/commands/spine-windtunnel.test.d.ts.map +1 -0
- package/dist/commands/spine-windtunnel.test.js +238 -0
- package/dist/commands/spine-windtunnel.test.js.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
// ─── Named constants ─────────────────────────────────
|
|
4
|
+
const LOCK_REL_PATH = '.totem/spine/gate-1/windtunnel.lock.json';
|
|
5
|
+
const COMMIT_SHA_REGEX = /^[0-9a-f]{40}$/;
|
|
6
|
+
/**
|
|
7
|
+
* `totem spine windtunnel freeze`
|
|
8
|
+
*
|
|
9
|
+
* Validates that the lock file at `LOCK_REL_PATH` (or `opts.lockPath`) is
|
|
10
|
+
* schema-valid and that `resolvedPrs === selectionRule(asOfCommit)` (S4 —
|
|
11
|
+
* completeness assertion). Writes the canonical lock path.
|
|
12
|
+
*
|
|
13
|
+
* The completeness assertion requires the lc clone (`--lc-dir`) so the
|
|
14
|
+
* command can re-derive the full code-touching PR set at `asOfCommit` and
|
|
15
|
+
* diff it against `resolvedPrs`. In the harness phase (no real lc run yet)
|
|
16
|
+
* the assertion is skipped with a loud warning.
|
|
17
|
+
*/
|
|
18
|
+
export async function freezeCommand(opts) {
|
|
19
|
+
const { WindtunnelLockSchema, safeExec, resolveGitRoot, TotemError } = await import('@mmnto/totem');
|
|
20
|
+
const cwd = process.cwd();
|
|
21
|
+
const repoRoot = resolveGitRoot(cwd) ?? cwd;
|
|
22
|
+
const lockPath = opts.lockPath
|
|
23
|
+
? path.resolve(cwd, opts.lockPath)
|
|
24
|
+
: path.join(repoRoot, LOCK_REL_PATH);
|
|
25
|
+
const lcDir = opts.lcDir ?? process.env['TOTEM_LC_DIR'];
|
|
26
|
+
// Read + validate the lock
|
|
27
|
+
let rawJson;
|
|
28
|
+
try {
|
|
29
|
+
rawJson = fs.readFileSync(lockPath, 'utf-8');
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
throw new TotemError('CONFIG_INVALID', `Wind-tunnel lock not found at ${lockPath}`, `Create the lock file at ${LOCK_REL_PATH} before running freeze.`);
|
|
33
|
+
}
|
|
34
|
+
let rawObj;
|
|
35
|
+
try {
|
|
36
|
+
rawObj = JSON.parse(rawJson);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
throw new TotemError('CONFIG_INVALID', `Wind-tunnel lock at ${lockPath} is not valid JSON`, 'Fix the JSON syntax and retry.');
|
|
40
|
+
}
|
|
41
|
+
const parsed = WindtunnelLockSchema.safeParse(rawObj);
|
|
42
|
+
if (!parsed.success) {
|
|
43
|
+
const issues = parsed.error.issues
|
|
44
|
+
.map((i) => ` • ${i.path.join('.')}: ${i.message}`)
|
|
45
|
+
.join('\n');
|
|
46
|
+
throw new TotemError('CONFIG_INVALID', `Wind-tunnel lock schema validation failed:\n${issues}`, 'Fix the lock file and retry.');
|
|
47
|
+
}
|
|
48
|
+
const lock = parsed.data;
|
|
49
|
+
console.error(`[WindtunnelFreeze] Lock schema valid — phase: ${lock.phase}`);
|
|
50
|
+
// S4: completeness assertion
|
|
51
|
+
if (lcDir) {
|
|
52
|
+
console.error(`[WindtunnelFreeze] lc-dir provided — asserting corpus completeness (S4)`);
|
|
53
|
+
await assertCorpusCompleteness(lock, lcDir, repoRoot, safeExec);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
console.error(`[WindtunnelFreeze] WARNING: --lc-dir not provided — corpus completeness assertion (S4) skipped.`);
|
|
57
|
+
console.error(` Set TOTEM_LC_DIR or pass --lc-dir to enable completeness check.`);
|
|
58
|
+
}
|
|
59
|
+
// Compute gate-1-scoped fixtureSha (OQ3) over BOTH control dirs so the lock's
|
|
60
|
+
// single fixtureSha protects positive AND negative fixtures.
|
|
61
|
+
const controlDirs = [
|
|
62
|
+
path.join(repoRoot, lock.controls.positiveRef),
|
|
63
|
+
path.join(repoRoot, lock.controls.negativeRef),
|
|
64
|
+
];
|
|
65
|
+
if (controlDirs.some((d) => fs.existsSync(d))) {
|
|
66
|
+
const fixtureSha = computeFixtureSha(controlDirs, repoRoot, safeExec);
|
|
67
|
+
if (fixtureSha && fixtureSha !== lock.controls.integrity.fixtureSha) {
|
|
68
|
+
console.error(`[WindtunnelFreeze] WARNING: controls.integrity.fixtureSha in lock (${lock.controls.integrity.fixtureSha}) does not match computed hash (${fixtureSha})`);
|
|
69
|
+
console.error(` Update the lock with fixtureSha: "${fixtureSha}" and re-freeze.`);
|
|
70
|
+
}
|
|
71
|
+
else if (fixtureSha) {
|
|
72
|
+
console.error(`[WindtunnelFreeze] Fixture integrity verified: ${fixtureSha}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
console.error(`[WindtunnelFreeze] Control dirs [${controlDirs.join(', ')}] do not exist — integrity check skipped.`);
|
|
77
|
+
}
|
|
78
|
+
console.error(`[WindtunnelFreeze] DONE — lock at ${lockPath} is schema-valid.`);
|
|
79
|
+
console.error(` Commit the lock file to establish the freeze proof (C3).`);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* `totem spine windtunnel run`
|
|
83
|
+
*
|
|
84
|
+
* Reads and validates the lock, derives the freeze proof from git history (C3),
|
|
85
|
+
* rejects a harness lock when `--phase certifying` is passed (P1), builds the
|
|
86
|
+
* shared post-image readStrategy, runs the engine (mock for harness phase),
|
|
87
|
+
* scores the result, and prints the verdict.
|
|
88
|
+
*
|
|
89
|
+
* Exit codes: 0 = PASS, 1 = FAIL / HONEST-NEGATIVE / needs-adjudication.
|
|
90
|
+
*/
|
|
91
|
+
export async function runCommand(opts) {
|
|
92
|
+
const { WindtunnelLockSchema, safeExec, resolveGitRoot, TotemError, scoreWindtunnel } = await import('@mmnto/totem');
|
|
93
|
+
const cwd = process.cwd();
|
|
94
|
+
const repoRoot = resolveGitRoot(cwd) ?? cwd;
|
|
95
|
+
const lockPath = opts.lockPath
|
|
96
|
+
? path.resolve(cwd, opts.lockPath)
|
|
97
|
+
: path.join(repoRoot, LOCK_REL_PATH);
|
|
98
|
+
const lcDir = opts.lcDir ?? process.env['TOTEM_LC_DIR'];
|
|
99
|
+
const requestedPhase = opts.phase;
|
|
100
|
+
// Validate --phase up front: an unrecognized value (e.g. a typo "certifyng")
|
|
101
|
+
// would otherwise slip past the P1 guard below (which only matches the exact
|
|
102
|
+
// string "certifying") and silently run as if no phase were requested.
|
|
103
|
+
if (requestedPhase !== undefined &&
|
|
104
|
+
requestedPhase !== 'harness' &&
|
|
105
|
+
requestedPhase !== 'certifying') {
|
|
106
|
+
throw new TotemError('CONFIG_INVALID', `Invalid --phase "${requestedPhase}" — must be "harness" or "certifying".`, 'Pass --phase certifying (or harness), or omit it.');
|
|
107
|
+
}
|
|
108
|
+
// Read + validate the lock
|
|
109
|
+
let rawJson;
|
|
110
|
+
try {
|
|
111
|
+
rawJson = fs.readFileSync(lockPath, 'utf-8');
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
throw new TotemError('CONFIG_INVALID', `Wind-tunnel lock not found at ${lockPath}`, `Run 'totem spine windtunnel freeze' first.`);
|
|
115
|
+
}
|
|
116
|
+
let rawObj;
|
|
117
|
+
try {
|
|
118
|
+
rawObj = JSON.parse(rawJson);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
throw new TotemError('CONFIG_INVALID', `Wind-tunnel lock at ${lockPath} is not valid JSON`, 'Fix the JSON syntax and retry.');
|
|
122
|
+
}
|
|
123
|
+
const parsed = WindtunnelLockSchema.safeParse(rawObj);
|
|
124
|
+
if (!parsed.success) {
|
|
125
|
+
const issues = parsed.error.issues
|
|
126
|
+
.map((i) => ` • ${i.path.join('.')}: ${i.message}`)
|
|
127
|
+
.join('\n');
|
|
128
|
+
throw new TotemError('CONFIG_INVALID', `Wind-tunnel lock schema validation failed:\n${issues}`, 'Fix the lock file and retry.');
|
|
129
|
+
}
|
|
130
|
+
const lock = parsed.data;
|
|
131
|
+
// P1: phase rejection — a certifying run rejects a harness-phase lock.
|
|
132
|
+
if (requestedPhase === 'certifying' && lock.phase === 'harness') {
|
|
133
|
+
throw new TotemError('CONFIG_INVALID', `Phase mismatch: --phase certifying requested but the lock is phase "harness" (P1).`, `Re-freeze with a "certifying" phase lock after the real rule set is minted (post strategy#516).`);
|
|
134
|
+
}
|
|
135
|
+
// C3: derive freeze proof from git history (not a self-embedded trusted field).
|
|
136
|
+
verifyFreezeProof(lockPath, repoRoot, safeExec);
|
|
137
|
+
// C6 / §5: fixture integrity is MANDATORY over BOTH control dirs (positive
|
|
138
|
+
// AND negative) — a missing/empty control dir while the lock declares a
|
|
139
|
+
// fixtureSha is corpus shrinkage / tampering, not a reason to skip.
|
|
140
|
+
// verifyControlIntegrity throws loud on missing/empty/mismatch.
|
|
141
|
+
const controlDirs = [
|
|
142
|
+
path.join(repoRoot, lock.controls.positiveRef),
|
|
143
|
+
path.join(repoRoot, lock.controls.negativeRef),
|
|
144
|
+
];
|
|
145
|
+
verifyControlIntegrity(controlDirs, lock.controls.integrity.fixtureSha, repoRoot, safeExec);
|
|
146
|
+
console.error(`[WindtunnelRun] Lock valid — phase: ${lock.phase}`);
|
|
147
|
+
// Build the shared post-image readStrategy (S1/C1).
|
|
148
|
+
// For the harness phase (no lc clone required — mock engine), we use a
|
|
149
|
+
// simple null-returning strategy (all files → skip classification = fail-open).
|
|
150
|
+
// When lcDir is provided, resolve post-image blobs from the lc clone.
|
|
151
|
+
const readStrategy = buildReadStrategy(lcDir, lock.corpus.selectionRule.asOfCommit, safeExec);
|
|
152
|
+
// Enrich with AST context for any additions (harness: no diff, so no additions).
|
|
153
|
+
// In the real certifying run, the caller would build additions from PR diffs
|
|
154
|
+
// and pass them through enrichWithAstContext + applyAstRulesToAdditions with
|
|
155
|
+
// the shared readStrategy (S1/C1 — same content for regex astContext + AST).
|
|
156
|
+
// Run the engine — harness phase uses mock engines.
|
|
157
|
+
const { mintedRuleIds, firings, groundTruth, positiveControlTargets } = await runMockEngine(lock, readStrategy);
|
|
158
|
+
// Score
|
|
159
|
+
const verdict = scoreWindtunnel({
|
|
160
|
+
firings,
|
|
161
|
+
groundTruth,
|
|
162
|
+
positiveControlTargets,
|
|
163
|
+
mintedRuleIds,
|
|
164
|
+
cullRateThreshold: lock.cullRateThreshold,
|
|
165
|
+
exposureFloors: {
|
|
166
|
+
activeRulesEvaluated: lock.exposureDenominator.activeRulesEvaluated.floor,
|
|
167
|
+
filesTouchedInWindow: lock.exposureDenominator.filesTouchedInWindow.floor,
|
|
168
|
+
positiveControlsExercised: lock.exposureDenominator.positiveControlsExercised.floor,
|
|
169
|
+
},
|
|
170
|
+
actualExposure: {
|
|
171
|
+
activeRulesEvaluated: mintedRuleIds.length,
|
|
172
|
+
filesTouchedInWindow: 0,
|
|
173
|
+
positiveControlsExercised: positiveControlTargets.length,
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
// Print verdict — exposure tuple never collapsed
|
|
177
|
+
console.log(`WindtunnelVerdict: ${verdict.verdict}`);
|
|
178
|
+
console.log(` precision: ${verdict.precision.toFixed(4)} (over surviving rules)`);
|
|
179
|
+
console.log(` mintedRuleCount: ${verdict.mintedRuleCount}`);
|
|
180
|
+
console.log(` culledCount: ${verdict.culledCount}`);
|
|
181
|
+
console.log(` survivingRuleCount:${verdict.survivingRuleCount}`);
|
|
182
|
+
console.log(` exposureTuple: [${verdict.exposureTuple.join(', ')}] (activeRules, filesTouched, positiveControls)`);
|
|
183
|
+
console.log(` nonVacuity: ${verdict.nonVacuity}`);
|
|
184
|
+
if (verdict.cullLedger.length > 0) {
|
|
185
|
+
console.log(` cullLedger (${verdict.cullLedger.length} entries):`);
|
|
186
|
+
for (const entry of verdict.cullLedger) {
|
|
187
|
+
console.log(` • rule ${entry.ruleId} culled on pr#${entry.pr} (${entry.reason})`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (verdict.needsAdjudication.length > 0) {
|
|
191
|
+
console.log(` needsAdjudication (${verdict.needsAdjudication.length} firing(s)):`);
|
|
192
|
+
for (const id of verdict.needsAdjudication) {
|
|
193
|
+
console.log(` • ${id}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// Exit non-zero on FAIL / HONEST-NEGATIVE / needs-adjudication
|
|
197
|
+
if (verdict.verdict !== 'PASS' || verdict.needsAdjudication.length > 0) {
|
|
198
|
+
process.exitCode = 1;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Boolean predicate: is `ancestor` an ancestor of `descendant` in the repo at
|
|
203
|
+
* `cwd`? `git merge-base --is-ancestor` encodes the answer in its exit code
|
|
204
|
+
* (0 = yes, 1 = no), so a non-zero exit is a legitimate FALSE, not an error to
|
|
205
|
+
* swallow. Any other failure (bad ref, repo unreadable) re-throws so it is not
|
|
206
|
+
* masked as a clean "false".
|
|
207
|
+
*/
|
|
208
|
+
export function isCommitAncestor(ancestor, descendant, cwd, safeExec) {
|
|
209
|
+
try {
|
|
210
|
+
safeExec('git', ['merge-base', '--is-ancestor', ancestor, descendant], { cwd });
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
const status = err.status;
|
|
215
|
+
if (status === 1)
|
|
216
|
+
return false;
|
|
217
|
+
throw new Error(`Wind-tunnel: 'git merge-base --is-ancestor ${ancestor} ${descendant}' failed in ${cwd}: ${err instanceof Error ? err.message : String(err)}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Build a post-image readStrategy (S1/C1).
|
|
222
|
+
* When lcDir is provided, resolves blobs via `git show <asOfCommit>:<path>` in
|
|
223
|
+
* the lc clone. Throws on unresolvable blob for an evaluated added file (C2).
|
|
224
|
+
* When lcDir is absent, returns null for all files (fail-open — harness mock).
|
|
225
|
+
*/
|
|
226
|
+
export function buildReadStrategy(lcDir, asOfCommit, safeExec) {
|
|
227
|
+
if (!lcDir) {
|
|
228
|
+
return async () => null;
|
|
229
|
+
}
|
|
230
|
+
return async (file) => {
|
|
231
|
+
const normalized = file.replace(/\\/g, '/');
|
|
232
|
+
try {
|
|
233
|
+
const content = safeExec('git', ['show', `${asOfCommit}:${normalized}`], { cwd: lcDir });
|
|
234
|
+
return content;
|
|
235
|
+
}
|
|
236
|
+
catch (err) {
|
|
237
|
+
// C2: missing blob for an evaluated added file is a hard error, not a
|
|
238
|
+
// silent no-match (corpus shrinkage).
|
|
239
|
+
throw new Error(`Wind-tunnel readStrategy: blob unresolvable for ${file} at ${asOfCommit} in ${lcDir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Verify the freeze proof from git history (C3).
|
|
245
|
+
* `git log --format=%H -- <lockPath>` must return at least one commit that is
|
|
246
|
+
* an ancestor of HEAD. The lock blob at that commit must be byte-identical to
|
|
247
|
+
* the current lock.
|
|
248
|
+
*/
|
|
249
|
+
export function verifyFreezeProof(lockPath, repoRoot, safeExec) {
|
|
250
|
+
const relLockPath = path.relative(repoRoot, lockPath).replace(/\\/g, '/');
|
|
251
|
+
let logOutput;
|
|
252
|
+
try {
|
|
253
|
+
logOutput = safeExec('git', ['log', '--format=%H', '--', relLockPath], { cwd: repoRoot });
|
|
254
|
+
}
|
|
255
|
+
catch (err) {
|
|
256
|
+
throw new Error(`Wind-tunnel freeze proof: git log failed for ${relLockPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
257
|
+
}
|
|
258
|
+
const commits = logOutput
|
|
259
|
+
.split('\n')
|
|
260
|
+
.map((l) => l.trim())
|
|
261
|
+
.filter((l) => COMMIT_SHA_REGEX.test(l));
|
|
262
|
+
if (commits.length === 0) {
|
|
263
|
+
throw new Error(`Wind-tunnel freeze proof: no commits found for ${relLockPath} — the lock has never been committed. Run 'totem spine windtunnel freeze' and commit the lock first (C3).`);
|
|
264
|
+
}
|
|
265
|
+
const freezeCommit = commits[0];
|
|
266
|
+
// Verify freezeCommit is an ancestor of HEAD
|
|
267
|
+
try {
|
|
268
|
+
safeExec('git', ['merge-base', '--is-ancestor', freezeCommit, 'HEAD'], { cwd: repoRoot });
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
throw new Error(`Wind-tunnel freeze proof: lock commit ${freezeCommit} is not an ancestor of HEAD (C3 — tampered or wrong branch).`);
|
|
272
|
+
}
|
|
273
|
+
// Verify blob identity via git object hashes (CRLF-immune, matching the
|
|
274
|
+
// .wind-tunnel-sha discipline) rather than a raw string compare — the latter
|
|
275
|
+
// spuriously fails on trailing-newline / line-ending normalization because
|
|
276
|
+
// `git show` output and the on-disk working file can differ by EOL alone.
|
|
277
|
+
let workingHash;
|
|
278
|
+
let committedHash;
|
|
279
|
+
try {
|
|
280
|
+
workingHash = safeExec('git', ['hash-object', '--', lockPath], { cwd: repoRoot }).trim();
|
|
281
|
+
committedHash = safeExec('git', ['rev-parse', `${freezeCommit}:${relLockPath}`], {
|
|
282
|
+
cwd: repoRoot,
|
|
283
|
+
}).trim();
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
throw new Error(`Wind-tunnel freeze proof: cannot resolve lock blob at ${freezeCommit}: ${err instanceof Error ? err.message : String(err)}`);
|
|
287
|
+
}
|
|
288
|
+
if (workingHash !== committedHash) {
|
|
289
|
+
throw new Error(`Wind-tunnel freeze proof: current lock differs from the committed blob at ${freezeCommit} (C3 — lock was modified after freeze).`);
|
|
290
|
+
}
|
|
291
|
+
console.error(`[WindtunnelRun] Freeze proof verified: lock committed at ${freezeCommit}`);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Compute gate-1-scoped fixtureSha via `git hash-object` over ALL control dirs
|
|
295
|
+
* (positive AND negative), so the single fixtureSha protects every fixture
|
|
296
|
+
* (OQ3 — do NOT extend the existing .totem/tests FIXTURE_DIR).
|
|
297
|
+
*/
|
|
298
|
+
export function computeFixtureSha(controlDirs, repoRoot, safeExec) {
|
|
299
|
+
// No try/catch around the body: a hash/IO failure must propagate so the
|
|
300
|
+
// integrity check fails LOUD (Tenet 4 — a silently null'd hash would skip the
|
|
301
|
+
// run-time tamper gate, the §5 no-silent-shrink discipline this design rests
|
|
302
|
+
// on). The only "soft" case is no files across all dirs, returned as null and
|
|
303
|
+
// handled by callers (controls absent / not yet populated at harness time).
|
|
304
|
+
//
|
|
305
|
+
// Hashes EVERY provided control dir (positive AND negative) so the single
|
|
306
|
+
// fixtureSha protects all fixtures — a tampered negative control (the cull
|
|
307
|
+
// guard) is as detectable as a tampered positive one.
|
|
308
|
+
const entries = [];
|
|
309
|
+
for (const dir of controlDirs) {
|
|
310
|
+
if (!fs.existsSync(dir))
|
|
311
|
+
continue;
|
|
312
|
+
const dirKey = path.basename(dir.replace(/[/\\]+$/, ''));
|
|
313
|
+
const files = fs
|
|
314
|
+
.readdirSync(dir, { recursive: true })
|
|
315
|
+
.map((f) => (f instanceof Buffer ? f.toString('utf-8') : String(f)))
|
|
316
|
+
// Normalize to forward-slash (A3): Windows readdir yields '\' separators,
|
|
317
|
+
// which would otherwise reorder the sort and change the digest per-platform.
|
|
318
|
+
.map((f) => f.replace(/\\/g, '/'))
|
|
319
|
+
.filter((f) => !fs.statSync(path.join(dir, f)).isDirectory());
|
|
320
|
+
for (const f of files) {
|
|
321
|
+
// Dir-qualified key: keeps cross-dir order stable AND makes a file moving
|
|
322
|
+
// between positive/ and negative/ change the aggregate (tamper-evident).
|
|
323
|
+
entries.push({ key: `${dirKey}/${f}`, fullPath: path.join(dir, f) });
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (entries.length === 0)
|
|
327
|
+
return null;
|
|
328
|
+
entries.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
|
|
329
|
+
// `git hash-object <path>` applies the repo's clean/EOL filter by default
|
|
330
|
+
// (verified: a CRLF file under `* text=auto` hashes identically to its LF
|
|
331
|
+
// form), so each per-file hash is CRLF-immune WITHOUT --filters (and
|
|
332
|
+
// --no-filters would defeat that immunity).
|
|
333
|
+
const combined = entries
|
|
334
|
+
.map((e) => `${e.key}:${safeExec('git', ['hash-object', '--', e.fullPath], { cwd: repoRoot }).trim()}`)
|
|
335
|
+
.join('\n');
|
|
336
|
+
return safeExec('git', ['hash-object', '--stdin'], {
|
|
337
|
+
cwd: repoRoot,
|
|
338
|
+
input: combined,
|
|
339
|
+
}).trim();
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Verify control-fixture integrity (C6 / §5 no-silent-shrink). The lock ALWAYS
|
|
343
|
+
* declares a fixtureSha (schema-required) covering ALL control dirs (positive
|
|
344
|
+
* AND negative), so any missing/empty control dir or hash mismatch is corpus
|
|
345
|
+
* shrinkage / tampering — it MUST fail loud, never silently pass.
|
|
346
|
+
*/
|
|
347
|
+
export function verifyControlIntegrity(controlDirs, expectedSha, repoRoot, safeExec) {
|
|
348
|
+
for (const dir of controlDirs) {
|
|
349
|
+
if (!fs.existsSync(dir)) {
|
|
350
|
+
throw new Error(`Wind-tunnel integrity: control dir ${dir} is missing but the lock declares fixtureSha ${expectedSha} (§5 no-silent-shrink). Restore the fixtures or re-freeze the lock.`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const actualSha = computeFixtureSha(controlDirs, repoRoot, safeExec);
|
|
354
|
+
if (actualSha === null) {
|
|
355
|
+
throw new Error(`Wind-tunnel integrity: control dirs [${controlDirs.join(', ')}] are empty but the lock declares fixtureSha ${expectedSha} (§5 no-silent-shrink). Restore the fixtures or re-freeze the lock.`);
|
|
356
|
+
}
|
|
357
|
+
if (actualSha !== expectedSha) {
|
|
358
|
+
throw new Error(`Wind-tunnel integrity: control fixtures changed — expected ${expectedSha}, got ${actualSha}. Revert the tampering or re-freeze with the updated fixtureSha.`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Assert corpus completeness (S4): resolvedPrs === selectionRule(asOfCommit).
|
|
363
|
+
* In the harness phase this is a structural check only (no real lc API call).
|
|
364
|
+
*/
|
|
365
|
+
export async function assertCorpusCompleteness(lock, lcDir, repoRoot, safeExec) {
|
|
366
|
+
// Verify the lc clone is accessible + at the correct asOfCommit.
|
|
367
|
+
// `merge-base --is-ancestor` exits non-zero to MEAN "not an ancestor" — that
|
|
368
|
+
// is a boolean predicate, not an error, so it gets its own probe helper.
|
|
369
|
+
const asOfCommit = lock.corpus.selectionRule.asOfCommit;
|
|
370
|
+
let headSha;
|
|
371
|
+
try {
|
|
372
|
+
headSha = safeExec('git', ['rev-parse', 'HEAD'], { cwd: lcDir }).trim();
|
|
373
|
+
}
|
|
374
|
+
catch (err) {
|
|
375
|
+
// S4: an inaccessible lc clone means freeze-time completeness cannot be
|
|
376
|
+
// proven. The harness phase tolerates this (no real corpus yet) but must
|
|
377
|
+
// surface it loudly — never silently pass off an unverifiable corpus.
|
|
378
|
+
throw new Error(`Wind-tunnel freeze: cannot access lc clone at ${lcDir} to verify corpus completeness (S4): ${err instanceof Error ? err.message : String(err)}. ` +
|
|
379
|
+
`Provide a valid --lc-dir / TOTEM_LC_DIR clone, or omit it to skip the completeness assertion entirely.`);
|
|
380
|
+
}
|
|
381
|
+
const isAncestor = isCommitAncestor(asOfCommit, headSha, lcDir, safeExec);
|
|
382
|
+
if (!isAncestor) {
|
|
383
|
+
console.error(`[WindtunnelFreeze] WARNING: asOfCommit ${asOfCommit} is not an ancestor of lc HEAD ${headSha} — corpus completeness assertion may be unreliable.`);
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
console.error(`[WindtunnelFreeze] lc clone at ${lcDir} includes asOfCommit ${asOfCommit} ✓`);
|
|
387
|
+
}
|
|
388
|
+
// Structural completeness: count + warn (the actual re-derivation of the full
|
|
389
|
+
// code-touching PR set requires querying the lc repo's merge history, which
|
|
390
|
+
// is operator-level work; the tool asserts the lock is non-empty and warns
|
|
391
|
+
// if the resolvedPrs count seems low).
|
|
392
|
+
const prCount = lock.corpus.resolvedPrs.length;
|
|
393
|
+
console.error(`[WindtunnelFreeze] resolvedPrs: ${prCount} entries (completeness requires operator verification against selectionRule)`);
|
|
394
|
+
void repoRoot; // used in freeze proof above
|
|
395
|
+
}
|
|
396
|
+
// ─── Mock engine (harness phase) ─────────────────────
|
|
397
|
+
/**
|
|
398
|
+
* Run mock engines for harness-phase validation (OQ2).
|
|
399
|
+
* Returns firings + ground-truth labels that exercise all verdict paths:
|
|
400
|
+
* PASS, HONEST-NEGATIVE (exposure floor, unlabeled), FAIL (FP, vacuity).
|
|
401
|
+
* For the actual harness lock (mintedRuleIds ≈ []), this returns empty results.
|
|
402
|
+
*/
|
|
403
|
+
async function runMockEngine(lock, _readStrategy) {
|
|
404
|
+
const { firingLabelId } = await import('@mmnto/totem');
|
|
405
|
+
// In harness phase, there are no real minted rules yet (strategy#516 pending)
|
|
406
|
+
const mintedRuleIds = [];
|
|
407
|
+
const firings = [];
|
|
408
|
+
const groundTruth = new Map();
|
|
409
|
+
const positiveControlTargets = [];
|
|
410
|
+
// Emit a diagnostic so operators know the mock engine ran
|
|
411
|
+
console.error(`[WindtunnelRun] Mock engine active (harness phase — no compiled rules yet; strategy#516 pending).`);
|
|
412
|
+
console.error(` resolvedPrs count: ${lock.corpus.resolvedPrs.length}`);
|
|
413
|
+
// Exercise firingLabelId to validate A2 path in harness
|
|
414
|
+
if (lock.corpus.resolvedPrs.length > 0) {
|
|
415
|
+
const samplePr = lock.corpus.resolvedPrs[0];
|
|
416
|
+
const sampleId = firingLabelId('mock-rule', samplePr.pr, 'sample/file.ts', 'sample line');
|
|
417
|
+
console.error(` sample firingLabelId (A2 validation): ${sampleId}`);
|
|
418
|
+
}
|
|
419
|
+
return { mintedRuleIds, firings, groundTruth, positiveControlTargets };
|
|
420
|
+
}
|
|
421
|
+
//# sourceMappingURL=spine-windtunnel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spine-windtunnel.js","sourceRoot":"","sources":["../../src/commands/spine-windtunnel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spine-windtunnel.test.d.ts","sourceRoot":"","sources":["../../src/commands/spine-windtunnel.test.ts"],"names":[],"mappings":""}
|