@hviana/sema 0.8.9 → 0.9.1

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 (111) hide show
  1. package/AGENTS.md +7 -7
  2. package/dist/src/alu/src/index.d.ts +1 -1
  3. package/dist/src/alu/src/index.js +1 -1
  4. package/dist/src/alu/src/parser.js +2 -6
  5. package/dist/src/alu/src/resonance.d.ts +13 -0
  6. package/dist/src/alu/src/resonance.js +41 -0
  7. package/dist/src/alu/test/alu.test.js +39 -0
  8. package/dist/src/bytes.d.ts +6 -2
  9. package/dist/src/bytes.js +10 -4
  10. package/dist/src/canon.js +44 -0
  11. package/dist/src/geometry.d.ts +19 -1
  12. package/dist/src/geometry.js +125 -141
  13. package/dist/src/meter.d.ts +27 -0
  14. package/dist/src/meter.js +28 -1
  15. package/dist/src/mind/articulation.js +14 -1
  16. package/dist/src/mind/attention.d.ts +12 -0
  17. package/dist/src/mind/attention.js +44 -16
  18. package/dist/src/mind/bridge.js +3 -3
  19. package/dist/src/mind/derivation.d.ts +40 -0
  20. package/dist/src/mind/derivation.js +34 -0
  21. package/dist/src/mind/graph-search.d.ts +89 -15
  22. package/dist/src/mind/graph-search.js +345 -174
  23. package/dist/src/mind/learning.js +1 -1
  24. package/dist/src/mind/mechanisms/cover.d.ts +19 -3
  25. package/dist/src/mind/mechanisms/cover.js +101 -58
  26. package/dist/src/mind/mechanisms/recall.js +0 -1
  27. package/dist/src/mind/mind.js +2 -2
  28. package/dist/src/mind/pipeline.d.ts +5 -1
  29. package/dist/src/mind/pipeline.js +175 -87
  30. package/dist/src/mind/primitives.d.ts +25 -5
  31. package/dist/src/mind/primitives.js +107 -44
  32. package/dist/src/mind/reasoning.d.ts +18 -4
  33. package/dist/src/mind/reasoning.js +445 -321
  34. package/dist/src/mind/recognition.js +55 -73
  35. package/dist/src/mind/resonance.js +1 -11
  36. package/dist/src/mind/traverse.d.ts +3 -3
  37. package/dist/src/mind/traverse.js +3 -3
  38. package/dist/src/mind/types.d.ts +7 -1
  39. package/dist/src/store-sqlite.d.ts +25 -0
  40. package/dist/src/store-sqlite.js +89 -1
  41. package/dist/src/store.d.ts +48 -4
  42. package/dist/src/store.js +86 -6
  43. package/docs/INDEX.md +18 -18
  44. package/docs/INVARIANTS.md +16 -16
  45. package/docs/architecture/bounded-reads.md +1 -1
  46. package/docs/architecture/caches.md +5 -4
  47. package/docs/architecture/closure.md +45 -5
  48. package/docs/architecture/cost-model.md +16 -0
  49. package/docs/architecture/factored-machinery.md +14 -13
  50. package/docs/architecture/fold-contract.md +51 -1
  51. package/docs/architecture/mechanism-market.md +21 -0
  52. package/docs/architecture/memoization.md +3 -3
  53. package/docs/architecture/meter.md +2 -1
  54. package/docs/architecture/saturation.md +12 -0
  55. package/docs/architecture/store.md +25 -2
  56. package/docs/failures/tempting-but-wrong.md +13 -2
  57. package/docs/harness/gates.md +12 -10
  58. package/docs/mechanisms/cover.md +23 -6
  59. package/jsr.json +1 -1
  60. package/package.json +1 -1
  61. package/src/alu/README.md +10 -2
  62. package/src/alu/src/index.ts +1 -0
  63. package/src/alu/src/parser.ts +6 -6
  64. package/src/alu/src/resonance.ts +42 -0
  65. package/src/alu/test/alu.test.ts +40 -0
  66. package/src/bytes.ts +13 -3
  67. package/src/canon.ts +40 -0
  68. package/src/geometry.ts +183 -154
  69. package/src/meter.ts +28 -1
  70. package/src/mind/articulation.ts +14 -2
  71. package/src/mind/attention.ts +47 -25
  72. package/src/mind/bridge.ts +3 -3
  73. package/src/mind/derivation.ts +77 -0
  74. package/src/mind/graph-search.ts +449 -221
  75. package/src/mind/learning.ts +1 -7
  76. package/src/mind/match.ts +1 -2
  77. package/src/mind/mechanisms/cast.ts +1 -2
  78. package/src/mind/mechanisms/cover.ts +149 -84
  79. package/src/mind/mechanisms/extraction.ts +1 -2
  80. package/src/mind/mechanisms/prefix-completion.ts +1 -1
  81. package/src/mind/mechanisms/recall.ts +1 -3
  82. package/src/mind/mechanisms/reference.ts +1 -1
  83. package/src/mind/mind.ts +5 -30
  84. package/src/mind/pipeline.ts +206 -102
  85. package/src/mind/primitives.ts +119 -43
  86. package/src/mind/reasoning.ts +558 -413
  87. package/src/mind/recognition.ts +49 -65
  88. package/src/mind/resonance.ts +2 -16
  89. package/src/mind/trace.ts +1 -1
  90. package/src/mind/traverse.ts +3 -3
  91. package/src/mind/types.ts +9 -11
  92. package/src/store-sqlite.ts +92 -1
  93. package/src/store.ts +113 -7
  94. package/test/105-derive-through-reports-its-refusal.test.mjs +8 -5
  95. package/test/106-the-join-fires.test.mjs +21 -0
  96. package/test/111-the-cover-assembly-is-counted.test.mjs +8 -5
  97. package/test/128-the-leads-somewhere-pair-agrees.test.mjs +18 -12
  98. package/test/136-the-two-named-limits.test.mjs +3 -2
  99. package/test/137-the-law-lives-once-and-below.test.mjs +21 -0
  100. package/test/148-exact-shortcuts-agree.test.mjs +188 -0
  101. package/test/149-the-closure-engine.test.mjs +138 -0
  102. package/test/150-the-join-is-output-sensitive.test.mjs +66 -0
  103. package/test/151-the-cover-pays-for-what-it-reaches.test.mjs +142 -0
  104. package/test/152-the-read-side-names-as-the-write-side.test.mjs +146 -0
  105. package/test/153-a-cheaper-bound-is-looked-at-first.test.mjs +155 -0
  106. package/test/24-generalization.test.mjs +32 -0
  107. package/test/36-bloom.test.mjs +53 -0
  108. package/test/37-cluster-dispersion-fusion.test.mjs +75 -0
  109. package/test/48-recognise-turn-connective.test.mjs +3 -2
  110. package/test/55-cost-meter.test.mjs +4 -4
  111. package/test/90-connector-read-cap.test.mjs +7 -7
