@hviana/sema 0.8.2 → 0.8.5

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 (126) hide show
  1. package/AGENTS.md +38 -37
  2. package/README.md +17 -38
  3. package/TRADEMARKS.md +0 -1
  4. package/dist/example/demo.js +85 -34
  5. package/dist/src/config.d.ts +11 -0
  6. package/dist/src/config.js +2 -0
  7. package/dist/src/geometry.d.ts +21 -10
  8. package/dist/src/geometry.js +21 -12
  9. package/dist/src/meter.d.ts +62 -0
  10. package/dist/src/meter.js +62 -0
  11. package/dist/src/mind/articulation.js +1 -1
  12. package/dist/src/mind/attention.d.ts +4 -0
  13. package/dist/src/mind/attention.js +167 -17
  14. package/dist/src/mind/canonical.d.ts +16 -0
  15. package/dist/src/mind/canonical.js +41 -0
  16. package/dist/src/mind/derivation.d.ts +201 -0
  17. package/dist/src/mind/derivation.js +327 -0
  18. package/dist/src/mind/graph-search.d.ts +2 -1
  19. package/dist/src/mind/graph-search.js +70 -29
  20. package/dist/src/mind/match.d.ts +3 -1
  21. package/dist/src/mind/match.js +7 -3
  22. package/dist/src/mind/mechanisms/alu.js +0 -2
  23. package/dist/src/mind/mechanisms/cast.d.ts +1 -5
  24. package/dist/src/mind/mechanisms/cast.js +16 -19
  25. package/dist/src/mind/mechanisms/confluence.d.ts +0 -3
  26. package/dist/src/mind/mechanisms/confluence.js +27 -9
  27. package/dist/src/mind/mechanisms/cover.js +17 -20
  28. package/dist/src/mind/mechanisms/extraction.d.ts +0 -1
  29. package/dist/src/mind/mechanisms/extraction.js +13 -8
  30. package/dist/src/mind/mechanisms/prefix-completion.js +0 -1
  31. package/dist/src/mind/mechanisms/recall.d.ts +0 -1
  32. package/dist/src/mind/mechanisms/recall.js +40 -13
  33. package/dist/src/mind/mechanisms/reference.js +3 -4
  34. package/dist/src/mind/mind.d.ts +4 -2
  35. package/dist/src/mind/mind.js +5 -4
  36. package/dist/src/mind/pipeline-mechanism.d.ts +7 -3
  37. package/dist/src/mind/pipeline.js +136 -44
  38. package/dist/src/mind/primitives.js +9 -1
  39. package/dist/src/mind/rationale.d.ts +21 -5
  40. package/dist/src/mind/rationale.js +16 -21
  41. package/dist/src/mind/reasoning.d.ts +12 -20
  42. package/dist/src/mind/reasoning.js +190 -106
  43. package/dist/src/mind/recognition.js +4 -8
  44. package/dist/src/mind/resonance.js +20 -1
  45. package/dist/src/mind/trace.js +1 -0
  46. package/dist/src/mind/traverse.js +6 -2
  47. package/dist/src/mind/types.d.ts +36 -13
  48. package/dist/src/mind/types.js +6 -3
  49. package/docs/INDEX.md +23 -24
  50. package/docs/INVARIANTS.md +16 -17
  51. package/docs/architecture/bounded-reads.md +5 -5
  52. package/docs/architecture/closure.md +65 -0
  53. package/docs/architecture/commonality.md +29 -20
  54. package/docs/architecture/cost-model.md +7 -7
  55. package/docs/architecture/determinism.md +7 -7
  56. package/docs/architecture/exact-vs-approximate.md +4 -4
  57. package/docs/architecture/factored-machinery.md +14 -14
  58. package/docs/architecture/match-project.md +2 -3
  59. package/docs/architecture/mechanism-market.md +16 -16
  60. package/docs/architecture/meter.md +10 -11
  61. package/docs/architecture/store.md +4 -4
  62. package/docs/architecture/thresholds.md +1 -1
  63. package/docs/failures/tempting-but-wrong.md +14 -5
  64. package/docs/harness/gates.md +7 -7
  65. package/docs/mechanisms/cast.md +2 -2
  66. package/docs/mechanisms/cover.md +4 -5
  67. package/docs/mechanisms/extraction.md +7 -7
  68. package/docs/mechanisms/recall.md +8 -9
  69. package/example/demo.ts +90 -37
  70. package/jsr.json +1 -1
  71. package/package.json +1 -1
  72. package/src/alu/README.md +11 -12
  73. package/src/config.ts +13 -0
  74. package/src/geometry.ts +21 -13
  75. package/src/meter.ts +62 -0
  76. package/src/mind/articulation.ts +0 -1
  77. package/src/mind/attention.ts +169 -17
  78. package/src/mind/canonical.ts +43 -0
  79. package/src/mind/derivation.ts +473 -0
  80. package/src/mind/graph-search.ts +76 -34
  81. package/src/mind/match.ts +7 -3
  82. package/src/mind/mechanisms/alu.ts +0 -2
  83. package/src/mind/mechanisms/cast.ts +20 -22
  84. package/src/mind/mechanisms/confluence.ts +27 -13
  85. package/src/mind/mechanisms/cover.ts +17 -20
  86. package/src/mind/mechanisms/extraction.ts +13 -9
  87. package/src/mind/mechanisms/prefix-completion.ts +0 -1
  88. package/src/mind/mechanisms/recall.ts +39 -13
  89. package/src/mind/mechanisms/reference.ts +2 -3
  90. package/src/mind/mind.ts +6 -4
  91. package/src/mind/pipeline-mechanism.ts +7 -3
  92. package/src/mind/pipeline.ts +160 -52
  93. package/src/mind/primitives.ts +9 -1
  94. package/src/mind/rationale.ts +27 -23
  95. package/src/mind/reasoning.ts +227 -120
  96. package/src/mind/recognition.ts +4 -8
  97. package/src/mind/resonance.ts +19 -1
  98. package/src/mind/trace.ts +1 -0
  99. package/src/mind/traverse.ts +7 -5
  100. package/src/mind/types.ts +41 -15
  101. package/test/105-derive-through-reports-its-refusal.test.mjs +24 -0
  102. package/test/118-the-join-reaches-a-key-off-the-cut.test.mjs +74 -0
  103. package/test/119-the-work-does-not-grow-with-the-corpus.test.mjs +122 -0
  104. package/test/120-composition-is-consequence.test.mjs +132 -0
  105. package/test/121-the-extension-does-not-grow-with-the-corpus.test.mjs +128 -0
  106. package/test/122-the-climb-search-does-not-grow-with-the-corpus.test.mjs +117 -0
  107. package/test/123-the-paired-formulas-agree.test.mjs +90 -0
  108. package/test/125-the-post-grounding-branch-publishes-its-operand.test.mjs +51 -0
  109. package/test/126-the-pipeline-does-not-name-mechanisms.test.mjs +42 -0
  110. package/test/128-the-leads-somewhere-pair-agrees.test.mjs +83 -0
  111. package/test/129-the-trace-payload-shape.test.mjs +164 -0
  112. package/test/133-the-decision-point-renders-the-state.test.mjs +204 -0
  113. package/test/134-the-law-explains-the-engines-own-refusal.test.mjs +237 -0
  114. package/test/135-one-law-any-producer.test.mjs +289 -0
  115. package/test/136-the-two-named-limits.test.mjs +205 -0
  116. package/test/137-the-law-lives-once-and-below.test.mjs +400 -0
  117. package/test/138-the-remainder-drains-only-what-a-move-declares.test.mjs +62 -0
  118. package/test/139-the-witness-is-engagement-not-explanation.test.mjs +51 -0
  119. package/test/140-irrelevant-supply-does-not-change-an-answer.test.mjs +48 -0
  120. package/test/141-the-question-is-paid-at-construction.test.mjs +98 -0
  121. package/test/32-confluence.test.mjs +68 -0
  122. package/test/36-already-answered-fusion.test.mjs +20 -2
  123. package/test/37-cluster-dispersion-fusion.test.mjs +30 -3
  124. package/test/38-reason-restate-guard.test.mjs +28 -2
  125. package/test/43-cast-analog-seat.test.mjs +10 -0
  126. package/test/55-cost-meter.test.mjs +862 -0
