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/API-MIGRATION.md CHANGED
@@ -1,27 +1,120 @@
1
- # Compiler API migration: schema 1 → schema 2
1
+ # Compiler API migration: schema 2 → schema 3
2
+
3
+ LawSpec 0.8 introduced API schema version **3**, which 0.9 continues to use.
4
+ Requests may omit `schemaVersion` or
5
+ send `3`. An explicit `2` (or any other version) receives a request diagnostic;
6
+ it is never silently reinterpreted. LawSpec specification syntax remains compatible.
7
+ The generated `index.d.ts` describes the public protocol. Internal Haskell
8
+ constructors and record fields are no longer the wire format.
9
+
10
+ ## 0.9 structural data and definition metadata
11
+
12
+ Successful results also expose `dataTypes: DataTypeDeclaration[]`. Each named
13
+ declaration has a resolved `id`, a display `name`, parameter IDs, an origin, and
14
+ constructors with resolved IDs and ordered typed fields. Use resolved IDs to
15
+ join references; constructors with the same display name can belong to different
16
+ units. Built-in container types do not need user declarations in this array.
17
+
18
+ Example bindings now use `DataValue`: either an existing tagged scalar or
19
+ `{kind: "data", type: Type, constructor: string, fields: DataValue[]}`. List values
20
+ use `List::Nil` and `List::Cons`, with head and tail fields; Maybe and Either use
21
+ their qualified constructor IDs. Do not flatten these values to JSON arrays or
22
+ nullable fields: that would lose constructor and nested-presence distinctions.
23
+
24
+ Expressions add `construct` nodes with a constructor ID and argument expressions,
25
+ and `match` nodes with a scrutinee and cases. Each case has a constructor ID,
26
+ ordered typed binders, and a body. Its binders are local to that case. Structural
27
+ expressions are represented by these nodes, not by scalar `constant` nodes.
28
+ Exhaustive API visitors must handle the added expression variants even though
29
+ the protocol continues to use schema version 3.
30
+
31
+ Successful results add `definitions: Definition[]`. Each entry contains `owner`,
32
+ the resolved declaration `id`, typed `arguments: Binder[]`, and a typed `body`.
33
+ The matching entry in `units[].declarations` supplies the signature and origin.
34
+ Calls retain their declaration ID; consumers can join against `definitions` to
35
+ distinguish checked bodies from external adapters. An empty array means the
36
+ program has no definitions.
37
+
38
+ The native frontend checks these bodies for typing, exhaustive matching,
39
+ structural termination, and potentially failing operations. Native reference
40
+ execution and source emission for Rust, Java, Kotlin, Python, JavaScript,
41
+ TypeScript, Go, and Haskell are implemented, including generic definitions
42
+ specialized to concrete signatures. The API exposes concrete instances with
43
+ generated names and resolved IDs, not unspecialized templates. Calls sharing a
44
+ signature reuse an instance; unused templates emit none. Consumers should join
45
+ by ID rather than parse generated names. Refinement-bearing definitions are
46
+ checked and emitted by both the native compiler and bundled WASM distribution.
47
+ Definition bodies produce generated source rather than
48
+ user-owned adapter stubs. Haskell native entry points take an `LS.SymbolContext`
49
+ and return `Either String a`; generated tests allocate a context per example or
50
+ property iteration so Symbol fixture identity does not escape its scope.
51
+
52
+ Refinement and contract expressions may now contain calls whose IDs resolve to
53
+ checked `definitions`. Validation still rejects calls to external adapters in
54
+ these expressions. Test planning evaluates the closed definitions when filtering
55
+ finite cases, boundaries, and concrete example inputs. Calls remain ordinary
56
+ typed call nodes; consumers need no source-level refinement interpreter.
57
+
58
+ ## Laws and typed expressions
59
+
60
+ Read `result.laws[i].examples` instead of `law.original.examples`. A binding is
61
+ now `{id, name, type, value}` rather than `[name, value]`. `value` retains the
62
+ lossless tagged scalar representation from schema 2. Expected results are typed
63
+ expressions in an assertion, for example `example.expectations[0].right.node.value`.
64
+
65
+ Every expression has `{type, origin, text, node}`. `text` is for presentation;
66
+ inspect `node` for semantics. Nodes explicitly distinguish constants, resolved
67
+ locals, declaration calls, arithmetic with capability evidence, short-circuit
68
+ operators, helpers, and conversions. Conversion mode `checked` means an exact
69
+ result must fit its adapter parameter; `explicit` records a source conversion.
70
+ There is no separate `typedExpressions` side table to match against source ASTs.
71
+
72
+ Assertions are the authoritative proposition tree:
73
+
74
+ - `{kind: "equal", evidence, left, right}`
75
+ - `{kind: "implies", guard, body}`
76
+ - `{kind: "all", items}`
77
+
78
+ The `left`, `right`, and `guards` compatibility projections on laws are removed.
79
+ Traverse the tree to preserve shared guard scope and conjunction order. Do not
80
+ flatten guards or turn refinement predicates into implications.
81
+
82
+ Inputs use `{id, name, type, predicates, bounds}`. IDs identify binders;
83
+ display names need not be globally unique. Bounds are derived generation hints
84
+ `{operator, value}` over preceding inputs. Predicates remain authoritative.
85
+ `generationPlan` and `inputRefinements` are replaced by these explicit fields.
86
+ Contracts expose typed argument/result binders, preconditions, and postconditions.
87
+ Refinement declarations expose documented parameter kinds, requirements, and a
88
+ printed definition; they are not serialized source ASTs.
89
+
90
+ ## Types, identity, and locations
91
+
92
+ Types are discriminated views, not `tag`/`contents` encodings:
2
93
 
