@systemfsoftware/vitest 0.3.0 → 2.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @systemfsoftware/vitest
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - Property failures (`PropertyRefuted`, `NonBooleanVerdict`, `CoverageBelowMinimum`, `VacuousProperty`, `SelfModelLaw`, `SeedStoreUnreadable`, `ReplayUnreadable`) are exported tagged errors whose fields (property name, site, seed, runs, witness, `replay` text) reach reporters, replacing the `detail` prose. A provided budget `seed` now gives each property its own stable seed; failing seeds are recorded in `__property_seeds__/<test file>.jsonl` and replayed first; vitest-config sets `record: false` in CI and Stryker.
8
+
9
+ - To keep one literal seed, set `arbitrary: { seed }` on the property.
10
+ - Commit `__property_seeds__` files; a case that must always run belongs in the test source.
11
+ - Catch a self-model law as `SelfModelLaw`, no longer `VacuousProperty`.
12
+
13
+ ## 1.0.0
14
+
15
+ ### Major Changes
16
+
17
+ - Require `effect` `^4` (stable 4.0.0). Release candidates are no longer supported: imports follow 4.0.0's module layout (`effect/http`, `effect/rpc`, `effect/http-api`, `effect/cluster`, `effect/process`, `effect/socket`, `effect/persistence`, `effect/reactivity`, `effect/encoding`, `effect/Arbitrary`), which does not exist in any 4.0.0 RC.
18
+
3
19
  ## 0.3.0
4
20
 
5
21
  ### Minor Changes