@@ -1,7 +1,17 @@
1
1
  # Tempting but Wrong — 13 Traps
2
2
 
3
3
  Thirteen shortcuts that look plausible and break an invariant. Each states what
4
- not to do, why it fails, and what to do instead.
4
+ not to do, why it fails, and what to do instead. **Some things are universal:
5
+ discovering bugs:**
6
+
7
+ - A bug must be pinned by a test that shows it.
8
+ - This test cannot be accidental; it is subtle and requires deep analysis. That
9
+ is, it is not the test itself that reveals the bug, but rather the class of
10
+ errors to which the bug belongs.
11
+ - This is difficult to do because the suite's small synthetic corpus easily
12
+ leads to accidental bugs, and real-world corpus must not be compromised.
13
+ - Something that happens due to deduplication, a tie-breaking rule, etc., isn't
14
+ a bug—and that’s a subtle point.
5
15
 
6
16
  ### 1. `score >= threshold` decides identity
7
17
 
@@ -30,8 +40,7 @@ not to do, why it fails, and what to do instead.
30
40
  - **WRONG:** Break equal-rank ties by picking the most recently inserted
31
41
  edge/node.
32
42
  - **WHY:** Tie-breaks must be corpus-determined and stable; last-inserted is
33
- recency-dependent and was fixed as a bug (`AGENTS §2` Invariant 1 —
34
- first-inserted fallback).
43
+ recency-dependent (`AGENTS §2` Invariant 1 — first-inserted fallback).
35
44
  - **CORRECT:** `guidedFirst`/`chooseNext`/`chooseAmong`: rank then
36
45
  first-inserted (lowest node id / `LIMIT 1` insertion order). Pinned by
37
46
  `test/03-recall.test.mjs` determinism suites.
@@ -55,8 +64,8 @@ not to do, why it fails, and what to do instead.
55
64
  policy is enforced by masking, not pricing (`AGENTS §2` Invariant 4 — One cost
56
65
  currency; `docs/architecture/cost-model.md` § Policy is not cost).
