@bjornpagen/bumbledb 0.5.0 → 0.7.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.
Files changed (100) hide show
  1. package/COOKBOOK.md +140 -136
  2. package/README.md +24 -11
  3. package/dist/closed.d.ts +7 -5
  4. package/dist/closed.d.ts.map +1 -1
  5. package/dist/closed.js +4 -1
  6. package/dist/closed.js.map +1 -1
  7. package/dist/count.js +1 -1
  8. package/dist/count.js.map +1 -1
  9. package/dist/db.d.ts +110 -73
  10. package/dist/db.d.ts.map +1 -1
  11. package/dist/db.js +172 -116
  12. package/dist/db.js.map +1 -1
  13. package/dist/exhume.d.ts +22 -10
  14. package/dist/exhume.d.ts.map +1 -1
  15. package/dist/exhume.js +42 -9
  16. package/dist/exhume.js.map +1 -1
  17. package/dist/face.d.ts +10 -6
  18. package/dist/face.d.ts.map +1 -1
  19. package/dist/face.js.map +1 -1
  20. package/dist/fields.d.ts +38 -16
  21. package/dist/fields.d.ts.map +1 -1
  22. package/dist/fields.js +33 -8
  23. package/dist/fields.js.map +1 -1
  24. package/dist/index.d.ts +9 -6
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +5 -2
  27. package/dist/index.js.map +1 -1
  28. package/dist/lower.d.ts +9 -9
  29. package/dist/lower.d.ts.map +1 -1
  30. package/dist/lower.js +17 -12
  31. package/dist/lower.js.map +1 -1
  32. package/dist/marshal.d.ts +17 -7
  33. package/dist/marshal.d.ts.map +1 -1
  34. package/dist/marshal.js +32 -10
  35. package/dist/marshal.js.map +1 -1
  36. package/dist/native.d.ts +60 -9
  37. package/dist/native.d.ts.map +1 -1
  38. package/dist/native.js.map +1 -1
  39. package/dist/query/atom.d.ts +199 -203
  40. package/dist/query/atom.d.ts.map +1 -1
  41. package/dist/query/atom.js +39 -48
  42. package/dist/query/atom.js.map +1 -1
  43. package/dist/query/find.d.ts +116 -0
  44. package/dist/query/find.d.ts.map +1 -0
  45. package/dist/query/{select.js → find.js} +22 -22
  46. package/dist/query/find.js.map +1 -0
  47. package/dist/query/lower.d.ts +131 -158
  48. package/dist/query/lower.d.ts.map +1 -1
  49. package/dist/query/lower.js +505 -494
  50. package/dist/query/lower.js.map +1 -1
  51. package/dist/query/predicate.d.ts +22 -14
  52. package/dist/query/predicate.d.ts.map +1 -1
  53. package/dist/query/predicate.js +35 -42
  54. package/dist/query/predicate.js.map +1 -1
  55. package/dist/query/run.d.ts +8 -8
  56. package/dist/query/run.d.ts.map +1 -1
  57. package/dist/query/run.js +16 -21
  58. package/dist/query/run.js.map +1 -1
  59. package/dist/query/scope.d.ts +139 -74
  60. package/dist/query/scope.d.ts.map +1 -1
  61. package/dist/query/scope.js +80 -33
  62. package/dist/query/scope.js.map +1 -1
  63. package/dist/relation.d.ts.map +1 -1
  64. package/dist/relation.js +3 -1
  65. package/dist/relation.js.map +1 -1
  66. package/dist/schema.d.ts.map +1 -1
  67. package/dist/schema.js +12 -2
  68. package/dist/schema.js.map +1 -1
  69. package/dist/spec.d.ts +20 -10
  70. package/dist/spec.d.ts.map +1 -1
  71. package/dist/spec.js.map +1 -1
  72. package/dist/statements.d.ts +22 -2
  73. package/dist/statements.d.ts.map +1 -1
  74. package/dist/statements.js +26 -5
  75. package/dist/statements.js.map +1 -1
  76. package/package.json +3 -3
  77. package/src/closed.ts +13 -7
  78. package/src/count.ts +1 -1
  79. package/src/db.ts +293 -177
  80. package/src/exhume.ts +48 -11
  81. package/src/face.ts +13 -6
  82. package/src/fields.ts +51 -15
  83. package/src/index.ts +12 -8
  84. package/src/lower.ts +17 -12
  85. package/src/marshal.ts +38 -13
  86. package/src/native.ts +59 -8
  87. package/src/query/atom.ts +297 -275
  88. package/src/query/find.ts +212 -0
  89. package/src/query/lower.ts +692 -724
  90. package/src/query/predicate.ts +37 -45
  91. package/src/query/run.ts +17 -22
  92. package/src/query/scope.ts +184 -90
  93. package/src/relation.ts +3 -1
  94. package/src/schema.ts +14 -2
  95. package/src/spec.ts +21 -9
  96. package/src/statements.ts +30 -6
  97. package/dist/query/select.d.ts +0 -128
  98. package/dist/query/select.d.ts.map +0 -1
  99. package/dist/query/select.js.map +0 -1
  100. package/src/query/select.ts +0 -215
package/src/query/atom.ts CHANGED
@@ -1,86 +1,61 @@
1
1
  /**
2
- * Atoms and conditions, STRUCTURAL edition — the body vocabulary of a
3
- * rule, mirroring the engine IR variant for variant
2
+ * Atoms and conditions, REFERENCE-IDENTITY edition — the body vocabulary of
3
+ * a rule, mirroring the engine IR variant for variant
4
4
  * (`bumbledb/crates/bumbledb/src/ir.rs`, the bijection target;
5
5
  * `docs/architecture/20-query-ir.md` normative). A `match` binding record
6
- * binds fields to vars, params, ∈-set params, or bare structural literals
7
- * — a closed-reference field's literal is its handle NAME, and a plain
8
- * ARRAY of names there is membership, folded into the program (closed-only
9
- * by owner ruling; see {@link BindingInput})
6
+ * binds fields to VARIABLES (minted by {@link v}), params, ∈-set params, or
7
+ * bare structural literals — a closed-reference field's literal is its
8
+ * handle NAME, and a plain ARRAY of names there is membership
10
9
  * (unmentioned fields ARE the wildcard — no wildcard value exists);
11
10
  * `not(Rel, {...})` is negation-as-position (anti-join); `eq`/`ne` and the
12
11
  * order roster, `pointIn` (the one spelling of `ir::CmpOp::PointIn`,
13
12
  * always lowered interval-left), `allen` (the 13-bit mask pair
14
13
  * comparison), and `and`/`or` (the input condition-tree grammar) complete
15
14
  * the roster. Nothing beyond the IR exists here — and the walls the engine
16
- * enforces at prepare are TYPES first: a var joins only domain-equal
17
- * fields (`JoinOk`, checked against the rule environment AND against the
18
- * binding record's own same-named siblings — two first occurrences of one
19
- * name inside one record are a join too), an
20
- * interval-typed var under a non-`pointIn` comparison is unwritable, and a
21
- * negated atom's variables must be positively bound (env membership IS the
22
- * safety rule). Every condition value carries its operands raw — the
23
- * runtime representation is the type-inference carrier, no phantoms.
15
+ * enforces at prepare are TYPES first: a variable joins only class-equal
16
+ * fields, judged at every binding position against the var's MINT slot
17
+ * ({@link MintSlotOf}); because {@link JoinOk} is an equality, that ALONE
18
+ * makes every cross-binding join transitively class-equal (the env/sibling
19
+ * checks the name-keyed edition needed are gone). An interval-typed var
20
+ * under a non-`pointIn` comparison is unwritable. BOUNDNESS (a negated
21
+ * atom's variables must be positively bound) is the one check types cannot
22
+ * carry — object identity is invisible to TS — so it is a construction-time
23
+ * wall only.
24
24
  *
25
25
  * This module also owns the plain runtime DATA a built rule is made of
26
26
  * (`RuleData`/`RecData` and friends): frozen values the lowering walks —
27
- * pure data, so lowering stays a pure, stable function of the query value.
27
+ * pure data (variable references included), so lowering stays a pure,
28
+ * stable function of the query value.
28
29
  */
