@mmnto/cli 1.72.1 → 1.73.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.
Files changed (35) hide show
  1. package/dist/commands/spine-cert-run-corpus.d.ts +43 -11
  2. package/dist/commands/spine-cert-run-corpus.d.ts.map +1 -1
  3. package/dist/commands/spine-cert-run-corpus.js +96 -41
  4. package/dist/commands/spine-cert-run-corpus.js.map +1 -1
  5. package/dist/commands/spine-corpus-disposition-source.d.ts +179 -0
  6. package/dist/commands/spine-corpus-disposition-source.d.ts.map +1 -0
  7. package/dist/commands/spine-corpus-disposition-source.js +237 -0
  8. package/dist/commands/spine-corpus-disposition-source.js.map +1 -0
  9. package/dist/commands/spine-corpus-disposition-source.test.d.ts +2 -0
  10. package/dist/commands/spine-corpus-disposition-source.test.d.ts.map +1 -0
  11. package/dist/commands/spine-corpus-disposition-source.test.js +170 -0
  12. package/dist/commands/spine-corpus-disposition-source.test.js.map +1 -0
  13. package/dist/commands/spine-derive-labels.d.ts +12 -0
  14. package/dist/commands/spine-derive-labels.d.ts.map +1 -0
  15. package/dist/commands/spine-derive-labels.js +142 -0
  16. package/dist/commands/spine-derive-labels.js.map +1 -0
  17. package/dist/commands/spine-derive-labels.test.d.ts +2 -0
  18. package/dist/commands/spine-derive-labels.test.d.ts.map +1 -0
  19. package/dist/commands/spine-derive-labels.test.js +157 -0
  20. package/dist/commands/spine-derive-labels.test.js.map +1 -0
  21. package/dist/commands/spine-fetch-dispositions.d.ts +27 -0
  22. package/dist/commands/spine-fetch-dispositions.d.ts.map +1 -0
  23. package/dist/commands/spine-fetch-dispositions.js +104 -0
  24. package/dist/commands/spine-fetch-dispositions.js.map +1 -0
  25. package/dist/commands/spine-fetch-dispositions.test.d.ts +2 -0
  26. package/dist/commands/spine-fetch-dispositions.test.d.ts.map +1 -0
  27. package/dist/commands/spine-fetch-dispositions.test.js +155 -0
  28. package/dist/commands/spine-fetch-dispositions.test.js.map +1 -0
  29. package/dist/commands/spine-windtunnel.d.ts +19 -0
  30. package/dist/commands/spine-windtunnel.d.ts.map +1 -1
  31. package/dist/commands/spine-windtunnel.js +84 -50
  32. package/dist/commands/spine-windtunnel.js.map +1 -1
  33. package/dist/index.js +35 -0
  34. package/dist/index.js.map +1 -1
  35. package/package.json +2 -2
