lawspec 0.7.0 → 0.9.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/README.md CHANGED
@@ -2,19 +2,37 @@
2
2
 
3
3
  **State the law once. Check it everywhere.**
4
4
 
5
- LawSpec 0.6 compiles reusable laws into native property tests, executable examples,
5
+ LawSpec 0.9 compiles reusable laws into native property tests, executable examples,
6
6
  and implementation adapters. The compiler is Haskell, distributed as prebuilt
7
7
  WebAssembly with a Node CLI and an asynchronous, typed JavaScript API.
8
8
 
9
- ## Portable scalars in 0.7.0
9
+ ## Structural data and total definitions in 0.9.0
10
10
 
11
- LawSpec now supports fixed and arbitrary integers, exact decimals and rationals,
11
+ LawSpec 0.9 adds `List`, algebraic `Maybe` and `Either`, named
12
+ parameterized products and sums, and checked total definitions on all eight
13
+ backends. See the [language reference](LANGUAGE.md),
14
+ [collections](examples/specs/collections.lawspec),
15
+ [data types](examples/specs/data_types.lawspec), and
16
+ [total functions](examples/specs/total_functions.lawspec).
17
+
18
+ Generated code is readable by default; `--minify` explicitly selects compact
19
+ output. Python follows PEP 8. See the [0.9 release notes](RELEASE-0.9.md)
20
+ and [API migration guide](API-MIGRATION.md).
21
+
22
+ ## Rust and the typed front end in 0.8.0
23
+
24
+ Rust joins Java, Python, JavaScript, TypeScript, Go, Haskell, and Kotlin. All
25
+ eight backends consume the same typed core and testing plan. Source expressions
26
+ retain their ranges, resolved identities, arithmetic evidence, and checked
27
+ conversions. See the [Rust guide](RUST.md) and [language reference](LANGUAGE.md).
28
+
29
+ The scalar catalog includes fixed and arbitrary integers, exact decimals and rationals,
12
30
  IEEE floats and complex values, Unicode and raw-text domains, bytes, symbols,
13
- and nested absence states on all seven targets. Integer arithmetic produces representation-independent
31
+ and nested absence states on all eight targets. Integer arithmetic produces representation-independent
14
32
  `Integer` values; exact division returns Rational. See the [primitive reference](PRIMITIVES.md)
15
33
  for constructors, arithmetic, native bridges, and machine-width profiles.
16
34
 
17
- Compiler API consumers should read the [schema v2 migration guide](API-MIGRATION.md).
35
+ Compiler API consumers should read the [schema v3 migration guide](API-MIGRATION.md).
18
36
  Scalar values use tagged, lossless encodings; generated runtime placement is
19
37
  separate from artifact ownership. Java 25+ and Python 3.13+ baselines are unchanged.
20
38
 
