@hviana/sema 0.2.6 → 0.2.7

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 (131) hide show
  1. package/dist/example/demo.d.ts +1 -0
  2. package/dist/example/demo.js +39 -0
  3. package/dist/example/train_base.d.ts +87 -0
  4. package/dist/example/train_base.js +2252 -0
  5. package/dist/src/alphabet.d.ts +7 -0
  6. package/dist/src/alphabet.js +33 -0
  7. package/dist/src/alu/src/alu.d.ts +185 -0
  8. package/dist/src/alu/src/alu.js +440 -0
  9. package/dist/src/alu/src/expr.d.ts +61 -0
  10. package/dist/src/alu/src/expr.js +318 -0
  11. package/dist/src/alu/src/index.d.ts +11 -0
  12. package/dist/src/alu/src/index.js +19 -0
  13. package/dist/src/alu/src/kernel-arith.d.ts +16 -0
  14. package/dist/src/alu/src/kernel-arith.js +264 -0
  15. package/dist/src/alu/src/kernel-bits.d.ts +19 -0
  16. package/dist/src/alu/src/kernel-bits.js +152 -0
  17. package/dist/src/alu/src/kernel-logic.d.ts +4 -0
  18. package/dist/src/alu/src/kernel-logic.js +60 -0
  19. package/dist/src/alu/src/kernel-nd.d.ts +3 -0
  20. package/dist/src/alu/src/kernel-nd.js +208 -0
  21. package/dist/src/alu/src/kernel-numeric.d.ts +54 -0
  22. package/dist/src/alu/src/kernel-numeric.js +366 -0
  23. package/dist/src/alu/src/operation.d.ts +168 -0
  24. package/dist/src/alu/src/operation.js +189 -0
  25. package/dist/src/alu/src/parser.d.ts +221 -0
  26. package/dist/src/alu/src/parser.js +577 -0
  27. package/dist/src/alu/src/resonance.d.ts +55 -0
  28. package/dist/src/alu/src/resonance.js +126 -0
  29. package/dist/src/alu/src/text.d.ts +31 -0
  30. package/dist/src/alu/src/text.js +73 -0
  31. package/dist/src/alu/src/value.d.ts +109 -0
  32. package/dist/src/alu/src/value.js +300 -0
  33. package/dist/src/alu/test/alu.test.d.ts +1 -0
  34. package/dist/src/alu/test/alu.test.js +764 -0
  35. package/dist/src/bytes.d.ts +14 -0
  36. package/dist/src/bytes.js +59 -0
  37. package/dist/src/canon.d.ts +26 -0
  38. package/dist/src/canon.js +57 -0
  39. package/dist/src/config.d.ts +111 -0
  40. package/dist/src/config.js +91 -0
  41. package/dist/src/derive/src/deduction.d.ts +125 -0
  42. package/dist/src/derive/src/deduction.js +155 -0
  43. package/dist/src/derive/src/index.d.ts +7 -0
  44. package/dist/src/derive/src/index.js +11 -0
  45. package/dist/src/derive/src/priority-queue.d.ts +20 -0
  46. package/dist/src/derive/src/priority-queue.js +73 -0
  47. package/dist/src/derive/src/rewrite.d.ts +56 -0
  48. package/dist/src/derive/src/rewrite.js +100 -0
  49. package/dist/src/derive/src/trie.d.ts +90 -0
  50. package/dist/src/derive/src/trie.js +217 -0
  51. package/dist/src/derive/test/derive.test.d.ts +1 -0
  52. package/dist/src/derive/test/derive.test.js +122 -0
  53. package/dist/src/extension.d.ts +37 -0
  54. package/dist/src/extension.js +7 -0
  55. package/dist/src/geometry.d.ts +202 -0
  56. package/dist/src/geometry.js +575 -0
  57. package/dist/src/index.d.ts +16 -0
  58. package/dist/src/index.js +18 -0
  59. package/dist/src/ingest-cache.d.ts +41 -0
  60. package/dist/src/ingest-cache.js +161 -0
  61. package/dist/src/mind/articulation.d.ts +6 -0
  62. package/dist/src/mind/articulation.js +99 -0
  63. package/dist/src/mind/attention.d.ts +400 -0
  64. package/dist/src/mind/attention.js +1763 -0
  65. package/dist/src/mind/bridge.d.ts +30 -0
  66. package/dist/src/mind/bridge.js +569 -0
  67. package/dist/src/mind/canonical.d.ts +29 -0
  68. package/dist/src/mind/canonical.js +88 -0
  69. package/dist/src/mind/graph-search.d.ts +285 -0
  70. package/dist/src/mind/graph-search.js +956 -0
  71. package/dist/src/mind/index.d.ts +7 -0
  72. package/dist/src/mind/index.js +5 -0
  73. package/dist/src/mind/junction.d.ts +124 -0
  74. package/dist/src/mind/junction.js +317 -0
  75. package/dist/src/mind/learning.d.ts +47 -0
  76. package/dist/src/mind/learning.js +248 -0
  77. package/dist/src/mind/match.d.ts +126 -0
  78. package/dist/src/mind/match.js +441 -0
  79. package/dist/src/mind/mechanisms/alu.d.ts +4 -0
  80. package/dist/src/mind/mechanisms/alu.js +36 -0
  81. package/dist/src/mind/mechanisms/cast.d.ts +89 -0
  82. package/dist/src/mind/mechanisms/cast.js +716 -0
  83. package/dist/src/mind/mechanisms/confluence.d.ts +24 -0
  84. package/dist/src/mind/mechanisms/confluence.js +225 -0
  85. package/dist/src/mind/mechanisms/cover.d.ts +6 -0
  86. package/dist/src/mind/mechanisms/cover.js +203 -0
  87. package/dist/src/mind/mechanisms/extraction.d.ts +67 -0
  88. package/dist/src/mind/mechanisms/extraction.js +387 -0
  89. package/dist/src/mind/mechanisms/recall.d.ts +13 -0
  90. package/dist/src/mind/mechanisms/recall.js +325 -0
  91. package/dist/src/mind/mind.d.ts +276 -0
  92. package/dist/src/mind/mind.js +572 -0
  93. package/dist/src/mind/pipeline-mechanism.d.ts +142 -0
  94. package/dist/src/mind/pipeline-mechanism.js +213 -0
  95. package/dist/src/mind/pipeline.d.ts +20 -0
  96. package/dist/src/mind/pipeline.js +217 -0
  97. package/dist/src/mind/primitives.d.ts +70 -0
  98. package/dist/src/mind/primitives.js +287 -0
  99. package/dist/src/mind/rationale.d.ts +139 -0
  100. package/dist/src/mind/rationale.js +163 -0
  101. package/dist/src/mind/reasoning.d.ts +34 -0
  102. package/dist/src/mind/reasoning.js +240 -0
  103. package/dist/src/mind/recognition.d.ts +20 -0
  104. package/dist/src/mind/recognition.js +390 -0
  105. package/dist/src/mind/resonance.d.ts +23 -0
  106. package/dist/src/mind/resonance.js +0 -0
  107. package/dist/src/mind/trace.d.ts +15 -0
  108. package/dist/src/mind/trace.js +73 -0
  109. package/dist/src/mind/traverse.d.ts +113 -0
  110. package/dist/src/mind/traverse.js +568 -0
  111. package/dist/src/mind/types.d.ts +289 -0
  112. package/dist/src/mind/types.js +130 -0
  113. package/dist/src/rabitq-ivf/src/database.d.ts +113 -0
  114. package/dist/src/rabitq-ivf/src/database.js +201 -0
  115. package/dist/src/rabitq-ivf/src/index.d.ts +7 -0
  116. package/dist/src/rabitq-ivf/src/index.js +4 -0
  117. package/dist/src/rabitq-ivf/src/ivf.d.ts +200 -0
  118. package/dist/src/rabitq-ivf/src/ivf.js +1165 -0
  119. package/dist/src/rabitq-ivf/src/prng.d.ts +19 -0
  120. package/dist/src/rabitq-ivf/src/prng.js +36 -0
  121. package/dist/src/rabitq-ivf/src/rabitq.d.ts +95 -0
  122. package/dist/src/rabitq-ivf/src/rabitq.js +283 -0
  123. package/dist/src/sema.d.ts +31 -0
  124. package/dist/src/sema.js +63 -0
  125. package/dist/src/store-sqlite.d.ts +184 -0
  126. package/dist/src/store-sqlite.js +942 -0
  127. package/dist/src/store.d.ts +663 -0
  128. package/dist/src/store.js +1618 -0
  129. package/dist/src/vec.d.ts +31 -0
  130. package/dist/src/vec.js +109 -0
  131. package/package.json +1 -1
