@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
@@ -9,7 +9,7 @@
9
9
  import { cosine, Vec } from "../vec.js";
10
10
  import type { AncestorReach, MindContext, SaturationStop } from "./types.js";
11
11
  import { gistOf, read } from "./primitives.js";
12
- import { leafIdRun } from "./canonical.js";
12
+ import { canonicalWindows, leafIdPrefix, leafIdRun } from "./canonical.js";
13
13
 
14
14
  // ── Session structural memo ─────────────────────────────────────────────
15
15
  //
@@ -836,3 +836,94 @@ export function allWindowsAreScaffolding(
836
836
  }
837
837
  return sawOne;
838
838
  }
839
+
840
+ // ── THE PREFIX SUPPLY ───────────────────────────────────────────────────────
841
+ //
842
+ // A RETRIEVAL capability, not a grounding one: "which trained forms does this
843
+ // byte run OPEN?" It lived inside a recall tier, which is the wrong altitude
844
+ // — it reads the write side's own leaf-id window index and answers a question
845
+ // about the STORE, so any mechanism may ask it.
846
+
847
+ /** Trained forms the query may OPEN, proposed from the write side's own
848
+ * leaf-id window index — the supply of last resort for prefix completion.
849
+ *
850
+ * WHY A SECOND SUPPLY EXISTS. The ranked list prefix completion normally reads
851
+ * is a resonance list, and resonance cannot rank a proper prefix: measured on
852
+ * the trained store, cos(prefix, form) falls from 0.9629 at a one-byte
853
+ * truncation to 0.6206 at three bytes, against a reachThreshold of 0.8750.
854
+ * Three bytes of truncation put the answer out of reach on GEOMETRY, not on a
855
+ * bug, so no k and no re-ranking recovers it.
856
+ *
857
+ * WHY THIS ROUTE WORKS WHERE THE FOLD DOES NOT. A query's own fold is
858
+ * useless here: content addressing is not phrase-position-invariant, so a
859
+ * standalone prefix folds to a DIFFERENT node than the same bytes sitting
860
+ * inside a longer deposit, and neither the prefix's own node nor its
861
+ * ancestors lead to the deposit (measured: the 22-byte prefix of the
862
+ * photosynthesis form resolves, is shared by 6 contexts, and does not have
863
+ * the form among its ancestors). Leaf ids ARE position-invariant — they are
864
+ * content-addressed on single bytes — and `indexSubSpans` already interns a
865
+ * flat branch over every canonical WINDOW of a deposit's leaf-id stream, with
866
+ * containment edges to the chunks that window spans. A query that is a
867
+ * prefix therefore shares those window nodes exactly, and reaches the deposit
868
+ * by climbing containment then parents. Nothing is added to the write side;
869
+ * this reads an index training already built.
870
+ *
871
+ * BOUNDED (§2.8), AND WITH NO NEW THRESHOLD. The window whose containment is
872
+ * SMALLEST carries the most evidence, and one saturated at `hubBound` carries
873
+ * none — that is the same √N reading of "hub" the rest of the mind uses, not
874
+ * a tuned knob. The upward walk spends a budget of `hubBound` nodes and
875
+ * fans out by W, so a hub query enumerates nothing and the caller stays
876
+ * silent rather than guessing (§2.13). Measured on the trained store: the
877
+ * photosynthesis form at a one-byte truncation picks a window with 52
878
+ * containers, visits 446 nodes, and yields exactly ONE candidate that
879
+ * survives the caller's byte compare — the form itself.
880
+ *
881
+ * These are PROPOSALS only. Every candidate still faces the byte-exact
882
+ * prefix compare and all three guards below, so a wrong proposal costs one
883
+ * bounded read and can never be voiced (§2.3). */
884
+ export function formsOpenedBy(
885
+ ctx: MindContext,
886
+ query: Uint8Array,
887
+ ): number[] {
888
+ const store = ctx.store;
889
+ const W = ctx.space.maxGroup;
890
+ const run = leafIdPrefix(ctx, query);
891
+ // The widest canonical window is the most discriminative one the write side
892
+ // ever interned; a query too short to spell one carries no window evidence.
893
+ const len = canonicalWindows(W)[1];
894
+ if (run.length < len) return [];
895
+ const bound = hubBound(ctx);
896
+
897
+ let best: number | null = null;
898
+ let bestN = 0;
899
+ for (let off = 0; off + len <= run.length; off++) {
900
+ const wid = store.findBranch(run.slice(off, off + len));
901
+ if (wid === null) continue;
902
+ const n = store.containersSlice(wid, 0, bound).length;
903
+ // Empty says the window spans no chunk; saturated says it is a hub, whose
904
+ // containment discriminates nothing. Neither is evidence.
905
+ if (n === 0 || n >= bound) continue;
906
+ if (best === null || n < bestN) {
907
+ best = wid;
908
+ bestN = n;
909
+ }
910
+ }
911
+ if (best === null) return [];
912
+
913
+ let frontier = store.containersSlice(best, 0, bound);
914
+ const seen = new Set<number>(frontier);
915
+ let budget = bound;
916
+ while (frontier.length > 0 && budget > 0) {
917
+ const next: number[] = [];
918
+ for (const f of frontier) {
919
+ if (budget-- <= 0) break;
920
+ for (const p of store.parentsFirst(f, W)) {
921
+ if (seen.has(p)) continue;
922
+ seen.add(p);
923
+ next.push(p);
924
+ }
925
+ }
926
+ frontier = next;
927
+ }
928
+ return [...seen];
929
+ }
package/src/store.ts CHANGED
@@ -970,16 +970,25 @@ export abstract class AbstractStore implements Store {
970
970
  /** Content (gist) index write buffer. */
971
971
  protected _contentBuffer: Array<{ id: NodeId; vector: Float32Array }> = [];
972
972
  /** Halo index write buffer — keyed by id so repeats within a batch coalesce. */
973
- protected _haloBuffer = new Map<NodeId, Float32Array>();
973
+ protected _haloBuffer: Map<NodeId, Float32Array> = new Map<
974
+ NodeId,
975
+ Float32Array
976
+ >();
974
977
  /** Containment write buffer: child → new parents, merged on flush cadence. */
975
- protected _containBuf = new Map<NodeId, Set<NodeId>>();
978
+ protected _containBuf: Map<NodeId, Set<NodeId>> = new Map<
979
+ NodeId,
980
+ Set<NodeId>
981
+ >();
976
982
 
977
983
  /** Dedup-target candidates still in the write buffer (keyed by id). Only
978
984
  * roots that have gained an edge/halo are targets; a fresh intermediate
979
985
  * branch is never folded onto. */
980
- protected _nearDedupBuf = new Map<NodeId, Float32Array>();
986
+ protected _nearDedupBuf: Map<NodeId, Float32Array> = new Map<
987
+ NodeId,
988
+ Float32Array
989
+ >();
981
990
  /** Ids currently in `_contentBuffer` (not yet flushed) — O(1) membership. */
982
- protected _bufferedIds = new Set<NodeId>();
991
+ protected _bufferedIds: Set<NodeId> = new Set<NodeId>();
983
992
 
984
993
  // ── Transparent-chain cache ────────────────────────────────────────────
985
994
 
@@ -171,18 +171,28 @@ test("3 — a near-tie between the winner and runner-up emits narrowDecision", a
171
171
  ["water is frigid so water is freezing", "freezing"],
172
172
  ]);
