@hviana/sema 0.1.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 (110) hide show
  1. package/AGENTS.md +470 -0
  2. package/AUTHORS.md +12 -0
  3. package/COMMERCIAL-LICENSE.md +19 -0
  4. package/CONTRIBUTING.md +15 -0
  5. package/HOW_IT_WORKS.md +4210 -0
  6. package/LICENSE.md +117 -0
  7. package/README.md +290 -0
  8. package/TRADEMARKS.md +19 -0
  9. package/example/demo.ts +46 -0
  10. package/example/train_base.ts +2675 -0
  11. package/index.html +893 -0
  12. package/package.json +25 -0
  13. package/src/alphabet.ts +34 -0
  14. package/src/alu/README.md +332 -0
  15. package/src/alu/src/alu.ts +541 -0
  16. package/src/alu/src/expr.ts +339 -0
  17. package/src/alu/src/index.ts +115 -0
  18. package/src/alu/src/kernel-arith.ts +377 -0
  19. package/src/alu/src/kernel-bits.ts +199 -0
  20. package/src/alu/src/kernel-logic.ts +102 -0
  21. package/src/alu/src/kernel-nd.ts +235 -0
  22. package/src/alu/src/kernel-numeric.ts +466 -0
  23. package/src/alu/src/operation.ts +344 -0
  24. package/src/alu/src/parser.ts +574 -0
  25. package/src/alu/src/resonance.ts +161 -0
  26. package/src/alu/src/text.ts +83 -0
  27. package/src/alu/src/value.ts +327 -0
  28. package/src/alu/test/alu.test.ts +1004 -0
  29. package/src/bytes.ts +62 -0
  30. package/src/config.ts +227 -0
  31. package/src/derive/README.md +295 -0
  32. package/src/derive/src/deduction.ts +263 -0
  33. package/src/derive/src/index.ts +24 -0
  34. package/src/derive/src/priority-queue.ts +70 -0
  35. package/src/derive/src/rewrite.ts +127 -0
  36. package/src/derive/src/trie.ts +242 -0
  37. package/src/derive/test/derive.test.ts +137 -0
  38. package/src/extension.ts +42 -0
  39. package/src/geometry.ts +511 -0
  40. package/src/index.ts +38 -0
  41. package/src/ingest-cache.ts +224 -0
  42. package/src/mind/articulation.ts +137 -0
  43. package/src/mind/attention.ts +1061 -0
  44. package/src/mind/canonical.ts +107 -0
  45. package/src/mind/graph-search.ts +1100 -0
  46. package/src/mind/index.ts +18 -0
  47. package/src/mind/junction.ts +347 -0
  48. package/src/mind/learning.ts +246 -0
  49. package/src/mind/match.ts +507 -0
  50. package/src/mind/mechanisms/alu.ts +33 -0
  51. package/src/mind/mechanisms/cast.ts +568 -0
  52. package/src/mind/mechanisms/confluence.ts +268 -0
  53. package/src/mind/mechanisms/cover.ts +248 -0
  54. package/src/mind/mechanisms/extraction.ts +422 -0
  55. package/src/mind/mechanisms/recall.ts +241 -0
  56. package/src/mind/mind.ts +483 -0
  57. package/src/mind/pipeline-mechanism.ts +326 -0
  58. package/src/mind/pipeline.ts +300 -0
  59. package/src/mind/primitives.ts +201 -0
  60. package/src/mind/rationale.ts +275 -0
  61. package/src/mind/reasoning.ts +198 -0
  62. package/src/mind/recognition.ts +234 -0
  63. package/src/mind/resonance.ts +0 -0
  64. package/src/mind/trace.ts +108 -0
  65. package/src/mind/traverse.ts +556 -0
  66. package/src/mind/types.ts +281 -0
  67. package/src/rabitq-hnsw/README.md +303 -0
  68. package/src/rabitq-hnsw/src/database.ts +492 -0
  69. package/src/rabitq-hnsw/src/heap.ts +90 -0
  70. package/src/rabitq-hnsw/src/hnsw.ts +514 -0
  71. package/src/rabitq-hnsw/src/index.ts +15 -0
  72. package/src/rabitq-hnsw/src/prng.ts +39 -0
  73. package/src/rabitq-hnsw/src/rabitq.ts +308 -0
  74. package/src/rabitq-hnsw/src/store.ts +994 -0
  75. package/src/rabitq-hnsw/test/hnsw.test.ts +1213 -0
  76. package/src/store-sqlite.ts +928 -0
  77. package/src/store.ts +2148 -0
  78. package/src/vec.ts +124 -0
  79. package/test/00-extract.test.mjs +151 -0
  80. package/test/01-floor.test.mjs +20 -0
  81. package/test/02-roundtrip.test.mjs +83 -0
  82. package/test/03-recall.test.mjs +98 -0
  83. package/test/04-think.test.mjs +627 -0
  84. package/test/05-concepts.test.mjs +84 -0
  85. package/test/08-storage.test.mjs +948 -0
  86. package/test/09-edges.test.mjs +65 -0
  87. package/test/11-universality.test.mjs +180 -0
  88. package/test/13-conversation.test.mjs +228 -0
  89. package/test/14-scaling.test.mjs +503 -0
  90. package/test/15-decomposition-gap.test.mjs +0 -0
  91. package/test/16-bridge.test.mjs +250 -0
  92. package/test/17-intelligence.test.mjs +240 -0
  93. package/test/18-alu.test.mjs +209 -0
  94. package/test/19-nd.test.mjs +254 -0
  95. package/test/20-stability.test.mjs +489 -0
  96. package/test/21-partial.test.mjs +158 -0
  97. package/test/22-multihop.test.mjs +130 -0
  98. package/test/23-rationale.test.mjs +316 -0
  99. package/test/24-generalization.test.mjs +416 -0
  100. package/test/25-embedding.test.mjs +75 -0
  101. package/test/26-cooperative.test.mjs +89 -0
  102. package/test/27-saturation-drop.test.mjs +637 -0
  103. package/test/28-unknowable.test.mjs +88 -0
  104. package/test/29-counterfactual.test.mjs +476 -0
  105. package/test/30-conflict-resolution.test.mjs +166 -0
  106. package/test/31-audit.test.mjs +288 -0
  107. package/test/32-confluence.test.mjs +173 -0
  108. package/test/33-multi-candidate.test.mjs +222 -0
  109. package/test/34-cross-region.test.mjs +252 -0
  110. package/tsconfig.json +16 -0