@@ -0,0 +1,157 @@
1
+ import * as fs from 'node:fs';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
5
+ import { deriveLabelsFromDispositions } from '@mmnto/totem';
6
+ import { deriveLabelsCommand } from './spine-derive-labels.js';
7
+ import { buildCertifyingFirings } from './spine-windtunnel.js';
8
+ const SHA40 = (n) => n.toString(16).padStart(40, '0');
9
+ /** A regex rule firing on `forbiddenCall(` (a made-up token — won't trip totem's own lint). */
10
+ function forbiddenCallRule() {
11
+ return {
12
+ lessonHash: 'rule-fc',
13
+ lessonHeading: 'No forbiddenCall',
14
+ pattern: 'forbiddenCall\\(',
15
+ message: 'forbidden call',
16
+ engine: 'regex',
17
+ compiledAt: '2026-06-22T00:00:00.000Z',
18
+ };
19
+ }
20
+ /** A unified diff that ADDS the given lines to `file` from line 1. */
21
+ function diffAdding(lines, file) {
22
+ return [
23
+ `diff --git a/${file} b/${file}`,
24
+ `--- a/${file}`,
25
+ `+++ b/${file}`,
26
+ `@@ -0,0 +1,${lines.length} @@`,
27
+ ...lines.map((l) => `+${l}`),
28
+ ].join('\n');
29
+ }
30
+ // ─── Equivalence: deriver labelIds ⊆ the run's buildFirings labelIds (panel) ──
31
+ //
32
+ // Both the certifying run and the deriver enumerate firings via the SAME
33
+ // `buildCertifyingFirings` — so the answer-key labelIds the deriver mints are the
34
+ // ones the run looks up. This proves the join end-to-end over REAL firings (zero
35
+ // network: an in-memory readStrategy stub) + the determinism of the shared path.
36
+ describe('5d-iii equivalence — buildCertifyingFirings ↔ deriveLabelsFromDispositions', () => {
37
+ const rules = [forbiddenCallRule()];
38
+ const prDiffs = [
39
+ { pr: 7, diff: diffAdding(['forbiddenCall()'], 'src/x.ts'), controlKind: 'corpus' },
40
+ ];
41
+ const readStrategy = async () => 'forbiddenCall()\n';
42
+ it('enumerates ≥1 firing and the deriver keys ONLY on real firing labelIds', async () => {
43
+ const built = await buildCertifyingFirings({
44
+ rules,
45
+ prDiffs,
46
+ readStrategy,
47
+ logPrefix: '[Test]',
48
+ });
49
+ expect(built.firings.length).toBeGreaterThan(0);
50
+ const firingLabelIds = new Set(built.firings.map((f) => f.labelId));
51
+ const firing = built.firings[0];
52
+ const dispositions = [
53
+ {
54
+ pr: 7,
55
+ mergeCommitSha: SHA40(7),
56
+ threads: [
57
+ {
58
+ path: 'src/x.ts',
59
+ // bind by the firing's own added content (what GitHub's diffHunk would carry).
60
+ diffHunk: `@@ -0,0 +1,1 @@\n+${firing.matchedLine}`,
61
+ isResolved: false,
62
+ isOutdated: false,
63
+ comments: [{ author: 'Jane', body: 'fixed' }],
64
+ },
65
+ ],
66
+ },
67
+ ];
68
+ const { labels } = deriveLabelsFromDispositions(built.firings, dispositions);
69
+ // every emitted labelId is a real firing labelId the run will look up (⊆).
70
+ for (const id of Object.keys(labels)) {
71
+ expect(firingLabelIds.has(id)).toBe(true);
72
+ }
73
+ expect(labels[firing.labelId]).toBe('TP');
74
+ });
75
+ it('is deterministic — two runs of the shared firing-setup mint identical labelIds', async () => {
76
+ const a = await buildCertifyingFirings({ rules, prDiffs, readStrategy, logPrefix: '[Test]' });
77
+ const b = await buildCertifyingFirings({ rules, prDiffs, readStrategy, logPrefix: '[Test]' });
78
+ expect(b.firings.map((f) => f.labelId).sort()).toEqual(a.firings.map((f) => f.labelId).sort());
79
+ });
80
+ });
81
+ // ─── Integrity gates (command-level; no git needed — the gate fires first) ────
82
+ function writeLockFixture(dir, integrity) {
83
+ const lock = {
84
+ schema: 'windtunnel.lock.v1',
85
+ canonicalPath: '.totem/spine/gate-1/windtunnel.lock.json',
86
+ gate: 'gate-1',
87
+ phase: 'certifying',
88
+ corpus: {
89
+ repo: 'mmnto-ai/liquid-city',
90
+ selectionRule: {
91
+ state: 'merged',
92
+ predicate: 'code-touching',
93
+ window: { type: 'all' },
94
+ asOfCommit: 'a'.repeat(40),
95
+ codePathClassifier: { includeGlobs: ['**/*.ts'], excludeGlobs: [] },
96
+ },
97
+ resolvedPrs: [3, 5].map((n) => ({
98
+ pr: n,
99
+ mergeCommit: SHA40(n),
100
+ baseSha: 'b'.repeat(40),
101
+ headSha: 'd'.repeat(40),
102
+ })),
103
+ },
104
+ fpDefinition: { rubricRef: 'r', groundTruthRef: 'g', adjudicator: 'a', precisionFloor: 1.0 },
105
+ controls: {
106
+ positiveRef: 'controls/positive/',
107
+ negativeRef: 'controls/negative/',
108
+ integrity: { mechanism: 'sha', fixtureSha: 'e'.repeat(40), ...integrity },
109
+ },
110
+ cullRateThreshold: 0.5,
111
+ exposureDenominator: {
112
+ activeRulesEvaluated: { floor: 2 },
113
+ filesTouchedInWindow: { floor: 0 },
114
+ positiveControlsExercised: { floor: 0 },
115
+ },
116
+ };
117
+ fs.writeFileSync(path.join(dir, 'windtunnel.lock.json'), JSON.stringify(lock, null, 2));
118
+ }
119
+ describe('deriveLabelsCommand — integrity gates', () => {
120
+ let dir;
121
+ let savedLcDir;
122
+ beforeEach(() => {
123
+ dir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-derive-'));
124
+ // The no-lc-dir guard reads TOTEM_LC_DIR — neutralize the ambient env for tests.
125
+ savedLcDir = process.env['TOTEM_LC_DIR'];
126
+ delete process.env['TOTEM_LC_DIR'];
127
+ });
128
+ afterEach(() => {
129
+ if (savedLcDir === undefined)
130
+ delete process.env['TOTEM_LC_DIR'];
131
+ else
132
+ process.env['TOTEM_LC_DIR'] = savedLcDir;
133
+ fs.rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
134
+ });
135
+ it('fails loud when no lc clone is provided (the answer key would be silently empty)', async () => {
136
+ writeLockFixture(dir, { corpusDispositionsSha: 'f'.repeat(64) });
137
+ await expect(deriveLabelsCommand({ lockPath: path.join(dir, 'windtunnel.lock.json'), cwd: dir })).rejects.toThrow(/no lc clone/i);
138
+ });
139
+ it('hard-fails when the lock is missing corpusDispositionsSha (un-gated provenance)', async () => {
140
+ writeLockFixture(dir, {}); // no corpusDispositionsSha stamped
141
+ await expect(deriveLabelsCommand({
142
+ lockPath: path.join(dir, 'windtunnel.lock.json'),
143
+ lcDir: dir, // a real dir; the gate fires before any git use
144
+ cwd: dir,
145
+ })).rejects.toThrow(/corpusDispositionsSha/);
146
+ });
147
+ it('hard-fails when corpus-dispositions.json does not match the stamped digest', async () => {
148
+ writeLockFixture(dir, { corpusDispositionsSha: 'a'.repeat(64) }); // a digest the file won't match
149
+ fs.writeFileSync(path.join(dir, 'corpus-dispositions.json'), '[]\n', 'utf-8');
150
+ await expect(deriveLabelsCommand({
151
+ lockPath: path.join(dir, 'windtunnel.lock.json'),
152
+ lcDir: dir,
153
+ cwd: dir,
154
+ })).rejects.toThrow(/integrity FAILED/i);
155
+ });
156
+ });
157
+ //# sourceMappingURL=spine-derive-labels.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-derive-labels.test.js","sourceRoot":"","sources":["../../src/commands/spine-derive-labels.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { CorpusDisposition } from '@mmnto/totem';
2
+ /** The held-out disposition source — the live adapter in the CLI, a fake in tests. */
3
+ export interface CorpusDispositionSource {
4
+ fetch(pr: number): Promise<CorpusDisposition>;
5
+ }
6
+ export interface FetchDispositionsOptions {
7
+ /** Path to the wind-tunnel lock (default `.totem/spine/gate-1/windtunnel.lock.json`). */
8
+ lockPath?: string;
9
+ /** Gate-1 output dir (default: the lock's dir). */
10
+ outputDir?: string;
11
+ /** Working dir (default `process.cwd()`; injected for tests). */
12
+ cwd?: string;
13
+ /** Injected source (tests). In the live CLI it is built from the lock's repo. */
14
+ source?: CorpusDispositionSource;
15
+ }
16
+ /**
17
+ * Compute the held-out CORPUS PRs whose dispositions label firings: `heldOutPrs`
18
+ * minus the positive/negative controls (positives are structural-TP; negatives
19
+ * are culled — neither reads a disposition). Deterministic ascending order.
20
+ */
21
+ export declare function corpusHeldOutPrs(split: {
22
+ heldOutPrs: number[];
23
+ positiveControlPrs: number[];
24
+ negativeControlPrs: number[];
25
+ }): number[];
26
+ export declare function fetchDispositionsCommand(opts: FetchDispositionsOptions): Promise<void>;
27
+ //# sourceMappingURL=spine-fetch-dispositions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-fetch-dispositions.d.ts","sourceRoot":"","sources":["../../src/commands/spine-fetch-dispositions.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAMtD,sFAAsF;AACtF,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,wBAAwB;IACvC,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,MAAM,CAAC,EAAE,uBAAuB,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B,GAAG,MAAM,EAAE,CAGX;AAED,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgH5F"}
@@ -0,0 +1,104 @@
1
+ // ─── #709 ground-truth deriver — slice 5d-ii: the fetch-dispositions command ──
2
+ //
3
+ // `totem spine windtunnel fetch-dispositions [--lock-path] [--output-dir]`
4
+ // freezes `corpus-dispositions.json` — the held-out CORPUS PRs' review threads,
5
+ // span-anchored — and stamps `controls.integrity.corpusDispositionsSha` into the
6
+ // lock. A by-hand, live producer step (like `record`): NEVER CI (the adapter's
7
+ // hard-gate enforces it). The certifying RUN never touches this; only the deriver
8
+ // (5d-iii) reads the frozen file. This module is the I/O driver (load → fetch →
9
+ // canonical write → stamp); the fetch + mapping live in the adapter, the schema
10
+ // in core.
11
+ import { createHash } from 'node:crypto';
12
+ import * as fs from 'node:fs';
13
+ import * as path from 'node:path';
14
+ import { CorpusDispositionSourceAdapter } from './spine-corpus-disposition-source.js';
15
+ const sha256Hex = (s) => createHash('sha256').update(s, 'utf-8').digest('hex');
16
+ /**
17
+ * Compute the held-out CORPUS PRs whose dispositions label firings: `heldOutPrs`
18
+ * minus the positive/negative controls (positives are structural-TP; negatives
19
+ * are culled — neither reads a disposition). Deterministic ascending order.
20
+ */
21
+ export function corpusHeldOutPrs(split) {
22
+ const controls = new Set([...split.positiveControlPrs, ...split.negativeControlPrs]);
23
+ return split.heldOutPrs.filter((pr) => !controls.has(pr)).sort((a, b) => a - b);
24
+ }
25
+ export async function fetchDispositionsCommand(opts) {
26
+ const { WindtunnelLockSchema, SplitArtifactSchema, CorpusDispositionsSchema, canonicalStringify, TotemError, } = await import('@mmnto/totem');
27
+ const cwd = opts.cwd ?? process.cwd();
28
+ const lockPath = opts.lockPath
29
+ ? path.resolve(cwd, opts.lockPath)
30
+ : path.resolve(cwd, '.totem/spine/gate-1/windtunnel.lock.json');
31
+ const gate1Dir = opts.outputDir ? path.resolve(cwd, opts.outputDir) : path.dirname(lockPath);
32
+ const readJsonFile = (p) => {
33
+ let raw;
34
+ try {
35
+ raw = fs.readFileSync(p, 'utf-8');
36
+ }
37
+ catch (err) {
38
+ throw new TotemError('CONFIG_INVALID', `fetch-dispositions: required file not found at ${p}`, 'Run `spine windtunnel materialize` first (lock + split.json must exist).', err);
39
+ }
40
+ try {
41
+ return JSON.parse(raw);
42
+ }
43
+ catch (err) {
44
+ throw new TotemError('CONFIG_INVALID', `fetch-dispositions: ${p} is not valid JSON`, 'Fix the JSON and retry.', err);
45
+ }
46
+ };
47
+ const lock = WindtunnelLockSchema.parse(readJsonFile(lockPath));
48
+ const split = SplitArtifactSchema.parse(readJsonFile(path.join(gate1Dir, 'split.json')));
49
+ const prs = corpusHeldOutPrs(split);
50
+ if (prs.length === 0) {
51
+ throw new TotemError('CONFIG_INVALID', 'fetch-dispositions: the split has no held-out CORPUS PRs (all held-out PRs are controls).', 'A cert corpus needs ≥1 non-control held-out PR for the answer key to label.');
52
+ }
53
+ // Build the live source from the lock's repo unless a fake is injected (tests).
54
+ let source = opts.source;
55
+ if (!source) {
56
+ // Require EXACTLY "owner/name" (greptile #2231 P2): a bare `!owner || !name`
57
+ // guard lets "github.com/owner/name" through as owner="github.com" → wrong
58
+ // fetch + a confusing "repo not found". The lock schema is plain z.string(),
59
+ // so this is the only parse-time defense.
60
+ const repoParts = lock.corpus.repo.split('/');
61
+ if (repoParts.length !== 2 || !repoParts[0] || !repoParts[1]) {
62
+ throw new TotemError('CONFIG_INVALID', `fetch-dispositions: lock.corpus.repo "${lock.corpus.repo}" is not "owner/name".`, 'Set corpus.repo in the lock to the "owner/name" form.');
63
+ }
64
+ source = new CorpusDispositionSourceAdapter({ owner: repoParts[0], name: repoParts[1], cwd });
65
+ }
66
+ // Fetch each held-out corpus PR (fail-loud — the freeze is all-or-nothing).
67
+ const dispositions = [];
68
+ for (const pr of prs) {
69
+ dispositions.push(await source.fetch(pr));
70
+ }
71
+ // Sort by pr for a deterministic frozen artifact (fetch order is already ascending,
72
+ // but sort defensively so an injected source can't perturb the on-disk bytes/digest).
73
+ dispositions.sort((a, b) => a.pr - b.pr);
74
+ // Write-side Zod validation (agy) BEFORE writing — never freeze a malformed artifact.
75
+ const validated = CorpusDispositionsSchema.parse(dispositions);
76
+ // Canonical write (sorted-key, LF + trailing newline) — the digest is over these
77
+ // exact on-disk bytes, so a freeze/deriver enforcer can sha256 the file directly.
78
+ fs.mkdirSync(gate1Dir, { recursive: true });
79
+ const dispositionsPath = path.join(gate1Dir, 'corpus-dispositions.json');
80
+ const text = `${canonicalStringify(validated, 2)}\n`;
81
+ const tmp = `${dispositionsPath}.tmp`;
82
+ fs.writeFileSync(tmp, text, 'utf-8');
83
+ fs.renameSync(tmp, dispositionsPath);
84
+ const corpusDispositionsSha = sha256Hex(text);
85
+ // Stamp the provenance digest into the lock (read-modify-write canonical), mirroring
86
+ // how `materialize` stamps prDiffsSha. Idempotent: re-running overwrites the field.
87
+ const stampedLock = {
88
+ ...lock,
89
+ controls: {
90
+ ...lock.controls,
91
+ integrity: { ...lock.controls.integrity, corpusDispositionsSha },
92
+ },
93
+ };
94
+ const lockText = `${canonicalStringify(stampedLock, 2)}\n`;
95
+ const lockTmp = `${lockPath}.tmp`;
96
+ fs.writeFileSync(lockTmp, lockText, 'utf-8');
97
+ fs.renameSync(lockTmp, lockPath);
98
+ const threadCount = validated.reduce((n, d) => n + d.threads.length, 0);
99
+ console.error(`[FetchDispositions] gate1Dir: ${gate1Dir}`);
100
+ console.error(` held-out corpus PRs: ${prs.length} · review threads: ${threadCount}`);
101
+ console.error(` corpusDispositionsSha: ${corpusDispositionsSha} (stamped into ${path.basename(lockPath)})`);
102
+ console.error(` Wrote corpus-dispositions.json (the deriver's frozen provenance).`);
103
+ }
104
+ //# sourceMappingURL=spine-fetch-dispositions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-fetch-dispositions.js","sourceRoot":"","sources":["../../src/commands/spine-fetch-dispositions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=spine-fetch-dispositions.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-fetch-dispositions.test.d.ts","sourceRoot":"","sources":["../../src/commands/spine-fetch-dispositions.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,155 @@
1
+ import { createHash } from 'node:crypto';
2
+ import * as fs from 'node:fs';
3
+ import * as os from 'node:os';
4
+ import * as path from 'node:path';
5
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
6
+ import { corpusHeldOutPrs, fetchDispositionsCommand, } from './spine-fetch-dispositions.js';
7
+ describe('corpusHeldOutPrs', () => {
8
+ it('is heldOut minus the positive/negative controls, sorted ascending', () => {
9
+ expect(corpusHeldOutPrs({
10
+ heldOutPrs: [9, 3, 7, 5, 11],
11
+ positiveControlPrs: [7],
12
+ negativeControlPrs: [11],
13
+ })).toEqual([3, 5, 9]);
14
+ });
15
+ it('is empty when every held-out PR is a control', () => {
16
+ expect(corpusHeldOutPrs({ heldOutPrs: [7, 11], positiveControlPrs: [7], negativeControlPrs: [11] })).toEqual([]);
17
+ });
18
+ });
19
+ // ─── Command integration (temp gate-1 dir, injected fake source) ─────────────
20
+ const SHA40 = (n) => n.toString(16).padStart(40, '0');
21
+ function writeFixtures(dir) {
22
+ const lock = {
23
+ schema: 'windtunnel.lock.v1',
24
+ canonicalPath: '.totem/spine/gate-1/windtunnel.lock.json',
25
+ gate: 'gate-1',
26
+ phase: 'certifying',
27
+ corpus: {
28
+ repo: 'mmnto-ai/liquid-city',
29
+ selectionRule: {
30
+ state: 'merged',
31
+ predicate: 'code-touching',
32
+ window: { type: 'all' },
33
+ asOfCommit: 'a'.repeat(40),
34
+ codePathClassifier: { includeGlobs: ['**/*.ts'], excludeGlobs: [] },
35
+ },
36
+ resolvedPrs: [3, 5, 7, 9].map((n) => ({
37
+ pr: n,
38
+ mergeCommit: SHA40(n),
39
+ baseSha: 'b'.repeat(40),
40
+ headSha: 'd'.repeat(40),
41
+ })),
42
+ },
43
+ fpDefinition: { rubricRef: 'r', groundTruthRef: 'g', adjudicator: 'a', precisionFloor: 1.0 },
44
+ controls: {
45
+ positiveRef: 'controls/positive/',
46
+ negativeRef: 'controls/negative/',
47
+ integrity: { mechanism: 'sha', fixtureSha: 'e'.repeat(40) },
48
+ },
49
+ cullRateThreshold: 0.5,
50
+ exposureDenominator: {
51
+ activeRulesEvaluated: { floor: 2 },
52
+ filesTouchedInWindow: { floor: 0 },
53
+ positiveControlsExercised: { floor: 0 },
54
+ },
55
+ };
56
+ const split = {
57
+ asOfCommit: 'a'.repeat(40),
58
+ trainPrs: [3],
59
+ heldOutPrs: [5, 7, 9],
60
+ excludedPrs: [],
61
+ positiveControlPrs: [7],
62
+ negativeControlPrs: [9],
63
+ splitRule: { predicate: 'code-touching', cutIndex: 1 },
64
+ };
65
+ fs.writeFileSync(path.join(dir, 'windtunnel.lock.json'), JSON.stringify(lock, null, 2));
66
+ fs.writeFileSync(path.join(dir, 'split.json'), JSON.stringify(split, null, 2));
67
+ }
68
+ /** A fake source: one thread per PR, deterministic content. */
69
+ const fakeSource = {
70
+ async fetch(pr) {
71
+ return {
72
+ pr,
73
+ mergeCommitSha: SHA40(pr),
74
+ threads: [
75
+ {
76
+ threadId: `T${pr}`,
77
+ path: `src/pr${pr}.ts`,
78
+ line: pr,
79
+ originalLine: pr - 1,
80
+ diffHunk: `@@ pr${pr} @@\n+line`,
81
+ isResolved: true,
82
+ isOutdated: false,
83
+ comments: [{ commentId: pr, author: 'coderabbitai[bot]', body: 'finding' }],
84
+ },
85
+ ],
86
+ };
87
+ },
88
+ };
89
+ describe('fetchDispositionsCommand', () => {
90
+ let dir;
91
+ beforeEach(() => {
92
+ dir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-fetch-disp-'));
93
+ writeFixtures(dir);
94
+ });
95
+ afterEach(() => {
96
+ // maxRetries/retryDelay: the repo convention for temp-dir teardown — guards the
97
+ // Windows file-lock ENOTEMPTY flake (describe.test.ts / doctor.test.ts pattern).
98
+ fs.rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
99
+ });
100
+ it('freezes corpus-dispositions.json for the corpus held-out PRs only (5, not 7/9)', async () => {
101
+ await fetchDispositionsCommand({
102
+ lockPath: path.join(dir, 'windtunnel.lock.json'),
103
+ cwd: dir,
104
+ source: fakeSource,
105
+ });
106
+ const written = JSON.parse(fs.readFileSync(path.join(dir, 'corpus-dispositions.json'), 'utf-8'));
107
+ // heldOut [5,7,9], controls {7,9} → only PR 5 is a corpus disposition.
108
+ expect(written.map((d) => d.pr)).toEqual([5]);
109
+ expect(written[0].threads[0].diffHunk).toBe('@@ pr5 @@\n+line');
110
+ });
111
+ it('stamps corpusDispositionsSha = sha256 of the exact on-disk bytes', async () => {
112
+ await fetchDispositionsCommand({
113
+ lockPath: path.join(dir, 'windtunnel.lock.json'),
114
+ cwd: dir,
115
+ source: fakeSource,
116
+ });
117
+ const bytes = fs.readFileSync(path.join(dir, 'corpus-dispositions.json'), 'utf-8');
118
+ const expected = createHash('sha256').update(bytes, 'utf-8').digest('hex');
119
+ const lock = JSON.parse(fs.readFileSync(path.join(dir, 'windtunnel.lock.json'), 'utf-8'));
120
+ expect(lock.controls.integrity.corpusDispositionsSha).toBe(expected);
121
+ expect(bytes.endsWith('\n')).toBe(true); // trailing newline (canonical)
122
+ });
123
+ it('is deterministic — a second run reproduces the identical digest', async () => {
124
+ const opts = { lockPath: path.join(dir, 'windtunnel.lock.json'), cwd: dir, source: fakeSource };
125
+ await fetchDispositionsCommand(opts);
126
+ const sha1 = JSON.parse(fs.readFileSync(path.join(dir, 'windtunnel.lock.json'), 'utf-8'))
127
+ .controls.integrity.corpusDispositionsSha;
128
+ await fetchDispositionsCommand(opts);
129
+ const sha2 = JSON.parse(fs.readFileSync(path.join(dir, 'windtunnel.lock.json'), 'utf-8'))
130
+ .controls.integrity.corpusDispositionsSha;
131
+ expect(sha2).toBe(sha1);
132
+ });
133
+ it('fails loud when the split has no held-out corpus PRs', async () => {
134
+ // Rewrite the split so every held-out PR is a control.
135
+ const split = JSON.parse(fs.readFileSync(path.join(dir, 'split.json'), 'utf-8'));
136
+ split.heldOutPrs = [7, 9];
137
+ split.positiveControlPrs = [7];
138
+ split.negativeControlPrs = [9];
139
+ fs.writeFileSync(path.join(dir, 'split.json'), JSON.stringify(split, null, 2));
140
+ await expect(fetchDispositionsCommand({
141
+ lockPath: path.join(dir, 'windtunnel.lock.json'),
142
+ cwd: dir,
143
+ source: fakeSource,
144
+ })).rejects.toThrow(/no held-out CORPUS PRs/i);
145
+ });
146
+ it('rejects a non-"owner/name" lock repo before any fetch (greptile #2231)', async () => {
147
+ // A 3-part repo ("github.com/owner/name") must fail at parse, not slip through
148
+ // as owner="github.com". No injected source → the live repo-parse path runs.
149
+ const lock = JSON.parse(fs.readFileSync(path.join(dir, 'windtunnel.lock.json'), 'utf-8'));
150
+ lock.corpus.repo = 'github.com/mmnto-ai/liquid-city';
151
+ fs.writeFileSync(path.join(dir, 'windtunnel.lock.json'), JSON.stringify(lock, null, 2));
152
+ await expect(fetchDispositionsCommand({ lockPath: path.join(dir, 'windtunnel.lock.json'), cwd: dir })).rejects.toThrow(/is not "owner\/name"/i);
153
+ });
154
+ });
155
+ //# sourceMappingURL=spine-fetch-dispositions.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-fetch-dispositions.test.js","sourceRoot":"","sources":["../../src/commands/spine-fetch-dispositions.test.ts"],"names":[],"mappings":"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"}
@@ -137,6 +137,25 @@ export declare function enumeratePrMetas(asOfCommit: string, lcDir: string, safe
137
137
  parseRevertSha: (body: string) => string | undefined;
138
138
  isBotIdentity: (author: string) => boolean;
139
139
  }): PrMeta[];
