@hviana/sema 0.4.1 → 0.4.2

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 (152) hide show
  1. package/package.json +1 -1
  2. package/src/ingest-cache.ts +4 -0
  3. package/src/meter.ts +5 -0
  4. package/src/mind/attention.ts +18 -1
  5. package/src/mind/bridge.ts +292 -54
  6. package/src/mind/junction.ts +21 -7
  7. package/src/mind/match.ts +92 -1
  8. package/src/mind/mechanisms/cast.ts +12 -0
  9. package/src/mind/mechanisms/confluence.ts +30 -1
  10. package/src/mind/mechanisms/cover.ts +36 -4
  11. package/src/mind/mechanisms/recall.ts +21 -44
  12. package/src/mind/mind.ts +39 -2
  13. package/src/mind/pipeline-mechanism.ts +86 -4
  14. package/src/mind/pipeline.ts +1 -1
  15. package/src/mind/reasoning.ts +15 -8
  16. package/src/mind/recognition.ts +40 -0
  17. package/src/mind/resonance.ts +0 -0
  18. package/src/mind/traverse.ts +17 -15
  19. package/src/mind/types.ts +10 -0
  20. package/test/49-natural-units-synonym-bridge.test.mjs +56 -15
  21. package/dist/example/demo.d.ts +0 -1
  22. package/dist/example/demo.js +0 -39
  23. package/dist/example/train_base.d.ts +0 -87
  24. package/dist/example/train_base.js +0 -2252
  25. package/dist/src/alphabet.d.ts +0 -7
  26. package/dist/src/alphabet.js +0 -33
  27. package/dist/src/alu/src/alu.d.ts +0 -185
  28. package/dist/src/alu/src/alu.js +0 -440
  29. package/dist/src/alu/src/expr.d.ts +0 -61
  30. package/dist/src/alu/src/expr.js +0 -318
  31. package/dist/src/alu/src/index.d.ts +0 -11
  32. package/dist/src/alu/src/index.js +0 -19
  33. package/dist/src/alu/src/kernel-arith.d.ts +0 -16
  34. package/dist/src/alu/src/kernel-arith.js +0 -264
  35. package/dist/src/alu/src/kernel-bits.d.ts +0 -19
  36. package/dist/src/alu/src/kernel-bits.js +0 -152
  37. package/dist/src/alu/src/kernel-logic.d.ts +0 -4
  38. package/dist/src/alu/src/kernel-logic.js +0 -60
  39. package/dist/src/alu/src/kernel-nd.d.ts +0 -3
  40. package/dist/src/alu/src/kernel-nd.js +0 -208
  41. package/dist/src/alu/src/kernel-numeric.d.ts +0 -54
  42. package/dist/src/alu/src/kernel-numeric.js +0 -366
  43. package/dist/src/alu/src/operation.d.ts +0 -168
  44. package/dist/src/alu/src/operation.js +0 -189
  45. package/dist/src/alu/src/parser.d.ts +0 -221
  46. package/dist/src/alu/src/parser.js +0 -577
  47. package/dist/src/alu/src/resonance.d.ts +0 -55
  48. package/dist/src/alu/src/resonance.js +0 -126
  49. package/dist/src/alu/src/text.d.ts +0 -31
  50. package/dist/src/alu/src/text.js +0 -73
  51. package/dist/src/alu/src/value.d.ts +0 -109
  52. package/dist/src/alu/src/value.js +0 -300
  53. package/dist/src/alu/test/alu.test.d.ts +0 -1
  54. package/dist/src/alu/test/alu.test.js +0 -764
  55. package/dist/src/bytes.d.ts +0 -14
  56. package/dist/src/bytes.js +0 -59
  57. package/dist/src/canon.d.ts +0 -26
  58. package/dist/src/canon.js +0 -57
  59. package/dist/src/config.d.ts +0 -111
  60. package/dist/src/config.js +0 -91
  61. package/dist/src/derive/src/deduction.d.ts +0 -136
  62. package/dist/src/derive/src/deduction.js +0 -159
  63. package/dist/src/derive/src/index.d.ts +0 -8
  64. package/dist/src/derive/src/index.js +0 -11
  65. package/dist/src/derive/src/priority-queue.d.ts +0 -20
  66. package/dist/src/derive/src/priority-queue.js +0 -73
  67. package/dist/src/derive/src/rewrite.d.ts +0 -56
  68. package/dist/src/derive/src/rewrite.js +0 -100
  69. package/dist/src/derive/src/trie.d.ts +0 -90
  70. package/dist/src/derive/src/trie.js +0 -217
  71. package/dist/src/derive/test/derive.test.d.ts +0 -1
  72. package/dist/src/derive/test/derive.test.js +0 -122
  73. package/dist/src/extension.d.ts +0 -37
  74. package/dist/src/extension.js +0 -7
  75. package/dist/src/geometry.d.ts +0 -175
  76. package/dist/src/geometry.js +0 -823
  77. package/dist/src/index.d.ts +0 -17
  78. package/dist/src/index.js +0 -19
  79. package/dist/src/ingest-cache.d.ts +0 -41
  80. package/dist/src/ingest-cache.js +0 -161
  81. package/dist/src/meter.d.ts +0 -171
  82. package/dist/src/meter.js +0 -269
  83. package/dist/src/mind/articulation.d.ts +0 -6
  84. package/dist/src/mind/articulation.js +0 -99
  85. package/dist/src/mind/attention.d.ts +0 -414
  86. package/dist/src/mind/attention.js +0 -2065
  87. package/dist/src/mind/bridge.d.ts +0 -39
  88. package/dist/src/mind/bridge.js +0 -738
  89. package/dist/src/mind/canonical.d.ts +0 -34
  90. package/dist/src/mind/canonical.js +0 -93
  91. package/dist/src/mind/graph-search.d.ts +0 -294
  92. package/dist/src/mind/graph-search.js +0 -996
  93. package/dist/src/mind/index.d.ts +0 -9
  94. package/dist/src/mind/index.js +0 -5
  95. package/dist/src/mind/junction.d.ts +0 -134
  96. package/dist/src/mind/junction.js +0 -331
  97. package/dist/src/mind/learning.d.ts +0 -75
  98. package/dist/src/mind/learning.js +0 -270
  99. package/dist/src/mind/match.d.ts +0 -166
  100. package/dist/src/mind/match.js +0 -565
  101. package/dist/src/mind/mechanisms/alu.d.ts +0 -4
  102. package/dist/src/mind/mechanisms/alu.js +0 -36
  103. package/dist/src/mind/mechanisms/cast.d.ts +0 -89
  104. package/dist/src/mind/mechanisms/cast.js +0 -773
  105. package/dist/src/mind/mechanisms/confluence.d.ts +0 -24
  106. package/dist/src/mind/mechanisms/confluence.js +0 -225
  107. package/dist/src/mind/mechanisms/cover.d.ts +0 -6
  108. package/dist/src/mind/mechanisms/cover.js +0 -203
  109. package/dist/src/mind/mechanisms/extraction.d.ts +0 -33
  110. package/dist/src/mind/mechanisms/extraction.js +0 -300
  111. package/dist/src/mind/mechanisms/recall.d.ts +0 -16
  112. package/dist/src/mind/mechanisms/recall.js +0 -388
  113. package/dist/src/mind/mind.d.ts +0 -330
  114. package/dist/src/mind/mind.js +0 -594
  115. package/dist/src/mind/pipeline-mechanism.d.ts +0 -172
  116. package/dist/src/mind/pipeline-mechanism.js +0 -382
  117. package/dist/src/mind/pipeline.d.ts +0 -49
  118. package/dist/src/mind/pipeline.js +0 -275
  119. package/dist/src/mind/primitives.d.ts +0 -66
  120. package/dist/src/mind/primitives.js +0 -306
  121. package/dist/src/mind/rationale.d.ts +0 -139
  122. package/dist/src/mind/rationale.js +0 -163
  123. package/dist/src/mind/reasoning.d.ts +0 -40
  124. package/dist/src/mind/reasoning.js +0 -272
  125. package/dist/src/mind/recognition.d.ts +0 -20
  126. package/dist/src/mind/recognition.js +0 -463
  127. package/dist/src/mind/resonance.d.ts +0 -23
  128. package/dist/src/mind/resonance.js +0 -0
  129. package/dist/src/mind/trace.d.ts +0 -15
  130. package/dist/src/mind/trace.js +0 -73
  131. package/dist/src/mind/traverse.d.ts +0 -124
  132. package/dist/src/mind/traverse.js +0 -649
  133. package/dist/src/mind/types.d.ts +0 -323
  134. package/dist/src/mind/types.js +0 -130
  135. package/dist/src/rabitq-ivf/src/database.d.ts +0 -113
  136. package/dist/src/rabitq-ivf/src/database.js +0 -201
  137. package/dist/src/rabitq-ivf/src/index.d.ts +0 -7
  138. package/dist/src/rabitq-ivf/src/index.js +0 -4
  139. package/dist/src/rabitq-ivf/src/ivf.d.ts +0 -200
  140. package/dist/src/rabitq-ivf/src/ivf.js +0 -1165
  141. package/dist/src/rabitq-ivf/src/prng.d.ts +0 -19
  142. package/dist/src/rabitq-ivf/src/prng.js +0 -36
  143. package/dist/src/rabitq-ivf/src/rabitq.d.ts +0 -95
  144. package/dist/src/rabitq-ivf/src/rabitq.js +0 -283
  145. package/dist/src/sema.d.ts +0 -31
  146. package/dist/src/sema.js +0 -63
  147. package/dist/src/store-sqlite.d.ts +0 -184
  148. package/dist/src/store-sqlite.js +0 -942
  149. package/dist/src/store.d.ts +0 -678
  150. package/dist/src/store.js +0 -1703
  151. package/dist/src/vec.d.ts +0 -31
  152. package/dist/src/vec.js +0 -109
