@hviana/sema 0.2.2 → 0.2.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 (60) hide show
  1. package/dist/src/mind/articulation.js +1 -1
  2. package/dist/src/mind/attention.d.ts +18 -2
  3. package/dist/src/mind/attention.js +88 -18
  4. package/dist/src/mind/bridge.d.ts +30 -0
  5. package/dist/src/mind/bridge.js +569 -0
  6. package/dist/src/mind/graph-search.d.ts +16 -1
  7. package/dist/src/mind/graph-search.js +34 -5
  8. package/dist/src/mind/match.d.ts +15 -2
  9. package/dist/src/mind/match.js +3 -8
  10. package/dist/src/mind/mechanisms/alu.js +8 -1
  11. package/dist/src/mind/mechanisms/cast.d.ts +54 -0
  12. package/dist/src/mind/mechanisms/cast.js +303 -48
  13. package/dist/src/mind/mechanisms/cover.js +24 -32
  14. package/dist/src/mind/mechanisms/extraction.js +75 -30
  15. package/dist/src/mind/mechanisms/recall.js +66 -0
  16. package/dist/src/mind/mind.d.ts +1 -0
  17. package/dist/src/mind/mind.js +6 -1
  18. package/dist/src/mind/pipeline.js +34 -2
  19. package/dist/src/mind/reasoning.d.ts +20 -1
  20. package/dist/src/mind/reasoning.js +84 -6
  21. package/dist/src/mind/recognition.js +157 -13
  22. package/dist/src/mind/traverse.js +16 -0
  23. package/dist/src/mind/types.d.ts +65 -2
  24. package/dist/src/mind/types.js +53 -7
  25. package/dist/src/store.d.ts +12 -3
  26. package/dist/src/store.js +9 -3
  27. package/package.json +1 -1
  28. package/src/mind/articulation.ts +1 -0
  29. package/src/mind/attention.ts +105 -17
  30. package/src/mind/bridge.ts +596 -0
  31. package/src/mind/graph-search.ts +59 -2
  32. package/src/mind/match.ts +19 -5
  33. package/src/mind/mechanisms/alu.ts +8 -1
  34. package/src/mind/mechanisms/cast.ts +336 -46
  35. package/src/mind/mechanisms/cover.ts +31 -36
  36. package/src/mind/mechanisms/extraction.ts +101 -40
  37. package/src/mind/mechanisms/recall.ts +79 -0
  38. package/src/mind/mind.ts +7 -1
  39. package/src/mind/pipeline.ts +37 -2
  40. package/src/mind/reasoning.ts +97 -5
  41. package/src/mind/recognition.ts +160 -12
  42. package/src/mind/traverse.ts +17 -0
  43. package/src/mind/types.ts +110 -6
  44. package/src/store.ts +19 -5
  45. package/test/35-attention-confidence.test.mjs +139 -0
  46. package/test/36-already-answered-fusion.test.mjs +128 -0
  47. package/test/37-cluster-dispersion-fusion.test.mjs +190 -0
  48. package/test/38-reason-restate-guard.test.mjs +94 -0
  49. package/test/39-cast-restate-guard.test.mjs +102 -0
  50. package/test/40-choosenext-scale-guard.test.mjs +75 -0
  51. package/test/41-seatofnode-direction.test.mjs +85 -0
  52. package/test/42-recognise-trace-idempotence.test.mjs +106 -0
  53. package/test/43-cast-analog-seat.test.mjs +244 -0
  54. package/test/44-recognise-edge-whitespace.test.mjs +63 -0
  55. package/test/45-liftanswer-restated-trim.test.mjs +60 -0
  56. package/test/46-recognise-multibyte-edge.test.mjs +85 -0
  57. package/test/47-cast-comparison-coverage.test.mjs +134 -0
  58. package/test/48-recognise-turn-connective.test.mjs +125 -0
  59. package/test/49-natural-units-synonym-bridge.test.mjs +175 -0
  60. package/test/50-cast-analog-consensus-floor.test.mjs +179 -0
@@ -96,6 +96,18 @@ export type GItem =
96
96
  cover: boolean;