57
66
  - **CORRECT:** Keep `PASS` dominating; enforce precedence in the caller (e.g.
58
- `pipeline.ts` masks recognised sites overlapped by `ComputedResult`). Pinned
59
- by `test/04-think.test.mjs` and `test/55-cost-meter.test.mjs`.
67
+ `cover.ts` masks recognised sites overlapped by `ComputedResult`). Pinned by
68
+ `test/04-think.test.mjs` and `test/55-cost-meter.test.mjs`.
60
69
 
61
70
  ### 6. Reimplementing `locate`/`align` inside a mechanism
62
71
 
@@ -3,7 +3,7 @@
3
3
  Four executable gates. Each: run the command, check what it guards, follow its
4
4
  §.
5
5
 
6
- ## 1 — Correctness (all 90 suites)
6
+ ## 1 — Correctness (all suites)
7
7
 
8
8
  ```bash
9
9
  npm test
@@ -12,9 +12,9 @@ npm test
12
12
  Guards honest silence, determinism, and every pinned contract. Silence:
13
13
  unrelated queries ground to nothing (`test/28`, `50`, `56`, `67`, `76`, `84`).
14
14
  Determinism: same seed + deposit order + query gives byte-identical answer
15
- (`test/20`). Every invariant is pinned — a simplification that fails a test is
16
- wrong until the test is shown wrong. §14–25 (pipeline), §64 (derived
17
- thresholds), AGENTS.md §2 invariants 1–5.
15
+ (`test/20`). Every invariant is pinned, the closure law included
16
+ (`test/133`–`140`). §14–25 (pipeline), §64 (derived thresholds), AGENTS.md §2
17
+ invariants 1–5.
18
18
 
19
19
  ## 2 — Work accounting (profiler)
20
20
 
@@ -23,9 +23,9 @@ node bench/profile-inference.mjs # add [n] to limit probes
23
23
  node bench/profile-inference.mjs --trace # trace is a debugging aid, not product
24
24
  ```
25
25
 
26
- Guards without trace: counters deterministic and diffable between runs; phases
27
- nest (not disjoint — `think` contains every mechanism phase); shared analyses
28
- charged to themselves, not to the first toucher; millisecond fields are
26
+ Guards without trace: counters exact and diffable between COLD runs; phases nest
27
+ (not disjoint — each phase is charged by its own layer); shared analyses charged
28
+ to themselves, not to the first toucher; millisecond fields are
29
29
  non-deterministic hints only. With `--trace`, recognition idempotence still
30
30
  holds (`test/42`). `src/meter.ts`, `docs/architecture/meter.md`, §55,
31
31
  `AGENTS.md` §6.
@@ -12,7 +12,7 @@ schema yields its own candidate and `think`'s single weight comparison picks.
12
12
  halo-matched `pre.rec.sites`. The product is `pre.weave()` — `points[]` (each
13
13
  with graded `runs[]`) and a per-query-byte `depth[]` (how many structures cover
14
14
  that byte). CAST's single-vs-multi test is measured from those runs: a second
15
- point must add ≥ one perception quantum of coverage the widest point does not.
15
+ point must add ≥ one perception quantum of coverage the widest does not.
16
16
 
17
17
  ## Gate — weave-local discriminative frame
18
18
 
@@ -76,5 +76,5 @@ redirection, or analogical comparison), not from a literal continuation.
76
76
  ## Source
77
77
 
78
78
  `src/mind/mechanisms/cast.ts` (`counterfactualTransfer`, `seatOfNode`,
79
- `MIN_WEAVE`), `src/mind/match.ts` (`alignGraded`, `project`, `depth`),
79
+ `MIN_WEAVE`, `weave.depth`), `src/mind/match.ts` (`alignGraded`, `project`),
80
80
  `src/geometry.ts` (`dominates`), `src/mind/graph-search.ts` (`STEP`).
@@ -15,9 +15,8 @@ consumes them directly; any site whose bytes overlap a computed span is masked
15
15
  - `formRules` follow continuation edges (`GraphSearch.formRules`): each hop
16
16
  costs `STEP` (1). Forks across all continuations up to the hub bound;
17
17
  disambiguation is distributional, not heuristic.
18
- - Edge-less forms may hop via a halo sibling (`conceptHop` / `resolveConcepts`
19
- in `src/mind/mechanisms/cover.ts`) at `CONCEPT` (10), borrowing a synonym's
20
- continuation.
18
+ - Edge-less forms may hop via a halo sibling (`conceptHop` / `resolveConcepts`)
19
+ at `CONCEPT` (10), borrowing a synonym's continuation.
21
20
 
22
21
  ## Gate — `leadsSomewhere` (`src/mind/traverse.ts`)
23
22
 
@@ -34,8 +33,8 @@ and are filtered during recognition.
34
33
  | `PASS` | 1000 / byte | each unaccounted byte |
35
34
  | `MICRO` | 1e-3 | per-byte A* heuristic (`h = (len-right)*MICRO`) |
36
35
 
