@mmnto/cli 1.70.0 → 1.71.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 (45) hide show
  1. package/dist/commands/spine-cert-corpus.d.ts +57 -0
  2. package/dist/commands/spine-cert-corpus.d.ts.map +1 -0
  3. package/dist/commands/spine-cert-corpus.js +51 -0
  4. package/dist/commands/spine-cert-corpus.js.map +1 -0
  5. package/dist/commands/spine-cert-corpus.test.d.ts +2 -0
  6. package/dist/commands/spine-cert-corpus.test.d.ts.map +1 -0
  7. package/dist/commands/spine-cert-corpus.test.js +112 -0
  8. package/dist/commands/spine-cert-corpus.test.js.map +1 -0
  9. package/dist/commands/spine-cert-e2e.test.d.ts +2 -0
  10. package/dist/commands/spine-cert-e2e.test.d.ts.map +1 -0
  11. package/dist/commands/spine-cert-e2e.test.js +145 -0
  12. package/dist/commands/spine-cert-e2e.test.js.map +1 -0
  13. package/dist/commands/spine-cert-persist.d.ts +63 -0
  14. package/dist/commands/spine-cert-persist.d.ts.map +1 -0
  15. package/dist/commands/spine-cert-persist.js +85 -0
  16. package/dist/commands/spine-cert-persist.js.map +1 -0
  17. package/dist/commands/spine-cert-persist.test.d.ts +2 -0
  18. package/dist/commands/spine-cert-persist.test.d.ts.map +1 -0
  19. package/dist/commands/spine-cert-persist.test.js +108 -0
  20. package/dist/commands/spine-cert-persist.test.js.map +1 -0
  21. package/dist/commands/spine-cert-record.d.ts +118 -0
  22. package/dist/commands/spine-cert-record.d.ts.map +1 -0
  23. package/dist/commands/spine-cert-record.js +194 -0
  24. package/dist/commands/spine-cert-record.js.map +1 -0
  25. package/dist/commands/spine-cert-record.test.d.ts +2 -0
  26. package/dist/commands/spine-cert-record.test.d.ts.map +1 -0
  27. package/dist/commands/spine-cert-record.test.js +129 -0
  28. package/dist/commands/spine-cert-record.test.js.map +1 -0
  29. package/dist/commands/spine-cert-run-corpus.d.ts +42 -0
  30. package/dist/commands/spine-cert-run-corpus.d.ts.map +1 -0
  31. package/dist/commands/spine-cert-run-corpus.js +133 -0
  32. package/dist/commands/spine-cert-run-corpus.js.map +1 -0
  33. package/dist/commands/spine-cert-run-corpus.test.d.ts +2 -0
  34. package/dist/commands/spine-cert-run-corpus.test.d.ts.map +1 -0
  35. package/dist/commands/spine-cert-run-corpus.test.js +171 -0
  36. package/dist/commands/spine-cert-run-corpus.test.js.map +1 -0
  37. package/dist/commands/spine-windtunnel.d.ts +65 -0
  38. package/dist/commands/spine-windtunnel.d.ts.map +1 -1
  39. package/dist/commands/spine-windtunnel.js +160 -7
  40. package/dist/commands/spine-windtunnel.js.map +1 -1
  41. package/dist/commands/spine-windtunnel.test.js +80 -1
  42. package/dist/commands/spine-windtunnel.test.js.map +1 -1
  43. package/dist/index.js +32 -0
  44. package/dist/index.js.map +1 -1
  45. package/package.json +2 -2