97
97
  rec: boolean;
98
98
  node?: number;
99
+ /** Set only for a {@link ComputedResult} axiom (an extension's derived
100
+ * value, e.g. ALU arithmetic) — as opposed to a genuinely RECOGNISED
101
+ * learned form. Both set `rec: true` (a computation bridges the cover
102
+ * exactly like a learned terminal answer), but they mean different
103
+ * things for `i..j`'s WIDTH: a recognised form's query-span width is
104
+ * real evidence of how much of the query's meaning it accounts for
105
+ * (liftAnswer's half-dominance framing decision); a computed span's
106
+ * width is operand digit-count, uncorrelated with meaning ("1000 - 421"
107
+ * is wider than "15 * 7" only because the numbers are bigger, not
108
+ * because subtraction is more "the point" of its query). See
109
+ * {@link liftAnswer}. */
110
+ computed?: boolean;
99
111
  };
100
112
  type OutItem = Extract<GItem, { kind: "out" }>;
101
113
 
@@ -138,6 +150,9 @@ export interface Seg {
138
150
  bytes: Uint8Array;
139
151
  rec: boolean;
140
152
  node?: number;
153
+ /** See the `computed` field of the "out" {@link GItem} — set only for an
154
+ * extension's derived value, never a genuinely recognised learned form. */
155
+ computed?: boolean;
141
156
  }
142
157
 