@@ -23,7 +41,7 @@ separate from artifact ownership. Java 25+ and Python 3.13+ baselines are unchan
23
41
  Install [LawSpec from npm](https://www.npmjs.com/package/lawspec):
24
42
 
25
43
  ```sh
26
- npm install --save-dev lawspec@0.7.0
44
+ npm install --save-dev lawspec@0.9.0
27
45
  npx lawspec --version
28
46
  ```
29
47
 
@@ -37,8 +55,8 @@ local dependencies so LawSpec can create its `package.json` and test script:
37
55
  ```sh
38
56
  mkdir lawspec-example
39
57
  cd lawspec-example
40
- npm exec --package=lawspec@0.7.0 -- lawspec init --target javascript
41
- npm install --save-dev lawspec@0.7.0
58
+ npm exec --package=lawspec@0.9.0 -- lawspec init --target javascript
59
+ npm install --save-dev lawspec@0.9.0
42
60
  npx lawspec check
43
61
  npx lawspec explain 'example.atoi_codec::itoa and then atoi yields a'
44
62
  npx lawspec doctor
@@ -71,9 +89,10 @@ properties with the selected framework's shrinking and failure reporting.
71
89
  | `go` | Go modules, Go 1.22–1.26 | Rapid 1.2.0, testing | `go test ./...` |
72
90
  | `haskell` | Stack, GHC 9.10, LTS 24.58 | Hspec 2.11, Hedgehog 1.5, hspec-hedgehog 0.3 | `stack test` |
73
91
  | `kotlin` | JDK/JVM 25, Gradle 9.1–9.3, Kotlin 2.3.21 | Kotest 5.9.1 | `gradle test` |
92
+ | `rust` | Rust 1.85+, edition 2024, Cargo | Proptest 1.11.0 | `cargo test` |
74
93
 
75
94
  Java 25 and Python 3.13 are the minimum baselines. New JVM releases are admitted
76
- through compatibility profiles after testing; v0.6's current JVM profile certifies
95
+ through compatibility profiles after testing; the current JVM profile certifies
77
96
  25. Python templates declare `requires-python = ">=3.13"` and runtime checks
78
97
  currently recognize 3.13 and 3.14. Kotlin templates pin Gradle's supported build
79
98
  configuration to Kotlin 2.3.21 and target JVM 25.
@@ -244,7 +263,7 @@ reusable laws accept these curried functions, their partial applications, and
244
263
  scalar parameters. Quantified test inputs remain scalar.
245
264
 
246
265
  The prelude defines the following laws. Every row has an executable example in
247
- [algebra.lawspec](https://github.com/brain-fuel/lawspec/blob/v0.7.0/examples/specs/algebra.lawspec), including both sides of every
266
+ [algebra.lawspec](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/algebra.lawspec), including both sides of every
248
267
  combined law. `f` and `g` are binary operations, `inverse` is unary, and `e` and
249
268
  `zero` are scalar parameters. All these laws require equality of the element type.
250
269
 
@@ -280,10 +299,10 @@ explicit domain predicate and conditional equations.
280
299
  `invertible` checks the supplied inverse operation. Check `identity` and
281
300
  `associative` as well when specifying a group. The prelude states contracts;
282
301
  it does not supply arithmetic implementations or prove a structure from random
283
- tests. The numeric examples use Int32 arithmetic modulo 2^32 so their laws hold
284
- at overflow boundaries on every target. JavaScript uses `Math.imul` for products,
285
- and Python explicitly wraps results into the signed Int32 range in the test
286
- adapters.
302
+ tests. The algebra and numeric currying examples use mathematical `Integer`
303
+ values and exact native arithmetic. Explicit expectations exceed Int32 and
304
+ machine bounds, so wrapping or lossy adapters fail even when their modular
305
+ arithmetic happens to satisfy the algebraic identities.
287
306
 
288
307
  Use `and` to require multiple conclusions in one law. For example:
289
308
 
@@ -312,11 +331,11 @@ their entire consequence. Every conjunct is type-checked and emitted. As with
312
331
  existing assertions, the first failure stops that individual test. `and` is now
313
332
  a reserved word.
314
333
 
315
- [Currying examples](https://github.com/brain-fuel/lawspec/blob/v0.7.0/examples/specs/currying.lawspec) demonstrate a four-argument
334
+ [Currying examples](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/currying.lawspec) demonstrate a four-argument
316
335
  function partially applied twice, a formatter with four heterogeneous arguments,
317
336
  and composition after partial application. Each example states its exact outputs.
318
337
  Run `node npm/bin/lawspec.mjs examples` after rebuilding to inspect all nine units
319
- in all seven target languages (126 artifacts).
338
+ in all eight target languages.
320
339
 
321
340
  The expanded API's **`assertion` tree is authoritative**: `AssertEqual` contains
322
341
  two expressions, `AssertImplies` contains a condition and consequence, and
@@ -364,7 +383,7 @@ law `valid ports round trip` is
364
383
  end
365
384
  ```
366
385
 
367
- The [complete port example](https://github.com/brain-fuel/lawspec/blob/v0.7.0/examples/specs/parse_port.lawspec)
386
+ The [complete port example](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/parse_port.lawspec)
368
387
  defines valid ports as 1–65535, and covers both endpoints, ordinary ports, zero,
369
388
  negative values, and 65536. All explicit `expect` assertions run regardless of
370
389
  the law's condition. A false condition skips only the consequence: invalid ports
@@ -382,7 +401,7 @@ The prelude includes `satisfies predicate` (the predicate holds for every input)
382
401
  and `left inverse when predicate parse render` (the guarded round trip above).
383
402
  These reusable laws preserve the condition and its lexical bindings when expanded.
384
403
  `equivalent` can also compare two predicates, since `Bool` supports equality.
385
- The [Boolean flags example](https://github.com/brain-fuel/lawspec/blob/v0.7.0/examples/specs/boolean_flags.lawspec)
404
+ The [Boolean flags example](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/boolean_flags.lawspec)
386
405
  checks that flipping twice restores both `false` and `true`; all targets generate
387
406
  Boolean property inputs and explicit tests for both Boolean boundary values. Java caps Boolean-only JetCheck runs at the number of
388
407
  possible input combinations (up to 100), avoiding generator exhaustion.
@@ -461,7 +480,7 @@ This expands to `for all (x :: Int32) . render (x) = referenceRender (x)`.
461
480
  The example inherits the input name `x` from the prelude. Both functions are
462
481
  user-owned adapter functions; either may delegate to your existing code.
463
482
 
464
- [The complete example](https://github.com/brain-fuel/lawspec/blob/v0.7.0/examples/specs/equivalent.lawspec) compares decimal
483
+ [The complete example](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/equivalent.lawspec) compares decimal
465
484
  renderers and two implementations that clamp negative integers to zero. For
466
485
  JavaScript, their adapters can be:
467
486
 
@@ -472,7 +491,7 @@ export const clamp = x => Math.max(0, x);
472
491
  export const referenceClamp = x => x < 0 ? 0 : x;
473
492
  ```
474
493
 
475
- The same specification generates native tests for all seven targets. The
494
+ The same specification generates native tests for all eight targets. The
476
495
  integration suite checks both examples with matching implementations, then
477
496
  breaks each alternative separately to verify detection. The general equivalence law alone does not establish independent correctness;
478
497
  two implementations can share the same bug. Explicit expectations additionally
@@ -498,7 +517,7 @@ law `normalizers agree` is
498
517
  end
499
518
  ```
500
519
 
501
- The [slug example](https://github.com/brain-fuel/lawspec/blob/v0.7.0/examples/specs/slug.lawspec)
520
+ The [slug example](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/slug.lawspec)
502
521
  compares two implementations of ASCII-space replacement. It includes empty,
503
522
  Unicode and escaped text. Each target uses its native string generator:
504
523
  JetCheck `Generator.stringsOf(Generator.asciiPrintableChars())`, Hypothesis `st.text()`, fast-check `fc.string()`,
@@ -525,7 +544,7 @@ law `canonicalization reaches a fixed point` is
525
544
  end
526
545
  ```
527
546
 
528
- The [canonical URL example](https://github.com/brain-fuel/lawspec/blob/v0.7.0/examples/specs/canonical_url.lawspec)
547
+ The [canonical URL example](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/canonical_url.lawspec)
529
548
  uses removal of **all trailing slashes** as a small fixed-point demonstration,
530
549
  not a complete URL canonicalization algorithm. For JavaScript:
531
550
 
@@ -534,7 +553,7 @@ export const canonicalize = value => value.replace(/\/+$/, "");
534
553
  ```
535
554
 
536
555
  Removing just one trailing slash fails the supplied repeated-slash example.
537
- The [mixed-input example](https://github.com/brain-fuel/lawspec/blob/v0.7.0/examples/specs/mixed_inputs.lawspec)
556
+ The [mixed-input example](https://github.com/brain-fuel/lawspec/blob/v0.9.0/examples/specs/mixed_inputs.lawspec)
538
557
  shows `Text` and `Int32` in the same quantified property and executable example.
539
558
  The JavaScript API represents input bindings and expected values as `number | string | boolean`.
540
559
  Each example includes `expectations: { actual: Expr; expected: number | string | boolean }[]`.
@@ -550,7 +569,7 @@ npx lawspec examples --target java --output example_artifacts
550
569
  This command works without a project configuration or native build tools. It
551
570
  compiles every bundled example and writes its tests and user-owned stubs to
552
571
  `example_artifacts/<language>/`, using each target's normal source/test layout.
553
- By default it exports all seven languages; `--json` returns the file inventory.
572
+ By default it exports all eight languages; `--json` returns the file inventory.
554
573
  From a checkout, `make examples` runs the same command.
555
574
 
556
575
  These are inspection artifacts, not initialized projects: no build files are
@@ -599,7 +618,7 @@ by the JS shim.
599
618
  ## Build and verify
600
619
 
601
620
  For contributors working from a repository checkout, build a local archive with
602
- `npm pack ./npm` and install it with `npm install --save-dev ./lawspec-0.7.0.tgz`.
621
+ `npm pack ./npm` and install it with `npm install --save-dev ./lawspec-0.9.0.tgz`.
603
622
  The package payload lives in `npm/`.
604
623
 
605
624
  ```sh
@@ -623,7 +642,7 @@ compiler-source and artifact hashes in `npm/build.json`; CI rejects stale WASM
623
642
  or hand-edited generated wrappers. The npm archive is a self-contained consumer
624
643
  artifact, with no install-time compilation or download hook.
625
644
 
626
- For all seven native integrations, install their build tools, then:
645
+ For all eight native integrations, install their build tools, then:
627
646
 
628
647
  ```sh
629
648
  # Set LAWSPEC_GRADLE to a Gradle 9.3.0 executable if it is not on PATH.
package/REFINEMENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- # Refinements and abstract integers (0.7.0)
1
+ # Refinements and abstract integers (0.9.0)
2
2
 
3
3
  A refinement restricts a scalar domain with a pure Boolean expression. LawSpec
4
4
  checks concrete examples, generates satisfying input tuples, and checks adapter
@@ -82,7 +82,8 @@ refinement PositiveInt8 is (value :: Int8 where value > 0) end
82
82
 
83
83
  Aliases preserve their underlying native representation. They can be nested in
84
84
  `Nullable` and `Optional`; inner predicates are checked only for present values.
85
- Type parameters range over the supported scalar types, including presence types.
85
+ Type parameters range over supported value types, including structural types.
86
+ Their declared capabilities determine which operations are available.
86
87
 
87
88
  `requires Integer T` describes integer capabilities in a generic declaration.
88
89
  `Integer` entails `Eq` and `Ordered`. `Ordered` currently covers exact real numbers
@@ -108,7 +109,30 @@ Adapter calls are forbidden in refinements. Predicate errors such as division by
108
109
  zero are reported as failures when evaluated; they are not ordinary rejection of
109
110
  an input. Short-circuited branches are not evaluated by generation optimizations.
110
111
 
111
- Every refined function signature creates a standalone property. Calls from other
112
+ In the 0.9 frontend, predicates can call checked total definitions, including
113
+ generic definitions specialized to the predicate's concrete types:
114
+
115
+ ```lawspec
116
+ definition nonempty (xs :: List a) :: Bool is
117
+ match xs with
118
+ | Nil -> false
119
+ | Cons head tail -> true
120
+ end
121
+ end
122
+
123
+ refinement Nonempty (T :: Type) is
124
+ (xs :: List T where nonempty xs)
125
+ end
126
+ ```
127
+
128
+ The same closed definitions evaluate example inputs, constant refinement
129
+ arguments, finite domains, and boundaries, and run in generated predicate and
130
+ contract checks on all eight targets. Calls to adapters cannot enter that closed
131
+ environment. Definitions can also refine their own parameters and results.
132
+ Their bodies must be proved total under the ordered input preconditions, and
133
+ every result refinement must follow from the body.
134
+
135
+ Every refined adapter signature creates a standalone property. Calls from other
112
136
  laws also check argument preconditions, invoke the adapter once, snapshot its
113
137
  result, and check postconditions. Calling a function outside its precondition is
114
138
  a test failure, not a discarded example. Ordinary `implies` guards retain their
@@ -156,3 +180,265 @@ Statically established empty executable domains and invalid examples are rejecte
156
180
  See [the bundled examples](examples/specs/refinements.lawspec) for overflow,
157
181
  abstract integer arguments/results, dependent bounds, optional refinements,
158
182
  floating classification, and raw-byte lengths.
183
+
184
+
185
+ ## Refined definitions
186
+
187
+ ```lawspec
188
+ definition increment (x :: Int8 where x < 127)
189
+ :: (result :: Int8 where result > x)
190
+ is
191
+ prelude.Int8 (x + 1)
192
+ end
193
+ ```
194
+
195
+ Arithmetic promotes before the explicit Int8 conversion. The compiler proves
196
+ that the precondition makes the conversion safe and that the result exceeds x.
197
+ Later parameters may depend on earlier parameters. Result binders must differ
198
+ from argument names.
199
+
200
+ Generic definitions retain their contracts through specialization. Templates,
201
+ including unused ones, must pass type, capability, termination and definedness
202
+ checks before concrete instances are emitted. Each closed call must satisfy its
203
+ callee's preconditions. Contracts cannot depend cyclically on their definitions
204
+ or call adapters. A claim the proof checker cannot establish is rejected.
205
+
206
+ The reference evaluator and all eight native backends validate arguments, check
207
+ preconditions in order, evaluate the body, validate its result, and check
208
+ postconditions. An invalid native call fails before unsafe body arithmetic.
209
+ Definitions are proved during compilation; adapter contracts instead generate
210
+ standalone properties because their implementations are external.
211
+
212
+ See [refined definitions](examples/specs/refined_definitions.lawspec) for generic
213
+ reciprocals, checked narrowing and dependent bounds. Both the native compiler
214
+ and packaged WASM build support these contracts.
215
+
216
+ The native definition-contract harnesses accept `LAWSPEC_CONTRACT_SOURCE=1`.
217
+ This compiles `test/fixtures/definition_contracts.lawspec` through the public
218
+ frontend before emitting native code. All eight targets pass both machine
219
+ profiles and readable/compact modes, including ordered predicate checks, exact
220
+ division through a specialized generic helper, narrowing, direct logical calls,
221
+ and postcondition rejection of deliberately corrupted results. The default mode
222
+ retains the independently constructed Core fixture.
223
+
224
+ ## Sum payload refinements
225
+
226
+ `Maybe (value :: Int8 where value > 0)` admits `Nothing` and positive `Just`
227
+ payloads. `Either (value :: Int8 where value > 0) Bool` checks the positive bound
228
+ only for `Left`; `Right` retains its Bool domain. Nested sums compose these
229
+ checks, and payload predicates may refer to earlier quantified inputs.
230
+
231
+ These refinements elaborate to exhaustive Core matches. Unselected branches are
232
+ not evaluated, and generated binder names preserve outer dependencies. Finite
233
+ domains retain distinct absence and variant states. Named data payload and constructor-field refinements are also supported. The bundled [sum refinement examples](examples/specs/sum_refinements.lawspec)
234
+ pass native framework execution on all eight targets under both machine profiles
235
+ and readable/compact layouts. The data integration harnesses include these laws
236
+ with their existing structural and incorrect-adapter checks.
237
+
238
+
239
+ ## List payload refinements
240
+
241
+ `List (value :: Int8 where value > 0)` constrains every element and admits the
242
+ empty list. Lists compose with other Lists, Maybe, and Either. An element
243
+ predicate can refer to an earlier quantified input, for example:
244
+
245
+ ```lawspec
246
+ law `elements exceed the earlier bound` is
247
+ definition is `for all` (floor :: Int8)
248
+ (xs :: List (value :: Int8 where value > floor)) .
249
+ prelude.length xs >= 0
250
+ end
251
+ end
252
+ ```
253
+
254
+ These domains elaborate to a typed, scoped Core `AllElements` predicate. It
255
+ checks elements in order, stops at the first false result, and returns true for
256
+ an empty list. Its binder is fresh with respect to outer dependencies. There is
257
+ no new user-facing predicate syntax. Explicit examples outside the domain are
258
+ rejected; nested predicates keep their element scope during specialization.
259
+ See [the List refinement examples](examples/specs/list_refinements.lawspec).
260
+
261
+ Generic definition signatures can contain List payload refinements, including
262
+ calls to generic Boolean helpers. Native entry points check these contracts.
263
+ The totality prover retains universal element facts for each List identity.
264
+ A stronger exact numeric bound can satisfy a weaker callee contract, including
265
+ nested Lists. Matching calls to pure Boolean helpers can also be reused after
266
+ specialization. Returned inputs and explicitly constructed Lists can establish
267
+ universal postconditions; the empty list satisfies every element predicate.
268
+ See [the List contract examples](examples/specs/list_contracts.lawspec).
269
+
270
+ Proof binders are fresh and scoped. An element condition never implies that a
271
+ list is nonempty, and facts about one list do not transfer to another list or to
272
+ an unrelated scalar. In a `Cons first rest` branch, `first` inherits the element
273
+ predicate and `rest` retains the universal predicate with its original outer
274
+ dependencies. Both are strict structural subterms for termination checking. A
275
+ `Nil` branch knows only that its matched list is empty. These facts stay inside
276
+ their branch and can establish branch-specific result contracts.
277
+
278
+ For example, a definition over `List (value :: Int8 where value != 0)` can divide
279
+ by each matched head and recursively process the tail. The bundled List contract
280
+ examples include exact reciprocal sums and nested rows. More complex implications,
281
+ including facts requiring a callee's result contract to be unfolded, remain
282
+ conservative and may be rejected.
283
+
284
+ Verified callee results are available to the total-definition proof checker.
285
+ A helper's postcondition can establish a nonzero divisor, justify checked integer
286
+ narrowing, or satisfy the next helper's input contract. For example:
287
+
288
+ ```lawspec
289
+ definition nonzero (value :: Int8 where value != 0)
290
+ :: (result :: Int8 where result != 0)
291
+ is value end
292
+
293
+ definition reciprocal (value :: Int8 where value != 0) :: Rational is
294
+ 1 / nonzero value
295
+ end
296
+ ```
297
+
298
+ The checker first proves the call's preconditions and, for recursive calls,
299
+ strict structural descent. Only then does it use the result guarantee. Recursive
300
+ List construction can therefore prove element postconditions by induction over
301
+ the tail. A returned List does not itself acquire structural-subterm status.
302
+ Guarantees remain scoped to evaluated branches and short-circuit operands;
303
+ a skipped call cannot justify arithmetic elsewhere. Every helper's own result
304
+ contract is checked, including helpers unused by laws.
305
+
306
+ Constructor-sensitive matching also preserves payload refinements in total
307
+ functions. A `Maybe` payload fact is available in the `Just` branch; an `Either`
308
+ fact belongs to its corresponding `Left` or `Right` branch. Constructed results
309
+ are checked against the matching alternative, including nested sums.
310
+
311
+ Whole-value refinements on named products can relate fields explicitly:
312
+
313
+ ```lawspec
314
+ type Range is Range lower :: Int8 upper :: Int8 end
315
+
316
+ definition gap
317
+ (range :: Range where match range with | Range lo hi -> hi > lo end)
318
+ :: Rational
319
+ is
320
+ match range with | Range lo hi -> 1 / (hi - lo) end
321
+ end
322
+ ```
323
+
324
+ The field relation justifies the nonzero denominator within that branch. It
325
+ cannot establish a fact about a different value or another constructor's payload.
326
+ This example uses a refinement on the function's whole input value; direct
327
+ constructor-field refinements can express the relation at the data declaration.
328
+
329
+
330
+ ## Named data payloads
331
+
332
+ A product or sum can receive refined type arguments. The predicate
333
+ applies wherever that parameter is stored, including recursive named
334
+ types, List elements, and Maybe/Either payloads. Other alternatives remain
335
+ unconstrained when they do not store that parameter.
336
+
337
+ ```lawspec
338
+ unit example.positive_pair
339
+
340
+ type Pair (a :: Type) (b :: Type) is
341
+ Pair first :: a second :: b
342
+ end
343
+
344
+ refinement Positive is (value :: Int8 where value > 0) end
345
+
346
+ definition reciprocal (pair :: Pair Positive Bool) :: Rational is
347
+ match pair with
348
+ | Pair first second -> 1 / first
349
+ end
350
+ end
351
+
352
+ law `half` is
353
+ definition is
354
+ `for all` (pair :: Pair Positive Bool) . reciprocal pair > 0
355
+ end
356
+ example `two` is
357
+ pair = Pair 2 false
358
+ expect reciprocal pair = rational(1, 2)
359
+ end
360
+ end
361
+ ```
362
+
363
+ The compiler lowers the payload requirement to a scoped traversal in the shared
364
+ Core. Generators, concrete examples, adapter contracts, and checked definition
365
+ entry points use that predicate. The native representation remains
366
+ `Pair Int8 Bool`; the refinement does not introduce a new wrapper type. Definition proofs
367
+ can use the selected field's predicate to establish that division is defined.
368
+
369
+ Free value names in a type argument retain the scope where the argument was
370
+ written. In `Pair Int8 (n :: Int8 where n > first)`, `first` refers to an earlier
371
+ outer input; a constructor field also named `first` does not capture it.
372
+
373
+ Recursive payloads such as `Tree Positive` use the same operation. Traversal
374
+ follows stored parameter positions, including mutual recursion and growing
375
+ arguments such as `Nest (List a)`. A fixed `Int8` field is not constrained merely
376
+ because another parameter is instantiated as `Int8`. Empty and phantom storage
377
+ satisfies its payload predicate without evaluating a callback. See the bundled
378
+ [recursive refinement example](examples/specs/recursive_refinements.lawspec),
379
+ which proves a positive result for a recursive sum and preserves outer thresholds.
380
+
381
+ The front end checks direct constructor field contracts:
382
+
383
+ ```lawspec
384
+ type Gap is
385
+ Gap first :: Int8 second :: (n :: Int8 where n > first)
386
+ end
387
+
388
+ definition inverseGap (gap :: Gap) :: Rational is
389
+ match gap with | Gap x y -> 1 / (y - x) end
390
+ end
391
+ ```
392
+
393
+ A field predicate may refer to that field and earlier fields. Construction in a
394
+ total definition must prove the predicates; matching makes them available in the
395
+ selected branch. Concrete example inputs and expected values are checked too.
396
+ The reference interpreter enforces predicates on definition inputs and results.
397
+ All eight backends enforce these
398
+ contracts in generated runtime checks and native Hypothesis/fast-check/proptest/
399
+ JetCheck/Kotest/Rapid/Hedgehog strategies. Each generated case
400
+ shares one Symbol fixture context across witnesses, inputs, adapter checks and
401
+ assertions. Witnesses supplement native strategies; sampled alternatives may
402
+ retain large counterexamples even when native branches can shrink further.
403
+ Web and Rust generation bound whole-value retries with `maxAttempts`; an exhausted search
404
+ reports failure rather than claiming that the domain is empty. Input guards use
405
+ fast-check preconditions, preserving its skip and shrink handling. Rust carries
406
+ predicate evaluation errors into property failures rather than treating them as
407
+ rejected candidates. Java preserves native JetCheck filtering/shrinking, caps each
408
+ filter at the smaller of `maxAttempts` and the framework's 100-attempt limit, and
409
+ reports evaluator errors as contextual generation failures. It uses one native
410
+ session per requested constructor-contract case to avoid session-wide draw
411
+ uniqueness exhaustion for fixture identities. Kotlin bounds candidate sampling
412
+ while retaining native shrink trees; case state carries evaluator errors past
413
+ input guards to the property failure. Go uses Rapid's bounded native filtering
414
+ and replay-based shrinking, with per-sample error state that prevents later fields
415
+ from hiding an evaluator failure. Required conjunctive Symbol equalities bind the
416
+ fixture identity directly; disjunctions retain their alternatives. Go's structural
417
+ properties honor `cases` with scoped Rapid settings, restoring the previous flag
418
+ after each sequential generated test. Rapid's explicit short-test mode may reduce
419
+ that count. Each filter uses at most the smaller of `maxAttempts` and Rapid's
420
+ five-attempt native limit; enclosing native generators and the engine retain
421
+ their own retry limits. For structural Go properties, minimization uses Rapid's
422
+ `-rapid.shrinktime` setting, not the scalar refinement engine's `maxShrinks`
423
+ step budget. Haskell constructor properties use native Hedgehog strategies with
424
+ one Symbol context per case. Each dependent draw is forced before the next draw;
425
+ evaluator failures cannot disappear behind a later discard. Native `filterT`
426
+ prunes rejected shrink branches instead of searching all their descendants.
427
+ Hedgehog receives `cases` as its test limit, `maxAttempts` as its property discard
428
+ limit, and `maxShrinks` as its shrink limit. Internal generator filters retain
429
+ Hedgehog's own retry policy; `maxAttempts` is not a total count of candidate draws.
430
+ Recursively refined named payloads use scoped payload predicates that follow
431
+ declared type-parameter positions through constructor fields.
432
+
433
+ Common domain planning filters finite constructor domains through their field
434
+ predicates. For larger domains, it searches combinations of field boundaries and
435
+ literal values from contracts. This covers dependent fields such as `Gap` and
436
+ sparse Symbol fixture identities. Recursive expansion and candidate combinations
437
+ have finite search budgets; every returned witness satisfies the contracts.
438
+ Exhausting that search reports that no witness was found, rather than declaring
439
+ the domain empty. Bounded samples are never reported as an exhaustive domain.
440
+
441
+ Expression annotations select a representation, such as `(127 :: Int8)`; they
442
+ do not establish a refinement contract. Inline refinement predicates in expression
443
+ annotations are rejected. Put the refinement on a quantified input or function
444
+ signature so that generation, checking, and definition proofs enforce it.
package/RELEASE-0.9.md ADDED
@@ -0,0 +1,61 @@
1
+ # LawSpec 0.9.0
2
+
3
+ This release adds structural data and checked total definitions across Java,
4
+ Python, JavaScript, TypeScript, Go, Haskell, Kotlin, and Rust.
5
+
6
+ ## Language
7
+
8
+ - `List a` supports nested contextual literals, structural equality, exact
9
+ length, deterministic boundaries, and native framework generation/shrinking.
10
+ - Algebraic `Maybe a` and `Either a b` provide `Nothing`/`Just` and `Left`/`Right`.
11
+ They remain distinct from interoperability `Nullable` and `Optional` values.
12
+ - Named parameterized products and sums have constructors and ordered fields.
13
+ Generated native types and typed adapters preserve their structure.
14
+ - Total definitions support exhaustive matching and checked structural recursion.
15
+ The compiler rejects partial matches and recursion it cannot establish as
16
+ terminating. Generic definitions specialize to their concrete uses.
17
+ - Refined definition signatures become executable native contracts. Scoped
18
+ payload predicates preserve type-parameter roles through recursive and mutual
19
+ data declarations, including predicates that depend on preceding inputs.
20
+
21
+ Existing scalar semantics remain intact: exact arithmetic does not wrap,
22
+ conversions to bounded adapter parameters are checked, floating equality follows
23
+ IEEE rules, and Symbol equality uses identity.
24
+
25
+ ## Generated output
26
+
27
+ Readable code is the default for runtimes, declarations, definitions, adapters,
28
+ tests, and scaffolds. Explicit `--minify` selects compact output for `init`,
29
+ `generate`, and `examples`; the compiler API accepts `minify: true`.
30
+
31
+ Output follows Google language-specific guidance where applicable, PEP 8 for
32
+ Python, standard Go and Rust formatting, and an 80-column Haskell layout.
33
+ Formatting is deterministic in both native and WASM compilation and requires
34
+ no formatter download. Compact output preserves required layout, literal
35
+ contents, and semantics. Changing formatting mode does not overwrite edited
36
+ adapters or create false adapter-signature updates.
37
+
38
+ ## API and compatibility
39
+
40
+ API schema 3 adds named data declarations, structural values, checked definitions,
41
+ construction/matching expressions, and scoped payload predicates. Existing scalar
42
+ wire encodings are unchanged. Exhaustive expression visitors must handle the
43
+ new variants; see [API migration](API-MIGRATION.md).
44
+
45
+ Java 25+, Python 3.13+, Node 22+, and Rust 1.85+ baselines remain unchanged.
46
+ Machine-width profiles, custom source/test directories, generation manifests,
47
+ and user ownership of adapters/build files remain supported. Framework-specific
48
+ strategies stay separate from reusable runtime source.
49
+
50
+ GADTs, indexed families, and general dependent types remain future work. See
51
+ [the language reference](LANGUAGE.md) and the target guides for native type
52
+ representations and framework-specific refinement/shrinking limits.
53
+
54
+ ## Examples and release acceptance
55
+
56
+ Bundled examples cover reverse involution, sorting idempotence/sortedness/length/
57
+ permutation, nested presence, products/sums, exhaustive matches, total functions,
58
+ and recursive payload refinements. Release acceptance includes compiler and
59
+ native/WASM checks, native execution on all eight targets, deliberately incorrect
60
+ adapters, independent formatting/syntax checks, regeneration protection, and
61
+ installation of the packed npm artifact. Publication is a separate step.