@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.
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=spine-windtunnel.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-windtunnel.test.d.ts","sourceRoot":"","sources":["../../src/commands/spine-windtunnel.test.ts"],"names":[],"mappings":""}