29
30
 
30
31
  import * as errors from "@superbuilders/errors"
31
- import type { AnyClosed } from "#closed.ts"
32
32
  import type { AnyField, ClosedIdField, ClosedRoster, Infer, IntervalValue } from "#fields.ts"
33
33
  import type { ClassLookup, ClassRecordOf, SchemaClasses } from "#law.ts"
34
34
  import type {
35
+ AnyVar,
35
36
  ClassedField,
36
37
  Duration,
37
- EnvShape,
38
38
  JoinOk,
39
39
  MaskParam,
40
+ MatchFields,
41
+ MatchOwner,
42
+ MintSlotOf,
40
43
  Param,
44
+ ParamsRecord,
41
45
  ParamValueAt,
42
46
  SetParam,
43
- ShapeOf,
44
- Var
47
+ ShapeOf
45
48
  } from "#query/scope.ts"
46
- import { isTerm } from "#query/scope.ts"
47
- import type { AnyRelation, FieldsShape, RelationFields } from "#relation.ts"
48
-
49
- /**
50
- * What a query atom matches over: an ordinary relation or a CLOSED
51
- * vocabulary (ψ query atoms — the engine folds a resolvable closed atom
52
- * into a plan-constant member set at prepare, or joins the L1-resident
53
- * virtual image when the shape does not fold; the SDK never pre-folds and
54
- * never knows which — transparency is the contract).
55
- */
56
- type MatchOwner = AnyRelation | AnyClosed
49
+ import { inferred, isTerm } from "#query/scope.ts"
50
+ import type { FieldsShape } from "#relation.ts"
57
51
 
58
52
  /**
59
- * The matchable field block of an atom owner: a relation's declared
60
- * fields; a closed relation's SEALED shape — the synthetic `id` (the
61
- * value's OWN roster-carrying descriptor, at its precise type: the handle
62
- * union rides into ψ id bindings and joins exactly as it does on a
63
- * referencing column) first, then the declared payload columns read
64
- * through the typed `columns` carrier (the one source of payload typing —
65
- * no parallel column table exists). The runtime twin is `sealedFieldsOf` in
66
- * `#query/lower.ts`; the id-first ordinal shift the two tiers share is
67
- * pinned by the lowering golden.
68
- */
69
- type MatchFields<R extends MatchOwner> = R extends AnyClosed
70
- ? { readonly id: R["id"] } & R["columns"]
71
- : R extends AnyRelation
72
- ? RelationFields<R>
73
- : never
74
-
75
- /**
76
- * One atom-binding position as runtime data. `literalSet` is a membership
77
- * ARRAY at a closed-reference field, folded into the program: `name` is
78
- * the content-addressed registry key its dense `ParamId` is minted under
79
- * (the lowering rides the existing param-set term; the SDK itself supplies
80
- * the translated member set at every execute — never the host).
53
+ * One atom-binding position as runtime data. A variable rides BY REFERENCE
54
+ * (`ref`) — object identity is the join. `literalSet` is a membership
55
+ * ARRAY at a closed-reference field, folded into the program.
81
56
  */
82
57
  type BindingTermData =
83
- | { readonly kind: "var"; readonly name: string }
58
+ | { readonly kind: "var"; readonly ref: AnyVar }
84
59
  | { readonly kind: "param"; readonly name: string }
85
60
  | { readonly kind: "setParam"; readonly name: string }
86
61
  | { readonly kind: "literalSet"; readonly name: string; readonly members: readonly string[] }
