@mmnto/cli 1.67.1 → 1.69.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,372 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { classifierInputKey, ClassifierResultLocalSchema, computeArtifactHash, DuplicateRecordError, extractorInputKey, FixtureIntegrityError, RecordingDraftClassifier, RecordingDraftExtractor, REPLAY_ARTIFACT_KIND, ReplayArtifactSchema, ReplayDraftClassifier, ReplayDraftExtractor, ReplayMissError, ReplayRecordSink, serializeReplayArtifact, } from './spine-llm-replay.js';
3
+ // ─── Stub ports (in-memory, deterministic — NO network, NO LLM) ──────────────
4
+ /** A canned `DraftExtractor`: returns a fixed `string[]` keyed by PR (default to a 1-elem draft). */
5
+ class StubExtractor {
6
+ byPr;
7
+ constructor(byPr) {
8
+ this.byPr = byPr;
9
+ }
10
+ draft(content) {
11
+ return Promise.resolve(this.byPr.get(content.pr) ?? [`draft for PR ${content.pr}`]);
12
+ }
13
+ }
14
+ /** A canned `DraftClassifier`: returns a fixed result keyed by dslSource (default structural). */
15
+ class StubClassifier {
16
+ byBody;
17
+ constructor(byBody) {
18
+ this.byBody = byBody;
19
+ }
20
+ classify(draft) {
21
+ return Promise.resolve(this.byBody.get(draft.dslSource) ?? {
22
+ disposition: 'structural',
23
+ dispositionSource: 'classified',
24
+ });
25
+ }
26
+ }
27
+ // ─── Fixture builders ────────────────────────────────
28
+ const MERGE_SHA_A = 'a'.repeat(40);
29
+ const MERGE_SHA_B = 'b'.repeat(40);
30
+ function comment(author, body) {
31
+ return { author, body };
32
+ }
33
+ function thread(opts) {
34
+ return {
35
+ path: opts?.path ?? 'packages/core/src/x.ts',
36
+ isResolved: opts?.isResolved ?? false,
37
+ isOutdated: opts?.isOutdated ?? false,
38
+ comments: opts?.comments ?? [comment('jane', 'a structural note')],
39
+ };
40
+ }
41
+ function content(opts) {
42
+ return {
43
+ pr: opts?.pr ?? 100,
44
+ mergeCommitSha: opts?.mergeCommitSha ?? MERGE_SHA_A,
45
+ threads: opts?.threads ?? [thread()],
46
+ };
47
+ }
48
+ function draft(opts) {
49
+ return {
50
+ provenance: {
51
+ mergedPr: opts?.pr ?? 100,
52
+ reviewThread: `pulls/${opts?.pr ?? 100}/comments`,
53
+ commitSha: opts?.commitSha ?? MERGE_SHA_A,
54
+ },
55
+ dslSource: opts?.dslSource ?? '**Pattern:** no-foo',
56
+ };
57
+ }
58
+ const STUB_PROVENANCE = {
59
+ promptTemplateHash: 'p'.repeat(64),
60
+ systemPromptHash: 's'.repeat(64),
61
+ provider: 'anthropic',
62
+ model: 'stub-model-1',
63
+ temperature: 0,
64
+ orchestratorVersion: 'stub-orchestrator-0',
65
+ adapterKind: 'extractor+classifier',
66
+ keyVersion: 'v1',
67
+ totemVersion: '0.0.0-test',
68
+ };
69
+ /** Per-draft ref resolver: a stable (pr, dslSource) ordinal-free ref for tests. */
70
+ function draftRefOf(d) {
71
+ return `cand-${d.provenance.mergedPr}-${d.dslSource}`;
72
+ }
73
+ // ─── 1. Record → replay determinism (FM-a) ───────────
74
+ describe('record → replay determinism (FM-a)', () => {
75
+ it('replays byte-identical extractor + classifier outputs recorded from a stub', async () => {
76
+ const sink = new ReplayRecordSink();
77
+ const recExtractor = new RecordingDraftExtractor(new StubExtractor(new Map([[100, ['draft-A', 'draft-B']]])), sink);
78
+ const recClassifier = new RecordingDraftClassifier(new StubClassifier(new Map([['draft-A', { disposition: 'behavioral', dispositionSource: 'classified' }]])), sink, draftRefOf);
79
+ const c = content({ pr: 100 });
80
+ const recordedDrafts = await recExtractor.draft(c);
81
+ const d = draft({ pr: 100, dslSource: 'draft-A' });
82
+ const recordedClass = await recClassifier.classify(d);
83
+ const artifact = sink.freeze(STUB_PROVENANCE);
84
+ const expectedHash = computeArtifactHash(artifact);
85
+ // Round-trip through serialization to prove the on-disk form replays too.
86
+ const reloaded = ReplayArtifactSchema.parse(JSON.parse(serializeReplayArtifact(artifact)));
87
+ const replayExtractor = new ReplayDraftExtractor(reloaded, expectedHash);
88
+ const replayClassifier = new ReplayDraftClassifier(reloaded, expectedHash, draftRefOf);
89
+ expect(await replayExtractor.draft(c)).toEqual(recordedDrafts);
90
+ expect(await replayClassifier.classify(d)).toEqual(recordedClass);
91
+ // And the recorded values are exactly what the stub produced.
92
+ expect(recordedDrafts).toEqual(['draft-A', 'draft-B']);
93
+ expect(recordedClass).toEqual({ disposition: 'behavioral', dispositionSource: 'classified' });
94
+ });
95
+ it('serializes deterministically regardless of record insertion order', async () => {
96
+ const buildSink = async (prs) => {
97
+ const sink = new ReplayRecordSink();
98
+ const rec = new RecordingDraftExtractor(new StubExtractor(new Map(prs.map((p) => [p, [`d-${p}`]]))), sink);
99
+ for (const p of prs)
100
+ await rec.draft(content({ pr: p }));
101
+ return sink.freeze(STUB_PROVENANCE);
102
+ };
103
+ const forward = serializeReplayArtifact(await buildSink([100, 200, 300]));
104
+ const reversed = serializeReplayArtifact(await buildSink([300, 200, 100]));
105
+ expect(forward).toBe(reversed);
106
+ });
107
+ });
108
+ // ─── 2. Drift / mutation red craft → FixtureIntegrityError ───────────────────
109
+ describe('drift / mutation red craft (fold B integrity)', () => {
110
+ it('throws FixtureIntegrityError when a recorded entry is mutated without updating the expected hash', async () => {
111
+ const sink = new ReplayRecordSink();
112
+ const rec = new RecordingDraftExtractor(new StubExtractor(new Map([[100, ['original']]])), sink);
113
+ await rec.draft(content({ pr: 100 }));
114
+ const artifact = sink.freeze(STUB_PROVENANCE);
115
+ const expectedHash = computeArtifactHash(artifact); // frozen at record time
116
+ // Tamper with ONE recorded raw entry, leaving the injected expected hash stale.
117
+ const key = extractorInputKey(content({ pr: 100 }));
118
+ const tampered = {
119
+ ...artifact,
120
+ records: {
121
+ ...artifact.records,
122
+ extractor: { ...artifact.records.extractor, [key]: ['TAMPERED'] },
123
+ },
124
+ };
125
+ expect(() => new ReplayDraftExtractor(tampered, expectedHash)).toThrow(FixtureIntegrityError);
126
+ expect(() => new ReplayDraftExtractor(tampered, expectedHash)).toThrow(/expected .* got /);
127
+ // The classifier replay shares the same gate.
128
+ expect(() => new ReplayDraftClassifier(tampered, expectedHash, draftRefOf)).toThrow(FixtureIntegrityError);
129
+ });
130
+ it('constructs cleanly when the expected hash matches the (untampered) records', async () => {
131
+ const sink = new ReplayRecordSink();
132
+ const rec = new RecordingDraftExtractor(new StubExtractor(new Map([[100, ['ok']]])), sink);
133
+ await rec.draft(content({ pr: 100 }));
134
+ const artifact = sink.freeze(STUB_PROVENANCE);
135
+ expect(() => new ReplayDraftExtractor(artifact, computeArtifactHash(artifact))).not.toThrow();
136
+ });
137
+ it('throws FixtureIntegrityError when a PROVENANCE field is mutated (fold F — prompt-hash covered by the gate)', async () => {
138
+ const sink = new ReplayRecordSink();
139
+ const rec = new RecordingDraftExtractor(new StubExtractor(new Map([[100, ['ok']]])), sink);
140
+ await rec.draft(content({ pr: 100 }));
141
+ const artifact = sink.freeze(STUB_PROVENANCE);
142
+ const expectedHash = computeArtifactHash(artifact); // frozen at record time
143
+ // Edit a PROVENANCE field (the prompt-template hash) WITHOUT re-recording or
144
+ // updating the expected hash. The integrity gate covers the whole artifact, so
145
+ // a prompt change must force a re-record — it can NEVER silently serve the same
146
+ // recorded outputs under a changed prompt (fold F). The records are untouched,
147
+ // so a records-only hash would MISS this; the whole-artifact hash catches it.
148
+ const tampered = {
149
+ ...artifact,
150
+ provenance: { ...artifact.provenance, promptTemplateHash: 'q'.repeat(64) },
151
+ };
152
+ expect(() => new ReplayDraftExtractor(tampered, expectedHash)).toThrow(FixtureIntegrityError);
153
+ expect(() => new ReplayDraftClassifier(tampered, expectedHash, draftRefOf)).toThrow(FixtureIntegrityError);
154
+ });
155
+ });
156
+ // ─── 3. Replay miss red craft → ReplayMissError (not a safe-default) ─────────
157
+ describe('replay miss red craft', () => {
158
+ it('throws ReplayMissError on an absent extractor inputKey — NOT a []', async () => {
159
+ const sink = new ReplayRecordSink();
160
+ const rec = new RecordingDraftExtractor(new StubExtractor(new Map([[100, ['recorded']]])), sink);
161
+ await rec.draft(content({ pr: 100 }));
162
+ const artifact = sink.freeze(STUB_PROVENANCE);
163
+ const replay = new ReplayDraftExtractor(artifact, computeArtifactHash(artifact));
164
+ // PR 999 was never recorded → MISS. It REJECTS with ReplayMissError; it must
165
+ // NOT resolve to a safe-default [] (the whole point of the no-fallback rule).
166
+ const missContent = content({ pr: 999 });
167
+ await expect(replay.draft(missContent)).rejects.toBeInstanceOf(ReplayMissError);
168
+ let resolvedTo;
169
+ await replay.draft(missContent).then((v) => {
170
+ resolvedTo = v;
171
+ }, () => {
172
+ /* expected rejection */
173
+ });
174
+ expect(resolvedTo).toBeUndefined();
175
+ });
176
+ it('throws ReplayMissError on an absent classifier inputKey — NOT a {behavioral, error-default}', async () => {
177
+ const sink = new ReplayRecordSink();
178
+ const rec = new RecordingDraftClassifier(new StubClassifier(new Map()), sink, draftRefOf);
179
+ await rec.classify(draft({ pr: 100, dslSource: 'recorded-body' }));
180
+ const artifact = sink.freeze(STUB_PROVENANCE);
181
+ const replay = new ReplayDraftClassifier(artifact, computeArtifactHash(artifact), draftRefOf);
182
+ await expect(replay.classify(draft({ pr: 100, dslSource: 'never-recorded' }))).rejects.toBeInstanceOf(ReplayMissError);
183
+ });
184
+ });
185
+ // ─── 4. Recorded-empty vs miss ───────────────────────
186
+ describe('recorded-empty vs miss (real rows, distinguishable from absence)', () => {
187
+ it('replays a recorded [] (extractor) as [] — a real row, not a miss', async () => {
188
+ const sink = new ReplayRecordSink();
189
+ const rec = new RecordingDraftExtractor(new StubExtractor(new Map([[100, []]])), sink);
190
+ const recorded = await rec.draft(content({ pr: 100 }));
191
+ expect(recorded).toEqual([]);
192
+ const artifact = sink.freeze(STUB_PROVENANCE);
193
+ const replay = new ReplayDraftExtractor(artifact, computeArtifactHash(artifact));
194
+ // HIT on a recorded [] — returns [], does NOT throw ReplayMissError.
195
+ await expect(replay.draft(content({ pr: 100 }))).resolves.toEqual([]);
196
+ });
197
+ it('replays a recorded {behavioral, error-default} (classifier) as that exact value', async () => {
198
+ const errorDefault = {
199
+ disposition: 'behavioral',
200
+ dispositionSource: 'error-default',
201
+ };
202
+ const sink = new ReplayRecordSink();
203
+ const rec = new RecordingDraftClassifier(new StubClassifier(new Map([['err-body', errorDefault]])), sink, draftRefOf);
204
+ const recorded = await rec.classify(draft({ pr: 100, dslSource: 'err-body' }));
205
+ expect(recorded).toEqual(errorDefault);
206
+ const artifact = sink.freeze(STUB_PROVENANCE);
207
+ const replay = new ReplayDraftClassifier(artifact, computeArtifactHash(artifact), draftRefOf);
208
+ await expect(replay.classify(draft({ pr: 100, dslSource: 'err-body' }))).resolves.toEqual(errorDefault);
209
+ });
210
+ });
211
+ // ─── 5. Duplicate key → throws ───────────────────────
212
+ describe('duplicate (adapterKind, inputKey) → DuplicateRecordError', () => {
213
+ it('throws when the same extractor input is recorded twice (never last-write-wins)', async () => {
214
+ const sink = new ReplayRecordSink();
215
+ const rec = new RecordingDraftExtractor(new StubExtractor(new Map([[100, ['x']]])), sink);
216
+ await rec.draft(content({ pr: 100 }));
217
+ await expect(rec.draft(content({ pr: 100 }))).rejects.toBeInstanceOf(DuplicateRecordError);
218
+ });
219
+ it('throws when the same classifier input (same draftRef) is recorded twice', async () => {
220
+ const sink = new ReplayRecordSink();
221
+ const rec = new RecordingDraftClassifier(new StubClassifier(new Map()), sink, draftRefOf);
222
+ await rec.classify(draft({ pr: 100, dslSource: 'dup' }));
223
+ await expect(rec.classify(draft({ pr: 100, dslSource: 'dup' }))).rejects.toBeInstanceOf(DuplicateRecordError);
224
+ });
225
+ it('does NOT collide two different sections sharing a coincidental key value', () => {
226
+ // extractor + classifier maps are independent; the same string in both is fine.
227
+ const sink = new ReplayRecordSink();
228
+ sink.recordExtractor('shared-key', ['e']);
229
+ expect(() => sink.recordClassifier('shared-key', {
230
+ disposition: 'structural',
231
+ dispositionSource: 'classified',
232
+ })).not.toThrow();
233
+ });
234
+ });
235
+ // ─── 6. inputKey semantics (fold D) ──────────────────
236
+ describe('extractorInputKey (fold D)', () => {
237
+ it('is stable for identical eligible content + same mergeCommitSha', () => {
238
+ const a = extractorInputKey(content({ pr: 100, mergeCommitSha: MERGE_SHA_A }));
239
+ const b = extractorInputKey(content({ pr: 100, mergeCommitSha: MERGE_SHA_A }));
240
+ expect(a).toBe(b);
241
+ });
242
+ it('differs when mergeCommitSha differs (provenance identity)', () => {
243
+ const a = extractorInputKey(content({ pr: 100, mergeCommitSha: MERGE_SHA_A }));
244
+ const b = extractorInputKey(content({ pr: 100, mergeCommitSha: MERGE_SHA_B }));
245
+ expect(a).not.toBe(b);
246
+ });
247
+ it('is INVARIANT to thread + comment reordering (normalization holds)', () => {
248
+ const t1 = thread({
249
+ path: 'a.ts',
250
+ comments: [comment('al', 'first'), comment('bo', 'second')],
251
+ });
252
+ const t2 = thread({ path: 'b.ts', comments: [comment('cy', 'third')] });
253
+ const forward = extractorInputKey(content({ threads: [t1, t2] }));
254
+ // Reverse the threads AND reverse t1's comments.
255
+ const t1rev = thread({
256
+ path: 'a.ts',
257
+ comments: [comment('bo', 'second'), comment('al', 'first')],
258
+ });
259
+ const reversed = extractorInputKey(content({ threads: [t2, t1rev] }));
260
+ expect(forward).toBe(reversed);
261
+ });
262
+ it('is INVARIANT to reordering threads on the SAME path that differ in later comments', () => {
263
+ // The bug greptile P1 + CR caught: two threads on ONE path sharing a first
264
+ // comment but differing LATER compared equal under the old (path, first-comment)
265
+ // sort → provider order leaked into the key. The full-canonical-JSON total order
266
+ // fixes it. (comments normalize by (body, author): 'shared' sorts before 'tail-*'.)
267
+ const t1 = thread({
268
+ path: 'same.ts',
269
+ comments: [comment('al', 'shared'), comment('al', 'tail-1')],
270
+ });
271
+ const t2 = thread({
272
+ path: 'same.ts',
273
+ comments: [comment('al', 'shared'), comment('al', 'tail-2')],
274
+ });
275
+ const forward = extractorInputKey(content({ threads: [t1, t2] }));
276
+ const reversed = extractorInputKey(content({ threads: [t2, t1] }));
277
+ expect(forward).toBe(reversed);
278
+ });
279
+ it('excludes resolved/outdated threads from the key (the port never sees them)', () => {
280
+ const eligible = thread({ path: 'a.ts', comments: [comment('al', 'keep')] });
281
+ const resolved = thread({ path: 'z.ts', isResolved: true, comments: [comment('zo', 'drop')] });
282
+ const withResolved = extractorInputKey(content({ threads: [eligible, resolved] }));
283
+ const withoutResolved = extractorInputKey(content({ threads: [eligible] }));
284
+ expect(withResolved).toBe(withoutResolved);
285
+ });
286
+ });
287
+ describe('ClassifierResultLocalSchema parity with core (GCA #2209, option a)', () => {
288
+ it('accepts / rejects EXACTLY what core ClassifierResultSchema does', async () => {
289
+ // The local CLI-side schema avoids a static runtime import of core's barrel
290
+ // (CLI-startup styleguide). This test is the guard against drift: a test MAY
291
+ // static-import core (the rule is about command-file startup, not tests).
292
+ const { ClassifierResultSchema } = await import('@mmnto/totem');
293
+ const cases = [
294
+ { disposition: 'structural', dispositionSource: 'classified' }, // valid
295
+ { disposition: 'behavioral', dispositionSource: 'classified' }, // valid
296
+ { disposition: 'behavioral', dispositionSource: 'error-default' }, // valid (safe-default)
297
+ { disposition: 'structural', dispositionSource: 'error-default' }, // refine → invalid
298
+ { disposition: 'nope', dispositionSource: 'classified' }, // enum → invalid
299
+ { disposition: 'structural' }, // missing field → invalid
300
+ ];
301
+ for (const c of cases) {
302
+ expect(ClassifierResultLocalSchema.safeParse(c).success).toBe(ClassifierResultSchema.safeParse(c).success);
303
+ }
304
+ });
305
+ });
306
+ describe('classifierInputKey (fold D)', () => {
307
+ it('is stable for the same provenance + dslSource + draftRef', () => {
308
+ const d = draft({ pr: 100, dslSource: 'body' });
309
+ expect(classifierInputKey(d, 'ref-0')).toBe(classifierInputKey(d, 'ref-0'));
310
+ });
311
+ it('two drafts from the SAME provenance with different draftRef do NOT collide', () => {
312
+ const d = draft({ pr: 100, dslSource: 'identical-body' });
313
+ // The classifier does not dedupe — two drafts (same provenance, same body)
314
+ // must key distinctly via draftRef.
315
+ expect(classifierInputKey(d, 'ref-0')).not.toBe(classifierInputKey(d, 'ref-1'));
316
+ });
317
+ it('differs when dslSource differs', () => {
318
+ const a = classifierInputKey(draft({ pr: 100, dslSource: 'body-a' }), 'ref-0');
319
+ const b = classifierInputKey(draft({ pr: 100, dslSource: 'body-b' }), 'ref-0');
320
+ expect(a).not.toBe(b);
321
+ });
322
+ });
323
+ // ─── 7. Serialization hygiene ────────────────────────
324
+ describe('serialization hygiene', () => {
325
+ it('serializes record keys SORTED (clean git diffs)', async () => {
326
+ const sink = new ReplayRecordSink();
327
+ const rec = new RecordingDraftExtractor(new StubExtractor(new Map([
328
+ [300, ['c']],
329
+ [100, ['a']],
330
+ [200, ['b']],
331
+ ])), sink);
332
+ // Record out of key order.
333
+ await rec.draft(content({ pr: 300 }));
334
+ await rec.draft(content({ pr: 100 }));
335
+ await rec.draft(content({ pr: 200 }));
336
+ const serialized = serializeReplayArtifact(sink.freeze(STUB_PROVENANCE));
337
+ const parsed = JSON.parse(serialized);
338
+ const keys = Object.keys(parsed.records.extractor);
339
+ expect(keys).toEqual([...keys].sort());
340
+ expect(keys).toHaveLength(3);
341
+ });
342
+ it('NEVER leaks durationMs / recordedAt / metadata into a record value', async () => {
343
+ const sink = new ReplayRecordSink();
344
+ const rec = new RecordingDraftExtractor(new StubExtractor(new Map([[100, ['only-the-output']]])), sink);
345
+ await rec.draft(content({ pr: 100 }));
346
+ const recC = new RecordingDraftClassifier(new StubClassifier(new Map()), sink, draftRefOf);
347
+ await recC.classify(draft({ pr: 100, dslSource: 'b' }));
348
+ const serialized = serializeReplayArtifact(sink.freeze(STUB_PROVENANCE));
349
+ // No non-deterministic / identifying metadata anywhere in the records block.
350
+ expect(serialized).not.toMatch(/durationMs|recordedAt|runId|run-id|localUser|userId/i);
351
+ const parsed = JSON.parse(serialized);
352
+ // Each record VALUE is strictly the port's output shape — nothing else.
353
+ const extractorVal = Object.values(parsed.records.extractor)[0];
354
+ expect(extractorVal).toEqual(['only-the-output']);
355
+ const classifierVal = Object.values(parsed.records.classifier)[0];
356
+ expect(Object.keys(classifierVal).sort()).toEqual([
357
+ 'disposition',
358
+ 'dispositionSource',
359
+ ]);
360
+ });
361
+ it('carries the artifact kind tag + provenance block OUTSIDE the records map', async () => {
362
+ const sink = new ReplayRecordSink();
363
+ const rec = new RecordingDraftExtractor(new StubExtractor(new Map([[100, ['x']]])), sink);
364
+ await rec.draft(content({ pr: 100 }));
365
+ const artifact = sink.freeze(STUB_PROVENANCE);
366
+ expect(artifact.kind).toBe(REPLAY_ARTIFACT_KIND);
367
+ expect(artifact.provenance).toEqual(STUB_PROVENANCE);
368
+ // Provenance is not inside records.
369
+ expect(JSON.stringify(artifact.records)).not.toContain('anthropic');
370
+ });
371
+ });
372
+ //# sourceMappingURL=spine-llm-replay.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-llm-replay.test.js","sourceRoot":"","sources":["../../src/commands/spine-llm-replay.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,165 @@
1
+ /**
2
+ * ADR-111 Stage-1 Extract — the live CLI `ReviewThreadSource` adapter (slice 5a,
3
+ * mmnto-ai/totem#2201).
4
+ *
5
+ * Core defines the `ReviewThreadSource` port and stays network-free + LLM-free +
6
+ * deterministic; THIS file is the IO-at-the-edge implementation that wraps the
7
+ * GitHub GraphQL `reviewThreads` API behind that port. It fetches a PR's merge
8
+ * commit + its review threads (each carrying `isResolved` / `isOutdated`), maps
9
+ * them to the provider-neutral `ReviewThreadContent`, and SURFACES the per-thread
10
+ * resolution flags to core. It does NOT filter resolved/outdated threads — the
11
+ * contract-owner ruling is "surface, don't filter": core decides eligibility and
12
+ * drop-ledgers every rejection (§8 "every rejection ledgered"). A server-side or
13
+ * client-side `isResolved:false` pre-filter is FORBIDDEN here.
14
+ *
15
+ * Error contract (the discriminated `FetchResult`, §6): a per-PR failure is NEVER
16
+ * thrown — the orchestrator iterates the whole train slice and must not abort on
17
+ * one bad PR. Network / not-found → `{kind:'unreachable'}`; a malformed or
18
+ * unmappable payload → `{kind:'unparseable'}`. The mining run continues; the loud
19
+ * drop is core's job.
20
+ *
21
+ * Reuses the established `gh` CLI exec pattern (Tenet-21 — no bespoke GraphQL
22
+ * client). The `exec` seam is injectable so the query-spy + mapping tests run
23
+ * fully offline (no network, CI-locked).
24
+ */
25
+ import { z } from 'zod';
26
+ import type { FetchResult, ReviewThread, ReviewThreadSource } from '@mmnto/totem';
27
+ declare const GqlReviewThreadSchema: z.ZodObject<{
28
+ isResolved: z.ZodBoolean;
29
+ isOutdated: z.ZodBoolean;
30
+ path: z.ZodString;
31
+ comments: z.ZodObject<{
32
+ pageInfo: z.ZodObject<{
33
+ hasNextPage: z.ZodBoolean;
34
+ }, "strip", z.ZodTypeAny, {
35
+ hasNextPage: boolean;
36
+ }, {
37
+ hasNextPage: boolean;
38
+ }>;
39
+ nodes: z.ZodArray<z.ZodObject<{
40
+ author: z.ZodNullable<z.ZodObject<{
41
+ login: z.ZodString;
42
+ }, "strip", z.ZodTypeAny, {
43
+ login: string;
44
+ }, {
45
+ login: string;
46
+ }>>;
47
+ body: z.ZodString;
48
+ }, "strip", z.ZodTypeAny, {
49
+ body: string;
50
+ author: {
51
+ login: string;
52
+ } | null;
53
+ }, {
54
+ body: string;
55
+ author: {
56
+ login: string;
57
+ } | null;
58
+ }>, "many">;
59
+ }, "strip", z.ZodTypeAny, {
60
+ pageInfo: {
61
+ hasNextPage: boolean;
62
+ };
63
+ nodes: {
64
+ body: string;
65
+ author: {
66
+ login: string;
67
+ } | null;
68
+ }[];
69
+ }, {
70
+ pageInfo: {
71
+ hasNextPage: boolean;
72
+ };
73
+ nodes: {
74
+ body: string;
75
+ author: {
76
+ login: string;
77
+ } | null;
78
+ }[];
79
+ }>;
80
+ }, "strip", z.ZodTypeAny, {
81
+ path: string;
82
+ comments: {
83
+ pageInfo: {
84
+ hasNextPage: boolean;
85
+ };
86
+ nodes: {
87
+ body: string;
88
+ author: {
89
+ login: string;
90
+ } | null;
91
+ }[];
92
+ };
93
+ isResolved: boolean;
94
+ isOutdated: boolean;
95
+ }, {
96
+ path: string;
97
+ comments: {
98
+ pageInfo: {
99
+ hasNextPage: boolean;
100
+ };
101
+ nodes: {
102
+ body: string;
103
+ author: {
104
+ login: string;
105
+ } | null;
106
+ }[];
107
+ };
108
+ isResolved: boolean;
109
+ isOutdated: boolean;
110
+ }>;
111
+ /**
112
+ * Build the `reviewThreads` GraphQL query. It REQUESTS `isResolved` and
113
+ * `isOutdated` per thread (so core HAS the signal to decide on) — it deliberately
114
+ * does NOT add an `isResolved: false` server-side filter (the "surface, don't
115
+ * filter" ruling; the query-spy test asserts both halves). Exported for the
116
+ * query-spy test.
117
+ */
118
+ export declare function buildReviewThreadsQuery(owner: string, name: string, pr: number): string;
119
+ /**
120
+ * The injectable command-exec seam. Matches the relevant part of `safeExec`'s
121
+ * signature; the tests pass a fake that intercepts the outgoing GraphQL query
122
+ * (no network). When not injected, the adapter lazy-loads `safeExec` (below).
123
+ */
124
+ export type GhExec = (command: string, args: string[]) => string;
125
+ /**
126
+ * Map a validated GraphQL response to the surviving `ReviewThread[]` with their
127
+ * resolution flags surfaced. Pure — exported for the mapping test. A null author
128
+ * (deleted/ghost) coerces to '' (`isBotIdentity('')` is false, so it stays a
129
+ * human-author '' that core's empty-body / count logic handles correctly; the
130
+ * body still gates inclusion).
131
+ */
132
+ export declare function mapThreads(nodes: z.infer<typeof GqlReviewThreadSchema>[]): ReviewThread[];
133
+ export interface ReviewThreadSourceAdapterOptions {
134
+ /** The repo to query, as `owner` + `name`. */
135
+ owner: string;
136
+ name: string;
137
+ /** Working directory for the `gh` invocation (real adapter). */
138
+ cwd?: string;
139
+ /** Injectable exec seam (tests). Defaults to a `gh`-backed `safeExec`. */
140
+ exec?: GhExec;
141
+ }
142
+ /**
143
+ * The live `ReviewThreadSource`. Constructible + exported now (slice 5a); wiring
144
+ * it into the spine orchestrator's `run` command is slice 5c.
145
+ */
146
+ export declare class ReviewThreadSourceAdapter implements ReviewThreadSource {
147
+ private readonly owner;
148
+ private readonly name;
149
+ private readonly cwd;
150
+ /** Injected exec seam (tests); when absent the default is lazy-loaded once via `execPromise`. */
151
+ private readonly injectedExec;
152
+ /**
153
+ * Memoized lazy-load of the default `gh`-backed exec (real runs). Memoizes the
154
+ * PROMISE, not the resolved value, so concurrent `fetch()` calls on one adapter
155
+ * instance share a single `loadDefaultExec` instead of racing a `!this.exec`
156
+ * guard (CR #2207 — was benign since dynamic import is idempotent, now explicit).
157
+ */
158
+ private execPromise;
159
+ constructor(opts: ReviewThreadSourceAdapterOptions);
160
+ /** Resolve the exec seam: the injected one (tests), else the memoized lazy-loaded default. */
161
+ private resolveExec;
162
+ fetch(pr: number): Promise<FetchResult>;
163
+ }
164
+ export {};
165
+ //# sourceMappingURL=spine-review-thread-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-review-thread-source.d.ts","sourceRoot":"","sources":["../../src/commands/spine-review-thread-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AA6BlF,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQzB,CAAC;AAsBH;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAuBvF;AAID;;;;GAIG;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,CAAC;AAoBjE;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,EAAE,GAAG,YAAY,EAAE,CAWzF;AAID,MAAM,WAAW,gCAAgC;IAC/C,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,qBAAa,yBAA0B,YAAW,kBAAkB;IAClE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,iGAAiG;IACjG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD;;;;;OAKG;IACH,OAAO,CAAC,WAAW,CAA8B;gBAErC,IAAI,EAAE,gCAAgC;IAOlD,8FAA8F;IAC9F,OAAO,CAAC,WAAW;IAMb,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAoF9C"}