@hviana/sema 0.5.2 → 0.5.4

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 (157) hide show
  1. package/AGENTS.md +115 -53
  2. package/HOW_IT_WORKS.md +291 -184
  3. package/jsr.json +6 -0
  4. package/package.json +1 -1
  5. package/src/mind/bridge.ts +10 -104
  6. package/src/mind/match.ts +497 -7
  7. package/src/mind/{prefix-completion.ts → mechanisms/prefix-completion.ts} +66 -92
  8. package/src/mind/mechanisms/recall.ts +38 -129
  9. package/src/mind/mechanisms/reference.ts +343 -0
  10. package/src/mind/mind.ts +12 -8
  11. package/src/mind/pipeline-mechanism.ts +120 -3
  12. package/src/mind/pipeline.ts +16 -2
  13. package/src/mind/traverse.ts +92 -1
  14. package/src/store.ts +13 -4
  15. package/test/33-multi-candidate.test.mjs +21 -11
  16. package/test/70-prefix-completion.test.mjs +1 -1
  17. package/test/72-prefix-candidate-supply.test.mjs +7 -9
  18. package/test/74-prefix-trap-not-sprung-early.test.mjs +1 -1
  19. package/test/76-reference-binding.test.mjs +543 -0
  20. package/dist/example/demo.d.ts +0 -1
  21. package/dist/example/demo.js +0 -39
  22. package/dist/example/train_base.d.ts +0 -93
  23. package/dist/example/train_base.js +0 -2269
  24. package/dist/src/alphabet.d.ts +0 -7
  25. package/dist/src/alphabet.js +0 -33
  26. package/dist/src/alu/src/alu.d.ts +0 -185
  27. package/dist/src/alu/src/alu.js +0 -440
  28. package/dist/src/alu/src/expr.d.ts +0 -61
  29. package/dist/src/alu/src/expr.js +0 -318
  30. package/dist/src/alu/src/index.d.ts +0 -11
  31. package/dist/src/alu/src/index.js +0 -19
  32. package/dist/src/alu/src/kernel-arith.d.ts +0 -16
  33. package/dist/src/alu/src/kernel-arith.js +0 -264
  34. package/dist/src/alu/src/kernel-bits.d.ts +0 -19
  35. package/dist/src/alu/src/kernel-bits.js +0 -152
  36. package/dist/src/alu/src/kernel-logic.d.ts +0 -4
  37. package/dist/src/alu/src/kernel-logic.js +0 -60
  38. package/dist/src/alu/src/kernel-nd.d.ts +0 -3
  39. package/dist/src/alu/src/kernel-nd.js +0 -208
  40. package/dist/src/alu/src/kernel-numeric.d.ts +0 -54
  41. package/dist/src/alu/src/kernel-numeric.js +0 -366
  42. package/dist/src/alu/src/operation.d.ts +0 -168
  43. package/dist/src/alu/src/operation.js +0 -189
  44. package/dist/src/alu/src/parser.d.ts +0 -221
  45. package/dist/src/alu/src/parser.js +0 -577
  46. package/dist/src/alu/src/resonance.d.ts +0 -55
  47. package/dist/src/alu/src/resonance.js +0 -126
  48. package/dist/src/alu/src/text.d.ts +0 -31
  49. package/dist/src/alu/src/text.js +0 -73
  50. package/dist/src/alu/src/value.d.ts +0 -109
  51. package/dist/src/alu/src/value.js +0 -300
  52. package/dist/src/alu/test/alu.test.d.ts +0 -1
  53. package/dist/src/alu/test/alu.test.js +0 -764
  54. package/dist/src/bytes.d.ts +0 -14
  55. package/dist/src/bytes.js +0 -59
  56. package/dist/src/canon.d.ts +0 -45
  57. package/dist/src/canon.js +0 -85
  58. package/dist/src/config.d.ts +0 -111
  59. package/dist/src/config.js +0 -91
  60. package/dist/src/derive/src/deduction.d.ts +0 -136
  61. package/dist/src/derive/src/deduction.js +0 -159
  62. package/dist/src/derive/src/index.d.ts +0 -8
  63. package/dist/src/derive/src/index.js +0 -11
  64. package/dist/src/derive/src/priority-queue.d.ts +0 -20
  65. package/dist/src/derive/src/priority-queue.js +0 -73
  66. package/dist/src/derive/src/rewrite.d.ts +0 -56
  67. package/dist/src/derive/src/rewrite.js +0 -100
  68. package/dist/src/derive/src/trie.d.ts +0 -90
  69. package/dist/src/derive/src/trie.js +0 -217
  70. package/dist/src/derive/test/derive.test.d.ts +0 -1
  71. package/dist/src/derive/test/derive.test.js +0 -122
  72. package/dist/src/extension.d.ts +0 -37
  73. package/dist/src/extension.js +0 -7
  74. package/dist/src/geometry.d.ts +0 -233
  75. package/dist/src/geometry.js +0 -1089
  76. package/dist/src/index.d.ts +0 -17
  77. package/dist/src/index.js +0 -19
  78. package/dist/src/ingest-cache.d.ts +0 -41
  79. package/dist/src/ingest-cache.js +0 -165
  80. package/dist/src/meter.d.ts +0 -176
  81. package/dist/src/meter.js +0 -274
  82. package/dist/src/mind/articulation.d.ts +0 -6
  83. package/dist/src/mind/articulation.js +0 -99
  84. package/dist/src/mind/attention.d.ts +0 -430
  85. package/dist/src/mind/attention.js +0 -2418
  86. package/dist/src/mind/bridge.d.ts +0 -39
  87. package/dist/src/mind/bridge.js +0 -998
  88. package/dist/src/mind/canonical.d.ts +0 -34
  89. package/dist/src/mind/canonical.js +0 -93
  90. package/dist/src/mind/frame-filler.d.ts +0 -15
  91. package/dist/src/mind/frame-filler.js +0 -535
  92. package/dist/src/mind/graph-search.d.ts +0 -294
  93. package/dist/src/mind/graph-search.js +0 -996
  94. package/dist/src/mind/index.d.ts +0 -9
  95. package/dist/src/mind/index.js +0 -5
  96. package/dist/src/mind/junction.d.ts +0 -137
  97. package/dist/src/mind/junction.js +0 -358
  98. package/dist/src/mind/learning.d.ts +0 -75
  99. package/dist/src/mind/learning.js +0 -265
  100. package/dist/src/mind/match.d.ts +0 -192
  101. package/dist/src/mind/match.js +0 -666
  102. package/dist/src/mind/mechanisms/alu.d.ts +0 -4
  103. package/dist/src/mind/mechanisms/alu.js +0 -36
  104. package/dist/src/mind/mechanisms/cast.d.ts +0 -89
  105. package/dist/src/mind/mechanisms/cast.js +0 -1186
  106. package/dist/src/mind/mechanisms/confluence.d.ts +0 -24
  107. package/dist/src/mind/mechanisms/confluence.js +0 -271
  108. package/dist/src/mind/mechanisms/cover.d.ts +0 -6
  109. package/dist/src/mind/mechanisms/cover.js +0 -232
  110. package/dist/src/mind/mechanisms/extraction.d.ts +0 -33
  111. package/dist/src/mind/mechanisms/extraction.js +0 -327
  112. package/dist/src/mind/mechanisms/recall.d.ts +0 -16
  113. package/dist/src/mind/mechanisms/recall.js +0 -558
  114. package/dist/src/mind/mind.d.ts +0 -386
  115. package/dist/src/mind/mind.js +0 -754
  116. package/dist/src/mind/pipeline-mechanism.d.ts +0 -183
  117. package/dist/src/mind/pipeline-mechanism.js +0 -521
  118. package/dist/src/mind/pipeline.d.ts +0 -49
  119. package/dist/src/mind/pipeline.js +0 -331
  120. package/dist/src/mind/prefix-completion.d.ts +0 -59
  121. package/dist/src/mind/prefix-completion.js +0 -270
  122. package/dist/src/mind/primitives.d.ts +0 -85
  123. package/dist/src/mind/primitives.js +0 -333
  124. package/dist/src/mind/rationale.d.ts +0 -139
  125. package/dist/src/mind/rationale.js +0 -163
  126. package/dist/src/mind/reasoning.d.ts +0 -42
  127. package/dist/src/mind/reasoning.js +0 -305
  128. package/dist/src/mind/recognition.d.ts +0 -20
  129. package/dist/src/mind/recognition.js +0 -696
  130. package/dist/src/mind/resonance.d.ts +0 -35
  131. package/dist/src/mind/resonance.js +0 -365
  132. package/dist/src/mind/trace.d.ts +0 -15
  133. package/dist/src/mind/trace.js +0 -73
  134. package/dist/src/mind/traverse.d.ts +0 -158
  135. package/dist/src/mind/traverse.js +0 -716
  136. package/dist/src/mind/types.d.ts +0 -418
  137. package/dist/src/mind/types.js +0 -179
  138. package/dist/src/rabitq-ivf/src/database.d.ts +0 -113
  139. package/dist/src/rabitq-ivf/src/database.js +0 -201
  140. package/dist/src/rabitq-ivf/src/index.d.ts +0 -7
  141. package/dist/src/rabitq-ivf/src/index.js +0 -4
  142. package/dist/src/rabitq-ivf/src/ivf.d.ts +0 -200
  143. package/dist/src/rabitq-ivf/src/ivf.js +0 -1165
  144. package/dist/src/rabitq-ivf/src/prng.d.ts +0 -19
  145. package/dist/src/rabitq-ivf/src/prng.js +0 -36
  146. package/dist/src/rabitq-ivf/src/rabitq.d.ts +0 -95
  147. package/dist/src/rabitq-ivf/src/rabitq.js +0 -313
  148. package/dist/src/sema.d.ts +0 -41
  149. package/dist/src/sema.js +0 -77
  150. package/dist/src/store-sqlite.d.ts +0 -184
  151. package/dist/src/store-sqlite.js +0 -942
  152. package/dist/src/store.d.ts +0 -762
  153. package/dist/src/store.js +0 -1823
  154. package/dist/src/vec.d.ts +0 -31
  155. package/dist/src/vec.js +0 -109
  156. package/src/mind/frame-filler.ts +0 -604
  157. package/test/69-frame-filler.test.mjs +0 -115