37
- Mechanism weight is `moves + PASS * unaccounted_bytes`; comparison is at `STEP`
38
- grade, then by `scaffolding` bytes, then list order.
36
+ The cover reports `moves` (its derivation's discrete work) and `accounted`; the
37
+ ladder prices both.
39
38
 
40
39
  ## Pre-resolution (`src/mind/mechanisms/cover.ts`)
41
40
 
@@ -7,13 +7,13 @@ what sits between them.
7
7
 
8
8
  ## Matcher — `skillExemplar` / `isSpanShaped` / `containsSpan` (`src/mind/match.ts`)
9
9
 
10
- An exemplar is span-shaped when its answer is an in-order embedding of its
11
- context. `isSpanShaped` is the open reading (sparse subsequence, any gaps) used
12
- to accept candidates; `answerRunsInContext` is the strong reading (greedy
13
- longest contiguous runs) used to decompose the answer for projection. Candidates
14
- are ranked anchors from `climbAttentionAll` (`Precomputed.spanShapedOf`), tried
15
- in order up to `pre.k`; sub-quantum (`< W = maxGroup`) or unanchored results are
16
- skipped.
10
+ An exemplar is span-shaped when its answer embeds in order. `isSpanShaped` is
11
+ the open reading (sparse subsequence, any gaps) for acceptance; `containsSpan`
12
+ is the strict reading (contiguous run, or a resolved node) that fusion gates on,
13
+ extraction decomposes with `answerRunsInContext` (greedy longest runs).
14
+ Candidates are ranked anchors from `climbAttentionAll`
15
+ (`Precomputed.spanShapedOf`), tried up to `pre.k`; sub-quantum (`< W`) or
16
+ unanchored results are skipped.
17
17
 
18
18
  ## Projection — read between located frames (`src/mind/mechanisms/extraction.ts`)
19
19
 
@@ -24,16 +24,15 @@ W = `maxGroup` (river window); bars from `src/geometry.ts`.
24
24
  ## Echo — the refusing tail
25
25
 
26
26
  If no tier grounded, the exact cosine of the top hit is re-folded (`gistOf` on
27
- its bytes). Decision uses that exact value in the same query-relative,
28
- chance-corrected fraction — never the RaBitQ estimate. Below `reach` → silence;
29
- restating → silence; otherwise the hit's own bytes are returned as an ungrounded
30
- echo.
27
+ its bytes). It uses that exact value in the same chance-corrected fraction —
28
+ never the RaBitQ estimate. Below `reach` → silence; restating → silence;
29
+ otherwise the hit's own bytes are returned as an ungrounded echo.
31
30
 
32
31
  ## Provenance
33
32
 
34
33
  Grounded answers carry `recall`; the echo carries `recall-echo` (`echoed: true`
35
- on `RecallResult`). Consumers distinguish a continuation through learned edges
36
- from a near-identity echo.
34
+ on `RecallResult`); it declares `used: ∅`. Consumers distinguish a continuation
35
+ through learned edges from a near-identity echo.
37
36
 
38
37
  ## Substitution bridge — refusal-path only (`src/mind/bridge.ts`)
39
38
 
@@ -47,13 +46,13 @@ unanimous, and the raw gap is length-balanced. Coverage must dominate the query
47
46
  and no dismissed gap may hide known content (`dismissedKnownContent` gate). Cost
48
47
  is `CONCEPT` per substitution plus `STEP`; accounted spans include matched and
49
48
  substituted ranges (so a 28/29-byte paraphrase is not charged `PASS` per
50
- substituted byte — observed double-charge that let `cast` outbid the bridge).
49
+ substituted byte — the double-charge that let `cast` outbid the bridge).
51
50
  Zero-substitution identity bridges carry `complete: true` (the whole read-out);
52
51
  substituted bridges do not.
53
52
 
54
- Scaffolding-only queries abstain: when every stored window that could anchor is
53
+ Scaffolding-only queries abstain: when every window that could anchor is
55
54
  saturated (corpus-global scaffolding, `allWindowsAreScaffolding`), the bridge
56
- returns nothing — a single substituted word cannot carry the semantic load.
55
+ returns nothing — one substituted word cannot carry the load.
57
56
 
58
57
  ## Cost
59
58
 
package/example/demo.ts CHANGED
@@ -1,44 +1,97 @@
1
- // demo.ts — one short session that drives the WHOLE pipeline from one memory.
1
+ // demo.ts — a corpus goes in, and the memory is read back out.
2
2
  //