173
173
  // The near-tie has to be REAL: two candidates whose accounted spans are the
174
- // same, separated by a single move. `steel is hard so steel is` is that
175
- // extraction and recall both explain the whole prefix (grades 21011 and
176
- // 21010, margin 1).
174
+ // same, separated by a single move. `water is hard so water is ???` is that
175
+ // extraction and recall both explain the same span (grades 25011 and
176
+ // 25010, margin 1).
177
177
  //
178
- // The old fixture, `steel is frigid so steel is ???`, was a near-tie only
179
- // while CAST could not fire on it: the counterfactual subject and the seat
180
- // it fills sit on opposite sides of one recurring structure, and CAST's
181
- // subject gate used to reject any point whose alignment continued PAST the
182
- // seat which that very recurrence guarantees. With CAST firing, it leaves
183
- // only "???" unexplained and wins by 22008; a decisive win is the opposite
184
- // of what this test pins, and test 3b already covers it.
185
- const { steps } = await trace(m, "steel is hard so steel is");
178
+ // THIS FIXTURE HAS NOW BEEN REPLACED TWICE, BOTH TIMES FOR THE SAME REASON:
179
+ // a mechanism that genuinely explains the query started firing, and a
180
+ // decisive win is the opposite of what this test pins.
181
+ //
182
+ // * `steel is frigid so steel is ???` was a near-tie only while CAST could
183
+ // not fire on it CAST's subject gate used to reject any point whose
184
+ // alignment continued PAST the seat, which that fixture's recurrence
185
+ // guarantees. With CAST firing it wins by 22008.
186
+ // * `steel is hard so steel is` was a near-tie only while prefix
187
+ // completion was a buried recall TIER. As a market mechanism it grounds
188
+ // that query for what it is — the literal opening of exactly one trained
189
+ // form — at grade 1 against 21010, and answers `steel is hard so steel
190
+ // is strong`. That is a better answer, not a regression.
191
+ //
192
+ // The lesson for whoever re-fixtures this next: pick a query no mechanism can
193
+ // explain OUTRIGHT. A trailing `???` is what keeps this one honest — it is
194
+ // not the prefix of anything trained.
195
+ const { steps } = await trace(m, "water is hard so water is ???");
186
196
  const narrow = stepsNamed(steps, "narrowDecision");
187
197
  assert.equal(narrow.length, 1, "expected exactly one narrowDecision step");
