@orkestrel/probe 0.0.1

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,1134 @@
1
+ import { ArrayShape } from '@orkestrel/contract';
2
+ import { EmitterErrorHandler } from '@orkestrel/emitter';
3
+ import { EmitterHooks } from '@orkestrel/emitter';
4
+ import { EmitterInterface } from '@orkestrel/emitter';
5
+ import { Guard } from '@orkestrel/contract';
6
+ import { LiteralShape } from '@orkestrel/contract';
7
+ import { ObjectShape } from '@orkestrel/contract';
8
+ import { StringShape } from '@orkestrel/contract';
9
+
10
+ /**
11
+ * Carries the candidate drafts a claim asserts about and the test that exercises them.
12
+ *
13
+ * @remarks
14
+ * `files` and `test` belong to different TypeScript projects. Each draft in `files` is checked
15
+ * against the project its claim names, and `test` is checked against the root project, because a
16
+ * test needs the Vitest and Node globals the scoped projects remove. A direct type-stage call that
17
+ * supplies no project infers one from each candidate path.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const subject: Case = {
22
+ * files: [{ path: 'src/core/greeting.ts', text: "export const GREETING = 'hi'\n" }],
23
+ * test: {
24
+ * path: 'tmp/probe/greeting.test.ts',
25
+ * text: "import { expect, test } from 'vitest'\nimport { GREETING } from '../../src/core/greeting.js'\ntest('greets', () => expect(GREETING).toBe('hi'))\n",
26
+ * },
27
+ * }
28
+ * ```
29
+ */
30
+ export declare interface Case {
31
+ /** The candidate drafts the test imports, in the order the claim supplies them. */
32
+ readonly files: readonly Draft[];
33
+ /** The test that exercises those drafts. */
34
+ readonly test: Draft;
35
+ }
36
+
37
+ /**
38
+ * Describes the drafts a claim asserts about and the test that exercises them.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * const test = { path: 'tests/src/core/greeting.test.ts', text: '' }
43
+ * compileGuard(CASE_SHAPE)({ files: [], test }) // true
44
+ * ```
45
+ */
46
+ export declare const CASE_SHAPE: ObjectShape<{
47
+ files: ArrayShape<ObjectShape<{
48
+ path: StringShape;
49
+ text: StringShape;
50
+ }, false>>;
51
+ test: ObjectShape<{
52
+ path: StringShape;
53
+ text: StringShape;
54
+ }, false>;
55
+ }, false>;
56
+
57
+ /**
58
+ * Carries one stage's outcome: what it cost and what it reported.
59
+ *
60
+ * @remarks
61
+ * An empty `issues` list is the clean result. There is no separate pass flag, because passing is
62
+ * exactly the absence of issues and a stored flag could disagree with the list beside it.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * const check: Check = { stage: 'lint', elapsed: 17, issues: [] }
67
+ * ```
68
+ */
69
+ export declare interface Check {
70
+ /** The stage that produced this outcome. */
71
+ readonly stage: Stage;
72
+ /** Milliseconds the stage took. */
73
+ readonly elapsed: number;
74
+ /** Every message the stage's tool reported, in the tool's own order. */
75
+ readonly issues: readonly Issue[];
76
+ }
77
+
78
+ /**
79
+ * Carries everything the service needs to produce one verdict.
80
+ *
81
+ * @remarks
82
+ * `project` names the TypeScript project the candidate drafts in both cases are checked against,
83
+ * because the root project admits host globals the scoped projects remove and would report green
84
+ * where the gate reports red. The test drafts remain on the root project for Vitest and Node globals.
85
+ *
86
+ * The control's candidate drafts must differ from the case's. A control byte-identical to its case
87
+ * cannot break, so it never produces the `origin: 'claimant'` issue a receipt requires, and the
88
+ * claim is unprovable however correct the case is.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * const claim: Claim = {
93
+ * project: 'configs/src/tsconfig.core.json',
94
+ * case: {
95
+ * files: [{ path: 'src/core/greeting.ts', text: "export const GREETING = 'hi'\n" }],
96
+ * test: {
97
+ * path: 'tmp/probe/greeting.test.ts',
98
+ * text: "import { expect, test } from 'vitest'\nimport { GREETING } from '../../src/core/greeting.js'\ntest('greets', () => expect(GREETING).toBe('hi'))\n",
99
+ * },
100
+ * },
101
+ * control: {
102
+ * files: [{ path: 'src/core/greeting.ts', text: "export const GREETING: number = 'hi'\n" }],
103
+ * test: {
104
+ * path: 'tmp/probe/greeting.test.ts',
105
+ * text: "import { expect, test } from 'vitest'\nimport { GREETING } from '../../src/core/greeting.js'\ntest('greets', () => expect(GREETING).toBe('hi'))\n",
106
+ * },
107
+ * stage: 'type',
108
+ * reason: 'a string literal assigned to a number must not compile',
109
+ * },
110
+ * }
111
+ * ```
112
+ */
113
+ export declare interface Claim {
114
+ /** Workspace-relative path of the TypeScript project the candidate drafts are checked against. */
115
+ readonly project: string;
116
+ /** The drafts and test the claim asserts about. */
117
+ readonly case: Case;
118
+ /** The negative control that must break, and where. */
119
+ readonly control: Control;
120
+ }
121
+
122
+ /**
123
+ * Describes one claim and is the sole source of both the published tool schema and the guard
124
+ * applied to an arriving claim.
125
+ *
126
+ * @remarks
127
+ * The Model Context Protocol tool publishes `compileSchema(CLAIM_SHAPE)` and admits a call with
128
+ * `isClaim`. Deriving the advertised schema from this one value is what stops the two from drifting
129
+ * apart across a release on any member either can express. `isClaim` is narrower on the one member
130
+ * neither a schema keyword nor this shape can carry — the containment rule on `Draft.path` — and
131
+ * `validators.ts` names where.
132
+ *
133
+ * @example
134
+ * ```ts
135
+ * const schema = compileSchema(CLAIM_SHAPE)
136
+ * const admits = compileGuard(CLAIM_SHAPE)
137
+ * schema.type // 'object'
138
+ * admits({ project: 'tsconfig.json' }) // false
139
+ * ```
140
+ */
141
+ export declare const CLAIM_SHAPE: ObjectShape<{
142
+ project: StringShape;
143
+ case: ObjectShape<{
144
+ files: ArrayShape<ObjectShape<{
145
+ path: StringShape;
146
+ text: StringShape;
147
+ }, false>>;
148
+ test: ObjectShape<{
149
+ path: StringShape;
150
+ text: StringShape;
151
+ }, false>;
152
+ }, false>;
153
+ control: ObjectShape<{
154
+ stage: LiteralShape<readonly ["type", "lint", "runtime"]>;
155
+ reason: StringShape;
156
+ files: ArrayShape<ObjectShape<{
157
+ path: StringShape;
158
+ text: StringShape;
159
+ }, false>>;
160
+ test: ObjectShape<{
161
+ path: StringShape;
162
+ text: StringShape;
163
+ }, false>;
164
+ }, false>;
165
+ }, false>;
166
+
167
+ /**
168
+ * Computes the proof token a verdict carries, or returns nothing when the claim was not proven.
169
+ *
170
+ * @remarks
171
+ * A receipt is minted on these conditions together: both phases report one check per stage, the
172
+ * case carries no issue, the control carries at least one `origin: 'claimant'` issue
173
+ * at the stage it declared, and every other control stage carries no claimant issue. A control
174
+ * that fails somewhere else has falsified the instrument rather than the claim, so no receipt is
175
+ * minted for it.
176
+ *
177
+ * Both phases owe every stage, not the case alone. `stayed` reads the control entries a verdict
178
+ * carries, so a control that omits a stage entirely would otherwise read as a stage that stayed
179
+ * clean, and the receipt would certify an inspection that never ran. `prove` records every stage
180
+ * for both phases, so this condition refuses only a verdict a caller assembled by hand.
181
+ *
182
+ * The token names every condition the verdict was reached under, so a receipt read away from its
183
+ * verdict still says what was judged and what judged it: the claim's digest, the stage the control
184
+ * broke at, the tool versions, and the project the candidate drafts were checked against.
185
+ * The call's identity is deliberately absent. It carries no integrity and it is the only value
186
+ * stopping two honest runs of one claim from producing one comparable string, so leaving it out is
187
+ * what makes "re-run `prove` and compare tokens" a verification a reader can perform.
188
+ *
189
+ * The project goes last, and its own path and digest are joined by `@`. Split the token on
190
+ * `RECEIPT_SEPARATOR`, take fields 0 through 5, and rejoin the remainder with that separator to
191
+ * read the project field; inside it the digest is everything after the final `@`. That rule stays
192
+ * total for a workspace-relative project path containing either character.
193
+ *
194
+ * An `origin: 'instrument'` issue in either phase means the inspection did not complete and
195
+ * refuses the receipt. A workspace issue in the control does not decide whether the claimant's
196
+ * candidate broke, while one in the case still means that the case did not run clean.
197
+ *
198
+ * @param verdict - The verdict whose case and control checks decide the outcome
199
+ * @param stage - The stage the claim's control declared it must fail at
200
+ * @returns The receipt token, or `undefined` when any condition fails
201
+ *
202
+ * @example
203
+ * ```ts
204
+ * computeReceipt(proven, 'type')
205
+ * // 'probe:6ca20c3bff623031d3955b9d1a76d71d:type:typescript@6.0.3:oxlint@1.79.0:vitest@4.1.11:configs/src/tsconfig.core.json@3b674fdf121c85efb9ed1bab25ceeec8'
206
+ * computeReceipt(proven, 'lint') // undefined
207
+ * ```
208
+ */
209
+ export declare function computeReceipt(verdict: Verdict, stage: Stage): string | undefined;
210
+
211
+ /**
212
+ * Extends a case with the stage it must fail at and the reason it must fail there.
213
+ *
214
+ * @remarks
215
+ * A claim that cannot state what would falsify it cannot be proven, so the control is required
216
+ * rather than optional. `stage` is the axis the control varies: a control that fails at a stage
217
+ * other than the one it names has falsified the instrument, not the claim.
218
+ *
219
+ * @example
220
+ * ```ts
221
+ * const control: Control = {
222
+ * files: [{ path: 'src/core/greeting.ts', text: "export const GREETING: number = 'hi'\n" }],
223
+ * test: {
224
+ * path: 'tmp/probe/greeting.test.ts',
225
+ * text: "import { expect, test } from 'vitest'\nimport { GREETING } from '../../src/core/greeting.js'\ntest('greets', () => expect(GREETING).toBe('hi'))\n",
226
+ * },
227
+ * stage: 'type',
228
+ * reason: 'a string literal assigned to a number must not compile',
229
+ * }
230
+ * ```
231
+ */
232
+ export declare interface Control extends Case {
233
+ /** The stage this control must report issues at. */
234
+ readonly stage: Stage;
235
+ /** Why the control fails there, in the claimant's own words. */
236
+ readonly reason: string;
237
+ }
238
+
239
+ /**
240
+ * Describes the negative control, which is a case plus where and why it must break.
241
+ *
242
+ * @remarks
243
+ * Built from `CASE_SHAPE`'s own properties rather than a second copy of them, so the control and
244
+ * the case cannot describe a draft differently.
245
+ *
246
+ * @example
247
+ * ```ts
248
+ * const test = { path: 'tests/src/core/greeting.test.ts', text: '' }
249
+ * compileGuard(CONTROL_SHAPE)({ files: [], test, stage: 'type', reason: 'must not compile' }) // true
250
+ * ```
251
+ */
252
+ export declare const CONTROL_SHAPE: ObjectShape<{
253
+ stage: LiteralShape<readonly ["type", "lint", "runtime"]>;
254
+ reason: StringShape;
255
+ files: ArrayShape<ObjectShape<{
256
+ path: StringShape;
257
+ text: StringShape;
258
+ }, false>>;
259
+ test: ObjectShape<{
260
+ path: StringShape;
261
+ text: StringShape;
262
+ }, false>;
263
+ }, false>;
264
+
265
+ /**
266
+ * Creates the failure raised when an instrument is used after it was torn down.
267
+ *
268
+ * @remarks
269
+ * Every resident entity in this package refuses this way, so the subject names which one in the
270
+ * message and the condition is the same for all of them. A caller that meets this builds a
271
+ * replacement rather than retrying: teardown is permanent.
272
+ *
273
+ * @param subject - The torn-down entity, named as the message names it, such as `type stage`
274
+ * @returns A typed teardown failure
275
+ *
276
+ * @example
277
+ * ```ts
278
+ * createDestroyedError('type stage').message // 'The type stage has been destroyed'
279
+ * createDestroyedError('probe').code // 'destroyed'
280
+ * ```
281
+ */
282
+ export declare function createDestroyedError(subject: string): ProbeError;
283
+
284
+ /**
285
+ * Carries one proposed file's location and its contents.
286
+ *
287
+ * @remarks
288
+ * A draft is a file as the claimant proposes it rather than as the workspace holds it. `path` is
289
+ * contained within the workspace, relative to its root, and need not exist on disk. The type and
290
+ * lint stages read the text from memory; only the runtime stage writes a file.
291
+ *
292
+ * @example
293
+ * ```ts
294
+ * const draft: Draft = { path: 'src/core/greeting.ts', text: "export const GREETING = 'hi'\n" }
295
+ * ```
296
+ */
297
+ export declare interface Draft {
298
+ /** Workspace-relative path the stages resolve the text against. */
299
+ readonly path: string;
300
+ /** The file's full contents. */
301
+ readonly text: string;
302
+ }
303
+
304
+ /**
305
+ * Describes one proposed file a claim carries.
306
+ *
307
+ * @remarks
308
+ * `path` is constrained to a non-empty string because every stage resolves a file by it, so an
309
+ * empty path names no file. That minimum is the whole of the constraint here, and it is the one
310
+ * place the wire contract is wider than what this package admits: `isDraft` enforces the same
311
+ * minimum and also refuses an absolute path and one that traverses out of the workspace, which no
312
+ * JSON Schema keyword can express. A caller that satisfies this shape can still be refused, and
313
+ * `ProbeServer` names the member when it is.
314
+ *
315
+ * @example
316
+ * ```ts
317
+ * compileGuard(DRAFT_SHAPE)({ path: 'src/core/greeting.ts', text: '' }) // true
318
+ * ```
319
+ */
320
+ export declare const DRAFT_SHAPE: ObjectShape<{
321
+ path: StringShape;
322
+ text: StringShape;
323
+ }, false>;
324
+
325
+ /**
326
+ * Renders one stage's outcome as its summary line followed by every message it reported.
327
+ *
328
+ * @remarks
329
+ * A clean stage renders one line. The count appears even when it is zero, because that line is
330
+ * what shows a reader the stage ran; a silent stage and a skipped stage read the same.
331
+ *
332
+ * @param check - The stage outcome to render
333
+ * @returns The summary line, then one indented line per issue
334
+ *
335
+ * @example
336
+ * ```ts
337
+ * formatCheck({ stage: 'lint', elapsed: 17, issues: [] })
338
+ * // 'lint: 0 issues (17 ms)'
339
+ * ```
340
+ */
341
+ export declare function formatCheck(check: Check): string;
342
+
343
+ /**
344
+ * Renders one tool message as a single line an agent can classify and locate.
345
+ *
346
+ * @param issue - The message and location a stage reported
347
+ * @returns The bracketed origin, location, and message, separated by spaces
348
+ *
349
+ * @example
350
+ * ```ts
351
+ * const located: Issue = {
352
+ * origin: 'claimant',
353
+ * path: 'src/core/greeting.ts',
354
+ * message: 'not assignable',
355
+ * line: 1,
356
+ * }
357
+ * const whole: Issue = {
358
+ * origin: 'claimant',
359
+ * path: 'src/core/greeting.ts',
360
+ * message: 'not assignable',
361
+ * }
362
+ * formatIssue(located) // '[claimant] src/core/greeting.ts:1 not assignable'
363
+ * formatIssue(whole) // '[claimant] src/core/greeting.ts not assignable'
364
+ * ```
365
+ */
366
+ export declare function formatIssue(issue: Issue): string;
367
+
368
+ /**
369
+ * Renders one generated specification: the caller's own test text, then the marker naming the
370
+ * revision that wrote it.
371
+ *
372
+ * @remarks
373
+ * The marker is what makes a file in a target workspace attributable to this package. A generated
374
+ * specification carries text the caller supplied, so its name alone cannot separate it from a
375
+ * developer's own file, and a sweep reading the name alone deletes that file. The marker goes last
376
+ * so every line of the caller's text keeps the number a reported stack frame gives it, and the text
377
+ * gains a terminating newline first so the marker is never appended to a line of the test.
378
+ *
379
+ * @param text - The caller's own test text
380
+ * @param revision - The writing host's process id and a fresh UUID, joined by `-`
381
+ * @returns The bytes the runtime stage writes for that revision
382
+ *
383
+ * @example
384
+ * ```ts
385
+ * formatSpecification("test('greets', () => {})\n", '4821-9f0c')
386
+ * // "test('greets', () => {})\n// @orkestrel/probe generated specification 4821-9f0c\n"
387
+ * ```
388
+ */
389
+ export declare function formatSpecification(text: string, revision: string): string;
390
+
391
+ /**
392
+ * Renders a whole verdict as the text an agent reads.
393
+ *
394
+ * @remarks
395
+ * Every stage appears for both the case and the control, so no failing stage can be masked by an
396
+ * earlier one. The closing line always states the receipt or its absence, so a reader never has to
397
+ * infer from silence whether the claim was proven.
398
+ *
399
+ * The heading lines carry everything the receipt binds, each in the name-then-value form the
400
+ * toolchain line established: the call's identity, the claim it answered, the tools that ran, and
401
+ * the project that judged the candidates. A verdict carrying the control's reason renders it next,
402
+ * before either phase's checks. A reader comparing two verdicts therefore reads what differed
403
+ * without recomputing anything.
404
+ *
405
+ * @param verdict - The verdict to render
406
+ * @returns The identity, claim, toolchain, project, and reason when present, then every case and
407
+ * control stage, then the receipt line
408
+ *
409
+ * @example
410
+ * ```ts
411
+ * formatVerdict(verdict).split('\n')[1] // 'claim 6ca20c3bff623031d3955b9d1a76d71d'
412
+ * ```
413
+ */
414
+ export declare function formatVerdict(verdict: Verdict): string;
415
+
416
+ /**
417
+ * Checks whether a value carries a claim's candidate drafts and its test.
418
+ *
419
+ * @param value - The value to check
420
+ * @returns True if the value is a case; false otherwise
421
+ *
422
+ * @example
423
+ * ```ts
424
+ * const test = { path: 'tests/src/core/greeting.test.ts', text: 'test("greets", () => {})\n' }
425
+ * isCase({ files: [], test }) // true
426
+ * ```
427
+ */
428
+ export declare const isCase: Guard<Case>;
429
+
430
+ /**
431
+ * Checks whether a value carries one stage's outcome.
432
+ *
433
+ * @param value - The value to check
434
+ * @returns True if the value is a check; false otherwise
435
+ *
436
+ * @example
437
+ * ```ts
438
+ * isCheck({ stage: 'lint', elapsed: 17, issues: [] }) // true
439
+ * ```
440
+ */
441
+ export declare const isCheck: Guard<Check>;
442
+
443
+ /**
444
+ * Checks whether a value carries a project, a case, and a control.
445
+ *
446
+ * @remarks
447
+ * Exact rather than open: a claim is this package's own record, so an unknown member is a caller
448
+ * sending a contract this service does not implement rather than a wider caller it must tolerate.
449
+ *
450
+ * `CLAIM_SHAPE` is the wire contract's shape and this is the admission rule the tool enforces, and
451
+ * the rule is strictly narrower than the shape. They agree on every member but `Draft.path`: the
452
+ * shape constrains it to a non-empty string, while `isDraft` also refuses an absolute path
453
+ * and one that traverses out of the workspace, so `../../etc/hosts` satisfies
454
+ * `compileGuard(CLAIM_SHAPE)` and is refused here. `ProbeServer` advertises the shape and enforces
455
+ * this rule, so it names the refused member rather than reporting only that the claim was invalid.
456
+ *
457
+ * @param value - The value to check
458
+ * @returns True if the value is a claim; false otherwise
459
+ *
460
+ * @example
461
+ * ```ts
462
+ * isClaim({ project: 'tsconfig.json', case: subject, control }) // true
463
+ * isClaim({ project: 'tsconfig.json', case: subject }) // false
464
+ * ```
465
+ */
466
+ export declare const isClaim: Guard<Claim>;
467
+
468
+ /**
469
+ * Checks whether a value carries a case plus the stage and reason it must fail for.
470
+ *
471
+ * @param value - The value to check
472
+ * @returns True if the value is a control; false otherwise
473
+ *
474
+ * @example
475
+ * ```ts
476
+ * const test = { path: 'tests/src/core/greeting.test.ts', text: 'test("greets", () => {})\n' }
477
+ * isControl({ files: [], test, stage: 'type', reason: 'must not compile' }) // true
478
+ * isControl({ files: [], test }) // false
479
+ * ```
480
+ */
481
+ export declare const isControl: Guard<Control>;
482
+
483
+ /**
484
+ * Checks whether a value carries a proposed file's path and text.
485
+ *
486
+ * @remarks
487
+ * Rejects an empty, absolute, or workspace-escaping path. A contained relative path may contain
488
+ * `.` or may traverse to a parent that remains inside the workspace. Every stage resolves a file
489
+ * by that path, so admitting an escape here would defer the refusal until a stage had already
490
+ * accepted the draft. An `Issue` carries no such minimum because this package produces issues
491
+ * rather than admits them.
492
+ *
493
+ * @param value - The value to check
494
+ * @returns True if the value is a draft; false otherwise
495
+ *
496
+ * @example
497
+ * ```ts
498
+ * isDraft({ path: 'src/core/greeting.ts', text: 'export const GREETING = "hi"\n' }) // true
499
+ * isDraft({ path: '../../etc/hosts', text: '' }) // false
500
+ * isDraft({ path: 'src/core/greeting.ts' }) // false
501
+ * ```
502
+ */
503
+ export declare const isDraft: Guard<Draft>;
504
+
505
+ /**
506
+ * Checks whether a value carries one message, its location, and the origin of the fault it names.
507
+ *
508
+ * @remarks
509
+ * `origin` is required rather than optional. Every issue this package produces sets it, and a
510
+ * receipt turns on it: a control's issue disproves the claim only when its origin names the
511
+ * claimant.
512
+ *
513
+ * @param value - The value to check
514
+ * @returns True if the value is an issue; false otherwise
515
+ *
516
+ * @example
517
+ * ```ts
518
+ * isIssue({ origin: 'claimant', path: 'src/core/greeting.ts', message: 'not assignable' }) // true
519
+ * isIssue({ path: 'src/core/greeting.ts', message: 'not assignable' }) // false
520
+ * ```
521
+ */
522
+ export declare const isIssue: Guard<Issue>;
523
+
524
+ /**
525
+ * Checks whether a value names a party an issue carries.
526
+ *
527
+ * @param value - The value to check
528
+ * @returns True if the value is a party; false otherwise
529
+ *
530
+ * @example
531
+ * ```ts
532
+ * isParty('claimant') // true
533
+ * isParty('workspace') // true
534
+ * isParty('instrument') // true
535
+ * isParty('stage') // false
536
+ * ```
537
+ */
538
+ export declare const isParty: Guard<Party>;
539
+
540
+ /**
541
+ * Checks whether an unknown value is a {@link ProbeError}.
542
+ *
543
+ * @remarks
544
+ * Recognition combines the global own-property brand with the native `Error` base, the subclass
545
+ * prototype, the fixed name, a party {@link PROBE_PARTIES} declares, and a condition
546
+ * {@link PROBE_ERROR_CODES} declares. The brand carries recognition across duplicate installations
547
+ * and across an ESM and a CommonJS copy of this package, where the two classes are different values.
548
+ * A plain `Error`, a property-only lookalike, and a branded value carrying an undeclared origin or
549
+ * condition all stay outside the type.
550
+ *
551
+ * @param value - The value to inspect
552
+ * @returns True only for a `ProbeError` instance; false otherwise
553
+ *
554
+ * @example
555
+ * ```ts
556
+ * isProbeError(createDestroyedError('probe')) // true
557
+ * isProbeError(new Error('The probe has been destroyed')) // false
558
+ * ```
559
+ */
560
+ export declare function isProbeError(value: unknown): value is ProbeError;
561
+
562
+ /**
563
+ * Checks whether a value names one resolved TypeScript project and what it contained.
564
+ *
565
+ * @remarks
566
+ * Rejects an empty path and an empty digest. A verdict names the project that judged it, so a
567
+ * blank member here would report a project the type stage never applied.
568
+ *
569
+ * @param value - The value to check
570
+ * @returns True if the value is a project; false otherwise
571
+ *
572
+ * @example
573
+ * ```ts
574
+ * isProject({ path: 'configs/src/tsconfig.core.json', digest: '3b674fdf121c85ef' }) // true
575
+ * isProject({ path: 'configs/src/tsconfig.core.json', digest: '' }) // false
576
+ * ```
577
+ */
578
+ export declare const isProject: Guard<Project>;
579
+
580
+ /**
581
+ * Checks whether a value names a stage.
582
+ *
583
+ * @param value - The value to check
584
+ * @returns True if the value is a stage name; false otherwise
585
+ *
586
+ * @example
587
+ * ```ts
588
+ * isStage('lint') // true
589
+ * isStage('typecheck') // false
590
+ * ```
591
+ */
592
+ export declare const isStage: Guard<Stage>;
593
+
594
+ /**
595
+ * Carries one message a stage reported, where it reported it, and whose fault it names.
596
+ *
597
+ * @remarks
598
+ * The stage is not repeated here. An issue always arrives inside the `Check` that names its
599
+ * stage, so a second copy could only drift from the first.
600
+ *
601
+ * A `claimant` issue is a tool's diagnostic about a candidate draft, and nothing else. Every
602
+ * other claimant fault is thrown. Without this invariant, a bad test path could satisfy the
603
+ * receipt condition even though the test never ran.
604
+ *
605
+ * `path` is the workspace-relative path a reader can open, which is not always the path the tool
606
+ * named. Each stage maps its tool's own spelling back: the type stage from the compiler's absolute
607
+ * path, the lint stage from the document URI it opened, and the runtime stage from the generated
608
+ * specification it wrote to the test path the case declared.
609
+ *
610
+ * `line` is absent when the stage's tool reported no line, which happens for a whole-file
611
+ * diagnostic. A runtime failure is not one of those: a failure Vitest reported at a stack frame
612
+ * carries that frame's line.
613
+ *
614
+ * @example
615
+ * ```ts
616
+ * const issue: Issue = {
617
+ * origin: 'claimant',
618
+ * path: 'src/core/greeting.ts',
619
+ * message: "Type 'string' is not assignable to type 'number'.",
620
+ * line: 1,
621
+ * }
622
+ * ```
623
+ */
624
+ export declare interface Issue {
625
+ /** The party that must act on this message. */
626
+ readonly origin: Party;
627
+ /** Workspace-relative path this message is reported against. */
628
+ readonly path: string;
629
+ /** The diagnostic or failure message. */
630
+ readonly message: string;
631
+ /** One-based line the tool reported, or absent when it reported none. */
632
+ readonly line?: number;
633
+ }
634
+
635
+ /**
636
+ * Checks whether a value names every resolved tool version.
637
+ *
638
+ * @param value - The value to check
639
+ * @returns True if the value is a toolchain; false otherwise
640
+ *
641
+ * @example
642
+ * ```ts
643
+ * isToolchain({ typescript: '6.0.3', oxlint: '1.79.0', vitest: '4.1.11' }) // true
644
+ * isToolchain({ typescript: '6.0.3' }) // false
645
+ * ```
646
+ */
647
+ export declare const isToolchain: Guard<Toolchain>;
648
+
649
+ /**
650
+ * Checks whether a value carries a complete verdict.
651
+ *
652
+ * @remarks
653
+ * Accepts any check count, because arity is the coordinator's obligation rather than this guard's:
654
+ * a stage that could not start throws before a verdict is built, so a short list can only arrive
655
+ * from a caller that assembled one by hand.
656
+ *
657
+ * @param value - The value to check
658
+ * @returns True if the value is a verdict; false otherwise
659
+ *
660
+ * @example
661
+ * ```ts
662
+ * const basis = { id: '01J8Z0', digest: '6ca20c3b', toolchain, project, elapsed: 337 }
663
+ * isVerdict({ ...basis, case: [], control: [] }) // true
664
+ * isVerdict({ ...basis, case: [] }) // false
665
+ * ```
666
+ */
667
+ export declare const isVerdict: Guard<Verdict>;
668
+
669
+ /**
670
+ * Checks whether one file's text is the generated specification written for one revision.
671
+ *
672
+ * @remarks
673
+ * Reads the marker `formatSpecification` writes, taken from that function rather than restated, so
674
+ * the writer and the reader cannot drift apart. An empty body renders the marker alone, which is
675
+ * why the comparison is built from a call rather than from a second copy of the text.
676
+ *
677
+ * @param text - The file's full contents
678
+ * @param revision - The revision the file's name declares
679
+ * @returns True if the text ends with this package's marker for that revision; false otherwise
680
+ *
681
+ * @example
682
+ * ```ts
683
+ * matchesSpecification(formatSpecification('', '4821-9f0c'), '4821-9f0c') // true
684
+ * matchesSpecification('export const NOTE = 1\n', '4821-9f0c') // false
685
+ * ```
686
+ */
687
+ export declare function matchesSpecification(text: string, revision: string): boolean;
688
+
689
+ /**
690
+ * Names who must act on an issue or probe failure.
691
+ *
692
+ * @remarks
693
+ * `claimant` is the caller who wrote the claim: its input, selections, candidate draft, and
694
+ * lifecycle. `workspace` is the target tree probe borrows. `instrument` is this package.
695
+ *
696
+ * @example
697
+ * ```ts
698
+ * const party: Party = 'claimant'
699
+ * ```
700
+ */
701
+ export declare type Party = (typeof PROBE_PARTIES)[number];
702
+
703
+ /**
704
+ * Lists the conditions that can end a probe operation.
705
+ *
706
+ * @remarks
707
+ * One list feeds the code union and the error guard, so a condition cannot be constructed by one
708
+ * and refused by the other. The guard reads this list rather than the class, which is what lets it
709
+ * refuse a lookalike carrying a condition this package never declared.
710
+ *
711
+ * @example
712
+ * ```ts
713
+ * PROBE_ERROR_CODES // ['refused', 'missing', 'malformed', 'destroyed', 'deadline']
714
+ * ```
715
+ */
716
+ export declare const PROBE_ERROR_CODES: readonly ["refused", "missing", "malformed", "destroyed", "deadline"];
717
+
718
+ /**
719
+ * Lists the parties that can own action on an issue or probe failure.
720
+ *
721
+ * @remarks
722
+ * One list feeds the `Party` type and its guard, so a party cannot be admitted by one and refused
723
+ * by another.
724
+ *
725
+ * @example
726
+ * ```ts
727
+ * PROBE_PARTIES // ['claimant', 'workspace', 'instrument']
728
+ * ```
729
+ */
730
+ export declare const PROBE_PARTIES: readonly ["claimant", "workspace", "instrument"];
731
+
732
+ /**
733
+ * Lists the stages a claim passes through, in the order a verdict reports them.
734
+ *
735
+ * @remarks
736
+ * One list feeds the `Stage` type, the wire shape, the stage guard, and the receipt computation, so
737
+ * a stage cannot be admitted by one and refused by another. The type derives from this list rather
738
+ * than standing beside it, so a stage the list omits is a stage no member of the union names.
739
+ *
740
+ * @example
741
+ * ```ts
742
+ * PROBE_STAGES // ['type', 'lint', 'runtime']
743
+ * ```
744
+ */
745
+ export declare const PROBE_STAGES: readonly ["type", "lint", "runtime"];
746
+
747
+ /**
748
+ * Reports one probe failure under stable ownership and condition axes.
749
+ *
750
+ * @remarks
751
+ * Every failure raised while serving a claim arrives as one of these, so a consumer catching from
752
+ * `prove`, from a stage, or from a workspace leaf branches on {@link Party} and
753
+ * {@link ProbeErrorCode} rather than on message text. Narrow a caught value with
754
+ * {@link isProbeError} before reading either member. A pure leaf called directly with a value
755
+ * `isClaim` would refuse raises the host's own fault unchanged, because those leaves are written to
756
+ * be total over a validated claim rather than over every value.
757
+ *
758
+ * @example
759
+ * ```ts
760
+ * const error = new ProbeError('Path escapes the workspace: ../secrets.env', {
761
+ * origin: 'claimant',
762
+ * code: 'refused',
763
+ * context: { path: '../secrets.env' },
764
+ * })
765
+ * error.origin // 'claimant'
766
+ * error.code // 'refused'
767
+ * error.context?.path // '../secrets.env'
768
+ * ```
769
+ */
770
+ export declare class ProbeError extends Error {
771
+ readonly name = "ProbeError";
772
+ readonly origin: Party;
773
+ readonly code: ProbeErrorCode;
774
+ readonly context?: ProbeErrorContext;
775
+ /**
776
+ * Creates one classified probe failure.
777
+ *
778
+ * @param message - Human-readable description of what failed
779
+ * @param options - The ownership, condition, optional structured context, and optional cause
780
+ */
781
+ constructor(message: string, options: ProbeErrorOptions);
782
+ }
783
+
784
+ /**
785
+ * Names the condition that ended a probe operation, derived from {@link PROBE_ERROR_CODES}.
786
+ *
787
+ * @remarks
788
+ * Each condition names a different repair. `refused` changes the rejected value. `missing` creates
789
+ * or installs the named thing. `malformed` repairs the value read against a contract. `destroyed`
790
+ * builds a replacement. `deadline` changes the budget or the work it bounds according to the
791
+ * failure's {@link Party}.
792
+ *
793
+ * @example
794
+ * ```ts
795
+ * const code: ProbeErrorCode = 'missing'
796
+ * ```
797
+ */
798
+ export declare type ProbeErrorCode = (typeof PROBE_ERROR_CODES)[number];
799
+
800
+ /**
801
+ * Carries the structured detail one probe failure reports beside its message.
802
+ *
803
+ * @remarks
804
+ * Every member is absent unless the failure has that value to report, so a reader branches on
805
+ * presence rather than on a sentinel. `value` is the rejected input itself, carried unchanged, so
806
+ * treat it as untrusted when rendering it.
807
+ *
808
+ * @example
809
+ * ```ts
810
+ * const context: ProbeErrorContext = { stage: 'runtime', deadline: 30_000 }
811
+ * ```
812
+ */
813
+ export declare interface ProbeErrorContext {
814
+ /** The stage the failure belongs to, when one stage owns it. */
815
+ readonly stage?: Stage;
816
+ /**
817
+ * The path involved, spelled as the refusing operation named it: workspace-relative for an
818
+ * input a caller supplied, absolute for a file this package resolved.
819
+ */
820
+ readonly path?: string;
821
+ /** The workspace-relative TypeScript project involved, for a project failure. */
822
+ readonly project?: string;
823
+ /** The installed package name involved, for a workspace toolchain failure. */
824
+ readonly name?: string;
825
+ /** Milliseconds the expired budget allowed, for a deadline failure. */
826
+ readonly deadline?: number;
827
+ /** The rejected value, for an input the guards refused. */
828
+ readonly value?: unknown;
829
+ }
830
+
831
+ /**
832
+ * Configures one probe failure at construction.
833
+ *
834
+ * @remarks
835
+ * `origin` and `code` are required, because a failure a consumer cannot branch on is the failure
836
+ * this type exists to replace. `cause` carries the underlying fault where one ended the operation,
837
+ * and reaches the native `Error` option of the same name.
838
+ *
839
+ * @example
840
+ * ```ts
841
+ * const options: ProbeErrorOptions = {
842
+ * origin: 'claimant',
843
+ * code: 'refused',
844
+ * context: { path: '../secrets.env' },
845
+ * }
846
+ * ```
847
+ */
848
+ export declare interface ProbeErrorOptions {
849
+ /** The party that must act on this failure. */
850
+ readonly origin: Party;
851
+ /** The condition that ended the operation. */
852
+ readonly code: ProbeErrorCode;
853
+ /** Structured detail about the failure. */
854
+ readonly context?: ProbeErrorContext;
855
+ /** The underlying fault, when one ended the operation. */
856
+ readonly cause?: unknown;
857
+ }
858
+
859
+ /**
860
+ * Reports what a probe observes while it serves.
861
+ *
862
+ * @remarks
863
+ * `arm` fires when the boot control has reported red and the service will answer calls; a probe
864
+ * arriving before it awaits that step rather than starting a second one. `expire` fires when the
865
+ * coordinator's own deadline destroyed a stage and a replacement took its place, which is the only
866
+ * way a synchronous infinite loop is ever reported.
867
+ *
868
+ * @example
869
+ * ```ts
870
+ * const hooks: EmitterHooks<ProbeEventMap> = { prove: (verdict) => console.log(verdict.id) }
871
+ * ```
872
+ */
873
+ export declare type ProbeEventMap = {
874
+ /** The boot control reported red and the instrument has begun answering calls. */
875
+ readonly arm: readonly [toolchain: Toolchain];
876
+ /** A claim was answered. */
877
+ readonly prove: readonly [verdict: Verdict];
878
+ /** The coordinator's deadline fired at one stage and that stage was replaced before this event. */
879
+ readonly expire: readonly [claim: Claim];
880
+ /** A fault surfaced for observation. */
881
+ readonly error: readonly [error: unknown];
882
+ };
883
+
884
+ /**
885
+ * Answers a claim with type, lint, and runtime evidence in one call.
886
+ *
887
+ * @remarks
888
+ * Warming begins at construction and `prove` awaits it, so there is no `start`: the harness owns
889
+ * the process and a restart is a new process rather than a second lifecycle.
890
+ *
891
+ * `prove` re-reads the target workspace before it answers, so a file edited since the last call is
892
+ * judged as it stands on disk rather than as a warm service remembers it. The resident readers key
893
+ * that sweep differently: the runtime stage compares each workspace module's contents, and the type
894
+ * stage versions a disk file by its modification time.
895
+ *
896
+ * @example
897
+ * ```ts
898
+ * const verdict = await probe.prove(claim)
899
+ * console.log(formatVerdict(verdict))
900
+ * await probe.destroy()
901
+ * ```
902
+ */
903
+ export declare interface ProbeInterface {
904
+ /** Observation surface for arming, answers, deadline expiry, and faults. */
905
+ readonly emitter: EmitterInterface<ProbeEventMap>;
906
+ /** The tool versions resolved from the workspace at construction. */
907
+ readonly toolchain: Toolchain;
908
+ /**
909
+ * Answers one claim with every stage's evidence.
910
+ *
911
+ * @param claim - The case, its control, and the project the candidate drafts in both cases
912
+ * are checked against
913
+ * @returns The verdict, carrying one check per stage for both the case and the control
914
+ * @throws When a stage cannot start, so no verdict ever reports a stage that did not run
915
+ */
916
+ prove(claim: Claim): Promise<Verdict>;
917
+ /**
918
+ * Tears down the resident engines and releases the processes they hold.
919
+ *
920
+ * @returns A promise that settles when every engine has released its resources
921
+ */
922
+ destroy(): Promise<void>;
923
+ }
924
+
925
+ /**
926
+ * Configures a probe.
927
+ *
928
+ * @remarks
929
+ * `workspace` is the target root whose installed `typescript`, `oxlint`, and `vitest` the stages
930
+ * resolve, and whose files each stage re-reads before it answers. Default: the current working
931
+ * directory. `deadline` is the coordinator's milliseconds budget for one active stage inspection.
932
+ * Queue wait is not charged to that inspection; the inspections and runtime recoveries ahead of it
933
+ * carry their own bounds. The runtime deadline lives outside the worker because a test timeout
934
+ * expressed in worker configuration cannot fire while that worker spins. One runtime inspection in
935
+ * every 64 also pays the resident runner's replacement, so budget `deadline` against that
936
+ * inspection rather than the common one.
937
+ *
938
+ * @example
939
+ * ```ts
940
+ * const options: ProbeOptions = { workspace: '/srv/checkout', deadline: 30_000 }
941
+ * ```
942
+ */
943
+ export declare interface ProbeOptions {
944
+ /** Initial listeners, wired at construction. */
945
+ readonly on?: EmitterHooks<ProbeEventMap>;
946
+ /** Handler for a listener throw. */
947
+ readonly error?: EmitterErrorHandler;
948
+ /** Target workspace root. Default: the current working directory. */
949
+ readonly workspace?: string;
950
+ /**
951
+ * Milliseconds one active stage inspection may take; an expired stage is replaced. Default:
952
+ * 30,000 ms.
953
+ */
954
+ readonly deadline?: number;
955
+ }
956
+
957
+ /**
958
+ * Names the TypeScript project that judged a verdict's candidate drafts.
959
+ *
960
+ * @remarks
961
+ * A verdict is an assertion about code under one compiler configuration, and the same code passes
962
+ * under one project and fails under another, so a verdict that omits the project states less than
963
+ * it appears to. `path` names which project file, in the resolved workspace-relative spelling
964
+ * rather than the caller's. `digest` names what that project contained, because a receipt travels
965
+ * away from the workspace that minted it and a path alone is a claim about a name.
966
+ *
967
+ * @example
968
+ * ```ts
969
+ * const project: Project = {
970
+ * path: 'configs/src/tsconfig.core.json',
971
+ * digest: '3b674fdf121c85efb9ed1bab25ceeec8',
972
+ * }
973
+ * ```
974
+ */
975
+ export declare interface Project {
976
+ /** Resolved workspace-relative path of the project file the type stage applied. */
977
+ readonly path: string;
978
+ /** Digest of that project's resolved compiler options, workspace-relative and key-sorted. */
979
+ readonly digest: string;
980
+ }
981
+
982
+ /**
983
+ * Names the leading token every receipt carries.
984
+ *
985
+ * @remarks
986
+ * A receipt travels away from the verdict that minted it — an agent pastes it into the promotion
987
+ * action — so it names itself rather than relying on where it was found.
988
+ *
989
+ * @example
990
+ * ```ts
991
+ * const receipt =
992
+ * 'probe:6ca20c3bff623031d3955b9d1a76d71d:type:typescript@6.0.3:oxlint@1.79.0:vitest@4.1.11:configs/src/tsconfig.core.json@3b674fdf121c85efb9ed1bab25ceeec8'
993
+ * receipt.startsWith(RECEIPT_PREFIX) // true
994
+ * ```
995
+ */
996
+ export declare const RECEIPT_PREFIX = "probe";
997
+
998
+ /**
999
+ * Names the character joining a receipt's tokens.
1000
+ *
1001
+ * @remarks
1002
+ * A project path can contain this character, so the project field goes last and a reader rejoins
1003
+ * every field from index 6 onward with this separator rather than expecting a fixed count.
1004
+ *
1005
+ * @example
1006
+ * ```ts
1007
+ * const receipt =
1008
+ * 'probe:6ca20c3bff623031d3955b9d1a76d71d:type:typescript@6.0.3:oxlint@1.79.0:vitest@4.1.11:configs/src/tsconfig.core.json@3b674fdf121c85efb9ed1bab25ceeec8'
1009
+ * receipt.split(RECEIPT_SEPARATOR).length // 7
1010
+ * ```
1011
+ */
1012
+ export declare const RECEIPT_SEPARATOR = ":";
1013
+
1014
+ /**
1015
+ * Names an inspection a claim passes through, derived from {@link PROBE_STAGES}.
1016
+ *
1017
+ * @remarks
1018
+ * They are irreducible modes rather than labels: each reads a different tool, and a verdict that
1019
+ * omits one hides a defect the agent would then believe it had fixed.
1020
+ *
1021
+ * @example
1022
+ * ```ts
1023
+ * const stage: Stage = 'lint'
1024
+ * ```
1025
+ */
1026
+ export declare type Stage = (typeof PROBE_STAGES)[number];
1027
+
1028
+ /**
1029
+ * Names the tool versions a verdict was produced with.
1030
+ *
1031
+ * @remarks
1032
+ * A probe is worth running only when its verdict predicts the gate's verdict, which holds only
1033
+ * when the probe and the gate read one installed copy of each tool. Carrying the resolved versions
1034
+ * on the verdict makes that claim checkable rather than assumed.
1035
+ *
1036
+ * @example
1037
+ * ```ts
1038
+ * const toolchain: Toolchain = { typescript: '6.0.3', oxlint: '1.79.0', vitest: '4.1.11' }
1039
+ * ```
1040
+ */
1041
+ export declare interface Toolchain {
1042
+ /** Resolved `typescript` version the type stage ran. */
1043
+ readonly typescript: string;
1044
+ /** Resolved `oxlint` version the lint stage ran. */
1045
+ readonly oxlint: string;
1046
+ /** Resolved `vitest` version the runtime stage ran. */
1047
+ readonly vitest: string;
1048
+ }
1049
+
1050
+ /**
1051
+ * Carries the full result of one claim: every stage, for both the case and its control.
1052
+ *
1053
+ * @remarks
1054
+ * A verdict exists only when every stage ran on both the case and the control, so `case`
1055
+ * and `control` each hold one entry per stage. A stage that cannot start throws instead, which is
1056
+ * why no member here models a missing stage. `receipt` is present only when the case reported no
1057
+ * issue, the control reported an `origin: 'claimant'` issue at the stage it declared,
1058
+ * every other control stage reported no claimant issue, and neither phase reported an
1059
+ * `origin: 'instrument'` issue.
1060
+ *
1061
+ * `id` identifies this call and `digest` identifies the claim it answered, so two calls over one
1062
+ * claim share a digest and differ in their identity. `digest` and `project` are required, because
1063
+ * the type stage always runs and a claim always names a project, so no verdict exists without
1064
+ * either value. A verdict returned by `Probe` also carries the control's claimant-authored
1065
+ * `reason` unchanged. A hand-built verdict may omit it because the receipt helper needs only the
1066
+ * recorded checks and declared stage.
1067
+ *
1068
+ * `digest` covers these things: the case bytes, the control bytes including this `reason`, and the
1069
+ * workspace they were read against. The reason is part of the control, so two claims differing only
1070
+ * in its prose are two claims and digest differently — a claimant who restates the falsifier has
1071
+ * answered a different question, and a digest that excluded it would describe less than the claim.
1072
+ * The workspace enters because every absolute string in a claim is rewritten relative to it before
1073
+ * hashing, so a claim carrying no absolute string digests the same in every workspace and one that
1074
+ * carries any digests per workspace. `receipt` carries this digest as a field, so the same inputs
1075
+ * reach the token.
1076
+ *
1077
+ * @example
1078
+ * ```ts
1079
+ * const broke: Issue = {
1080
+ * origin: 'claimant',
1081
+ * path: 'src/core/farewell.ts',
1082
+ * message: 'not assignable',
1083
+ * line: 1,
1084
+ * }
1085
+ * const verdict: Verdict = {
1086
+ * id: '88a5addc-7d33-40dc-9a5a-104b71f8787d',
1087
+ * digest: '6ca20c3bff623031d3955b9d1a76d71d',
1088
+ * toolchain: { typescript: '6.0.3', oxlint: '1.79.0', vitest: '4.1.11' },
1089
+ * project: {
1090
+ * path: 'configs/src/tsconfig.core.json',
1091
+ * digest: '3b674fdf121c85efb9ed1bab25ceeec8',
1092
+ * },
1093
+ * reason: 'a number annotation must reject the string literal beside it',
1094
+ * case: [
1095
+ * { stage: 'type', elapsed: 61, issues: [] },
1096
+ * { stage: 'lint', elapsed: 17, issues: [] },
1097
+ * { stage: 'runtime', elapsed: 259, issues: [] },
1098
+ * ],
1099
+ * control: [
1100
+ * { stage: 'type', elapsed: 58, issues: [broke] },
1101
+ * { stage: 'lint', elapsed: 16, issues: [] },
1102
+ * { stage: 'runtime', elapsed: 254, issues: [] },
1103
+ * ],
1104
+ * elapsed: 549,
1105
+ * receipt:
1106
+ * 'probe:6ca20c3bff623031d3955b9d1a76d71d:type:typescript@6.0.3:oxlint@1.79.0:vitest@4.1.11:configs/src/tsconfig.core.json@3b674fdf121c85efb9ed1bab25ceeec8',
1107
+ * }
1108
+ * ```
1109
+ */
1110
+ export declare interface Verdict {
1111
+ /** The revision identity this verdict was produced for, fresh per call. */
1112
+ readonly id: string;
1113
+ /** Digest of the case and control this verdict answers. */
1114
+ readonly digest: string;
1115
+ /** The tool versions that produced it. */
1116
+ readonly toolchain: Toolchain;
1117
+ /** The TypeScript project the candidate drafts were judged against. */
1118
+ readonly project: Project;
1119
+ /**
1120
+ * The claimant's explanation for the selected control, when the verdict came from a claim. Part
1121
+ * of the control, so it enters `digest` and through it the receipt token.
1122
+ */
1123
+ readonly reason?: string;
1124
+ /** One outcome per stage for the claim's case. */
1125
+ readonly case: readonly Check[];
1126
+ /** One outcome per stage for the claim's control. */
1127
+ readonly control: readonly Check[];
1128
+ /** Milliseconds the whole call took, including both the case and the control. */
1129
+ readonly elapsed: number;
1130
+ /** The proof token, absent when either phase reports an instrument failure. */
1131
+ readonly receipt?: string;
1132
+ }
1133
+
1134
+ export { }