3
- LawSpec 0.7.0 responses include `schemaVersion: 2`. Requests may omit the version
4
- or explicitly send `schemaVersion: 2`; unsupported versions receive a request
5
- diagnostic. Existing specification source remains compatible. Consumers of the
6
- JSON AST must migrate together with the compiler.
7
-
8
- ## Scalar values
94
+ ```js
95
+ { kind: "constructor", name: "Int8", arguments: [] }
96
+ { kind: "constructor", name: "Optional", arguments: [
97
+ { kind: "type", type: { kind: "constructor", name: "Int8", arguments: [] } }
98
+ ] }
99
+ ```
9
100
 
10
- Example bindings and expected values are uniformly tagged. Do not coerce every
11
- numeric value to JavaScript Number.
101
+ Function types use `{kind: "function", parameter, result}`; type variables use
102
+ `{kind: "variable", id}`. The argument model distinguishes types, natural indices
103
+ (encoded as decimal strings), and index variables. This representation does not
104
+ make unimplemented containers or dependent families available in 0.8.
12
105
 
13
- ```js
14
- // Previously: ["x", 42]
15
- // Now:
16
- ["x", { type: "Int32", value: "42" }]
106
+ Declaration/property/binder IDs remain stable when unrelated laws are inserted.
107
+ Origins are either `{kind: "source", span: {start, end}}` or
108
+ `{kind: "generated", declaration}`. Source ranges come from parsing, including
109
+ expressions in reused laws and refinements. Generated nodes identify their owner
110
+ instead of inventing source coordinates. Positions use one-based lines/columns;
111
+ end positions are exclusive and can include trailing parser whitespace.
17
112
 
18
- // Lossless unsigned 64-bit example:
19
- { type: "UInt64", value: "18446744073709551615" }
20
- ```
113
+ ## Scalar values remain lossless
21
114
 
22
115
  | Domain | Payload after `type` |
23
116
  | --- | --- |
24
- | All integers | `value`: decimal string |
117
+ | Integers, including logical Integer | `value`: decimal string |
25
118
  | Bool | `value`: Boolean |
26
119
  | Decimal | `coefficient`, `exponent`: decimal strings |
27
120
  | Rational | `numerator`, `denominator`: decimal strings; reduced, denominator positive |
@@ -33,53 +126,79 @@ numeric value to JavaScript Number.
33
126
  | Unit / Null / Undefined | No payload |
34
127
  | Nullable / Optional | `value`: null for missing, otherwise a tagged scalar |
35
128
 
