@hviana/sema 0.9.0 → 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 +20 -0
  14. package/dist/src/meter.js +21 -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 +29 -13
  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 +21 -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 +24 -9
  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
@@ -1,18 +1,18 @@
1
1
  # INVARIANTS — Laws, Proofs, Derivations
2
2
 
3
- | # | Law | Defined in | Pins | Doc |
4
- | -- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | ------------------------- |
5
- | 1 | Determinism | `src/config.ts:seed` `src/alphabet.ts:Alphabet` `src/mind/traverse.ts:guidedFirst` | `test/20` `test/42` | `determinism.md` |
6
- | 2 | Derived thresholds | `src/geometry.ts:mergeThreshold,identityBar,reachThreshold,significanceBar,consensusFloor,dominates` | `test/64` `test/40` | `thresholds.md` |
7
- | 3 | Exact decides / approximate proposes | `src/mind/primitives.ts:resolve` `src/mind/match.ts:locate,alignGraded` `src/mind/resonance.ts:bridge` | `test/51` | `exact-vs-approximate.md` |
8
- | 4 | One cost currency | `src/mind/graph-search.ts:MICRO,STEP,CONCEPT,PASS` `src/derive:lightestDerivation` (min,+) `src/mind/attention.ts:poolVotes` (+,+) | `test/55` `test/04` | `cost-model.md` |
9
- | 5 | Bounded reads | `src/store.ts:AbstractStore:nextFirst,parentsFirst,containersSlice,hasNext,bytesPrefix` `src/mind/traverse.ts:hubBound,hubCap` | `test/90` `test/14` | `bounded-reads.md` |
10
- | 6 | Fold contract | `src/geometry.ts:contentLevels` `src/mind/canonical.ts:canonicalWindows,chainReach` `src/canon.ts:canonicalizer` | `test/59` `test/63` | `fold-contract.md` |
11
- | 7 | Mechanism market | `src/mind/pipeline-mechanism.ts:PipelineMechanism,Precomputed` `src/mind/pipeline.ts:think,worthRunning` | `test/01` `test/04` | `mechanism-market.md` |
12
- | 8 | Two commonality measures | `src/mind/traverse.ts:reachOf,dominates,corpusN` (global) `cast.ts:depth[],MIN_WEAVE` (weave-local) | `test/17` `test/34` | `commonality.md` |
13
- | 9 | Memoization idempotence | `src/mind/pipeline-mechanism.ts:Precomputed` `src/mind/mind.ts:beginResponse,endResponse,_resolvedSubtrees` | `test/42` | `memoization.md` |
14
- | 10 | Caches as budgets | `src/store.ts:BoundedMap` `src/config.ts:StoreConfig:bytesCacheMax,recCacheBytes,haloCacheBytes` | `test/96` `test/91` | `caches.md` |
15
- | 11 | Honest degradation | `src/mind/pipeline.ts:weight=moves+PASS*unaccounted` `src/store.ts:BoundedMap:miss→re-derive` | `test/28` `test/84` | `store.md`+`caches.md` |
16
- | 12 | Meter contracts | `src/meter.ts:Meter,PhaseCost,time` `src/mind/pipeline-mechanism.ts:Precomputed.shared` | `test/55` | `meter.md` |
17
- | 13 | Saturation | `traverse.ts:edgeAncestors,types.ts:SaturationReason` `src/mind/junction.ts:junctionContainersFrom` `src/mind/resonance.ts:pivotInto` | `test/27` `test/16` | `saturation.md` |
18
- | 14 | Closure | `src/mind/derivation.ts:closed,admissible,advance` | `test/133`–`147` | `closure.md` |
3
+ | # | Law | Defined in | Pins | Doc |
4
+ | -- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | ------------------------- |
5
+ | 1 | Determinism | `src/config.ts:seed` `src/alphabet.ts:Alphabet` `src/mind/traverse.ts:guidedFirst` | `test/20` `test/42` | `determinism.md` |
6
+ | 2 | Derived thresholds | `src/geometry.ts:mergeThreshold,identityBar,reachThreshold,significanceBar,consensusFloor,dominates` | `test/64` `test/40` | `thresholds.md` |
7
+ | 3 | Exact decides / approximate proposes | `src/mind/primitives.ts:resolve` `src/mind/match.ts:locate,alignGraded` `src/mind/resonance.ts:bridge` | `test/51` | `exact-vs-approximate.md` |
8
+ | 4 | One cost currency | `src/mind/graph-search.ts:MICRO,STEP,CONCEPT,PASS` `src/derive:lightestDerivation` (min,+) `src/mind/attention.ts:poolVotes` (+,+) | `test/55` `test/04` | `cost-model.md` |
9
+ | 5 | Bounded reads | `src/store.ts:AbstractStore:nextFirst,parentsFirst,containersSlice,hasNext,bytesPrefix` `src/mind/traverse.ts:hubBound,hubCap` | `test/90` `test/14` | `bounded-reads.md` |
10
+ | 6 | Fold contract | `src/geometry.ts:contentLevels,contentIdentity` `src/mind/primitives.ts:branchNaming` `src/mind/canonical.ts:canonicalWindows,chainReach` `src/canon.ts:canonicalizer` | `test/59` `test/63` `test/152` | `fold-contract.md` |
11
+ | 7 | Mechanism market | `src/mind/pipeline-mechanism.ts:PipelineMechanism,Precomputed` `src/mind/pipeline.ts:think,worthRunning` | `test/01` `test/04` `test/153` | `mechanism-market.md` |
12
+ | 8 | Two commonality measures | `src/mind/traverse.ts:reachOf,dominates,corpusN` (global) `cast.ts:depth[],MIN_WEAVE` (weave-local) | `test/17` `test/34` | `commonality.md` |
13
+ | 9 | Memoization idempotence | `src/mind/pipeline-mechanism.ts:Precomputed` `src/mind/mind.ts:beginResponse,endResponse,_resolvedSubtrees` | `test/42` | `memoization.md` |
14
+ | 10 | Caches as budgets | `src/store.ts:BoundedMap` `src/config.ts:StoreConfig:bytesCacheMax,recCacheBytes,haloCacheBytes` | `test/96` `test/91` | `caches.md` |
15
+ | 11 | Honest degradation | `src/mind/pipeline.ts:weight=moves+PASS*unaccounted` `src/store.ts:BoundedMap:miss→re-derive` | `test/28` `test/84` | `store.md`+`caches.md` |
16
+ | 12 | Meter contracts | `src/meter.ts:Meter,PhaseCost,time` `src/mind/pipeline-mechanism.ts:Precomputed.shared` | `test/55` | `meter.md` |
17
+ | 13 | Saturation | `traverse.ts:edgeAncestors,types.ts:SaturationReason` `src/mind/junction.ts:junctionContainersFrom` `src/mind/resonance.ts:pivotInto` | `test/27` `test/16` | `saturation.md` |
18
+ | 14 | Closure | `src/mind/derivation.ts:admissible,advance,closeOver` | `test/133`–`151` | `closure.md` |
@@ -81,5 +81,5 @@ net); a walk with only a cap drifts to the cap.
81
81
  length; training throughput floor; exact recall at scale.