@@ -1,217 +0,0 @@
1
- /**
2
- * Forward prefix trie over integer symbols — the lazy site matcher.
3
- *
4
- * This is the matching primitive the lightest-derivation search consults *on
5
- * demand*: given a position in a sequence, {@link Trie.matchesAt} walks forward
6
- * from the root and reports every stored pattern that begins there, in
7
- * O(longest matching pattern). Nothing is scanned that the search never asks
8
- * about — there is no global automaton, no failure links, no precomputed match
9
- * table. That is the whole point: rewrite sites are *materialised only when
10
- * demanded* (the "lazy hyperedge generation" of the rewrite search), so the
11
- * matcher itself stays trivial and the search decides what to look at.
12
- *
13
- * It is fully generic and self-contained: symbols are non-negative integers
14
- * (bytes 0–255, Unicode code points, opcodes, …); patterns are any
15
- * `ArrayLike<number>` (`Uint8Array` or `number[]`); each pattern carries an
16
- * arbitrary `payload` returned on every match. The trie also exposes a tiny
17
- * cursor API ({@link Trie.root}, {@link Trie.step}, {@link Trie.terminal}) so a
18
- * caller can extend a partial match symbol-by-symbol — e.g. to ask "could this
19
- * span still grow into a known form?" while composing.
20
- *
21
- * ## Memory
22
- *
23
- * Most states (99.7 % in typical use) have exactly one outgoing transition.
24
- * Storing a full `Map` per state would cost ~88 bytes each. Instead, a singleton
25
- * transition is packed inline into two typed arrays — `_nxt` (Int32Array, 4
26
- * bytes) and `_sym` (Uint8Array, 1 byte) — for ~5 bytes per state, a 17×
27
- * reduction. Only the rare multi-transition state (~0.3 %) allocates a `Map`,
28
- * kept in a sparse `_multi` table keyed by state number.
29
- */
30
- const ROOT = 0;
31
- export class Trie {
32
- // ── compact transition storage ──────────────────────────────────────────
33
- // _nxt[s] — -1 terminal (no outgoing transition)
34
- // -2 multi-transition → _multi.get(s)
35
- // >=0 singleton target; the symbol is _sym[s]
36
- _nxt;
37
- _sym;
38
- _multi = null;
39
- // _end[s] is the pattern id ending exactly at s, or -1.
40
- _end;
41
- // Per-pattern data, indexed by pattern id.
42
- _lens = [];
43
- _vals = [];
44
- _len = 1; // next free state (state 0 = root)
45
- constructor() {
46
- const c = 256;
47
- this._nxt = new Int32Array(c);
48
- this._sym = new Uint8Array(c);
49
- this._end = new Int32Array(c);
50
- this._nxt[ROOT] = -1;
51
- this._end[ROOT] = -1;
52
- }
53
- /** The root state, for cursor walks. */
54
- get root() {
55
- return ROOT;
56
- }
57
- /** Number of distinct patterns stored. */
58
- get size() {
59
- return this._lens.length;
60
- }
61
- // ── internal helpers ────────────────────────────────────────────────────
62
- /** Allocate a fresh state, growing the typed arrays by a fixed increment
63
- * when full. No power-of-2 doubling — the transient double-memory spike
64
- * during growth is bounded to the increment. */
65
- _state() {
66
- const s = this._len++;
67
- if (s >= this._nxt.length) {
68
- const c = s + 4096;
69
- const nn = new Int32Array(c);
70
- nn.set(this._nxt);
71
- this._nxt = nn;
72
- const ns = new Uint8Array(c);
73
- ns.set(this._sym);
74
- this._sym = ns;
75
- const ne = new Int32Array(c);
76
- ne.set(this._end);
77
- this._end = ne;
78
- }
79
- this._nxt[s] = -1;
80
- this._end[s] = -1;
81
- return s;
82
- }
83
- /** Follow symbol `c` from state `s`. Returns the next state, or -1. */
84
- _follow(s, c) {
85
- const n = this._nxt[s];
86
- if (n >= 0)
87
- return this._sym[s] === c ? n : -1;
88
- if (n === -2)
89
- return this._multi.get(s).get(c) ?? -1;
90
- return -1; // n === -1
91
- }
92
- // ── cursor API (allocation-free) ─────────────────────────────────────────
93
- /** Follow one symbol from `state`; returns the next state or -1 if none. */
94
- step(state, symbol) {
95
- return this._follow(state, symbol);
96
- }
97
- /** The pattern ending exactly at `state`, or null. */
98
- terminal(state) {
99
- const id = this._end[state];
100
- return id === -1 ? null : { id, payload: this._vals[id] };
101
- }
102
- /** Length of the pattern with this id. */
103
- lengthOf(id) {
104
- return this._lens[id];
105
- }
106
- // ── build ───────────────────────────────────────────────────────────────
107
- /**
108
- * Insert a pattern, returning its id. Inserting the same symbol-sequence
109
- * twice returns the first id and keeps the first payload (patterns are keyed
110
- * by content). Empty patterns are ignored and return -1.
111
- */
112
- insert(pattern, payload) {
113
- const n = pattern.length;
114
- if (n === 0)
115
- return -1;
116
- let s = ROOT;
117
- for (let i = 0; i < n; i++) {
118
- const c = pattern[i];
119
- const t = this._nxt[s];
120
- if (t === -1) {
121
- // Terminal — place first transition as a singleton.
122
- const ns = this._state();
123
- this._nxt[s] = ns;
124
- this._sym[s] = c;
125
- s = ns;
126
- }
127
- else if (t >= 0) {
128
- // Singleton — either advance on match, or expand to multi.
129
- if (this._sym[s] === c) {
130
- s = t;
131
- }
132
- else {
133
- const map = new Map();
134
- map.set(this._sym[s], t);
135
- const ns = this._state();
136
- map.set(c, ns);
137
- if (!this._multi)
138
- this._multi = new Map();
139
- this._multi.set(s, map);
140
- this._nxt[s] = -2;
141
- s = ns;
142
- }
143
- }
144
- else {
145
- // Multi (t === -2) — extend the existing Map.
146
- const map = this._multi.get(s);
147
- let ns = map.get(c);
148
- if (ns === undefined) {
149
- ns = this._state();
150
- map.set(c, ns);
151
- }
152
- s = ns;
153
- }
154
- }
155
- if (this._end[s] !== -1)
156
- return this._end[s]; // already present
157
- const id = this._lens.length;
158
- this._lens.push(n);
159
- this._vals.push(payload);
160
- this._end[s] = id;
161
- return id;
162
- }
163
- // ── matching ───────────────────────────────────────────────────────────
164
- /**
165
- * Every stored pattern that begins exactly at `pos` in `seq`, shortest first.
166
- * Walks forward from the root in O(longest match); reports nothing about any
167
- * other position. This is the on-demand probe the search uses.
168
- */
169
- matchesAt(seq, pos) {
170
- const out = [];
171
- let s = ROOT;
172
- for (let i = pos, n = seq.length; i < n; i++) {
173
- s = this._follow(s, seq[i]);
174
- if (s === -1)
175
- break;
176
- const id = this._end[s];
177
- if (id !== -1) {
178
- out.push({
179
- start: pos,
180
- end: i + 1,
181
- length: this._lens[id],
182
- id,
183
- payload: this._vals[id],
184
- });
185
- }
186
- }
187
- return out;
188
- }
189
- /**
190
- * Every occurrence of every pattern anywhere in `seq` (eager form, the union
191
- * of {@link matchesAt} over all start positions). O(seq · longest pattern),
192
- * independent of how many patterns are stored. Use {@link matchesAt} when the
193
- * search only needs the sites at a particular position.
194
- */
195
- scan(seq) {
196
- const out = [];
197
- for (let pos = 0, n = seq.length; pos < n; pos++) {
198
- let s = ROOT;
199
- for (let i = pos; i < n; i++) {
200
- s = this._follow(s, seq[i]);
201
- if (s === -1)
202
- break;
203
- const id = this._end[s];
204
- if (id !== -1) {
205
- out.push({
206
- start: pos,
207
- end: i + 1,
208
- length: this._lens[id],
209
- id,
210
- payload: this._vals[id],
211
- });
212
- }
213
- }
214
- }
215
- return out;
216
- }
217
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,122 +0,0 @@
1
- // Self-contained tests for the `derive` library: the lightest-derivation
2
- // engine (including a multi-premise *bridge* rule), the on-demand trie matcher,
3
- // and the optimal cover. Uses node:test; no dependency on sema.
4
- import { test } from "node:test";
5
- import assert from "node:assert/strict";
6
- import { coverSequence, lightestDerivation, Trie, } from "../src/index.js";
7
- // ── trie: on-demand matching, no length bound ──────────────────────────────
8
- test("trie matchesAt reports forms beginning exactly at a position", () => {
9
- const t = new Trie();
10
- t.insert([1, 2], "ab");
11
- t.insert([1, 2, 3], "abc");
12
- t.insert([2, 3], "bc");
13
- const at0 = t.matchesAt([1, 2, 3, 4], 0).map((m) => m.payload);
14
- assert.deepEqual(at0, ["ab", "abc"]); // both forms starting at 0, shortest first
15
- const at1 = t.matchesAt([1, 2, 3, 4], 1).map((m) => m.payload);
16
- assert.deepEqual(at1, ["bc"]);
17
- const at3 = t.matchesAt([1, 2, 3, 4], 3).map((m) => m.payload);
18
- assert.deepEqual(at3, []); // nothing learned here → dead-ends immediately
19
- });
20
- test("trie scan finds every occurrence; duplicate inserts share an id", () => {
21
- const t = new Trie();
22
- const id1 = t.insert([7, 7], 1);
23
- const id2 = t.insert([7, 7], 2); // same content
24
- assert.equal(id1, id2);
25
- assert.equal(t.size, 1);
26
- const hits = t.scan([7, 7, 7]);
27
- assert.equal(hits.length, 2); // [0,2) and [1,3)
28
- });
29
- // ── engine: Dijkstra/Knuth core with a bridge (multi-premise) rule ─────────
30
- test("lightestDerivation solves a hypergraph with a bridge premise", () => {
31
- // Items: "A", "B", "AB". Axioms A (3) and B (4). A binary bridge A ∧ B → AB
32
- // at cost 1. The only derivation of AB costs 3 + 4 + 1 = 8.
33
- const A = "A", B = "B", AB = "AB";
34
- const system = {
35
- key: (s) => s,
36
- axioms: () => [{ item: A, cost: 3 }, { item: B, cost: 4 }],
37
- isGoal: (s) => s === AB,
38
- *rules(item) {
39
- // Bridge fires from either premise; the engine waits until both are known.
40
- if (item === A)
41
- yield { premises: [A, B], conclusion: AB, cost: 1 };
42
- if (item === B)
43
- yield { premises: [A, B], conclusion: AB, cost: 1 };
44
- },
45
- };
46
- const d = lightestDerivation(system);
47
- assert.ok(d);
48
- assert.equal(d.item, AB);
49
- assert.equal(d.cost, 8);
50
- assert.equal(d.premises.length, 2); // it really used the bridge
51
- });
52
- test("lightestDerivation picks the cheaper of competing derivations", () => {
53
- // Two ways to reach the goal G from axiom S: S→G cost 10, or S→M→G cost 3+3.
54
- const system = {
55
- key: (s) => s,
56
- axioms: () => [{ item: "S", cost: 0 }],
57
- isGoal: (s) => s === "G",
58
- *rules(item) {
59
- if (item === "S") {
60
- yield { premises: ["S"], conclusion: "G", cost: 10 };
61
- yield { premises: ["S"], conclusion: "M", cost: 3 };
62
- }
63
- if (item === "M")
64
- yield { premises: ["M"], conclusion: "G", cost: 3 };
65
- },
66
- };
67
- const d = lightestDerivation(system);
68
- assert.ok(d);
69
- assert.equal(d.cost, 6); // via M, not the direct 10
70
- assert.equal(d.rule?.premises[0], "M");
71
- });
72
- test("lightestDerivation returns null when the goal is unreachable", () => {
73
- const system = {
74
- key: (n) => "" + n,
75
- axioms: () => [{ item: 0, cost: 0 }],
76
- isGoal: (n) => n === 99,
77
- *rules(n) {
78
- if (n < 3)
79
- yield { premises: [n], conclusion: n + 1, cost: 1 };
80
- },
81
- };
82
- assert.equal(lightestDerivation(system), null);
83
- });
84
- // ── cover: optimal, not greedy ─────────────────────────────────────────────
85
- test("coverSequence maximises coverage, beating greedy longest-match", () => {
86
- // Over [0,4): one long span [1,4) (len 3) vs two short [0,2),[2,4) (cover 4).
87
- // Greedy-longest takes [1,4) and covers 3; the optimal cover takes the pair.
88
- const cover = coverSequence(4, [
89
- { start: 1, end: 4, payload: "long" },
90
- { start: 0, end: 2, payload: "left" },
91
- { start: 2, end: 4, payload: "right" },
92
- ]);
93
- assert.equal(cover.covered, 4);
94
- assert.equal(cover.uncovered, 0);
95
- assert.deepEqual(cover.spans.map((s) => s.payload), ["left", "right"]);
96
- });
97
- test("coverSequence prefers fewer, longer spans on ties (unit weight)", () => {
98
- // [0,3) covers the same as [0,1)+[1,3) but in one span → preferred.
99
- const cover = coverSequence(3, [
100
- { start: 0, end: 3, payload: "whole" },
101
- { start: 0, end: 1, payload: "a" },
102
- { start: 1, end: 3, payload: "b" },
103
- ]);
104
- assert.deepEqual(cover.spans.map((s) => s.payload), ["whole"]);
105
- });
106
- test("coverSequence leaves genuinely uncovered gaps uncovered", () => {
107
- const cover = coverSequence(10, [
108
- { start: 0, end: 3, payload: "x" },
109
- { start: 6, end: 9, payload: "y" },
110
- ]);
111
- assert.equal(cover.covered, 6);
112
- assert.equal(cover.uncovered, 4);
113
- assert.deepEqual(cover.spans.map((s) => s.payload), ["x", "y"]);
114
- });
115
- test("coverSequence honours weights when coverage ties", () => {
116
- // Both single-span covers cover all 2 symbols; the lighter weight wins.
117
- const cover = coverSequence(2, [
118
- { start: 0, end: 2, weight: 5, payload: "heavy" },
119
- { start: 0, end: 2, weight: 1, payload: "light" },
120
- ]);
121
- assert.deepEqual(cover.spans.map((s) => s.payload), ["light"]);
122
- });
@@ -1,37 +0,0 @@
1
- /** A half-open byte span of a query an extension computed, and the canonical
2
- * result bytes it is authoritative for. */
3
- export interface ComputedSpan {
4
- i: number;
5
- j: number;
6
- bytes: Uint8Array;
7
- }
8
- /** The generic capabilities the mind lends every extension — nothing here
9
- * names any particular extension, and every member is machinery the mind
10
- * already has:
11
- *
12
- * MEANING (resonance and grounding — the same mechanisms recall uses):
13
- * • meaningOf — which of some labelled forms does a span mean? Pure gist
14
- * nearness; the extension supplies its own vocabulary and gives the answer
15
- * its own reading.
16
- * • continuation — the grounded form the corpus continues a form to (the
17
- * continuation fixpoint recall grounds answers with), or null when the
18
- * form leads nowhere. The mind answers only "where does this form lead?";
19
- * what that continuation MEANS is the extension's business.
20
- *
21
- * GEOMETRY (the perception tree's own structure):
22
- * • segment — coherent runs by the alphabet-space merge the perception tree
23
- * uses, so an extension's notion of "separator" is the learnt geometry's.
24
- * • reach — the river's grouping capacity (maxGroup), bounding how far apart
25
- * two spans may sit and still be read as one construction. */
26
- export interface ExtensionHost {
27
- meaningOf(bytes: Uint8Array, anchors: ReadonlyArray<{
28
- name: string;
29
- form: Uint8Array;
30
- }>): Promise<string | null>;
31
- continuation(bytes: Uint8Array): Promise<Uint8Array | null>;
32
- segment(bytes: Uint8Array): Array<{
33
- i: number;
34
- j: number;
35
- }>;
36
- reach: number;
37
- }
@@ -1,7 +0,0 @@
1
- // extension.ts — shared types for computational extensions.
2
- //
3
- // Extensions (ALU, user computation packs) implement the PipelineMechanism
4
- // interface (pipeline-mechanism.ts) — this file holds only the types that
5
- // both the extension author and the pipeline need, without coupling either
6
- // to a specific mechanism.
7
- export {};
@@ -1,233 +0,0 @@
1
- import { Vec } from "./vec.js";
2
- import { Sema, Space } from "./sema.js";
3
- import { Alphabet } from "./alphabet.js";
4
- /** The store's geometric identity bar: cosine ≥ 1 − 1/√D is the similarity at
5
- * which `intern` already treats two gists as the SAME node. Recall reuses it
6
- * to accept a near-identical query, and the climb to accept a containing form —
7
- * one derived constant, never a tuned threshold. NOTE: this fixed bar is
8
- * the ESTIMATOR floor of an identity claim; a whole-span claim over a span
9
- * longer than the perception quantum must use the scale-aware
10
- * {@link identityBar}, which converts the tolerated fraction into bytes. */
11
- export declare function mergeThreshold(D: number): number;
12
- /** The scale-aware IDENTITY bar for a whole-span resonance claim over a span
13
- * of `len` bytes. Under the linear fold a cosine reads "fraction of aligned
14
- * shared bytes", so a FIXED cosine bar admits a byte budget that grows with
15
- * the span: 1 − 1/√D over a 4·√D-byte span tolerates four whole river
16
- * windows of foreign content while still claiming "near-identical". An
17
- * identity claim may tolerate at most ONE river window W — the perception
18
- * quantum, the same single-window budget near-dedup's differsByOneWindow
19
- * grants — so the bar is 1 − W/len, floored at mergeThreshold(D), below
20
- * which the RaBitQ estimator cannot certify identity anyway. This is the
21
- * angle+magnitude form of the identity test: the ANGLE carries the shared
22
- * fraction, the span's MAGNITUDE (√len, the linear fold's own norm) converts
23
- * the tolerated fraction into tolerated bytes. Derived from W, D and the
24
- * span; never tuned. */
25
- export declare function identityBar(D: number, maxGroup: number, len: number): number;
26
- /** The reach bar: half a river quantum, derived from the fold's own geometry.
27
- * A branch folds up to `maxGroup` children, so two forms that differ in ONE
28
- * whole child — the smallest distinction perception can mean — sit at cosine
29
- * ≈ 1 − 1/maxGroup. Half that quantum, 1 − 1/(2·maxGroup), is closer than any
30
- * single-child difference can be: a positional echo of the same content.
31
- *
32
- * This is an EQUAL-ARITY replacement law. The two-ended coordinate frame is
33
- * a bijective relabelling of the seats inside that node, so it does not change
34
- * the one-child overlap or this bar. Stability under a leading/trailing
35
- * insertion comes from preserving content-defined subtrees and their anchored
36
- * coordinates — never from lowering the confidence floor.
37
- *
38
- * Recall uses this as its confidence floor: a query whose nearest resonant
39
- * form sits below this bar is structurally unrelated to everything in the store
40
- * — further than any single-child variant — and the system returns null rather
41
- * than fabricate an answer from an unrelated form. Derived, never tuned. */
42
- export declare function reachThreshold(maxGroup: number): number;
43
- /** The estimator's own noise floor: 1/√D — ONE standard deviation of the
44
- * cosine between two independent random vectors in D dimensions (the same σ
45
- * {@link significanceBar} takes three of). It is the smallest difference in
46
- * cosine that is distinguishable from the rotation-uniformised RaBitQ
47
- * estimation error (see the MEASUREMENT CAVEAT above): a contrastive margin
48
- * below it is quantisation noise, not evidence. The consensus climb gates a
49
- * region's vote on its discriminative margin clearing this floor — the
50
- * minimal "above noise" bar, one σ, not the stricter 3σ relatedness bar.
51
- * Derived, never tuned. */
52
- export declare function estimatorNoise(D: number): number;
53
- /** The statistical-significance bar for whole-query resonance: 3/√D.
54
- * In D dimensions the expected cosine of two independent random vectors is 0
55
- * with standard deviation 1/√D. A cosine ≥ 3/√D is three standard deviations
56
- * above chance — the query is statistically related to the store, not merely
57
- * sharing random byte noise. Below this bar the consensus climb (which trusts
58
- * sub-region resonance) is skipped: there is no evidence the query belongs to
59
- * the same distribution as the stored content. Derived, never tuned. */
60
- export declare function significanceBar(D: number): number;
61
- /** The concept (halo) threshold: the cosine above which two nodes share a
62
- * distributional concept. A halo is a superposition of episode signatures in
63
- * D-dimensional space, so the expected cosine between two unrelated halos is 0
64
- * with standard deviation 1/√D. The structural midpoint 0.5 separates "more
65
- * similar than not" from noise; the +0.5/√D term adds one half-sigma margin
66
- * that vanishes as D → ∞, accounting for the wider noise band at lower D
67
- * without inventing a tuned constant. At D=1024 this gives 0.516, within
68
- * 3% of 0.5 — existing behavior is preserved while threshold and D move
69
- * together. Derived, never tuned. */
70
- export declare function conceptThreshold(D: number): number;
71
- /** The HALF-DOMINANCE predicate: whether a part covering `partLen` of a
72
- * whole of `wholeLen` covers STRICTLY more than half of it. A span that
73
- * dominates its whole can no longer discriminate the whole's own content —
74
- * the one test behind liftAnswer's keep-the-frame rule, collectRegions'
75
- * wrapper exclusion, and CAST's frame-depth majority (each cites this).
76
- * CAST's frame-FRACTION gate is the deliberately CLOSED variant (≥ ½ is
77
- * already unusable there) and stays inline where it is documented.
78
- * Derived from the structural midpoint, never tuned. */
79
- export declare function dominates(partLen: number, wholeLen: number): boolean;
80
- /** The consensus-vote significance floor: ln(N) + 1/2, where N is the number
81
- * of learnt contexts (edge sources). A single region's IDF-weighted vote for
82
- * an anchor reached through c contexts is at most ln(N/c) ≤ ln(N); the +1/2
83
- * demands the pooled vote exceed what ONE maximally-specific region could
84
- * contribute by half a unit — i.e. genuine corroboration beyond a lone
85
- * region's echo at this corpus scale. The ONE floor both consumers gate on:
86
- * recallByResonance trusting a climb anchor, and commitVotes admitting a
87
- * further point of attention. Defined once here so the two can never
88
- * drift apart. Derived from N, never tuned. */
89
- export declare function consensusFloor(N: number): number;
90
- /** The coverage bar for the reach (interior) index, when vector-similarity
91
- * gating is used. Returns the concept threshold — the structural midpoint
92
- * (~0.5 at D=1024) where two forms are "more similar than not."
93
- *
94
- * Currently UNUSED in the hot training path: interior nodes are indexed
95
- * unconditionally (hash-cons dedup bounds the index naturally).
96
- * Post-hoc structural compaction ({@link Store.compactContentIndex})
97
- * replaces runtime coverage gating with a batch pass that removes
98
- * structurally-isolated entries. Derived, never tuned. */
99
- export declare function coverageBar(_maxGroup: number, D: number): number;
100
- export interface Folded {
101
- tree: Sema;
102
- /** Byte length of the subtree — carried incrementally so the stable-prefix
103
- * boundary scan never re-walks subtrees (the old per-level walk was
104
- * O(n log n) over the whole input). */
105
- len: number;
106
- }
107
- export interface Grid {
108
- width: number;
109
- height: number;
110
- channels: number;
111
- data: Uint8Array;
112
- dims?: number[];
113
- }
114
- export declare function contentBoundaries(space: Space, bytes: Uint8Array): number[];
115
- /** Find the longest prefix of `bytes` whose leaf-id signature matches a
116
- * known branch via `lookup`. Returns the byte-length of that prefix, or 0. */
117
- export declare function knownPrefixLength(bytes: Uint8Array, leafAt: (i: number) => number | null, lookup: (leafIds: number[]) => number | null): number;
118
- /** Bytes → Sema tree. `leafAt` and `lookup` are store capabilities for
119
- * detecting previously-stored prefixes so the river can split at the
120
- * correct boundary. Pass them through from `perceive`; the geometry
121
- * computes the stable prefix internally.
122
- *
123
- * `boundaries` is the CALLER-computed stable-prefix boundary set (§10.3):
124
- * strictly-increasing proper byte offsets, each the length of a prefix that
125
- * is already a stored whole-stream form. When given, the fold splits into
126
- * the segments between consecutive boundaries — each folded independently,
127
- * exactly as it folded when it was learned — and the segment roots join
128
- * LEFT-NESTED (((s₀·s₁)·s₂)…), so every learnt cumulative-context root
129
- * reappears as an identical subtree (and, by hash-consing, the very same
130
- * node) inside the grown stream. This is what lets a conversation's next
131
- * turn extend perception instead of refolding it: identical prefixes
132
- * produce identical subtrees regardless of what follows them. */
133
- export declare function bytesToTree(space: Space, alphabet: Alphabet, bytes: Uint8Array, leafAt?: (i: number) => number | null, lookup?: (leafIds: number[]) => number | null, boundaries?: readonly number[]): Sema;
134
- /** A plain content fold's reusable state: the level-0 cut edges over the whole
135
- * stream and each segment's independently-folded root. See
136
- * {@link contentFoldIncremental}. */
137
- export interface ContentFold {
138
- edges: number[];
139
- segs: Folded[];
140
- }
141
- /** {@link contentFoldSpan} over a WHOLE stream, reusing the segments a previous
142
- * fold of a byte-identical prefix already produced.
143
- *
144
- * WHY THIS IS SOUND, AND WHY IT NEEDS NO BOUNDARIES. A level-0 segment is a
145
- * pure function of its own bytes ({@link flatFold} reads nothing else), so
146
- * reusing one whose [start,end) is unchanged is bit-identical to refolding it
147
- * — the cache can never change the tree, only skip work. And the cuts
148
- * themselves are stable under APPEND: {@link contentLevels} decides each cut
149
- * from a rolling hash over a local window, so bytes added at the right edge
150
- * cannot move a cut to their left (measured over a growing 12-turn context:
151
- * 100% of prior cuts survive every append, zero tail churn). Together those
152
- * two facts are the whole optimisation — a grown stream refolds only the
153
- * segments at its right edge.
154
- *
155
- * This is the reuse the conversation path wants, and it costs NOTHING in
156
- * structure: the tree is exactly the tree {@link bytesToTree} builds for the
157
- * same bytes with no boundary set at all. Turn boundaries buy prefix-ROOT
158
- * identity, which is a different property from incremental reuse; conflating
159
- * the two is what put an imposed boundary set on the inference path and left
160
- * it folding differently from the deposits it was querying.
161
- *
162
- * `groupByLevel` above the segments is re-run whole. It operates on segment
163
- * ROOTS (a few dozen items for a several-hundred-byte context), not on bytes,
164
- * and only its right edge actually changes shape — measured at ~40 rebuilt
165
- * nodes per turn, flat as the context grows sevenfold.
166
- *
167
- * PRECONDITION — `prev` MUST have been folded over a BYTE-IDENTICAL PREFIX of
168
- * `bytes`. Reuse is keyed on a segment's [start,end) OFFSETS, which is what
169
- * makes it O(1) per segment; offsets alone cannot witness that the underlying
170
- * bytes agree. Hand it a fold of DIFFERENT bytes whose cuts happen to land
171
- * in the same places and it will splice those foreign segments in — measured,
172
- * a deliberately mismatched `prev` produced a wrong tree on 336 of 400 random
173
- * streams. Verifying the bytes here would cost O(prefix) and defeat the
174
- * whole point, so the obligation sits with the caller, and every caller
175
- * discharges it structurally rather than by care: `perceiveDeposit` looks the
176
- * entry up under `latin1Key(bytes.subarray(0, L))` — the prefix's own bytes
177
- * ARE the cache key — and a conversation's fold state advances only by
178
- * append. A new caller that cannot make the same structural argument must
179
- * pass no `prev` at all; the cold path is always correct.
180
- * ({@link stablePrefixFoldIncremental} carries the identical precondition for
181
- * the identical reason.) */
182
- export declare function contentFoldIncremental(space: Space, alphabet: Alphabet, bytes: Uint8Array, prev?: ContentFold): {
183
- tree: Sema;
184
- fold: ContentFold;
185
- };
186
- /** A stable-prefix fold's reusable state: the segment edge offsets and each
187
- * segment's independently-folded root ({@link riverFoldRaw} output). A
188
- * grown stream whose boundary set EXTENDS a previous fold's reuses every
189
- * matching segment's Folded unchanged (segments fold independently by
190
- * construction, so reuse is bit-identical to refolding) and folds only the
191
- * new right-edge segment — O(turn) per extension. Purely a cache: the
192
- * produced tree never depends on cache state. */
193
- export interface StableFold {
194
- edges: number[];
195
- segs: Folded[];
196
- }
197
- /** {@link stablePrefixFold} with incremental segment reuse — same cuts, same
198
- * segment folds, same left-nested join, same single root normalize; `prev`
199
- * only elides recomputing segments whose [start,end) offsets it already
200
- * folded over a byte-identical prefix (the caller keys the cache by
201
- * content). Requires a non-empty effective boundary set. */
202
- export declare function stablePrefixFoldIncremental(space: Space, alphabet: Alphabet, bytes: Uint8Array, boundaries: readonly number[], prev?: StableFold): {
203
- tree: Sema;
204
- fold: StableFold;
205
- };
206
- /** Plain river fold WITHOUT the final root normalize — the segment-level
207
- * building block of {@link stablePrefixFold} (interiors must keep their
208
- * byte-proportional magnitude; only the whole perception's root is ever
209
- * normalized). Exported so callers that COMPOSE already-existing structural
210
- * parts into a hypothetical synthetic root (see {@link composeStructuralGist})
211
- * can feed the same raw primitive instead of duplicating its mathematics. */
212
- export declare function riverFoldRaw(space: Space, row: Folded[]): Folded;
213
- /** One already-existing structural vector to compose, paired with the byte
214
- * span (query-slot) length it stands in for. `len`, not the vector's own
215
- * magnitude, is what {@link composeStructuralGist} restores — the composed
216
- * slot's NATURAL span, exactly as the linear river fold would carry it. */
217
- export interface StructuralPart {
218
- v: Vec;
219
- len: number;
220
- }
221
- /** Synthesize a hypothetical internal structure from already-existing
222
- * structural vectors — NOT from bytes. This is the raw positional
223
- * composition the linear river fold already uses (see the folding header
224
- * above): each part is positionally bound into its own seat, its natural
225
- * span magnitude is preserved, the parts are linearly superposed, and only
226
- * the final synthetic root is normalized. It never calls {@link gistOf}
227
- * (there is no `gistOf` here — geometry.ts has no store), never perceives a
228
- * concatenated byte string, and never interns or stores a new node: the
229
- * result is an opaque, ungrounded Vec for an ANN probe only. */
230
- export declare function composeStructuralGist(space: Space, parts: readonly StructuralPart[]): Vec;
231
- export declare function hilbertBytes(grid: Grid): Uint8Array;
232
- export declare function gridToTree(space: Space, alphabet: Alphabet, grid: Grid): Sema;
233
- export declare function stackGrids(frames: Grid[]): Grid;