@lemmabase/lemma-engine 0.8.20 → 0.8.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,7 +7,7 @@ Pricing tiers, tax brackets, leave entitlement, eligibility checks, discount sta
7
7
  ```lemma
8
8
  spec pricing 2026-01-01
9
9
 
10
- data money: quantity
10
+ data money: measure
11
11
  -> unit eur 1.00
12
12
  -> decimals 2
13
13
 
@@ -42,7 +42,7 @@ The `Response` carries every rule's value (or `veto` if no result could be compu
42
42
  - **Deterministic.** `(spec, data, effective_date) → result`. No DB, no clock, no ambient state. Same inputs → same outputs, every time.
43
43
  - **Explainable.** The `Response` tells you which rules contributed and why; pair it with the [CLI](https://github.com/lemma/lemma) for a full reasoning trace.
44
44
  - **Time-aware.** Multiple versions of the same spec coexist. Pass an `effective` date and the engine resolves the version in force on that day.
45
- - **Statically checked.** Type errors, missing data, cycles, quantity-family mismatches - all caught at `load()` time. Bad specs never reach `run()`.
45
+ - **Statically checked.** Type errors, missing data, cycles, measure-family mismatches - all caught at `load()` time. Bad specs never reach `run()`.
46
46
  - **Runs anywhere V8 does.** ~2 MB WASM, no native binary, no postinstall script.
47
47
  - **Editor in a tab.** Includes an in-process language server and a Monaco adapter, so you can build a real Lemma editor experience client-side - diagnostics, completion, formatting... even without setting up a server.
48
48
 
@@ -141,6 +141,10 @@ In the browser, the registry must allow your origin (CORS). Use `https` or `http
141
141
 