@@ -0,0 +1,108 @@
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 { persistCertifyingOutcome } from './spine-cert-persist.js';
6
+ // ─── Fixtures ────────────────────────────────────────
7
+ const COMMIT = 'a'.repeat(40);
8
+ const NOW = '2026-06-20T23:59:59.000Z';
9
+ let tmpDir;
10
+ beforeEach(() => {
11
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-cert-persist-'));
12
+ });
13
+ afterEach(() => {
14
+ fs.rmSync(tmpDir, { recursive: true, force: true });
15
+ });
16
+ function provenance(mergedPr = 100) {
17
+ return { mergedPr, reviewThread: `pr#${mergedPr}/t1`, commitSha: COMMIT };
18
+ }
19
+ function makeRule(lessonHash) {
20
+ return {
21
+ lessonHash,
22
+ lessonHeading: `Rule ${lessonHash}`,
23
+ pattern: 'debugger',
24
+ message: 'no debugger',
25
+ engine: 'regex',
26
+ compiledAt: '2026-06-20T00:00:00.000Z',
27
+ };
28
+ }
29
+ function makeVerdict(kind) {
30
+ return {
31
+ verdict: kind,
32
+ precision: kind === 'PASS' ? 1.0 : null,
33
+ mintedRuleCount: 1,
34
+ culledCount: 0,
35
+ survivingRuleCount: 1,
36
+ exposureTuple: [2, 1, 1],
37
+ cullLedger: [],
38
+ nonVacuity: kind === 'PASS',
39
+ needsAdjudication: [],
40
+ diagnostics: { survivorPrecision: kind === 'PASS' ? 1.0 : null },
41
+ };
42
+ }
43
+ /** A positive-control firing for rule r1 on pr 1, so its per-rule positiveControl is true. */
44
+ function positiveFiring() {
45
+ return {
46
+ ruleId: 'r1',
47
+ pr: 1,
48
+ filePath: 'src/a.ts',
49
+ matchedLine: 'debugger;',
50
+ controlKind: 'positive',
51
+ targetRuleId: 'r1',
52
+ labelId: 'label-r1-pos',
53
+ };
54
+ }
55
+ function baseInput(verdict) {
56
+ return {
57
+ verdict,
58
+ firings: [positiveFiring()],
59
+ mintedRuleIds: ['r1'],
60
+ positiveControlTargets: [{ pr: 1, targetRuleId: 'r1' }],
61
+ candidates: [makeRule('r1')],
62
+ provenanceByRule: new Map([['r1', provenance()]]),
63
+ certifiedRulesOutPath: path.join(tmpDir, 'gate-1', 'compiled-rules.json'),
64
+ reportDir: path.join(tmpDir, 'gate-1', 'run-reports'),
65
+ nowIso: NOW,
66
+ asOfCommit: COMMIT,
67
+ };
68
+ }
69
+ // ─── Tests ───────────────────────────────────────────
70
+ describe('persistCertifyingOutcome', () => {
71
+ it('PASS ⟹ writes stamped PASS-survivors to the cert output + a run report', async () => {
72
+ const result = await persistCertifyingOutcome(baseInput(makeVerdict('PASS')));
73
+ expect(result.persisted).toBe(true);
74
+ expect(result.stampedCount).toBe(1);
75
+ expect(result.certifiedRulesPath).toBeDefined();
76
+ // The certified-rules file exists and carries the hard-stamped survivor.
77
+ const written = JSON.parse(fs.readFileSync(result.certifiedRulesPath, 'utf-8'));
78
+ expect(written.rules).toHaveLength(1);
79
+ expect(written.rules[0].lessonHash).toBe('r1');
80
+ expect(written.rules[0].ruleClass).toBe('hard');
81
+ expect(written.rules[0].legitimacy.positiveControl).toBe(true);
82
+ expect(written.rules[0].unverified).toBe(false);
83
+ // The transient report exists and records the PASS outcome.
84
+ const report = JSON.parse(fs.readFileSync(result.reportPath, 'utf-8'));
85
+ expect(report.kind).toBe('windtunnel-cert-run.v1');
86
+ expect(report.persisted).toBe(true);
87
+ expect(report.verdict.verdict).toBe('PASS');
88
+ expect(report.stampedRuleIds).toEqual(['r1']);
89
+ });
90
+ it('non-PASS ⟹ writes NO cert rules (corpus untouched) but STILL writes a report (§6 L3)', async () => {
91
+ const result = await persistCertifyingOutcome(baseInput(makeVerdict('HONEST-NEGATIVE')));
92
+ expect(result.persisted).toBe(false);
93
+ expect(result.stampedCount).toBe(0);
94
+ expect(result.certifiedRulesPath).toBeUndefined();
95
+ // No compiled-rules file written anywhere under the cert output dir.
96
+ expect(fs.existsSync(path.join(tmpDir, 'gate-1', 'compiled-rules.json'))).toBe(false);
97
+ // The report IS written, recording the non-terminal outcome.
98
+ const report = JSON.parse(fs.readFileSync(result.reportPath, 'utf-8'));
99
+ expect(report.persisted).toBe(false);
100
+ expect(report.verdict.verdict).toBe('HONEST-NEGATIVE');
101
+ expect(report.skips).toContainEqual({ reason: 'verdict-not-pass', verdict: 'HONEST-NEGATIVE' });
102
+ });
103
+ it('the report filename embeds the injected timestamp slug + a run-identity hash', async () => {
104
+ const result = await persistCertifyingOutcome(baseInput(makeVerdict('PASS')));
105
+ expect(path.basename(result.reportPath)).toMatch(/^run-20260620T235959-[0-9a-f]{12}\.json$/);
106
+ });
107
+ });
108
+ //# sourceMappingURL=spine-cert-persist.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-cert-persist.test.js","sourceRoot":"","sources":["../../src/commands/spine-cert-persist.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ import type { DraftClassifier, DraftExtractor, ReviewThreadSource, SplitArtifact, SplitLedger, WindtunnelLock } from '@mmnto/totem';
2
+ import { type ReplayArtifact, type ReplayProvenance } from './spine-llm-replay.js';
3
+ /**
4
+ * Minimal draft shape `certDraftRef` keys on — a structural subset of core's
5
+ * (intentionally non-exported, transient) `DraftCandidate`. Assignable to the
6
+ * `(draft: DraftCandidate) => string` resolver the Recording/Replay classifiers
7
+ * expect, via parameter contravariance.
8
+ */
9
+ type DraftRefInput = {
10
+ provenance: {
11
+ mergedPr: number;
12
+ };
13
+ dslSource: string;
14
+ };
15
+ /**
16
+ * The shared per-draft ref resolver. MUST be byte-identical in RECORD and REPLAY
17
+ * so `classifierInputKey(draft, draftRef(draft))` produces the same key in both —
18
+ * a divergence here would make every replay a `ReplayMissError`. Keyed on the
19
+ * provenance PR + the DSL body (a draft is uniquely identified by its source
20
+ * within a PR); ordinal-free so it survives re-ordering.
21
+ */
22
+ export declare function certDraftRef(d: DraftRefInput): string;
23
+ export interface RecordReplayFixtureDeps {
24
+ split: SplitArtifact;
25
+ splitLedger: SplitLedger;
26
+ /** Review-thread source (live gh adapter in the record command). */
27
+ source: ReviewThreadSource;
28
+ /** Live draft extractor to record (wrapped in RecordingDraftExtractor). */
29
+ liveExtractor: DraftExtractor;
30
+ /** Live draft classifier to record (wrapped in RecordingDraftClassifier). */
31
+ liveClassifier: DraftClassifier;
32
+ /** Seed-blindness attestation (passed through to extract). */
33
+ seedClassesProvided: boolean;
34
+ /** Prompt/provider provenance bound into the frozen artifact's whole-artifact hash. */
35
+ provenance: ReplayProvenance;
36
+ }
37
+ /**
38
+ * Drive the extract + classify stages through the RECORDING decorators to freeze
39
+ * a `llm-replay.v1` fixture (A2 record path). Runs extract (records every
40
+ * extractor output) then classify (records every classifier output) over the
41
+ * train slice, then `sink.freeze(provenance)` → the artifact + its
42
+ * `computeArtifactHash` (the EXTERNAL expected-hash the lock's L2 `llmReplaySha`
43
+ * carries). Compile is NOT run here — recording captures only the non-deterministic
44
+ * LLM edge (extract/classify); the deterministic compile/firing replays from it.
45
+ */
46
+ export declare function recordReplayFixture(deps: RecordReplayFixtureDeps): Promise<{
47
+ artifact: ReplayArtifact;
48
+ hash: string;
49
+ }>;
50
+ /**
51
+ * Construct the REPLAY-mode extractor + classifier from a frozen artifact + its
52
+ * external expected-hash (the lock's L2 `llmReplaySha`). Both constructors
53
+ * re-validate the whole-artifact integrity (assertFixtureIntegrity) before any
54
+ * lookup, so a tampered/stale fixture fails loud. Uses the shared `certDraftRef`
55
+ * so keys match what `recordReplayFixture` froze. Pure: zero LLM, zero network.
56
+ */
57
+ export declare function buildReplayAdapters(artifact: ReplayArtifact, expectedHash: string): {
58
+ extractor: DraftExtractor;
59
+ classifier: DraftClassifier;
60
+ };
61
+ /** The injectable record deps — live in the CLI, fakes in tests. */
62
+ export interface RecordDeps {
63
+ source: ReviewThreadSource;
64
+ liveExtractor: DraftExtractor;
65
+ liveClassifier: DraftClassifier;
66
+ provenance: ReplayProvenance;
67
+ }
68
+ export interface RecordCommandOptions {
69
+ /** Path to the wind-tunnel lock (default `.totem/spine/gate-1/windtunnel.lock.json`). */
70
+ lockPath?: string;
71
+ /** Gate-1 output dir (default: the lock's dir). */
72
+ outputDir?: string;
73
+ /**
74
+ * Operator attestation that seed classes were supplied to the live extract —
75
+ * flows into the fold-I FM-f `seedClassesProvided` ledger field. Default false
76
+ * (seed-blind), so an unset flag preserves the seed-blind-by-construction claim.
77
+ */
78
+ seedClassesProvided?: boolean;
79
+ /**
80
+ * Record deps. Injected in tests; in the live CLI path the caller builds them
81
+ * from the orchestrator config (createOrchestrator + the Live adapters + the
82
+ * gh ReviewThreadSource). REQUIRED — there is no safe default LLM/provider, so
83
+ * the command fails loud rather than guess.
84
+ */
85
+ deps: RecordDeps;
86
+ }
87
+ /**
88
+ * A2 record path — freeze the `llm-replay.v1` fixture + the review content the
89
+ * certifying RUN replays. Loads the lock + split, drives extract→classify
90
+ * through the RECORDING decorators over the train slice (capturing both the LLM
91
+ * outputs AND the fetched review content), writes `llm-replay.v1.json` +
92
+ * `review-content.json` to the gate-1 dir, and returns the artifact's
93
+ * `computeArtifactHash` — the EXTERNAL hash the operator wires into the lock's L2
94
+ * `controls.integrity.llmReplaySha`. Separate from `run` (fail-safe: `run` stays
95
+ * replay-only and never triggers a live record in CI).
96
+ */
97
+ export declare function recordCommand(opts: RecordCommandOptions): Promise<{
98
+ artifactPath: string;
99
+ contentPath: string;
100
+ hash: string;
101
+ }>;
102
+ export interface LiveRecordConfig {
103
+ provider: string;
104
+ model: string;
105
+ cwd: string;
106
+ totemVersion: string;
107
+ env?: NodeJS.ProcessEnv;
108
+ }
109
+ /**
110
+ * Construct the LIVE record deps from the orchestrator config: the gh
111
+ * ReviewThreadSource, an `InvokeOrchestrator` (createOrchestrator), the Live
112
+ * extract/classify adapters (frozen prompts), and the run-level provenance.
113
+ * Operational — exercised by hand when freezing a real corpus, never in CI
114
+ * (the adapters' construction-time guards reject a CI env / missing credential).
115
+ */
116
+ export declare function buildLiveRecordDeps(lock: WindtunnelLock, config: LiveRecordConfig): Promise<RecordDeps>;
117
+ export {};
118
+ //# sourceMappingURL=spine-cert-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-cert-record.d.ts","sourceRoot":"","sources":["../../src/commands/spine-cert-record.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EAEd,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,cAAc,EACf,MAAM,cAAc,CAAC;AAEtB,OAAO,EAIL,KAAK,cAAc,EAGnB,KAAK,gBAAgB,EAGtB,MAAM,uBAAuB,CAAC;AAE/B;;;;;GAKG;AACH,KAAK,aAAa,GAAG;IAAE,UAAU,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7E;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,CAErD;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,aAAa,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,oEAAoE;IACpE,MAAM,EAAE,kBAAkB,CAAC;IAC3B,2EAA2E;IAC3E,aAAa,EAAE,cAAc,CAAC;IAC9B,6EAA6E;IAC7E,cAAc,EAAE,eAAe,CAAC;IAChC,8DAA8D;IAC9D,mBAAmB,EAAE,OAAO,CAAC;IAC7B,uFAAuF;IACvF,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC;IAAE,QAAQ,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBrD;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,cAAc,EACxB,YAAY,EAAE,MAAM,GACnB;IAAE,SAAS,EAAE,cAAc,CAAC;IAAC,UAAU,EAAE,eAAe,CAAA;CAAE,CAK5D;AAID,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,aAAa,EAAE,cAAc,CAAC;IAC9B,cAAc,EAAE,eAAe,CAAC;IAChC,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,IAAI,EAAE,UAAU,CAAC;CAClB;AAgBD;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA0EtE;AASD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,UAAU,CAAC,CAuErB"}
@@ -0,0 +1,194 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { computeArtifactHash, RecordingDraftClassifier, RecordingDraftExtractor, ReplayDraftClassifier, ReplayDraftExtractor, ReplayRecordSink, serializeReplayArtifact, } from './spine-llm-replay.js';
4
+ /**
5
+ * The shared per-draft ref resolver. MUST be byte-identical in RECORD and REPLAY
6
+ * so `classifierInputKey(draft, draftRef(draft))` produces the same key in both —
7
+ * a divergence here would make every replay a `ReplayMissError`. Keyed on the
8
+ * provenance PR + the DSL body (a draft is uniquely identified by its source
9
+ * within a PR); ordinal-free so it survives re-ordering.
10
+ */
11
+ export function certDraftRef(d) {
12
+ return `cand-${d.provenance.mergedPr}-${d.dslSource}`;
13
+ }
14
+ /**
15
+ * Drive the extract + classify stages through the RECORDING decorators to freeze
16
+ * a `llm-replay.v1` fixture (A2 record path). Runs extract (records every
17
+ * extractor output) then classify (records every classifier output) over the
18
+ * train slice, then `sink.freeze(provenance)` → the artifact + its
19
+ * `computeArtifactHash` (the EXTERNAL expected-hash the lock's L2 `llmReplaySha`
20
+ * carries). Compile is NOT run here — recording captures only the non-deterministic
21
+ * LLM edge (extract/classify); the deterministic compile/firing replays from it.
22
+ */
23
+ export async function recordReplayFixture(deps) {
24
+ const { runExtractStage, runClassifyStage } = await import('@mmnto/totem');
25
+ const sink = new ReplayRecordSink();
26
+ const recExtractor = new RecordingDraftExtractor(deps.liveExtractor, sink);
27
+ const recClassifier = new RecordingDraftClassifier(deps.liveClassifier, sink, certDraftRef);
28
+ const extract = await runExtractStage(deps.split, {
29
+ source: deps.source,
30
+ extractor: recExtractor,
31
+ seedClassesProvided: deps.seedClassesProvided,
32
+ });
33
+ await runClassifyStage(extract, deps.splitLedger, { classifier: recClassifier });
34
+ const artifact = sink.freeze(deps.provenance);
35
+ return { artifact, hash: computeArtifactHash(artifact) };
36
+ }
37
+ /**
38
+ * Construct the REPLAY-mode extractor + classifier from a frozen artifact + its
39
+ * external expected-hash (the lock's L2 `llmReplaySha`). Both constructors
40
+ * re-validate the whole-artifact integrity (assertFixtureIntegrity) before any
41
+ * lookup, so a tampered/stale fixture fails loud. Uses the shared `certDraftRef`
42
+ * so keys match what `recordReplayFixture` froze. Pure: zero LLM, zero network.
43
+ */
44
+ export function buildReplayAdapters(artifact, expectedHash) {
45
+ return {
46
+ extractor: new ReplayDraftExtractor(artifact, expectedHash),
47
+ classifier: new ReplayDraftClassifier(artifact, expectedHash, certDraftRef),
48
+ };
49
+ }
50
+ /** Wrap a source so every fetched review-thread content is captured for freezing. */
51
+ function capturingSource(inner, captured) {
52
+ return {
53
+ async fetch(pr) {
54
+ const result = await inner.fetch(pr);
55
+ if (result.kind === 'ok')
56
+ captured.push(result.content);
57
+ return result;
58
+ },
59
+ };
60
+ }
61
+ /**
62
+ * A2 record path — freeze the `llm-replay.v1` fixture + the review content the
63
+ * certifying RUN replays. Loads the lock + split, drives extract→classify
64
+ * through the RECORDING decorators over the train slice (capturing both the LLM
65
+ * outputs AND the fetched review content), writes `llm-replay.v1.json` +
66
+ * `review-content.json` to the gate-1 dir, and returns the artifact's
67
+ * `computeArtifactHash` — the EXTERNAL hash the operator wires into the lock's L2
68
+ * `controls.integrity.llmReplaySha`. Separate from `run` (fail-safe: `run` stays
69
+ * replay-only and never triggers a live record in CI).
70
+ */
71
+ export async function recordCommand(opts) {
72
+ const { WindtunnelLockSchema, SplitArtifactSchema, TotemError } = await import('@mmnto/totem');
73
+ const cwd = process.cwd();
74
+ const lockPath = opts.lockPath
75
+ ? path.resolve(cwd, opts.lockPath)
76
+ : path.resolve(cwd, '.totem/spine/gate-1/windtunnel.lock.json');
77
+ const gate1Dir = opts.outputDir ? path.resolve(cwd, opts.outputDir) : path.dirname(lockPath);
78
+ // Guard the two critical reads: a missing file or malformed JSON surfaces as a
79
+ // structured TotemError (original error attached as cause), not a cryptic crash.
80
+ const readJsonFile = (p) => {
81
+ let raw;
82
+ try {
83
+ raw = fs.readFileSync(p, 'utf-8');
84
+ }
85
+ catch (err) {
86
+ throw new TotemError('CONFIG_INVALID', `Record: required file not found at ${p}`, 'Ensure the gate-1 lock and split.json exist before recording.', err);
87
+ }
88
+ try {
89
+ return JSON.parse(raw);
90
+ }
91
+ catch (err) {
92
+ throw new TotemError('CONFIG_INVALID', `Record: ${p} is not valid JSON`, 'Fix the JSON syntax and retry.', err);
93
+ }
94
+ };
95
+ const lock = WindtunnelLockSchema.parse(readJsonFile(lockPath));
96
+ const split = SplitArtifactSchema.parse(readJsonFile(path.join(gate1Dir, 'split.json')));
97
+ const splitLedger = {
98
+ split,
99
+ corpus: lock.corpus.resolvedPrs.map((p) => p.pr),
100
+ corpusMergeCommits: lock.corpus.resolvedPrs.map((p) => ({
101
+ pr: p.pr,
102
+ mergeCommit: p.mergeCommit,
103
+ })),
104
+ };
105
+ const capturedContent = [];
106
+ const { artifact, hash } = await recordReplayFixture({
107
+ split,
108
+ splitLedger,
109
+ source: capturingSource(opts.deps.source, capturedContent),
110
+ liveExtractor: opts.deps.liveExtractor,
111
+ liveClassifier: opts.deps.liveClassifier,
112
+ seedClassesProvided: opts.seedClassesProvided ?? false,
113
+ provenance: opts.deps.provenance,
114
+ });
115
+ fs.mkdirSync(gate1Dir, { recursive: true });
116
+ const artifactPath = path.join(gate1Dir, 'llm-replay.v1.json');
117
+ const contentPath = path.join(gate1Dir, 'review-content.json');
118
+ fs.writeFileSync(artifactPath, serializeReplayArtifact(artifact), 'utf-8');
119
+ fs.writeFileSync(contentPath, JSON.stringify(capturedContent, null, 2), 'utf-8');
120
+ console.error(`[WindtunnelRecord] Froze ${artifactPath}`);
121
+ console.error(`[WindtunnelRecord] Froze ${contentPath} (${capturedContent.length} PR(s))`);
122
+ console.error(`[WindtunnelRecord] llm-replay hash (wire into lock controls.integrity.llmReplaySha):`);
123
+ console.log(hash);
124
+ return { artifactPath, contentPath, hash };
125
+ }
126
+ /** Env var carrying each provider's credential (presence check, never read). */
127
+ const PROVIDER_CREDENTIAL_ENV = {
128
+ anthropic: 'ANTHROPIC_API_KEY',
129
+ gemini: 'GEMINI_API_KEY',
130
+ openai: 'OPENAI_API_KEY',
131
+ };
132
+ /**
133
+ * Construct the LIVE record deps from the orchestrator config: the gh
134
+ * ReviewThreadSource, an `InvokeOrchestrator` (createOrchestrator), the Live
135
+ * extract/classify adapters (frozen prompts), and the run-level provenance.
136
+ * Operational — exercised by hand when freezing a real corpus, never in CI
137
+ * (the adapters' construction-time guards reject a CI env / missing credential).
138
+ */
139
+ export async function buildLiveRecordDeps(lock, config) {
140
+ const { createOrchestrator } = await import('../orchestrators/orchestrator.js');
141
+ const { TotemError } = await import('@mmnto/totem');
142
+ const { LiveDraftExtractor, LiveDraftClassifier, buildReplayProvenance, MINER_EXTRACT_SYSTEM_PROMPT, MINER_CLASSIFY_SYSTEM_PROMPT, } = await import('./spine-llm-adapters.js');
143
+ const { ReviewThreadSourceAdapter } = await import('./spine-review-thread-source.js');
144
+ const [owner, name] = lock.corpus.repo.split('/');
145
+ if (!owner || !name) {
146
+ throw new TotemError('CONFIG_INVALID', `Record: lock.corpus.repo "${lock.corpus.repo}" is not "owner/name".`, 'Set corpus.repo in the lock to the "owner/name" form.');
147
+ }
148
+ const env = config.env ?? process.env;
149
+ const credentialPresent = Boolean(env[PROVIDER_CREDENTIAL_ENV[config.provider] ?? '']);
150
+ // Build a fully-typed OrchestratorConfig — no `as` cast. The live record path
151
+ // supports only the API-key providers (see PROVIDER_CREDENTIAL_ENV); `shell`
152
+ // and `ollama` carry required fields (command / baseUrl) the record path does
153
+ // not model, so the prior cast silently passed `command: undefined` for shell.
154
+ let invoke;
155
+ switch (config.provider) {
156
+ case 'anthropic':
157
+ invoke = createOrchestrator({ provider: 'anthropic' });
158
+ break;
159
+ case 'gemini':
160
+ invoke = createOrchestrator({ provider: 'gemini' });
161
+ break;
162
+ case 'openai':
163
+ invoke = createOrchestrator({ provider: 'openai' });
164
+ break;
165
+ default:
166
+ throw new TotemError('CONFIG_INVALID', `Record: unsupported provider "${config.provider}" for the live record path.`, 'Use --provider with anthropic, gemini, or openai.');
167
+ }
168
+ const totemDir = `${config.cwd}/.totem`;
169
+ const adapterDeps = {
170
+ invoke,
171
+ model: config.model,
172
+ cwd: config.cwd,
173
+ totemDir,
174
+ provider: config.provider,
175
+ credentialPresent,
176
+ temperature: 0,
177
+ env,
178
+ };
179
+ return {
180
+ source: new ReviewThreadSourceAdapter({ owner, name, cwd: config.cwd }),
181
+ liveExtractor: new LiveDraftExtractor(adapterDeps),
182
+ liveClassifier: new LiveDraftClassifier(adapterDeps),
183
+ provenance: buildReplayProvenance({
184
+ extractSystemPrompt: MINER_EXTRACT_SYSTEM_PROMPT,
185
+ classifySystemPrompt: MINER_CLASSIFY_SYSTEM_PROMPT,
186
+ provider: config.provider,
187
+ model: config.model,
188
+ temperature: 0,
189
+ orchestratorVersion: config.totemVersion,
190
+ totemVersion: config.totemVersion,
191
+ }),
192
+ };
193
+ }
194
+ //# sourceMappingURL=spine-cert-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-cert-record.js","sourceRoot":"","sources":["../../src/commands/spine-cert-record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=spine-cert-record.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-cert-record.test.d.ts","sourceRoot":"","sources":["../../src/commands/spine-cert-record.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,129 @@
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 { recordCommand } from './spine-cert-record.js';
6
+ import { computeArtifactHash, } from './spine-llm-replay.js';
7
+ const sha = (n) => String(n).padStart(40, '0');
8
+ const REGEX_DSL = ['**Pattern:** `forbiddenCall\\(`', '**Engine:** regex'].join('\n');
9
+ const PROVENANCE = {
10
+ promptTemplateHash: sha(11),
11
+ systemPromptHash: sha(12),
12
+ provider: 'anthropic',
13
+ model: 'claude-test',
14
+ temperature: 0,
15
+ orchestratorVersion: '0.0.0-test',
16
+ adapterKind: 'extractor+classifier',
17
+ keyVersion: 'v1',
18
+ totemVersion: '0.0.0-test',
19
+ };
20
+ function content(pr) {
21
+ return {
22
+ pr,
23
+ mergeCommitSha: sha(pr),
24
+ threads: [
25
+ {
26
+ path: 'src/a.ts',
27
+ comments: [{ author: 'Jane', body: 'note' }],
28
+ isResolved: false,
29
+ isOutdated: false,
30
+ },
31
+ ],
32
+ };
33
+ }
34
+ function fakeDeps() {
35
+ return {
36
+ source: {
37
+ async fetch(pr) {
38
+ return { kind: 'ok', content: content(pr) };
39
+ },
40
+ },
41
+ liveExtractor: {
42
+ async draft() {
43
+ return [REGEX_DSL];
44
+ },
45
+ },
46
+ liveClassifier: {
47
+ async classify() {
48
+ return { disposition: 'structural', dispositionSource: 'classified' };
49
+ },
50
+ },
51
+ provenance: PROVENANCE,
52
+ };
53
+ }
54
+ function validLock() {
55
+ return {
56
+ schema: 'windtunnel.lock.v1',
57
+ canonicalPath: '.totem/spine/gate-1/windtunnel.lock.json',
58
+ gate: 'gate-1',
59
+ phase: 'certifying',
60
+ corpus: {
61
+ repo: 'mmnto-ai/liquid-city',
62
+ selectionRule: {
63
+ state: 'merged',
64
+ predicate: 'touches-code',
65
+ window: { type: 'all' },
66
+ asOfCommit: sha(100),
67
+ },
68
+ resolvedPrs: [{ pr: 1, mergeCommit: sha(1), baseSha: sha(2), headSha: sha(3) }],
69
+ },
70
+ fpDefinition: {
71
+ rubricRef: 'controls/rubric.md',
72
+ groundTruthRef: 'controls/gt.json',
73
+ adjudicator: 'operator',
74
+ precisionFloor: 1.0,
75
+ },
76
+ controls: {
77
+ positiveRef: 'controls/positive/',
78
+ negativeRef: 'controls/negative/',
79
+ integrity: { mechanism: 'git-hash-object', fixtureSha: sha(0) },
80
+ },
81
+ cullRateThreshold: 0.25,
82
+ exposureDenominator: {
83
+ activeRulesEvaluated: { floor: 2 },
84
+ filesTouchedInWindow: { floor: 0 },
85
+ positiveControlsExercised: { floor: 0 },
86
+ },
87
+ };
88
+ }
89
+ const SPLIT = {
90
+ asOfCommit: sha(100),
91
+ trainPrs: [1],
92
+ heldOutPrs: [],
93
+ excludedPrs: [],
94
+ positiveControlPrs: [],
95
+ negativeControlPrs: [],
96
+ splitRule: { predicate: 'code-touching non-bot', cutIndex: 1 },
97
+ };
98
+ let tmpDir;
99
+ let gate1Dir;
100
+ let lockPath;
101
+ beforeEach(() => {
102
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-record-cmd-'));
103
+ gate1Dir = path.join(tmpDir, 'gate-1');
104
+ fs.mkdirSync(gate1Dir, { recursive: true });
105
+ lockPath = path.join(gate1Dir, 'windtunnel.lock.json');
106
+ fs.writeFileSync(lockPath, JSON.stringify(validLock()), 'utf-8');
107
+ fs.writeFileSync(path.join(gate1Dir, 'split.json'), JSON.stringify(SPLIT), 'utf-8');
108
+ });
109
+ afterEach(() => {
110
+ fs.rmSync(tmpDir, { recursive: true, force: true });
111
+ });
112
+ describe('recordCommand (A2 record path)', () => {
113
+ it('freezes the llm-replay artifact + review content and returns the integrity hash', async () => {
114
+ const result = await recordCommand({ lockPath, deps: fakeDeps() });
115
+ expect(fs.existsSync(result.artifactPath)).toBe(true);
116
+ expect(fs.existsSync(result.contentPath)).toBe(true);
117
+ // The returned hash matches computeArtifactHash over the written artifact.
118
+ const artifact = JSON.parse(fs.readFileSync(result.artifactPath, 'utf-8'));
119
+ expect(result.hash).toBe(computeArtifactHash(artifact));
120
+ // The frozen content carries the fetched train PR.
121
+ const frozenContent = JSON.parse(fs.readFileSync(result.contentPath, 'utf-8'));
122
+ expect(frozenContent).toHaveLength(1);
123
+ expect(frozenContent[0].pr).toBe(1);
124
+ // The artifact recorded both extractor + classifier outputs.
125
+ expect(Object.keys(artifact.records.extractor).length).toBeGreaterThan(0);
126
+ expect(Object.keys(artifact.records.classifier).length).toBeGreaterThan(0);
127
+ });
128
+ });
129
+ //# sourceMappingURL=spine-cert-record.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-cert-record.test.js","sourceRoot":"","sources":["../../src/commands/spine-cert-record.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { GroundTruthLabel, MinerLedgers, ResolvedPrDiff, ReviewThreadContent, Stage4VerifierDeps } from '@mmnto/totem';
2
+ import { type ReplayArtifact } from './spine-llm-replay.js';
3
+ import type { CertifyingCorpusProvider } from './spine-windtunnel.js';
4
+ export interface CertRunFixtureInputs {
5
+ split: import('@mmnto/totem').SplitArtifact;
6
+ artifact: ReplayArtifact;
7
+ content: ReviewThreadContent[];
8
+ prDiffs: ResolvedPrDiff[];
9
+ groundTruth: Map<string, GroundTruthLabel>;
10
+ }
11
+ /**
12
+ * Load + validate the committed cert-run fixture inputs from the gate-1 dir.
13
+ * Async so the `@mmnto/totem` runtime values (schema + error class) are
14
+ * dynamically imported per the CLI lazy-import convention, not pulled in at
15
+ * module load.
16
+ */
17
+ export declare function loadCertRunFixtures(gate1Dir: string): Promise<CertRunFixtureInputs>;
18
+ export interface ReplayCorpusProviderOptions {
19
+ /** The `.totem/spine/gate-1` dir holding the committed cert-run fixtures. */
20
+ gate1Dir: string;
21
+ /** Stage-4 verifier deps (listFiles/readFile) — injected so the run is testable. */
22
+ stage4: Stage4VerifierDeps;
23
+ /** Injected timestamp (Tenet 15 determinism). */
24
+ now: string;
25
+ /** Seed-blindness attestation (fold-I §7). */
26
+ seedClassesProvided?: boolean;
27
+ /** Optional sink for the fold-I miner ledgers (defaults to gate1Dir/miner-ledgers.json). */
28
+ onLedgers?: (ledgers: MinerLedgers) => void;
29
+ }
30
+ /**
31
+ * Build the REPLAY-mode `CertifyingCorpusProvider` the certifying run injects.
32
+ *
33
+ * Loads the committed cert-run fixtures (split, frozen `llm-replay.v1` artifact,
34
+ * frozen review content, resolved-PR diffs, ground-truth labels) from the gate-1
35
+ * dir, constructs the zero-network replay adapters (gated on the lock's L2
36
+ * `llmReplaySha`) + a frozen review-thread source, then composes them through
37
+ * `buildCertifyingCorpus`. fold-I ledgers are emitted (default: written to
38
+ * `miner-ledgers.json`) for §7 observability. Throws loud if the lock lacks the
39
+ * L2 replay hash (no safe default for an integrity gate).
40
+ */
41
+ export declare function buildReplayCorpusProvider(opts: ReplayCorpusProviderOptions): CertifyingCorpusProvider;
42
+ //# sourceMappingURL=spine-cert-run-corpus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-cert-run-corpus.d.ts","sourceRoot":"","sources":["../../src/commands/spine-cert-run-corpus.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,mBAAmB,EAGnB,kBAAkB,EAEnB,MAAM,cAAc,CAAC;AAItB,OAAO,EAAE,KAAK,cAAc,EAAwB,MAAM,uBAAuB,CAAC;AAClF,OAAO,KAAK,EAAoB,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAiDxF,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,cAAc,EAAE,aAAa,CAAC;IAC5C,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC5C;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAoCzF;AAiBD,MAAM,WAAW,2BAA2B;IAC1C,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,oFAAoF;IACpF,MAAM,EAAE,kBAAkB,CAAC;IAC3B,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,4FAA4F;IAC5F,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;CAC7C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,2BAA2B,GAChC,wBAAwB,CA6C1B"}