@@ -103,12 +78,12 @@ interface AtomData {
103
78
  /** One comparison operator name (mirrors `ir::CmpOp`). */
104
79
  type CmpKind = "eq" | "ne" | "lt" | "le" | "gt" | "ge" | "pointIn" | "allen"
105
80
 
106
- /** One comparison side as runtime data. */
81
+ /** One comparison side as runtime data (variables and the measure ride BY REFERENCE). */
107
82
  type CmpTermData =
108
- | { readonly kind: "var"; readonly name: string }
83
+ | { readonly kind: "var"; readonly ref: AnyVar }
109
84
  | { readonly kind: "param"; readonly name: string }
110
85
  | { readonly kind: "setParam"; readonly name: string }
111
- | { readonly kind: "measure"; readonly name: string }
86
+ | { readonly kind: "measure"; readonly ref: AnyVar }
112
87
  | { readonly kind: "literal"; readonly value: unknown }
113
88
 
114
89
  /** The `allen` mask position as runtime data. */
@@ -133,48 +108,63 @@ interface TreeData {
133
108
  /** Any condition node as runtime data. */
134
109
  type CondData = CmpData | TreeData
135
110
 
136
- /** One aggregate's runtime description (select vocabulary, over var NAMES). */
111
+ /** One aggregate's runtime description (find vocabulary, over variable REFERENCES). */
137
112
  type AggData =
138
113
  | { readonly op: "count" }
139
- | { readonly op: "countDistinct"; readonly over: string }
140
- | { readonly op: "fold"; readonly fold: "sum" | "min" | "max"; readonly over: string | { readonly duration: string } }
141
- | { readonly op: "arg"; readonly direction: "argMax" | "argMin"; readonly over: string; readonly key: string }
142
- | { readonly op: "pack"; readonly over: string }
143
-
144
- /** One classified select entry as runtime data. */
145
- type SelectEntryData =
146
- | { readonly kind: "var"; readonly over: string }
147
- | { readonly kind: "measure"; readonly over: string }
114
+ | { readonly op: "countDistinct"; readonly over: AnyVar }
115
+ | {
116
+ readonly op: "fold"
117
+ readonly fold: "sum" | "min" | "max"
118
+ readonly over: AnyVar | { readonly duration: AnyVar }
119
+ }
120
+ | { readonly op: "arg"; readonly direction: "argMax" | "argMin"; readonly over: AnyVar; readonly key: AnyVar }
121
+ | { readonly op: "pack"; readonly over: AnyVar }
122
+
123
+ /** One classified find entry as runtime data (variables and the measure ride BY REFERENCE). */
124
+ type FindEntryData =
125
+ | { readonly kind: "var"; readonly over: AnyVar }
126
+ | { readonly kind: "measure"; readonly over: AnyVar }
148
127
  | { readonly kind: "aggregate"; readonly agg: AggData }
149
128
 
150
129
  /**
151
- * One answer column: its name (the row object key), its entry, and — when
152
- * the column's value is a closed reference (a projected var or an
153
- * Arg-carried payload bound at a closed-referencing field) — the roster the
154
- * decode lifts row ids back to handle NAMES through (the read half of the
155
- * marshal bijection; `undefined` on every bare column). The slice is
156
- * SDK-side marshaling data only: the wire `ProgramIr` never carries it.
130
+ * One answer column: its name (the row object key — the find record's key,
131
+ * so renames are real and a duplicate column is unrepresentable), its entry,
132
+ * the classed mint SLOT its values flow from (a projected var or an
133
+ * Arg-carried payload; `undefined` for counts/folds/measures/pack, which
134
+ * derive numbers or intervals), and — when that slot is a closed reference —
135
+ * the roster the decode lifts row ids back to handle NAMES through
136
+ * (`undefined` on every bare column). The slice is SDK-side marshaling data
137
+ * only: the wire `ProgramIr` never carries it.
157
138
  */
158
- interface SelectColumn {
139
+ interface FindColumn {
159
140
  readonly name: string
160
- readonly entry: SelectEntryData
141
+ readonly entry: FindEntryData
161
142
  readonly closed: ClosedRoster | undefined
143
+ readonly slot: ClassedField | undefined
162
144
  }
163
145
 
164
- /** One body item of a rule, in written order. */
146
+ /**
147
+ * One body item of a rule, in written order. The idb join is a NAMED record
148
+ * over the rec's head keys (`key`) bound to local variables (`ref`) — the
149
+ * typed wall a record's unordered keys would otherwise lose.
150
+ */
165
151
  type RuleItem =
166
152
  | { readonly kind: "atom"; readonly atom: AtomData }
167
153
  | { readonly kind: "negated"; readonly atom: AtomData }
168
- | { readonly kind: "idb"; readonly rec: RecData; readonly vars: readonly string[] }
154
+ | {
155
+ readonly kind: "idb"
156
+ readonly rec: RecData
157
+ readonly bindings: ReadonlyArray<{ readonly key: string; readonly ref: AnyVar }>
158
+ /** `true` on a negated finished-stratum atom (`r.not(rec, {...})`): probed through its anti-probe, binds nothing. */
159
+ readonly negated: boolean
160
+ }
169
161
  | { readonly kind: "cond"; readonly cond: CondData }
170
162
 
171
163
  /**
172
164
  * One use of a parameter inside a rule, in written order: the census the
173
165
  * query-level registry folds (first use mints the dense `ParamId`, first
174
166
  * FIELD-ANCHORED use types the wire). `members` is present exactly on a
175
- * membership-array use (a literal set folded into the program): the handle
176
- * names the SDK itself translates and supplies at execute — the entry
177
- * never appears in the host's params object.
167
+ * membership-array use.
178
168
  */
179
169
  interface ParamUse {
180
170
  readonly name: string
@@ -187,9 +177,7 @@ interface ParamUse {
187
177
  /** One complete rule as runtime data. */
188
178
  interface RuleData {
189
179
  readonly items: readonly RuleItem[]
190
- readonly select: readonly SelectColumn[]
191
- /** Variable name → the classed slot its FIRST positive binding carries (the runtime env — descriptor + class). */
192
- readonly varFields: Readonly<Record<string, ClassedField>>
180
+ readonly finds: readonly FindColumn[]
193
181
  readonly paramUses: readonly ParamUse[]
194
182
  }
195
183
 
@@ -205,23 +193,15 @@ interface RecData {
205
193
 
206
194
  /**
207
195
  * What a binding position of field `F` accepts: a bare structural literal
208
- * of the field's value type, a var/param/∈-set-param term — and, when the
209
- * field is interval-typed, a bare point literal (the IR's membership
210
- * typing rule: an element-typed term at an interval field is point
211
- * membership; an interval-typed term is value equality). A
212
- * CLOSED-reference field additionally takes a plain ARRAY of handle names
213
- * read as membership — `kind: ["Practice", "Review"]` (the drizzle law:
214
- * set membership is an array, never an operator). Arrays are CLOSED-ONLY
215
- * in this packet by owner ruling: ordinary u64/str membership already has
216
- * its spelling through `r.inSet` params; widening literal arrays to every
217
- * literal-capable kind is a separate future taste call — deliberately not
218
- * done here.
196
+ * of the field's value type, a variable/param/∈-set-param term — and, when
197
+ * the field is interval-typed, a bare point literal. A CLOSED-reference
198
+ * field additionally takes a plain ARRAY of handle names read as membership.
219
199
  */
220
200
  type BindingInput<F extends AnyField> =
221
201
  | Infer<F>
222
202
  | (F extends ClosedIdField ? readonly Infer<F>[] : never)
223
203
  | (F extends { readonly kind: "interval" } ? bigint : never)
224
- | Var<string>
204
+ | AnyVar
225
205
  | Param<string>
226
206
  | SetParam<string>
227
207
 
@@ -237,8 +217,8 @@ type MatchShape<F extends FieldsShape> = {
237
217
  /**
238
218
  * One field position of a bindings record as a classed slot: the declared
239
219
  * descriptor plus the slot's law-computed class, read off the relation's
240
- * class record (`CR` — the schema class map's entry for the atom's
241
- * relation). The one shape every join judgment compares.
220
+ * class record (`CR`). The one shape a binding position's join judgment
221
+ * compares against.
242
222
  */
243
223
  type SlotAt<F extends FieldsShape, CR, K> = {
244
224
  readonly field: F[K & keyof F]
@@ -246,49 +226,20 @@ type SlotAt<F extends FieldsShape, CR, K> = {
246
226
  }
247
227
 
248
228
  /**
249
- * The var binding's judgment against the incoming rule environment: a name
250
- * already bound must land on a class-equal slot (bare pairs only with bare).
229
+ * The per-property join judgment of a bindings record: a VARIABLE binding
230
+ * must join its own MINT slot to the position slot (a cross-class reuse maps
231
+ * the property to `never`). Because {@link JoinOk} is an equality, judging
232
+ * every position against the mint slot makes all cross-binding joins
233
+ * mutually class-equal by transitivity — no env or sibling arm is needed.
251
234
  */
252
- type EnvJoinOk<Env extends EnvShape, F extends FieldsShape, CR, K, N extends string> = N extends keyof Env
253
- ? JoinOk<Env[N], SlotAt<F, CR, K>>
254
- : true
255
-
256
- /**
257
- * The var binding's judgment against its OWN record's siblings: two
258
- * bindings of one var name inside a single bindings record are the same
259
- * join the environment check judges across atoms, so every same-named
260
- * sibling must be class-equal too. Without this arm two FIRST occurrences
261
- * of one name (a record the environment has not seen yet) would meet no
262
- * check at all — the intra-atom join would silently cross classes.
263
- */
264
- type SiblingJoinOk<F extends FieldsShape, CR, B, K extends keyof B, N extends string> = false extends {
265
- [K2 in Exclude<keyof B & keyof F, K>]: B[K2] extends Var<N> ? JoinOk<SlotAt<F, CR, K2>, SlotAt<F, CR, K>> : true
266
- }[Exclude<keyof B & keyof F, K>]
267
- ? false
268
- : true
269
-
270
- /**
271
- * The per-property join judgment of a bindings record: a var binding must
272
- * be class-equal to the rule environment's binding of the name AND to
273
- * every same-named sibling of its own record (a cross-class reuse maps
274
- * the property to `never` — the compile error the old value brand carried,
275
- * now law-born off the schema type's class map).
276
- */
277
- type BindingOk<Env extends EnvShape, F extends FieldsShape, CR, B, K extends keyof B> =
278
- B[K] extends Var<infer N extends string>
279
- ? [EnvJoinOk<Env, F, CR, K, N>, SiblingJoinOk<F, CR, B, K, N>] extends [true, true]
280
- ? true
281
- : false
282
- : true
283
-
284
- /** The validated bindings record (intersect with the inferred `B` — errors land on the offending property). */
285
- type CheckBindings<Env extends EnvShape, F extends FieldsShape, CR, B> = {
286
- readonly [K in keyof B]: K extends keyof F ? (BindingOk<Env, F, CR, B, K> extends true ? B[K] : never) : never
287
- }
288
-
289
- /** The environment a bindings record contributes: var name → the bound slot (descriptor + class). */
290
- type BindEnv<F extends FieldsShape, CR, B> = {
291
- readonly [K in keyof B & keyof F as B[K] extends Var<infer N extends string> ? N : never]: SlotAt<F, CR, K>
235
+ type CheckBindings<Classes extends SchemaClasses, F extends FieldsShape, CR, B> = {
236
+ readonly [K in keyof B]: K extends keyof F
237
+ ? B[K] extends AnyVar
238
+ ? JoinOk<MintSlotOf<Classes, B[K]>, SlotAt<F, CR, K>> extends true
239
+ ? B[K]
240
+ : never
241
+ : B[K]
242
+ : never
292
243
  }
293
244
 
294
245
  /** The params-object fragments a bindings record contributes (one union member per param use). */
@@ -302,8 +253,8 @@ type BindParams<F extends FieldsShape, B> = {
302
253
 
303
254
  /**
304
255
  * One comparison VALUE: op plus its operands, raw — the runtime
305
- * representation carries the operand types, so `.where`'s environment
306
- * check and the params inference both read the value itself (no phantom).
256
+ * representation carries the operands (variable references included), so
257
+ * `.where`'s judgment and the params inference both read the value itself.
307
258
  * `mask` is populated exactly for `allen`.
308
259
  */
309
260
  interface Cmp<Op extends CmpKind, L, R, M = undefined> {
@@ -324,9 +275,9 @@ interface Tree<Ch extends readonly AnyTreeChild[]> {
324
275
  /**
325
276
  * One negated-atom VALUE — negation is a position in the rule (anti-join
326
277
  * over sets, no null trick): a binding satisfies it iff NO fact matches.
327
- * Its variables must be positively bound in the rule — environment
328
- * membership at `.where` IS the safety rule, a compile error before it is
329
- * the engine's refusal.
278
+ * Its variables must be positively bound in the rule — a construction-time
279
+ * wall (BOUNDNESS is invisible to the type tier), before the engine's own
280
+ * refusal.
330
281
  */
331
282
  interface NotAtom<R extends MatchOwner, B> {
332
283
  readonly cond: "not"
@@ -334,6 +285,35 @@ interface NotAtom<R extends MatchOwner, B> {
334
285
  readonly bindings: B
335
286
  }
336
287
 
288
+ /**
289
+ * A recursive predicate as a NEGATION target — the structural half of the
290
+ * rec reference (`data` carries rules, never fields, so an EDB or closed
291
+ * owner can never match it and the `not()` overloads stay disjoint).
292
+ */
293
+ interface RecTarget {
294
+ readonly name: string
295
+ readonly data: RecData
296
+ readonly [inferred]?: { readonly params: ParamsRecord; readonly head: HeadShapeOf }
297
+ }
298
+
299
+ /** The head signature a threaded rec target carries (`undefined` before its first rule seals one). */
300
+ type HeadShapeOf = Readonly<Record<string, ClassedField>> | undefined
301
+
302
+ /**
303
+ * One negated FINISHED-STRATUM atom — negation OF a lower stratum is
304
+ * engine-legal (the strata judge refuses only negation *through* a cycle:
305
+ * a finished set is what keeps the operator monotone), and this value is
306
+ * its one spelling: `r.not(reach, { c })` in an output rule rejects every
307
+ * binding the finished stratum extends, through the engine's anti-probe.
308
+ * Binds nothing, only rejects — every variable it names must be positively
309
+ * bound in the rule (the same safety rule as EDB negation).
310
+ */
311
+ interface NotIdbAtom<Target extends RecTarget, B> {
312
+ readonly cond: "notIdb"
313
+ readonly target: Target
314
+ readonly bindings: B
315
+ }
316
+
337
317
  /** Any comparison value. */
338
318
  type AnyCmp = Cmp<CmpKind, unknown, unknown, unknown>
339
319
 
@@ -343,23 +323,26 @@ type AnyTreeChild = AnyCmp | Tree<readonly AnyTreeChild[]>
343
323
  /** Any negated-atom value. */
344
324
  type AnyNotAtom = NotAtom<MatchOwner, unknown>
345
325
 
346
- /** Any `.where` input: a comparison, a condition tree, or a negated atom. */
347
- type AnyCond = AnyCmp | Tree<readonly AnyTreeChild[]> | AnyNotAtom
326
+ /** Any negated finished-stratum value. */
327
+ type AnyNotIdbAtom = NotIdbAtom<RecTarget, unknown>
328
+
329
+ /** Any `.where` input: a comparison, a condition tree, or a negated atom (EDB, closed, or finished stratum). */
330
+ type AnyCond = AnyCmp | Tree<readonly AnyTreeChild[]> | AnyNotAtom | AnyNotIdbAtom
348
331
 
349
332
  /** What `eq`'s right side accepts (`ParamSet` is `Eq`-only — the IR's rule). */
350
- type EqRight = Var<string> | Param<string> | SetParam<string> | bigint | string | boolean | Uint8Array | IntervalValue
333
+ type EqRight = AnyVar | Param<string> | SetParam<string> | bigint | string | boolean | Uint8Array | IntervalValue
351
334
 
352
335
  /** What `ne`'s right side accepts. */
353
- type NeRight = Var<string> | Param<string> | bigint | string | boolean | Uint8Array | IntervalValue
336
+ type NeRight = AnyVar | Param<string> | bigint | string | boolean | Uint8Array | IntervalValue
354
337
 
355
338
  /** One side of an order comparison: orderable terms only (the IR's comparison rules). */
356
- type OrderSide = Var<string> | Param<string> | Duration<string> | bigint
339
+ type OrderSide = AnyVar | Param<string> | Duration | bigint
357
340
 
358
341
  /** The point side of `pointIn`. */
359
- type PointSide = Var<string> | Param<string> | bigint
342
+ type PointSide = AnyVar | Param<string> | bigint
360
343
 
361
344
  /** The interval side of `pointIn`/`allen`. */
362
- type IntervalSide = Var<string> | Param<string> | IntervalValue
345
+ type IntervalSide = AnyVar | Param<string> | IntervalValue
363
346
 
364
347
  /** Builds one comparison value. */
365
348
  function comparison<Op extends CmpKind, L, R, M>(op: Op, lhs: L, rhs: R, mask: M): Cmp<Op, L, R, M> {
@@ -381,17 +364,17 @@ function assertTermSide(op: string, lhs: unknown, rhs: unknown): void {
381
364
 
382
365
  /**
383
366
  * The equality comparison (`ir::CmpOp::Eq`) — a bound variable against a
384
- * variable (var-to-var unification, domain-equal by the environment
385
- * check), a param (typed by the variable), an ∈-set param (`Eq`-only, the
386
- * IR's set rule), or a bare literal of the variable's own value type.
387
- * Prefer direct placement in `match` where punning applies.
367
+ * variable (var-to-var unification, class-equal by the join judgment), a
368
+ * param (typed by the variable), an ∈-set param (`Eq`-only), or a bare
369
+ * literal of the variable's own value type. Prefer direct placement in
370
+ * `match` where punning applies.
388
371
  */
389
- function eq<L extends Var<string>, const R extends EqRight>(left: L, right: R): Cmp<"eq", L, R> {
372
+ function eq<L extends AnyVar, const R extends EqRight>(left: L, right: R): Cmp<"eq", L, R> {
390
373
  return comparison("eq", left, right, undefined)
391
374
  }
392
375
 
393
376
  /** Typed disequality (`ir::CmpOp::Ne`). "Not in set" has no operator — write a negated atom. */
394
- function ne<L extends Var<string>, const R extends NeRight>(left: L, right: R): Cmp<"ne", L, R> {
377
+ function ne<L extends AnyVar, const R extends NeRight>(left: L, right: R): Cmp<"ne", L, R> {
395
378
  return comparison("ne", left, right, undefined)
396
379
  }
397
380
 
@@ -429,12 +412,8 @@ function ge<const L extends OrderSide, const R extends OrderSide>(left: L, right
429
412
  * Point membership as a predicate (`ir::CmpOp::PointIn`) — THE one
430
413
  * spelling: `pointIn(t, w)` holds iff `w.start ≤ t < w.end`. The IR
431
414
  * orders the operands interval-left, point-right; the value stores them
432
- * that way whatever the surface argument order (a literal `span(...)`
433
- * interval operand is legal and tags by the point sibling's element
434
- * domain — the bug-hunt fix, now also a type-level guarantee).
435
- * Interval ⊇ interval is NOT this operator; that predicate is
436
- * `allen(a, ALLEN.covers, b)` — the name `covers` belongs to the Allen
437
- * roster alone (the canonical-utterance law: one meaning, one spelling).
415
+ * that way whatever the surface argument order. Interval ⊇ interval is NOT
416
+ * this operator; that predicate is `allen(a, ALLEN.covers, b)`.
438
417
  */
439
418
  function pointIn<const P extends PointSide, const I extends IntervalSide>(point: P, interval: I): Cmp<"pointIn", I, P> {
440
419
  assertTermSide("pointIn", point, interval)
@@ -444,17 +423,14 @@ function pointIn<const P extends PointSide, const I extends IntervalSide>(point:
444
423
  /**
445
424
  * The 13-bit mask range: bits above the low 13 are unrepresentable in the
446
425
  * engine's `AllenMask` (`bumbledb/crates/bumbledb/src/allen.rs`:
447
- * `AllenMask::new` refuses them) — the check here is the same boundary,
448
- * moved to construction where the message can name the constants.
426
+ * `AllenMask::new` refuses them).
449
427
  */
450
428
  const ALLEN_ALL_BITS = (1 << 13) - 1
451
429
 
452
430
  /**
453
431
  * The Allen coordinate system's named constants — the 13 basics in the
454
- * engine's palindromic bit order (bit i = basic i:
455
- * `bumbledb/crates/bumbledb/src/allen.rs`, a specified representation)
456
- * plus the workload composites, values identical to the engine's. Compose
457
- * with `|`: `ALLEN.before | ALLEN.meets`.
432
+ * engine's palindromic bit order plus the workload composites, values
433
+ * identical to the engine's. Compose with `|`: `ALLEN.before | ALLEN.meets`.
458
434
  */
459
435
  const ALLEN = Object.freeze({
460
436
  before: 1 << 0,
@@ -484,9 +460,7 @@ const ALLEN = Object.freeze({
484
460
  * THE interval-pair comparison (`ir::CmpOp::Allen`): two interval terms of
485
461
  * one element type, satisfied iff the pair's classification is in the
486
462
  * 13-bit mask — a literal built from the `ALLEN` constants, or a mask
487
- * parameter (`r.maskParam`). Vacuous masks (empty/full) are the engine's
488
- * two distinct typed rejections; nothing is pre-judged here beyond the
489
- * representable bit range.
463
+ * parameter (`r.maskParam`).
490
464
  */
491
465
  function allen<const A extends IntervalSide, const M extends number | MaskParam<string>, const B extends IntervalSide>(
492
466
  left: A,
@@ -515,148 +489,193 @@ function and<const C extends readonly AnyTreeChild[]>(...children: C): Tree<C> {
515
489
  /**
516
490
  * Disjunction node of the input condition grammar (`ConditionTree::Or`) —
517
491
  * the one place the surface admits a nested OR; validation distributes it
518
- * to DNF rules engine-side (OR is data or it is nothing). `Or([])` keeps
519
- * its algebraic reading (false: the rule denotes nothing).
492
+ * to DNF rules engine-side. `Or([])` keeps its algebraic reading (false).
520
493
  */
521
494
  function or<const C extends readonly AnyTreeChild[]>(...children: C): Tree<C> {
522
495
  return Object.freeze({ cond: "tree", op: "or", children: Object.freeze(children) })
523
496
  }
524
497
 
525
498
  /**
526
- * Negation — anti-join over sets: `not(Rel, { field: r.var("x"), ... })`
499
+ * Negation — anti-join over sets: `not(Rel, { field: someVar, ... })`
527
500
  * rejects every binding some matching fact extends. A negated atom binds
528
501
  * nothing, only rejects: every variable it names must be positively bound
529
- * in the rule, which `.where`'s environment check makes a COMPILE error
530
- * (the engine's safety refusal stands behind it). A CLOSED owner is legal
531
- * here too — the engine folds a resolvable negated closed atom to the
532
- * COMPLEMENT of its member set (domain-witness guarded), and the SDK's
533
- * negation rules apply to it unchanged.
502
+ * in the rule, a construction-time wall (the engine's safety refusal stands
503
+ * behind it). A CLOSED owner is legal here too — and so is a FINISHED
504
+ * STRATUM: `not(reach, { c })` in an output rule negates the rec's
505
+ * finished set (a named record over its head keys, variables only — the
506
+ * same wall `idb()` holds), the one spelling of the engine-legal
507
+ * complement query (`(n) | Node(id: n), !reach(n);` on the Rust surface).
534
508
  */
535
- function not<R extends MatchOwner, const B extends MatchShape<MatchFields<R>>>(
536
- relation: R,
509
+ function not<R extends MatchOwner, const B extends MatchShape<MatchFields<R>>>(relation: R, bindings: B): NotAtom<R, B>
510
+ function not<Target extends RecTarget, const B extends Readonly<Record<string, AnyVar>>>(
511
+ target: Target,
537
512
  bindings: B
538
- ): NotAtom<R, B> {
539
- const value: NotAtom<R, B> = { cond: "not", relation, bindings }
540
- return Object.freeze(value)
513
+ ): NotIdbAtom<Target, B>
514
+ function not(
515
+ relation: MatchOwner | RecTarget,
516
+ bindings: Readonly<Record<string, unknown>>
517
+ ): NotAtom<MatchOwner, unknown> | NotIdbAtom<RecTarget, unknown> {
518
+ if (isRecTarget(relation)) {
519
+ return Object.freeze({ cond: "notIdb" as const, target: relation, bindings })
520
+ }
521
+ return Object.freeze({ cond: "not" as const, relation, bindings })
541
522
  }
542
523
 
543
524
  /**
544
- * Whether a var name is bound in the environment at an orderable (u64/i64)
545
- * field. A CLOSED reference is excluded even though its kind is `u64`: a
546
- * vocabulary's declaration-id order is an accident, not semantics
547
- * (`docs/architecture/10-data-model.md` § orderability — order on it is
548
- * refused exactly as the enum's ordinal order was), so every
549
- * order-comparison and fold position refuses closed-bound terms — this
550
- * judgment is the one gate they all read, and the construction-time
551
- * validations in `#query/lower.ts` are its runtime twin.
525
+ * THE negation-target discriminant: a rec's runtime data carries its rules,
526
+ * a relation's its fields (and a closed relation's its handle roster) — the
527
+ * shapes are disjoint by construction, so the dispatch is total.
552
528
  */
553
- type OrderVarOk<Env extends EnvShape, N extends string> = N extends keyof Env
554
- ? Env[N]["field"] extends { readonly closed: ClosedRoster }
555
- ? false
556
- : Env[N]["field"]["kind"] extends "u64" | "i64"
557
- ? true
558
- : false
559
- : false
529
+ function isRecTarget(value: MatchOwner | RecTarget): value is RecTarget {
530
+ return "rules" in value.data
531
+ }
560
532
 
561
- /** Whether a var name is bound at an interval field. */
562
- type IntervalVarOk<Env extends EnvShape, N extends string> = N extends keyof Env
563
- ? Env[N]["field"]["kind"] extends "interval"
533
+ /**
534
+ * Whether a variable's OWN field is orderable (u64/i64). A CLOSED reference
535
+ * is excluded even though its kind is `u64`: a vocabulary's declaration-id
536
+ * order is an accident, not semantics (`docs/architecture/10-data-model.md`
537
+ * § orderability), so every order-comparison and fold position refuses
538
+ * closed-bound terms — this judgment is the one gate they all read, and the
539
+ * construction-time validations in `#query/lower.ts` are its runtime twin.
540
+ */
541
+ type OrderVarOk<V extends AnyVar> = V["field"] extends { readonly closed: ClosedRoster }
542
+ ? false
543
+ : V["field"]["kind"] extends "u64" | "i64"
564
544
  ? true
565
545
  : false
566
- : false
567
546
 
568
- /** One order-comparison side's judgment against the environment. */
569
- type OrderSideOk<Env extends EnvShape, T> =
570
- T extends Var<infer N extends string>
571
- ? OrderVarOk<Env, N>
572
- : T extends Duration<infer N extends string>
573
- ? IntervalVarOk<Env, N>
574
- : true
547
+ /** Whether a variable's OWN field is interval-typed. */
548
+ type IntervalVarOk<V extends AnyVar> = V["field"]["kind"] extends "interval" ? true : false
549
+
550
+ /** One order-comparison side's judgment (off the term's own field). */
551
+ type OrderSideOk<T> = T extends AnyVar
552
+ ? OrderVarOk<T>
553
+ : T extends Duration<infer V extends AnyVar>
554
+ ? IntervalVarOk<V>
555
+ : true
575
556
 
576
557
  /** One point side's judgment. */
577
- type PointSideOk<Env extends EnvShape, T> = T extends Var<infer N extends string> ? OrderVarOk<Env, N> : true
558
+ type PointSideOk<T> = T extends AnyVar ? OrderVarOk<T> : true
578
559
 
579
560
  /** One interval side's judgment. */
580
- type IntervalSideOk<Env extends EnvShape, T> = T extends Var<infer N extends string> ? IntervalVarOk<Env, N> : true
581
-
582
- /** The `eq`/`ne` judgment: left var bound; right joins it (class-equal var, param, or an exact-type literal). */
583
- type EqOk<Env extends EnvShape, L, R> =
584
- L extends Var<infer N extends string>
585
- ? N extends keyof Env
586
- ? R extends Var<infer M extends string>
587
- ? M extends keyof Env
588
- ? JoinOk<Env[N], Env[M]>
589
- : false
590
- : R extends Param<string> | SetParam<string>
591
- ? true
592
- : [R] extends [Infer<Env[N]["field"]>]
593
- ? true
594
- : false
561
+ type IntervalSideOk<T> = T extends AnyVar ? IntervalVarOk<T> : true
562
+
563
+ /** The `eq`/`ne` judgment: var-var joins by mint slot; var-literal is exact-typed by the var's own field. */
564
+ type EqOk<Classes extends SchemaClasses, L, R> = L extends AnyVar
565
+ ? R extends AnyVar
566
+ ? JoinOk<MintSlotOf<Classes, L>, MintSlotOf<Classes, R>> extends true
567
+ ? true
595
568
  : false
596
- : false
569
+ : R extends Param<string> | SetParam<string>
570
+ ? true
571
+ : [R] extends [Infer<L["field"]>]
572
+ ? true
573
+ : false
574
+ : false
597
575
 
598
- /** One negated-atom binding's judgment: a var must be positively bound (safety) AND class-equal. */
599
- type NotBindingOk<Env extends EnvShape, S extends ClassedField, T> =
600
- T extends Var<infer N extends string> ? (N extends keyof Env ? JoinOk<Env[N], S> : false) : true
576
+ /** One negated-atom binding's judgment: a variable must be class-equal (boundness is a runtime wall). */
577
+ type NotBindingOk<Classes extends SchemaClasses, S extends ClassedField, T> = T extends AnyVar
578
+ ? JoinOk<MintSlotOf<Classes, T>, S> extends true
579
+ ? true
580
+ : false
581
+ : true
601
582
 
602
583
  /** The whole negated atom's judgment (`CR` — the negated relation's class record off the schema class map). */
603
- type NotOk<Env extends EnvShape, F extends FieldsShape, CR, B> = false extends {
604
- [K in keyof B]: NotBindingOk<Env, SlotAt<F, CR, K>, B[K]>
584
+ type NotOk<Classes extends SchemaClasses, F extends FieldsShape, CR, B> = false extends {
585
+ [K in keyof B]: NotBindingOk<Classes, SlotAt<F, CR, K>, B[K]>
605
586
  }[keyof B]
606
587
  ? false
607
588
  : true
608
589
 
590
+ /** Reads a rec target's sealed head signature off its inference slot (`undefined` on an unthreaded handle). */
591
+ type RecHeadOf<T> = T extends { readonly [inferred]?: infer S }
592
+ ? Exclude<S, undefined> extends { readonly head: infer H }
593
+ ? H
594
+ : undefined
595
+ : undefined
596
+
597
+ /** Reads a rec target's params record off its inference slot. */
598
+ type RecParamsOf<T> = T extends { readonly [inferred]?: infer S }
599
+ ? Exclude<S, undefined> extends { readonly params: infer P }
600
+ ? P
601
+ : never
602
+ : never
603
+
604
+ /** One negated finished-stratum position's judgment: a variable, class-equal to its head slot when the head is carried. */
605
+ type NotIdbBindingOk<Classes extends SchemaClasses, HeadSlot, V> = V extends AnyVar
606
+ ? HeadSlot extends ClassedField
607
+ ? JoinOk<HeadSlot, MintSlotOf<Classes, V>> extends true
608
+ ? true
609
+ : false
610
+ : true
611
+ : false
612
+
609
613
  /**
610
- * One condition's judgment against the rule environment — the type-level
611
- * twin of the engine's comparison roster: class-equal joins (off the
612
- * schema type's class map), orderable order sides (an interval var under a
613
- * non-`pointIn` op is exactly here refused), kind-correct
614
- * `pointIn`/`allen` sides, and negated-atom safety (the negated
615
- * relation's class record is resolved through `Classes` by its name). The
616
- * leading `[AnyTreeChild] extends [C]` arm is the recursion's base case:
617
- * at an UNRESOLVED constraint (the whole condition union — or a tree's
618
- * child union, which is the union itself) the judgment is vacuously true —
619
- * without it the constraint instantiation recurses into itself.
614
+ * The whole negated finished-stratum atom's judgment — the negation twin of
615
+ * the `idb()` chain's `CheckIdbBindings`: when the target carries its head
616
+ * (a threaded rec handle), the bindings record's key set must EXACTLY equal
617
+ * the head's and each variable must be class-equal to its head slot; an
618
+ * unthreaded handle still takes variables only.
620
619
  */
621
- type CondOkBool<Env extends EnvShape, Classes extends SchemaClasses, C> = [AnyTreeChild] extends [C]
620
+ type NotIdbOk<Classes extends SchemaClasses, Head, B> =
621
+ Head extends Readonly<Record<string, ClassedField>>
622
+ ? [keyof B] extends [keyof Head]
623
+ ? [keyof Head] extends [keyof B]
624
+ ? false extends { [K in keyof B]: NotIdbBindingOk<Classes, Head[K & keyof Head], B[K]> }[keyof B]
625
+ ? false
626
+ : true
627
+ : false
628
+ : false
629
+ : false extends { [K in keyof B]: B[K] extends AnyVar ? true : false }[keyof B]
630
+ ? false
631
+ : true
632
+
633
+ /**
634
+ * One condition's judgment — the type-level twin of the engine's comparison
635
+ * roster: class-equal joins (off the mint slots), orderable order sides (an
636
+ * interval var under a non-`pointIn` op is exactly here refused),
637
+ * kind-correct `pointIn`/`allen` sides, and negated-atom class safety. The
638
+ * leading `[AnyTreeChild] extends [C]` arm is the recursion's base case.
639
+ */
640
+ type CondOkBool<Classes extends SchemaClasses, C> = [AnyTreeChild] extends [C]
622
641
  ? true
623
642
  : C extends Cmp<infer Op, infer L, infer R, unknown>
624
643
  ? Op extends "eq" | "ne"
625
- ? EqOk<Env, L, R>
644
+ ? EqOk<Classes, L, R>
626
645
  : Op extends "lt" | "le" | "gt" | "ge"
627
- ? [OrderSideOk<Env, L>, OrderSideOk<Env, R>] extends [true, true]
646
+ ? [OrderSideOk<L>, OrderSideOk<R>] extends [true, true]
628
647
  ? true
629
648
  : false
630
649
  : Op extends "pointIn"
631
- ? [IntervalSideOk<Env, L>, PointSideOk<Env, R>] extends [true, true]
650
+ ? [IntervalSideOk<L>, PointSideOk<R>] extends [true, true]
632
651
  ? true
633
652
  : false
634
653
  : Op extends "allen"
635
- ? [IntervalSideOk<Env, L>, IntervalSideOk<Env, R>] extends [true, true]
654
+ ? [IntervalSideOk<L>, IntervalSideOk<R>] extends [true, true]
636
655
  ? true
637
656
  : false
638
657
  : false
639
658
  : C extends Tree<infer Ch extends readonly AnyTreeChild[]>
640
- ? false extends CondOkBool<Env, Classes, Ch[number]>
659
+ ? false extends CondOkBool<Classes, Ch[number]>
641
660
  ? false
642
661
  : true
643
- : C extends NotAtom<infer R extends MatchOwner, infer B>
644
- ? NotOk<Env, MatchFields<R>, ClassRecordOf<Classes, R["name"]>, B>
645
- : false
662
+ : C extends NotIdbAtom<infer T extends RecTarget, infer B>
663
+ ? NotIdbOk<Classes, RecHeadOf<T>, B>
664
+ : C extends NotAtom<infer R extends MatchOwner, infer B>
665
+ ? NotOk<Classes, MatchFields<R>, ClassRecordOf<Classes, R["name"]>, B>
666
+ : false
646
667
 
647
668
  /** The validated `.where` argument (intersect with the inferred condition type). */
648
- type CheckCond<Env extends EnvShape, Classes extends SchemaClasses, C> =
649
- CondOkBool<Env, Classes, C> extends true ? C : never
650
-
651
- /** The `eq`/`ne` params contribution: the param typed by the left variable's field. */
652
- type EqParams<Env extends EnvShape, L, R> =
653
- L extends Var<infer N extends string>
654
- ? R extends Param<infer P extends string>
655
- ? { readonly [Q in P]: Infer<Env[N & keyof Env]["field"]> }
656
- : R extends SetParam<infer P extends string>
657
- ? { readonly [Q in P]: readonly Infer<Env[N & keyof Env]["field"]>[] }
658
- : never
659
- : never
669
+ type CheckCond<Classes extends SchemaClasses, C> = CondOkBool<Classes, C> extends true ? C : never
670
+
671
+ /** The `eq`/`ne` params contribution: the param typed by the left variable's own field. */
672
+ type EqParams<L, R> = L extends AnyVar
673
+ ? R extends Param<infer P extends string>
674
+ ? { readonly [Q in P]: Infer<L["field"]> }
675
+ : R extends SetParam<infer P extends string>
676
+ ? { readonly [Q in P]: readonly Infer<L["field"]>[] }
677
+ : never
678
+ : never
660
679
 
661
680
  /** An order side's params contribution (order params are always `bigint`). */
662
681
  type OrderSideParams<T> = T extends Param<infer P extends string> ? { readonly [Q in P]: bigint } : never
@@ -670,14 +689,13 @@ type MaskParams<M> = M extends MaskParam<infer P extends string> ? { readonly [Q
670
689
  /**
671
690
  * One condition's params-object fragments (a union; the rule builder folds
672
691
  * them into the inferred `Params` record) — every param typed by its use.
673
- * The leading arm is the same base case as {@link CondOkBool}'s: the
674
- * unresolved constraint contributes nothing.
692
+ * The leading arm is the same base case as {@link CondOkBool}'s.
675
693
  */
676
- type CondParams<Env extends EnvShape, C> = [AnyTreeChild] extends [C]
694
+ type CondParams<C> = [AnyTreeChild] extends [C]
677
695
  ? never
678
696
  : C extends Cmp<infer Op, infer L, infer R, infer M>
679
697
  ? Op extends "eq" | "ne"
680
- ? EqParams<Env, L, R>
698
+ ? EqParams<L, R>
681
699
  : Op extends "lt" | "le" | "gt" | "ge"
682
700
  ? OrderSideParams<L> | OrderSideParams<R>
683
701
  : Op extends "pointIn"
@@ -686,16 +704,18 @@ type CondParams<Env extends EnvShape, C> = [AnyTreeChild] extends [C]
686
704
  ? IntervalSideParams<L> | IntervalSideParams<R> | MaskParams<M>
687
705
  : never
688
706
  : C extends Tree<infer Ch extends readonly AnyTreeChild[]>
689
- ? CondParams<Env, Ch[number]>
690
- : C extends NotAtom<infer R extends MatchOwner, infer B>
691
- ? BindParams<MatchFields<R>, B>
692
- : never
707
+ ? CondParams<Ch[number]>
708
+ : C extends NotIdbAtom<infer T extends RecTarget, unknown>
709
+ ? RecParamsOf<T>
710
+ : C extends NotAtom<infer R extends MatchOwner, infer B>
711
+ ? BindParams<MatchFields<R>, B>
712
+ : never
693
713
 
694
714
  /** The flattened params record one bindings record contributes. */
695
715
  type BindParamsShape<F extends FieldsShape, B> = ShapeOf<BindParams<F, B>>
696
716
 
697
717
  /** The flattened params record one condition contributes. */
698
- type CondParamsShape<Env extends EnvShape, C> = ShapeOf<CondParams<Env, C>>
718
+ type CondParamsShape<C> = ShapeOf<CondParams<C>>
699
719
 
700
720
  export type {
701
721
  AggData,
@@ -704,7 +724,6 @@ export type {
704
724
  AnyNotAtom,
705
725
  AnyTreeChild,
706
726
  AtomData,
707
- BindEnv,
708
727
  BindingEntry,
709
728
  BindingInput,
710
729
  BindingTermData,
@@ -720,6 +739,8 @@ export type {
720
739
  CondOkBool,
721
740
  CondParams,
722
741
  CondParamsShape,
742
+ FindColumn,
743
+ FindEntryData,
723
744
  IntervalSide,
724
745
  IntervalVarOk,
725
746
  MaskData,
@@ -727,15 +748,16 @@ export type {
727
748
  MatchOwner,
728
749
  MatchShape,
729
750
  NotAtom,
751
+ NotIdbAtom,
730
752
  OrderSide,
731
753
  OrderVarOk,
732
754
  ParamUse,
733
755
  PointSide,
734
756
  RecData,
757
+ RecTarget,
735
758
  RuleData,
736
759
  RuleItem,
737
- SelectColumn,
738
- SelectEntryData,
760
+ SlotAt,
739
761
  Tree,
740
762
  TreeData
741
763
  }