142
142
  Lemma is pre-1.0. The WASM API is stable for most use cases, but breaking changes may occur between minor versions. Pin your dependency version and review the [changelog](https://github.com/lemma/lemma/blob/main/CHANGELOG.md) before upgrading.
143
143
 
144
+ ### WASM panic behavior
145
+
146
+ Rust panics cannot unwind on the `wasm32` target, so an internal invariant violation (a bug) traps the WASM instance. The call throws a `RuntimeError` which you can catch with `try/catch` to fail gracefully, but the module's linear memory is poisoned — constructing a new `Engine()` from the same initialized module is not safe. To recover, re-initialize the WASM module (`init()` again) or, for robust containment, run the engine in a Web Worker and respawn the worker on trap. The panic message (prefixed `BUG: ...`) is logged to the console before the trap. All domain-level failures (invalid specs, bad data, impossible rules) are reported as `EngineError[]` or vetoes and never cause traps.
147
+
144
148
  ## Related
145
149
 
146
150
  - [`lemmabase.com`](https://lemmabase.com): public database for Lemma Specs
@@ -24,7 +24,6 @@ export class Engine {
24
24
  * Canonical Lemma source for `repository`, formatted from the in-engine AST (e.g. `"lemma"`).
25
25
  */
26
26
  format_repository(repository: string): string;
27
- invert(spec_name: string, rule_name: string, target_json: string, provided_values_json: string): any;
28
27
  /**
29
28
  * Same data as [`Engine::list`]: grouped [`ResolvedRepository`] JSON without planning.
30
29
  */
@@ -125,16 +124,15 @@ export interface InitOutput {
125
124
  readonly wasmengine_fetch: (a: number, b: number, c: number) => number;
126
125
  readonly wasmengine_format: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
127
126
  readonly wasmengine_format_repository: (a: number, b: number, c: number, d: number) => void;
128
- readonly wasmengine_invert: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => void;
129
127
  readonly wasmengine_list: (a: number, b: number) => void;
130
128
  readonly wasmengine_load: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
131
129
  readonly wasmengine_load_batch: (a: number, b: number, c: number, d: number, e: number) => void;
132
130
  readonly wasmengine_new: () => number;
133
131
  readonly wasmengine_run: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number) => void;
134
132
  readonly wasmengine_schema: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
135
- readonly __wasm_bindgen_func_elem_12173: (a: number, b: number, c: number, d: number) => void;
133
+ readonly __wasm_bindgen_func_elem_12297: (a: number, b: number, c: number, d: number) => void;
136
134
  readonly __wasm_bindgen_func_elem_2740: (a: number, b: number, c: number, d: number) => void;
137
- readonly __wasm_bindgen_func_elem_12188: (a: number, b: number, c: number, d: number) => void;
135
+ readonly __wasm_bindgen_func_elem_12302: (a: number, b: number, c: number, d: number) => void;
138
136
  readonly __wbindgen_export: (a: number, b: number) => number;
139
137
  readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
140
138
  readonly __wbindgen_export3: (a: number) => void;
package/lemma.bindings.js CHANGED
@@ -79,36 +79,6 @@ export class Engine {
79
79
  wasm.__wbindgen_export4(deferred3_0, deferred3_1, 1);
80
80
  }
81
81
  }
82
- /**
83
- * @param {string} spec_name
84
- * @param {string} rule_name
85
- * @param {string} target_json
86
- * @param {string} provided_values_json
87
- * @returns {any}
88
- */
89
- invert(spec_name, rule_name, target_json, provided_values_json) {
90
- try {
91
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
92
- const ptr0 = passStringToWasm0(spec_name, wasm.__wbindgen_export, wasm.__wbindgen_export2);
93
- const len0 = WASM_VECTOR_LEN;
94
- const ptr1 = passStringToWasm0(rule_name, wasm.__wbindgen_export, wasm.__wbindgen_export2);
95
- const len1 = WASM_VECTOR_LEN;
96
- const ptr2 = passStringToWasm0(target_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
97
- const len2 = WASM_VECTOR_LEN;
98
- const ptr3 = passStringToWasm0(provided_values_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
99
- const len3 = WASM_VECTOR_LEN;
100
- wasm.wasmengine_invert(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
101
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
102
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
103
- var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
104
- if (r2) {
105
- throw takeObject(r1);
106
- }
107
- return takeObject(r0);
108
- } finally {
109
- wasm.__wbindgen_add_to_stack_pointer(16);
110
- }
111
- }
112
82
  /**
113
83
  * Same data as [`Engine::list`]: grouped [`ResolvedRepository`] JSON without planning.
114
84
  * @returns {any}
@@ -696,7 +666,7 @@ function __wbg_get_imports() {
696
666
  const a = state0.a;
697
667
  state0.a = 0;
698
668
  try {
699
- return __wasm_bindgen_func_elem_12188(a, state0.b, arg0, arg1);
669
+ return __wasm_bindgen_func_elem_12302(a, state0.b, arg0, arg1);
700
670
  } finally {
701
671
  state0.a = a;
702
672
  }
@@ -855,8 +825,8 @@ function __wbg_get_imports() {
855
825
  return addHeapObject(ret);
856
826
  },
857
827
  __wbindgen_cast_0000000000000001: function(arg0, arg1) {
858
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1410, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
859
- const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_12173);
828
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1414, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
829
+ const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_12297);
860
830
  return addHeapObject(ret);
861
831
  },
862
832
  __wbindgen_cast_0000000000000002: function(arg0, arg1) {
@@ -898,10 +868,10 @@ function __wbg_get_imports() {
898
868
  };
899
869
  }
900
870
 
901
- function __wasm_bindgen_func_elem_12173(arg0, arg1, arg2) {
871
+ function __wasm_bindgen_func_elem_12297(arg0, arg1, arg2) {
902
872
  try {
903
873
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
904
- wasm.__wasm_bindgen_func_elem_12173(retptr, arg0, arg1, addHeapObject(arg2));
874
+ wasm.__wasm_bindgen_func_elem_12297(retptr, arg0, arg1, addHeapObject(arg2));
905
875
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
906
876
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
907
877
  if (r1) {
@@ -926,8 +896,8 @@ function __wasm_bindgen_func_elem_2740(arg0, arg1, arg2) {
926
896
  }
927
897
  }
928
898
 
929
- function __wasm_bindgen_func_elem_12188(arg0, arg1, arg2, arg3) {
930
- wasm.__wasm_bindgen_func_elem_12188(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
899
+ function __wasm_bindgen_func_elem_12302(arg0, arg1, arg2, arg3) {
900
+ wasm.__wasm_bindgen_func_elem_12302(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
931
901
  }
932
902
 
933
903
 
package/lemma.d.ts CHANGED
@@ -50,6 +50,10 @@ declare module './lemma.bindings.js' {
50
50
 
51
51
  /**
52
52
  * `repository`: qualifier or `null`/omit for workspace — same as `Engine::run` `repo`.
53
+ *
54
+ * `data_values`: pass integers as numbers, decimals as strings (e.g.
55
+ * `{ quantity: 42, rate: "0.075" }`). Non-integer numbers are rejected
56
+ * to prevent silent precision loss from IEEE 754 doubles.
53
57
  */
54
58
  run(
55
59
  repository: string | null | undefined,
@@ -147,7 +151,7 @@ export type LemmaType =
147
151
  & (
148
152
  | { kind: "boolean"; help: string }
149
153
  | {
150
- kind: "quantity";
154
+ kind: "measure";
151
155
  minimum: string | null;
152
156
  maximum: string | null;
153
157
  decimals: number | null;
@@ -155,7 +159,7 @@ export type LemmaType =
155
159
  help: string;
156
160
  }
157
161
  | {
158
- kind: "quantity range";
162
+ kind: "measure range";
159
163
  minimum: string | null;
160
164
  maximum: string | null;
161
165
  decimals: number | null;
@@ -201,9 +205,11 @@ export type LemmaType =
201
205
  /** One input declared in a spec. Omitted fields are absent (not `null`). */
202
206
  export interface DataEntry {
203
207
  type: LemmaType;
204
- /** Literal bound in the source (`data x: literal`). */
205
- bound_value?: LiteralValue;
206
- /** `-> default ...` suggestion; omitted from `bound_value` until evaluation applies it. */
208
+ /** Spec literal or literal `with` binding; UIs may skip review. */
209
+ prefilled?: LiteralValue;
210
+ /** Caller overlay when schema was built with supplied values. */
211
+ supplied?: LiteralValue;
212
+ /** `-> default ...` suggestion; prompt with prefill in interactive UIs. */
207
213
  default?: LiteralValue;
208
214
  }
209
215
 
@@ -220,7 +226,7 @@ export interface RuleResult {
220
226
  display?: string | null;
221
227
  veto_reason?: string | null;
222
228
  rule_type: string;
223
- quantity?: Record<string, string> | null;
229
+ measure?: Record<string, string> | null;
224
230
  ratio?: Record<string, string> | null;
225
231
  number?: string | null;
226
232
  boolean?: boolean | null;
@@ -233,7 +239,7 @@ export interface RuleResult {
233
239
  }
234
240
 
235
241
  export interface RuleResultPayload {
236
- quantity?: Record<string, string> | null;
242
+ measure?: Record<string, string> | null;
237
243
  ratio?: Record<string, string> | null;
238
244
  number?: string | null;
239
245
  boolean?: boolean | null;
@@ -252,7 +258,7 @@ export interface EvaluationDataEntry {
252
258
  export interface SpecSchema {
253
259
  spec: string;
254
260
  data: Record<string, DataEntry>;
255
- /** Rule result types; quantity and ratio entries expose `units[]` like their data counterparts. */
261
+ /** Rule result types; measure and ratio entries expose `units[]` like their data counterparts. */
256
262
  rules: Record<string, LemmaType>;
257
263
  meta: Record<string, unknown>;
258
264
  }