143
158
  /** Read the chosen spans back off a derivation: the goal is a chain of bridge
@@ -155,6 +170,7 @@ function readCover(derivation: Derivation<GItem>): Seg[] {
155
170
  bytes: out.bytes,
156
171
  rec: out.rec,
157
172
  node: out.node,
173
+ computed: out.computed,
158
174
  });
159
175
  }
160
176
  node = node.premises[0];
@@ -356,6 +372,7 @@ export class GraphSearch {
356
372
  conceptTarget: ReadonlyMap<number, number>,
357
373
  leaves: ReadonlyArray<Leaf>,
358
374
  splits: ReadonlySet<number>,
375
+ starts: ReadonlySet<number>,
359
376
  substitutions?: ReadonlyMap<number, Uint8Array>,
360
377
  connectors?: ReadonlyMap<string, Uint8Array>,
361
378
  computedResults?: ReadonlyArray<ComputedResult>,
@@ -377,6 +394,7 @@ export class GraphSearch {
377
394
  sites,
378
395
  leaves,
379
396
  splits,
397
+ starts,
380
398
  },
381
399
  conceptTarget,
382
400
  substitutions,
@@ -405,6 +423,7 @@ export class GraphSearch {
405
423
  sites: ReadonlyArray<Site>;
406
424
  leaves: ReadonlyArray<Leaf>;
407
425
  splits: ReadonlySet<number>;
426
+ starts: ReadonlySet<number>;
408
427
  },
409
428
  conceptTarget: ReadonlyMap<number, number>,
410
429
  substitutions?: ReadonlyMap<number, Uint8Array>,
@@ -418,6 +437,7 @@ export class GraphSearch {
418
437
  conceptTarget,
419
438
  recognition.leaves,
420
439
  recognition.splits,
440
+ recognition.starts,
421
441
  substitutions,
422
442
  connectors,
423
443
  computedResults,
@@ -448,11 +468,22 @@ export class GraphSearch {
448
468
  conceptTarget: ReadonlyMap<number, number>,
449
469
  leaves: ReadonlyArray<Leaf>,
450
470
  splits: ReadonlySet<number>,
471
+ starts: ReadonlySet<number>,
451
472
  substitutions?: ReadonlyMap<number, Uint8Array>,
452
473
  connectors?: ReadonlyMap<string, Uint8Array>,
453
474
  computedResults?: ReadonlyArray<ComputedResult>,
454
475
  ): DeductionSystem<GItem> {
455
476
  const W = this.maxGroup; // fusible span ceiling (shortest composite bound)
477
+ // Same corpus-scale hub floor {@link atomIsHub}/{@link atomReach} (traverse.ts)
478
+ // derive for byte atoms — duplicated here rather than imported because this
479
+ // module is deliberately host-based (no MindContext), and both inputs
480
+ // (maxGroup, edgeSourceCount) are already in scope with no ctx needed. If
481
+ // the formula ever changes, it must change in BOTH places (see canonical.ts's
482
+ // header for the same write/read-side duplication convention).
483
+ const atomsAreHubs = Math.max(
484
+ 1,
485
+ Math.ceil((this.store.edgeSourceCount() * W) / 256),
486
+ ) > Math.ceil(Math.sqrt(Math.max(2, this.store.edgeSourceCount())));
456
487
  const nodeBytes = (n: number) => this.store.bytesPrefix(n, ALL);
457
488
  // Content-addressed probes over the store's hash-cons maps — the same keys
458
489
  // training filled. No byte-by-byte trie walk.
@@ -550,6 +581,7 @@ export class GraphSearch {
550
581
  cover: true,
551
582
  rec: true,
552
583
  node: u.node,
584
+ computed: true,
553
585
  },
554
586
  cost: STEP,
555
587
  };
@@ -588,6 +620,8 @@ export class GraphSearch {
588
620
  return this.outRules(it, {
589
621
  W,
590
622
  splits,
623
+ starts,
624
+ atomsAreHubs,
591
625
  coversDone,
592
626
  outsByStart,
593
627
  outsByEnd,
@@ -949,6 +983,8 @@ export class GraphSearch {
949
983
  ctx: {
950
984
  W: number;
951
985
  splits: ReadonlySet<number>;
986
+ starts: ReadonlySet<number>;
987
+ atomsAreHubs: boolean;
952
988
  coversDone: Set<number>;
953
989
  outsByStart: Map<number, OutItem[]>;
954
990
  outsByEnd: Map<number, OutItem[]>;
@@ -1095,12 +1131,30 @@ export class GraphSearch {
1095
1131
  r: OutItem,
1096
1132
  ctx: {
1097
1133
  W: number;
1134
+ starts: ReadonlySet<number>;
1135
+ atomsAreHubs: boolean;
1098
1136
  findLeafU: (b: Uint8Array) => number | undefined;
1099
1137
  findBranchU: (k: number[]) => number | undefined;
1100
1138
  },
1101
1139
  ): Iterable<Rule<GItem>> {
1102
1140
  const bytes = concat2(l.bytes, r.bytes);
1103
- let node = bytes.length <= ctx.W ? ctx.findLeafU(bytes) : undefined;
1141
+ // A PURE leaf-leaf fuse (neither side already a recognised completion)
1142
+ // is opportunistic cross-leaf recovery exactly like recognition.ts's own
1143
+ // canonical chain — findLeaf/findBranch here have no idea WHY these two
1144
+ // leaves are adjacent, only that their concatenation happens to spell a
1145
+ // trained form ("hi" recovered from "W[hi]ch"). The same corpus-scale
1146
+ // caution recognition.ts's `boundary` gate applies: trust it fully when
1147
+ // `l.i` is a position the query's OWN fold chose as a boundary (real
1148
+ // structural evidence); past the scale where atoms themselves stop
1149
+ // discriminating, an interior offset's opportunistic match is noise, not
1150
+ // a genuine cross-leaf recovery. A completion-involved fuse (l.rec ||
1151
+ // r.rec) is a different, legitimate case — a rewrite growing into its
1152
+ // neighbour — and is exempt, same as recognition.ts's rec-derived sites.
1153
+ const trusted = l.rec || r.rec || ctx.starts.has(l.i) ||
1154
+ !ctx.atomsAreHubs;
1155
+ let node = (trusted && bytes.length <= ctx.W)
1156
+ ? ctx.findLeafU(bytes)
1157
+ : undefined;
1104
1158
  // Whether this pair ACTUALLY forms a 2-child branch — the hard evidence
1105
1159
  // that the fused bytes are a learned form worth keeping alive. Derived
1106
1160
  // from the same findBranchU probe that sets `node`; when false, the pair
@@ -1108,7 +1162,10 @@ export class GraphSearch {
1108
1162
  // node cannot contribute to any further fusion (findBranch needs two
1109
1163
  // nodes, resolve needs a completion, and findLeaf already had its chance).
1110
1164
  let pairFormsBranch = false;
1111
- if (node === undefined && l.node !== undefined && r.node !== undefined) {
1165
+ if (
1166
+ trusted && node === undefined && l.node !== undefined &&
1167
+ r.node !== undefined
1168
+ ) {
1112
1169
  node = ctx.findBranchU([l.node, r.node]);
1113
1170
  pairFormsBranch = node !== undefined;
1114
1171
  }
package/src/mind/match.ts CHANGED
@@ -325,18 +325,32 @@ export async function haloSiblings(
325
325
  * strength, not a pick. Returns the direct halo cosine, or failing that the
326
326
  * highest mutual-halo-sibling min-score (second-order analogy), or failing
327
327
  * that the SHARED-FRAME strength (below) — the gate CAST's comparison
328
- * schema validates genuine analogs with (bar: significanceBar). */
328
+ * schema validates genuine analogs with (bar: significanceBar).
329
+ *
330
+ * The result names its TIER alongside the score: `halo: true` means the
331
+ * score cleared a significanceBar-gated HALO tier (direct company cosine
332
+ * or mutual-sibling) — genuine distributional evidence; `halo: false`
333
+ * means only the structural shared-frame fallback matched, a coverage
334
+ * fraction with no bar of its own. CAST's comparison gate treats the two
335
+ * differently (see cast.ts): halo evidence stands alone, frame evidence
336
+ * needs the query to have named the analog or the climb root to be
337
+ * trusted. */
338
+ export interface AnalogyEvidence {
339
+ score: number;
340
+ halo: boolean;
341
+ }
342
+
329
343
  export async function analogyStrength(
330
344
  ctx: MindContext,
331
345
  a: number,
332
346
  b: number,
333
- ): Promise<number> {
347
+ ): Promise<AnalogyEvidence> {
334
348
  const ha = ctx.store.halo(a);
335
349
  const hb = ctx.store.halo(b);
336
350
  if (ha && hb) {
337
351
  const bar = significanceBar(ctx.store.D);
338
352
  const direct = cosine(ha, hb);
339
- if (direct >= bar) return direct;
353
+ if (direct >= bar) return { score: direct, halo: true };
340
354
  const sibsA = await haloSiblings(ctx, a, ha, bar);
341
355
  const sibsB = await haloSiblings(ctx, b, hb, bar);
342
356
  let best = 0;
@@ -347,9 +361,9 @@ export async function analogyStrength(
347
361
  best = Math.max(best, Math.min(x.score, y.score));
348
362
  }
349
363
  }
350
- if (best > 0) return best;
364
+ if (best > 0) return { score: best, halo: true };
351
365
  }
352
- return sharedFrameStrength(ctx, a, b);
366
+ return { score: sharedFrameStrength(ctx, a, b), halo: false };
353
367
  }
354
368
 
355
369
  /** The STRUCTURAL analogy tier: two nodes are analogs when their byte
@@ -16,7 +16,14 @@ import type { PipelineMechanism } from "../pipeline-mechanism.js";
16
16
  export function aluToMechanism(alu: Alu): PipelineMechanism {
17
17
  return {
18
18
  name: "alu",
19
- provenance: "cover",
19
+ // Not a cover derivation: cover.ts composes an answer by walking
20
+ // recognised query STRUCTURE; the ALU evaluates a recognised expression
21
+ // to its authoritative result and hands the bytes back untouched. It
22
+ // shares cover's near-zero floor (computation always wins, masked into
23
+ // cover's own search — see mechanisms/cover.ts), but the candidate this
24
+ // produces is not one of cover's derivations, so it carries its own
25
+ // honest label, the same way extract/cast/recall each carry theirs.
26
+ provenance: "alu",
20
27
  parse: (query) => alu.parse(query),
21
28
  async floor(_ctx, _query, pre, _worthRunning) {
22
29
  return pre.computed.length > 0 ? 0 : null;