3
- // We give Sema a handful of plain notes, then ask things that no single note
4
- // answers. The headline query is the third one: from three worked examples Sema
5
- // learns the shape of "X was painted by Y", lifts the painter out of a sentence
6
- // it has NEVER seen, and then — in the same pass — reasons forward to a separate
7
- // fact about that painter. The reply contains no word from the question. That is
8
- // retrieval, generalization, and reasoning composing as a single act, with every
9
- // step traceable back to the notes behind it.
3
+ // Sema is given a small corpus of plain notes, each one the shape every deposit
4
+ // has: a context, and what follows it. Then the memory is read two ways — what
5
+ // it HOLDS (`sampleCorpus`), and which of its notes a question REACHES
6
+ // (`searchCorpusText`). Both run through the same content-addressed machinery an
7
+ // answer uses (src/mind/corpus.ts); nothing is indexed and nothing is written.
8
+ //
9
+ // The search addresses content EXACTLY, not by keyword: a question reaches a
10
+ // note when it shares chunk-aligned content with it, so a question with no such
11
+ // overlap is reported as exactly that — a STATE, rendered by the text layer
12
+ // (`CorpusTextResult.note`), never as prose the engine invented.
13
+ //
14
+ // The last act is two ordinary answers, each with its derivation streamed as it
15
+ // unfolds, the PROVENANCE that names the route it grounded on, and the work it
16
+ // cost read off the meter: the rationale and the meter ARE the explanation
17
+ // surface (AGENTS.md §6).
18
+
19
+ import { decodeText, formatReport, Mind, SQliteStore } from "../src/index.js";
20
+
21
+ // One relation shown three times — a pattern taught purely by example — plus a
22
+ // stray fact keyed on a name none of the examples mention.
23
+ const CORPUS: Array<[string, string]> = [
24
+ ["The Mona Lisa was painted by Leonardo da Vinci.", "Leonardo da Vinci"],
25
+ ["The Starry Night was painted by Vincent van Gogh.", "Vincent van Gogh"],
26
+ [
27
+ "The Night Watch was painted by Rembrandt van Rijn.",
28
+ "Rembrandt van Rijn",
29
+ ],
30
+ ["Pablo Picasso", "Pablo Picasso co-founded the Cubist movement"],
31
+ ["The Weeping Woman was painted by Pablo Picasso.", "Pablo Picasso"],
32
+ ];
10
33
 
11
- import { Mind } from "../src/index.js";
12
- import { SQliteStore } from "../src/store-sqlite.js";
34
+ // Questions the corpus can address, and one it cannot — the honest miss.
35
+ const QUERIES = [
36
+ "The Mona Lisa was painted by Leonardo da Vinci.",
37
+ "Pablo Picasso",
38
+ "xylophone",
39
+ ];
40
+
41
+ // One question answered by composing across the notes, and one answered by
42
+ // computing: the two routes the corpus search does not take.
43
+ const ASKS = [
44
+ "The Weeping Woman was painted by Pablo Picasso.",
45
+ "a museum charges 12*4 for a family ticket",
46
+ ];
13
47
 
14
48
  async function main(): Promise<void> {
15
- const mind = new Mind({ store: new SQliteStore({ path: ":memory:" }) });
16
- const ask = async (q: string) => (await mind.respondText(q)).trim();
17
-
18
- // ── Jot down what we know. Each line is just (context → what follows). ──
19
- await mind.ingest([
20
- // One relation, shown three times — a pattern taught purely by example:
21
- ["The Mona Lisa was painted by Leonardo da Vinci.", "Leonardo da Vinci"],
22
- ["The Starry Night was painted by Vincent van Gogh.", "Vincent van Gogh"],
23
- [
24
- "The Night Watch was painted by Rembrandt van Rijn.",
25
- "Rembrandt van Rijn",
26
- ],
27
- // One stray fact, keyed on a name none of the examples mention:
28
- ["Pablo Picasso", "Pablo Picasso co-founded the Cubist movement"],
29
- ]);
30
-
31
- // 1) GENERALIZE — apply the learned pattern to an unseen sentence and read out
32
- // the painter. "Pablo Picasso" was never given as an answer; Sema locates it
33
- // by analogy to the three examples.
34
- console.log(await ask("The Weeping Woman was painted by Pablo Picasso."));
35
- // → "Pablo Picasso co-founded the Cubist movement"
36
- // …and, having found the painter, it KEEPS GOING: the name bridges into the
37
- // one fact it holds about him. The answer appears in no word of the question.
38
-
39
- // 2) COMPUTE — exact arithmetic, grounded right where the notes go silent.
40
- console.log(await ask("a museum charges 12*4 for a family ticket"));
41
- // → "48"
49
+ const mind = new Mind({
50
+ store: new SQliteStore({ path: ":memory:" }),
51
+ profile: true,
52
+ });
53
+ await mind.ingest(CORPUS);
54
+
55
+ // 1) WHAT THE MEMORY HOLDS — real pairs, browsed, no query and no random draw.
56
+ console.log("— the corpus, as the memory holds it —");
57
+ for (const p of mind.sampleCorpus(4).pairs) {
58
+ console.log(` ${decodeText(p.context)} → ${decodeText(p.continuation)}`);
59
+ }
60
+
61
+ // 2) SEARCH — which stored notes does a question reach? A question that
62
+ // addresses the corpus answers with pairs; one that shares nothing with it
63
+ // answers with a note saying so.
64
+ for (const q of QUERIES) {
65
+ const r = mind.searchCorpusText(q, 3);
66
+ console.log(`\n— "${q}" — ${r.resolved} resolved / ${r.reached} reached`);
67
+ if (r.note !== undefined) console.log(` ${r.note}`);
68
+ for (const p of r.pairs) {
69
+ console.log(
70
+ ` ${p.context} → ${p.continuation} (${p.matchedBytes} matched)`,
71
+ );
72
+ }
73
+ }
74
+
75
+ // 3) ANSWERS, WITH THEIR DERIVATION — the same pipeline, read as data. Steps
76
+ // repeat (recognise re-enters under every mechanism that needs it), so each
77
+ // distinct mechanism-and-note is printed once, in the order it first ran.
78
+ for (const q of ASKS) {
79
+ const seen = new Set<string>();
80
+ const trace: string[] = [];
81
+ const r = await mind.respond(q, (s) => {
82
+ const line = `${s.mechanism.join(" › ")}${s.note ? ` — ${s.note}` : ""}`;
83
+ if (seen.has(line)) return;
84
+ seen.add(line);
85
+ trace.push(`${" ".repeat(Math.max(0, s.mechanism.length - 1))}${line}`);
86
+ });
87
+ console.log(`\n— "${q}" — ${r.provenance ?? "no answer"}`);
88
+ console.log(` ${decodeText(r.bytes).trim()}`);
89
+ console.log("— how —");
90
+ for (const s of trace) console.log(s);
91
+ if (mind.lastCost !== null) {
92
+ console.log(`— what it cost —\n${formatReport(mind.lastCost)}`);
93
+ }
94
+ }
42
95
 
43
96
  await mind.store.close();
44
97
  }