package/README.md CHANGED
@@ -171,16 +171,78 @@ it.prop(
171
171
 
172
172
  ### The constant-impostor gate
173
173
 
174
- After a property holds, it runs again against a constant impostor of its subject — a fake that returns the first output forever, whatever the input. Each subject is judged across every property in its file, when the file ends. If nothing in the file refutes the impostor, the file fails `VacuousProperty`:
174
+ After a property holds, it runs again against a constant impostor of its subject — a fake that returns the first output forever, whatever the input. Each subject is judged across every property in its file, when the file ends. If nothing in the file refutes the impostor, the file fails with `VacuousProperty`:
175
175
 
176
- > sort: no property in this file refuted the constant impostor of \`sort\`, so nothing here pins it down. … Laws that only relate outputs to each other (additivity, idempotence, commutativity, round trips through the subject) hold for such constants. Pin the output to the input: compare against an independent model (\`subject(x)\` equals a straightforward reimplementation), or conjoin a base case (\`subject([one])\` equals its known value). Also check that the body calls the \`subject\` it was given, not the imported implementation.
176
+ ```ts
177
+ export interface VacuousProperty {
178
+ readonly _tag: 'VacuousProperty'
179
+ readonly subjects: ReadonlyArray<{
180
+ readonly label: string
181
+ readonly properties: ReadonlyArray<{
182
+ readonly property: { name: string; site: string | null; seed: number; runs: number }
183
+ readonly frozen:
184
+ | { _tag: 'Frozen'; outputs: ReadonlyArray<{ member: string; output: { rendered: string; value: unknown } }> }
185
+ | { _tag: 'NeverCalled' }
186
+ }>
187
+ }>
188
+ readonly exempt: ReadonlyArray<{ name: string; kind: string }>
189
+ readonly replay: string
190
+ }
191
+ ```
192
+
193
+ The `frozen` union distinguishes a subject whose impostor was called (`Frozen`, with rendered outputs for each member) from one never called during the vacuity check (`NeverCalled`). Replay the same verdict with:
194
+
195
+ ```bash
196
+ CONFORMANCE_REPLAY="property=<hash>;seed=<n>;runs=<n>|..." pnpm test
197
+ ```
198
+
199
+ Other property failures are exported from the package root as tagged errors — each carries its own fields:
200
+
201
+ - **`PropertyRefuted`**: `property` (name, site, seed, runs), `counterexample` (rendered, value), `shrinks`, `replay`
202
+ - **`NonBooleanVerdict`**: `property`, `drawn` (rendered, value), `returned` (array of kinds), `replay`
203
+ - **`CoverageBelowMinimum`**: `property`, `classes` (array of {label, hits, runs, minimum}), `replay`
204
+ - **`SelfModelLaw`**: `name`, `site` — the law compared the subject to itself
205
+ - **`SeedStoreUnreadable`**: `file`, `line`, `detail` — a seed store file's line could not be decoded
206
+ - **`ReplayUnreadable`**: `text` — `CONFORMANCE_REPLAY` names neither the kernel's `seed=…;path=…` nor a property entry
177
207
 
178
- `sorting is ordered` alone is vacuous, because a constant empty array is also ordered. A law that pins the output to an input refutes the impostor for that subject:
208
+ A reporter receives every field on the raw error, so a script or agent narrows by `_tag` and reads the fields directly without parsing messages:
179
209
 
180
210
  ```ts
181
- it.law.model('agree with insertion sort', { of: [S.Array(S.Int)], subject: sort }, insertionSort)
211
+ if (error._tag === 'VacuousProperty') {
212
+ for (const subject of error.subjects) {
213
+ for (const run of subject.properties) {
214
+ console.log(run.property.name, run.frozen._tag, run.property.seed)
215
+ }
216
+ }
217
+ }
182
218
  ```
183
219
 
220
+ ### Seeds and the seed store
221
+
222
+ A provided budget asks for derandomized runs by carrying a `seed`. Each property then gets its own stable seed derived from that seed and its identity, so different properties draw different inputs and the same property draws the same inputs in every process and on every machine:
223
+
224
+ ```ts
225
+ // vitest.config.ts
226
+ export default defineConfig({
227
+ test: { provide: { '@systemfsoftware/vitest:property-check': { runs: 30, seed: 1 } } },
228
+ })
229
+ ```
230
+
231
+ **Seed precedence**: a property's own `arbitrary: { seed: 7 }` wins over a provided seed. With a provided `seed`, the engine hashes it (FNV-1a) with the property's identity — its package, its file relative to the Vitest project root, and its full test name. With neither, each property draws from a fresh random seed. Every failure reports the seed it ran with.
232
+
233
+ **Migration**: code that relied on a provided seed making every property share one stream must set `arbitrary: { seed: <literal> }` on each property that needs a literal seed.
234
+
235
+ **The seed store and recording**: failing seeds are automatically saved to a checked-in JSON Lines file `__property_seeds__/<test file>.jsonl` beside the test file. Each line holds either:
236
+
237
+ - Refuted: `{ "_tag": "Refuted", "property": "full test name", "seed": 42, "attempt": 5, "size": 3, "path": [0,1], "failure": "ReturnedFalse" }`
238
+ - NonBoolean: `{ "_tag": "NonBoolean", "property": "full test name", "seed": 42, "runs": 100 }`
239
+
240
+ Recorded seeds replay before novel draws on every run, whatever the budget. Only a refuted or non-boolean failure writes, and only in a run that is not derandomized and does not set `record: false`; the shared config sets `record: false` in CI and in Stryker workers. Commit seed store updates like snapshot files.
241
+
242
+ **Generator changes**: if a property's generator changes, its recorded seeds may no longer produce their old counterexamples, so the failure stops reproducing. Cases that must always run belong in the test source itself, not in the seed store.
243
+
244
+ **The `record` option**: `{ runs: 30, record: false }` opts out of writing seeds for a run; the engine still reads and replays existing seeds.
245
+
184
246
  ### Law kinds
185
247
 
186
248
  `it.law.model` (an independent oracle), `it.law.metamorphic` (the input transform), `it.law.roundTrip` (the encode/decode pair) and `it.law.invariant` (a predicate on the output) are sugar over the same gate.
@@ -0,0 +1,503 @@
1
+
2
+ import * as Cause from "effect/Cause";
3
+ import * as Effect$1 from "effect/Effect";
4
+ import * as Schema$1 from "effect/Schema";
5
+ import * as Tracer from "effect/Tracer";
6
+ import { Schema } from "effect";
7
+ import * as Arbitrary from "effect/Arbitrary";
8
+ //#endregion
9
+ //#region src/internal/errors.schema.d.ts
10
+ /**
11
+ * The contract rules a rendered failure record can break (R10, KTD7).
12
+ *
13
+ * @internal
14
+ */
15
+ declare const Breach: Schema.Literals<readonly ["R1", "R2", "R6"]>;
16
+ /** @internal */
17
+ type Breach = typeof Breach.Type;
18
+ //#endregion
19
+ //#region src/internal/property/error.schema.d.ts
20
+ /**
21
+ * One witness: the text the renderer prints for a value, and a JSON-safe projection of the same traversal (R3, KD7).
22
+ *
23
+ * @internal
24
+ */
25
+ declare const Witness: Schema.Struct<{
26
+ readonly rendered: Schema.String;
27
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
28
+ }>;
29
+ /** @internal */
30
+ type Witness = typeof Witness.Type;
31
+ /**
32
+ * One property involved in a failure: its full name, its declaration site, its seed and its run count (R2).
33
+ *
34
+ * @internal
35
+ */
36
+ declare const PropertyRun: Schema.Struct<{
37
+ readonly name: Schema.String;
38
+ readonly site: Schema.NullOr<Schema.String>;
39
+ readonly seed: Schema.brand<Schema.Int, "PropertySeed">;
40
+ readonly runs: Schema.brand<Schema.Int, "PropertyRunCount">;
41
+ }>;
42
+ /** @internal */
43
+ type PropertyRun = typeof PropertyRun.Type;
44
+ declare const PropertyRefuted_base: Schema.Class<PropertyRefuted, Schema.TaggedStruct<"PropertyRefuted", {
45
+ readonly property: Schema.Struct<{
46
+ readonly name: Schema.String;
47
+ readonly site: Schema.NullOr<Schema.String>;
48
+ readonly seed: Schema.brand<Schema.Int, "PropertySeed">;
49
+ readonly runs: Schema.brand<Schema.Int, "PropertyRunCount">;
50
+ }>;
51
+ readonly counterexample: Schema.Struct<{
52
+ readonly rendered: Schema.String;
53
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
54
+ }>;
55
+ readonly shrinks: Schema.brand<Schema.Int, "PropertyShrinkCount">;
56
+ readonly replay: Schema.String;
57
+ }>, import("effect/Cause").YieldableError>;
58
+ /**
59
+ * A falsified property: the property that ran, the shrunk counterexample the generator settled on, and how many
60
+ * shrink steps it took to reach it (R2-R4).
61
+ *
62
+ * @internal
63
+ */
64
+ declare class PropertyRefuted extends PropertyRefuted_base {
65
+ get message(): string;
66
+ }
67
+ declare const NonBooleanVerdict_base: Schema.Class<NonBooleanVerdict, Schema.TaggedStruct<"NonBooleanVerdict", {
68
+ readonly property: Schema.Struct<{
69
+ readonly name: Schema.String;
70
+ readonly site: Schema.NullOr<Schema.String>;
71
+ readonly seed: Schema.brand<Schema.Int, "PropertySeed">;
72
+ readonly runs: Schema.brand<Schema.Int, "PropertyRunCount">;
73
+ }>;
74
+ readonly drawn: Schema.Struct<{
75
+ readonly rendered: Schema.String;
76
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
77
+ }>;
78
+ readonly returned: Schema.$Array<Schema.Literals<readonly ["undefined", "object", "boolean", "number", "bigint", "string", "symbol", "function", "effect"]>>;
79
+ readonly replay: Schema.String;
80
+ }>, import("effect/Cause").YieldableError>;
81
+ /**
82
+ * A verdict that was not a literal boolean: the property that ran, the first drawn values whose verdict was not a
83
+ * boolean, and every kind of value the property returned (R4).
84
+ *
85
+ * @internal
86
+ */
87
+ declare class NonBooleanVerdict extends NonBooleanVerdict_base {
88
+ get message(): string;
89
+ }
90
+ declare const CoverageBelowMinimum_base: Schema.Class<CoverageBelowMinimum, Schema.TaggedStruct<"CoverageBelowMinimum", {
91
+ readonly property: Schema.Struct<{
92
+ readonly name: Schema.String;
93
+ readonly site: Schema.NullOr<Schema.String>;
94
+ readonly seed: Schema.brand<Schema.Int, "PropertySeed">;
95
+ readonly runs: Schema.brand<Schema.Int, "PropertyRunCount">;
96
+ }>;
97
+ readonly classes: Schema.$Array<Schema.Struct<{
98
+ readonly label: Schema.String;
99
+ readonly hits: Schema.Int;
100
+ readonly runs: Schema.Int;
101
+ readonly minimum: Schema.Finite;
102
+ }>>;
103
+ readonly replay: Schema.String;
104
+ }>, import("effect/Cause").YieldableError>;
105
+ /**
106
+ * A property whose declared coverage classes stayed under their minima: the property and the failed classes, in
107
+ * declaration order (R7).
108
+ *
109
+ * @internal
110
+ */
111
+ declare class CoverageBelowMinimum extends CoverageBelowMinimum_base {
112
+ get message(): string;
113
+ }
114
+ declare const SelfModelLaw_base: Schema.Class<SelfModelLaw, Schema.TaggedStruct<"SelfModelLaw", {
115
+ readonly name: Schema.String;
116
+ readonly site: Schema.NullOr<Schema.String>;
117
+ }>, import("effect/Cause").YieldableError>;
118
+ /**
119
+ * A model law given the subject itself as its oracle, so it compares nothing (R13).
120
+ *
121
+ * @internal
122
+ */
123
+ declare class SelfModelLaw extends SelfModelLaw_base {
124
+ get message(): string;
125
+ }
126
+ declare const SeedStoreUnreadable_base: Schema.Class<SeedStoreUnreadable, Schema.TaggedStruct<"SeedStoreUnreadable", {
127
+ readonly file: Schema.String;
128
+ readonly line: Schema.Int;
129
+ readonly detail: Schema.String;
130
+ }>, import("effect/Cause").YieldableError>;
131
+ /**
132
+ * A seed-store line that could not be decoded (R16, KTD6).
133
+ *
134
+ * @internal
135
+ */
136
+ declare class SeedStoreUnreadable extends SeedStoreUnreadable_base {
137
+ get message(): string;
138
+ }
139
+ declare const VacuousProperty_base: Schema.Class<VacuousProperty, Schema.TaggedStruct<"VacuousProperty", {
140
+ readonly subjects: Schema.$Array<Schema.Struct<{
141
+ readonly label: Schema.String;
142
+ readonly properties: Schema.$Array<Schema.Struct<{
143
+ readonly property: Schema.Struct<{
144
+ readonly name: Schema.String;
145
+ readonly site: Schema.NullOr<Schema.String>;
146
+ readonly seed: Schema.brand<Schema.Int, "PropertySeed">;
147
+ readonly runs: Schema.brand<Schema.Int, "PropertyRunCount">;
148
+ }>;
149
+ readonly frozen: Schema.Union<readonly [Schema.TaggedStruct<"Frozen", {
150
+ readonly outputs: Schema.$Array<Schema.Struct<{
151
+ readonly member: Schema.String;
152
+ readonly output: Schema.Struct<{
153
+ readonly rendered: Schema.String;
154
+ readonly value: Schema.Codec<Schema.Json, Schema.Json, never, never>;
155
+ }>;
156
+ }>>;
157
+ }>, Schema.TaggedStruct<"NeverCalled", {}>]>;
158
+ }>>;
159
+ }>>;
160
+ readonly exempt: Schema.$Array<Schema.Struct<{
161
+ readonly name: Schema.String;
162
+ readonly kind: Schema.String;
163
+ }>>;
164
+ readonly replay: Schema.String;
165
+ }>, import("effect/Cause").YieldableError>;
166
+ /**
167
+ * Thrown at file end when no property in the file refuted a subject's constant impostor (R12, R5, R6).
168
+ *
169
+ * @internal
170
+ */
171
+ declare class VacuousProperty extends VacuousProperty_base {
172
+ get message(): string;
173
+ }
174
+ declare const ReplayUnreadable_base: Schema.Class<ReplayUnreadable, Schema.TaggedStruct<"ReplayUnreadable", {
175
+ readonly text: Schema.String;
176
+ }>, import("effect/Cause").YieldableError>;
177
+ /** @internal */
178
+ declare class ReplayUnreadable extends ReplayUnreadable_base {
179
+ get message(): string;
180
+ }
181
+ //#endregion
182
+ //#region src/internal/failure-record.d.ts
183
+ /** A value the renderer narrows rather than assumes. */
184
+ type Opaque$1<A = unknown> = A;
185
+ /**
186
+ * A value a recorded span attribute or a replay path carries. Structured values stay structured on the span
187
+ * (KTD2); the renderer decides the text.
188
+ *
189
+ * @internal
190
+ */
191
+ type AttributeValue = string | number | boolean | null | ReadonlyArray<AttributeValue> | {
192
+ readonly [key: string]: AttributeValue;
193
+ };
194
+ /**
195
+ * The test a failure happened in, as Vitest knows it. `file` is the path the rerun command names, so a caller
196
+ * that holds an absolute path derives the repo-relative one before handing it over.
197
+ *
198
+ * @internal
199
+ */
200
+ interface TestIdentity {
201
+ /**
202
+ * The npm package the test file belongs to, e.g. `@systemfsoftware/effect-readiness`. Empty when the run
203
+ * provided no name: the rerun command then drops its `pnpm --filter` prefix and runs from the package
204
+ * directory, which is not a breach (R6).
205
+ */
206
+ readonly package: string;
207
+ /** The test file, as the rerun command writes it. */
208
+ readonly file: string;
209
+ /** The scenario name the rerun command filters on with `-t`. */
210
+ readonly name: string;
211
+ }
212
+ /**
213
+ * The value a generator chose a run by: the kernel's seed and decision path, or a property counterexample's
214
+ * seed and path. A path without a seed is a replay value offered for a baseline run, which R6 refuses (KTD5).
215
+ *
216
+ * @internal
217
+ */
218
+ interface ReplayValue {
219
+ /** The generator's seed, or `undefined` when only a path was recorded. */
220
+ readonly seed: number | undefined;
221
+ /** The decisions the generator chose, in order; a decision is the index the scheduler picked (KTD5). */
222
+ readonly path: ReadonlyArray<number>;
223
+ }
224
+ /**
225
+ * A contract rule a rendered record breaks; the runner refuses such a record (R10, KTD7).
226
+ *
227
+ * @internal
228
+ */
229
+ /**
230
+ * What a rendered failure gives Vitest: the tag the error carries, the record text, and the rules it breaks.
231
+ *
232
+ * @internal
233
+ */
234
+ interface FailureRecord {
235
+ /** The headline's failure tag, e.g. `StepError`; the runner sets it as the thrown error's `name`. */
236
+ readonly name: string;
237
+ /** The text Vitest prints as the failure's message. */
238
+ readonly record: string;
239
+ /** The contract rules the record breaks: `R1` empty headline, `R2` no location, `R6` replay or rerun. */
240
+ readonly breaches: ReadonlyArray<Breach>;
241
+ /**
242
+ * The raised failure itself when it is one of the property-channel variants, so an in-process corpus run reads
243
+ * its fields without parsing the record text (R1, R2). Absent for every other failure.
244
+ */
245
+ readonly failure?: Opaque$1;
246
+ }
247
+ /**
248
+ * Everything one failure is rendered from: the failure, its run's spans, the test and the replay value.
249
+ *
250
+ * @internal
251
+ */
252
+ interface FailureRecordInput<E = never> {
253
+ /** The failure itself: a `Cause`, or the value a program threw or failed with. */
254
+ readonly failure: Cause.Cause<E> | E;
255
+ /** Every span the failing run recorded, in creation order. */
256
+ readonly spans: ReadonlyArray<Tracer.NativeSpan>;
257
+ /** The test the run belonged to. */
258
+ readonly identity: TestIdentity;
259
+ /** The generator that chose this run, or `undefined` on a run no generator chose. */
260
+ readonly replay: ReplayValue | undefined;
261
+ /**
262
+ * The seed the kernel's scheduler chose. The kernel knows its own scheduler, so it hands the note over rather
263
+ * than the renderer guessing it; a run no scheduler chose renders no note (KTD5).
264
+ */
265
+ readonly schedule?: {
266
+ readonly seed: number;
267
+ } | undefined;
268
+ /**
269
+ * The workspace root the rendered paths are relativized against, provided by the shared config the same way the
270
+ * package name is. Omitted, paths print absolute.
271
+ */
272
+ readonly root?: string | undefined;
273
+ }
274
+ /**
275
+ * A value `JSON.stringify` carries: the projection a witness travels to a consumer as (R3, KD7).
276
+ *
277
+ * @internal
278
+ */
279
+ type JsonValue = Schema$1.Json;
280
+ /**
281
+ * The one traversal a value's rendered text and its JSON projection come from (R3, KD7): `rendered` is exactly
282
+ * `renderValue`'s text, `value` is the same walk with every value JSON cannot carry marked by kind, and a cycle
283
+ * marks `circular` rather than recursing forever.
284
+ *
285
+ * @internal
286
+ */
287
+ declare const witnessOf: (value: Opaque$1) => Witness;
288
+ /** @internal */
289
+ declare const summaryOf: (value: Opaque$1) => string;
290
+ /**
291
+ * Renders the record Vitest prints for one spec failure, and the contract rules it breaks.
292
+ *
293
+ * Never throws: a `Cause` renders layer by layer, a thrown `Error` renders as one layer, and any other value
294
+ * renders as itself. The first location the record names is the raising frame — the first stack frame outside
295
+ * `node_modules` and outside the spec libraries' own `src/` and `dist/` — and when no layer has one, the
296
+ * innermost failed span's site stands in, or the innermost unfinished cell's decide site for a deadlock (KTD6).
297
+ *
298
+ * @internal
299
+ */
300
+ declare const renderFailureRecord: <E>(input: FailureRecordInput<E>) => FailureRecord;
301
+ /** @internal */
302
+ declare const throwFailureRecord: <E>(input: FailureRecordInput<E>) => never;
303
+ interface TaskLike {
304
+ readonly name?: string | undefined;
305
+ readonly fullName?: string | undefined;
306
+ readonly fullTestName?: string | undefined;
307
+ }
308
+ /** @internal */
309
+ declare const testIdentityOf: (task?: TaskLike | null) => TestIdentity;
310
+ //#endregion
311
+ //#region src/internal/property/defaults.d.ts
312
+ /** @internal The `test.provide` key the shared config fills with this run's tier's check options. */
313
+ declare const checkDefaultsKey = "@systemfsoftware/vitest:property-check";
314
+ /**
315
+ * The check options a run supplies as its property default, minus `replay`. `record` asks the engine to write a
316
+ * failing seed to the checked-in seed store, which it does unless a run opts out.
317
+ *
318
+ * @internal
319
+ */
320
+ interface PropertyBudget extends Omit<Arbitrary.CheckOptions, 'replay'> {
321
+ /** Write failing seeds to the seed store; default true. A derandomized run never writes regardless. */
322
+ readonly record?: boolean | undefined;
323
+ }
324
+ /** @internal The check options a run supplies as its property default (KTD4). */
325
+ type ProvidedCheckDefaults = PropertyBudget;
326
+ //#endregion
327
+ //#region src/internal/property/impostor.d.ts
328
+ /**
329
+ * A value the fork hands over without inspecting: an argument to the subject, or one of its outputs.
330
+ *
331
+ * @internal
332
+ */
333
+ type Opaque<A = unknown> = A;
334
+ /**
335
+ * A function under test: any argument, any output.
336
+ *
337
+ * @internal
338
+ */
339
+ type SubjectFunction = (...values: ReadonlyArray<never>) => Opaque;
340
+ /**
341
+ * A record of functions under test; every member is replaced by a constant.
342
+ *
343
+ * @internal
344
+ */
345
+ type MemberRecord = {
346
+ readonly [key: string]: SubjectFunction;
347
+ };
348
+ /**
349
+ * The function under test, or a record of them.
350
+ *
351
+ * @internal
352
+ */
353
+ type Subject = SubjectFunction | MemberRecord;
354
+ /**
355
+ * One key the impostor froze and the raw output it answered with: the subject itself, or a record member.
356
+ *
357
+ * @internal
358
+ */
359
+ interface FrozenOutput {
360
+ readonly member: string;
361
+ readonly output: Opaque;
362
+ }
363
+ /**
364
+ * One property's verdict against a subject's impostor: whether the property refuted the fake, the property it
365
+ * ran, and the raw outputs the fake froze for it.
366
+ *
367
+ * @internal
368
+ */
369
+ interface Refutation {
370
+ /** `true` when the property falsified for the impostor, so the property does pin the subject down. */
371
+ readonly refuted: boolean;
372
+ readonly property: PropertyRun;
373
+ /** The property's identity hash, so a vacuous verdict's replay text can name it (R9, R11). */
374
+ readonly identity: number;
375
+ readonly frozen: ReadonlyArray<FrozenOutput>;
376
+ }
377
+ /**
378
+ * The R12 repair verdict for one subject no property in the file refuted.
379
+ *
380
+ * @internal
381
+ */
382
+ interface FileLedger {
383
+ readonly record: (subject: Subject, verdict: Refutation) => void;
384
+ /** Records a law kind exempt from the gate, so a refusal can list it (R6). */
385
+ readonly recordExempt: (name: string, kind: string) => void;
386
+ /** The single refusal when at least one subject is vacuous, or `undefined` when the file holds. */
387
+ readonly finalise: () => VacuousProperty | undefined;
388
+ }
389
+ declare namespace kinds_d_exports {
390
+ export { LawApi, LawKind, LawSubject, MetamorphicRelation, deterministicHolds, idempotentHolds, invariantHolds, metamorphicHolds, modelHolds, roundTripHolds, spreadValues };
391
+ }
392
+ /** @internal */
393
+ type LawKind = 'model' | 'metamorphic' | 'roundTrip' | 'invariant' | 'idempotent' | 'deterministic';
394
+ /**
395
+ * A subject of a law kind: a function of the generated values.
396
+ *
397
+ * @internal
398
+ */
399
+ type LawSubject<G extends Gens, A> = (...values: ReadonlyArray<ElementValues<G>>) => A;
400
+ /**
401
+ * A metamorphic relation: the input transform, and how the two outputs relate (structural equality by default).
402
+ *
403
+ * @internal
404
+ */
405
+ interface MetamorphicRelation<G extends Gens, A> {
406
+ readonly transform: (...values: ReadonlyArray<ElementValues<G>>) => Values<G>;
407
+ readonly relate?: (original: A, transformed: A) => boolean;
408
+ }
409
+ /**
410
+ * The R13 law surface: four gated kinds and two declared exemptions.
411
+ *
412
+ * @internal
413
+ */
414
+ interface LawApi {
415
+ readonly model: <const G extends Gens, A, N extends number, S extends LawSubject<G, A>>(name: string, spec: PropertySpec<G, S, N>, oracle: LawSubject<G, A>) => void;
416
+ readonly metamorphic: <const G extends Gens, A, N extends number, S extends LawSubject<G, A>>(name: string, spec: PropertySpec<G, S, N>, relation: MetamorphicRelation<G, A>) => void;
417
+ readonly roundTrip: <const G extends Gens, E, N extends number, S extends LawSubject<G, E>>(name: string, spec: PropertySpec<G, S, N>, decode: (encoded: E) => Values<G>) => void;
418
+ readonly invariant: <const G extends Gens, A, N extends number, S extends LawSubject<G, A>>(name: string, spec: PropertySpec<G, S, N>, holds: (output: A, ...values: ReadonlyArray<ElementValues<G>>) => boolean) => void;
419
+ readonly idempotent: <const G extends Gens, N extends number, S extends (value: ElementValues<G>) => ElementValues<G>>(name: string, spec: PropertySpec<G, S, N>) => void;
420
+ readonly deterministic: <const G extends Gens, A, N extends number, S extends LawSubject<G, A>>(name: string, spec: PropertySpec<G, S, N>) => void;
421
+ }
422
+ /**
423
+ * The generated values as the argument list a law subject is called with.
424
+ *
425
+ * @internal
426
+ */
427
+ declare const spreadValues: <G extends Gens>(values: Values<G>) => ReadonlyArray<ElementValues<G>>;
428
+ /** @internal */
429
+ declare const modelHolds: <G extends Gens, A>(oracle: LawSubject<G, A>) => (subject: LawSubject<G, A>, values: Values<G>) => boolean;
430
+ /** @internal */
431
+ declare const metamorphicHolds: <G extends Gens, A>(relation: MetamorphicRelation<G, A>) => (subject: LawSubject<G, A>, values: Values<G>) => boolean;
432
+ /** @internal */
433
+ declare const roundTripHolds: <G extends Gens, E>(decode: (encoded: E) => Values<G>) => (subject: LawSubject<G, E>, values: Values<G>) => boolean;
434
+ /** @internal */
435
+ declare const invariantHolds: <G extends Gens, A>(holds: (output: A, ...values: ReadonlyArray<ElementValues<G>>) => boolean) => (subject: LawSubject<G, A>, values: Values<G>) => boolean;
436
+ /** @internal */
437
+ declare const idempotentHolds: <G extends Gens>() => (subject: (value: ElementValues<G>) => ElementValues<G>, values: Values<G>) => boolean;
438
+ /** @internal */
439
+ declare const deterministicHolds: <G extends Gens, A>() => (subject: LawSubject<G, A>, values: Values<G>) => boolean;
440
+ declare namespace engine_d_exports {
441
+ export { ArbitraryInput, CoveragePredicate, ElementValues, Gens, PropApi, PropertyRuntime, PropertySpec, PropertySubject, PropertyTask, Values, makeProperty };
442
+ }
443
+ /** @internal */
444
+ type ArbitraryInput = Schema$1.Top | Arbitrary.Arbitrary<Schema$1.Top['Type']>;
445
+ /** @internal */
446
+ type Gens = ReadonlyArray<ArbitraryInput> | {
447
+ readonly [key: string]: ArbitraryInput;
448
+ };
449
+ type Generated<I> = I extends Schema$1.Schema<infer T> ? T : I extends Arbitrary.Arbitrary<infer A> ? A : never;
450
+ /** @internal */
451
+ type Values<G extends Gens> = { readonly [K in keyof G]: Generated<G[K]>; };
452
+ /** @internal */
453
+ type ElementValues<G extends Gens> = G extends ReadonlyArray<ArbitraryInput> ? Generated<G[number]> : never;
454
+ /** @internal */
455
+ type PropertySubject = Subject;
456
+ /** @internal */
457
+ type CoveragePredicate<G extends Gens> = (...values: ReadonlyArray<ElementValues<G>>) => boolean;
458
+ type PropertyRuns<N extends number> = number extends N ? number : `${N}` extends `-${bigint}` ? never : `${N}` extends `${bigint}` ? (N extends 0 ? never : N) : never;
459
+ /** @internal */
460
+ interface PropertySpec<G extends Gens, S extends PropertySubject, N extends number> {
461
+ readonly of: G;
462
+ readonly subject: S;
463
+ /**
464
+ * The property's own run count. Omitted, the configured default applies; when the run provides none,
465
+ * the built-in default of 100 does.
466
+ */
467
+ readonly runs?: N & PropertyRuns<N>;
468
+ /** Labelled input predicates, each with the minimum share of runs it must see (R14). */
469
+ readonly cover?: Readonly<Record<string, readonly [CoveragePredicate<G>, number]>>;
470
+ /** The property's own check options, merged field by field over the provided and built-in defaults. */
471
+ readonly arbitrary?: Arbitrary.CheckOptions;
472
+ }
473
+ /** @internal */
474
+ interface PropertyTask {
475
+ /** The property's run-time identity (KTD3): its package, project-relative file and full name. */
476
+ readonly identity: TestIdentity;
477
+ /** The absolute path of the test file whose seed store is read and written beside it (KTD6); `null` keeps no store. */
478
+ readonly filepath: string | null;
479
+ /** The provided property budget, or `undefined` when the run provided none. */
480
+ readonly budget: ProvidedCheckDefaults | undefined;
481
+ }
482
+ /** @internal */
483
+ interface PropertyRuntime<R> {
484
+ /** Registers the property's program; the runtime runs it inside the test it registers, under that test's binding. */
485
+ readonly register: (name: string, program: (task: PropertyTask) => Effect$1.Effect<void, Cause.Cause<NonBooleanVerdict>, never>) => void;
486
+ readonly provide: <A, E>(effect: Effect$1.Effect<A, E, R>) => Effect$1.Effect<A, E, never>;
487
+ /** The file ledger every property of this runtime records its impostor verdict into (R20, KTD10). */
488
+ readonly ledger: FileLedger;
489
+ }
490
+ /** @internal */
491
+ interface PropApi<R> {
492
+ readonly prop: <const G extends Gens, S extends PropertySubject, N extends number>(name: string, spec: PropertySpec<G, S, N>, holds: (subject: S, values: Values<G>) => boolean) => void;
493
+ readonly effectProp: <const G extends Gens, S extends PropertySubject, N extends number, E>(name: string, spec: PropertySpec<G, S, N>, holds: (subject: S, values: Values<G>) => Effect$1.Effect<boolean, E, R>) => void;
494
+ readonly law: LawApi;
495
+ }
496
+ /**
497
+ * The property surface over one runtime: `prop`, `effectProp`, and the R13 law kinds routed through the gate.
498
+ *
499
+ * @internal
500
+ */
501
+ declare const makeProperty: <R>(runtime: PropertyRuntime<R>) => PropApi<R>;
502
+ //#endregion
503
+ export { VacuousProperty as A, witnessOf as C, ReplayUnreadable as D, PropertyRefuted as E, Breach as M, __exportAll as N, SeedStoreUnreadable as O, throwFailureRecord as S, NonBooleanVerdict as T, ReplayValue as _, PropertySubject as a, summaryOf as b, LawApi as c, ProvidedCheckDefaults as d, checkDefaultsKey as f, JsonValue as g, FailureRecordInput as h, PropertySpec as i, Witness as j, SelfModelLaw as k, kinds_d_exports as l, FailureRecord as m, Gens as n, Values as o, AttributeValue as p, PropApi as r, engine_d_exports as s, ArbitraryInput as t, PropertyBudget as u, TestIdentity as v, CoverageBelowMinimum as w, testIdentityOf as x, renderFailureRecord as y };