@graphrefly/graphrefly 0.47.1 → 0.47.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/base/composition/index.cjs +24 -16
  2. package/dist/base/composition/index.cjs.map +1 -1
  3. package/dist/base/composition/index.js +6 -6
  4. package/dist/base/index.cjs +142 -86
  5. package/dist/base/index.cjs.map +1 -1
  6. package/dist/base/index.js +11 -11
  7. package/dist/base/io/index.cjs +114 -68
  8. package/dist/base/io/index.cjs.map +1 -1
  9. package/dist/base/io/index.js +5 -5
  10. package/dist/base/sources/browser/index.cjs +13 -9
  11. package/dist/base/sources/browser/index.cjs.map +1 -1
  12. package/dist/base/sources/browser/index.js +13 -9
  13. package/dist/base/sources/browser/index.js.map +1 -1
  14. package/dist/base/sources/event/index.cjs +1 -1
  15. package/dist/base/sources/event/index.cjs.map +1 -1
  16. package/dist/base/sources/event/index.js +1 -1
  17. package/dist/base/sources/index.cjs +21 -13
  18. package/dist/base/sources/index.cjs.map +1 -1
  19. package/dist/base/sources/index.js +3 -3
  20. package/dist/base/sources/node/index.cjs +43 -37
  21. package/dist/base/sources/node/index.cjs.map +1 -1
  22. package/dist/base/sources/node/index.js +43 -37
  23. package/dist/base/sources/node/index.js.map +1 -1
  24. package/dist/{chunk-VLAGJZSL.js → chunk-3O3NKZJW.js} +2 -2
  25. package/dist/{chunk-YJ4U2D2C.js → chunk-446I4EGD.js} +9 -7
  26. package/dist/chunk-446I4EGD.js.map +1 -0
  27. package/dist/{chunk-DKNHAICT.js → chunk-5GVURVIG.js} +14 -8
  28. package/dist/chunk-5GVURVIG.js.map +1 -0
  29. package/dist/{chunk-2OB3CEJS.js → chunk-6MRSX3YK.js} +2 -2
  30. package/dist/{chunk-EVYY4X5A.js → chunk-6ZLCPUXS.js} +2 -2
  31. package/dist/{chunk-U225SKB4.js → chunk-7AVQIGF6.js} +61 -10
  32. package/dist/chunk-7AVQIGF6.js.map +1 -0
  33. package/dist/{chunk-7EGRP2VX.js → chunk-7BULJTL6.js} +2 -2
  34. package/dist/{chunk-7EGRP2VX.js.map → chunk-7BULJTL6.js.map} +1 -1
  35. package/dist/{chunk-7ADWWI2T.js → chunk-DDTS7F5O.js} +6 -4
  36. package/dist/chunk-DDTS7F5O.js.map +1 -0
  37. package/dist/{chunk-OCUDSN63.js → chunk-EL5VHUGK.js} +79 -47
  38. package/dist/chunk-EL5VHUGK.js.map +1 -0
  39. package/dist/{chunk-4GYMCUDZ.js → chunk-EP4WVQLX.js} +5 -5
  40. package/dist/{chunk-SOOKUYVM.js → chunk-F7EKHR32.js} +13 -9
  41. package/dist/chunk-F7EKHR32.js.map +1 -0
  42. package/dist/{chunk-RGMTUZCL.js → chunk-FQSQONOU.js} +3 -3
  43. package/dist/{chunk-RAGGHLCV.js → chunk-GUNIRPEJ.js} +8 -6
  44. package/dist/{chunk-RAGGHLCV.js.map → chunk-GUNIRPEJ.js.map} +1 -1
  45. package/dist/{chunk-BU3SEFA5.js → chunk-IOJDYUA7.js} +2 -2
  46. package/dist/{chunk-Y52CS6YA.js → chunk-JA67ZQG2.js} +2 -2
  47. package/dist/{chunk-Y52CS6YA.js.map → chunk-JA67ZQG2.js.map} +1 -1
  48. package/dist/{chunk-DM4OMPWK.js → chunk-KNU73RZW.js} +2 -2
  49. package/dist/{chunk-K7PDZYQE.js → chunk-KRFGO5QH.js} +18 -14
  50. package/dist/{chunk-K7PDZYQE.js.map → chunk-KRFGO5QH.js.map} +1 -1
  51. package/dist/{chunk-Z4YXAUDN.js → chunk-KUFXLAEY.js} +11 -7
  52. package/dist/{chunk-Z4YXAUDN.js.map → chunk-KUFXLAEY.js.map} +1 -1
  53. package/dist/{chunk-YXCPV26R.js → chunk-MS3WPRJR.js} +37 -25
  54. package/dist/chunk-MS3WPRJR.js.map +1 -0
  55. package/dist/{chunk-CXANAIZU.js → chunk-N65E26UL.js} +3 -3
  56. package/dist/{chunk-O3MT7DYI.js → chunk-N6MNJNHB.js} +2 -2
  57. package/dist/{chunk-A7KV5UK4.js → chunk-OXD5LFQP.js} +2 -2
  58. package/dist/{chunk-V4Y3TM7U.js → chunk-PTWADEH3.js} +8 -6
  59. package/dist/chunk-PTWADEH3.js.map +1 -0
  60. package/dist/{chunk-IHTWQEDR.js → chunk-QFE5BQH7.js} +2 -2
  61. package/dist/{chunk-IHTWQEDR.js.map → chunk-QFE5BQH7.js.map} +1 -1
  62. package/dist/{chunk-J5WFUEO4.js → chunk-R6ZCSXKX.js} +3 -3
  63. package/dist/{chunk-PZWISPIQ.js → chunk-S7HN5FHL.js} +17 -11
  64. package/dist/chunk-S7HN5FHL.js.map +1 -0
  65. package/dist/{chunk-RJOG4IJU.js → chunk-T7SP3EYR.js} +18 -12
  66. package/dist/chunk-T7SP3EYR.js.map +1 -0
  67. package/dist/{chunk-4S53H2KR.js → chunk-VAZXUK6G.js} +2 -2
  68. package/dist/{chunk-IJRR6YAI.js → chunk-VLDRAMP7.js} +18 -12
  69. package/dist/chunk-VLDRAMP7.js.map +1 -0
  70. package/dist/{chunk-B4AKFXGE.js → chunk-VNXAF2KE.js} +3 -3
  71. package/dist/{chunk-MTTRCEJT.js → chunk-VP3TIUDF.js} +2 -2
  72. package/dist/{chunk-6XZYT4SW.js → chunk-WGDEBIP4.js} +5 -5
  73. package/dist/{chunk-E5OZPDIW.js → chunk-X7BA5PWG.js} +7 -5
  74. package/dist/chunk-X7BA5PWG.js.map +1 -0
  75. package/dist/compat/index.cjs +1 -1
  76. package/dist/compat/index.cjs.map +1 -1
  77. package/dist/compat/index.js +2 -2
  78. package/dist/compat/nestjs/index.cjs +1 -1
  79. package/dist/compat/nestjs/index.cjs.map +1 -1
  80. package/dist/compat/nestjs/index.js +2 -2
  81. package/dist/index.cjs +283 -142
  82. package/dist/index.cjs.map +1 -1
  83. package/dist/index.js +32 -32
  84. package/dist/presets/ai/index.cjs +42 -26
  85. package/dist/presets/ai/index.cjs.map +1 -1
  86. package/dist/presets/ai/index.js +10 -10
  87. package/dist/presets/harness/index.cjs +53 -33
  88. package/dist/presets/harness/index.cjs.map +1 -1
  89. package/dist/presets/harness/index.js +21 -21
  90. package/dist/presets/index.cjs +76 -48
  91. package/dist/presets/index.cjs.map +1 -1
  92. package/dist/presets/index.js +24 -24
  93. package/dist/presets/resilience/index.cjs +35 -23
  94. package/dist/presets/resilience/index.cjs.map +1 -1
  95. package/dist/presets/resilience/index.js +5 -5
  96. package/dist/solutions/index.cjs +71 -45
  97. package/dist/solutions/index.cjs.map +1 -1
  98. package/dist/solutions/index.js +21 -21
  99. package/dist/{timeout-U5O4ESK3.js → timeout-BEABACRP.js} +2 -2
  100. package/dist/utils/ai/browser.cjs.map +1 -1
  101. package/dist/utils/ai/browser.js +9 -9
  102. package/dist/utils/ai/index.cjs +41 -25
  103. package/dist/utils/ai/index.cjs.map +1 -1
  104. package/dist/utils/ai/index.js +17 -17
  105. package/dist/utils/ai/node.js +3 -3
  106. package/dist/utils/domain-templates/index.cjs +1 -1
  107. package/dist/utils/domain-templates/index.cjs.map +1 -1
  108. package/dist/utils/domain-templates/index.js +2 -2
  109. package/dist/utils/graphspec/index.cjs +1 -1
  110. package/dist/utils/graphspec/index.cjs.map +1 -1
  111. package/dist/utils/graphspec/index.js +2 -2
  112. package/dist/utils/harness/index.cjs +16 -10
  113. package/dist/utils/harness/index.cjs.map +1 -1
  114. package/dist/utils/harness/index.js +1 -1
  115. package/dist/utils/index.cjs +138 -55
  116. package/dist/utils/index.cjs.map +1 -1
  117. package/dist/utils/index.js +21 -21
  118. package/dist/utils/memory/index.cjs +51 -0
  119. package/dist/utils/memory/index.cjs.map +1 -1
  120. package/dist/utils/memory/index.d.cts +58 -9
  121. package/dist/utils/memory/index.d.ts +58 -9
  122. package/dist/utils/memory/index.js +1 -1
  123. package/dist/utils/orchestration/index.cjs +5 -3
  124. package/dist/utils/orchestration/index.cjs.map +1 -1
  125. package/dist/utils/orchestration/index.js +1 -1
  126. package/dist/utils/process/index.js +2 -2
  127. package/dist/utils/reduction/index.cjs +1 -1
  128. package/dist/utils/reduction/index.cjs.map +1 -1
  129. package/dist/utils/reduction/index.js +1 -1
  130. package/dist/utils/resilience/index.cjs +35 -23
  131. package/dist/utils/resilience/index.cjs.map +1 -1
  132. package/dist/utils/resilience/index.js +4 -4
  133. package/dist/utils/surface/index.cjs +1 -1
  134. package/dist/utils/surface/index.cjs.map +1 -1
  135. package/dist/utils/surface/index.js +3 -3
  136. package/package.json +1 -1
  137. package/dist/chunk-7ADWWI2T.js.map +0 -1
  138. package/dist/chunk-DKNHAICT.js.map +0 -1
  139. package/dist/chunk-E5OZPDIW.js.map +0 -1
  140. package/dist/chunk-IJRR6YAI.js.map +0 -1
  141. package/dist/chunk-OCUDSN63.js.map +0 -1
  142. package/dist/chunk-PZWISPIQ.js.map +0 -1
  143. package/dist/chunk-RJOG4IJU.js.map +0 -1
  144. package/dist/chunk-SOOKUYVM.js.map +0 -1
  145. package/dist/chunk-U225SKB4.js.map +0 -1
  146. package/dist/chunk-V4Y3TM7U.js.map +0 -1
  147. package/dist/chunk-YJ4U2D2C.js.map +0 -1
  148. package/dist/chunk-YXCPV26R.js.map +0 -1
  149. /package/dist/{chunk-VLAGJZSL.js.map → chunk-3O3NKZJW.js.map} +0 -0
  150. /package/dist/{chunk-2OB3CEJS.js.map → chunk-6MRSX3YK.js.map} +0 -0
  151. /package/dist/{chunk-EVYY4X5A.js.map → chunk-6ZLCPUXS.js.map} +0 -0
  152. /package/dist/{chunk-4GYMCUDZ.js.map → chunk-EP4WVQLX.js.map} +0 -0
  153. /package/dist/{chunk-RGMTUZCL.js.map → chunk-FQSQONOU.js.map} +0 -0
  154. /package/dist/{chunk-BU3SEFA5.js.map → chunk-IOJDYUA7.js.map} +0 -0
  155. /package/dist/{chunk-DM4OMPWK.js.map → chunk-KNU73RZW.js.map} +0 -0
  156. /package/dist/{chunk-CXANAIZU.js.map → chunk-N65E26UL.js.map} +0 -0
  157. /package/dist/{chunk-O3MT7DYI.js.map → chunk-N6MNJNHB.js.map} +0 -0
  158. /package/dist/{chunk-A7KV5UK4.js.map → chunk-OXD5LFQP.js.map} +0 -0
  159. /package/dist/{chunk-J5WFUEO4.js.map → chunk-R6ZCSXKX.js.map} +0 -0
  160. /package/dist/{chunk-4S53H2KR.js.map → chunk-VAZXUK6G.js.map} +0 -0
  161. /package/dist/{chunk-B4AKFXGE.js.map → chunk-VNXAF2KE.js.map} +0 -0
  162. /package/dist/{chunk-MTTRCEJT.js.map → chunk-VP3TIUDF.js.map} +0 -0
  163. /package/dist/{chunk-6XZYT4SW.js.map → chunk-WGDEBIP4.js.map} +0 -0
  164. /package/dist/{timeout-U5O4ESK3.js.map → timeout-BEABACRP.js.map} +0 -0