package/jsr.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://jsr.io/schema/config-file.v1.json",
3
3
  "name": "@hviana/sema",
4
- "version": "0.8.2",
4
+ "version": "0.8.5",
5
5
  "exports": "./src/index.ts"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hviana/sema",
3
- "version": "0.8.2",
3
+ "version": "0.8.5",
4
4
  "description": "Sema: a non-parametric, instance-based reasoning system.",
5
5
  "repository": {
6
6
  "type": "git",
package/src/alu/README.md CHANGED
@@ -8,10 +8,10 @@ a truth value) are declared here once.
8
8
 
9
9
  It joins the mind as a `PipelineMechanism`
10
10
  ([`../mind/pipeline-mechanism.ts`](../mind/pipeline-mechanism.ts)) whose only
11
- special role is the optional `parse(query)` method every mechanism may
12
- implement. The mind knows nothing about what the ALU computes; it only knows
13
- that `parse` returns `ComputedSpan[]`, which enter the one lightest-derivation
14
- search as authoritative axioms (at `STEP` cost, like a learned edge).
11
+ special role is the optional `parse(query)` every mechanism may implement. The
12
+ mind knows nothing about what the ALU computes; it only knows that `parse`
13
+ returns `ComputedSpan[]`, which enter the one lightest-derivation search as
14
+ authoritative axioms (at `STEP`, like a learned edge).
15
15
 
16
16
  It has no dependency on the rest of the codebase except the pure byte helpers in
17
17
  `../bytes.ts`, and is intended to be reused as a self-contained sublibrary in
@@ -166,7 +166,7 @@ The ALU is completely decoupled from Sema. It joins the mind through
166
166
  re-exported from [`../mind/pipeline.ts`](../mind/pipeline.ts)), a thin adapter
167
167
  that wraps the ALU's `parse` in a `PipelineMechanism` — the same uniform
168
168
  interface every grounding mechanism (CAST, confluence, cover, extraction,
169
- recall) implements, so nothing about the ALU is special-cased in the pipeline.
169
+ recall) implements, so nothing about the ALU is special-cased.
170
170
 
171
171
  ### The contract
172
172
 
@@ -175,7 +175,7 @@ recall) implements, so nothing about the ALU is special-cased in the pipeline.
175
175
  ```ts
176
176
  interface PipelineMechanism {
177
177
  parse?(query: Uint8Array): Promise<ComputedSpan[]>;
178
- floor(ctx, query, pre): Promise<number | null>;
178
+ floor(ctx, query, pre, worthRunning): Promise<number | null>;
179
179
  run(ctx, query, pre): Promise<MechanismResult[]>;
180
180
  }
181
181
  ```
@@ -259,7 +259,7 @@ whose span overlaps a computed span is **masked** before the search. This is the
259
259
  the computed `4` is the cover's sole completion there. The search itself stays a
260
260
  neutral cost engine (a computed `Out` and a learned edge both cost `STEP`);
261
261
  precedence lives entirely in the masking step, which is in
262
- `src/mind/pipeline.ts`, not in the search and not in the ALU.
262
+ `src/mind/mechanisms/cover.ts`, not in the search and not in the ALU.
263
263
 
264
264
  A computation and an _unrelated_ rewrite still compose in one answer
265
265
  (`"ice 2+2"` → `"cold 4"`) because the masking is scoped to the colliding span
@@ -302,11 +302,10 @@ registry.derive("hypot", 2, ["hypot"], (args, ctx) =>
302
302
  ]));