82
82
  - `test/89` — completion recursion stays output-sensitive (nested searches/pops
83
83
  sublinear); guards the count of reads, not just per-read size.
84
- - `test/90` — connector probe (`resolveConnectors`) reads by the query length
84
+ - `test/90` — connector probe (`offerConnectors`) reads by the query length
85
85
  (`QUERY.length + 1`), not by the learnt continuation; per-read size bound.
@@ -31,6 +31,7 @@ candidate window for `"smallest"` never rescans from front.
31
31
  | Cache | Field | Budget | `sizeOf` | Eviction |
32
32
  | ------------------- | -------------------------- | ---------------------------- | ------------------- | -------------- |
33
33
  | dedup leaf/branch | `_leafKey` / `_branchKey` | `dedupCacheMax` 1M entries | 1 | lru |
34
+ | flat-branch hits | `_flatKey` | `dedupCacheMax` 1M entries | 1 | lru+clock |
34
35
  | reconstructed bytes | `_bytesCache` | `bytesCacheMax` 20 MB | `byteLength` | smallest+clock |
35
36
  | content length | `_lenCache` | `bytesCacheMax` | 16 | lru |
36
37
  | node records | `_recCache` | `recCacheBytes` 10 MB | leaf+4·kids+12 | lru+clock |
@@ -76,10 +77,10 @@ must discharge it.
76
77
  `contentFoldIncremental` segments bit-identically.
77
78
  - Wrong: mismatched `prev` reused by offset produced wrong tree (336 vs 400
78
79
  bytes) — a coincidental prefix length aliased unrelated content.
79
- - Now: `perceiveDeposit` keys by `latin1Key(bytes.subarray(0,L))` (prefix
80
- bytes), probes longest cached proper prefix first; `_depositTrees` populated
81
- only for conversational deposits (budget discipline), otherwise cold path
82
- always correct.
80
+ - Now: `perceiveDeposit` keys by `latin1(bytes.subarray(0,L))` (prefix bytes),
81
+ probes longest cached proper prefix first; `_depositTrees` populated only for
82
+ conversational deposits (budget discipline), otherwise cold path always
83
+ correct.
83
84
 
84
85
  ## Pins
85
86
 
@@ -3,9 +3,10 @@
3
3
  > **Law:** a step is admitted only when it CLOSES the derivation, or MOVES to
4
4
  > structure it has not consumed, or CARRIES material the asker left unaccounted.
5
5
 
6
- One unit and one law, asked by every tier that decides whether to continue: the
7
- chart's frontier, the market's candidates, the post-grounding walk, fusion, and
8
- the mechanisms' own gates. None re-spells a condition the law owns.
6
+ One unit, one law and one engine, asked by every tier that decides whether to
7
+ continue: the chart's frontier, the market's candidates, the post-grounding
8
+ walk, fusion, and the mechanisms' own gates. None re-spells a condition the law
9
+ owns.
9
10
 
10
11
  ## The unit — `src/mind/derivation.ts`
11
12
 
@@ -43,7 +44,35 @@ not carry.
43
44
 
44
45
  The walk ends when the layer stops offering or the law refuses; owning no
45
46
  search, the law cannot prevent a cycle — that is the layer's, over the structure