@@ -0,0 +1,88 @@
1
+ // canonical.ts — THE canonical-segmentation convention, defined once.
2
+ //
3
+ // The store's canonical reading of a byte stream — "the id of each single-byte
4
+ // leaf, chained into flat branches" — is a WRITE/READ CONTRACT split across
5
+ // four consumers that previously each re-implemented the chaining loop:
6
+ //
7
+ // WRITE side (training):
8
+ // • learning.indexSubSpans — interns sliding windows of the two
9
+ // {@link canonicalWindows} lengths over the stream's leaf ids;
10
+ // • learning.deposit — interns the WHOLE stream as one flat branch
11
+ // (via {@link leafIdPrefix}) so every deposit has a byte-level identity.
12
+ // READ side (inference):
13
+ // • recognition's canonical pass — chains leaf ids from every position and
14
+ // probes each growing prefix as a flat branch, up to {@link chainReach};
15
+ // • attention.canonicalChunkId — reads a chunk's window of leaf ids
16
+ // (via {@link leafIdRun}) and probes its prefixes for the best anchor.
17
+ // (geometry.knownPrefixLength is the same convention below the store layer,
18
+ // expressed through injected `leafAt`/`lookup` capabilities — it cannot
19
+ // import this module without inverting the dependency spine, so its header
20
+ // cross-references this file instead.)
21
+ //
22
+ // If the write side's windows or the read side's reach ever change, they must
23
+ // change HERE — a drift between them silently makes recognition stop finding
24
+ // what training indexed, which no type checker catches.
25
+ /** The two sliding-window lengths the WRITE side interns over a stream's leaf
26
+ * ids: W−1 and W (the river's grouping quantum and its off-by-one neighbour,
27
+ * so a form straddling a group boundary is reachable from either cut). */
28
+ export function canonicalWindows(W) {
29
+ return [W - 1, W];
30
+ }
31
+ /** The READ side's chain reach: how many leaf ids a canonical chain may grow
32
+ * to from one position — W², the deepest two-level composite the write side's
33
+ * windows can spell. */
34
+ export function chainReach(W) {
35
+ return W * W;
36
+ }
37
+ /** The id of the single-byte leaf at position `p`, or null when that byte was
38
+ * never interned. */
39
+ export function leafIdAt(ctx, bytes, p) {
40
+ return ctx.store.findLeaf(bytes.subarray(p, p + 1));
41
+ }
42
+ /** The leaf ids of the window `[from, to)`, or null the moment ANY byte in it
43
+ * is unknown — the all-or-nothing read {@link canonicalChunkId} anchors on. */
44
+ export function leafIdRun(ctx, bytes, from, to) {
45
+ const ids = [];
46
+ for (let i = from; i < to; i++) {
47
+ const lid = leafIdAt(ctx, bytes, i);
48
+ if (lid === null)
49
+ return null;
50
+ ids.push(lid);
51
+ }
52
+ return ids;
53
+ }
54
+ /** The leaf ids of the LONGEST KNOWN PREFIX of `bytes` — stops at the first
55
+ * unknown byte and returns what it has (possibly empty). The caller decides
56
+ * what a partial prefix means (deposit only interns the whole-stream flat
57
+ * branch when the prefix covers everything). */
58
+ export function leafIdPrefix(ctx, bytes) {
59
+ const ids = [];
60
+ for (let i = 0; i < bytes.length; i++) {
61
+ const lid = leafIdAt(ctx, bytes, i);
62
+ if (lid === null)
63
+ break;
64
+ ids.push(lid);
65
+ }
66
+ return ids;
67
+ }
68
+ /** The canonical W-window node ids of a byte stream, offset → id — the
69
+ * CONTENT-ADDRESSED IDENTITY of every W-sized slice, under which any content
70
+ * two deposits share IS the same node (hash-consing paid the comparison at
71
+ * write time). The read side of the {@link canonicalWindows} contract asked
72
+ * at every offset: a window over unknown bytes, or one never interned as a
73
+ * flat branch, has no identity and is skipped. Confluence's meet and CAST's
74
+ * frame detection both read shared/common content through this — never
75
+ * through a byte scan. */
76
+ export function windowIds(ctx, bytes) {
77
+ const W = ctx.space.maxGroup;
78
+ const out = new Map();
79
+ for (let off = 0; off + W <= bytes.length; off++) {
80
+ const ids = leafIdRun(ctx, bytes, off, off + W);
81
+ if (ids === null)
82
+ continue;
83
+ const wid = ctx.store.findBranch(ids);
84
+ if (wid !== null)
85
+ out.set(off, wid);
86
+ }
87
+ return out;
88
+ }
@@ -0,0 +1,285 @@
1
+ import type { Store } from "../store.js";
2
+ import type { GraphSearchHost } from "./types.js";
3
+ /** A recognised form: a span of the query that names a node already in the
4
+ * store. `payload` is that node id. */
5
+ export interface Site {
6
+ start: number;
7
+ end: number;
8
+ payload: number;
9
+ }
10
+ /** A perceived leaf of the query tree, carrying the node id it resolves to. */
11
+ export interface Leaf {
12
+ start: number;
13
+ end: number;
14
+ bytes: Uint8Array;
15
+ node: number | null;
16
+ }
17
+ /** A COMPUTED span: the result of applying a manual rule (an extension's
18
+ * operation — e.g. the `alu` extension's arithmetic) to a recognised stretch
19
+ * of the query. Every
20
+ * bit of the intelligence — recognising the operator (literally or by
21
+ * resonance), parsing the operands, evaluating the operation — is done by the
22
+ * caller (src/mind/pipeline.ts), which hands the search the finished result span; the search
23
+ * treats it exactly like any other recognised completion (a learned fact that
24
+ * happens to be computed rather than stored). `node` is the canonical id of
25
+ * the result bytes when the store already holds them, else undefined. */
26
+ export interface ComputedResult {
27
+ i: number;
28
+ j: number;
29
+ bytes: Uint8Array;
30
+ node?: number;
31
+ }
32
+ export type GItem = {
33
+ kind: "cover";
34
+ p: number;
35
+ } | {
36
+ kind: "form";
37
+ i: number;
38
+ j: number;
39
+ node: number;
40
+ via: boolean;
41
+ /** Set when this form was born by RECOMPOSING rewritten parts into a deeper
42
+ * learned whole (the fuse of ≥2 recognised completions that names an
43
+ * edge-bearing node). Its onward continuation is charged at MICRO, not
44
+ * STEP: once parts are recomposed into a learned form, following that form
45
+ * to its grounded answer is the recomposition completing — so the
46
+ * consolidated, more-explanatory reading wins over leaving the parts split.
47
+ * See {@link GraphSearch.fuse} and {@link GraphSearch.formRules}. */
48
+ rcmp?: boolean;
49
+ } | {
50
+ kind: "out";
51
+ i: number;
52
+ j: number;
53
+ bytes: Uint8Array;
54
+ cover: boolean;
55
+ rec: boolean;
56
+ node?: number;
57
+ /** Set only for a {@link ComputedResult} axiom (an extension's derived
58
+ * value, e.g. ALU arithmetic) — as opposed to a genuinely RECOGNISED
59
+ * learned form. Both set `rec: true` (a computation bridges the cover
60
+ * exactly like a learned terminal answer), but they mean different
61
+ * things for `i..j`'s WIDTH: a recognised form's query-span width is
62
+ * real evidence of how much of the query's meaning it accounts for
63
+ * (liftAnswer's half-dominance framing decision); a computed span's
64
+ * width is operand digit-count, uncorrelated with meaning ("1000 - 421"
65
+ * is wider than "15 * 7" only because the numbers are bigger, not
66
+ * because subtraction is more "the point" of its query). See
67
+ * {@link liftAnswer}. */
68
+ computed?: boolean;
69
+ };
70
+ export declare const STEP = 1;
71
+ export declare const CONCEPT = 10;
72
+ export declare const PASS = 1000;
73
+ /** The cheapest local cost in the ladder: a recognised completion bridging into
74
+ * the cover. Far below STEP, so connecting two recognised spans never disturbs
75
+ * the ordering — and, being the minimum per-position cost, it is the per-byte
76
+ * unit of the admissible search heuristic (see {@link GraphSearch.buildSearch}). */
77
+ export declare const MICRO = 0.001;
78
+ /** One chosen span of the cover, left to right. `node` is the graph node the
79
+ * span resolved to (when known) — for a recognised completion it is the chain's
80
+ * terminal node, the foothold the bridge walks edges from. */
81
+ export interface Seg {
82
+ i: number;
83
+ j: number;
84
+ bytes: Uint8Array;
85
+ rec: boolean;
86
+ node?: number;
87
+ /** See the `computed` field of the "out" {@link GItem} — set only for an
88
+ * extension's derived value, never a genuinely recognised learned form. */
89
+ computed?: boolean;
90
+ }
91
+ /** One rule application inside the cover's lightest derivation — the FINEST
92
+ * grain of Sema's core reasoning, one node of the adapted A*LD proof tree. `move`
93
+ * names which deduction rule fired (the reasoning act); `premises` and
94
+ * `conclusion` are the items it consumed and produced, each rendered as a
95
+ * positioned, possibly-node-bearing span; `cost` is the rule's local weight
96
+ * (STEP for a learned edge, CONCEPT for a synonym hop, 0 for a free fuse, …);
97
+ * `order` is its post-order position so a tracer can replay the proof in the
98
+ * order it was built (premises before conclusion). */
99
+ export interface DerivationStep {
100
+ order: number;
101
+ move: DerivationMove;
102
+ premises: DerivationItem[];
103
+ conclusion: DerivationItem;
104
+ cost: number;
105
+ /** The `order`s of the steps that produced this one's premises — the EXACT
106
+ * data-flow edges of the proof tree (a `bridge` names the `ground` whose
107
+ * `out` it crossed and the earlier `cover` it extended). A premise that is
108
+ * an axiom (a seed leaf/form/computed result, never a rule conclusion) has no
109
+ * producer and contributes no edge, so this lists only the derived premises —
110
+ * the finest dependency structure the inference holds. */
111
+ producers: number[];
112
+ }
113
+ /** A premise or conclusion of a {@link DerivationStep}, flattened from a {@link
114
+ * GItem} into the fields a rationale cares about. */
115
+ export interface DerivationItem {
116
+ kind: "cover" | "form" | "out";
117
+ /** `[i, j)` span for a form/out; for a cover item, `[p, p]`. */
118
+ span: [number, number];
119
+ /** The bytes an `out` carries (the only item kind that holds output bytes). */
120
+ bytes?: Uint8Array;
121
+ /** The graph node a form/out resolves to, when known. */
122
+ node?: number;
123
+ }
124
+ /** The reasoning act a derivation rule performs — the human name for which of
125
+ * {@link GraphSearch}'s rules fired, recovered from the rule's premise/
126
+ * conclusion shape (the rules carry no label, so this classifies by structure,
127
+ * the single place that maps rule geometry to a name). */
128
+ export type DerivationMove = "axiom" | "follow-edge" | "concept-hop" | "voice" | "ground" | "splice-connector" | "split" | "fuse" | "recompose" | "bridge" | "pool-vote" | "step";
129
+ /** The lightest-derivation search over the Sema graph. One instance binds the
130
+ * store, `maxGroup` (the fusible span ceiling), and the canonical
131
+ * {@link resolve} callback; {@link cover} then solves one query. */
132
+ export declare class GraphSearch {
133
+ private readonly store;
134
+ private readonly maxGroup;
135
+ /** The host whose capabilities the search consults: resolve (canonical node
136
+ * id of a byte span), recogniseSpan (content-addressed graph lookup for
137
+ * recursive completion), and chooseNext (distributional-evidence edge
138
+ * disambiguation when a recognised form has multiple continuations). */
139
+ private readonly host;
140
+ constructor(store: Store, maxGroup: number,
141
+ /** The host whose capabilities the search consults: resolve (canonical node
142
+ * id of a byte span), recogniseSpan (content-addressed graph lookup for
143
+ * recursive completion), and chooseNext (distributional-evidence edge
144
+ * disambiguation when a recognised form has multiple continuations). */
145
+ host: GraphSearchHost);
146
+ /** Explore the Sema graph for the lightest cover of the query and return its
147
+ * chosen spans left-to-right — WITH the derivation's total weight (the g
148
+ * value of the goal item, in the exported cost ladder), which think's
149
+ * grounding decider compares against the other mechanisms' candidates —
150
+ * or null if the query cannot be covered.
151
+ *
152
+ * The search runs on the query's tree leaves, not flat bytes — leaf-level
153
+ * cover axioms, recognised forms as graph entry points — and discovers
154
+ * cross-leaf forms by fusing adjacent fragments on demand (the only
155
+ * byte-processing it does, and only where a derivation needs it). When
156
+ * `substitutions` is given, recognised forms emit substitute bytes directly
157
+ * (cost 0) — articulation splicing the asker's wording in.
158
+ *
159
+ * Any learnt connector between two rewrites is spliced IN by the in-search
160
+ * connector rule (see {@link outRules}), so the returned spans already carry
161
+ * it — there is no post-pass. */
162
+ cover(queryLen: number, sites: ReadonlyArray<Site>, conceptTarget: ReadonlyMap<number, number>, leaves: ReadonlyArray<Leaf>, splits: ReadonlySet<number>, starts: ReadonlySet<number>, substitutions?: ReadonlyMap<number, Uint8Array>, connectors?: ReadonlyMap<string, Uint8Array>, computedResults?: ReadonlyArray<ComputedResult>,
163
+ /** When given, receives the lightest derivation's rule applications — the
164
+ * full adapted A*LD proof tree as classified {@link DerivationStep}s — for the TOP
165
+ * cover only (a recursive recompletion solves its own sub-cover and is not
166
+ * reported here, to keep the trace one layer per think). Off by default,
167
+ * so the search pays nothing when no one inspects. */
168
+ onDerivation?: (steps: DerivationStep[]) => void): {
169
+ segs: Seg[];
170
+ cost: number;
171
+ } | null;
172
+ /** Build the deduction system for one span and return its lightest cover's
173
+ * chosen spans — the SINGLE routine the query and every produced composite
174
+ * run through. `recognition` carries the span's recognised forms; the query
175
+ * brings its own (with pre-resolved concepts/connectors), a recursive
176
+ * completion re-recognises the produced bytes (edge/fuse only).
177
+ *
178
+ * No depth limit governs nesting — convergence is INTRINSIC, exactly as in the
179
+ * adapted A*LD chart and {@link completeForward}: a completion only recurses into a
180
+ * node it has not already entered ({@link recompleteNode}'s cycle guard), and
181
+ * the node ids are finite, so the recursion must terminate on its own. A
182
+ * decomposition may therefore run as deep as the graph licenses — three
183
+ * decomposes, two recomposes, any mix — and stops only when it reaches a node
184
+ * that leads nowhere new, never at an arbitrary count. */
185
+ private solve;
186
+ /** The weighted deduction system the graph exploration solves (the four
187
+ * reductions of adapted A*LD live in {@link lightestDerivation}; this only states the
188
+ * items, axioms, goal, and rules — see {@link GItem} for the item kinds).
189
+ *
190
+ * Forms that span across leaves are discovered BY the rules, which fuse
191
+ * adjacent fragments toward a known leaf (findLeaf) or branch (findBranch);
192
+ * a completion fused with its neighbour may spell a deeper learned form the
193
+ * flat probes can't name, recovered canonically by {@link resolve}. */
194
+ private buildSearch;
195
+ /** cover(p): the BRIDGE rule — extend the cover across any coverable out that
196
+ * begins at p, stepping the frontier from p to that out's end.
197
+ *
198
+ * This is what links the rewritten parts of a multi-form answer. An out is
199
+ * either a recognised completion (`rec`, free) or a literal span the query
200
+ * carried between known forms — the connective: a space, comma, period,
201
+ * newline, or any run of bytes that was never recognised. Bridging a literal
202
+ * costs PASS per byte (so the search still prefers to recognise), but it is
203
+ * the cheapest — indeed only — way to cross a gap that has no learned form,
204
+ * and it KEEPS that connective in the cover chain, so the asker's own linking
205
+ * material reappears when it still coheres ("ice, fire" → "cold, hot", not
206
+ * "coldhot"). A recognised completion bridges for a tiny ε (1e-3, far below
207
+ * STEP), so a single connected span beats two separate ones on coherence
208
+ * without disturbing the cost ladder's ordering.
209
+ *
210
+ * Marks p finalised so the symmetric out-side bridge ({@link outRules}) can
211
+ * fire for outs that arrive after their start position is covered. */
212
+ private coverRules;
213
+ /** The BRIDGE rule, built once for its two arrival orders (cover-first in
214
+ * {@link coverRules}, out-first in {@link outRules}): ε for a recognised
215
+ * completion; PASS per byte for a literal connective — kept in the cover
216
+ * so the asker's own connector survives where it fits. ONE definition of
217
+ * the cost expression, so the ladder's application cannot drift between
218
+ * the two sides. */
219
+ private bridgeRule;
220
+ /** The connector-SPLICE rule for an oriented (l, r) pair, or null when the
221
+ * pair does not qualify — the ONE body behind {@link outRules}' two
222
+ * mirror loops (this-as-left over resolved right partners, this-as-right
223
+ * over resolved left partners). Fires only when both sides are
224
+ * recognised, r starts at or after l ends, and the gap between them is
225
+ * empty or wholly recognised — never across the asker's own literal
226
+ * separator. */
227
+ private trySplice;
228
+ /** form(i,j,node,via): follow the graph out of `node`, or (in articulation)
229
+ * emit its substitute voice directly. */
230
+ private formRules;
231
+ /** Complete a node that an edge produced but that bears no further whole-edge,
232
+ * by COVERING ITS OWN BYTES — the very same operation the top query runs.
233
+ * Completion is not a special pass: a produced composite ("p1 p2") is just
234
+ * another span to cover, and covering it re-applies recognition, edge-follow,
235
+ * fusion and recomposition to discover that its parts continue (p1→R1, p2→R2)
236
+ * and recompose into a deeper learnt form (→ FINAL). This is why a single
237
+ * edge-target needs no bespoke logic — it routes back through {@link solve}.
238
+ *
239
+ * Re-recognition (not the node's tree children) is what surfaces the learnt
240
+ * parts: content-defined chunking may cut "p1 p2" as "p1 p"|"2", so only
241
+ * recognising the bytes recovers p1 and p2 as the forms the graph knows.
242
+ *
243
+ * The recovered answer is accepted only when it MOVED and names a LEARNT node
244
+ * ({@link resolve}) — the graph itself gates against re-expanding a contained
245
+ * form ("ice is cold" ⊅→ "ice is cold is cold").
246
+ *
247
+ * Termination is INTRINSIC, not a depth limit: a node already on the
248
+ * completion stack ({@link recompleteOpen}) is not re-entered — a self-
249
+ * referential recomposition is a cycle that can yield nothing new, so it
250
+ * stops there, exactly as {@link completeForward} stops on a revisited edge.
251
+ * Distinct node ids are finite and each finished completion is memoised, so a
252
+ * legitimate chain runs as deep as the graph licenses and no further. */
253
+ private recompleteNode;
254
+ /** Per-cover memo of each produced node's completion (so the many terminal
255
+ * outs of a long query re-cover each distinct node at most once); reset at the
256
+ * top of {@link cover}. */
257
+ private recompleteMemo;
258
+ /** The nodes currently being re-completed — the recursion stack. A node in
259
+ * this set is not re-entered, so a cyclic recomposition terminates naturally
260
+ * (the same cycle guard {@link completeForward} uses), with no depth cap. */
261
+ private recompleteOpen;
262
+ /** out(i,j,bytes,…): index it for the binary rules, then offer splicing a
263
+ * learnt connector (the in-search bridge), splitting (at a sub-leaf form
264
+ * boundary), bridging (cover(i) ∧ this → cover(j)), and fusing with an
265
+ * adjacent finalised out. */
266
+ private outRules;
267
+ /** Whether the query span [from, to) is wholly covered by RECOGNISED outs —
268
+ * the test that lets a connector jump across INTERIOR answers (an N-ary whole)
269
+ * but never across the asker's own unrecognised framing (a space or comma the
270
+ * asker wrote between parts). Empty span (from === to, the adjacent case) is
271
+ * trivially recognised. Otherwise step right-to-left: from `to`, find a
272
+ * recognised out ending there and continue from its start, until reaching
273
+ * `from`. Greedy-longest is sufficient here — the spans in play are the few
274
+ * recognised answers of one query, not a general interval cover. */
275
+ private gapRecognised;
276
+ /** Fuse two adjacent finalised outs — the search's own discovery of forms
277
+ * that cross leaf boundaries. The concatenation may be a known leaf
278
+ * (findLeaf, when short enough), or — when both sides resolved — their pair a
279
+ * known branch (findBranch); a completion fused with its neighbour may spell
280
+ * a deeper learned form, recovered canonically by {@link resolve} (gated on a
281
+ * completion being present, so it only runs along chains). The fused span
282
+ * lives on as an intermediate out while it could still grow into a form, and
283
+ * enters the graph as a form the moment it names a node. */
284
+ private fuse;
285
+ }