303
303
  ```
304
304
 
305
- No kernel edit, no graph-search edit, no resonance edit — name it, list its
306
- surface forms, write the body in terms of existing ops. A scalar op broadcasts
307
- over `nd` automatically; pass `structural = true` (the trailing flag on
308
- `prim`/`derive`) only for an op that consumes a list _whole_, like the `nd`
309
- kernel's own.
305
+ No kernel, graph-search or resonance edit — name it, list its surface forms,
306
+ write the body from existing ops. A scalar op broadcasts over `nd`
307
+ automatically; pass `structural = true` (the trailing flag on `prim`/`derive`)
308
+ only for an op that consumes a list _whole_, like the `nd` kernel's own.
310
309
 
311
310
  ## Layout
312
311
 
package/src/config.ts CHANGED
@@ -116,6 +116,17 @@ export interface MindConfig {
116
116
  seed: number;
117
117
  recallQueryK: number;
118
118
  haloQueryK: number;
119
+ /** Branch nodes the pivot sweep may PROBE looking for the learnt context an
120
+ * answer contains — the pivot's own shortlist capacity, separate from
121
+ * `recallQueryK` because they are different quantities: this one bounds a
122
+ * MECHANICAL sweep over the answer's tree (breadth-first, largest regions
123
+ * first, so an exhausted allowance drops the far ones and never the near
124
+ * ones), while `recallQueryK` bounds the bridge's candidate reads. Sharing
125
+ * one number for both meant that tightening either silently starved the
126
+ * other — measured: at `recallQueryK: 1` the pivot cannot find a pivot at
127
+ * all. (`rationaleSampleK` was split out of `recallQueryK` for the same
128
+ * reason, found by an adversarial review.) */
129
+ pivotProbeK: number;
119
130
  /** Corpus reading (see src/mind/corpus.ts): results per call, resolved
120
131
  * nodes climbed from, contexts requested per climb, probes used to stride
121
132
  * the id space when browsing, bytes of each side a preview keeps, and the
@@ -148,6 +159,7 @@ export const DEFAULT_CONFIG: MindConfig = {
148
159
  seed: 42,
149
160
  recallQueryK: 12,
150
161
  haloQueryK: 12,
162
+ pivotProbeK: 12,
151
163
  rationaleSampleK: 12,
152
164
  corpusLimitMax: 24,
153
165
  corpusClimbs: 24,
@@ -196,6 +208,7 @@ export function resolveConfig(opts: Partial<MindConfig> = {}): MindConfig {
196
208
  seed: opts.seed ?? DEFAULT_CONFIG.seed,
197
209
  recallQueryK: opts.recallQueryK ?? DEFAULT_CONFIG.recallQueryK,
198
210
  haloQueryK: opts.haloQueryK ?? DEFAULT_CONFIG.haloQueryK,
211
+ pivotProbeK: opts.pivotProbeK ?? DEFAULT_CONFIG.pivotProbeK,
199
212
  rationaleSampleK: opts.rationaleSampleK ?? DEFAULT_CONFIG.rationaleSampleK,
200
213
  corpusLimitMax: opts.corpusLimitMax ?? DEFAULT_CONFIG.corpusLimitMax,
201
214
  corpusClimbs: opts.corpusClimbs ?? DEFAULT_CONFIG.corpusClimbs,
package/src/geometry.ts CHANGED
@@ -155,23 +155,31 @@ export function profileCapacity(D: number): number {
155
155
  return Math.max(1, Math.floor(Math.sqrt(D)));
156
156
  }
157
157
 
158
+ /**
159
+ * The POOLED-vote significance floor, and the derivation lives here because
160
+ * its PREMISE is a property of the caller's weighting.
161
+ *
162
+ * DERIVATION (docs/architecture/thresholds.md §2): a maximally-specific region
163
+ * contributes at most `ln N` to a pooled vote, so `ln(N) + 1/2` sits half a
164
+ * unit above ONE region's ceiling — it demands corroboration BEYOND a single
165
+ * region, which is what makes it a consensus bar rather than a resonance bar.
166
+ *
167
+ * PREMISE: that per-region ceiling is an IDF, `ln(N/c)` — attention.ts's
168
+ * `inverse` mode, the mode every non-test caller runs. The other two modes
169
+ * weight a region by `ln(1+c)` (`direct`) or `ln(N/c) + ln(1+c)` (`combined`),
170
+ * i.e. `ln N + ln(1 + 1/c)`, so they exceed the premise's ceiling by at most
171
+ * `ln 2` — a DERIVED bound, not a hole: the floor stays within `ln 2` of its
172
+ * own premise in every mode, and exactly on it in `inverse`.
173
+ *
174
+ * MEASURED: the floor is read on the pooled vote (`commitVotes`, `recall`,
175
+ * `cast`). Across 27 anchors on 6 queries, 11 cleared it by the sum and NONE
176
+ * by a single region's peak — gating on one region would refuse every elected
177
+ * root.
178
+ */
158
179
  export function consensusFloor(N: number): number {
159
180
  return Math.log(N) + 1 / 2;
160
181
  }
161
182
 
162
- /** The coverage bar for the reach (interior) index, when vector-similarity
163
- * gating is used. Returns the concept threshold — the structural midpoint
164
- * (~0.5 at D=1024) where two forms are "more similar than not."
165
- *
166
- * Currently UNUSED in the hot training path: interior nodes are indexed
167
- * unconditionally (hash-cons dedup bounds the index naturally).
168
- * Post-hoc structural compaction ({@link Store.compactContentIndex})
169
- * replaces runtime coverage gating with a batch pass that removes
170
- * structurally-isolated entries. Derived, never tuned. */
171
- export function coverageBar(_maxGroup: number, D: number): number {
172
- return conceptThreshold(D);
173
- }
174
-
175
183
  // ---- types ----
176
184
 
177
185
  export interface Folded {
package/src/meter.ts CHANGED
@@ -223,6 +223,12 @@ export class Meter {
223
223
  joinNoKey = 0;
224
224
  /** Refused: the fact contains no entity that leads anywhere. */
225
225
  joinNoEntity = 0;
226
+ /** `recompleteNode` re-covered a produced form — the descent that decomposes
227
+ * a completion by ITS OWN kids. Without this the descent is invisible: a
228
+ * caller could see the chain's result but not whether the recomposition
229
+ * happened, so "the recursion stopped" and "the recursion never ran" were
230
+ * indistinguishable from the counters alone. */
231
+ recompletes = 0;
226
232
 
227
233
  // ── Mind: the multi-hop pivot (EXTENSION) ───────────────────────────────
228
234
  //
@@ -233,6 +239,62 @@ export class Meter {
233
239
  /** Times the reasoner pivoted on a span its answer contains and stepped
234
240
  * across that fact. */
235
241
  pivotSteps = 0;
242
+ /** Canon probes REFUSED because the canon budget ran out — the one thing the
243
+ * budget does that nothing could see. The budget itself is derived
244
+ * (`bytes.length · chainReach(W)²`, recognition.ts), and the cheap exact route
245
+ * is deliberately unbudgeted, so this counter says exactly when the expensive
246
+ * route was priced out. Counted where the fact happens (the `!canonBudget`
247
+ * refusal), not where the probe is called. */
248
+ canonProbesDenied = 0;
249
+ /** The pipeline's remainder AT THE DECISION POINT, in bytes: what the grounded
250
+ * answer plus the pre-computed spans left unexplained, after the same W floor
251
+ * the fuse gate uses. This is the quantity that licenses (or refuses) the
252
+ * post-grounding extension and the fusion — it was computed, used, and never
253
+ * published, so nothing could measure what a search had LEFT when it decided.
254
+ * Read with {@link postGroundingRemainderSpans}. */
255
+ postGroundingRemainderBytes = 0;
256
+ /** How many spans that remainder consists of (each at least one W window). */
257
+ postGroundingRemainderSpans = 0;
258
+ /** Times `fuseAttention` produced a FUSED answer — not times it was called.
259
+ * It is entered whenever the query has a remainder ≥ W and returns early when
260
+ * there is nothing to bridge (`containsSpan`, a lone root, an empty pass), so
261
+ * the call and the fact are different things and only the fact is counted.
262
+ * Its own rationale step reports the fusion; this is the untraced view, and
263
+ * its cost is one bridging edge: `fuseRuns · STEP`. */
264
+ fuseRuns = 0;
265
+ /** Steps the post-grounding EXTENSION took — pivots plus forward-absorbs.
266
+ * `pivotSteps` counts only the former, so before this the extension's COST was
267
+ * not computable at all. With it, the price of extending the answer is
268
+ * `reasonSteps · STEP`, the ladder's own value for following an edge. */
269
+ reasonSteps = 0;
270
+ /** Bytes of the grounding's UNCOVERED material the extension was justified by
271
+ * — the union of the spans each step carried a `W`-window of. The gate
272
+ * already computed WHICH span carried it per step and kept only a boolean;
273
+ * this is that fact, accumulated. Read with {@link reasonSteps}: one is the
274
+ * price, the other the explanation. */
275
+ reasonCarriedBytes = 0;
276
+ /** Bytes of the question's REMAINDER a step CONSUMED — the drop the law's own
277
+ * `advance` makes when a declared move carries the material it accounts for.
278
+ * Read with {@link reasonSteps} and {@link reasonCarriedBytes}: carrying is
279
+ * the engagement, this is the consumption, and before it the second was
280
+ * invisible. */
281
+ closureDrainedBytes = 0;
282
+ /** Bytes of the question the grounding PRICED but whose material its answer does
283
+ * NOT carry, at or above one quantum — the debt the construction leaves for the
284
+ * walk to pay by carrying it. Zero means the grounding's coverage is honest:
285
+ * everything it priced is either held by the answer or under the W floor. */
286
+ groundingWithheldBytes = 0;
287
+ /** Branch-node probes the pivot sweep actually spent looking for the learnt
288
+ * context an answer contains (one `resonate` per probe). The untraced view
289
+ * of what the multi-hop's shortlist costs. */
290
+ pivotProbes = 0;
291
+ /** Branch nodes the pivot's probe cap withheld (`branchCount − probeCap`, over
292
+ * every call). A capacity fact, not a verdict: the sweep is breadth-first,
293
+ * so the probes it DOES spend are the largest regions, and recognition still
294
+ * contributes every exact containment candidate regardless of the budget.
295
+ * Read it with {@link pivotProbes} — one says the work, the other the
296
+ * shortfall. */
297
+ pivotBranchesUnprobed = 0;
236
298
 
237
299
  // ── Mind: the cover's connector assembly (LIMIT) ────────────────────────
238
300
  //
@@ -119,7 +119,6 @@ export async function articulate(
119
119
  new Map(),
120
120
  ans.leaves,
121
121
  ans.splits,
122
- ans.starts,
123
122
  substitutions,
124
123
  undefined,
125
124
  undefined,