@mmnto/cli 1.68.0 → 1.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/spine-llm-adapters.d.ts +273 -0
- package/dist/commands/spine-llm-adapters.d.ts.map +1 -0
- package/dist/commands/spine-llm-adapters.js +549 -0
- package/dist/commands/spine-llm-adapters.js.map +1 -0
- package/dist/commands/spine-llm-adapters.test.d.ts +2 -0
- package/dist/commands/spine-llm-adapters.test.d.ts.map +1 -0
- package/dist/commands/spine-llm-adapters.test.js +395 -0
- package/dist/commands/spine-llm-adapters.test.js.map +1 -0
- package/dist/commands/spine-llm-replay.d.ts +446 -0
- package/dist/commands/spine-llm-replay.d.ts.map +1 -0
- package/dist/commands/spine-llm-replay.js +492 -0
- package/dist/commands/spine-llm-replay.js.map +1 -0
- package/dist/commands/spine-llm-replay.test.d.ts +2 -0
- package/dist/commands/spine-llm-replay.test.d.ts.map +1 -0
- package/dist/commands/spine-llm-replay.test.js +372 -0
- package/dist/commands/spine-llm-replay.test.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-111 miner slice 5b-i — the deterministic LLM record/replay SCAFFOLD.
|
|
3
|
+
*
|
|
4
|
+
* The certifying run (slice 5) introduces the miner's first NON-deterministic,
|
|
5
|
+
* LLM-backed components (the live `DraftExtractor` / `DraftClassifier` adapters,
|
|
6
|
+
* slice 5b-ii). The cohort panel's central answer (consolidated fold A, 4/4) is
|
|
7
|
+
* that those live outputs must be FROZEN into a recorded replay artifact so the
|
|
8
|
+
* scorer + falsification harness can re-run the certifying experiment ZERO-LLM,
|
|
9
|
+
* byte-deterministically, and auditably — "arguably contract-MANDATED" by §6
|
|
10
|
+
* (fail-loud, no degrade) + §8 (every decision ledgered) + Tenet-15.
|
|
11
|
+
*
|
|
12
|
+
* THIS file is the deterministic record/replay scaffold proven in isolation with
|
|
13
|
+
* a STUB orchestrator: NO live LLM, NO network, NO prompts (those are slice
|
|
14
|
+
* 5b-ii, which populates the provenance block from the real adapter). It defines:
|
|
15
|
+
*
|
|
16
|
+
* - the `llm-replay.v1` Zod artifact (two typed record sections + a provenance
|
|
17
|
+
* block), CLI-side — the replay artifact is a CLI-layer concern; core stays
|
|
18
|
+
* unaware of it;
|
|
19
|
+
* - the deterministic `inputKey` digests for the extractor + classifier ports
|
|
20
|
+
* (mirroring core's `deriveClaimId` — `sha256("<prefix>" + canonicalJson(...))`
|
|
21
|
+
* over IDENTITY fields only);
|
|
22
|
+
* - record/replay decorators (generic over the port) that wrap the core ports;
|
|
23
|
+
* - the EXTERNAL-expected-hash integrity gate (fold B — a self-hash the artifact
|
|
24
|
+
* validates against itself is circular; a content+hash co-rewrite would pass).
|
|
25
|
+
*
|
|
26
|
+
* Determinism discipline: this module is `new Date()` / `Math.random()` -free. A
|
|
27
|
+
* recorded `[]` (extractor) or `{behavioral, error-default}` (classifier) is a
|
|
28
|
+
* REAL row — present in the map, distinguishable from a missing key (a replay
|
|
29
|
+
* MISS is a corpus-integrity failure, never a safe-default).
|
|
30
|
+
*
|
|
31
|
+
* Reuse (Tenet-21): the canonical key-sorted serializer (`canonicalStringify`),
|
|
32
|
+
* the full-digest hash (`calculateDeterministicHash` shape), the `deriveClaimId`
|
|
33
|
+
* identity-fields-only pattern, and the wind-tunnel's external-expected-hash
|
|
34
|
+
* integrity discipline (`verifyControlIntegrity`) are all reused, not reinvented.
|
|
35
|
+
*/
|
|
36
|
+
import { z } from 'zod';
|
|
37
|
+
import type { ClassifierResult, ExtractStageResult, ReviewThreadContent } from '@mmnto/totem';
|
|
38
|
+
type DraftCandidate = ExtractStageResult['drafts'][number];
|
|
39
|
+
/** Discriminates the two record sections for the duplicate-key guard. */
|
|
40
|
+
export type AdapterKind = 'extractor' | 'classifier';
|
|
41
|
+
/**
|
|
42
|
+
* A replay query hit an `inputKey` absent from the frozen records. This is a
|
|
43
|
+
* CORPUS-INTEGRITY failure, never a recoverable per-PR condition: the frozen
|
|
44
|
+
* experiment's premise is that every input the certifying run will ask for was
|
|
45
|
+
* recorded. A miss means the corpus drifted out from under the replay (a new
|
|
46
|
+
* input appeared, or a recorded one was dropped). Falling back to `[]` /
|
|
47
|
+
* `{behavioral, error-default}` would absorb that drift silently and let the
|
|
48
|
+
* certifying verdict diverge from the frozen one undetected — so we throw.
|
|
49
|
+
*/
|
|
50
|
+
export declare class ReplayMissError extends Error {
|
|
51
|
+
readonly adapterKind: AdapterKind;
|
|
52
|
+
readonly inputKey: string;
|
|
53
|
+
constructor(adapterKind: AdapterKind, inputKey: string);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The loaded replay fixture's content-hash does not match the EXTERNAL expected
|
|
57
|
+
* hash injected at construction (fold B). The expected hash is supplied by the
|
|
58
|
+
* caller (5c sources it from a committed lock), NOT embedded in the artifact —
|
|
59
|
+
* an embedded self-hash would be circular (a content+hash co-rewrite passes its
|
|
60
|
+
* own check). A mismatch means the fixture was tampered with or drifted; the
|
|
61
|
+
* replay must NOT proceed, so we throw AT CONSTRUCTION (before any query).
|
|
62
|
+
*/
|
|
63
|
+
export declare class FixtureIntegrityError extends Error {
|
|
64
|
+
readonly expectedHash: string;
|
|
65
|
+
readonly actualHash: string;
|
|
66
|
+
constructor(expectedHash: string, actualHash: string);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Recording the same `(adapterKind, inputKey)` twice with (potentially)
|
|
70
|
+
* different outputs. The record sink is APPEND-ONCE: a duplicate is never
|
|
71
|
+
* last-write-wins (that would silently launder a non-deterministic adapter's
|
|
72
|
+
* second answer over its first). The recording run must be deterministic, so a
|
|
73
|
+
* duplicate key is a producer bug → throw.
|
|
74
|
+
*/
|
|
75
|
+
export declare class DuplicateRecordError extends Error {
|
|
76
|
+
readonly adapterKind: AdapterKind;
|
|
77
|
+
readonly inputKey: string;
|
|
78
|
+
constructor(adapterKind: AdapterKind, inputKey: string);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Deterministic extractor inputKey (fold D). `sha256(canonicalJson({ keyVersion,
|
|
82
|
+
* pr, mergeCommitSha, threads: <normalized eligible threads> }))`. MUST include
|
|
83
|
+
* `mergeCommitSha` (provenance identity). The eligible set is normalized so
|
|
84
|
+
* provider thread/comment order can't change the key; resolved/outdated threads
|
|
85
|
+
* are excluded (the port never sees them). Mirrors `deriveClaimId`: the version
|
|
86
|
+
* is BOTH a payload field and a digest-input prefix.
|
|
87
|
+
*/
|
|
88
|
+
export declare function extractorInputKey(content: ReviewThreadContent): string;
|
|
89
|
+
/**
|
|
90
|
+
* Deterministic classifier inputKey (fold D). `sha256(canonicalJson({
|
|
91
|
+
* keyVersion, provenance, dslSource, draftRef }))`. The classifier does NOT
|
|
92
|
+
* dedupe drafts — TWO drafts from the SAME provenance must not collide to one
|
|
93
|
+
* key — so `draftRef` (a stable ordinal/ref the caller supplies, e.g. the slice-3
|
|
94
|
+
* per-(pr, ordinal) candidate ref) disambiguates them. Without it, N drafts with
|
|
95
|
+
* an identical body from one PR would map to one record and lose N-1 outputs.
|
|
96
|
+
*/
|
|
97
|
+
export declare function classifierInputKey(draft: DraftCandidate, draftRef: string): string;
|
|
98
|
+
/**
|
|
99
|
+
* Run-level provenance block. In 5b-i these fields are populated by the (stub)
|
|
100
|
+
* caller — the SCHEMA and the integrity gate covering them are what this slice
|
|
101
|
+
* builds; 5b-ii populates them from the live adapter. They pin the exact frozen
|
|
102
|
+
* experiment (prompt + model + adapter + key version + tool version) so a replay
|
|
103
|
+
* is reproducible and a provenance drift is detectable. Provenance lives OUTSIDE
|
|
104
|
+
* the records map (the records block is strictly `inputKey → output`).
|
|
105
|
+
*/
|
|
106
|
+
export declare const ReplayProvenanceSchema: z.ZodObject<{
|
|
107
|
+
/** sha256 of the frozen draft/classify prompt TEMPLATE (the decaying-prompt pin). */
|
|
108
|
+
promptTemplateHash: z.ZodString;
|
|
109
|
+
/** sha256 of the frozen system prompt. */
|
|
110
|
+
systemPromptHash: z.ZodString;
|
|
111
|
+
/** LLM provider id (e.g. `anthropic` / `gemini` / `openai`). */
|
|
112
|
+
provider: z.ZodString;
|
|
113
|
+
/** Model id (e.g. a pinned model snapshot). */
|
|
114
|
+
model: z.ZodString;
|
|
115
|
+
/** Decode temperature the frozen outputs were produced at. */
|
|
116
|
+
temperature: z.ZodNumber;
|
|
117
|
+
/** The orchestrator build the live adapter ran under. */
|
|
118
|
+
orchestratorVersion: z.ZodString;
|
|
119
|
+
/** Which port adapter produced these records (`extractor` / `classifier` / a combined run). */
|
|
120
|
+
adapterKind: z.ZodString;
|
|
121
|
+
/** The inputKey schema version (so a key-shape change is recorded, not silent). */
|
|
122
|
+
keyVersion: z.ZodString;
|
|
123
|
+
/** The totem/CLI version that froze the artifact. */
|
|
124
|
+
totemVersion: z.ZodString;
|
|
125
|
+
}, "strip", z.ZodTypeAny, {
|
|
126
|
+
model: string;
|
|
127
|
+
temperature: number;
|
|
128
|
+
provider: string;
|
|
129
|
+
promptTemplateHash: string;
|
|
130
|
+
systemPromptHash: string;
|
|
131
|
+
orchestratorVersion: string;
|
|
132
|
+
adapterKind: string;
|
|
133
|
+
keyVersion: string;
|
|
134
|
+
totemVersion: string;
|
|
135
|
+
}, {
|
|
136
|
+
model: string;
|
|
137
|
+
temperature: number;
|
|
138
|
+
provider: string;
|
|
139
|
+
promptTemplateHash: string;
|
|
140
|
+
systemPromptHash: string;
|
|
141
|
+
orchestratorVersion: string;
|
|
142
|
+
adapterKind: string;
|
|
143
|
+
keyVersion: string;
|
|
144
|
+
totemVersion: string;
|
|
145
|
+
}>;
|
|
146
|
+
export type ReplayProvenance = z.infer<typeof ReplayProvenanceSchema>;
|
|
147
|
+
/**
|
|
148
|
+
* The records block: STRICTLY `inputKey → the port's raw return value`. A
|
|
149
|
+
* recorded `[]` (extractor) / `{behavioral, error-default}` (classifier) is a
|
|
150
|
+
* REAL row, distinct from a missing key. NEVER write `durationMs` / `recordedAt`
|
|
151
|
+
* / local-user / run-id into a record — those are non-deterministic / identifying
|
|
152
|
+
* metadata that would corrupt the content-hash and break the frozen-experiment
|
|
153
|
+
* premise. The maps are plain `Record<inputKey, output>`; record keys are
|
|
154
|
+
* written SORTED by the canonical serializer (clean git diffs).
|
|
155
|
+
*/
|
|
156
|
+
/**
|
|
157
|
+
* CLI-side validation of a recorded `ClassifierResult` (GCA #2209 + the cohort
|
|
158
|
+
* panel's "replay artifact schema is a CLI-layer concern", gemini): a LOCAL Zod
|
|
159
|
+
* schema rather than a static runtime import of core's `ClassifierResultSchema`
|
|
160
|
+
* (which would pull the heavy `@mmnto/totem` barrel onto the CLI-startup path).
|
|
161
|
+
* Mirrors core's shape AND its refinement (`error-default` ⟹ `behavioral`, the
|
|
162
|
+
* low-privilege safe-default) so a recorded `{structural, error-default}` is
|
|
163
|
+
* rejected. A test asserts parity with core, so this duplication can't silently
|
|
164
|
+
* drift if core's `ClassifierResult` changes.
|
|
165
|
+
*/
|
|
166
|
+
export declare const ClassifierResultLocalSchema: z.ZodEffects<z.ZodObject<{
|
|
167
|
+
disposition: z.ZodEnum<["structural", "behavioral"]>;
|
|
168
|
+
dispositionSource: z.ZodEnum<["classified", "error-default"]>;
|
|
169
|
+
}, "strip", z.ZodTypeAny, {
|
|
170
|
+
disposition: "structural" | "behavioral";
|
|
171
|
+
dispositionSource: "classified" | "error-default";
|
|
172
|
+
}, {
|
|
173
|
+
disposition: "structural" | "behavioral";
|
|
174
|
+
dispositionSource: "classified" | "error-default";
|
|
175
|
+
}>, {
|
|
176
|
+
disposition: "structural" | "behavioral";
|
|
177
|
+
dispositionSource: "classified" | "error-default";
|
|
178
|
+
}, {
|
|
179
|
+
disposition: "structural" | "behavioral";
|
|
180
|
+
dispositionSource: "classified" | "error-default";
|
|
181
|
+
}>;
|
|
182
|
+
export declare const ReplayRecordsSchema: z.ZodObject<{
|
|
183
|
+
/** `inputKey → DraftExtractor.draft()` return (a `string[]`; `[]` is a real row). */
|
|
184
|
+
extractor: z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString, "many">>;
|
|
185
|
+
/** `inputKey → DraftClassifier.classify()` return (a `ClassifierResult`). */
|
|
186
|
+
classifier: z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodObject<{
|
|
187
|
+
disposition: z.ZodEnum<["structural", "behavioral"]>;
|
|
188
|
+
dispositionSource: z.ZodEnum<["classified", "error-default"]>;
|
|
189
|
+
}, "strip", z.ZodTypeAny, {
|
|
190
|
+
disposition: "structural" | "behavioral";
|
|
191
|
+
dispositionSource: "classified" | "error-default";
|
|
192
|
+
}, {
|
|
193
|
+
disposition: "structural" | "behavioral";
|
|
194
|
+
dispositionSource: "classified" | "error-default";
|
|
195
|
+
}>, {
|
|
196
|
+
disposition: "structural" | "behavioral";
|
|
197
|
+
dispositionSource: "classified" | "error-default";
|
|
198
|
+
}, {
|
|
199
|
+
disposition: "structural" | "behavioral";
|
|
200
|
+
dispositionSource: "classified" | "error-default";
|
|
201
|
+
}>>;
|
|
202
|
+
}, "strip", z.ZodTypeAny, {
|
|
203
|
+
extractor: Record<string, string[]>;
|
|
204
|
+
classifier: Record<string, {
|
|
205
|
+
disposition: "structural" | "behavioral";
|
|
206
|
+
dispositionSource: "classified" | "error-default";
|
|
207
|
+
}>;
|
|
208
|
+
}, {
|
|
209
|
+
extractor: Record<string, string[]>;
|
|
210
|
+
classifier: Record<string, {
|
|
211
|
+
disposition: "structural" | "behavioral";
|
|
212
|
+
dispositionSource: "classified" | "error-default";
|
|
213
|
+
}>;
|
|
214
|
+
}>;
|
|
215
|
+
export type ReplayRecords = z.infer<typeof ReplayRecordsSchema>;
|
|
216
|
+
/** Stable artifact-format tag — bumped if the envelope shape changes. */
|
|
217
|
+
export declare const REPLAY_ARTIFACT_KIND = "llm-replay.v1";
|
|
218
|
+
/** The full `llm-replay.v1` artifact: format tag + provenance + the two record sections. */
|
|
219
|
+
export declare const ReplayArtifactSchema: z.ZodObject<{
|
|
220
|
+
kind: z.ZodLiteral<"llm-replay.v1">;
|
|
221
|
+
provenance: z.ZodObject<{
|
|
222
|
+
/** sha256 of the frozen draft/classify prompt TEMPLATE (the decaying-prompt pin). */
|
|
223
|
+
promptTemplateHash: z.ZodString;
|
|
224
|
+
/** sha256 of the frozen system prompt. */
|
|
225
|
+
systemPromptHash: z.ZodString;
|
|
226
|
+
/** LLM provider id (e.g. `anthropic` / `gemini` / `openai`). */
|
|
227
|
+
provider: z.ZodString;
|
|
228
|
+
/** Model id (e.g. a pinned model snapshot). */
|
|
229
|
+
model: z.ZodString;
|
|
230
|
+
/** Decode temperature the frozen outputs were produced at. */
|
|
231
|
+
temperature: z.ZodNumber;
|
|
232
|
+
/** The orchestrator build the live adapter ran under. */
|
|
233
|
+
orchestratorVersion: z.ZodString;
|
|
234
|
+
/** Which port adapter produced these records (`extractor` / `classifier` / a combined run). */
|
|
235
|
+
adapterKind: z.ZodString;
|
|
236
|
+
/** The inputKey schema version (so a key-shape change is recorded, not silent). */
|
|
237
|
+
keyVersion: z.ZodString;
|
|
238
|
+
/** The totem/CLI version that froze the artifact. */
|
|
239
|
+
totemVersion: z.ZodString;
|
|
240
|
+
}, "strip", z.ZodTypeAny, {
|
|
241
|
+
model: string;
|
|
242
|
+
temperature: number;
|
|
243
|
+
provider: string;
|
|
244
|
+
promptTemplateHash: string;
|
|
245
|
+
systemPromptHash: string;
|
|
246
|
+
orchestratorVersion: string;
|
|
247
|
+
adapterKind: string;
|
|
248
|
+
keyVersion: string;
|
|
249
|
+
totemVersion: string;
|
|
250
|
+
}, {
|
|
251
|
+
model: string;
|
|
252
|
+
temperature: number;
|
|
253
|
+
provider: string;
|
|
254
|
+
promptTemplateHash: string;
|
|
255
|
+
systemPromptHash: string;
|
|
256
|
+
orchestratorVersion: string;
|
|
257
|
+
adapterKind: string;
|
|
258
|
+
keyVersion: string;
|
|
259
|
+
totemVersion: string;
|
|
260
|
+
}>;
|
|
261
|
+
records: z.ZodObject<{
|
|
262
|
+
/** `inputKey → DraftExtractor.draft()` return (a `string[]`; `[]` is a real row). */
|
|
263
|
+
extractor: z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString, "many">>;
|
|
264
|
+
/** `inputKey → DraftClassifier.classify()` return (a `ClassifierResult`). */
|
|
265
|
+
classifier: z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodObject<{
|
|
266
|
+
disposition: z.ZodEnum<["structural", "behavioral"]>;
|
|
267
|
+
dispositionSource: z.ZodEnum<["classified", "error-default"]>;
|
|
268
|
+
}, "strip", z.ZodTypeAny, {
|
|
269
|
+
disposition: "structural" | "behavioral";
|
|
270
|
+
dispositionSource: "classified" | "error-default";
|
|
271
|
+
}, {
|
|
272
|
+
disposition: "structural" | "behavioral";
|
|
273
|
+
dispositionSource: "classified" | "error-default";
|
|
274
|
+
}>, {
|
|
275
|
+
disposition: "structural" | "behavioral";
|
|
276
|
+
dispositionSource: "classified" | "error-default";
|
|
277
|
+
}, {
|
|
278
|
+
disposition: "structural" | "behavioral";
|
|
279
|
+
dispositionSource: "classified" | "error-default";
|
|
280
|
+
}>>;
|
|
281
|
+
}, "strip", z.ZodTypeAny, {
|
|
282
|
+
extractor: Record<string, string[]>;
|
|
283
|
+
classifier: Record<string, {
|
|
284
|
+
disposition: "structural" | "behavioral";
|
|
285
|
+
dispositionSource: "classified" | "error-default";
|
|
286
|
+
}>;
|
|
287
|
+
}, {
|
|
288
|
+
extractor: Record<string, string[]>;
|
|
289
|
+
classifier: Record<string, {
|
|
290
|
+
disposition: "structural" | "behavioral";
|
|
291
|
+
dispositionSource: "classified" | "error-default";
|
|
292
|
+
}>;
|
|
293
|
+
}>;
|
|
294
|
+
}, "strip", z.ZodTypeAny, {
|
|
295
|
+
kind: "llm-replay.v1";
|
|
296
|
+
provenance: {
|
|
297
|
+
model: string;
|
|
298
|
+
temperature: number;
|
|
299
|
+
provider: string;
|
|
300
|
+
promptTemplateHash: string;
|
|
301
|
+
systemPromptHash: string;
|
|
302
|
+
orchestratorVersion: string;
|
|
303
|
+
adapterKind: string;
|
|
304
|
+
keyVersion: string;
|
|
305
|
+
totemVersion: string;
|
|
306
|
+
};
|
|
307
|
+
records: {
|
|
308
|
+
extractor: Record<string, string[]>;
|
|
309
|
+
classifier: Record<string, {
|
|
310
|
+
disposition: "structural" | "behavioral";
|
|
311
|
+
dispositionSource: "classified" | "error-default";
|
|
312
|
+
}>;
|
|
313
|
+
};
|
|
314
|
+
}, {
|
|
315
|
+
kind: "llm-replay.v1";
|
|
316
|
+
provenance: {
|
|
317
|
+
model: string;
|
|
318
|
+
temperature: number;
|
|
319
|
+
provider: string;
|
|
320
|
+
promptTemplateHash: string;
|
|
321
|
+
systemPromptHash: string;
|
|
322
|
+
orchestratorVersion: string;
|
|
323
|
+
adapterKind: string;
|
|
324
|
+
keyVersion: string;
|
|
325
|
+
totemVersion: string;
|
|
326
|
+
};
|
|
327
|
+
records: {
|
|
328
|
+
extractor: Record<string, string[]>;
|
|
329
|
+
classifier: Record<string, {
|
|
330
|
+
disposition: "structural" | "behavioral";
|
|
331
|
+
dispositionSource: "classified" | "error-default";
|
|
332
|
+
}>;
|
|
333
|
+
};
|
|
334
|
+
}>;
|
|
335
|
+
export type ReplayArtifact = z.infer<typeof ReplayArtifactSchema>;
|
|
336
|
+
/**
|
|
337
|
+
* Serialize an artifact to canonical, key-SORTED JSON, PRETTY-printed for a
|
|
338
|
+
* committable artifact + clean diffs. Record keys land sorted because the
|
|
339
|
+
* canonicalizer recursively sorts object keys — so re-freezing in a different
|
|
340
|
+
* insertion order is a no-op diff.
|
|
341
|
+
*
|
|
342
|
+
* NOTE (greptile/CR #2209): the content-hash (`computeArtifactHash`) is computed
|
|
343
|
+
* over the MINIFIED canonical form (`canonicalJson`), NOT these pretty-printed
|
|
344
|
+
* bytes. Both run through the same `canonicalize` (so they never drift on key
|
|
345
|
+
* order), but they are NOT byte-identical — to verify integrity always call
|
|
346
|
+
* `computeArtifactHash(loadedArtifact)`; never `sha256` the raw file bytes.
|
|
347
|
+
*/
|
|
348
|
+
export declare function serializeReplayArtifact(artifact: ReplayArtifact): string;
|
|
349
|
+
/**
|
|
350
|
+
* The artifact CONTENT-HASH (fold B + fold F): sha256 over the canonically-
|
|
351
|
+
* serialized WHOLE artifact (kind + provenance + records). Deterministic +
|
|
352
|
+
* git-independent (the pure replay path has no git dependency — contrast the
|
|
353
|
+
* wind-tunnel's `git hash-object`, which 5c may switch to for wind-tunnel
|
|
354
|
+
* consistency, out of scope here). Hashing the WHOLE artifact (not records-only)
|
|
355
|
+
* means the integrity gate ALSO COVERS the provenance block — so a prompt / model
|
|
356
|
+
* / key-version edit (e.g. `promptTemplateHash`) WITHOUT a re-record trips the
|
|
357
|
+
* gate (fold F: a prompt change must force a re-record, never silently serve
|
|
358
|
+
* stale outputs under a changed prompt). The expected hash is EXTERNAL (caller-
|
|
359
|
+
* injected; 5c sources it from a committed lock) — never embedded (a self-hash
|
|
360
|
+
* the artifact validates against itself is circular: a content+hash co-rewrite
|
|
361
|
+
* would pass its own check).
|
|
362
|
+
*/
|
|
363
|
+
export declare function computeArtifactHash(artifact: ReplayArtifact): string;
|
|
364
|
+
/**
|
|
365
|
+
* The append-once record sink the `Recording*` decorators write into. Holds the
|
|
366
|
+
* in-progress records map; `freeze()` produces the immutable artifact. A
|
|
367
|
+
* duplicate `(adapterKind, inputKey)` throws `DuplicateRecordError` — never
|
|
368
|
+
* last-write-wins (a second output for the same input is a non-determinism leak
|
|
369
|
+
* the recording run must surface, not absorb).
|
|
370
|
+
*/
|
|
371
|
+
export declare class ReplayRecordSink {
|
|
372
|
+
private readonly extractor;
|
|
373
|
+
private readonly classifier;
|
|
374
|
+
recordExtractor(inputKey: string, output: string[]): void;
|
|
375
|
+
recordClassifier(inputKey: string, output: ClassifierResult): void;
|
|
376
|
+
/** Snapshot the records as a plain (Zod-validated) object — keys land sorted on serialize. */
|
|
377
|
+
records(): ReplayRecords;
|
|
378
|
+
/** Assemble the full `llm-replay.v1` artifact from the recorded sink + a provenance block. */
|
|
379
|
+
freeze(provenance: ReplayProvenance): ReplayArtifact;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Records every `DraftExtractor.draft()` call's inputKey → raw `string[]` output
|
|
383
|
+
* into the sink, then passes the value THROUGH unchanged. The recorded value is
|
|
384
|
+
* the PORT's return (pre-core-funnel) — a recorded `[]` is a real row. A
|
|
385
|
+
* duplicate inputKey throws (via the sink).
|
|
386
|
+
*/
|
|
387
|
+
export declare class RecordingDraftExtractor {
|
|
388
|
+
private readonly wrapped;
|
|
389
|
+
private readonly sink;
|
|
390
|
+
constructor(wrapped: {
|
|
391
|
+
draft(content: ReviewThreadContent): Promise<string[]>;
|
|
392
|
+
}, sink: ReplayRecordSink);
|
|
393
|
+
draft(content: ReviewThreadContent): Promise<string[]>;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Records every `DraftClassifier.classify()` call's inputKey → raw
|
|
397
|
+
* `ClassifierResult` output into the sink, then passes it through unchanged. The
|
|
398
|
+
* caller supplies a `draftRef` (the disambiguator for multiple drafts from one
|
|
399
|
+
* provenance — fold D). A duplicate inputKey throws (via the sink).
|
|
400
|
+
*
|
|
401
|
+
* `classify` does not take a `draftRef` in the core port signature, so the
|
|
402
|
+
* decorator binds it via a per-draft ref RESOLVER the caller supplies (e.g. the
|
|
403
|
+
* slice-3 per-(pr, ordinal) candidate ref). The resolver is pure + deterministic.
|
|
404
|
+
*/
|
|
405
|
+
export declare class RecordingDraftClassifier {
|
|
406
|
+
private readonly wrapped;
|
|
407
|
+
private readonly sink;
|
|
408
|
+
private readonly draftRef;
|
|
409
|
+
constructor(wrapped: {
|
|
410
|
+
classify(draft: DraftCandidate): Promise<ClassifierResult>;
|
|
411
|
+
}, sink: ReplayRecordSink, draftRef: (draft: DraftCandidate) => string);
|
|
412
|
+
classify(draft: DraftCandidate): Promise<ClassifierResult>;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* PURE replay of `DraftExtractor` — zero live LLM / network calls. Computes the
|
|
416
|
+
* inputKey for the requested content, looks it up in the frozen records:
|
|
417
|
+
* - HIT → return the recorded `string[]` (including a recorded `[]` — a real row);
|
|
418
|
+
* - MISS → throw `ReplayMissError` (NEVER fall back to `[]`).
|
|
419
|
+
*
|
|
420
|
+
* Integrity (fold B + F): the constructor takes the EXTERNAL expected content-
|
|
421
|
+
* hash, computes the actual WHOLE-ARTIFACT hash (records + provenance), and throws
|
|
422
|
+
* `FixtureIntegrityError` AT CONSTRUCTION on mismatch — so a tampered/drifted
|
|
423
|
+
* fixture (records OR a prompt-provenance edit) can never serve a single replay.
|
|
424
|
+
*/
|
|
425
|
+
export declare class ReplayDraftExtractor {
|
|
426
|
+
private readonly records;
|
|
427
|
+
constructor(fixture: ReplayArtifact, expectedHash: string);
|
|
428
|
+
draft(content: ReviewThreadContent): Promise<string[]>;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* PURE replay of `DraftClassifier` — zero live calls. Computes the inputKey
|
|
432
|
+
* (using the caller's `draftRef` resolver), looks it up:
|
|
433
|
+
* - HIT → return the recorded `ClassifierResult` (including a recorded
|
|
434
|
+
* `{behavioral, error-default}` — a real row);
|
|
435
|
+
* - MISS → throw `ReplayMissError` (NEVER fall back to the safe-default).
|
|
436
|
+
*
|
|
437
|
+
* Same external-expected-hash integrity gate at construction (fold B).
|
|
438
|
+
*/
|
|
439
|
+
export declare class ReplayDraftClassifier {
|
|
440
|
+
private readonly records;
|
|
441
|
+
private readonly draftRef;
|
|
442
|
+
constructor(fixture: ReplayArtifact, expectedHash: string, draftRef: (draft: DraftCandidate) => string);
|
|
443
|
+
classify(draft: DraftCandidate): Promise<ClassifierResult>;
|
|
444
|
+
}
|
|
445
|
+
export {};
|
|
446
|
+
//# sourceMappingURL=spine-llm-replay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spine-llm-replay.d.ts","sourceRoot":"","sources":["../../src/commands/spine-llm-replay.ts"],"names":[],"mappings":"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"}
|