@@ -34,14 +34,7 @@ import {
34
34
  estimatorNoise,
35
35
  type StructuralPart,
36
36
  } from "../geometry.js";
37
- import {
38
- foldTree,
39
- gistOf,
40
- latin1Key,
41
- perceive,
42
- read,
43
- resolve,
44
- } from "./primitives.js";
37
+ import { foldTree, gistOf, perceive, read, resolve } from "./primitives.js";
45
38
  import { recognise } from "./recognition.js";
46
39
  import { leafIdRun } from "./canonical.js";
47
40
  import {
@@ -63,10 +56,10 @@ import {
63
56
  walkCache,
64
57
  } from "./junction.js";
65
58
  import type { Vec } from "../vec.js";
66
- import { indexOf } from "../bytes.js";
59
+ import { indexOf, latin1 } from "../bytes.js";
67
60
  import { restates } from "./derivation.js";
68
61
  import type { RationaleItem } from "./rationale.js";
69
- import { rDeriv, rItem, rNode, traceDerivation } from "./trace.js";
62
+ import { rItem, rNode, traceDerivation } from "./trace.js";
70
63
 
71
64
  // ═══════════════════════════════════════════════════════════════════════════
72
65
  // climbConsensus / inspectRationale instrumentation.
@@ -501,7 +494,7 @@ export async function climbAttentionAll(
501
494
  // Content-keyed memo — works for both single-turn respond() and multi-turn
502
495
  // respondTurn().
503
496
  if (ctx.climbMemo) {
504
- const contentKey = latin1Key(query);
497
+ const contentKey = latin1(query);
505
498
  const modeKey = `${k}:${mode}`;
506
499
  let byRead = ctx.climbMemo.get(contentKey);
507
500
  if (byRead === undefined) {
@@ -1629,7 +1622,10 @@ export function poolVotes(
1629
1622
  * Strict `<` (not `<=`): verified against gap 3.1's own "gender equality"
1630
1623
  * root, whose two genuine clusters sit EXACTLY W bytes apart — `<= W`
1631
1624
  * would wrongly merge them into one and break that pinned requirement. */
1632
- function countClusters(spans: readonly [number, number][], W: number): number {
1625
+ export function countClusters(
1626
+ spans: readonly [number, number][],
1627
+ W: number,
1628
+ ): number {
1633
1629
  if (spans.length === 0) return 0;
1634
1630
  const sorted = [...spans].sort((a, b) => a[0] - b[0]);
1635
1631
  let clusters = 1;
@@ -2103,20 +2099,46 @@ export function canonicalChunkId(
2103
2099
  if (len < 2) return flatId;
2104
2100
 
2105
2101
  // Within one window, the widest reach is still the right CANONICAL
2106
- // identity — a chunk's anchor should be its most general stable form.
2107
- let bestId = flatId;
2108
- let bestReach = edgeAncestors(ctx, flatId, N, reachMemo);
2102
+ // identity — a chunk's anchor should be its most general stable form. A
2103
+ // SATURATED reach is the widest there is: its count is wherever the climb
2104
+ // happened to stop deciding, so an unsaturated prefix never out-widens it
2105
+ // by comparing against that count. (It used to: on test/24's gap-3.1
2106
+ // fixture the region `ace and ` had its saturated window replaced by the
2107
+ // unsaturated 2-byte prefix `e `, and that sub-window anchor voted.)
2108
+ //
2109
+ // So a window's anchor is its SHORTEST saturated form when any saturates,
2110
+ // and its widest-reaching form otherwise — and the forms are climbed
2111
+ // shortest first, stopping at the first that saturates: the forms longer
2112
+ // than it cannot change the anchor. Measured over 8 queries on the
2113
+ // 31.7M-node store: 339 of 347 windows saturate, 312 already at their
2114
+ // 2-byte prefix, while the full window and the 3-byte prefix — climbed
2115
+ // first, to √N contexts each — were 89% of the visits.
2116
+ const forms: number[] = [flatId];
2109
2117
  for (let k2 = 1; k2 < len; k2++) {
2110
- const shortIds = ids.slice(0, len - k2);
2111
- const shortId = ctx.store.findBranch(shortIds);
2112
- if (shortId === null) continue;
2113
- const shortReach = edgeAncestors(ctx, shortId, N, reachMemo);
2114
- if (
2115
- shortReach.saturated ||
2116
- shortReach.contextsReached > bestReach.contextsReached
2117
- ) {
2118
- bestId = shortId;
2119
- bestReach = shortReach;
2118
+ const shortId = ctx.store.findBranch(ids.slice(0, len - k2));
2119
+ if (shortId !== null) forms.push(shortId);
2120
+ }
2121
+ const reaches: AncestorReach[] = new Array(forms.length);
2122
+ let bestId: number | null = null;
2123
+ let bestReach: AncestorReach | null = null;
2124
+ for (let f = forms.length - 1; f >= 0; f--) {
2125
+ const r = edgeAncestors(ctx, forms[f], N, reachMemo);
2126
+ if (r.saturated) {
2127
+ bestId = forms[f];
2128
+ bestReach = r;
2129
+ break;
2130
+ }
2131
+ reaches[f] = r;
2132
+ }
2133
+ if (bestId === null || bestReach === null) {
2134
+ // None saturates: the widest reach, the longer form on a tie.
2135
+ bestId = forms[0];
2136
+ bestReach = reaches[0];
2137
+ for (let f = 1; f < forms.length; f++) {
2138
+ if (reaches[f].contextsReached > bestReach.contextsReached) {
2139
+ bestId = forms[f];
2140
+ bestReach = reaches[f];
2141
+ }
2120
2142
  }
2121
2143
  }
2122
2144
  if (fallback === null) fallback = bestId;
@@ -94,7 +94,7 @@ import { cosine, type Vec } from "../vec.js";
94
94
  import { conceptThreshold, dominates, significanceBar } from "../geometry.js";
95
95
  import { bytesEqual, indexOf } from "../bytes.js";
96
96
  import type { MindContext } from "./types.js";
97
- import { foldTree, perceive, read } from "./primitives.js";
97
+ import { exactNode, perceive, read } from "./primitives.js";
98
98
  import { chainReach, leafIdRun } from "./canonical.js";
99
99
  import {
100
100
  allWindowsAreScaffolding,
@@ -491,7 +491,7 @@ async function bridgeImpl(
491
491
  ) continue;
492
492
  let use = sid;
493
493
  if (!ctx.store.hasNext(use)) {
494
- const folded = foldTree(ctx, perceive(ctx, tb), 0).node;
494
+ const folded = exactNode(ctx, tb);
495
495
  if (folded === null || folded === sid || !ctx.store.hasNext(folded)) {
496
496
  continue;
497
497
  }
@@ -508,7 +508,7 @@ async function bridgeImpl(
508
508
  // be a FLAT content twin whose continuation edge lives on the
509
509
  // fold-shaped deposit node with the same bytes — the same twin split
510
510
  // canonResolve bridges by re-folding (primitives.ts) — but the re-fold
511
- // (a full perceive of the candidate's bytes) is paid only for proposals
511
+ // (an identity fold of the candidate's bytes) is paid only for proposals
512
512
  // that could align at all: alignment can only seed at a picked anchor
513
513
  // window occurring literally in the candidate (measured: unconditional
514
514
  // re-folds multiplied the refusal-path latency several-fold).
@@ -489,3 +489,80 @@ export async function closure(
489
489
  d = next;
490
490
  }
491
491
  }
492
+
493
+ // ── The engine: one closure over layers ─────────────────────────────────────
494
+
495
+ /** A LAYER of the closure — a named producer of continuations for one state.
496
+ * The layer OFFERS (its {@link Offer} is the whole of what it decides); the
497
+ * law admits; the engine sequences. The hooks are the layer's own
498
+ * instrumentation, called by the engine at the moments the law defines. */
499
+ export interface ClosureLayer {
500
+ /** The layer's name — its rationale scope and its meter phase. */
501
+ readonly name: string;
502
+ /** Whether the layer has anything to offer this state at all. A layer that
503
+ * does not engage is not ENTERED: no offer is asked and no work is charged
504
+ * to it. Omitted: it always engages. */
505
+ readonly engages?: (d: DerivationState) => boolean;
506
+ /** The layer's continuations, one at a time ({@link Offer}'s contract). */
507
+ readonly offer: Offer;
508
+ /** Called for each step the law admits, with the state before and after. */
509
+ readonly onTaken?: (
510
+ before: DerivationState,
511
+ after: DerivationState,
512
+ witnesses: ReadonlyArray<Witness>,
513
+ ) => void;
514
+ /** Called when the law refused the continuation the layer offered. */
515
+ readonly onRefused?: (at: DerivationState) => void;
516
+ /** Called once the layer's walk has ended — the layer offered nothing more,
517
+ * or the law refused — with the state it began from and the one it reached. */
518
+ readonly onEnd?: (from: DerivationState, to: DerivationState) => void;
519
+ }
520
+
521
+ /** THE CLOSURE ENGINE — close a derivation under the law, layer by layer.
522
+ *
523
+ * Each layer is walked to its own end ({@link closure}: the layer offers, the
524
+ * law admits or refuses), and the state it reaches is the state the next layer
525
+ * is offered against. Layers are PHASES, in the order given, never revisited:
526
+ * a later layer composes what an earlier one produced, and nothing it adds is
527
+ * re-offered to the earlier one.
528
+ *
529
+ * THE LAW'S FIRST CLAUSE IS APPLIED HERE, ONCE. A FIXED state admits no
530
+ * transition (`admissible` refuses it before anything else), so no layer is
531
+ * entered at all — the decision a caller used to spell as "skip the walk for a
532
+ * complete grounding, and skip the fusion too" is the law's, not the caller's,
533
+ * and it is taken before any layer pays for an offer it could never have
534
+ * taken.
535
+ *
536
+ * `enter` wraps each entered layer's walk — the caller's instrumentation (a
537
+ * meter phase), which this module cannot import: it reads nothing but the
538
+ * state and the layers. */
539
+ export async function closeOver(
540
+ d: DerivationState,
541
+ query: Uint8Array,
542
+ W: number,
543
+ layers: ReadonlyArray<ClosureLayer>,
544
+ enter?: (
545
+ name: string,
546
+ walk: () => Promise<DerivationState>,
547
+ ) => Promise<DerivationState>,
548
+ ): Promise<DerivationState> {
549
+ for (const layer of layers) {
550
+ if (d.fixed) return d;
551
+ if (layer.engages !== undefined && !layer.engages(d)) continue;
552
+ const from = d;
553
+ const walk = async (): Promise<DerivationState> => {
554
+ const to = await closure(
555
+ from,
556
+ query,
557
+ W,
558
+ layer.offer,
559
+ layer.onTaken,
560
+ layer.onRefused,
561
+ );
562
+ layer.onEnd?.(from, to);
563
+ return to;
564
+ };
565
+ d = enter === undefined ? await walk() : await enter(layer.name, walk);
566
+ }
567
+ return d;
568
+ }