lawspec 0.9.0 → 0.11.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 +78 -2
- package/HASKELL.md +1 -0
- package/KOTLIN.md +5 -0
- package/LANGUAGE.md +70 -11
- package/NATIVE-BINDINGS.md +1049 -0
- package/PRIMITIVES.md +1 -1
- package/README.md +86 -23
- package/REFINEMENTS.md +6 -1
- package/RELEASE-0.10.md +60 -0
- package/RELEASE-0.11.md +62 -0
- package/api.mjs +23 -3
- package/bin/lawspec.mjs +17 -4
- package/build.json +60 -38
- package/core.wasm +0 -0
- package/examples/native-payments/go/example/payments/domain.go +38 -0
- package/examples/native-payments/go/example/payments/native_generators_test.go +13 -0
- package/examples/native-payments/go/lawspec.json +136 -0
- package/examples/native-payments/haskell/lawspec.json +149 -0
- package/examples/native-payments/haskell/src/PaymentsDomain.hs +21 -0
- package/examples/native-payments/haskell/test/PaymentGenerators.hs +12 -0
- package/examples/native-payments/java/lawspec.json +165 -0
- package/examples/native-payments/java/src/main/java/domain/PaymentsDomain.java +32 -0
- package/examples/native-payments/java/src/test/java/domain/PaymentGenerators.java +16 -0
- package/examples/native-payments/javascript/lawspec.json +149 -0
- package/examples/native-payments/javascript/src/payments_domain.mjs +44 -0
- package/examples/native-payments/javascript/test/lawspec_generators.mjs +6 -0
- package/examples/native-payments/kotlin/lawspec.json +165 -0
- package/examples/native-payments/kotlin/src/main/kotlin/domain/PaymentsDomain.kt +17 -0
- package/examples/native-payments/kotlin/src/test/kotlin/domain/PaymentGenerators.kt +12 -0
- package/examples/native-payments/python/lawspec.json +149 -0
- package/examples/native-payments/python/src/payments_domain.py +60 -0
- package/examples/native-payments/python/tests/lawspec_generators.py +15 -0
- package/examples/native-payments/rust/lawspec.json +167 -0
- package/examples/native-payments/rust/src/domain.rs +37 -0
- package/examples/native-payments/rust/src/lib.rs +2 -0
- package/examples/native-payments/rust/tests/support/lawspec_generators.rs +11 -0
- package/examples/native-payments/typescript/lawspec.json +149 -0
- package/examples/native-payments/typescript/src/payments_domain.ts +42 -0
- package/examples/native-payments/typescript/test/lawspec_generators.ts +8 -0
- package/examples/specs/indexed_families.lawspec +59 -0
- package/examples/specs/payments.lawspec +76 -0
- package/examples-command.mjs +5 -0
- package/files.mjs +6 -6
- package/index.d.ts +53 -2
- package/native-examples.mjs +81 -0
- package/package.json +2 -2
|
@@ -0,0 +1,1049 @@
|
|
|
1
|
+
# Native domain bindings: 0.10 acceptance scope
|
|
2
|
+
|
|
3
|
+
Status: implementation and local acceptance complete; remote CI remains pending. The payment example now executes with
|
|
4
|
+
compiler-generated Rust bridges and application-library linkage. Rust supports
|
|
5
|
+
generic products/sums, regular recursive mappings, nested built-in containers,
|
|
6
|
+
and native Proptest factories that compose child strategies and retain shrinking.
|
|
7
|
+
Python now has checked application-class bridges with renamed fields, shared
|
|
8
|
+
schema validation and native Hypothesis factories. JavaScript and TypeScript
|
|
9
|
+
have application-class bridges and native fast-check factories.
|
|
10
|
+
Java now emits typed codecs for application records, sum variants and enum
|
|
11
|
+
constants, with native JetCheck factories. Kotlin has checked application-class
|
|
12
|
+
bridges and native Kotest factories. Go has checked application bridges and native Rapid factories in local or
|
|
13
|
+
explicitly imported packages. Haskell has application-owned types and native
|
|
14
|
+
Hedgehog factories. All eight targets now have custom codec-hook implementations. Full release acceptance remains incomplete. Unsupported
|
|
15
|
+
emission requests fail explicitly.
|
|
16
|
+
|
|
17
|
+
## Audit of 0.9
|
|
18
|
+
|
|
19
|
+
The checked-in compiler, generated API, and WASM fingerprints agree
|
|
20
|
+
(`node tools/build-integrity.mjs`). The audit inspected the following boundaries:
|
|
21
|
+
|
|
22
|
+
| Boundary | Existing machinery | Missing for 0.10 |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| Public request and CLI | Schema v3 requests pass sources, target, layout, machine profile, generation limits and formatting through `Api.hs` and `npm/bin/lawspec.mjs`. | Per-target external type and generator bindings, validation, public declarations and config forwarding. |
|
|
25
|
+
| Typed front end | Resolved declaration IDs, parameterized data declarations, constructor fields, contracts and total definitions. | Binding resolution against those identities; native names must not enter language inference or change equality. |
|
|
26
|
+
| Testing plan | `Testing.hs` plans finite domains, deterministic boundaries, examples and framework generation requirements. | Explicit generator selection while retaining independent examples and boundary coverage. |
|
|
27
|
+
| Rust | `RustData.hs` generates enums plus `IntoValue`/`FromValue`; `RustEmit.hs` checks schema values around adapter calls. | Application-owned struct/enum representations and framework strategy bindings. |
|
|
28
|
+
| Java | `JavaData.hs` generates domain types; `LawSpecSchema.java` exposes typed `Codec<T>` conversions with validation. | External constructors/accessors, native type selection and JetCheck generator selection. |
|
|
29
|
+
| Python | `PythonData.hs` generates dataclasses; `lawspec_schema.py` associates constructor metadata with native classes. | Explicit native imports and renamed fields/factories; Hypothesis strategy selection. |
|
|
30
|
+
| JavaScript/TypeScript | `WebData.hs` and `WebTypes.hs` generate classes and native signatures; `lawspec_schema.mjs` validates constructor identities and fields. | External classes/representations and fast-check arbitrary selection without losing shrinking. |
|
|
31
|
+
| Go | `GoData.hs` generates types and codecs; `lawspec_codecs.go` supplies typed checked conversions and contextual errors. | Application types, explicit field mappings and Rapid generator selection. |
|
|
32
|
+
| Haskell | `HaskellData.hs` generates ADTs; `LawSpecCodecs.hs` supplies compositional typed codecs. | Application modules/constructors/selectors and Hedgehog generator selection. |
|
|
33
|
+
| Kotlin | `KotlinData.hs` generates classes with checked schema bridges and native Kotest properties. | External classes/accessors and Kotest arbitrary selection. |
|
|
34
|
+
| File ownership | Source/test placement is separate from generated/user ownership; `npm/files.mjs` protects edited artifacts and reports adapter changes. | Apply these protections to binding support and generator stubs, including migration from existing adapters. |
|
|
35
|
+
|
|
36
|
+
The word “native” in 0.9 means target-language representations of LawSpec types.
|
|
37
|
+
It does not mean an application can configure its own pre-existing domain model.
|
|
38
|
+
Users can hand-write conversions in their adapters today, but the compiler does
|
|
39
|
+
not select or generate those conversions. Likewise, using native property
|
|
40
|
+
frameworks today does not provide a user-configurable generator binding.
|
|
41
|
+
|
|
42
|
+
The Rust test emitter currently includes generated source/runtime modules by
|
|
43
|
+
path. External-library bindings must use the application library's type identity
|
|
44
|
+
in tests; compiling a second copy of a runtime-backed `Decimal` creates a
|
|
45
|
+
different Rust type. The manual baseline recompiles the domain alongside the
|
|
46
|
+
fixture and therefore does not yet prove external-library linkage.
|
|
47
|
+
|
|
48
|
+
The first implementation component, `LawSpec.NativeBinding`, resolves structured
|
|
49
|
+
native references and complete constructor/field mappings against Core. It
|
|
50
|
+
normalizes fields to declaration order and resolves generic generator arities.
|
|
51
|
+
`NativeBindingSpec` tests its validation. Public request parsing, CLI target
|
|
52
|
+
forwarding, generated TypeScript declarations and initial Rust emission are
|
|
53
|
+
implemented. Unknown binding fields are rejected. Binding requests require
|
|
54
|
+
schema version 4 so older schema-3 compilers reject them rather than ignoring
|
|
55
|
+
native representation choices. Existing requests without bindings retain
|
|
56
|
+
schema-3 compatibility.
|
|
57
|
+
|
|
58
|
+
## Acceptance domain
|
|
59
|
+
|
|
60
|
+
[`payments.lawspec`](examples/specs/payments.lawspec) defines `Currency`, `Money`
|
|
61
|
+
and `Payment`, with adapters for fee calculation, payment round trips and archives
|
|
62
|
+
of optional payments. It fixes the following observable behavior:
|
|
63
|
+
|
|
64
|
+
- Adding a fee of exactly 0.2 preserves currency and arbitrary decimal precision.
|
|
65
|
+
- Successful and declined payments retain their variant and payload.
|
|
66
|
+
- Archives retain order, duplicates, empty lists and the difference between a
|
|
67
|
+
missing payment and a present declined payment.
|
|
68
|
+
|
|
69
|
+
The application model deliberately uses different names:
|
|
70
|
+
|
|
71
|
+
| LawSpec | Application model |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `Currency.USD`, `.EUR`, `.GBP` | `CurrencyCode.Dollars`, `.Euros`, `.Pounds` |
|
|
74
|
+
| `Money` / constructor `Money` | `Price` product |
|
|
75
|
+
| `amount`, `currency` | `major`, `unit` |
|
|
76
|
+
| `Payment.Paid.value` | `PaymentStatus.Settled.price` |
|
|
77
|
+
| `Payment.Declined.reason` | `PaymentStatus.Rejected.explanation` |
|
|
78
|
+
| `addFee`, `roundTrip`, `archive` | `apply_fee`, `restore`, `store` |
|
|
79
|
+
|
|
80
|
+
The Rust application fixture is
|
|
81
|
+
[`domain.rs`](test/fixtures/native-payments/domain.rs). It does not import the
|
|
82
|
+
generated domain types. It uses LawSpec's framework-independent exact Decimal
|
|
83
|
+
runtime. Its hand-written adapter records the conversion work 0.10 must remove;
|
|
84
|
+
merely bundling that adapter does not satisfy native binding support.
|
|
85
|
+
|
|
86
|
+
Run the baseline with:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
node tools/native-payments-integration.mjs
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
This checks/generates the model through the packaged WASM on all eight targets,
|
|
93
|
+
executes generated Rust properties/examples/boundaries against application types,
|
|
94
|
+
and confirms three deliberately broken applications fail laws rather than fail
|
|
95
|
+
compilation. The three mutations change the fee, erase currency and erase missing
|
|
96
|
+
payments. Logs and generated projects are in `.artifacts/native-payments/`.
|
|
97
|
+
Generation on a target is not evidence of execution on that target.
|
|
98
|
+
|
|
99
|
+
## Current generated Rust path
|
|
100
|
+
|
|
101
|
+
`test/fixtures/native-payments/bindings.json` is the concrete configuration.
|
|
102
|
+
Pass it as `nativeBindings` in a schema-4 `planGeneration` request, or set
|
|
103
|
+
`nativeBindings` on a Rust target in `lawspec.json`. The JavaScript API selects
|
|
104
|
+
schema 4 automatically when that option is supplied. `check` validates binding
|
|
105
|
+
identities; `planGeneration` additionally checks target support.
|
|
106
|
+
|
|
107
|
+
Native references are arrays of identifier components, never code snippets.
|
|
108
|
+
`types` maps qualified type identities, all their constructors and all fields.
|
|
109
|
+
`functions` maps qualified adapter identities to application functions.
|
|
110
|
+
`rustCrate` names the application library for test linkage. A bound unit must
|
|
111
|
+
currently map every adapter; its generated bridge is compiler-owned. Existing
|
|
112
|
+
user adapters are protected by the ownership manifest and cannot be overwritten
|
|
113
|
+
silently when adopting bindings.
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/native-bound-payments.mjs
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Unlike the manual baseline, this generates every conversion from configuration,
|
|
120
|
+
links generated tests to the application library's runtime/data/adapter modules,
|
|
121
|
+
and executes both 32-bit and 64-bit semantic profiles, including a custom layout.
|
|
122
|
+
Total-definition bodies are compiled in the test crate against those shared
|
|
123
|
+
runtime types because their evaluators are crate-private. The three negative
|
|
124
|
+
adapters must fail executable laws. Output is in `.artifacts/native-bound-payments/`.
|
|
125
|
+
Generator-only native machine-sized boundaries are additionally checked by
|
|
126
|
+
`tools/rust-native-shapes.mjs`: the host-width profile passes and the other
|
|
127
|
+
profile fails contextually with an architecture mismatch.
|
|
128
|
+
|
|
129
|
+
### Rust custom generators
|
|
130
|
+
|
|
131
|
+
Add a generator binding such as:
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
{"type":"example.payments::type::Money","factory":["lawspec_generators","prices"]}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The application supplies `prices()` in `<testDir>/support/lawspec_generators.rs`,
|
|
138
|
+
returning a Proptest strategy whose values have the mapped application type.
|
|
139
|
+
Factories for parameterized types receive one boxed native strategy per type
|
|
140
|
+
argument. Generated conversions map these strategies directly, preserving their
|
|
141
|
+
value trees and shrinkers. Native samples and shrinks must satisfy the schema;
|
|
142
|
+
invalid values fail contextually. Exhausted custom strategies cannot fall back
|
|
143
|
+
to deterministic witnesses. Explicit examples, boundaries and finite-domain
|
|
144
|
+
enumeration still run independently of the custom distribution.
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core LAWSPEC_NATIVE_GENERATORS=1 node tools/native-bound-payments.mjs
|
|
148
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core LAWSPEC_NATIVE_GENERATORS=1 node tools/rust-native-shapes.mjs
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The payment strategy deliberately omits several explicit examples and shrinks
|
|
152
|
+
to EUR 1. The shapes fixture checks generic child shrinking, recursive mappings,
|
|
153
|
+
empty records, refined quantifiers and finite singleton enumeration in readable
|
|
154
|
+
and compact output. Direct mappings currently require recursive indirection
|
|
155
|
+
compatible with the generated representation; alternate storage and phantom
|
|
156
|
+
representations still need codec-hook support.
|
|
157
|
+
|
|
158
|
+
## Custom codec hooks
|
|
159
|
+
|
|
160
|
+
A named type can select a pair of conversion hooks instead of constructor/field
|
|
161
|
+
mappings. Hooks are structured function references, not embedded source code:
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"type": "native.codecs::type::Parcel",
|
|
166
|
+
"native": ["crate", "domain", "Parcel"],
|
|
167
|
+
"codec": {
|
|
168
|
+
"toNative": ["crate", "codecs", "to_parcel"],
|
|
169
|
+
"fromNative": ["crate", "codecs", "from_parcel"]
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Both directions are required. Supplying constructor mappings as well is an error.
|
|
175
|
+
The canonical side uses generated LawSpec data types; the native side uses the
|
|
176
|
+
application type. For each type parameter, the hook receives a child conversion
|
|
177
|
+
function in that direction. Rust hooks return `lawspec_runtime::Result<T>`.
|
|
178
|
+
For example, `to_parcel<T, N>` takes a canonical `Parcel<T>` and `&dyn Fn(T) -> N`,
|
|
179
|
+
and returns `Result<domain::Parcel<N>>`. The reverse receives the native value
|
|
180
|
+
and `&dyn Fn(N) -> T`. Returned errors include the type identity and direction.
|
|
181
|
+
|
|
182
|
+
Hooks are application-owned source functions with no testing dependency. Schema
|
|
183
|
+
validation still surrounds adapter calls and native generator values; hooks cannot
|
|
184
|
+
remove range checks or constructor contracts. The compiler continues to select
|
|
185
|
+
native generators independently, preserving their shrink trees through conversions.
|
|
186
|
+
|
|
187
|
+
`test/fixtures/native-codecs` demonstrates a private-field generic product and a
|
|
188
|
+
recursive chain represented by a flat vector plus an explicit termination flag.
|
|
189
|
+
It preserves the distinction between an absent tail and a tail containing Stop.
|
|
190
|
+
Both profiles and output formats are compiled and executed with native/WASM
|
|
191
|
+
parity. Tests verify generic Proptest shrinking through the hooks, contextual
|
|
192
|
+
errors from either direction, and rejection of invalid codec results and native
|
|
193
|
+
generator samples. The source library is checked separately from test code.
|
|
194
|
+
|
|
195
|
+
```sh
|
|
196
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/rust-native-codecs.mjs
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Haskell hooks return `Either String value`. A generic hook has the shape:
|
|
200
|
+
|
|
201
|
+
```haskell
|
|
202
|
+
toParcel :: Data.Parcel a -> (a -> b) -> Either String (Domain.Parcel b)
|
|
203
|
+
fromParcel :: Domain.Parcel b -> (b -> a) -> Either String (Data.Parcel a)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
The generated bridge keeps logical type-parameter payloads opaque and supplies
|
|
207
|
+
checked child converters. Hooks must use those converters to cross between the
|
|
208
|
+
logical payload and the application's native payload. The enclosing codec retains
|
|
209
|
+
schema validation and the example's Symbol context. Hook errors identify the type
|
|
210
|
+
and conversion direction.
|
|
211
|
+
|
|
212
|
+
`bindings-haskell.json` and the Haskell modules in `test/fixtures/native-codecs`
|
|
213
|
+
exercise private products, a flattened recursive representation, nested generic
|
|
214
|
+
payloads and refined fields. The integration checks source compilation with test
|
|
215
|
+
packages hidden, both machine profiles, both output formats, custom layouts and
|
|
216
|
+
native/WASM parity. A failing generic property retains Hedgehog shrinking to a
|
|
217
|
+
payload of 61. Invalid hook results and native generator samples fail contextually.
|
|
218
|
+
|
|
219
|
+
```sh
|
|
220
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core LAWSPEC_GHC=/absolute/path/to/ghc node tools/haskell-native-codecs.mjs
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Python hooks return the converted value and raise an exception on failure. For
|
|
224
|
+
example, `to_parcel(value, convert_item)` receives a generated canonical
|
|
225
|
+
`ParcelParcel` and returns the application's `Parcel`; `from_parcel` reverses
|
|
226
|
+
that conversion. Generic hooks use each directional child converter when moving
|
|
227
|
+
payloads between canonical and native representations. Unlike Haskell's opaque
|
|
228
|
+
payload bridge, Python supplies canonical native payloads to these converters.
|
|
229
|
+
|
|
230
|
+
The Python bridge checks the declared native class, validates canonical results,
|
|
231
|
+
and wraps hook exceptions with the type identity and direction. Hooks compose
|
|
232
|
+
with direct field mappings, preserve the shared Symbol context and do not import
|
|
233
|
+
Hypothesis. The `codec_domain.py`, `codec_hooks.py` and `codec_generators.py`
|
|
234
|
+
fixtures exercise private storage, flattened recursion and nested generic values.
|
|
235
|
+
The integration checks source execution with site packages disabled, native/WASM
|
|
236
|
+
parity, all profile/format combinations, custom layouts and Hypothesis shrinking
|
|
237
|
+
to 61. Faulty hooks, invalid generator samples and collapsed chain endings fail
|
|
238
|
+
executable tests.
|
|
239
|
+
|
|
240
|
+
```sh
|
|
241
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/python-native-codecs.mjs
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
JavaScript and TypeScript use the same canonical-value and child-converter
|
|
245
|
+
interface as Python. Hooks return values or throw exceptions. The bridge checks
|
|
246
|
+
the declared application class, validates canonical results, and attaches type
|
|
247
|
+
identity and direction to errors while retaining the original cause. Hook tables
|
|
248
|
+
are copied when binding a schema, so later configuration mutations cannot change
|
|
249
|
+
its conversions.
|
|
250
|
+
|
|
251
|
+
The TypeScript fixtures use ECMAScript private fields and typed generic hook
|
|
252
|
+
signatures. They also transpile to JavaScript for the same executable acceptance
|
|
253
|
+
cases. Source code compiles independently of testing types. Both web targets
|
|
254
|
+
execute the private product, flattened chain and refined Positive examples under
|
|
255
|
+
both profiles, formats and custom layouts, with native/WASM parity. fast-check
|
|
256
|
+
retains child shrinking to 61. Tests reject failures in either hook direction,
|
|
257
|
+
invalid canonical results, invalid native generator values and collapsed endings.
|
|
258
|
+
|
|
259
|
+
```sh
|
|
260
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/web-native-codecs.mjs
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Java hooks use typed `java.util.function.Function` child converters. For example,
|
|
264
|
+
`to_parcel(Parcel<A> value, Function<A, B> convert)` returns an application-owned
|
|
265
|
+
`CodecDomain.Parcel<B>`. The generated bridge instantiates canonical generic
|
|
266
|
+
payloads as checked `LawSpecRuntime.Value` values, supplies the native child codec
|
|
267
|
+
methods, and validates the result against the schema. Hooks throw exceptions on
|
|
268
|
+
failure; the bridge adds the type identity and conversion direction while retaining
|
|
269
|
+
the cause. No testing library is needed by the hooks or generated source codecs.
|
|
270
|
+
|
|
271
|
+
The Java fixtures use private fields and a flattened recursive representation.
|
|
272
|
+
The integration compiles source independently, executes nested codec conversions,
|
|
273
|
+
and checks both profiles, formats and custom layouts with native/WASM parity.
|
|
274
|
+
The emitted JetCheck factory demonstrably shrinks generic payloads and matches
|
|
275
|
+
an independent run of the application generator (98 to 49 for the chosen predicate
|
|
276
|
+
and seed). JetCheck does not guarantee the smallest mathematical counterexample.
|
|
277
|
+
Incorrect hooks, invalid refined outputs, invalid generator samples and collapsed
|
|
278
|
+
chain endings fail executable properties/examples after successful compilation.
|
|
279
|
+
|
|
280
|
+
```sh
|
|
281
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/java-native-codecs.mjs
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Kotlin hooks follow the same opaque canonical-payload convention as Java, using
|
|
285
|
+
ordinary Kotlin function parameters. For example,
|
|
286
|
+
`to_parcel(value: Parcel<A>, convert: (A) -> B): CodecDomain.Parcel<B>` returns the
|
|
287
|
+
application type. The reverse hook receives `(B) -> A`. Both directions retain
|
|
288
|
+
schema validation, Symbol context, generic child codecs and contextual exceptions.
|
|
289
|
+
The conversion source compiles and executes without Kotest dependencies.
|
|
290
|
+
|
|
291
|
+
Kotlin's private-storage product, flattened chain, refined value and native
|
|
292
|
+
factories execute under both profiles, formats and custom layouts, with native/WASM
|
|
293
|
+
parity. The emitted generic Kotest factory retains its shrink tree (66 to 1 in the
|
|
294
|
+
fixture). Incorrect hooks, collapsed endings, invalid results and invalid native
|
|
295
|
+
samples compile before failing tests.
|
|
296
|
+
|
|
297
|
+
```sh
|
|
298
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/kotlin-native-codecs.mjs
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Go hooks return `(value, error)`, with generic converters represented by ordinary
|
|
302
|
+
function parameters. The canonical type parameters carry checked `LawSpecValue`
|
|
303
|
+
payloads. The bridge preserves the active Symbol context and encoder traversal
|
|
304
|
+
path when invoking child conversions, and wraps returned errors or panics with the
|
|
305
|
+
type identity and direction. Framework-independent source compiles with `go build`.
|
|
306
|
+
|
|
307
|
+
The Go fixture defines hooks in the generated canonical type's package. This lets
|
|
308
|
+
hooks name canonical variants without creating an import cycle. Its application
|
|
309
|
+
model uses private pointer-backed product storage and a flat slice representation
|
|
310
|
+
of the recursive chain. Both profiles, formats and custom layouts execute with
|
|
311
|
+
native/WASM parity. An intentionally failing property proves that the emitted
|
|
312
|
+
Rapid factory still shrinks its payload to 61. Faulty conversions, collapsed
|
|
313
|
+
endings and invalid refined results/generator values fail executable tests.
|
|
314
|
+
|
|
315
|
+
```sh
|
|
316
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/go-native-codecs.mjs
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
The imported-model fixture in `test/fixtures/native-go-codecs` additionally places
|
|
320
|
+
the private application model and Rapid factories in separate packages. Local hooks
|
|
321
|
+
call the model's public constructors and accessors, so the application package has
|
|
322
|
+
no dependency on generated types. Generated codecs import only the application
|
|
323
|
+
model; factories remain a test dependency. This path compiles source independently
|
|
324
|
+
and executes the same profile/format/layout, shrinking and negative-test matrix.
|
|
325
|
+
|
|
326
|
+
```sh
|
|
327
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/go-imported-codecs.mjs
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
All eight targets now implement codec hooks. Hooks that name generated canonical
|
|
331
|
+
types belong beside those types: placing them in a package that imports the
|
|
332
|
+
canonical package while the generated bridge imports that hook package would
|
|
333
|
+
create an ordinary Go import cycle.
|
|
334
|
+
|
|
335
|
+
## Implementation contract
|
|
336
|
+
|
|
337
|
+
### Current Python path
|
|
338
|
+
|
|
339
|
+
`test/fixtures/native-payments/bindings-python.json` maps the same payment domain
|
|
340
|
+
to application classes in `domain.py`. Python native references contain module
|
|
341
|
+
components followed by an exported class or function name. A bound unit must
|
|
342
|
+
map every adapter. Classes are checked by exact constructor identity; fields
|
|
343
|
+
are read by mapped attribute name and constructed with keyword arguments, so
|
|
344
|
+
keyword-only dataclasses and reordered fields work. Generic and recursive schema
|
|
345
|
+
traversal retains constructor predicates and canonical diagnostic field names.
|
|
346
|
+
|
|
347
|
+
`lawspec_native.py` and bound adapters are generated source files. Runtime schema
|
|
348
|
+
rebinding is independent of Hypothesis. Native function failures and invalid
|
|
349
|
+
results receive adapter context. Python integers have no architecture-sized
|
|
350
|
+
representation, so the semantic machine-width profile is enforced by validation.
|
|
351
|
+
|
|
352
|
+
```sh
|
|
353
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/python-native-payments.mjs
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
This fixture covers both semantic profiles, both layouts, custom source/test
|
|
357
|
+
directories, keyword-only fields, and incorrect fee/currency/absence adapters.
|
|
358
|
+
Schema tests cover recursive generic mappings, Symbol identity, invalid mappings
|
|
359
|
+
and retained constructor predicates.
|
|
360
|
+
|
|
361
|
+
Python generator bindings reference factories in importable test modules. Each
|
|
362
|
+
factory receives one native Hypothesis strategy per type parameter and returns
|
|
363
|
+
a strategy producing the application representation. The generated test helper
|
|
364
|
+
maps native values through the checked schema, retaining Hypothesis shrinking.
|
|
365
|
+
Invalid samples and shrinks fail contextually instead of being filtered. An
|
|
366
|
+
exhausted custom strategy cannot fall back to a deterministic witness.
|
|
367
|
+
|
|
368
|
+
```sh
|
|
369
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core LAWSPEC_NATIVE_GENERATORS=1 node tools/python-native-payments.mjs
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
This mode checks the emitted Money factory's shrinking, a refined scalar's use
|
|
373
|
+
of its custom factory, and exhaustive Unit enumeration without factory sampling.
|
|
374
|
+
Runtime checks cover generic child strategies and nested custom scalars. Factory
|
|
375
|
+
modules remain application-owned. Their regeneration protection is covered by the
|
|
376
|
+
all-target ownership matrix below. Optional Python generator stubs are described
|
|
377
|
+
below; all eight targets support scaffolds.
|
|
378
|
+
|
|
379
|
+
### Current JavaScript and TypeScript path
|
|
380
|
+
|
|
381
|
+
`bindings-web.json` maps the payment model to the application classes in
|
|
382
|
+
`domain.ts`. References use module path segments followed by an exported name;
|
|
383
|
+
source references resolve from the source root, and generator references from
|
|
384
|
+
the test root. The emitter selects `.mjs` for JavaScript and `.js` imports for
|
|
385
|
+
TypeScript. Payload classes receive one object whose keys are mapped native
|
|
386
|
+
field names; unit classes receive no arguments. Classes must expose mapped
|
|
387
|
+
fields as own properties. Alternate constructor conventions need codec hooks.
|
|
388
|
+
|
|
389
|
+
Generated bridges retain canonical typed adapter signatures and convert through
|
|
390
|
+
an application schema. Generic and recursive traversal preserves class identity,
|
|
391
|
+
Symbol identity, constructor predicates, and tagged absence states. The emitted
|
|
392
|
+
native-generator helper composes fast-check arbitraries, maps their values through
|
|
393
|
+
checked conversions, and keeps their shrink contexts. Invalid samples/shrinks
|
|
394
|
+
fail contextually; exhausted custom generators cannot use witness fallback.
|
|
395
|
+
|
|
396
|
+
```sh
|
|
397
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core LAWSPEC_NATIVE_GENERATORS=1 node tools/web-native-payments.mjs
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
The integration compiles TypeScript, executes both targets in readable/compact
|
|
401
|
+
mode at both machine profiles with custom layouts, and rejects incorrect fee,
|
|
402
|
+
currency and absence handling. Runtime checks also exercise generic native child
|
|
403
|
+
arbitraries and deliberately invalid shrink values. Full release acceptance,
|
|
404
|
+
including broader generator/refinement coverage, remains pending.
|
|
405
|
+
|
|
406
|
+
### Current Java path
|
|
407
|
+
|
|
408
|
+
`bindings-java.json` maps the payment types to records, sealed variants and enum
|
|
409
|
+
constants nested in the application-owned `PaymentsDomain` class. Java references
|
|
410
|
+
are fully qualified type, constructor or static method names. Mapped payload
|
|
411
|
+
fields use accessor methods; constructors receive fields in LawSpec declaration
|
|
412
|
+
order. `unit` mappings refer to enum constants. An empty application record uses
|
|
413
|
+
`record` or `variant` style instead. Alternate conventions need codec hooks.
|
|
414
|
+
|
|
415
|
+
`LawSpecNativeCodecs` composes typed codecs over the shared schema. Application
|
|
416
|
+
types stay separate from generated canonical declarations, while validation,
|
|
417
|
+
constructor predicates and Symbol contexts are shared. Generic recursive codecs
|
|
418
|
+
are constructed lazily during traversal. Bound units map every adapter; generated
|
|
419
|
+
bridges are source-owned and retain canonical typed signatures.
|
|
420
|
+
|
|
421
|
+
```sh
|
|
422
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/java-native-payments.mjs
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
The fixture executes the payment laws and recursive generic shape laws under
|
|
426
|
+
both profiles and formatting modes, with custom directories and three incorrect
|
|
427
|
+
payment adapters. Native generator factories can be selected with `generators`
|
|
428
|
+
entries referencing static methods. Generic factories receive a typed JetCheck
|
|
429
|
+
generator for each type argument; the compiler specializes reachable concrete
|
|
430
|
+
types and composes checked application codecs around those strategies.
|
|
431
|
+
|
|
432
|
+
The JetCheck runtime now provides native factory hooks and checked strategy
|
|
433
|
+
mapping. `tools/java-native-generator-runtime.mjs` checks generic child
|
|
434
|
+
composition, actual shrinking, invalid sample/shrink replay failures, exhaustion
|
|
435
|
+
without witness fallback, and the existing constructor-contract behavior at both
|
|
436
|
+
machine profiles. The generated path is exercised with:
|
|
437
|
+
|
|
438
|
+
```sh
|
|
439
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core LAWSPEC_NATIVE_GENERATORS=1 node tools/java-native-payments.mjs
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
This adds Money and generic Box factories, a refined Int8 factory and a finite
|
|
443
|
+
Seal factory that fails if sampled. The tests check emitted Money shrinking,
|
|
444
|
+
refined-input factory use and finite enumeration. Native conversion failures
|
|
445
|
+
are carried through composed draws to property callbacks, including during
|
|
446
|
+
shrink replay. Runtime control exceptions remain under JetCheck's control.
|
|
447
|
+
Generator source is application-owned and stays in test directories; generated
|
|
448
|
+
source codecs do not depend on JetCheck. Formatting and wider release acceptance
|
|
449
|
+
remain pending.
|
|
450
|
+
|
|
451
|
+
### Current Kotlin path
|
|
452
|
+
|
|
453
|
+
`bindings-kotlin.json` maps the payment model to application-owned Kotlin classes
|
|
454
|
+
in `PaymentsDomain.kt`. Payload mappings read properties and call constructors
|
|
455
|
+
in LawSpec field order. Unit mappings reference enum constants or singleton
|
|
456
|
+
objects and compare identity. Payload constructors are checked by exact runtime
|
|
457
|
+
class. Generic and recursive codecs compose through the same shared schema used
|
|
458
|
+
by canonical Kotlin data, retaining contracts and logical diagnostic field names.
|
|
459
|
+
|
|
460
|
+
`LawSpecNativeCodecs.kt` and bound canonical adapters are generated source files;
|
|
461
|
+
neither requires Kotest. A bound unit currently maps every adapter. Alternate
|
|
462
|
+
construction conventions still need codec hooks.
|
|
463
|
+
|
|
464
|
+
Kotlin generator bindings select application-owned factory functions returning
|
|
465
|
+
Kotest `Arb` values. Generic factories receive one typed native arbitrary per type
|
|
466
|
+
argument. Generated helpers compose checked codecs around those arbitraries,
|
|
467
|
+
retaining their shrink trees. Invalid samples and shrink candidates reach the
|
|
468
|
+
property callback as contextual failures; custom strategies cannot fall back to
|
|
469
|
+
witnesses when exhausted. Refinements filter the configured distribution while
|
|
470
|
+
explicit examples, boundaries and finite-domain enumeration remain independent.
|
|
471
|
+
|
|
472
|
+
```sh
|
|
473
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core LAWSPEC_NATIVE_GENERATORS=1 node tools/kotlin-native-payments.mjs
|
|
474
|
+
node tools/kotlin-native-generator-runtime.mjs
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
The generated checks exercise generic factories, Money shrinking, refined scalar
|
|
478
|
+
factory use, finite singleton enumeration without invoking its factory, and an
|
|
479
|
+
invalid Text factory whose surrogate value must fail in the generated property.
|
|
480
|
+
Runtime checks additionally exercise invalid native shrink candidates reaching
|
|
481
|
+
Kotest callbacks and exhausted custom strategies with available witnesses.
|
|
482
|
+
|
|
483
|
+
```sh
|
|
484
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/kotlin-native-payments.mjs
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
The integration executes payment and recursive generic shape laws, examples and
|
|
488
|
+
boundaries under both machine profiles and formatting modes, including custom
|
|
489
|
+
source/test directories. It compares native/WASM emission and checks that
|
|
490
|
+
incorrect fee, currency and absence adapters fail executable laws.
|
|
491
|
+
`tools/kotlin-native-source.mjs` additionally compiles only generated source,
|
|
492
|
+
application types and codec checks without Kotest dependencies. It executes exact
|
|
493
|
+
decimal, raw code-point/UTF-16/byte, Symbol identity, nested absence and unmapped
|
|
494
|
+
variant checks under both machine profiles.
|
|
495
|
+
|
|
496
|
+
### Current Go path
|
|
497
|
+
|
|
498
|
+
`bindings-go.json` maps the payment and recursive shape domains to application
|
|
499
|
+
structs, interfaces and enum constants in their existing generated-test packages.
|
|
500
|
+
References contain either one package-local identifier or a declared import alias
|
|
501
|
+
and an exported identifier. Payload fields use
|
|
502
|
+
explicit native names and keyed struct construction; unit mappings name enum
|
|
503
|
+
constants. Application functions can retain names such as `AddFee`: checked Core
|
|
504
|
+
calls are lowered to separate generated bridge names, including contract calls.
|
|
505
|
+
|
|
506
|
+
`lawspec_native_codecs.go` contains framework-independent checked conversions.
|
|
507
|
+
Only reachable native codecs are emitted per package. The bridge preserves exact
|
|
508
|
+
scalar values, generic child codecs, recursion and schema field diagnostics.
|
|
509
|
+
Application symbols are reserved before Go emission. If a canonical type or variant
|
|
510
|
+
would collide, the compiler gives that generated family a fresh `Canonical`-prefixed
|
|
511
|
+
name. Existing names are considered too: an application `Box` and an existing
|
|
512
|
+
canonical `CanonicalBox` produce `Canonical1Box` for the conflicting generated
|
|
513
|
+
family. Qualified logical identities, schema values and propositions remain
|
|
514
|
+
unchanged. Codec hooks support alternate pointer/storage conventions.
|
|
515
|
+
|
|
516
|
+
```sh
|
|
517
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/go-native-payments.mjs
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
The integration builds source packages and executes laws/examples/boundaries for
|
|
521
|
+
payments, recursive generic shapes and scalar/absence adapters under both machine
|
|
522
|
+
profiles and output formats, with custom directories. It compares native/WASM output and checks Go formatting, raw UTF-16/bytes, Symbol
|
|
523
|
+
identity, invalid Text context, constructor contracts with a shared Symbol context,
|
|
524
|
+
and bound adapter postconditions. Three incorrect payment adapters must fail
|
|
525
|
+
executable laws.
|
|
526
|
+
|
|
527
|
+
Go generator bindings name package-local factories returning Rapid generators.
|
|
528
|
+
Generic factories receive a native generator per type argument. The generated
|
|
529
|
+
`lawspec_native_generators_test.go` composes these with checked codecs, preserving
|
|
530
|
+
Rapid's draw/replay stream and shrinking. Native validation failures use a distinct
|
|
531
|
+
panic type so they reach properties without swallowing Rapid's discard control.
|
|
532
|
+
Custom factories bypass witness fallback and constructor rejection; their invalid
|
|
533
|
+
values and shrink candidates are failures. Refinements still filter the custom
|
|
534
|
+
distribution, and finite domains are enumerated without invoking factories.
|
|
535
|
+
|
|
536
|
+
```sh
|
|
537
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core LAWSPEC_NATIVE_GENERATORS=1 node tools/go-native-payments.mjs
|
|
538
|
+
node tools/go-native-generator-runtime.mjs
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
These checks cover typed generic composition, emitted Money shrinking to 1.61,
|
|
542
|
+
refined scalar factory use, finite singleton handling, invalid Text samples and
|
|
543
|
+
exhausted refined distributions. Runtime tests also demonstrate invalid native
|
|
544
|
+
shrink candidates reaching property callbacks, invalid constructor contracts and
|
|
545
|
+
exhaustion despite an available witness. Factory files are application-owned test
|
|
546
|
+
code. Regeneration protection and optional Go generator stubs are covered below.
|
|
547
|
+
|
|
548
|
+
### Go external packages
|
|
549
|
+
|
|
550
|
+
Declare package paths separately from structured native references:
|
|
551
|
+
|
|
552
|
+
```json
|
|
553
|
+
{
|
|
554
|
+
"goImports": [{"alias": "domain", "path": "example.org/application/domain"}],
|
|
555
|
+
"functions": [{"declaration": "example::echo", "native": ["domain", "Echo"]}]
|
|
556
|
+
}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
The same alias can qualify native types, constructors and generator factories.
|
|
560
|
+
External names and mapped fields must be exported. Aliases are resolved to
|
|
561
|
+
compiler-owned import names, so configuration aliases such as `schema` and `rapid`
|
|
562
|
+
cannot shadow generated locals or framework imports. Each artifact imports only
|
|
563
|
+
its dependencies; an unused configured import does not create a package dependency.
|
|
564
|
+
Duplicate aliases/paths, traversal paths and undeclared aliases fail planning.
|
|
565
|
+
`goImports` is rejected for other targets.
|
|
566
|
+
|
|
567
|
+
`test/fixtures/native-go-external` supplies application-owned generic products,
|
|
568
|
+
recursive sums, enums and Rapid factories in separate Go packages. The fixture
|
|
569
|
+
executes checked bridges under both profiles and custom layouts, including a
|
|
570
|
+
UInt64 maximum example. Generated source builds independently of the generator
|
|
571
|
+
package, and a broken application must compile before failing its laws. A separate
|
|
572
|
+
failing property verifies that the imported generic factory retains native Rapid
|
|
573
|
+
shrinking down to a Box payload of 61. Native and WASM emission are compared.
|
|
574
|
+
|
|
575
|
+
```sh
|
|
576
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/go-native-external.mjs
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
Direct mappings require compatible field representations. Application packages
|
|
580
|
+
with their own wrappers or alternate recursive storage can use the codec hooks
|
|
581
|
+
described above. Canonical name reservation applies consistently to generated data,
|
|
582
|
+
codecs, adapter bridges, native factories, definitions and tests in both output
|
|
583
|
+
formats. Imported names do not occupy the local application namespace.
|
|
584
|
+
|
|
585
|
+
`test/fixtures/native-go-names` exercises colliding generic products and recursive
|
|
586
|
+
sums, an occupied canonical prefix, native generator selection and a broken adapter
|
|
587
|
+
that compiles before failing its laws. The hook fixture can also run with a native
|
|
588
|
+
`Parcel` name, verifying that user hooks and generated codecs agree on the renamed
|
|
589
|
+
canonical family.
|
|
590
|
+
|
|
591
|
+
```sh
|
|
592
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core node tools/go-native-names.mjs
|
|
593
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core LAWSPEC_GO_COLLISIONS=1 node tools/go-native-codecs.mjs
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### Current Haskell path
|
|
597
|
+
|
|
598
|
+
`bindings-haskell.json` maps the payment domain to application-owned types in
|
|
599
|
+
`PaymentsDomain.hs`. Generated codecs construct and match records by their mapped
|
|
600
|
+
field names, independently of native declaration order. Canonical adapter bridges
|
|
601
|
+
validate both directions and carry each example's Symbol context into codecs.
|
|
602
|
+
Unit-returning application calls are forced before encoding their result. Application
|
|
603
|
+
imports receive distinct aliases, including modules named `P`, `Data` or `Codec`;
|
|
604
|
+
references that shadow generated module files are rejected during planning.
|
|
605
|
+
|
|
606
|
+
```sh
|
|
607
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core LAWSPEC_GHC=/absolute/path/to/ghc node tools/haskell-native-payments.mjs
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
Set `LAWSPEC_GHC_PACKAGE_DB` when Hspec/Hedgehog live in a separate package database.
|
|
611
|
+
The integration executes payments under both machine profiles, readable and compact
|
|
612
|
+
output, and custom directories, with native/WASM emission parity. Bound adapter
|
|
613
|
+
postconditions are executed. Incorrect fee, currency and absence implementations,
|
|
614
|
+
and a throwing Unit adapter, must compile and then fail executable laws. The same matrix includes generic records, recursive sums, nested instances and
|
|
615
|
+
finite singleton types from `native_shapes.lawspec`.
|
|
616
|
+
|
|
617
|
+
Haskell factories return native Hedgehog `Gen` values and receive a native child
|
|
618
|
+
generator per type parameter. Generated codecs map those trees without replacing
|
|
619
|
+
their shrinking. Custom factories bypass witness fallback and constructor
|
|
620
|
+
rejection; invalid native values are contextual failures. Finite domains are
|
|
621
|
+
still enumerated without invoking their factories. Framework helpers remain in
|
|
622
|
+
test directories, and source compilation is checked with testing packages hidden.
|
|
623
|
+
|
|
624
|
+
```sh
|
|
625
|
+
LAWSPEC_CORE=/absolute/path/to/lawspec-core LAWSPEC_GHC=/absolute/path/to/ghc LAWSPEC_NATIVE_GENERATORS=1 node tools/haskell-native-payments.mjs
|
|
626
|
+
node tools/haskell-native-generator-runtime.mjs
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
The emitted factories retain Money shrinking to 1.61 and generic Box shrinking
|
|
630
|
+
to 13. Invalid Decimal samples fail emitted properties, and a custom Int8
|
|
631
|
+
distribution containing only zero exhausts the refined input instead of using a
|
|
632
|
+
witness. The runtime checks also cover invalid shrink candidates and empty factories.
|
|
633
|
+
Source-only execution additionally checks raw code points, UTF-16 units, bytes,
|
|
634
|
+
supplementary characters, nested absence states, scoped Symbol constructor contracts,
|
|
635
|
+
and native architecture mismatch diagnostics. Regeneration protection is covered below; generator stubs remain unfinished.
|
|
636
|
+
|
|
637
|
+
### Shared requirements
|
|
638
|
+
|
|
639
|
+
1. **Resolve bindings once.** Add per-target configuration/API bindings keyed by
|
|
640
|
+
qualified LawSpec declaration identity. Resolve and validate them against
|
|
641
|
+
typed Core before emission. Reject unknown types, constructors or fields,
|
|
642
|
+
duplicate/incomplete mappings, incompatible type arities, malformed target
|
|
643
|
+
references and unsupported representations with contextual diagnostics.
|
|
644
|
+
Ordinary specifications retain their meaning and default generated types.
|
|
645
|
+
2. **Generate checked native bridges.** Support application-owned products and
|
|
646
|
+
sums with explicit constructor/field mappings and callable codec hooks for
|
|
647
|
+
representations that cannot be expressed as direct mappings. Compose through
|
|
648
|
+
type parameters, recursion, `List`, `Maybe`, `Either`, `Nullable` and `Optional`.
|
|
649
|
+
Preserve exact values, Symbol identity, distinct absence states, constructor
|
|
650
|
+
contracts and both machine profiles. Validate adapter inputs and outputs;
|
|
651
|
+
invalid native values fail rather than becoming rejected generator samples.
|
|
652
|
+
3. **Connect native generators.** Bind factories returning the target framework's
|
|
653
|
+
generator/strategy/arbitrary. Compose and map those objects directly; do not
|
|
654
|
+
sample them into a separate random-value generator or replace their shrinkers.
|
|
655
|
+
Factories for parameterized types receive generators for their type arguments.
|
|
656
|
+
Validate generated values, including shrinks, through the same bridge. Retain
|
|
657
|
+
refinement predicates and their existing failure-versus-rejection distinction.
|
|
658
|
+
Custom random distributions never remove explicit examples, deterministic
|
|
659
|
+
boundaries or exhaustive finite-domain cases.
|
|
660
|
+
4. **Keep target details out of propositions.** Binding resolution produces a
|
|
661
|
+
backend binding plan alongside the existing typed testing plan. Arithmetic,
|
|
662
|
+
equality, total definitions and refinements continue to use checked Core
|
|
663
|
+
semantics. Schema/codec source remains independent of test frameworks.
|
|
664
|
+
5. **Preserve application ownership.** Import existing application code; never
|
|
665
|
+
rewrite it. Generate bridge source and framework-specific test helpers in
|
|
666
|
+
their respective directories. Keep optional implementation/generator stubs
|
|
667
|
+
user-owned. Support custom layouts, regeneration and adapter-update reporting.
|
|
668
|
+
6. **Ship one coherent interface.** Update the public API declarations and their
|
|
669
|
+
generator, CLI config validation, diagnostics, documentation and examples
|
|
670
|
+
together. Decide schema versioning from the actual wire changes; do not
|
|
671
|
+
silently accept and ignore requested binding configuration.
|
|
672
|
+
|
|
673
|
+
## Ownership, regeneration and migration
|
|
674
|
+
|
|
675
|
+
Generated bridges and numeric/schema runtimes belong in source directories.
|
|
676
|
+
Framework helpers belong in test directories (Go test files share their package's
|
|
677
|
+
source directory). Application models, conversion hooks and generator factories
|
|
678
|
+
remain application-owned. The ownership manifest records generated-file hashes;
|
|
679
|
+
it does not take ownership of existing application files.
|
|
680
|
+
|
|
681
|
+
When adopting bindings, an existing user-owned adapter at the new bridge's path
|
|
682
|
+
blocks generation, even if it still contains an untouched scaffold. Move the
|
|
683
|
+
implementation into the configured application module and save the old adapter
|
|
684
|
+
outside the generated bridge path before regenerating. Do not edit the manifest
|
|
685
|
+
to make application code appear compiler-owned. The compiler can then create its
|
|
686
|
+
bridge without overwriting the saved adapter.
|
|
687
|
+
|
|
688
|
+
Removing bindings preserves the former bridge when that path becomes a user-owned
|
|
689
|
+
adapter and reports the required adapter scaffold as an update. Review that update
|
|
690
|
+
and implement the ordinary adapter before running tests: obsolete generated
|
|
691
|
+
binding helpers can be removed during this migration. Source/test layout changes
|
|
692
|
+
relocate generated files; application code stays where it is until the user moves
|
|
693
|
+
it or adjusts project configuration.
|
|
694
|
+
|
|
695
|
+
The all-target filesystem matrix checks:
|
|
696
|
+
|
|
697
|
+
- Adoption blocks writes until the user adapter has been moved aside.
|
|
698
|
+
- Unchanged generation is a no-op, including after profile/format changes.
|
|
699
|
+
- Edits to generated files block replacement or removal during relocation.
|
|
700
|
+
- Edits detected between planning and applying abort before writes begin.
|
|
701
|
+
- Application generator files and saved adapters remain byte-for-byte intact.
|
|
702
|
+
- Removing bindings preserves adapter content and reports the required update.
|
|
703
|
+
- Custom source/test layouts retain artifact placement and ownership separately.
|
|
704
|
+
|
|
705
|
+
```sh
|
|
706
|
+
node --test npm/test/native-ownership.test.mjs
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
### Optional generator scaffolds
|
|
710
|
+
|
|
711
|
+
A generator binding may opt into a user-owned factory scaffold with `"stub": true`:
|
|
712
|
+
|
|
713
|
+
```json
|
|
714
|
+
{
|
|
715
|
+
"generators": [
|
|
716
|
+
{"type": "List", "factory": ["application_generators", "lists"], "stub": true}
|
|
717
|
+
]
|
|
718
|
+
}
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
All eight targets implement this option.
|
|
722
|
+
Omitting `stub` (or setting it to false) keeps the existing import-only behavior on every target.
|
|
723
|
+
|
|
724
|
+
For this Python example, generation creates `tests/application_generators.py`
|
|
725
|
+
(or the equivalent under a custom test directory). `lists(argument_0)` receives
|
|
726
|
+
its element Hypothesis strategy and must return a native `SearchStrategy`. The
|
|
727
|
+
initial body raises `NotImplementedError`; implement it using native strategy
|
|
728
|
+
composition to preserve shrinking. Multiple requested factories in the same module
|
|
729
|
+
share one file. Use a dedicated test module: names that conflict with generated
|
|
730
|
+
support, application binding modules, or another scaffold are rejected. A
|
|
731
|
+
scaffolded factory must belong to exactly one logical type.
|
|
732
|
+
|
|
733
|
+
Scaffolds remain readable and PEP 8 formatted in either output format. Existing
|
|
734
|
+
files are preserved, including edited implementations. Changes to the requested
|
|
735
|
+
type or type-parameter arity are reported through `adapterUpdates`; they never
|
|
736
|
+
replace the implementation. Changing the test layout leaves the old user-owned
|
|
737
|
+
file intact and creates a scaffold at the new path if absent. Move your actual
|
|
738
|
+
implementation to the new path before running its tests.
|
|
739
|
+
|
|
740
|
+
```sh
|
|
741
|
+
node --test npm/test/native-bindings.test.mjs
|
|
742
|
+
LAWSPEC_CORE="$PWD/.artifacts/native-binding-core" LAWSPEC_GENERATOR_STUBS=1 node tools/python-native-payments.mjs
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
The Python integration compiles and invokes the unimplemented factories, then
|
|
746
|
+
implements them with the application generators and runs the payment properties
|
|
747
|
+
in both machine profiles and output formats. Native/WASM plans must match.
|
|
748
|
+
Rust factories return `proptest::strategy::BoxedStrategy<NativeType>` and take one
|
|
749
|
+
boxed strategy for each type parameter. Type parameters carry `Debug + 'static`
|
|
750
|
+
bounds. A reference such as `["factories", "collections", "values"]` creates
|
|
751
|
+
`tests/support/factories.rs` with a public `collections` module and `values`
|
|
752
|
+
function; `crate` and `self` prefixes refer to that same integration-test module.
|
|
753
|
+
Factories sharing a root share one user-owned file. Test modules import this
|
|
754
|
+
support automatically. Explicit `crate`/`self` references keep importing the local
|
|
755
|
+
support module even with `stub: false`; the existing factory file is preserved.
|
|
756
|
+
For an unprefixed custom root, retain `stub: true` after implementation, or make
|
|
757
|
+
the local reference explicit before disabling scaffolding. The application crate named by `rustCrate` remains the
|
|
758
|
+
source of native types and the shared runtime. Scaffolds cannot use that crate
|
|
759
|
+
name, framework imports, or generated support names as their local root.
|
|
760
|
+
|
|
761
|
+
Rust scaffold bodies use `unimplemented!` until the user supplies a strategy.
|
|
762
|
+
Regeneration preserves the implementation, and changes to native return types or
|
|
763
|
+
parameter signatures appear in `adapterUpdates`. Generated scaffold files remain
|
|
764
|
+
readable in compact mode. Nested modules and raw Rust keyword identifiers are
|
|
765
|
+
supported; ambiguous factory/module paths and case-insensitive file collisions
|
|
766
|
+
are rejected. Existing external-crate factories remain import-only when `stub`
|
|
767
|
+
is omitted.
|
|
768
|
+
|
|
769
|
+
```sh
|
|
770
|
+
LAWSPEC_CORE="$PWD/.artifacts/native-binding-core" node tools/rust-generator-scaffolds.mjs
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
The Rust matrix compiles framework-independent source and test scaffolds, verifies
|
|
774
|
+
explicit failure before implementation, then runs the generic application factories
|
|
775
|
+
and their native shrinkers after implementation. It also compiles signatures for
|
|
776
|
+
all scalar types, built-in containers, and an unbound generic data type. Both
|
|
777
|
+
machine profiles, readable/compact output, custom directories, native/WASM parity,
|
|
778
|
+
file preservation and signature-change reporting are covered.
|
|
779
|
+
|
|
780
|
+
JavaScript and TypeScript factories are exported functions returning native
|
|
781
|
+
fast-check arbitraries. A factory reference `["factories", "collections", "lists"]`
|
|
782
|
+
creates `test/factories/collections.mjs` (or `.ts`). Factories in one module share
|
|
783
|
+
one user-owned file. TypeScript signatures use `fc.Arbitrary<T>` child arguments
|
|
784
|
+
and the bound native result type; unbound types use the ordinary generated data
|
|
785
|
+
representation. Source-type imports are adjusted from the actual nested factory
|
|
786
|
+
directory when custom source/test layouts are selected.
|
|
787
|
+
|
|
788
|
+
Both web formats keep scaffolds readable and throw a contextual error until
|
|
789
|
+
implemented. They preserve existing implementations and report changed signatures,
|
|
790
|
+
including native-class changes, through `adapterUpdates`. JavaScript and Python
|
|
791
|
+
include a native-result label so a class change also updates the untyped scaffold
|
|
792
|
+
contract. Conflicts with generated test modules or scaffold signature dependencies
|
|
793
|
+
are diagnosed before writing files.
|
|
794
|
+
|
|
795
|
+
```sh
|
|
796
|
+
LAWSPEC_CORE="$PWD/.artifacts/native-binding-core" LAWSPEC_GENERATOR_STUBS=1 node tools/web-native-payments.mjs
|
|
797
|
+
LAWSPEC_CORE="$PWD/.artifacts/native-binding-core" node tools/web-generator-scaffolds.mjs
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
The web matrix compiles and invokes the initial scaffolds, then runs implemented
|
|
801
|
+
payment and generic list factories with native shrinking. The signature catalog
|
|
802
|
+
covers every scalar, built-in container, native generic class and unbound generic
|
|
803
|
+
data type. TypeScript also rejects an intentionally wrong arbitrary result type.
|
|
804
|
+
Both profiles, formats, nested custom layouts and native/WASM parity are checked.
|
|
805
|
+
|
|
806
|
+
Java factories are public static methods returning native JetCheck
|
|
807
|
+
`Generator<NativeType>` values. A reference such as
|
|
808
|
+
`["application", "Factories", "prices"]` creates the user-owned test file
|
|
809
|
+
`application/Factories.java` under the configured test directory. The last two
|
|
810
|
+
segments name the class and method; earlier segments name the package. Generic
|
|
811
|
+
methods take one `Generator<T>` per type parameter. Scalar payloads use boxed
|
|
812
|
+
native types; Nullable/Optional keep their tagged runtime representation.
|
|
813
|
+
|
|
814
|
+
The initial methods throw `UnsupportedOperationException`. Implement them using
|
|
815
|
+
JetCheck composition to retain shrinking. Scaffolds require a named package
|
|
816
|
+
because generated framework helpers cannot access classes in the unnamed package.
|
|
817
|
+
Classes that conflict with generated/application classes or signature packages,
|
|
818
|
+
and methods that conflict with inherited Object methods, are rejected. Factories
|
|
819
|
+
in one class share one file. Existing implementations, custom layouts and
|
|
820
|
+
signature-update reporting use the same ownership rules as other targets.
|
|
821
|
+
|
|
822
|
+
```sh
|
|
823
|
+
LAWSPEC_CORE="$PWD/.artifacts/native-binding-core" LAWSPEC_GENERATOR_STUBS=1 node tools/java-native-payments.mjs
|
|
824
|
+
LAWSPEC_CORE="$PWD/.artifacts/native-binding-core" node tools/java-generator-scaffolds.mjs
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
The Java matrix compiles the scaffold before implementation, verifies explicit
|
|
828
|
+
runtime failure, then executes native payment and generic-shape generators,
|
|
829
|
+
shrinking checks, finite-domain handling and invalid-adapter/generator mutants.
|
|
830
|
+
The catalog compiles every scalar and container signature, native and canonical
|
|
831
|
+
generic result types, and rejects an intentionally wrong generator result type.
|
|
832
|
+
Both machine profiles, output formats, custom layouts and native/WASM parity are
|
|
833
|
+
covered.
|
|
834
|
+
|
|
835
|
+
Kotlin scaffolds use named objects with functions returning Kotest `Arb<Native>`.
|
|
836
|
+
The last two reference segments name the object and function; earlier segments
|
|
837
|
+
name its package. For example, `["application", "Factories", "prices"]` creates
|
|
838
|
+
`application/Factories.kt` under the configured test directory. Generic factories
|
|
839
|
+
receive one `Arb<T>` child per type parameter. Native generic classes, generated
|
|
840
|
+
unbound data types, and tagged Nullable/Optional types share the compiler's Kotlin
|
|
841
|
+
type mapping. The initial bodies throw contextual `NotImplementedError` values.
|
|
842
|
+
|
|
843
|
+
Objects must be in named packages and must not collide with generated/application
|
|
844
|
+
classes, Kotest support, runtime packages or signature dependencies. Inherited Any
|
|
845
|
+
method conflicts are rejected. The file remains user-owned; readable/compact
|
|
846
|
+
switches preserve it, while native-result or generic-signature changes are reported
|
|
847
|
+
as adapter updates. Keep existing top-level factories import-only, or use a named
|
|
848
|
+
object when requesting scaffolds.
|
|
849
|
+
|
|
850
|
+
```sh
|
|
851
|
+
LAWSPEC_CORE="$PWD/.artifacts/native-binding-core" LAWSPEC_GENERATOR_STUBS=1 node tools/kotlin-native-payments.mjs
|
|
852
|
+
LAWSPEC_CORE="$PWD/.artifacts/native-binding-core" node tools/kotlin-generator-scaffolds.mjs
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
The Kotlin integration compiles and invokes the initial factories, implements them
|
|
856
|
+
with native application arbitraries, then checks payments, generic/recursive
|
|
857
|
+
shapes, shrinking, finite enumeration, invalid text, exhausted refinements and
|
|
858
|
+
incorrect adapters. Its signature catalog checks all scalars and containers,
|
|
859
|
+
native/canonical generic classes, source-only compilation without Kotest, and
|
|
860
|
+
rejection of a deliberately wrong `Arb` result type. Both machine profiles,
|
|
861
|
+
formats, custom layouts and native/WASM parity are covered.
|
|
862
|
+
|
|
863
|
+
Go scaffolds are package-local functions returning `*rapid.Generator[Native]`,
|
|
864
|
+
with one generic child generator per type parameter. Each consuming unit gets a
|
|
865
|
+
user-owned `native_generators_test.go` beside its generated tests. Only the
|
|
866
|
+
factories used by that package are included. Named Go imports are supported in
|
|
867
|
+
native result types, while imported **factories** stay import-only: scaffolding
|
|
868
|
+
does not write into dependencies. A requested factory with no quantified use is
|
|
869
|
+
rejected because there is no consuming package in which to place its scaffold.
|
|
870
|
+
|
|
871
|
+
The scaffold initially panics with its logical type identity. Existing files are
|
|
872
|
+
preserved, signature/native-result changes produce adapter updates, and compact
|
|
873
|
+
mode keeps the user file readable and gofmt compatible. Factory names must not
|
|
874
|
+
shadow application declarations in the same package, built-ins, runtime imports,
|
|
875
|
+
generated support or Go test entry points. Type-parameter names avoid canonical
|
|
876
|
+
and application type names. Source and test layouts continue sharing the same Go
|
|
877
|
+
package directories.
|
|
878
|
+
|
|
879
|
+
```sh
|
|
880
|
+
LAWSPEC_CORE="$PWD/.artifacts/native-binding-core" LAWSPEC_GENERATOR_STUBS=1 node tools/go-native-payments.mjs
|
|
881
|
+
LAWSPEC_CORE="$PWD/.artifacts/native-binding-core" node tools/go-generator-scaffolds.mjs
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
The Go matrix compiles the initial factory files, verifies explicit missing-body
|
|
885
|
+
failures, then executes application payment/shape factories with native shrinking,
|
|
886
|
+
finite-domain/refinement behavior and broken adapters/generators. The catalog
|
|
887
|
+
compiles every scalar and container signature, imported generic models, and a
|
|
888
|
+
canonical type named `T0` to check that generic parameters cannot capture type
|
|
889
|
+
names. It rejects an intentionally wrong Rapid result type. Both profiles,
|
|
890
|
+
formats, custom layouts, source-only builds and native/WASM parity are covered.
|
|
891
|
+
|
|
892
|
+
Haskell scaffolds group typed Hedgehog factories in a user-owned module under the
|
|
893
|
+
test directory. For example, `["Application", "Generators", "lists"]` produces
|
|
894
|
+
`Application/Generators.hs` with `lists :: H.Gen a0 -> H.Gen [a0]`. Each type
|
|
895
|
+
parameter receives a native child generator; the result uses the application type
|
|
896
|
+
when bound, otherwise the canonical generated type. Scalar signatures preserve
|
|
897
|
+
the existing native representations, including `Data.Text.Text` versus `[Char]`
|
|
898
|
+
and tagged nullable/optional values.
|
|
899
|
+
|
|
900
|
+
Bodies initially call `error` with the logical type identity. Implement them by
|
|
901
|
+
composing Hedgehog generators to retain shrinking. Modules that conflict with
|
|
902
|
+
application models/functions/hooks, generated modules or reserved runtime modules
|
|
903
|
+
are rejected, including case-insensitive filename collisions. Nested modules and
|
|
904
|
+
custom test roots are supported; scaffolds remain readable in compact mode.
|
|
905
|
+
Edits remain user-owned and changes to native types or factory arity appear in
|
|
906
|
+
`adapterUpdates`.
|
|
907
|
+
|
|
908
|
+
```sh
|
|
909
|
+
LAWSPEC_CORE="$PWD/.artifacts/native-binding-core" LAWSPEC_GENERATOR_STUBS=1 node tools/haskell-native-payments.mjs
|
|
910
|
+
LAWSPEC_CORE="$PWD/.artifacts/native-binding-core" node tools/haskell-generator-scaffolds.mjs
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
Set `LAWSPEC_GHC` and, when required, `LAWSPEC_GHC_PACKAGE_DB` for both commands.
|
|
914
|
+
The payment matrix compiles and invokes the initial scaffold before supplying
|
|
915
|
+
application factories and exercising native shrinking and invalid-generator
|
|
916
|
+
diagnostics. The signature catalog compiles all scalar/container signatures,
|
|
917
|
+
canonical and native generic models, rejects an incorrect `Gen String` result,
|
|
918
|
+
and checks explicit missing-body failures. Both profiles, formats, custom layouts,
|
|
919
|
+
framework-independent source builds and native/WASM parity are covered.
|
|
920
|
+
|
|
921
|
+
## Release evidence required
|
|
922
|
+
|
|
923
|
+
### Bundled application projects
|
|
924
|
+
|
|
925
|
+
`lawspec examples --example payments` exports one project for each of the eight
|
|
926
|
+
targets under `native_payments/`. Use `--target rust` (or another target) to select
|
|
927
|
+
one, `--output` to choose a directory, and `--machine-bits 32` to select the other
|
|
928
|
+
machine profile. Each project includes the shared specification, application-owned
|
|
929
|
+
domain types and functions, a native price generator, binding configuration, build
|
|
930
|
+
files and a README with commands. Run `lawspec check`, `lawspec generate`, and the
|
|
931
|
+
native test command after installing its dependencies.
|
|
932
|
+
|
|
933
|
+
The native generator intentionally restricts prices to EUR 1.00–2.00. Explicit
|
|
934
|
+
USD/GBP and exact-decimal examples remain in the law, demonstrating that custom
|
|
935
|
+
distributions do not replace those checks. The applications use host exact decimal
|
|
936
|
+
types when faithful and framework-independent support otherwise.
|
|
937
|
+
|
|
938
|
+
Exports use `.lawspec/example.json`; compilation uses `.lawspec/generated.json`.
|
|
939
|
+
This separation lets repeated export preserve edited application files without
|
|
940
|
+
removing or overwriting generated code, including edited generated code that the
|
|
941
|
+
compiler will separately protect. Updated bundled user files are reported for
|
|
942
|
+
review through the existing update channel. Export does not run dependency
|
|
943
|
+
installation or native tests.
|
|
944
|
+
|
|
945
|
+
`tools/native-example-package.mjs` packs and locally installs the npm artifact,
|
|
946
|
+
exports and checks all eight projects, then runs Rust generation, native tests,
|
|
947
|
+
re-export and `generate --check` through the installed CLI. After that script,
|
|
948
|
+
`tools/native-example-runtime.mjs` accepts the other seven target names to execute
|
|
949
|
+
the exported projects with the installed compiler and cached native toolchains.
|
|
950
|
+
For Haskell set `LAWSPEC_GHC` and `LAWSPEC_GHC_PACKAGE_DB`; other cached dependency
|
|
951
|
+
locations can be overridden where the runner exposes environment variables.
|
|
952
|
+
|
|
953
|
+
`node tools/native-example-integration.mjs <target>` performs the public installed
|
|
954
|
+
CLI acceptance path: pack and install, export the payment project, prepare native
|
|
955
|
+
dependencies, check and generate, run the normal native build tool, reject an
|
|
956
|
+
incorrect fee implementation, restore application source, re-export, and check
|
|
957
|
+
regeneration. Logs for every command are retained under
|
|
958
|
+
`.artifacts/native-example-integration/`. CI runs this for every target with the
|
|
959
|
+
default profile and with `LAWSPEC_MACHINE_BITS=32 LAWSPEC_MINIFY=1`.
|
|
960
|
+
`LAWSPEC_PYTHON` selects the Python version for uv; an existing interpreter can be
|
|
961
|
+
selected with `LAWSPEC_PYTHON_EXECUTABLE`. `LAWSPEC_NODE_MODULES` and
|
|
962
|
+
`LAWSPEC_GRADLE` select existing web dependencies and Gradle respectively.
|
|
963
|
+
`LAWSPEC_OFFLINE=1` uses offline npm, uv, Maven and Cargo operations and disables
|
|
964
|
+
Go proxy access; Stack still requires its normal configured dependency cache.
|
|
965
|
+
`STACK_ROOT` and `GRADLE_USER_HOME` can select writable copies of existing caches.
|
|
966
|
+
|
|
967
|
+
The installed CLI/native-tool path has passed for all eight targets in both CI
|
|
968
|
+
configurations: 64-bit readable output and 32-bit compact output. TypeScript
|
|
969
|
+
uses the exact declared dependencies recovered from the existing npm cache;
|
|
970
|
+
Haskell uses a writable copy of the existing Stack cache. Kotlin's Gradle 9.3.0
|
|
971
|
+
checks were run in the user's normal terminal because this sandbox prohibits
|
|
972
|
+
Gradle's coordination socket. The saved logs confirm successful native tests,
|
|
973
|
+
seven expected failures among 45 tests for the deliberately incorrect fee, and
|
|
974
|
+
zero planned regeneration changes in both configurations. This verifies the
|
|
975
|
+
installed CLI/Gradle path as well as the separate compilation/runtime harness.
|
|
976
|
+
The remote run of these CI additions exposed failures in the Kotlin and Haskell
|
|
977
|
+
target jobs. They came from the 0.9 narrowing of abstract `Integer` adapter
|
|
978
|
+
results, not from bindings, and are fixed in 0.11
|
|
979
|
+
([release notes](RELEASE-0.11.md#tower-polymorphic-integer-results-restored)).
|
|
980
|
+
|
|
981
|
+
The runnable assets live in `examples/native-payments/` and are copied into the
|
|
982
|
+
npm package by `tools/wasm.sh`. The original `lawspec examples` command retains its
|
|
983
|
+
inspection-artifact behavior.
|
|
984
|
+
|
|
985
|
+
### Remaining acceptance gates
|
|
986
|
+
|
|
987
|
+
The release audit maps the six shared requirements to these executable checks:
|
|
988
|
+
|
|
989
|
+
| Requirement | Evidence and checks |
|
|
990
|
+
| --- | --- |
|
|
991
|
+
| Resolve bindings once | `NativeBindingSpec` checks identities, complete mappings, ordering, arities, reference validation and unchanged defaults. `NativeRequestSpec` checks the public request boundary. `stack test` passes 509 examples. |
|
|
992
|
+
| Checked native bridges | The target-specific native-payment, native-codec and native-shapes runners compile application models and reject incorrect conversions, precision loss, altered variants and collapsed absence. They compare native/WASM plans across machine profiles, layouts and formatting. |
|
|
993
|
+
| Native generation and shrinking | The native-generator runtime checks and payment/codec runners verify framework factories, shrinking, invalid samples/shrinks, contracts and exhaustion. The shared empty-domain runners cover ignored and demanded empty parameters on all eight targets. |
|
|
994
|
+
| Core semantics and source independence | `tools/check-boundaries.mjs` checks all eight emitter dependency boundaries. The codec/source runners build generated source without test-framework dependencies; native representations are checked against the shared schema. |
|
|
995
|
+
| Application ownership | `npm/test/native-ownership.test.mjs` checks all-target migration, edited files, custom layouts, profile/format changes and adapter updates. `npm/test/native-bindings.test.mjs` covers optional generator scaffolds and signature changes. |
|
|
996
|
+
| Coherent public interface | Schema negotiation and declarations are covered by compiler/npm tests; `tools/build-integrity.mjs` checks compiler/WASM/API fingerprints. Bundled projects are exercised by the installed-package runners. The migration guide and release notes document the interface. |
|
|
997
|
+
|
|
998
|
+
The full npm regression suite passes 77 tests, and the package smoke test passes
|
|
999
|
+
installed API generation on all eight targets plus executable Rust scaffold,
|
|
1000
|
+
doctor, adapter and regeneration checks. The package contains the binding guide,
|
|
1001
|
+
migration notes, release notes and all eight application example configurations.
|
|
1002
|
+
The remote CI gate for these checks was reviewed during the 0.11 release, which
|
|
1003
|
+
re-ran every target job, including both installed native-binding profiles.
|
|
1004
|
+
|
|
1005
|
+
The empty-parameter audit must distinguish an empty type from an inhabited type
|
|
1006
|
+
that mentions it. A native factory for `Phantom Empty` may ignore its child
|
|
1007
|
+
generator; it must not fail merely because `Empty` has no values. Demanding an
|
|
1008
|
+
empty child still cannot produce a sample or make a property pass vacuously.
|
|
1009
|
+
Finite containers such as `List Empty` retain exhaustive enumeration.
|
|
1010
|
+
|
|
1011
|
+
Python supplies Hypothesis `st.nothing()` for an uninhabited native generator
|
|
1012
|
+
argument. Rust supplies a Proptest strategy with a rejecting filter, bounded by
|
|
1013
|
+
Proptest's rejection budget. Haskell supplies Hedgehog `Gen.discard`, Go uses
|
|
1014
|
+
Rapid's native discard control, and Java uses JetCheck's bounded rejecting
|
|
1015
|
+
filter. Kotlin supplies an Arb that fails when sampled; JavaScript and TypeScript
|
|
1016
|
+
supply a fast-check Arbitrary that throws when generation is requested. They do
|
|
1017
|
+
not use an always-false fast-check filter, which can loop indefinitely.
|
|
1018
|
+
Each permits a factory to ignore an empty parameter without inventing a
|
|
1019
|
+
value for that type. Actually demanding the empty child fails generation.
|
|
1020
|
+
|
|
1021
|
+
The shared `test/fixtures/native_empty_domains.lawspec` gives the phantom type a
|
|
1022
|
+
stored Int8 field and sets a low exhaustive limit in the runners, ensuring that
|
|
1023
|
+
the native factory is exercised rather than hidden by singleton enumeration.
|
|
1024
|
+
The Python, Rust, Haskell, Go, Java, Kotlin and web `tools/<target>-native-empty-domains.mjs`
|
|
1025
|
+
runners execute the generated properties and
|
|
1026
|
+
reject a mutant factory that demands its empty child. Both machine profiles and
|
|
1027
|
+
formats pass with native/WASM parity; direct runtime checks also verify retained
|
|
1028
|
+
shrinking and rejection of an empty root. Python additionally binds an
|
|
1029
|
+
application-owned phantom class. Java's empty native codec decoder throws
|
|
1030
|
+
directly, avoiding an invalid switch expression with no result branches. Kotlin,
|
|
1031
|
+
JavaScript and TypeScript also pass their native payment/generator regressions
|
|
1032
|
+
after the empty-parameter changes.
|
|
1033
|
+
|
|
1034
|
+
- Compiler tests for valid mappings, rejected malformed/incomplete mappings,
|
|
1035
|
+
generic specialization, recursion, symbol/absence semantics and contracts.
|
|
1036
|
+
- Lossless native/WASM request and diagnostic parity for the binding interface.
|
|
1037
|
+
- Payment domain builds and executes on Java, Python, JavaScript, TypeScript,
|
|
1038
|
+
Go, Haskell, Kotlin and Rust using genuinely application-owned types.
|
|
1039
|
+
- Native custom generators are invoked, their shrinkers demonstrably shrink
|
|
1040
|
+
failing domain values, invalid values/shrinks fail contextually, and explicit
|
|
1041
|
+
examples/boundaries still run when a generator omits those values.
|
|
1042
|
+
- Deliberately broken field/variant mappings and precision-losing adapters fail
|
|
1043
|
+
deterministically. Empty/exhausted generator behavior cannot pass vacuously.
|
|
1044
|
+
- Both machine profiles, architecture mismatch diagnostics, custom layouts,
|
|
1045
|
+
regeneration protection and packaged installation remain tested.
|
|
1046
|
+
- Python follows PEP 8; Rust remains a first-class acceptance target throughout.
|
|
1047
|
+
|
|
1048
|
+
GADTs, dependent indices and cross-unit package resolution are subsequent work.
|
|
1049
|
+
They are not prerequisites for binding ordinary 0.9 products and sums.
|