188
198
  assert.ok(/margin \d+ grade-unit/.test(narrow[0].note), narrow[0].note);
@@ -36,7 +36,7 @@ import { test } from "node:test";
36
36
  import assert from "node:assert/strict";
37
37
  import { Mind } from "../dist/src/index.js";
38
38
  import { SQliteStore } from "../dist/src/store-sqlite.js";
39
- import { prefixCompletion } from "../dist/src/mind/prefix-completion.js";
39
+ import { prefixCompletion } from "../dist/src/mind/mechanisms/prefix-completion.js";
40
40
 
41
41
  const enc = (s) => new TextEncoder().encode(s);
42
42
  const dec = new TextDecoder();
@@ -8,7 +8,7 @@
8
8
  // 0.9629 at a one-byte truncation to 0.6206 at three bytes, against a
9
9
  // reachThreshold of 0.8750. The mechanism's guards were therefore never
10
10
  // reached — the trace read `candidates: 24, opened: 0` — and the query answered
11
- // nothing. `prefixCandidates` is the second SUPPLY that closes it, reading the
11
+ // nothing. `formsOpenedBy` is the second SUPPLY that closes it, reading the
12
12
  // leaf-id WINDOW index `indexSubSpans` already writes at deposit time. No
13
13
  // ingestion, storage or fold change is involved: this test would pass on a
14
14
  // store trained before the supply existed.
@@ -16,7 +16,7 @@
16
16
  // WHY THE ASSERTIONS ARE SHAPED THIS WAY. On a small fixture resonance may
17
17
  // well return the form by luck, and then an end-to-end "does it answer?" test
18
18
  // would pass with the supply deleted — pinning nothing. So the contract is
19
- // asserted on `prefixCandidates` DIRECTLY, and the resonance list is asserted
19
+ // asserted on `formsOpenedBy` DIRECTLY, and the resonance list is asserted
20
20
  // to lack the form, which is what makes the supply load-bearing rather than
21
21
  // redundant.
22
22
  //
@@ -27,10 +27,8 @@ import { test } from "node:test";
27
27
  import assert from "node:assert/strict";
28
28
  import { Mind } from "../dist/src/index.js";
29
29
  import { SQliteStore } from "../dist/src/store-sqlite.js";
30
- import {
31
- prefixCandidates,
32
- prefixCompletion,
33
- } from "../dist/src/mind/prefix-completion.js";
30
+ import { prefixCompletion } from "../dist/src/mind/mechanisms/prefix-completion.js";
31
+ import { formsOpenedBy } from "../dist/src/mind/traverse.js";
34
32
  import { gistOf, resolve } from "../dist/src/mind/primitives.js";
35
33
 
36
34
  const enc = (s) => new TextEncoder().encode(s);
@@ -71,7 +69,7 @@ test("a proper prefix reaches its trained form through the window supply", async
71
69
  // prefix is a LARGE-CORPUS property — cos falls to 0.6206 at a three-byte
72
70
  // truncation against a 0.8750 bar, on a 15.7M-node store — and cannot be
73
71
  // reproduced at this scale. That is why the contract below is asserted on
74
- // `prefixCandidates` DIRECTLY: deleting or emptying the supply fails this
72
+ // `formsOpenedBy` DIRECTLY: deleting or emptying the supply fails this
75
73
  // test regardless of what resonance happens to return.
76
74
  const ranked = (await m.store.resonate(gistOf(m, query), 64)).map((h) =>
77
75
  h.id
@@ -84,7 +82,7 @@ test("a proper prefix reaches its trained form through the window supply", async
84
82
  );
85
83
 
86
84
  // THE CONTRACT — the write side's own window index proposes the form.
87
- const proposed = prefixCandidates(m, query);
85
+ const proposed = formsOpenedBy(m, query);
88
86
  assert.ok(
89
87
  proposed.includes(formId),
90
88
  `the window supply must propose the trained form the query opens ` +
@@ -105,7 +103,7 @@ test("a proper prefix reaches its trained form through the window supply", async
105
103
  // supply that widened until it found something would be the real defect.
106
104
  const hub = enc("The ");
107
105
  assert.equal(
108
- prefixCompletion(m, hub, prefixCandidates(m, hub)),
106
+ prefixCompletion(m, hub, formsOpenedBy(m, hub)),
109
107
  null,
110
108
  "a query carrying no discriminative window must stay silent",
111
109
  );
@@ -31,7 +31,7 @@ import { test } from "node:test";
31
31
  import assert from "node:assert/strict";
32
32
  import { Mind } from "../dist/src/index.js";
33
33
  import { SQliteStore } from "../dist/src/store-sqlite.js";
34
- import { prefixCompletion } from "../dist/src/mind/prefix-completion.js";
34
+ import { prefixCompletion } from "../dist/src/mind/mechanisms/prefix-completion.js";
35
35
  import { resolve } from "../dist/src/mind/primitives.js";
36
36
 
37
37
  const enc = (s) => new TextEncoder().encode(s);