140
+ /**
141
+ * Build the certifying-run firings from a corpus's rules + prDiffs — the SHARED
142
+ * firing-setup the certifying run AND the 5d-iii label-deriver both call, so they
143
+ * enumerate byte-identical `RuleFiring` labelIds over the same fixtures. The panel
144
+ * anti-drift mandate: any divergence here (cwd resolution / ruleEngineCtx / the
145
+ * buildFirings call) would silently break the deriver↔run labelId join and void
146
+ * the answer key. Encapsulates:
147
+ * - cwd resolution (`resolveGitRoot(process.cwd())` — NOT raw `process.cwd()`, #1304),
148
+ * - the per-invocation `ruleEngineCtx` (logger + shield-warn state),
149
+ * - `buildFirings` (fold-F archived-assert runs inside it),
150
+ * - the A1 (fold-D) post-dedup labelId-uniqueness hard-gate.
151
+ * `logPrefix` differentiates the caller in warn output ([WindtunnelRun] / [DeriveLabels]).
152
+ */
153
+ export declare function buildCertifyingFirings(input: {
154
+ rules: import('@mmnto/totem').CompiledRule[];
155
+ prDiffs: import('@mmnto/totem').ResolvedPrDiff[];
156
+ readStrategy: (file: string) => Promise<string | null>;
157
+ logPrefix: string;
158
+ }): Promise<import('@mmnto/totem').BuildFiringsResult>;
140
159
  /**
141
160
  * Run the REAL engine for the certifying phase (5c-i — #2189 item 1).
142
161
  *
@@ -1 +1 @@
1
- {"version":3,"file":"spine-windtunnel.d.ts","sourceRoot":"","sources":["../../src/commands/spine-windtunnel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spine-windtunnel.d.ts","sourceRoot":"","sources":["../../src/commands/spine-windtunnel.ts"],"names":[],"mappings":"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"}