@@ -0,0 +1,234 @@
1
+ // recognition.ts — Section 2 of the mind:
2
+ // Address + Read over byte streams — decompose a query into its known forms.
3
+ //
4
+ // recognise — structural + canonical decomposition into every stored form
5
+ // that leads somewhere (has a continuation edge or a halo).
6
+ // segment — leaf-parent segmentation using the geometry's own groupings.
7
+ import { rItem } from "./trace.js";
8
+
9
+ import type { MindContext, Recognition, Segment } from "./types.js";
10
+ import { foldTree, gistOf, perceive, resolve } from "./primitives.js";
11
+ import { leadsSomewhere } from "./traverse.js";
12
+ import { chainReach, leafIdAt } from "./canonical.js";
13
+ import { isChunk, type Sema } from "../sema.js";
14
+ import type { Leaf, Site } from "./graph-search.js";
15
+
16
+ /** Decompose a byte stream into every stored form that leads somewhere
17
+ * (has a continuation edge or a halo). Two complementary readings:
18
+ *
19
+ * • structural — walk the query's own perceived tree, naming each subtree
20
+ * by findLeaf at the leaves and findBranch above. Catches every form
21
+ * aligned to the query's segmentation.
22
+ *
23
+ * • canonical — re-derive the store's segmentation directly: at each byte,
24
+ * the longest known leaf, chained into flat branches. Names forms the
25
+ * query's own cut cannot, and records sub-leaf boundaries as `splits`.
26
+ *
27
+ * Both O(n · maxGroup) bounded O(1) probes — never a scan of the corpus. */
28
+ export function recognise(ctx: MindContext, bytes: Uint8Array): Recognition {
29
+ // Per-response memo (see MindContext.recogniseMemo): think, articulate and
30
+ // the pre-consume pass all recognise the same byte objects; each repeat is
31
+ // O(n·maxGroup²) store probes. Skipped while tracing so every call still
32
+ // emits its rationale step.
33
+ if (ctx.recogniseMemo && !ctx.trace) {
34
+ const hit = ctx.recogniseMemo.get(bytes);
35
+ if (hit !== undefined) return hit;
36
+ const fresh = recogniseImpl(ctx, bytes);
37
+ ctx.recogniseMemo.set(bytes, fresh);
38
+ return fresh;
39
+ }
40
+ return recogniseImpl(ctx, bytes);
41
+ }
42
+
43
+ function recogniseImpl(ctx: MindContext, bytes: Uint8Array): Recognition {
44
+ const store = ctx.store;
45
+ const sites: Site[] = [];
46
+ const leaves: Leaf[] = [];
47
+ const splits = new Set<number>();
48
+ if (bytes.length === 0) return { sites, leaves, splits };
49
+
50
+ // Span-resolve memo for THIS call: the structural pass (sub-runs inside
51
+ // leaf-parents) and the canonical pass (leaf-id chains) probe overlapping
52
+ // spans, and each resolve() is a full fold of the sub-span (fresh subarray
53
+ // objects — the per-response perceive memo cannot see them). Keyed
54
+ // numerically by (start, end); resolve is pure and the store is read-only
55
+ // here, so a hit is exact.
56
+ const spanIds = new Map<number, number | null>();
57
+ const resolveSpan = (start: number, end: number): number | null => {
58
+ const key = start * (bytes.length + 1) + end;
59
+ let id = spanIds.get(key);
60
+ if (id === undefined) {
61
+ id = resolve(ctx, bytes.subarray(start, end));
62
+ spanIds.set(key, id);
63
+ }
64
+ return id;
65
+ };
66
+
67
+ const emit = (start: number, end: number, id: number) => {
68
+ if (leadsSomewhere(ctx, id)) {
69
+ sites.push({ start, end, payload: id });
70
+ }
71
+ };
72
+
73
+ // ── structural: the query's own perceived tree ──────────────────────
74
+ const starts = new Set<number>();
75
+ starts.add(0);
76
+ foldTree(ctx, perceive(ctx, bytes), 0, (n, start, end, node) => {
77
+ if (n.kids === null) {
78
+ leaves.push({ start, end, bytes: n.leaf ?? new Uint8Array(0), node });
79
+ }
80
+ if (node !== null) emit(start, end, node);
81
+ if (isChunk(n)) {
82
+ starts.add(start);
83
+ // Try every sub-span within this leaf-parent.
84
+ const leafOffsets: number[] = [];
85
+ let off = start;
86
+ for (const k of n.kids) {
87
+ leafOffsets.push(off);
88
+ off += k.leaf?.length ?? 0;
89
+ }
90
+ for (let i = 0; i < n.kids.length; i++) {
91
+ const subIds: number[] = [];
92
+ for (let j = i; j < n.kids.length; j++) {
93
+ const kj = n.kids[j];
94
+ if (kj.kids !== null || !kj.leaf) break;
95
+ const lid = store.findLeaf(kj.leaf);
96
+ if (lid === null) break;
97
+ subIds.push(lid);
98
+ const branch = store.findBranch(subIds);
99
+ if (branch === null) continue;
100
+ const subEnd = leafOffsets[j] + (kj.leaf?.length ?? 0);
101
+ const resolved = resolveSpan(leafOffsets[i], subEnd);
102
+ if (resolved !== null) emit(leafOffsets[i], subEnd, resolved);
103
+ }
104
+ }
105
+ }
106
+ });
107
+
108
+ // ── canonical: longest-known-leaf re-segmentation ──────────────────
109
+ const W = ctx.space.maxGroup;
110
+ const singleLeaf: Array<{ id: number; end: number } | null> = new Array(
111
+ bytes.length,
112
+ ).fill(null);
113
+ for (let p = 0; p < bytes.length; p++) {
114
+ const id = leafIdAt(ctx, bytes, p);
115
+ if (id !== null) singleLeaf[p] = { id, end: p + 1 };
116
+ }
117
+
118
+ const leafFrom = (p: number): { id: number; end: number } | null => {
119
+ if (p >= bytes.length) return null;
120
+ return singleLeaf[p];
121
+ };
122
+
123
+ const chunkEnd = new Uint32Array(bytes.length);
124
+ const sorted = [...starts].sort((a, b) => a - b);
125
+ for (let si = 0; si < sorted.length; si++) {
126
+ const chunkStart = sorted[si];
127
+ const chunkLimit = si + 1 < sorted.length ? sorted[si + 1] : bytes.length;
128
+ for (let p = chunkStart; p < chunkLimit; p++) {
129
+ chunkEnd[p] = chunkLimit;
130
+ }
131
+ }
132
+
133
+ const tryChain = (
134
+ p: number,
135
+ maxIds: number,
136
+ ): void => {
137
+ const first = leafFrom(p);
138
+ if (!first) return;
139
+ emit(p, first.end, first.id);
140
+ const ids = [first.id];
141
+ let pos = first.end;
142
+ let prevId: number | null = null;
143
+ for (let depth = 1; pos < bytes.length && ids.length <= maxIds; depth++) {
144
+ const nx = leafFrom(pos);
145
+ if (!nx) break;
146
+ ids.push(nx.id);
147
+ pos = nx.end;
148
+ if (store.findBranch(ids) === null) continue;
149
+ const id = resolveSpan(p, pos);
150
+ if (id === null || id === prevId) continue;
151
+ prevId = id;
152
+ emit(p, pos, id);
153
+ }
154
+ };
155
+
156
+ for (let p = 0; p < bytes.length; p++) {
157
+ if (starts.has(p)) {
158
+ tryChain(p, chainReach(W)); // boundary start — full reach
159
+ } else {
160
+ const limit = chunkEnd[p] + W;
161
+ tryChain(p, Math.min(limit - p, chainReach(W)));
162
+ }
163
+ }
164
+
165
+ // ── splits: a form boundary that does not fall on a leaf edge ────────
166
+ const leafEdges = new Set<number>([bytes.length]);
167
+ for (const lf of leaves) leafEdges.add(lf.start);
168
+ for (const s of sites) {
169
+ if (!leafEdges.has(s.start)) splits.add(s.start);
170
+ if (!leafEdges.has(s.end)) splits.add(s.end);
171
+ }
172
+
173
+ ctx.trace?.step(
174
+ "recognise",
175
+ [rItem(bytes, "query")],
176
+ sites.map((s) =>
177
+ rItem(bytes.subarray(s.start, s.end), "form", s.payload, [
178
+ s.start,
179
+ s.end,
180
+ ])
181
+ ),
182
+ `decompose the query into ${sites.length} learnt form(s) that lead somewhere` +
183
+ ` (over ${leaves.length} perceived leaves)`,
184
+ );
185
+
186
+ return { sites, leaves, splits };
187
+ }
188
+
189
+ /** Segment bytes using the geometry's own groupings — leaf-parent
190
+ * nodes from the perceived tree, with consecutive bare leaves merged
191
+ * into one segment. Each segment's gist is perceived from its bytes
192
+ * IN ISOLATION, so the same content has the same gist regardless of
193
+ * where it appears. */
194
+ export function segment(ctx: MindContext, bytes: Uint8Array): Segment[] {
195
+ const tree = perceive(ctx, bytes);
196
+ const out: Segment[] = [];
197
+ let pendingStart = -1;
198
+ let pendingEnd = -1;
199
+
200
+ const flush = () => {
201
+ if (pendingStart >= 0 && pendingEnd > pendingStart) {
202
+ out.push({
203
+ start: pendingStart,
204
+ end: pendingEnd,
205
+ v: gistOf(ctx, bytes.subarray(pendingStart, pendingEnd)),
206
+ });
207
+ }
208
+ pendingStart = -1;
209
+ pendingEnd = -1;
210
+ };
211
+
212
+ const walk = (n: Sema, start: number): number => {
213
+ if (n.kids === null) {
214
+ const end = start + (n.leaf?.length ?? 0);
215
+ if (pendingStart < 0) pendingStart = start;
216
+ pendingEnd = end;
217
+ return end;
218
+ }
219
+ if (isChunk(n)) {
220
+ flush();
221
+ let end = start;
222
+ for (const c of n.kids) end += c.leaf?.length ?? 0;
223
+ out.push({ start, end, v: gistOf(ctx, bytes.subarray(start, end)) });
224
+ return end;
225
+ }
226
+ flush();
227
+ let pos = start;
228
+ for (const c of n.kids) pos = walk(c, pos);
229
+ return pos;
230
+ };
231
+ walk(tree, 0);
232
+ flush();
233
+ return out;
234
+ }
Binary file
@@ -0,0 +1,108 @@
1
+ // trace.ts — trace instrumentation + persistence (Section 9 of the mind).
2
+ //
3
+ // rItem, rNode, rDeriv — build RationaleItems from bytes/nodes/derivations
4
+ // traceDerivation — trace a full derivation proof tree
5
+ // MOVE_NOTE — human-readable names for each derivation move
6
+
7
+ import type { MindContext } from "./types.js";
8
+ import { read } from "./primitives.js";
9
+ import type { DerivationItem, DerivationStep } from "./graph-search.js";
10
+ import { decodeText } from "./rationale.js";
11
+ import type { RationaleItem } from "./rationale.js";
12
+
13
+ export function rItem(
14
+ bytes: Uint8Array,
15
+ role?: string,
16
+ node?: number,
17
+ span?: [number, number],
18
+ ): RationaleItem {
19
+ return {
20
+ text: decodeText(bytes),
21
+ role,
22
+ node: node ?? undefined,
23
+ span,
24
+ };
25
+ }
26
+
27
+ export function rNode(
28
+ ctx: MindContext,
29
+ id: number,
30
+ role?: string,
31
+ score?: number,
32
+ ): RationaleItem {
33
+ return {
34
+ text: decodeText(read(ctx, id)),
35
+ node: id,
36
+ role,
37
+ score,
38
+ };
39
+ }
40
+
41
+ export function rDeriv(
42
+ ctx: MindContext,
43
+ it: DerivationStep["conclusion"],
44
+ role?: string,
45
+ ): RationaleItem {
46
+ const text = it.bytes
47
+ ? decodeText(it.bytes)
48
+ : it.node !== undefined
49
+ ? decodeText(read(ctx, it.node))
50
+ : it.kind === "cover"
51
+ ? `cover@${it.span[0]}`
52
+ : `[${it.span[0]},${it.span[1]})`;
53
+ return { text, role: role ?? it.kind, node: it.node, span: it.span };
54
+ }
55
+
56
+ /** The standard FALL-THROUGH closer every self-gating mechanism ends with:
57
+ * close the open scope with no outputs and the reason, and return null so
58
+ * the caller can `return fail("…")` in one expression. `t` is the scope an
59
+ * enclosing `ctx.trace?.enter(...)` returned (undefined when not tracing). */
60
+ export function traceFail(
61
+ t: { done(outputs: RationaleItem[], note?: string): void } | undefined,
62
+ ): (note: string) => null {
63
+ return (note: string): null => {
64
+ t?.done([], note);
65
+ return null;
66
+ };
67
+ }
68
+
69
+ export const MOVE_NOTE: Record<string, string> = {
70
+ "follow-edge": "follow a learned continuation edge — 'what follows what'",
71
+ "concept-hop": "jump a concept (halo) link — a synonym's edge",
72
+ "voice": "emit the asker's own wording for this form (articulation)",
73
+ "ground": "a chain reached its terminal answer",
74
+ "splice-connector": "splice a learnt connector between two rewrites",
75
+ "split": "cut a span at a sub-leaf form boundary so a form can be reached",
76
+ "fuse": "fuse adjacent fragments toward a deeper learned form",
77
+ "recompose": "recompose fused parts into a learned whole that leads on",
78
+ "bridge": "advance the cover frontier across this span",
79
+ "pool-vote":
80
+ "pool independent regions' evidence for a shared anchor (sum, not shortest path)",
81
+ "axiom": "a seed: a perceived leaf, recognised form, or computed result",
82
+ "step": "a derivation step",
83
+ };
84
+
85
+ export function traceDerivation(
86
+ ctx: MindContext,
87
+ steps: ReadonlyArray<DerivationStep>,
88
+ ): void {
89
+ const t = ctx.trace;
90
+ if (!t) return;
91
+ const indexOfOrder = new Map<number, number>();
92
+ for (const s of steps) {
93
+ const note = MOVE_NOTE[s.move] ?? s.move;
94
+ const deps = s.producers
95
+ .map((o) => indexOfOrder.get(o))
96
+ .filter((x): x is number => x !== undefined);
97
+ const premises: RationaleItem[] = s.premises.map((p) => rDeriv(ctx, p));
98
+ const conclusion: RationaleItem[] = [rDeriv(ctx, s.conclusion)];
99
+ const index = t.step(
100
+ s.move,
101
+ premises,
102
+ conclusion,
103
+ s.cost > 0 ? `${note} (cost ${s.cost})` : note,
104
+ deps.length > 0 ? deps : undefined,
105
+ );
106
+ indexOfOrder.set(s.order, index);
107
+ }
108
+ }