46
- it holds.
47
+ it holds. A transition is only ever `advance`: a fusion the law refuses is not
48
+ taken (there is no hand-built fallback).
49
+
50
+ ## The engine — `closeOver`
51
+
52
+ `closeOver(state, query, W, layers, enter?)` closes a derivation under the law,
53
+ layer by layer. A layer (`ClosureLayer`) is a named `Offer` with its own
54
+ instrumentation hooks; each is walked by `closure` to its own end, and the state
55
+ it reaches is the state the next layer is offered against. Layers are PHASES, in
56
+ order, never revisited.
57
+
58
+ - **¬FIXED is the engine's.** A fixed state admits no transition, so no layer is
59
+ entered for it — the walk-skip and fusion-skip a caller used to spell by hand
60
+ are the law's first clause, taken before any layer pays.
61
+ - **Engagement is the layer's.** A layer that has nothing to offer a state
62
+ (`engages`) is not entered: no offer, no meter phase.
63
+ - **The pipeline's post-grounding stage IS the engine**, with two layers: the
64
+ walk (`walkLayer` — forward absorb or pivot) and the fusion (`fusionLayer` —
65
+ one composed transition, engaged only while the derivation is open). There is
66
+ no hand-built state anywhere outside `advance` (`test/137.7`).
67
+
68
+ ## The four quantities (trap 13), and where each stands
69
+
70
+ | Quantity | Status |
71
+ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
72
+ | offer of a hop | Consequence. Chart: the corpus's continuations under the READ cap, each a MOVE priced STEP, the search decides (`test/112`). Walk: absorb/pivot, the law admits. |
73
+ | depth of a join | Consequence. The join consumes the shortest tail prefix naming a learnt key that leads — CONTAINS (resolves) ∧ MOVES (leads) — and chains until the tail is consumed; no count (`test/108`). It is priced for the facts a lightest derivation STANDS ON, round by round (`solve`'s join license), never for every fact the exploration reaches — the `deepen` cure for the `recompleteNode` trap. |
74
+ | scope of a gap | Consequence for alignment (`alignAround` walks outward, no cap). NOT for recognition's interior pass: its reach `W⁴ + 2r` bounds an exhaustive embedded-form probe; exact unbounded reach needs a whole-stream index the store does not have. |
75
+ | scope of a substitution | Consequence: the gap between two aligned anchors (`unexplainedSpans`), gated as scaffolding by the global commonality reading. The filler-unanimity window (`chainReach`) is a derived decision scale, not an explosion cap. |
47
76
 
48
77
  ## One cost home
49
78
 
@@ -51,7 +80,7 @@ it holds.
51
80
  `weigh`). A mechanism reports `moves` and `accounted` — what it did — and never
52
81
  a price; `cover` reports its chart derivation's work.
53
82
 
54
- ## Two limits, proved and left out
83
+ ## Three limits, proved and left out
55
84
 
56
85
  1. **The chart cannot evaluate accounting** — its interface has no parameter for
57
86
  it, and carrying it per item was measured and rejected. The chart reads the
@@ -62,6 +91,9 @@ a price; `cover` reports its chart derivation's work.
62
91
  `reason`'s echo guards stop with the remainder non-empty, and recall's
63
92
  reverse tiers close with an empty accounting. That is a fact about the
64
93
  asker's material in the store, available only to the layer holding it.
94
+ 3. **The extension is not priced into the market** (`test/136.2`): the engine
95
+ closes the WINNER only; pricing each candidate's closure would run the walk
96
+ for every candidate, and that comparison has not been measured.
65
97
 
66
98
  ## Layering
67
99
 
@@ -78,3 +110,11 @@ vocabulary, not the tracer's.
78
110
  - `test/142`, `test/143` — the offer's contract, and the cycles.
79
111
  - `test/144`, `test/146`, `test/147` — identity is content, the `contains` gate,
80
112
  the witness ladder.