@@ -170,7 +170,7 @@ interface ReviewRequest {
170
170
  readonly threshold: number;
171
171
  }
172
172
  interface FactStoreAuditRecord extends BaseAuditRecord {
173
- readonly action: "ingest" | "invalidate" | "outcome" | "consolidate" | "overflow";
173
+ readonly action: "ingest" | "invalidate" | "outcome" | "consolidate" | "decay" | "overflow";
174
174
  readonly id?: FactId;
175
175
  readonly reason?: CascadeReason;
176
176
  }
@@ -181,11 +181,59 @@ interface ReactiveFactStoreConfig<T> {
181
181
  /** Shard count for the default hash-mod sharder. Default 4 (§3.2). */
182
182
  readonly shardCount?: number;
183
183
  readonly scoring?: Node<ScoringPolicy<T>>;
184
+ /**
185
+ * Forgetting-curve policy `(confidence, ageNs) => confidence'` (MEME L1
186
+ * time-drift / Hassabis forgetting curve, DS-14.7 PART 4.1 face ②). `ageNs`
187
+ * is the fact's monotonic age (`monotonicNs() - t_ns`, a `bigint`
188
+ * nanosecond duration — `Number()` it for float math; precision degrades
189
+ * for ages beyond `Number.MAX_SAFE_INTEGER` ns ≈ 104 days of process
190
+ * uptime). Reactive: the policy itself can evolve (e.g.
191
+ * `derived([outcome], …)` for continual learning — spec §1.4
192
+ * push-on-update).
193
+ *
194
+ * **Activation contract.** The decay processor exists only when
195
+ * {@link decayTrigger} is *configured*. Once it is, **both** a
196
+ * `decayTrigger` tick **and** a `decay` policy emit drive a full pass
197
+ * (push-on-update — the `outcomeProcessor`+`scoring` precedent). A policy
198
+ * Node's *initial* value therefore runs a pass on first resolution: if you
199
+ * build `decay` via `derived(...)`, expect a store-wide pass when it first
200
+ * settles. With no `decayTrigger` configured the face is fully inert
201
+ * (mirrors {@link consolidate}/{@link consolidateTrigger}).
202
+ *
203
+ * Each pass applies the current policy to every *live* fact (`validTo`
204
+ * unset), clamps to `[0, 1]`, and writes back only facts whose confidence
205
+ * actually changed (a fact obsoleted earlier in the same tick is never
206
+ * resurrected). A drop below {@link reviewThreshold} surfaces via the
207
+ * `review` topic; decay never sets `validTo`, so it cannot itself drive the
208
+ * cascade.
209
+ *
210
+ * **Quiescence is the policy's responsibility.** The only no-op guard is
211
+ * exact-equality (`next === confidence`). A policy with no reachable
212
+ * fixpoint (e.g. plain geometric `c => c * 0.5`) therefore re-decays and
213
+ * re-emits **every** live fact on **every** tick forever (silent CPU/GC +
214
+ * audit-log churn — never an error). Bound it in the policy: clamp to a
215
+ * floor and return `confidence` unchanged once at/below it (so the
216
+ * exact-equality guard quiesces the store). The {@link decayExponential}
217
+ * recipe is the ergonomic alternative that owns its own `fromTimer` +
218
+ * `floor`/`epsilon` and writes through the `ingest` face (no
219
+ * `decay`/`decayTrigger` wiring). Use this face when you want the store to
220
+ * own decay as a reactive, swappable policy and you are providing the floor.
221
+ */
184
222
  readonly decay?: Node<DecayPolicy>;
185
223
  readonly admissionFilter?: Node<AdmissionFilter<T>>;
186
224
  readonly ingest: Node<MemoryFragment<T>>;
187
225
  readonly outcome?: Node<OutcomeSignal>;
188
226
  readonly query?: Node<MemoryQuery>;
227
+ /**
228
+ * Decay trigger — a reactive timer/cron Node (e.g. `fromTimer(...)` /
229
+ * `fromCron(...)`). Configuring it creates the decay processor; each tick
230
+ * then re-applies the current {@link decay} policy to every live fact (a
231
+ * `decay` policy emit also drives a pass — see {@link decay}'s "Activation
232
+ * contract"). A tick before any `decay` policy has emitted is a no-op.
233
+ * Without this field the `decay` face is fully inert (mirrors
234
+ * {@link consolidateTrigger}/{@link consolidate}).
235
+ */
236
+ readonly decayTrigger?: Node<unknown>;
189
237
  /**
190
238
  * Consolidator trigger — a reactive timer/cron Node (e.g. `fromCron(...)`).
191
239
  * When supplied, the `consolidated` node maps each tick to summarized
@@ -620,14 +668,15 @@ declare function consolidationRem<T>(opts: ConsolidationRemOptions<T>): Consolid
620
668
  * re-ingest write commits **synchronously this tick** (graphrefly push is
621
669
  * synchronous) and the next tick decays from there.
622
670
  *
623
- * > **Why a recipe, not the `decay` face.** `ReactiveFactStoreConfig.decay:
624
- * > Node<DecayPolicy>` is a *locked design face* (DS-14.7 PART 4.1) but the
625
- * > shipped `reactiveFactStore()` v1 factory does **not** consume it (tracked
626
- * > as a factory-gap item in `docs/optimizations.md`). This recipe delivers the
627
- * > §5.8 "`decay` recipe uses `fromTimer` for periodic confidence drift"
628
- * > behavior over the **wired** `ingest` face instead fully spec-compliant
629
- * > and zero-core-change. It composes regardless of whether the `decay` face is
630
- * > later wired.
671
+ * > **Recipe vs the `decay` face.** `ReactiveFactStoreConfig.decay:
672
+ * > Node<DecayPolicy>` (DS-14.7 PART 4.1 face ②) **is wired** in the factory —
673
+ * > pair it with `decayTrigger` and the store owns decay as a reactive,
674
+ * > swappable policy. This recipe is the **ergonomic alternative**: it owns its
675
+ * > own `fromTimer` and writes through the already-wired `ingest` face, so the
676
+ * > caller wires no `decay`/`decayTrigger` and the recipe composes whether or
677
+ * > not the face is also used. Both deliver the §5.8 "`fromTimer` for periodic
678
+ * > confidence drift" behavior; pick the face for a caller-controlled policy
679
+ * > Node, this recipe for a self-contained drop-in forgetting curve.
631
680
  *
632
681
  * **Convergence (conditional — read this).** Per-id decay is computed against
633
682
  * the elapsed time since this fact was last decayed (recipe-owned closure
@@ -170,7 +170,7 @@ interface ReviewRequest {
170
170
  readonly threshold: number;
171
171
  }
172
172
  interface FactStoreAuditRecord extends BaseAuditRecord {
173
- readonly action: "ingest" | "invalidate" | "outcome" | "consolidate" | "overflow";
173
+ readonly action: "ingest" | "invalidate" | "outcome" | "consolidate" | "decay" | "overflow";
174
174
  readonly id?: FactId;
175
175
  readonly reason?: CascadeReason;
176
176
  }
@@ -181,11 +181,59 @@ interface ReactiveFactStoreConfig<T> {
181
181
  /** Shard count for the default hash-mod sharder. Default 4 (§3.2). */
182
182
  readonly shardCount?: number;
183
183
  readonly scoring?: Node<ScoringPolicy<T>>;
184
+ /**
185
+ * Forgetting-curve policy `(confidence, ageNs) => confidence'` (MEME L1
186
+ * time-drift / Hassabis forgetting curve, DS-14.7 PART 4.1 face ②). `ageNs`
187
+ * is the fact's monotonic age (`monotonicNs() - t_ns`, a `bigint`
188
+ * nanosecond duration — `Number()` it for float math; precision degrades
189
+ * for ages beyond `Number.MAX_SAFE_INTEGER` ns ≈ 104 days of process
190
+ * uptime). Reactive: the policy itself can evolve (e.g.
191
+ * `derived([outcome], …)` for continual learning — spec §1.4
192
+ * push-on-update).
193
+ *
194
+ * **Activation contract.** The decay processor exists only when
195
+ * {@link decayTrigger} is *configured*. Once it is, **both** a
196
+ * `decayTrigger` tick **and** a `decay` policy emit drive a full pass
197
+ * (push-on-update — the `outcomeProcessor`+`scoring` precedent). A policy
198
+ * Node's *initial* value therefore runs a pass on first resolution: if you
199
+ * build `decay` via `derived(...)`, expect a store-wide pass when it first
200
+ * settles. With no `decayTrigger` configured the face is fully inert
201
+ * (mirrors {@link consolidate}/{@link consolidateTrigger}).
202
+ *
203
+ * Each pass applies the current policy to every *live* fact (`validTo`
204
+ * unset), clamps to `[0, 1]`, and writes back only facts whose confidence
205
+ * actually changed (a fact obsoleted earlier in the same tick is never
206
+ * resurrected). A drop below {@link reviewThreshold} surfaces via the
207
+ * `review` topic; decay never sets `validTo`, so it cannot itself drive the
208
+ * cascade.
209
+ *
210
+ * **Quiescence is the policy's responsibility.** The only no-op guard is
211
+ * exact-equality (`next === confidence`). A policy with no reachable
212
+ * fixpoint (e.g. plain geometric `c => c * 0.5`) therefore re-decays and
213
+ * re-emits **every** live fact on **every** tick forever (silent CPU/GC +
214
+ * audit-log churn — never an error). Bound it in the policy: clamp to a
215
+ * floor and return `confidence` unchanged once at/below it (so the
216
+ * exact-equality guard quiesces the store). The {@link decayExponential}
217
+ * recipe is the ergonomic alternative that owns its own `fromTimer` +
218
+ * `floor`/`epsilon` and writes through the `ingest` face (no
219
+ * `decay`/`decayTrigger` wiring). Use this face when you want the store to
220
+ * own decay as a reactive, swappable policy and you are providing the floor.
221
+ */
184
222
  readonly decay?: Node<DecayPolicy>;
185
223
  readonly admissionFilter?: Node<AdmissionFilter<T>>;
186
224
  readonly ingest: Node<MemoryFragment<T>>;
187
225
  readonly outcome?: Node<OutcomeSignal>;
188
226
  readonly query?: Node<MemoryQuery>;
227
+ /**
228
+ * Decay trigger — a reactive timer/cron Node (e.g. `fromTimer(...)` /
229
+ * `fromCron(...)`). Configuring it creates the decay processor; each tick
230
+ * then re-applies the current {@link decay} policy to every live fact (a
231
+ * `decay` policy emit also drives a pass — see {@link decay}'s "Activation
232
+ * contract"). A tick before any `decay` policy has emitted is a no-op.
233
+ * Without this field the `decay` face is fully inert (mirrors
234
+ * {@link consolidateTrigger}/{@link consolidate}).
235
+ */
236
+ readonly decayTrigger?: Node<unknown>;
189
237
  /**
190
238
  * Consolidator trigger — a reactive timer/cron Node (e.g. `fromCron(...)`).
191
239
  * When supplied, the `consolidated` node maps each tick to summarized
@@ -620,14 +668,15 @@ declare function consolidationRem<T>(opts: ConsolidationRemOptions<T>): Consolid
620
668
  * re-ingest write commits **synchronously this tick** (graphrefly push is
621
669
  * synchronous) and the next tick decays from there.
622
670
  *
623
- * > **Why a recipe, not the `decay` face.** `ReactiveFactStoreConfig.decay:
624
- * > Node<DecayPolicy>` is a *locked design face* (DS-14.7 PART 4.1) but the
625
- * > shipped `reactiveFactStore()` v1 factory does **not** consume it (tracked
626
- * > as a factory-gap item in `docs/optimizations.md`). This recipe delivers the
627
- * > §5.8 "`decay` recipe uses `fromTimer` for periodic confidence drift"
628
- * > behavior over the **wired** `ingest` face instead fully spec-compliant
629
- * > and zero-core-change. It composes regardless of whether the `decay` face is
630
- * > later wired.
671
+ * > **Recipe vs the `decay` face.** `ReactiveFactStoreConfig.decay:
672
+ * > Node<DecayPolicy>` (DS-14.7 PART 4.1 face ②) **is wired** in the factory —
673
+ * > pair it with `decayTrigger` and the store owns decay as a reactive,
674
+ * > swappable policy. This recipe is the **ergonomic alternative**: it owns its
675
+ * > own `fromTimer` and writes through the already-wired `ingest` face, so the
676
+ * > caller wires no `decay`/`decayTrigger` and the recipe composes whether or
677
+ * > not the face is also used. Both deliver the §5.8 "`fromTimer` for periodic
678
+ * > confidence drift" behavior; pick the face for a caller-controlled policy
679
+ * > Node, this recipe for a self-contained drop-in forgetting curve.
631
680
  *
632
681
  * **Convergence (conditional — read this).** Per-id decay is computed against
633
682
  * the elapsed time since this fact was last decayed (recipe-owned closure
@@ -13,7 +13,7 @@ import {
13
13
  scoringByOutcome,
14
14
  shardByTenant,
15
15
  vectorIndex
16
- } from "../../chunk-U225SKB4.js";
16
+ } from "../../chunk-7AVQIGF6.js";
17
17
  import "../../chunk-QMBYUVRL.js";
18
18
  import "../../chunk-FMPF42Q4.js";
19
19
  import "../../chunk-BXGZFGZ4.js";
@@ -379,9 +379,11 @@ function humanInput(opts) {
379
379
  });
380
380
  }
381
381
  });
382
- return () => {
383
- promptUnsub();
384
- respUnsub?.();
382
+ return {
383
+ onDeactivation: () => {
384
+ promptUnsub();
385
+ respUnsub?.();
386
+ }
385
387
  };
386
388
  },
387
389
  {