36
- Text is also encoded as units, making the scalar schema uniform. Raw surrogate
37
- code points never travel through JSON strings. The enclosing input type supplies
38
- the inner type of a missing presence value.
39
-
40
- `Expr.Number.contents` is now a decimal **string**. New expression nodes are
41
- `DecimalNumber` (coefficient/exponent strings), `ScalarLit`, `Binary`, `Unary`, and `Annotate`. `Type.Applied` represents Nullable
42
- and Optional. Expanded laws include `typedExpressions`, with operation operand
43
- and result types plus an explicit `requiredConversion` for checked adapter bridges. Assertion trees remain authoritative;
44
- `left`, `right`, and `guards` remain compatibility projections.
45
-
46
- ## Profiles and artifacts
47
-
48
- Requests accept `machineBits?: 32 | 64`, defaulting to 64. Successful responses
49
- include the selected `machineBits`. A profile controls language domains, not the
50
- architecture of the WASM compiler itself.
51
-
52
- Artifacts now include `placement: "source" | "test"` independently of
53
- `ownership: "user" | "generated"`. A generated runtime belongs in a source
54
- directory. Do not infer its placement from generated ownership. Continue using
55
- the manifest writer to protect edited generated files and preserve user adapters.
56
-
57
- The generated `index.d.ts` declares the complete discriminated unions. CLI
58
- `explain` prints the new scalar values without converting large integers to
59
- floating point. Native and WASM dispatch expose the same schema.
60
-
61
-
62
- ## Refinements in the unreleased 0.7.0 schema
63
-
64
- API v2 also carries parameterized refinements and executable contracts. `Integer`
65
- is a logical integer scalar tag whose `value` is a decimal string. Default integer
66
- literals and promoted integer operations now have logical type `Integer`; explicit
67
- `BigInt` declarations retain their native mappings. Both tags preserve exact values.
68
-
69
- `Law.requirements` contains `Capability` nodes (`Eq`, `Integer`, `Ordered`,
70
- `Bounded`) with their target types. Types add `Refined`, `RefinementApp`,
71
- `Qualified`, and `CheckedType` nodes. Refinement arguments explicitly distinguish
72
- `TypeArgument` from `ValueArgument`; declaration parameter kind `Type` is not a
73
- runtime scalar. Expressions add `TypeBound` and logical operators.
74
-
75
- Responses expose unit-owned `refinements` and `contracts`. Each expanded property
76
- has `propertyKind` (`law` or `contract`), `generation` settings, and a
77
- `generationPlan`. Inputs retain their underlying `inputType` and carry separate
78
- `inputRefinements`. Domain plans include derived comparison bounds; the complete
79
- predicate remains authoritative. Refinements must not be interpreted as implication
80
- guards or as permission to count rejected inputs as successful checks.
81
-
82
- Requests accept partial `generation` settings (`cases`, `maxAttempts`,
83
- `maxShrinks`, `exhaustiveLimit`). Project configuration accepts the same object.
84
- Generated TypeScript declarations define the complete wire shapes. These additions
85
- are included in schema v2 before its release; schema v1 remains unsupported.
129
+ Do not coerce integer strings to JavaScript Number. Text uses code units or code
130
+ points as appropriate to its domain; raw surrogates never pass through JSON
131
+ strings. The enclosing type supplies the inner type of a missing presence value.
132
+
133
+ ## Checking, generation, and artifacts
134
+
135
+ `check` and `expand` validate the language. `planGeneration` additionally checks
136
+ whether its input domains can be executed. For example, a well-typed empty finite
137
+ refinement can pass `check` and fail generation with an empty-domain diagnostic.
138
+ Exhausted refinement searches fail explicitly; rejected inputs do not count as
139
+ successful tests.
140
+
141
+ Requests retain `machineBits?: 32 | 64` (default 64) and partial `generation`
142
+ settings (`cases`, `maxAttempts`, `maxShrinks`, `exhaustiveLimit`). Rust joins the
143
+ seven existing targets. Artifacts retain separate `ownership` and `placement`:
144
+ generated runtime source belongs in source directories, adapters remain
145
+ user-owned, and test helpers belong in test directories. Never infer placement
146
+ from ownership or assume a fixed number of generated files. Continue using the
147
+ manifest writer to protect edited files.
148
+
149
+ All nonempty test plans now emit the portable scalar runtime. Existing Haskell
150
+ projects must include `text` and `bytestring` in the component that compiles
151
+ that source. Doctor reports the missing dependencies before generation. Build
152
+ files remain user-owned; new scaffolds already include these dependencies.
153
+
154
+ ## Formatting requests and adapter references (0.9)
155
+
156
+ `GenerationRequest` accepts `minify?: boolean`, defaulting to `false`. The CLI
157
+ passes an explicit `--minify` from `generate` and `examples`. `init --minify`
158
+ also compacts newly created scaffolds and the configuration JSON; the choice is
159
+ not saved as a project setting. Existing project build files stay user-owned. Source/test placement is independent of
160
+ formatting. Compact rendering preserves mandatory newlines, indentation, token
161
+ separators, comments, and literal contents.
162
+
163
+ User-owned artifacts may include `adapterReference`, the compiler's canonical
164
+ readable scaffold. It is comparison data, not the user's implementation and not
165
+ an additional file to write. Manifest writers should hash this reference when
166
+ present, falling back to `content` for older producers. Continue hashing actual
167
+ `content` for generated-file ownership. This keeps a switch of formatting mode
168
+ from producing false adapter-update reports, while declared interface changes
169
+ still request review. Never normalize, overwrite, or hash user implementations
170
+ as the required adapter interface. Existing version-1 manifests remain readable.
171
+
172
+ Native and bundled WASM requests share this formatting behavior. CLI scaffolds,
173
+ generated sources, and tests preserve the same ownership rules in both modes.
174
+
175
+
176
+ Scoped List payload predicates use the schema-3 expression node
177
+ `{kind: "allElements", value: Expr, binder: Binder, predicate: Expr}`. The binder
178
+ is local to `predicate`; `value` is evaluated in the surrounding scope. The
179
+ predicate and result have type Bool. Visitors must handle this node alongside
180
+ `match`, including empty-list truth and short-circuit evaluation.
181
+
182
+ The Core also defines a scoped recursive payload operation:
183
+ `{kind: "allPayloads", value: Expr, predicates: PayloadPredicate[]}`, where each
184
+ `PayloadPredicate` contains a `binder: Binder` and `predicate: Expr`. Entries
185
+ correspond, in order, to the root data type's type arguments. Each binder has
186
+ that argument's type and is local only to its own predicate; sibling predicates
187
+ cannot refer to it. The scrutinee is evaluated in the surrounding scope, and
188
+ both each predicate and the whole operation have type Bool.
189
+
190
+ Traversal follows stored parameter occurrences through recursive declarations,
191
+ including nested containers and changing type arguments. It does not constrain
192
+ unrelated fixed fields that happen to have the same concrete type. Empty and
193
+ phantom occurrences are vacuously true; rejection short-circuits traversal.
194
+
195
+ Source named-payload refinements now elaborate to this discriminator, including
196
+ recursive applications. API consumers should handle it in checked Core views.
197
+ All eight Core emitters support this operation in definitions, properties and
198
+ constructor predicates.
199
+ The internal surface predicate node is type checked and lowered through
200
+ specialization and template proofs into this same Core operation. Internal
201
+ definition and constructor contracts support recursive payload proof facts. Constructor predicates are audited in order, and callback
202
+ matches/constructions participate in the constructor dependency-cycle check.
203
+ The TypeScript declarations now include both
204
+ `allElements` and `allPayloads`; exhaustive visitors should handle both.
package/GO.md ADDED
@@ -0,0 +1,144 @@
1
+ # Native Go data
2
+
3
+ LawSpec 0.9 generates native named Go types for parameterized products and sums.
4
+ The compiler consumes checked Core declarations, plans names across all units,
5
+ and emits sealed interfaces plus named variant structs, following Go+'s enum
6
+ lowering approach.
7
+
8
+ For example:
9
+
10
+ ```lawspec
11
+ unit example.trees
12
+
13
+ type Tree (a :: Type) is
14
+ Leaf value :: a
15
+ Branch children :: List (Tree a)
16
+ end
17
+
18
+ echo :: Tree Int8 -> Tree Int8
19
+
20
+ law `echo preserves the tree` is
21
+ definition is `for all` (x :: Tree Int8) . echo x = x end
22
+ end
23
+ ```
24
+
25
+ The adapter receives `Tree[int8]`. Its native variants are `TreeLeaf[int8]`,
26
+ with an exported `Value` field, and `TreeBranch[int8]`, with an exported
27
+ `Children []Tree[int8]` field. The interface's private marker method includes
28
+ the type parameters, so even a nullary or phantom variant retains its generic
29
+ identity. Go rejects a `TreeLeaf[bool]` where `Tree[int8]` is required.
30
+
31
+ A correct identity adapter is:
32
+
33
+ ```go
34
+ func Echo(value0 Tree[int8]) Tree[int8] {
35
+ return value0
36
+ }
37
+ ```
38
+
39
+ Adapters remain user-owned. Generated files belong to the same unit package;
40
+ custom Go layouts keep source and tests in a shared directory tree. Duplicate
41
+ type names across units receive qualified generated names. The compiler rejects
42
+ adapter names that collide with generated native declarations or runtime names.
43
+
44
+ ## Containers and presence
45
+
46
+ - `List a` uses `[]T`. Nil and empty slices represent the same empty list.
47
+ - `Maybe a` uses `LawSpecMaybe[T]`, constructed with `LawSpecNothing[T]()` or
48
+ `LawSpecJust(value)`. `Value()` returns the payload and its presence flag.
49
+ - `Either a b` uses `LawSpecEither[L, R]`, constructed with
50
+ `LawSpecLeft[L, R](value)` or `LawSpecRight[L, R](value)`. Its zero value is
51
+ invalid and checked conversion rejects it.
52
+ - `Nullable a` and `Optional a` use distinct generic support structs with
53
+ `Present` and `Value` fields. These tags preserve nested absence states.
54
+
55
+ Native scalar fields retain their domains: UInt64 uses `uint64`, arbitrary
56
+ integers use `*LawSpecBigInt`, rational values use `*LawSpecRational`, and raw
57
+ UTF-16 text uses `[]uint16`. Text uses a valid UTF-8 Go string; arbitrary bytes
58
+ use `[]byte`. Unit, Null, and Undefined have distinct named support types when
59
+ stored inside data. Native void adapter results continue to normalize to Unit.
60
+
61
+ ## Total definitions
62
+
63
+ Checked source definitions emit native methods on `LawSpecDefinitions` in the
64
+ unit's package:
65
+
66
+ ```lawspec
67
+ unit example.total
68
+
69
+ definition increment (x :: Int8) :: BigInt is x + 1 end
70
+ ```
71
+
72
+ ```go
73
+ symbols := map[string]*LawSpecSymbol{}
74
+ result := LawSpecDefinitions.Increment(symbols, 127) // big integer 128
75
+ ```
76
+
77
+ The method accepts `int8` and returns `*LawSpecBigInt`. Lists, products, sums, and
78
+ nested presence retain their native parameterized types. A dedicated method
79
+ namespace allows a definition named `architecture` to coexist with the native
80
+ `Architecture` data type. Ordinary adapter functions retain their existing names.
81
+
82
+ Reuse the Symbol context within one example. Checked codecs copy and validate
83
+ native arguments and results; failures panic with the resolved definition name.
84
+ Machine-sized native bindings check the architecture across the complete type,
85
+ including alternatives not selected by the current value. Logical evaluation
86
+ still follows the explicitly selected machine profile.
87
+
88
+ `lawspec_definitions.go` belongs in source directories and does not import Rapid.
89
+ It contains the unit's native entry points and checked logical bodies. Properties
90
+ call the bodies directly; definitions never become user-owned adapter stubs.
91
+ Definitions and properties share typed expression rendering, preserving lazy
92
+ branches, short-circuit guards, single evaluation of match inputs, exact
93
+ arithmetic, and structural equality.
94
+
95
+ The frontend checks structural termination and potentially failing operations.
96
+ Generic definitions specialize to concrete uses. Refined signatures become
97
+ checked contracts, and refinement predicates may call checked definitions.
98
+
99
+ `tools/go-definitions-integration.mjs` checks source-only packages, four rejected
100
+ native type mismatches, both profiles and architecture diagnostics, recursive
101
+ properties, incorrect adapters, custom layouts, compact execution, and
102
+ regeneration protection. Readable definition source matches `gofmt` exactly.
103
+ Compact Go documents retain tabs rather than expanding them into spaces.
104
+
105
+ ## Checked bridges and tests
106
+
107
+ Generated codecs validate both conversion directions and copy mutable payloads.
108
+ An adapter cannot mutate a list, byte slice, or big integer in a test fixture
109
+ through an input alias. Unexpected or nil native variants, invalid scalar
110
+ representations, and cyclic values fail with type/field context. Shared acyclic
111
+ subtrees remain valid. Native machine-sized fields require the selected
112
+ `machineBits` profile to match the Go architecture.
113
+
114
+ Generated equality follows LawSpec semantics, including componentwise floating
115
+ comparison and Symbol identity. It does not substitute Go pointer identity or
116
+ reflection-based equality for structural equality.
117
+
118
+ Rapid generation composes native generators and shrinkers. A structural node
119
+ budget bounds recursive values, reserves each product field's minimum cost,
120
+ and permits list lengths supported by the remaining budget. Empty domains,
121
+ nullary constructors, and nested absence states are handled explicitly.
122
+
123
+ The reusable source files (`lawspec_runtime.go`, `lawspec_schema.go`,
124
+ `lawspec_codecs.go`, and generated data/schema/codec declarations) do not import
125
+ Rapid. Framework-specific generation lives in
126
+ `lawspec_data_strategies_test.go`; generated laws live in `lawspec_test.go`.
127
+
128
+ Native declarations, schema descriptions, codecs, runtime support, and generated
129
+ tests use structured formatting that matches `gofmt`. The bundled examples and
130
+ total-definition fixture are checked against `gofmt` under both machine profiles.
131
+ No external formatter is needed when generating code.
132
+
133
+ The compiler and CLI accept explicit `--minify` for generated output.
134
+ Readable output remains the default; formatting changes preserve adapter ownership
135
+ and edited-file protection. The bundled WASM uses the same layout.
136
+
137
+ Internal typed Core definitions with attached contracts are proved before Go
138
+ emission. Generated logical entry points validate arguments, check preconditions
139
+ in order, validate the result, and check postconditions; native wrappers share
140
+ these checks. The standalone contract fixture exercises both machine profiles
141
+ and formatting modes, including exact division, checked narrowing, nested calls,
142
+ and rejection of deliberately corrupted results. Readable contract bodies match
143
+ `gofmt`. Refined source definition signatures now produce these contracts through
144
+ template proof and specialization.
package/HASKELL.md ADDED
@@ -0,0 +1,171 @@
1
+ # Native Haskell data
2
+
3
+ LawSpec 0.9 emits ordinary parameterized algebraic data types from checked Core
4
+ products and sums. Constructors and record selectors have stable names planned
5
+ across all units. For example:
6
+
7
+ ```lawspec
8
+ unit example.trees
9
+
10
+ type Tree (a :: Type) is
11
+ Leaf value :: a
12
+ Branch children :: List (Tree a)
13
+ end
14
+
15
+ echo :: Tree Int8 -> Tree Int8
16
+ ```
17
+
18
+ The generated `LawSpecData` module supplies `Tree a`, `TreeLeaf`, and
19
+ `TreeBranch`. An adapter can implement identity directly:
20
+
21
+ ```haskell
22
+ echo :: Data.Tree I.Int8 -> Data.Tree I.Int8
23
+ echo value = value
24
+ ```
25
+
26
+ The generated adapter imports `LawSpecData` as `Data` and `Data.Int` as `I`.
27
+ Adapters remain user-owned. Recursive and mutually recursive fields use native
28
+ Haskell recursion; phantom parameters remain in signatures. Empty data types
29
+ have no constructors. They can appear in inhabited containers such as
30
+ `Maybe Empty`, but cannot supply a standalone generated argument.
31
+
32
+ ## Containers and scalar representations
33
+
34
+ | LawSpec | Haskell |
35
+ | --- | --- |
36
+ | `List a` | `[a]` |
37
+ | `Text` | `Data.Text.Text` |
38
+ | `List Char` | `[Char]`, the linked-list representation |
39
+ | `Maybe a` | `Maybe a`, with `Nothing` and `Just` |
40
+ | `Either a b` | `Either a b`, with `Left` and `Right` |
41
+ | `Nullable a` | `LS.Nullable a`, with `NullValue` and `NullableValue` |
42
+ | `Optional a` | `LS.Optional a`, with `UndefinedValue` and `OptionalValue` |
43
+ | `BigInt`, `BigUInt`, `Integer` | `Integer`, with domain checks |
44
+ | `Decimal` | `LS.Decimal`, wrapping an exact finite base-ten `Rational` |
45
+ | `Rational` | `Rational` |
46
+ | `Complex64`, `Complex128` | `Complex Float`, `Complex Double` |
47
+ | `CodePoint` | `Char`, including surrogate code points |
48
+ | `CodeUnit16` | `Word16` |
49
+ | `CodePointText`, `Utf16Text` | `LS.CodePointText [Char]`, `LS.Utf16Text [Word16]` |
50
+ | `Bytes` | `ByteString` |
51
+ | `Symbol` | `LS.Symbol`, with scoped fixture identities |
52
+ | `Unit` | `()` |
53
+ | `Null`, `Undefined` | `LS.Null`, `LS.Undefined` |
54
+
55
+ `Char` and `Text` exclude surrogate code points. Checked codecs reject invalid
56
+ native values rather than replacing characters. `Symbol` equality uses its
57
+ identity; matching descriptions alone do not establish equality. Distinct
58
+ presence wrappers preserve nested absence states. IEEE NaN and signed-zero
59
+ equality remain the same inside containers and custom types.
60
+
61
+ ## Generated support and testing
62
+
63
+ `LawSpecData`, `LawSpecDataSchema`, `LawSpecDataCodecs`, `LawSpecSchema`,
64
+ `LawSpecCodecs`, and `LawSpecRuntime` belong in the source directory. They have no
65
+ property-framework dependency. Native conversion returns contextual failures for
66
+ invalid domains, fields, tags, or arities. Binding machine-sized native types
67
+ requires the selected `machineBits` profile to match the host, including fields
68
+ of unselected variants.
69
+
70
+ `LawSpecDataStrategies` belongs in the test directory and composes native Hedgehog
71
+ generators and shrinkers. Bounded recursive generation reserves every product
72
+ field's minimum size before distributing spare nodes. Lists have variable lengths
73
+ within the available budget. Shrinking uses Hedgehog's choices, integers, and
74
+ lists, retaining schema-valid representations.
75
+
76
+ The Haskell scaffold uses Hspec, Hedgehog, hspec-hedgehog, containers, and mtl in
77
+ its test component. Source and test roots can be customized independently.
78
+ Readable/compact declaration fixtures are covered by
79
+ `tools/haskell-data-integration.mjs`; main compiler output and incorrect adapters
80
+ are covered by `tools/haskell-data-properties.mjs`.
81
+
82
+ ## Formatting
83
+
84
+ Haskell output uses an 80-column layout with spaces for indentation. Runtime
85
+ sources, native declarations, adapter stubs, definitions, and property files are
86
+ readable by default. Explicit `--minify` selects compact documents while retaining
87
+ the layout required by Haskell. Generation uses the same deterministic document
88
+ renderer in native and WASM builds; it does not invoke a downloaded formatter.
89
+
90
+ `tools/haskell-formatting-integration.mjs` checks the bundled corpus at both
91
+ machine widths for line length, tabs, and trailing whitespace. It compares
92
+ readable and compact parsed syntax using `tools/HaskellSyntaxCheck.hs`, built
93
+ against the installed GHC parser. The comparison discards source locations and
94
+ layout annotations while retaining literals, operators, and program structure.
95
+ Set `LAWSPEC_CORE`, `LAWSPEC_GHC`, and `LAWSPEC_HASKELL_SYNTAX_CHECK` to the
96
+ corresponding executables. This is a development check, not a package dependency.
97
+
98
+ ## Total definitions
99
+
100
+ Checked definitions become native functions in `LawSpecDefinitions.<Unit>`:
101
+
102
+ ```lawspec
103
+ unit example.total
104
+
105
+ definition increment (x :: Int8) :: BigInt is x + 1 end
106
+ ```
107
+
108
+ The generated native signature is equivalent to:
109
+
110
+ ```haskell
111
+ increment :: LS.SymbolContext -> I.Int8 -> Either String Integer
112
+ ```
113
+
114
+ Create a context with `LS.newSymbolContext`, then pass it to calls belonging to
115
+ the same example. A repeated Symbol fixture ID has the same identity in that
116
+ context; separate contexts remain distinct even when IDs and descriptions match.
117
+ Codecs preserve the identity of already-scoped native Symbols. Creating the
118
+ context uses IO; evaluating a definition is pure.
119
+
120
+ Native entry points check arguments and results and return contextual `Left`
121
+ diagnostics for invalid native representations. Native machine-sized bindings
122
+ check the whole type, including unselected constructors, against `machineBits`.
123
+ `LawSpecDefinitionBodies` contains the shared logical implementation, which uses
124
+ the configured machine profile independently of the host architecture.
125
+
126
+ Definitions do not create adapter stubs. Their source modules and scalar/schema
127
+ support have no Hspec or Hedgehog dependency. Generated tests allocate a context
128
+ per example, boundary, or property iteration. Properties and definitions share a
129
+ typed expression renderer with lazy guards, exhaustive matching, structural
130
+ equality, checked conversions, and exact integer promotion.
131
+
132
+ `tools/haskell-definitions-integration.mjs` exercises native and property calls,
133
+ both machine profiles, readable/compact definitions, complete minified projects,
134
+ custom source/test roots,
135
+ native type errors, incorrect adapters, generic specialization, and regeneration
136
+ protection. Refined definition signatures are checked before emission and
137
+ enforced at native entry points.
138
+
139
+
140
+ Hspec property files now use structured documents for helpers, examples,
141
+ boundaries/finite cases, native Hedgehog strategies, dependent refinement domains,
142
+ guarded assertions and contract wrappers. Adapter bridges compose checked codecs
143
+ and force argument values before calling native code. Contracts retain lazy
144
+ precondition checks and force the result before checking postconditions. Fresh
145
+ Symbol contexts cover refined properties as well as ordinary native strategies.
146
+ Scalar literals and diagnostic strings now use document-level encoding. Long
147
+ strings concatenate independently escaped chunks; large integers parse exact
148
+ decimal strings with their required Integer type.
149
+
150
+ `tools/haskell-data-properties.mjs` accepts `LAWSPEC_MINIFY=1` and
151
+ `LAWSPEC_MACHINE_BITS=32,64`. Its scalar scenario includes bundled examples and
152
+ shared arithmetic conformance vectors; its refinements scenario includes four
153
+ faulty adapters. Native machine-sized adapter bindings require a matching host
154
+ architecture; the scalar scenario defaults to 64 bits.
155
+
156
+ `tools/haskell-message-integration.mjs` uses native code-point strings and integer
157
+ constants independent of the emitter to check Unicode, escapes, whitespace,
158
+ large signed integers and diagnostic prefixes in readable and compact modes.
159
+ Its executable fixture lines fit within 80 columns. Long metadata comments wrap
160
+ to the output width.
161
+
162
+ Internal typed Core definitions with attached contracts are proved before Haskell
163
+ emission. Generated source checks preconditions after argument validation and
164
+ postconditions after result validation, without property-framework dependencies.
165
+ Checks sequence through Either, so a rejected precondition prevents later
166
+ predicates and the body from running. Results are forced and validated before
167
+ postconditions. Readable contract fixtures fit within 80 columns.
168
+ The shared native fixture passes both machine profiles and formatting modes,
169
+ including exact division, narrowing, nested calls, direct logical entry checks,
170
+ and rejection of corrupted results. Refined source definition signatures now
171
+ produce these contracts through template proof and specialization.