113
+ - `test/137.7` — no transition is built by hand outside the law.
114
+ - `test/149` — the engine: ¬FIXED first, layers as phases, engagement, a refusal
115
+ ends one layer, and the pipeline sequences no layer by hand.
116
+ - `test/150` — the join prices the facts a derivation stands on, not every fact
117
+ the exploration reaches (a hub's degree changes nothing).
118
+ - `test/151` — the cover's other async premises (connectors, concept hops) are
119
+ resolved where the search reaches them; a span's cheapest completion
120
+ dominates; a grounding on the whole query pays no fusion climb.
@@ -56,6 +56,21 @@ minimum per-byte cost in the ladder (every real per-byte cost is `>= MICRO`,
56
56
  including `PASS`), and only the suffix past `right` is counted, so `h` never
57
57
  exceeds the true remaining cost.
58
58
 
59
+ ## Dominance — why `PASS ≫ STEP` does not flood the chart
60
+
61
+ The heuristic charges `MICRO` for a byte the goal will pay `PASS` for, so a
62
+ cover that leaves bytes unexplained lets the search spend up to `PASS / STEP`
63
+ hops looking for one more explained byte. Coverage itself cannot use them: every
64
+ recognised completion of `[i, j)` advances the cover from `i` to `j` at the same
65
+ `MICRO`. So a form or completion of `[i, j)` whose cost has reached that of a
66
+ completion of `[i, j)` already yielded is DOMINATED and fires no rule
67
+ (`buildSearch`, metered as `searchDominated`): every completion it could lead to
68
+ costs at least as much, and a tie goes to the one yielded first. What a
69
+ completion's BYTES could still do — fuse, splice, join — fires from the
70
+ completion the search would stand on for that span, the same cure the join
71
+ license and `deepen` apply. The first hop's stop-here (`STEP + CONCEPT`) is then
72
+ a real horizon: no chain deeper than it is expanded.
73
+
59
74
  ## Policy is not cost
60
75
 
61
76
  "Computation always wins" is **not** priced into the ladder (a computed result
@@ -69,3 +84,4 @@ the sole completion there. Keep policy in callers; keep the engine neutral.
69
84
  - `test/53` — cross-region probe instrumentation
70
85
  - `test/54` — evidence `k` instrumentation
71
86
  - `test/55` — cost meter (`Meter`, `CostReport`, `searchPops`/`searchPushes`)
87
+ - `test/151` — dominance: a hub's degree generates no chart work
@@ -7,19 +7,20 @@ Siblings: `match-project.md`, `commonality.md`, `meter.md`.
7
7
 
8
8
  ## Single-definition contracts
9
9
 
10
- | Symbol | Defined in | One fact |
11
- | ------------------------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
12
- | `contentLevels` | `src/geometry.ts` | Single boundary rule: cuts + levels from one rolling hash pass; every segmentation reads it. |
13
- | `canonicalWindows` / `chainReach` / `leafIdRun` / `windowIds` | `src/mind/canonical.ts` | Write/read contract: training interns `W-1,W` windows, reading chains to `W²` and probes `W`-windows — drift silences recognition. |
14
- | `junction.ts` + `WalkCache` | `src/mind/junction.ts` | Shared junction ascent (parents + containers) with bounded `√N·W` walk; `WalkCache` memoizes capped reads/parents/containers per response; bridge and attention share it. |
15
- | `joinWithBridge` | `src/mind/resonance.ts` | One out-of-search assembly: `bridge(left,right)` or bare concat with `bridgeMiss` trace. |
16
- | `dismissedKnownContent` | `src/mind/bridge.ts` | Pure attestation: any unaccounted `W`-window that resolves as known content — shared gap guard for substitution and CAST. |
17
- | `sharedReachMemo` | `src/mind/traverse.ts` | One response-scoped `AncestorReach` memo (cleared on write and for traces); every `reachOf`/`edgeAncestors` consumer shares it. |
18
- | `guidedFirst` | `src/mind/traverse.ts` | Guided-or-first answer bytes: `guidedNext` else first-inserted edge (`LIMIT 1`). |
19
- | `leadsSomewhere` | `src/mind/traverse.ts` | Admission predicate: `hasNext` (cached) or `hasHalo`; sites that lead nowhere contribute no derivation. |
20
- | `isChunk` | `src/sema.ts` | `kids !== null && kids.every(k=>k.kids===null)` — smallest grouped unit; governs regions, seams, indexing. |
21
- | `twoEndedSeat` | `src/sema.ts` | One seat algebra: first half low seats, second half high seats; shared by perception, `fold`, and canonical folds. |
22
- | `closed`/`admissible`/`advance` | `src/mind/derivation.ts` | One admission for every derivation step and the readings every tier asks. |
10
+ | Symbol | Defined in | One fact |
11
+ | ------------------------------------------------------------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
12
+ | `contentLevels` | `src/geometry.ts` | Single boundary rule: cuts + levels from one rolling hash pass; every segmentation reads it. |
13
+ | `canonicalWindows` / `chainReach` / `leafIdRun` / `windowIds` | `src/mind/canonical.ts` | Write/read contract: training interns `W-1,W` windows, reading chains to `W²` and probes `W`-windows — drift silences recognition. |
14
+ | `junction.ts` + `WalkCache` | `src/mind/junction.ts` | Shared junction ascent (parents + containers) with bounded `√N·W` walk; `WalkCache` memoizes capped reads/parents/containers per response; bridge and attention share it. |
15
+ | `joinWithBridge` | `src/mind/resonance.ts` | One out-of-search assembly: `bridge(left,right)` or bare concat with `bridgeMiss` trace. |
16
+ | `dismissedKnownContent` | `src/mind/bridge.ts` | Pure attestation: any unaccounted `W`-window that resolves as known content — shared gap guard for substitution and CAST. |
17
+ | `sharedReachMemo` | `src/mind/traverse.ts` | One response-scoped `AncestorReach` memo (cleared on write and for traces); every `reachOf`/`edgeAncestors` consumer shares it. |
18
+ | `guidedFirst` | `src/mind/traverse.ts` | Guided-or-first answer bytes: `guidedNext` else first-inserted edge (`LIMIT 1`). |
19
+ | `leadsSomewhere` | `src/store.ts` (raw), `src/mind/traverse.ts` (memoised) | Admission predicate: `hasNext` or `hasHalo`, defined once on the store; traverse memoises the edge tier per response. |
20
+ | `isChunk` | `src/sema.ts` | `kids !== null && kids.every(k=>k.kids===null)` — smallest grouped unit; governs regions, seams, indexing. |
21
+ | `twoEndedSeat` | `src/sema.ts` | One seat algebra: first half low seats, second half high seats; shared by perception, `fold`, and canonical folds. |
22
+ | `closed`/`admissible`/`advance`/`closeOver` | `src/mind/derivation.ts` | One admission for every derivation step, the readings every tier asks, and the engine that walks the post-grounding layers. |
23
+ | `exactNode` | `src/mind/primitives.ts` | The exact content-addressed lookup (`resolve`, `canonResolve`): the identity fold (`contentIdentity`, geometry.ts) — a miss decided by the segment filter, a hit named bottom-up, no vectors. |
23
24
 
24
25
  ## Pins
25
26
 
@@ -56,6 +56,50 @@ drift without a type error. Levels are read from the hash the cut was accepted
56
56
  at — level `L` when `h` vanishes mod `W^(L+1)` — so level-`L` cuts nest inside
57
57
  level-`(L-1)` and expected span is `W^(L+1)` bytes.
58
58
 
59
+ ## One shape, two algebras
60
+
61
+ Which items group under which parent is decided by the cut levels, the keyring
62
+ and — inside an over-long row — each item's `itemKey` (eight raw gist
63
+ coordinates). `groupByLevel`/`foldSlice` are written ONCE over a fold algebra
64
+ (`join`, `key`) and run over two of them: the vector fold (`perceive`) and the
65
+ identity fold (`contentIdentity`), which names the node a stream folds to by
66
+ asking the store bottom-up and reads only the coordinates `itemKey` hashes,
67
+ lazily, with the same float32 additions in the same order. `exactNode` is the
68
+ identity fold, so resolving a span builds no D-dimensional gist and leaves
69
+ nothing in the perception memo (measured on the 31.7M-node store: one join query
70
+ went 185 s / 4.4 GB retained → 40 s / 81 MB, same answer). A grouping rule
71
+ written twice would be a write/read drift waiting to happen; written once, the
72
+ two folds cannot disagree about the tree.
73
+
74
+ ## Same tree is not enough — the read side names as the write side names
75
+
76
+ The store's `intern` names a branch by its children, and when they name none it
77
+ looks up the FLAT node over the same bytes and REUSES it (step 1b, "same bytes,
78
+ same node"). Every deposit interns flat nodes — its whole input and each
79
+ canonical window — so a later deposit's branch is often stored as an earlier
80
+ deposit's window (`ver` + `!` stored as the window `ver!`). The same tree is
81
+ then named by a node no child lookup can reach. `exactNode` and `foldTree` name
82
+ a branch exactly as `intern` does (`branchNaming`, `src/mind/primitives.ts`):
83
+ the children first, the flat node over the same bytes when they name nothing —
84
+ and an unnamed child does not settle it, since the write side minted that child
85
+ and still reached step 1b. Measured on the 31.7M-node store: 7 of 80 dialogue
86
+ turns asked verbatim had resolved to nothing and fell to the composition path
87
+ (26–41 s); they now resolve to their own context.
88
+
89
+ A name found only through the bytes is where the exact lookup used to MISS, and
90
+ a flat index entry is not a learnt structure, so `resolve` still asks the
91
+ canonical class there (`exactNaming`'s `byBytes`): it holds the learnt member
92
+ that leads somewhere, when there is one. The store holds such byte-only names
93
+ from an earlier deposit path (today's deposits always intern the structure
94
+ beside the flat copy), which is why `test/152` builds the state through the
95
+ store's write API.
96
+
97
+ One stored turn of the same set still does not resolve: its context was stored
98
+ with cuts at the ends of the conversation's EARLIER contexts (103 and 227 bytes
99
+ into a 257-byte context) — a boundary-imposed shape neither today's deposit path
100
+ nor the training-time one produces from these bytes, and that the read side
101
+ could reproduce only by guessing turn boundaries, which this contract forbids.
102
+
59
103
  ## Optional canonical capability
60
104
 
61
105
  `canonAdd`/`canonFind` (`src/store.ts` — `canonCount`/`eachContent`) is an
@@ -81,7 +125,13 @@ any change here.
81
125
  - `test/59` — shift invariance floors (content-defined cuts preserved over
82
126
  random binary and prose).
83
127
  - `test/63` — offset/W invariance and `contentLevels` distribution expectations.
128
+ - `test/148` — the identity fold names exactly what the vector fold names (every
129
+ sub-span of corpus and noise), and groups exactly as it does over long
130
+ low-entropy streams that force the `itemKey` split.
131
+ - `test/152` — a deposit stored through an earlier deposit's flat window
132
+ resolves to its own context, both folds name it, and it is answered on the
133
+ exact path.
84
134
 
85
135
  See:
86
- `src/geometry.ts:contentLevels`/`contentBoundaries`/`contentFoldIncremental`/`stablePrefixFold`;
136
+ `src/geometry.ts:contentLevels`/`contentBoundaries`/`contentFoldIncremental`/`stablePrefixFold`/`contentIdentity`;
87
137
  `AGENTS.md` §2 invariants.
@@ -67,6 +67,25 @@ Weight is one currency: `weight = moves + PASS · unaccountedBytes` where
67
67
  Cover runs first so a near-zero-cost computed span prunes the rest through the
68
68
  same mechanism — not a special case.
69
69
 
70
+ - **A cheaper bound is looked at first.** Before mechanism `m` first-touches
71
+ anything, every LATER mechanism whose floor grade is strictly below `m`'s runs
72
+ ahead of it (cheapest first); the lowest grade they reach is `bound`, and any
73
+ mechanism floored above `bound` is skipped (`meter.mechanismsBounded`). The
74
+ bound is learnt by calling `floor` with a `worthRunning` that refuses — the
75
+ investment discipline makes that free. The DECISION is the declared order's: a
76
+ run-ahead mechanism bounds the final grade whether or not the declared order
77
+ would have run it (if pruned, the incumbent already sat at or below its
78
+ floor); every candidate above `bound` loses to the winner, and every mechanism
79
+ floored at or below it meets the same run-or-prune decision, so `consider`
80
+ replays the same candidates in declared order. Equal floors are not skipped,
81
+ so an earlier mechanism keeps the tie it would win. Running ahead is never
82
+ extra work: only a mechanism floored at or below `p` can prune `p`, and each
83
+ such mechanism has already run or runs ahead of `p`. Measured on the
84
+ 31.7M-node store: a lowercased Persian turn (#83) went from 18.0 s to 1.2 s,
85
+ and #114 from 1.9 s to 0.7 s. In both, a grade-1 recall or prefix answer no
86
+ longer waits behind CAST's climb and weave. Of 42 composition-regime queries,
87
+ none changed its answer.
88
+
70
89
  - **Investment discipline.** `worthRunning` is passed _into_ `floor`. A floor
71
90
  that would first-touch an expensive shared analysis (`pre.attention()` climb,
72
91
  `pre.weave()`, `pre.resonance()`) checks `worthRunning(cheapestBound)` first
@@ -93,3 +112,5 @@ out so `PASS`-bridged bytes are still charged. `narrowDecision` and
93
112
 
94
113
  - `test/01-floor` — floor geometry.
95
114
  - `test/04-think` — decider, admissible pruning, investment discipline.
115
+ - `test/153` — run-ahead bounds: the composition market is skipped below CAST's
116
+ floor, and the decision equals a declared-order oracle.
@@ -47,9 +47,9 @@ conversation's persistent ones (content-keyed, cross-turn).
47
47
  | Memo | Key | Scope |
48
48
  | ------------------- | ----------------------------------------- | -------------------------------------------- |
49
49
  | `perceiveMemo` | `perceiveKey(bytes)` (latin1) | response / conversation |
50
- | `recogniseMemo` | `latin1Key(bytes)` | response / conversation |
51
- | `climbMemo` | `latin1Key(bytes)` | response / conversation |
52
- | `canonMemo` | `latin1Key(bytes)` | response (when `canon` set) |
50
+ | `recogniseMemo` | `latin1(bytes)` | response / conversation |
51
+ | `climbMemo` | `latin1(bytes)` | response / conversation |
52
+ | `canonMemo` | `latin1(bytes)` | response (when `canon` set) |
53
53
  | `_resolvedSubtrees` | `WeakMap<Sema, {id,len}>` (node identity) | response / conversation |
54
54
  | `_edgeChoice` | `Map<nodeId, pick>` | response only — **cleared** in `endResponse` |
55
55
  | `_gistCache` | `BoundedMap<nodeId, Vec>` 32 MB | **session-lifetime** (not per-response) |
@@ -3,7 +3,8 @@
3
3
  `src/meter.ts` is the one computational-usage accounting surface. It counts what
4
4
  inference _cost_ so a slow response can be attributed instead of guessed at. The
5
5
  rationale says why an answer was chosen; the meter says what it cost to choose
6
- it. Harness: `bench/profile-inference.mjs`.
6
+ it. Harness: the public path — `new Mind({ profile: true })`, then
7
+ `mind.lastCost` (`formatReport` / `sumReports`).
7
8
 
8
9
  ## Five contracts
9
10
 
@@ -48,6 +48,18 @@ full — identical to the unbounded climb. Work is `O(bound)` contexts times loc
48
48
  structure, never `O(N)`. Container seeding is streamed in `bound`-sized pages
49
49
  for the same reason.
50
50
 
51
+ Refuted tightening: **container fan-out as a hub** — deciding a containment seed
52
+ saturated when its first `containersSlice(bound+1)` page overflows, the reading
53
+ `junction.ts` applies to the same links. It conflates the PLACES a window occurs
54
+ with the CONTEXTS it reaches, and saturation is defined over contexts. Proved on
55
+ `test/49`'s fixture (N = 5, `sqrt(N)` = 3): `fran` sits in 4 containers yet its
56
+ full climb reaches 2 contexts — discriminative — and the rule called it
57
+ saturated, as it did `of f`, `fra`, `is`, `ranc`, `ance`. On the 31.7M-node
58
+ store no such window climbed unsaturated (18 composition queries; those climbs
59
+ were 38% of all visits), because at `sqrt(N)` = 1,560 a full page of containers
60
+ rarely converges on few contexts — but the rule is the same wrong reading at
61
+ both scales. The streamed seed stays.
62
+
51
63
  Trace records the first deciding stop as
52
64
  `SaturationStop { reason, node, observed, limit }` plus `visited`/`maxDepth`;
53
65
  absent when unsaturated or untraced.
@@ -27,7 +27,23 @@ a row. `has(id)` is `id < 0 || id < _nextId`.
27
27
  A branch whose kids are all leaves is **flat** — stored as raw bytes in `leaf`
28
28
  with an empty `kids` blob as marker (`flatKidsBytes`/`flatBytesKids`). Dedup
29
29
  probes hash then verify: `hashOf`→`h`→`LIMIT 1` fetch→byte compare (bloom
30
- negative filter first).
30
+ negative filter first). `flatBranchMayExist(bytes)` is the filter alone — its
31
+ `false` is exact, its `true` means "look it up" — for a caller that will verify
32
+ anyway: `exactNode` (primitives.ts) refuses a stream whose level-0 segment
33
+ cannot exist before naming any node, so a resolve miss costs hashing.
34
+ `findFlatBranch` memoizes HITS (`_flatKey`, keyed by the bytes themselves) and
35
+ never misses — the filter answers first, so a span that is not stored builds no
36
+ key, while the segments the identity fold names, asked by every span that
37
+ contains them, cost a map hit. `flatSpans(bytes)` returns a prober over ONE
38
+ buffer that answers exactly `findFlatBranch(bytes.subarray(s, e))`. `hashOf` is
39
+ FNV-1a, a left fold, so the prober extends the hash each start was last probed
40
+ at, and keeps one byte-short copy for the edge scan's trimmed retry. A span
41
+ scanner sweeping ends upward pays O(1) per probe instead of O(span).
42
+ Recognition's interior pass was hashing O(n·reach²) bytes: 251,660,406 for one
43
+ response on the 31.7M-node store (`test/153.4`).
44
+
45
+ `leadsSomewhere(id)` — `hasNext || hasHalo` — is the admission predicate's ONE
46
+ raw definition; `traverse.ts` memoises its edge tier per response.
31
47
 
32
48
  `bytes(id)`/`bytesPrefix(id, cap)` are shared with `BoundedMap` caches — callers
33
49
  must **never mutate** the returned buffer. `contentLen(id, cap)` walks with
@@ -43,7 +59,14 @@ window apart. Gists sit in `_pendingGist` (byte-budgeted `BoundedMap`);
43
59
  `batchSize` batches. Buffers flush on cadence, `commit()`, and close. Halo mass
44
60
  re-indexes geometrically (`mass<=4 || powerOfTwo`) and encodes 2-bit quantized.
45
61
  Canon index is optional: `canonAdd`/ `canonFind`/`canonCount` over 32-bit
46
- canonical hashes, caller verifies bytes.
62
+ canonical hashes, caller verifies bytes. The SQLite backend keeps a negative
63
+ filter over the canon hashes too (kept exact on `canonAdd`; the table is never
64
+ deleted from), because recognition and the join probe it once per span and
65
+ almost every answer is "no such key". It is PERSISTED (`canon_bloom`) in the
66
+ same transaction as the canon rows it covers, stamped with that commit's
67
+ `canon.upto`; an open whose meta disagrees with the stamp (rows written without
68
+ it) rebuilds it by one scan of the h column — seconds on a trained store, paid
69
+ once instead of per process (`test/36`).
47
70
 
48
71
  ## Containment, batching, LRU
49
72
 
@@ -12,6 +12,15 @@ discovering bugs:**
12
12
  leads to accidental bugs, and real-world corpus must not be compromised.
13
13
  - Something that happens due to deduplication, a tie-breaking rule, etc., isn't
14
14
  a bug—and that’s a subtle point.
15
+ - A change in behavior is not a behavioral regression: A change that shifts a
16
+ response from correct to incorrect is not necessarily a regression. Sometimes,
17
+ there may be many other responses that were incorrect but have become correct.
18
+ Overall, there must be a net gain. Budget adjustments or computational
19
+ optimizations often require this.
20
+ - Often, a pathological search is not necessarily resolved by a constant
21
+ derivative. A constant derivative is typically a type of short-circuit
22
+ breaker; it can cause truncation and is not necessarily a budget-related
23
+ measure. Therefore, it must be used wisely.
15
24
 
16
25
  ### 1. `score >= threshold` decides identity
17
26
 
@@ -174,8 +183,10 @@ discovering bugs:**
174
183
  the quantities the machine already has (`leadsSomewhere`, the
175
184
  exact-then-canonical identity, `accounted` bytes, the ladder, `hubBound`),
176
185
  from which the reach of a gap, the offer of a hop, the depth of a join and the
177
- scope of a substitution are CONSEQUENCES, not four separate decisions. Nothing
178
- in this repository is that today.
186
+ scope of a substitution are CONSEQUENCES, not four separate decisions. Where
187
+ the repository stands against it — the engine (`closeOver`), which of the four
188
+ follow from the law, and the one that does not, with the reason — is stated in
189
+ `docs/architecture/closure.md`, and nowhere else.
179
190
  - **THE STANDARD A CHANGE MUST MEET:** state which consequence it is, and show
180
191
  it following from the law. A change that cannot be stated that way is not
181
192
  ready.
@@ -13,22 +13,24 @@ 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
15
  (`test/20`). Every invariant is pinned, the closure law included
16
- (`test/133`–`147`). §14–25 (pipeline), §64 (derived thresholds), AGENTS.md §2
16
+ (`test/133`–`151`). §14–25 (pipeline), §64 (derived thresholds), AGENTS.md §2
17
17
  invariants 1–5.
18
18
 
19
19
  ## 2 — Work accounting (profiler)
20
20
 
21
- ```bash
22
- node bench/profile-inference.mjs # add [n] to limit probes
23
- node bench/profile-inference.mjs --trace # trace is a debugging aid, not product
21
+ ```js
22
+ const mind = new Mind({ profile: true }); // meter attached per response
23
+ await mind.respondText(q); // then read mind.lastCost
24
+ console.log(formatReport(mind.lastCost)); // sumReports() over several
24
25
  ```
25
26
 
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
- non-deterministic hints only. With `--trace`, recognition idempotence still
30
- holds (`test/42`). `src/meter.ts`, `docs/architecture/meter.md`, §55,
31
- `AGENTS.md` §6.
27
+ The public path is the harness (`AGENTS.md` §6); there is no separate bench
28
+ script. Guards without trace: counters exact and diffable between COLD runs;
29
+ phases nest (not disjoint — each phase is charged by its own layer); shared
30
+ analyses charged to themselves, not to the first toucher; millisecond fields are
31
+ non-deterministic hints only. With an `inspectRationale` callback attached,
32
+ recognition idempotence still holds (`test/42`). `src/meter.ts`,
33
+ `docs/architecture/meter.md`, §55, `AGENTS.md` §6.
32
34
 
33
35
  ## 3 — Dependency footprint
34
36
 
@@ -15,8 +15,15 @@ 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
- at `CONCEPT` (10), borrowing a synonym's continuation.
18
+ - Edge-less forms may hop via a halo sibling (`conceptHop` / `offerConcepts`) at
19
+ `CONCEPT` (10), borrowing a synonym's continuation.
20
+ - A span's cheapest completion DOMINATES the rest (`buildSearch`): a form or
21
+ completion of `[i, j)` whose cost has reached that of a completion of `[i, j)`
22
+ already yielded fires no rule (`searchDominated`). Coverage is positional, so
23
+ only the cheapest matters to the goal; the byte rules (fuse, splice, join)
24
+ fire from the completion the search would stand on, never from every
25
+ alternative it reached. It also makes the first hop's stop-here
26
+ (`STEP + CONCEPT`) a real horizon for the chain.
20
27
 
21
28
  ## Gate — `leadsSomewhere` (`src/mind/traverse.ts`)
22
29
 
@@ -36,11 +43,18 @@ and are filtered during recognition.
36
43
  The cover reports `moves` (its derivation's discrete work) and `accounted`; the
37
44
  ladder prices both.
38
45
 
39
- ## Pre-resolution (`src/mind/mechanisms/cover.ts`)
46
+ ## Licensed premises (`src/mind/mechanisms/cover.ts`, `Licence` in `graph-search.ts`)
40
47
 
41
- `resolveConcepts` and `resolveConnectors` pre-resolve the async maps the
42
- synchronous search cannot gather: concept targets and learnt connectors, keyed
43
- by node pair. Bridges (`bridge`) splice connectors between rewrites.
48
+ The synchronous search cannot run the async reads two of its rules need — a
49
+ concept target (a halo lookup) and a learnt connector between two answers (a
50
+ `bridge`). `offerConcepts` and `offerConnectors` OFFER the keys up front (cheap:
51
+ `hasNext`, the touching-site pairs and the N-ary allowances); the search ASKS
52
+ for an offered key only where it reaches it — a connector when its splice's two
53
+ premises meet, a concept target when the hop's asking form (held at the hop's
54
+ own cost) is popped. A cover that asked is provisional: `cover.run` grants the
55
+ asked keys and covers again, until a cover asks nothing — which is then the
56
+ cover every key resolved in advance would have made. The joins licensed by
57
+ ask-free rounds are kept across the re-covers.
44
58
 
45
59
  ## Provenance
46
60
 
@@ -54,3 +68,6 @@ independent evidence streams meet at one anchor — see
54
68
 
55
69
  - `test/09-edges.test.mjs` — edge following and hop semantics
56
70
  - `test/19-nd.test.mjs` — form rules and multi-hop chains
71
+ - `test/151` — connectors and concept hops resolved where the search reaches
72
+ them; a span's cheapest completion dominates (a hub's degree generates no
73
+ work)
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.9.0",
4
+ "version": "0.9.1",
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.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Sema: a non-parametric, instance-based reasoning system.",
5
5
  "repository": {
6
6
  "type": "git",
package/src/alu/README.md CHANGED
@@ -238,8 +238,16 @@ const sync = await prefetchResonance(resonance, spans);
238
238
  ```
239
239
 
240
240
  The synchronous op callbacks never await — they read from the pre-resolved
241
- snapshots. The public `Mind.compute(name, operands)` path pre-resolves every
242
- symbol span before the synchronous kernel runs, using the same discipline.
241
+ snapshots. A named operation applied to the query's operand stream resolves
242
+ opposites ON DEMAND (`withOppositesOnDemand`). The kernel runs against a
243
+ snapshot of the opposites resolved so far. When it asked for one of its symbol
244
+ operands that is not resolved yet, that one is resolved through the host and the
245
+ pure kernel runs again. The result is the eager prefetch's, but only the
246
+ polymorphic inverse reads opposites. Before this, every symbol operand of ANY
247
+ operation paid one host call, and on Sema each is a halo-index query (30–200 ms
248
+ of a plain dialogue turn's parse that computed nothing). The public
249
+ `Mind.compute(name, operands)` path pre-resolves every symbol span before the
250
+ synchronous kernel runs, using the same discipline.
243
251
 
244
252
  ### The mind loop
245
253
 
@@ -51,6 +51,7 @@ export {
51
51
  prefetchOpposites,
52
52
  prefetchRecognisedOps,
53
53
  prefetchResonance,
54
+ withOppositesOnDemand,
54
55
  } from "./resonance.js";
55
56
 
56
57
  export {
@@ -45,10 +45,9 @@ import type { Alu } from "./alu.js";
45
45
  import {
46
46
  type AluResonance,
47
47
  type ConceptAnchor,
48
- prefetchOpposites,
49
48
  prefetchResonance,
49
+ withOppositesOnDemand,
50
50
  } from "./resonance.js";
51
- import { NO_RESONANCE } from "./operation.js";
52
51
  import { int, real, symbol, symbolSpans, type Value } from "./value.js";
53
52
  import { nonSpaceRuns } from "./text.js";
54
53
  import { bytesEqual, latin1 } from "../../bytes.js";
@@ -573,10 +572,11 @@ export class QueryParser {
573
572
  const symbols = picked.flatMap((t, k) =>
574
573
  t.kind === "term" ? [args[k]] : []
575
574
  );
576
- const resonance = symbols.length > 0
577
- ? await prefetchOpposites(this.resonance, symbols)
578
- : NO_RESONANCE;
579
- const bytes = this.alu.applyBytes(name, args, resonance);
575
+ const bytes = await withOppositesOnDemand(
576
+ this.resonance,
577
+ symbols,
578
+ (resonance) => this.alu.applyBytes(name, args, resonance),
579
+ );
580
580
  if (bytes === null) return null;
581
581
  if (
582
582
  symbols.length === args.length && args.some((a) => bytesEqual(bytes, a))