@@ -1,9 +0,0 @@
1
- export { Mind } from "./mind.js";
2
- export type { Input, Response } from "./mind.js";
3
- export type { ComputedSpan, ExtensionHost } from "./mind.js";
4
- export type { MechanismResult, PipelineMechanism, Precomputed, } from "./pipeline-mechanism.js";
5
- export type { InspectRationale, RationaleItem, RationaleStep, } from "./rationale.js";
6
- export type { AnchorRejectionReason, ClimbConsensusData, ConsensusAnchorTrace, ConsensusReachTrace, ConsensusRegionTrace, CrossRegionTier, JunctionVoteTrace, RegionOutcome, } from "./attention.js";
7
- export type { AncestorReach, AttentionRead, SaturationReason, SaturationStop, } from "./types.js";
8
- export type { DepositReport } from "./learning.js";
9
- export type { DecideGroundingData, NarrowDecisionData, Provenance, } from "./pipeline.js";
@@ -1,5 +0,0 @@
1
- // mind/index.ts — public surface of the mind module.
2
- //
3
- // Re-exports the Mind class and all public types that were previously
4
- // exported from mind/mind.ts directly.
5
- export { Mind } from "./mind.js";
@@ -1,134 +0,0 @@
1
- import type { Hit } from "../store.js";
2
- import type { MindContext } from "./types.js";
3
- export interface Junction {
4
- /** The node whose learnt bytes evidence this junction (a container form,
5
- * a continuation, or a context). */
6
- id: number;
7
- /** The bytes that belong between left and right. */
8
- interior: Uint8Array;
9
- }
10
- /** Which relaxation produced a {@link SynonymJunction}: one side replaced by
11
- * a distributional halo sibling (`single-synonym`), or both (`double-
12
- * synonym`) — the two remaining rungs of the graded ladder below exact DAG
13
- * containment (see the module doc atop {@link junctionSynonyms}). */
14
- export type SynonymJunctionTier = "single-synonym" | "double-synonym";
15
- export interface SynonymJunction extends Junction {
16
- tier: SynonymJunctionTier;
17
- /** Sibling score for a single-synonym junction; min(left, right) sibling
18
- * score for a double-synonym junction. */
19
- confidence: number;
20
- }
21
- /** The exact node ids and halo siblings resolved for one junction call's two
22
- * sides — computed ONCE and reused by every ladder rung that needs them
23
- * (junctionSynonyms' two tiers, and the structural-resonance tier beyond
24
- * it). A failed synonym junction means only "no common DAG container was
25
- * proven" — it does NOT mean the loaded siblings stop being useful. */
26
- export interface JunctionSynonymSides {
27
- leftId: number | null;
28
- rightId: number | null;
29
- leftSiblings: Hit[];
30
- rightSiblings: Hit[];
31
- }
32
- /** Resolve `left`/`right` to their exact node ids (when known) and load each
33
- * resolved side's halo siblings once — deterministic (haloSiblings already
34
- * ranks nearest-first) and shared by every ladder rung that consults
35
- * siblings, so no ladder rung repeats a halo ANN query the previous one
36
- * already paid for. */
37
- export declare function loadJunctionSynonymSides(ctx: MindContext, left: Uint8Array, right: Uint8Array): Promise<JunctionSynonymSides>;
38
- /** Seed node ids to ascend from for one side of a junction: the side's own
39
- * node when it is a stored form, plus — when the node has no structural
40
- * parents — its canonical window ids. A non-W-aligned node may have no
41
- * parents, but its constituent W-grams typically do; the window ids
42
- * provide alternative ascent paths. The `parentsFirst(…, 1)` probe is a
43
- * single indexed lookup, far cheaper than computing every window id, so
44
- * the window-id path is only taken when the node alone cannot ascend.
45
- * Exported for callers (synonym junctions) that hold one side FIXED across
46
- * several calls and so compute its seeds once instead of per call. */
47
- export declare function junctionSeeds(ctx: MindContext, b: Uint8Array): number[];
48
- /** Per-response cache of the identity walks' pure reads (capped bytes,
49
- * parent pages, container pages), keyed by the response lifecycle object
50
- * (ctx.climbMemo). One response issues many walks whose ancestries overlap
51
- * heavily (pair sides repeat across combos, and synonym walks revisit the
52
- * same neighbourhoods); the store is read-only while a response is in flight,
53
- * so every one of these reads is a pure function of the id — repeats cost a
54
- * Map hit instead of a SQL statement or a byte reconstruction. */
55
- export interface WalkCache {
56
- /** id → prefix bytes read so far + whether they are the COMPLETE bytes
57
- * (shorter than the cap that read them). */
58
- reads: Map<number, {
59
- b: Uint8Array;
60
- complete: boolean;
61
- }>;
62
- parents: Map<number, number[]>;
63
- containers: Map<number, number[]>;
64
- }
65
- export declare function walkCache(ctx: MindContext): WalkCache | null;
66
- export declare function cachedRead(ctx: MindContext, cache: WalkCache | null, id: number, cap: number): Uint8Array;
67
- /** Tier 1 body, parameterised on already-resolved seed lists so a caller
68
- * holding one side FIXED across several calls (synonym junctions) pays for
69
- * that side's seeds once, not once per call. The byte-containment check
70
- * below ensures only genuine containers are returned regardless of seeds.
71
- *
72
- * BOUNDED at corpus scale by three disciplines (profiled on a 17.7M-node
73
- * store, where the unbounded form spent >90% of a query's CPU here):
74
- * • PHRASE-SCALE READS — a junction container is by contract a whole the
75
- * pair nearly exhausts (glue from a period to a phrase), so every visit
76
- * reads at most `maxContainer + 1` bytes (`bytesPrefix` stops early).
77
- * A node whose bytes exceed the cap cannot be a junction container, and
78
- * its ancestors are strictly larger — the branch is PRUNED, never
79
- * reconstructing a corpus-sized deposit (an oasst2 conversation) just
80
- * to reject it.
81
- * • EXPANSION BUDGET — at most √N·W nodes are popped in total: a √N-wide
82
- * frontier (the one fan-out convention) through the ~W structural
83
- * levels that separate phrase-scale content from its containers
84
- * (perception trees are W-ary, so a junction container lies within a
85
- * few levels of its parts). A side too common to decide within the
86
- * budget abstains here and falls through to the resonance tier (the
87
- * climb's own saturation semantics).
88
- *
89
- * REFUTED TIGHTENING (measured, 325K contexts): giving this walk
90
- * edgeAncestors' cumulative LATERAL-CONE limit — abstain once the
91
- * accumulated lateral entries pass √N — would cut most of the pops (47
92
- * of 56 walks exceed √N lateral, and 47 exhaust the budget), but TWO OF
93
- * THE FOUR walks that actually found a container had lateral spread of
94
- * 1425 and 1426, far past √N. The cone limit is sound for
95
- * edgeAncestors' question and wrong for this one: a junction container
96
- * is legitimately reached across many containing structures. Half the
97
- * successful junctions would be lost.
98
- * • per-node hub guards — parent fan-outs beyond √N are hubs (not
99
- * expanded); each node contributes at most one √N page of containers;
100
- * √N collected candidates decide. */
101
- export declare function junctionContainersFrom(ctx: MindContext, left: Uint8Array, right: Uint8Array, maxContainer: number, leftSeeds: number[], rightSeeds: number[],
102
- /** Shared expansion budget — a TIER's √N pops, not each walk's, when one
103
- * tier issues several walks (synonym junctions try up to 2·haloQueryK
104
- * siblings; without a shared budget each sibling would spend its own √N). */
105
- budget?: {
106
- n: number;
107
- },
108
- /** ORDER-FREE containment: also accept containers holding right-then-left.
109
- * A junction is evidence that the two forms were LEARNT TOGETHER; which
110
- * one the query happened to mention first is a fact about the query, not
111
- * about the learnt whole. The walk is identical (the seed ascent does not
112
- * depend on order) — only the byte-containment test gains a second probe,
113
- * so order-freedom costs two indexOf calls per visited node, never a
114
- * second walk. */
115
- unordered?: boolean): Junction[];
116
- /** Tier 1 entry point: every learnt whole that literally contains
117
- * left-then-right, found by ascending the structural DAG (parents +
118
- * containment links) from the two sides' content-addressed identities.
119
- * Both sides' seeds resolved fresh, one call. */
120
- export declare function junctionContainers(ctx: MindContext, left: Uint8Array, right: Uint8Array, maxContainer: number, unordered?: boolean): Junction[];
121
- /** Tier 2.5: synonym junctions — the container ascent (tier 1) applied to
122
- * halo siblings of left and right. When a distributional synonym of one
123
- * form participates in a learnt whole with the other form, the container
124
- * between the synonym and the other side is valid evidence for the
125
- * original pair. The container evidence is exact (content-addressed DAG
126
- * ascent, with window-id-enhanced seeds so non-W-aligned siblings still
127
- * ascend); the relaxation is only in which form occupies one side — a
128
- * distributional sibling rather than the exact form.
129
- *
130
- * ONE expansion budget is shared by every sibling walk in this call, so
131
- * cost is bounded at √N·W pops total regardless of how many siblings are
132
- * tried. A sibling whose bytes exceed `maxInterior` is skipped (it
133
- * cannot be junction-sized). */
134
- export declare function junctionSynonyms(ctx: MindContext, left: Uint8Array, right: Uint8Array, maxInterior: number, unordered?: boolean, sides?: JunctionSynonymSides): Promise<SynonymJunction[]>;
@@ -1,331 +0,0 @@
1
- // junction.ts — content-addressed junction search (bridge Tier 1).
2
- //
3
- // "Which learnt wholes ran L and R together?" answered by DAG ascent, not a
4
- // similarity guess: hash-consing means any deposit containing L's bytes shares
5
- // L's node (or L's canonical-window ids — position-independent identities), so
6
- // climbing parents + containment links from L's and R's seeds reaches every
7
- // container that literally holds L-then-R. A resonance seed (the gist of the
8
- // bare concatenation — an object never learnt) could rank the true container
9
- // out of its top-k; the ascent cannot.
10
- //
11
- // Extracted from resonance.ts so BOTH the bridge (a connector between two
12
- // adjacent ANSWER pieces) and cross-region attention (the joint CONTEXT of two
13
- // non-adjacent QUERY regions) ascend by the same disciplined, bounded walk.
14
- import { read, resolve } from "./primitives.js";
15
- import { windowIds } from "./canonical.js";
16
- import { hubBound } from "./traverse.js";
17
- import { haloSiblings } from "./match.js";
18
- import { indexOf } from "../bytes.js";
19
- /** Resolve `left`/`right` to their exact node ids (when known) and load each
20
- * resolved side's halo siblings once — deterministic (haloSiblings already
21
- * ranks nearest-first) and shared by every ladder rung that consults
22
- * siblings, so no ladder rung repeats a halo ANN query the previous one
23
- * already paid for. */
24
- export async function loadJunctionSynonymSides(ctx, left, right) {
25
- const leftId = resolve(ctx, left);
26
- const rightId = resolve(ctx, right);
27
- const leftSiblings = leftId !== null ? await haloSiblings(ctx, leftId) : [];
28
- const rightSiblings = rightId !== null
29
- ? await haloSiblings(ctx, rightId)
30
- : [];
31
- return { leftId, rightId, leftSiblings, rightSiblings };
32
- }
33
- /** Seed node ids to ascend from for one side of a junction: the side's own
34
- * node when it is a stored form, plus — when the node has no structural
35
- * parents — its canonical window ids. A non-W-aligned node may have no
36
- * parents, but its constituent W-grams typically do; the window ids
37
- * provide alternative ascent paths. The `parentsFirst(…, 1)` probe is a
38
- * single indexed lookup, far cheaper than computing every window id, so
39
- * the window-id path is only taken when the node alone cannot ascend.
40
- * Exported for callers (synonym junctions) that hold one side FIXED across
41
- * several calls and so compute its seeds once instead of per call. */
42
- export function junctionSeeds(ctx, b) {
43
- const r = resolve(ctx, b);
44
- if (r !== null) {
45
- if (ctx.store.parentsFirst(r, 1).length > 0)
46
- return [r];
47
- const wids = [...windowIds(ctx, b).values()];
48
- return [r, ...wids];
49
- }
50
- const wids = [...windowIds(ctx, b).values()];
51
- if (wids.length <= 2)
52
- return wids;
53
- return [wids[0], wids[wids.length - 1]];
54
- }
55
- const walkCaches = new WeakMap();
56
- export function walkCache(ctx) {
57
- if (ctx.climbMemo === null)
58
- return null;
59
- let c = walkCaches.get(ctx.climbMemo);
60
- if (c === undefined) {
61
- walkCaches.set(ctx.climbMemo, c = { reads: new Map(), parents: new Map(), containers: new Map() });
62
- }
63
- return c;
64
- }
65
- export function cachedRead(ctx, cache, id, cap) {
66
- if (cache === null)
67
- return read(ctx, id, cap + 1);
68
- const hit = cache.reads.get(id);
69
- // A cached COMPLETE read serves any cap; a cached truncated read serves
70
- // any cap it already covers (the caller only checks `length > cap`).
71
- if (hit !== undefined && (hit.complete || hit.b.length > cap))
72
- return hit.b;
73
- const b = read(ctx, id, cap + 1);
74
- cache.reads.set(id, { b, complete: b.length <= cap });
75
- return b;
76
- }
77
- function cachedParents(ctx, cache, id, limit) {
78
- if (cache === null)
79
- return ctx.store.parentsFirst(id, limit);
80
- let v = cache.parents.get(id);
81
- if (v === undefined) {
82
- v = ctx.store.parentsFirst(id, limit);
83
- cache.parents.set(id, v);
84
- }
85
- return v;
86
- }
87
- function cachedContainers(ctx, cache, id, limit) {
88
- if (cache === null)
89
- return ctx.store.containersSlice(id, 0, limit);
90
- let v = cache.containers.get(id);
91
- if (v === undefined) {
92
- v = ctx.store.containersSlice(id, 0, limit);
93
- cache.containers.set(id, v);
94
- }
95
- return v;
96
- }
97
- /** Tier 1 body, parameterised on already-resolved seed lists so a caller
98
- * holding one side FIXED across several calls (synonym junctions) pays for
99
- * that side's seeds once, not once per call. The byte-containment check
100
- * below ensures only genuine containers are returned regardless of seeds.
101
- *
102
- * BOUNDED at corpus scale by three disciplines (profiled on a 17.7M-node
103
- * store, where the unbounded form spent >90% of a query's CPU here):
104
- * • PHRASE-SCALE READS — a junction container is by contract a whole the
105
- * pair nearly exhausts (glue from a period to a phrase), so every visit
106
- * reads at most `maxContainer + 1` bytes (`bytesPrefix` stops early).
107
- * A node whose bytes exceed the cap cannot be a junction container, and
108
- * its ancestors are strictly larger — the branch is PRUNED, never
109
- * reconstructing a corpus-sized deposit (an oasst2 conversation) just
110
- * to reject it.
111
- * • EXPANSION BUDGET — at most √N·W nodes are popped in total: a √N-wide
112
- * frontier (the one fan-out convention) through the ~W structural
113
- * levels that separate phrase-scale content from its containers
114
- * (perception trees are W-ary, so a junction container lies within a
115
- * few levels of its parts). A side too common to decide within the
116
- * budget abstains here and falls through to the resonance tier (the
117
- * climb's own saturation semantics).
118
- *
119
- * REFUTED TIGHTENING (measured, 325K contexts): giving this walk
120
- * edgeAncestors' cumulative LATERAL-CONE limit — abstain once the
121
- * accumulated lateral entries pass √N — would cut most of the pops (47
122
- * of 56 walks exceed √N lateral, and 47 exhaust the budget), but TWO OF
123
- * THE FOUR walks that actually found a container had lateral spread of
124
- * 1425 and 1426, far past √N. The cone limit is sound for
125
- * edgeAncestors' question and wrong for this one: a junction container
126
- * is legitimately reached across many containing structures. Half the
127
- * successful junctions would be lost.
128
- * • per-node hub guards — parent fan-outs beyond √N are hubs (not
129
- * expanded); each node contributes at most one √N page of containers;
130
- * √N collected candidates decide. */
131
- export function junctionContainersFrom(ctx, left, right, maxContainer, leftSeeds, rightSeeds,
132
- /** Shared expansion budget — a TIER's √N pops, not each walk's, when one
133
- * tier issues several walks (synonym junctions try up to 2·haloQueryK
134
- * siblings; without a shared budget each sibling would spend its own √N). */
135
- budget,
136
- /** ORDER-FREE containment: also accept containers holding right-then-left.
137
- * A junction is evidence that the two forms were LEARNT TOGETHER; which
138
- * one the query happened to mention first is a fact about the query, not
139
- * about the learnt whole. The walk is identical (the seed ascent does not
140
- * depend on order) — only the byte-containment test gains a second probe,
141
- * so order-freedom costs two indexOf calls per visited node, never a
142
- * second walk. */
143
- unordered = false) {
144
- const bound = hubBound(ctx);
145
- const joinedLength = left.length + right.length;
146
- const seeds = [...new Set([...leftSeeds, ...rightSeeds])];
147
- if (seeds.length === 0)
148
- return [];
149
- const b = budget ?? { n: bound * ctx.space.maxGroup };
150
- if (ctx.meter)
151
- ctx.meter.junctionWalks++;
152
- // DEPTH CAP: perception trees are W-ary and a junction container is
153
- // phrase-scale, so it sits within ~log_W(maxContainer) structural levels
154
- // of its parts — at most W levels for any practical W (plus the
155
- // containment hop the seeds already are). Ancestry beyond that depth is
156
- // strictly larger than any admissible container; walking it can only burn
157
- // budget, never find a junction.
158
- const maxDepth = ctx.space.maxGroup;
159
- const out = [];
160
- const cache = walkCache(ctx);
161
- const seen = new Set(seeds);
162
- const stack = seeds.map((id) => ({
163
- id,
164
- d: 0,
165
- }));
166
- while (stack.length > 0 && out.length < bound && b.n-- > 0) {
167
- const { id: x, d } = stack.pop();
168
- if (ctx.meter)
169
- ctx.meter.junctionPops++;
170
- const f = cachedRead(ctx, cache, x, maxContainer);
171
- if (f.length > maxContainer)
172
- continue; // beyond phrase scale: prune branch
173
- if (unordered) {
174
- // Order-free containment does NOT require disjoint occurrences: two
175
- // grid-aligned fragments of the same whole legitimately OVERLAP inside
176
- // it ("red " at 0 and " cir" at 3 in `red circle`), and both being
177
- // literal substrings is the evidence. The interior is the gap between
178
- // them when they are disjoint, empty otherwise. Only the containment
179
- // test differs from the ordered form — and because occurrences may
180
- // overlap or abut, `f.length > joinedLength` is too strict (grid
181
- // fragments of one whole sum past it; "red " + "circle" exactly equals
182
- // `red circle`). The container must be a STRICT super-form of each
183
- // side, so that holding both is more than restating either.
184
- const li = indexOf(f, left, 0);
185
- const ri = li >= 0 ? indexOf(f, right, 0) : -1;
186
- if (li >= 0 && ri >= 0 && f.length > Math.max(left.length, right.length)) {
187
- const lo = Math.min(li + left.length, ri + right.length);
188
- const hi = Math.max(li, ri);
189
- out.push({
190
- id: x,
191
- interior: lo < hi ? f.subarray(lo, hi) : f.subarray(0, 0),
192
- });
193
- }
194
- }
195
- else if (f.length > joinedLength) {
196
- const li = indexOf(f, left, 0);
197
- if (li >= 0) {
198
- const ri = indexOf(f, right, li + left.length);
199
- if (ri >= 0) {
200
- out.push({ id: x, interior: f.subarray(li + left.length, ri) });
201
- }
202
- }
203
- }
204
- if (d >= maxDepth)
205
- continue; // deeper ancestry is beyond phrase scale
206
- const parents = cachedParents(ctx, cache, x, bound + 1);
207
- if (parents.length <= bound) { // beyond √N parents: a hub, not expanded
208
- for (const p of parents) {
209
- if (!seen.has(p)) {
210
- seen.add(p);
211
- stack.push({ id: p, d: d + 1 });
212
- }
213
- }
214
- }
215
- // Containment fan-out under the SAME hub reading as parents: a node
216
- // whose containers fill a whole √N page is COMMON content — its
217
- // containment ancestry reaches a non-discriminative slice of the corpus
218
- // (the climb's saturation semantics), and walking it would spend the
219
- // entire budget discovering nothing a junction could use. Such a node
220
- // is not expanded through containment; a pair whose sides are common
221
- // abstains here in a handful of pops and falls through to the resonance
222
- // tier. Below the page bound the read IS the full container list, so
223
- // the walk stays exact exactly where identity evidence discriminates.
224
- const containers = cachedContainers(ctx, cache, x, bound);
225
- if (containers.length < bound) {
226
- for (const c of containers) {
227
- if (!seen.has(c)) {
228
- seen.add(c);
229
- stack.push({ id: c, d: d + 1 });
230
- }
231
- }
232
- }
233
- }
234
- return out;
235
- }
236
- /** Tier 1 entry point: every learnt whole that literally contains
237
- * left-then-right, found by ascending the structural DAG (parents +
238
- * containment links) from the two sides' content-addressed identities.
239
- * Both sides' seeds resolved fresh, one call. */
240
- export function junctionContainers(ctx, left, right, maxContainer, unordered = false) {
241
- return junctionContainersFrom(ctx, left, right, maxContainer, junctionSeeds(ctx, left), junctionSeeds(ctx, right), undefined, unordered);
242
- }
243
- /** Tier 2.5: synonym junctions — the container ascent (tier 1) applied to
244
- * halo siblings of left and right. When a distributional synonym of one
245
- * form participates in a learnt whole with the other form, the container
246
- * between the synonym and the other side is valid evidence for the
247
- * original pair. The container evidence is exact (content-addressed DAG
248
- * ascent, with window-id-enhanced seeds so non-W-aligned siblings still
249
- * ascend); the relaxation is only in which form occupies one side — a
250
- * distributional sibling rather than the exact form.
251
- *
252
- * ONE expansion budget is shared by every sibling walk in this call, so
253
- * cost is bounded at √N·W pops total regardless of how many siblings are
254
- * tried. A sibling whose bytes exceed `maxInterior` is skipped (it
255
- * cannot be junction-sized). */
256
- export async function junctionSynonyms(ctx, left, right, maxInterior, unordered = false, sides) {
257
- const s = sides ?? await loadJunctionSynonymSides(ctx, left, right);
258
- if (s.leftId === null && s.rightId === null)
259
- return [];
260
- // ── Tier 2.5a: single-synonym — one side replaced by a halo sibling ──────
261
- // ONE shared expansion budget across BOTH directions of this tier.
262
- const singleBudget = { n: hubBound(ctx) * ctx.space.maxGroup };
263
- const singleOut = new Map();
264
- const keepBest = (map, j, tier, confidence) => {
265
- const prev = map.get(j.id);
266
- if (prev === undefined || confidence > prev.confidence) {
267
- map.set(j.id, { ...j, tier, confidence });
268
- }
269
- };
270
- // Left-side synonyms: containers of sibling+right. `right`'s seeds are
271
- // FIXED across every sibling this loop tries.
272
- if (s.leftId !== null) {
273
- const rightSeeds = junctionSeeds(ctx, right);
274
- for (const sib of s.leftSiblings) {
275
- const sibBytes = read(ctx, sib.id, maxInterior + 1);
276
- if (sibBytes.length === 0 || sibBytes.length > maxInterior)
277
- continue;
278
- const containers = junctionContainersFrom(ctx, sibBytes, right, sibBytes.length + right.length + maxInterior, junctionSeeds(ctx, sibBytes), rightSeeds, singleBudget, unordered);
279
- for (const c of containers) {
280
- keepBest(singleOut, c, "single-synonym", sib.score);
281
- }
282
- }
283
- }
284
- // Right-side synonyms: containers of left+sibling. `left`'s seeds are
285
- // likewise fixed across this loop.
286
- if (s.rightId !== null) {
287
- const leftSeeds = junctionSeeds(ctx, left);
288
- for (const sib of s.rightSiblings) {
289
- const sibBytes = read(ctx, sib.id, maxInterior + 1);
290
- if (sibBytes.length === 0 || sibBytes.length > maxInterior)
291
- continue;
292
- const containers = junctionContainersFrom(ctx, left, sibBytes, left.length + sibBytes.length + maxInterior, leftSeeds, junctionSeeds(ctx, sibBytes), singleBudget, unordered);
293
- for (const c of containers) {
294
- keepBest(singleOut, c, "single-synonym", sib.score);
295
- }
296
- }
297
- }
298
- if (singleOut.size > 0)
299
- return [...singleOut.values()];
300
- // ── Tier 2.5b: double-synonym — BOTH sides replaced, tried only when
301
- // single-synonym found NOTHING. Every (leftSibling, rightSibling) pair,
302
- // sorted deterministically, bounded to haloQueryK pairs total, ONE fresh
303
- // shared budget for the whole tier. ─────────────────────────────────────
304
- if (s.leftSiblings.length === 0 || s.rightSiblings.length === 0)
305
- return [];
306
- const pairs = [];
307
- for (const l of s.leftSiblings) {
308
- for (const r of s.rightSiblings) {
309
- pairs.push({ l, r, confidence: Math.min(l.score, r.score) });
310
- }
311
- }
312
- pairs.sort((a, b) => b.confidence - a.confidence ||
313
- a.l.id - b.l.id ||
314
- a.r.id - b.r.id);
315
- const doubleOut = new Map();
316
- const budget = { n: hubBound(ctx) * ctx.space.maxGroup };
317
- const tries = Math.min(pairs.length, ctx.cfg.haloQueryK);
318
- for (let i = 0; i < tries; i++) {
319
- const { l, r, confidence } = pairs[i];
320
- const lBytes = read(ctx, l.id, maxInterior + 1);
321
- const rBytes = read(ctx, r.id, maxInterior + 1);
322
- if (lBytes.length === 0 || lBytes.length > maxInterior ||
323
- rBytes.length === 0 || rBytes.length > maxInterior)
324
- continue;
325
- const containers = junctionContainersFrom(ctx, lBytes, rBytes, lBytes.length + rBytes.length + maxInterior, junctionSeeds(ctx, lBytes), junctionSeeds(ctx, rBytes), budget, unordered);
326
- for (const c of containers) {
327
- keepBest(doubleOut, c, "double-synonym", confidence);
328
- }
329
- }
330
- return [...doubleOut.values()];
331
- }
@@ -1,75 +0,0 @@
1
- import { Sema } from "../sema.js";
2
- import type { Input, MindContext } from "./types.js";
3
- /** Intern a perceived tree into node ids, bottom-up, sharing equal subtrees.
4
- * Returns the root node id and a map from tree nodes to their ids.
5
- *
6
- * Memoized by NODE IDENTITY (ctx._internIds): the pyramid fold shares a
7
- * prefix's subtree OBJECTS across an accumulated context's deposits, and a
8
- * node already interned needs nothing again — its id is permanent
9
- * (content-addressed) and its intern-time side effects (gist capture, kid
10
- * rows) fired at first mint; re-interning was pure lookups. A memo hit
11
- * therefore skips the WHOLE shared subtree, making the intern walk
12
- * O(new nodes) per deposit instead of O(context). Only the hit node
13
- * itself enters `ids`; descendants stay reachable via the memo (see
14
- * idOf in indexSubSpans and the changedNodes prune). */
15
- export declare function internTreeIds(ctx: MindContext, node: Sema, ids: Map<Sema, number>): Promise<number>;
16
- /** Index flat branches for sub-spans of a deposit's byte stream, linked to
17
- * their structural chunks via durable CONTAINMENT edges. */
18
- export declare function indexSubSpans(ctx: MindContext, tree: Sema, ids: Map<Sema, number>): Promise<boolean>;
19
- /** Perceive, intern, and index a single input. Returns the perceived tree,
20
- * root id, id map, and the changed (new) subtrees for halo reinforcement. */
21
- export declare function deposit(ctx: MindContext, input: Input, track: boolean, conversational?: boolean): Promise<{
22
- tree: Sema;
23
- rootId: number;
24
- ids: Map<Sema, number>;
25
- changed: Sema[];
26
- }>;
27
- /** Ingest a single input (a bare experience, no continuation). */
28
- export declare function ingestOne(ctx: MindContext, input: Input): Promise<Sema & {
29
- id: number;
30
- }>;
31
- /** What one ingested item deposited — reported through {@link ingest}'s
32
- * optional `onDeposit` callback. Pure provenance read-out: node ids are
33
- * content-addressed, so two byte-identical items report the SAME ids (that
34
- * is content addressing working, not an error), and the callback observes
35
- * the deposit without influencing it. */
36
- export interface DepositReport {
37
- /** Zero-based position of the item in the ingested input (0 for a scalar
38
- * or single pair). */
39
- index: number;
40
- /** Whether the item was a bare experience or a (context, continuation)
41
- * pair. */
42
- kind: "one" | "pair";
43
- /** Root node id of the item's (context) bytes. */
44
- contextId: number;
45
- /** Root node id of the continuation bytes — pairs only. */
46
- continuationId?: number;
47
- }
48
- /** Ingest a pair (context, continuation) — learn an edge and pour halos.
49
- * Returns the deposited root ids (context, continuation) — a pure
50
- * read-out; callers that ignore it behave exactly as before. */
51
- export declare function ingestPair(ctx: MindContext, ctxInput: Input, cont: Input): Promise<{
52
- ctxId: number;
53
- contId: number;
54
- }>;
55
- /** Dispatch the public ingest input shapes onto one-input / pair handlers —
56
- * THE one reading of ingest's polymorphic surface (scalar, (context,
57
- * continuation) pair, or a list mixing bare inputs and pairs). Both ingest
58
- * paths — the direct one below and {@link CachedIngest} — route through
59
- * this, so the shape-detection can never drift between them again (the
60
- * ingest cache once re-implemented it and drifted). */
61
- export declare function dispatchIngest(input: Input | (Input | [Input, Input])[], second: Input | undefined, onOne: (input: Input) => Promise<Sema & {
62
- id: number;
63
- }>, onPair: (ctxInput: Input, cont: Input) => Promise<void>): Promise<(Sema & {
64
- id: number;
65
- }) | undefined>;
66
- /** Ingest an input or array of inputs/pairs. The public ingest entry point.
67
- *
68
- * `onDeposit`, when given, is invoked once per ingested item with the
69
- * deposited root node ids ({@link DepositReport}) — item-level provenance
70
- * for tooling that needs to know which stored node an ingested item became.
71
- * Purely observational: the callback runs after the item's deposit
72
- * completed and nothing reads its result. */
73
- export declare function ingest(ctx: MindContext, input: Input | (Input | [Input, Input])[], second?: Input, onDeposit?: (report: DepositReport) => void): Promise<(Sema & {
74
- id: number;
75
- }) | undefined>;