@remnic/core 9.3.628 → 9.3.630

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 (231) hide show
  1. package/dist/access-cli.js +18 -18
  2. package/dist/access-http.d.ts +6 -4
  3. package/dist/access-http.js +7 -6
  4. package/dist/access-mcp.d.ts +6 -4
  5. package/dist/access-mcp.js +6 -5
  6. package/dist/{access-service-C_sfOHsX.d.ts → access-service-C4v-eFjB.d.ts} +2 -2
  7. package/dist/access-service.d.ts +6 -4
  8. package/dist/access-service.js +5 -4
  9. package/dist/action-confidence.d.ts +1 -1
  10. package/dist/active-memory-bridge.d.ts +1 -1
  11. package/dist/active-recall.d.ts +1 -1
  12. package/dist/active-recall.js +1 -1
  13. package/dist/behavior-learner.d.ts +1 -1
  14. package/dist/behavior-signals.d.ts +1 -1
  15. package/dist/bootstrap.d.ts +6 -4
  16. package/dist/briefing.d.ts +33 -2
  17. package/dist/briefing.js +5 -2
  18. package/dist/buffer-surprise-report.d.ts +1 -1
  19. package/dist/buffer.d.ts +1 -1
  20. package/dist/calibration.d.ts +1 -1
  21. package/dist/calibration.js +2 -2
  22. package/dist/causal-behavior.d.ts +1 -1
  23. package/dist/causal-consolidation.d.ts +1 -1
  24. package/dist/causal-consolidation.js +5 -5
  25. package/dist/{chunk-GE7Q7KXP.js → chunk-2VJ7AJFX.js} +2 -2
  26. package/dist/{chunk-KVFYTRMV.js → chunk-4QEUKASL.js} +2 -2
  27. package/dist/{chunk-KB4MFBF5.js → chunk-5S6IREG3.js} +3 -3
  28. package/dist/{chunk-LQYTQCXM.js → chunk-6LBQL5US.js} +2 -2
  29. package/dist/{chunk-KGIGRNR6.js → chunk-723OMPUI.js} +4 -4
  30. package/dist/{chunk-TZDSNIRO.js → chunk-ADOD7PJC.js} +5 -5
  31. package/dist/{chunk-SHV5Y2WU.js → chunk-BL33LBTN.js} +3 -3
  32. package/dist/{chunk-532VCWYW.js → chunk-BWK5EEKS.js} +2 -2
  33. package/dist/{chunk-KKTXCFD7.js → chunk-EORL2IDM.js} +39 -8
  34. package/dist/{chunk-KKTXCFD7.js.map → chunk-EORL2IDM.js.map} +1 -1
  35. package/dist/{chunk-F3FY3D3S.js → chunk-F6USGHMO.js} +10 -5
  36. package/dist/chunk-F6USGHMO.js.map +1 -0
  37. package/dist/{chunk-STDAAGH7.js → chunk-GXWFZYSR.js} +39 -3
  38. package/dist/chunk-GXWFZYSR.js.map +1 -0
  39. package/dist/{chunk-3VONWEQB.js → chunk-HZVIYZYN.js} +2 -2
  40. package/dist/{chunk-Y3TMFC6I.js → chunk-K3BTOW7N.js} +3 -3
  41. package/dist/{chunk-Z3CCEP6F.js → chunk-K47C6M2C.js} +5 -5
  42. package/dist/{chunk-N5RGXWLQ.js → chunk-MQ24KOOR.js} +2 -2
  43. package/dist/{chunk-3MNBW7R7.js → chunk-NRQJBK36.js} +2 -2
  44. package/dist/{chunk-MON3LMO7.js → chunk-NRST7W5Q.js} +5 -5
  45. package/dist/{chunk-3R2UZV3U.js → chunk-OOFBE62K.js} +2 -2
  46. package/dist/{chunk-MVQN73GT.js → chunk-OQMR2SDZ.js} +2 -2
  47. package/dist/{chunk-UGHUNQ74.js → chunk-RSKUUEBA.js} +73 -1
  48. package/dist/chunk-RSKUUEBA.js.map +1 -0
  49. package/dist/{chunk-QDV6VAD4.js → chunk-S5W37FPX.js} +2 -2
  50. package/dist/{chunk-57QXN2CS.js → chunk-SACS6KE6.js} +2 -2
  51. package/dist/{chunk-UELS6WWF.js → chunk-UE57H4MA.js} +2 -2
  52. package/dist/{chunk-2RHI3FGV.js → chunk-VUTPRX7K.js} +20 -14
  53. package/dist/{chunk-2RHI3FGV.js.map → chunk-VUTPRX7K.js.map} +1 -1
  54. package/dist/{chunk-AZ4RI3QD.js → chunk-YJOWWRRS.js} +450 -48
  55. package/dist/chunk-YJOWWRRS.js.map +1 -0
  56. package/dist/{chunk-P2D2MM47.js → chunk-ZZSXUZF3.js} +2 -2
  57. package/dist/{cli-EZv6YE6_.d.ts → cli-B_6EMiQc.d.ts} +3 -3
  58. package/dist/cli.d.ts +7 -5
  59. package/dist/cli.js +18 -17
  60. package/dist/compounding/engine.d.ts +1 -1
  61. package/dist/compounding/engine.js +2 -2
  62. package/dist/compounding/preference-consolidator.d.ts +1 -1
  63. package/dist/compression-optimizer.d.ts +1 -1
  64. package/dist/config.d.ts +1 -1
  65. package/dist/config.js +1 -1
  66. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  67. package/dist/connectors/codex-materialize-runner.js +2 -2
  68. package/dist/connectors/codex-materialize.d.ts +1 -1
  69. package/dist/connectors/index.d.ts +1 -1
  70. package/dist/connectors/index.js +2 -2
  71. package/dist/consolidation-provenance-check.d.ts +1 -1
  72. package/dist/consolidation-undo.d.ts +1 -1
  73. package/dist/contradiction/index.d.ts +1 -1
  74. package/dist/conversation-index/backend.d.ts +1 -1
  75. package/dist/conversation-index/chunker.d.ts +1 -1
  76. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  77. package/dist/conversation-index/indexer.d.ts +1 -1
  78. package/dist/conversation-index/search.d.ts +1 -1
  79. package/dist/day-summary.d.ts +1 -1
  80. package/dist/delinearize.d.ts +1 -1
  81. package/dist/direct-answer-wiring.d.ts +1 -1
  82. package/dist/direct-answer.d.ts +1 -1
  83. package/dist/embedding-fallback.d.ts +1 -1
  84. package/dist/enrichment/index.d.ts +1 -1
  85. package/dist/entity-retrieval.d.ts +1 -1
  86. package/dist/entity-retrieval.js +2 -2
  87. package/dist/entity-schema.d.ts +1 -1
  88. package/dist/explicit-capture.d.ts +6 -4
  89. package/dist/extraction-judge-telemetry.d.ts +1 -1
  90. package/dist/extraction-judge-training.d.ts +1 -1
  91. package/dist/extraction-judge.d.ts +1 -1
  92. package/dist/extraction-judge.js +3 -3
  93. package/dist/extraction.d.ts +1 -1
  94. package/dist/extraction.js +3 -3
  95. package/dist/fallback-llm.d.ts +1 -1
  96. package/dist/fallback-llm.js +2 -2
  97. package/dist/identity-continuity.d.ts +1 -1
  98. package/dist/importance.d.ts +1 -1
  99. package/dist/index.d.ts +9 -9
  100. package/dist/index.js +29 -27
  101. package/dist/index.js.map +1 -1
  102. package/dist/intent.d.ts +1 -1
  103. package/dist/lcm/engine.d.ts +1 -1
  104. package/dist/lcm/index.d.ts +1 -1
  105. package/dist/lcm/tools.d.ts +1 -1
  106. package/dist/lifecycle.d.ts +1 -1
  107. package/dist/live-connectors-runner.d.ts +1 -1
  108. package/dist/local-llm.d.ts +1 -1
  109. package/dist/maintenance/memory-governance.d.ts +1 -1
  110. package/dist/maintenance/memory-governance.js +2 -2
  111. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +2 -2
  112. package/dist/maintenance/rebuild-memory-projection.js +3 -3
  113. package/dist/mcp-memory-inspector-app.d.ts +6 -4
  114. package/dist/memory-action-policy.d.ts +1 -1
  115. package/dist/memory-cache.d.ts +1 -1
  116. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  117. package/dist/memory-projection-store.d.ts +1 -1
  118. package/dist/memory-provenance.d.ts +1 -1
  119. package/dist/memory-worth-outcomes.d.ts +1 -1
  120. package/dist/models-json.d.ts +1 -1
  121. package/dist/namespaces/migrate.d.ts +1 -1
  122. package/dist/namespaces/migrate.js +3 -3
  123. package/dist/namespaces/principal.d.ts +1 -1
  124. package/dist/namespaces/search.d.ts +1 -1
  125. package/dist/namespaces/storage.d.ts +1 -1
  126. package/dist/namespaces/storage.js +2 -2
  127. package/dist/native-knowledge.d.ts +1 -1
  128. package/dist/operator-toolkit.d.ts +1 -1
  129. package/dist/operator-toolkit.js +6 -6
  130. package/dist/{orchestrator-CEycaY3M.d.ts → orchestrator-Dlw3ae4B.d.ts} +111 -10
  131. package/dist/orchestrator.d.ts +5 -3
  132. package/dist/orchestrator.js +15 -14
  133. package/dist/patterns-cli.d.ts +1 -1
  134. package/dist/policy-runtime.d.ts +1 -1
  135. package/dist/qmd-recall-cache.d.ts +1 -1
  136. package/dist/qmd.d.ts +1 -1
  137. package/dist/recall-disclosure-escalation.d.ts +1 -1
  138. package/dist/recall-explain-renderer.d.ts +1 -1
  139. package/dist/recall-planner-llm.d.ts +1 -1
  140. package/dist/recall-planner-llm.js +2 -2
  141. package/dist/recall-state.d.ts +1 -1
  142. package/dist/recall-tag-filter.d.ts +1 -1
  143. package/dist/recall-xray-cli.d.ts +1 -1
  144. package/dist/recall-xray-renderer.d.ts +1 -1
  145. package/dist/recall-xray.d.ts +1 -1
  146. package/dist/resolve-auth-token.d.ts +1 -1
  147. package/dist/resume-bundles.js +2 -2
  148. package/dist/retrieval-agents.d.ts +1 -1
  149. package/dist/retrieval-tiers.d.ts +1 -1
  150. package/dist/routing/engine.d.ts +1 -1
  151. package/dist/routing/store.d.ts +1 -1
  152. package/dist/schemas.d.ts +24 -24
  153. package/dist/search/embed-helper.d.ts +1 -1
  154. package/dist/search/factory.d.ts +1 -1
  155. package/dist/search/index.d.ts +1 -1
  156. package/dist/search/lancedb-backend.d.ts +1 -1
  157. package/dist/search/meilisearch-backend.d.ts +1 -1
  158. package/dist/search/noop-backend.d.ts +1 -1
  159. package/dist/search/orama-backend.d.ts +1 -1
  160. package/dist/search/port.d.ts +1 -1
  161. package/dist/search/remote-backend.d.ts +1 -1
  162. package/dist/{semantic-consolidation-FbhPeJjB.d.ts → semantic-consolidation-C4sefXEI.d.ts} +1 -1
  163. package/dist/semantic-consolidation.d.ts +2 -2
  164. package/dist/semantic-consolidation.js +3 -3
  165. package/dist/semantic-rule-promotion.js +2 -2
  166. package/dist/semantic-rule-verifier.d.ts +1 -1
  167. package/dist/semantic-rule-verifier.js +2 -2
  168. package/dist/session-observer-bands.d.ts +1 -1
  169. package/dist/session-observer-state.d.ts +1 -1
  170. package/dist/shared-context/manager.d.ts +1 -1
  171. package/dist/signal.d.ts +1 -1
  172. package/dist/storage.d.ts +38 -2
  173. package/dist/storage.js +5 -3
  174. package/dist/summarizer.d.ts +1 -1
  175. package/dist/summarizer.js +3 -3
  176. package/dist/summary-snapshot.d.ts +1 -1
  177. package/dist/temporal-supersession.d.ts +1 -1
  178. package/dist/temporal-validity.d.ts +1 -1
  179. package/dist/threading.d.ts +1 -1
  180. package/dist/tier-migration.d.ts +1 -1
  181. package/dist/tier-routing.d.ts +1 -1
  182. package/dist/topics.d.ts +1 -1
  183. package/dist/transcript.d.ts +1 -1
  184. package/dist/transfer/types.d.ts +12 -12
  185. package/dist/{types-D5VRAI04.d.ts → types-2vqxmO0j.d.ts} +39 -10
  186. package/dist/types.d.ts +1 -1
  187. package/dist/utility-runtime.d.ts +1 -1
  188. package/dist/verified-recall.js +2 -2
  189. package/package.json +1 -1
  190. package/src/access-service.ts +7 -0
  191. package/src/briefing.ts +67 -1
  192. package/src/index.ts +2 -0
  193. package/src/orchestrator.ts +42 -0
  194. package/src/storage.ts +100 -0
  195. package/src/wearables/cli.ts +6 -0
  196. package/src/wearables/config.test.ts +33 -4
  197. package/src/wearables/config.ts +39 -7
  198. package/src/wearables/memory-gen.test.ts +416 -1
  199. package/src/wearables/memory-gen.ts +381 -23
  200. package/src/wearables/pipeline.test.ts +309 -1
  201. package/src/wearables/pipeline.ts +131 -9
  202. package/src/wearables/service.test.ts +172 -0
  203. package/src/wearables/service.ts +84 -3
  204. package/src/wearables/storage-io.test.ts +81 -0
  205. package/src/wearables/trust.test.ts +123 -0
  206. package/src/wearables/trust.ts +168 -0
  207. package/src/wearables/types.ts +37 -8
  208. package/dist/chunk-AZ4RI3QD.js.map +0 -1
  209. package/dist/chunk-F3FY3D3S.js.map +0 -1
  210. package/dist/chunk-STDAAGH7.js.map +0 -1
  211. package/dist/chunk-UGHUNQ74.js.map +0 -1
  212. /package/dist/{chunk-GE7Q7KXP.js.map → chunk-2VJ7AJFX.js.map} +0 -0
  213. /package/dist/{chunk-KVFYTRMV.js.map → chunk-4QEUKASL.js.map} +0 -0
  214. /package/dist/{chunk-KB4MFBF5.js.map → chunk-5S6IREG3.js.map} +0 -0
  215. /package/dist/{chunk-LQYTQCXM.js.map → chunk-6LBQL5US.js.map} +0 -0
  216. /package/dist/{chunk-KGIGRNR6.js.map → chunk-723OMPUI.js.map} +0 -0
  217. /package/dist/{chunk-TZDSNIRO.js.map → chunk-ADOD7PJC.js.map} +0 -0
  218. /package/dist/{chunk-SHV5Y2WU.js.map → chunk-BL33LBTN.js.map} +0 -0
  219. /package/dist/{chunk-532VCWYW.js.map → chunk-BWK5EEKS.js.map} +0 -0
  220. /package/dist/{chunk-3VONWEQB.js.map → chunk-HZVIYZYN.js.map} +0 -0
  221. /package/dist/{chunk-Y3TMFC6I.js.map → chunk-K3BTOW7N.js.map} +0 -0
  222. /package/dist/{chunk-Z3CCEP6F.js.map → chunk-K47C6M2C.js.map} +0 -0
  223. /package/dist/{chunk-N5RGXWLQ.js.map → chunk-MQ24KOOR.js.map} +0 -0
  224. /package/dist/{chunk-3MNBW7R7.js.map → chunk-NRQJBK36.js.map} +0 -0
  225. /package/dist/{chunk-MON3LMO7.js.map → chunk-NRST7W5Q.js.map} +0 -0
  226. /package/dist/{chunk-3R2UZV3U.js.map → chunk-OOFBE62K.js.map} +0 -0
  227. /package/dist/{chunk-MVQN73GT.js.map → chunk-OQMR2SDZ.js.map} +0 -0
  228. /package/dist/{chunk-QDV6VAD4.js.map → chunk-S5W37FPX.js.map} +0 -0
  229. /package/dist/{chunk-57QXN2CS.js.map → chunk-SACS6KE6.js.map} +0 -0
  230. /package/dist/{chunk-UELS6WWF.js.map → chunk-UE57H4MA.js.map} +0 -0
  231. /package/dist/{chunk-P2D2MM47.js.map → chunk-ZZSXUZF3.js.map} +0 -0
@@ -1,4 +1,8 @@
1
1
  import { log } from "./logger.js";
2
+ import {
3
+ buildChainFollowupGenerator,
4
+ type BriefingFollowupGenerator,
5
+ } from "./briefing.js";
2
6
  import path from "node:path";
3
7
  import os from "node:os";
4
8
  import { createHash, randomBytes } from "node:crypto";
@@ -2516,6 +2520,28 @@ export class Orchestrator {
2516
2520
  };
2517
2521
  }
2518
2522
 
2523
+ /**
2524
+ * Build a briefing follow-up generator backed by the configured LLM chain
2525
+ * (gateway model source or local LLM). Returns `undefined` when no chain
2526
+ * is available so `buildBriefing` can surface a clear unavailable reason
2527
+ * instead of failing at call time. Used by the access service and CLI as
2528
+ * the fallback when no direct `openaiApiKey` is configured, so briefing
2529
+ * follow-ups ride the same routing as every other fast-tier LLM feature.
2530
+ */
2531
+ get briefingChainFollowupGenerator(): BriefingFollowupGenerator | undefined {
2532
+ // Plugin mode gates on `localLlmEnabled` alone: `LocalLlmClient.chatCompletion`
2533
+ // returns null when the master switch is off, so `localLlmFastEnabled` by
2534
+ // itself cannot serve requests (Cursor review on PR #1463).
2535
+ const chainAvailable =
2536
+ this.config.modelSource === "gateway"
2537
+ ? this._fastGatewayLlm?.isAvailable(
2538
+ this.config.fastGatewayAgentId || this.config.gatewayAgentId || undefined,
2539
+ ) === true
2540
+ : this.config.localLlmEnabled;
2541
+ if (!chainAvailable) return undefined;
2542
+ return buildChainFollowupGenerator(this.fastLlmForRerank);
2543
+ }
2544
+
2519
2545
  async initialize(): Promise<void> {
2520
2546
  // Recreate the deferred-ready gate on every initialize() call.
2521
2547
  // The same Orchestrator instance may be reused across stop/start cycles
@@ -10781,6 +10807,22 @@ export class Orchestrator {
10781
10807
  getStorage: async () =>
10782
10808
  await this.getStorageForNamespace(this.bulkImportWriteNamespace()),
10783
10809
  extract: (turns) => this.extraction.extract(turns),
10810
+ // Smart memoryMode runs candidates through the SAME extraction
10811
+ // judge (cache + defer counters included) the live extraction
10812
+ // pipeline uses, so wearable facts get identical LLM-as-judge
10813
+ // durability gating.
10814
+ judgeFacts: (candidates) =>
10815
+ judgeFactDurability(
10816
+ candidates,
10817
+ this.config,
10818
+ this.localLlm,
10819
+ new FallbackLlmClient(
10820
+ this.config.gatewayConfig,
10821
+ fallbackLlmRuntimeContextFromConfig(this.config),
10822
+ ),
10823
+ this.judgeVerdictCache,
10824
+ this.judgeDeferCounts,
10825
+ ),
10784
10826
  searchBackend: {
10785
10827
  search: async (query, maxResults) => {
10786
10828
  if (!this.qmd.isAvailable()) return null;
package/src/storage.ts CHANGED
@@ -1168,6 +1168,27 @@ export class ContentHashIndex {
1168
1168
  * normalizeAttributePairs({ foo: "bar", BAZ: "qux" })
1169
1169
  * // → "baz: qux; foo: bar"
1170
1170
  */
1171
+ /**
1172
+ * Remove the "[Attributes: ...]" suffix `writeMemory` appends to the
1173
+ * stored body when structuredAttributes are present, yielding the raw
1174
+ * fact text for content comparison. Inverse companion of
1175
+ * `normalizeAttributePairs` enrichment. String operations, not regex —
1176
+ * CodeQL js/polynomial-redos on a suffix-anchored pattern over
1177
+ * library-supplied content.
1178
+ */
1179
+ export function stripAttributesSuffix(content: string): string {
1180
+ const trimmed = content.trimEnd();
1181
+ if (!trimmed.endsWith("]")) return content.trim();
1182
+ const marker = "\n[Attributes: ";
1183
+ const markerIndex = trimmed.lastIndexOf(marker);
1184
+ if (markerIndex === -1) return content.trim();
1185
+ // The block must be the FINAL line and contain no "]" before the
1186
+ // closing bracket (mirrors the shape normalizeAttributePairs emits).
1187
+ const inner = trimmed.slice(markerIndex + marker.length, -1);
1188
+ if (inner.includes("]") || inner.includes("\n")) return content.trim();
1189
+ return trimmed.slice(0, markerIndex).trim();
1190
+ }
1191
+
1171
1192
  export function normalizeAttributePairs(pairs: Record<string, string>): string {
1172
1193
  return Object.entries(pairs)
1173
1194
  .map(([k, v]) => [k.trim().toLowerCase(), v.trim()] as [string, string])
@@ -2596,6 +2617,85 @@ export class StorageManager {
2596
2617
  return days;
2597
2618
  }
2598
2619
 
2620
+ /**
2621
+ * Locate a wearable-sourced memory by exact (trimmed) content,
2622
+ * ignoring the "[Attributes: ...]" suffix writeMemory appends for
2623
+ * structuredAttributes — callers pass the raw fact text. Used by the
2624
+ * smart trust pipeline to find an earlier borderline write when the
2625
+ * same fact re-extracts with stronger evidence.
2626
+ */
2627
+ async findWearableMemoryByContent(
2628
+ content: string,
2629
+ ): Promise<{ id: string; status: MemoryStatus | undefined } | null> {
2630
+ const needle = stripAttributesSuffix(content);
2631
+ const memories = await this.readAllMemories();
2632
+ for (const memory of memories) {
2633
+ if (
2634
+ typeof memory.frontmatter.source === "string" &&
2635
+ memory.frontmatter.source.startsWith("wearable:") &&
2636
+ stripAttributesSuffix(memory.content) === needle
2637
+ ) {
2638
+ return { id: memory.frontmatter.id, status: memory.frontmatter.status };
2639
+ }
2640
+ }
2641
+ return null;
2642
+ }
2643
+
2644
+ /**
2645
+ * Promote a pending_review wearable memory to active in place,
2646
+ * merging updated trust evidence into structuredAttributes. Returns
2647
+ * false when the memory is missing or no longer pending_review (a
2648
+ * concurrent review decision wins).
2649
+ */
2650
+ async promoteWearableMemory(
2651
+ id: string,
2652
+ attributeUpdates: Record<string, string>,
2653
+ confidence?: number,
2654
+ ): Promise<boolean> {
2655
+ const memories = await this.readAllMemories();
2656
+ const memory = memories.find((entry) => entry.frontmatter.id === id);
2657
+ if (!memory) return false;
2658
+ if (memory.frontmatter.status !== "pending_review") return false;
2659
+ return this.writeMemoryFrontmatter(memory, {
2660
+ status: "active",
2661
+ // Keep frontmatter confidence in step with the re-scored trust —
2662
+ // new smart writes persist trust as confidence, and a promoted
2663
+ // row must not keep its stale borderline value.
2664
+ ...(typeof confidence === "number" && Number.isFinite(confidence)
2665
+ ? { confidence: Math.min(1, Math.max(0, confidence)) }
2666
+ : {}),
2667
+ structuredAttributes: {
2668
+ ...(memory.frontmatter.structuredAttributes ?? {}),
2669
+ ...attributeUpdates,
2670
+ },
2671
+ });
2672
+ }
2673
+
2674
+ /**
2675
+ * Demote a pending_review wearable memory to rejected when a re-pass
2676
+ * produced an explicit judge-reject verdict, merging the evidence.
2677
+ * Returns false when the memory is missing or no longer
2678
+ * pending_review — active rows are NEVER auto-demoted (operator
2679
+ * approvals and accrued recall signals win; contradiction scans and
2680
+ * supersession own active-row retirement).
2681
+ */
2682
+ async demoteWearableMemory(
2683
+ id: string,
2684
+ attributeUpdates: Record<string, string>,
2685
+ ): Promise<boolean> {
2686
+ const memories = await this.readAllMemories();
2687
+ const memory = memories.find((entry) => entry.frontmatter.id === id);
2688
+ if (!memory) return false;
2689
+ if (memory.frontmatter.status !== "pending_review") return false;
2690
+ return this.writeMemoryFrontmatter(memory, {
2691
+ status: "rejected",
2692
+ structuredAttributes: {
2693
+ ...(memory.frontmatter.structuredAttributes ?? {}),
2694
+ ...attributeUpdates,
2695
+ },
2696
+ });
2697
+ }
2698
+
2599
2699
  private get factsDir(): string {
2600
2700
  return path.join(this.baseDir, "facts");
2601
2701
  }
@@ -125,6 +125,12 @@ function renderSyncSummary(summary: WearableSyncSummary): string {
125
125
  ` transcripts written: ${summary.transcriptsWritten.length > 0 ? summary.transcriptsWritten.join(", ") : "(none — unchanged)"}`,
126
126
  ` memories created: ${summary.memoriesCreated} (skipped ${summary.memoriesSkipped})`,
127
127
  ];
128
+ if (summary.memoriesPromoted > 0) {
129
+ lines.push(` memories promoted: ${summary.memoriesPromoted}`);
130
+ }
131
+ if (summary.memoriesDemoted > 0) {
132
+ lines.push(` memories demoted: ${summary.memoriesDemoted}`);
133
+ }
128
134
  if (summary.nativeMemoriesImported > 0) {
129
135
  lines.push(` native memories queued: ${summary.nativeMemoriesImported}`);
130
136
  }
@@ -25,17 +25,20 @@ test("boolean-ish strings coerce; garbage booleans throw", () => {
25
25
  assert.throws(() => parseWearablesConfig({ enabled: "fales" }), /wearables.enabled/);
26
26
  });
27
27
 
28
- test("source settings default to the least-privileged memory mode", () => {
28
+ test("source settings default to the fully-automated smart pipeline", () => {
29
29
  const parsed = parseWearablesConfig({
30
30
  enabled: true,
31
31
  sources: { limitless: { enabled: true } },
32
32
  });
33
33
  const source = parsed.sources.limitless;
34
- assert.equal(source.memoryMode, "review");
34
+ assert.equal(source.memoryMode, "smart");
35
+ assert.equal(source.sourceTrust, 0.8);
36
+ assert.equal(source.autoApproveTrust, 0.7);
37
+ assert.equal(source.reviewTrust, 0.45);
35
38
  assert.equal(source.minConfidence, 0.6);
36
39
  assert.equal(source.minImportance, "low");
37
- assert.equal(source.maxMemoriesPerDay, 20);
38
- assert.equal(source.importNativeMemories, "off");
40
+ assert.equal(source.maxMemoriesPerDay, 50);
41
+ assert.equal(source.importNativeMemories, "smart");
39
42
  assert.deepEqual(source.cleanup, {
40
43
  mergeSameSpeaker: true,
41
44
  stripFillers: true,
@@ -44,6 +47,32 @@ test("source settings default to the least-privileged memory mode", () => {
44
47
  });
45
48
  });
46
49
 
50
+ test("top-level defaults are full-featured: digest and off-the-record on", () => {
51
+ const parsed = parseWearablesConfig({});
52
+ assert.equal(parsed.digestEnabled, true);
53
+ assert.equal(parsed.offTheRecordEnabled, true);
54
+ assert.equal(parsed.redactionEnabled, true);
55
+ });
56
+
57
+ test("trust knobs validate range and ordering", () => {
58
+ assert.throws(
59
+ () => parseWearablesConfig({ sources: { bee: { sourceTrust: 1.5 } } }),
60
+ /sourceTrust must be a number between 0 and 1/,
61
+ );
62
+ assert.throws(
63
+ () => parseWearablesConfig({ sources: { bee: { autoApproveTrust: -1 } } }),
64
+ /autoApproveTrust/,
65
+ );
66
+ assert.throws(
67
+ () => parseWearablesConfig({ sources: { bee: { reviewTrust: 0.9, autoApproveTrust: 0.7 } } }),
68
+ /reviewTrust .* must be below autoApproveTrust/,
69
+ );
70
+ const parsed = parseWearablesConfig({
71
+ sources: { bee: { sourceTrust: 0.5, autoApproveTrust: 0.8, reviewTrust: 0.3 } },
72
+ });
73
+ assert.equal(parsed.sources.bee.sourceTrust, 0.5);
74
+ });
75
+
47
76
  test("invalid enum values list the valid options", () => {
48
77
  assert.throws(
49
78
  () =>
@@ -22,7 +22,7 @@ import type {
22
22
 
23
23
  export const KNOWN_WEARABLE_SOURCE_IDS = ["limitless", "bee", "omi"] as const;
24
24
 
25
- const MEMORY_MODES: WearableMemoryMode[] = ["off", "review", "auto"];
25
+ const MEMORY_MODES: WearableMemoryMode[] = ["off", "review", "auto", "smart"];
26
26
  const IMPORTANCE_LEVELS: ImportanceLevel[] = [
27
27
  "trivial",
28
28
  "low",
@@ -30,12 +30,15 @@ const IMPORTANCE_LEVELS: ImportanceLevel[] = [
30
30
  "high",
31
31
  "critical",
32
32
  ];
33
- const NATIVE_IMPORT_MODES = ["off", "review"] as const;
33
+ const NATIVE_IMPORT_MODES = ["off", "review", "smart"] as const;
34
34
 
35
35
  const DEFAULT_MIN_CONFIDENCE = 0.6;
36
36
  const DEFAULT_MIN_IMPORTANCE: ImportanceLevel = "low";
37
- const DEFAULT_MAX_MEMORIES_PER_DAY = 20;
37
+ const DEFAULT_MAX_MEMORIES_PER_DAY = 50;
38
38
  const MAX_MEMORIES_PER_DAY_CEILING = 500;
39
+ const DEFAULT_SOURCE_TRUST = 0.8;
40
+ const DEFAULT_AUTO_APPROVE_TRUST = 0.7;
41
+ const DEFAULT_REVIEW_TRUST = 0.45;
39
42
 
40
43
  export function defaultWearableCleanupSettings(): WearableCleanupSettings {
41
44
  return {
@@ -49,11 +52,14 @@ export function defaultWearableCleanupSettings(): WearableCleanupSettings {
49
52
  export function defaultWearableSourceSettings(): WearableSourceSettings {
50
53
  return {
51
54
  enabled: false,
52
- memoryMode: "review",
55
+ memoryMode: "smart",
56
+ sourceTrust: DEFAULT_SOURCE_TRUST,
57
+ autoApproveTrust: DEFAULT_AUTO_APPROVE_TRUST,
58
+ reviewTrust: DEFAULT_REVIEW_TRUST,
53
59
  minConfidence: DEFAULT_MIN_CONFIDENCE,
54
60
  minImportance: DEFAULT_MIN_IMPORTANCE,
55
61
  maxMemoriesPerDay: DEFAULT_MAX_MEMORIES_PER_DAY,
56
- importNativeMemories: "off",
62
+ importNativeMemories: "smart",
57
63
  cleanup: defaultWearableCleanupSettings(),
58
64
  };
59
65
  }
@@ -63,8 +69,8 @@ export function defaultWearablesConfig(): WearablesConfig {
63
69
  enabled: false,
64
70
  redactionEnabled: true,
65
71
  redactionPatterns: [],
66
- offTheRecordEnabled: false,
67
- digestEnabled: false,
72
+ offTheRecordEnabled: true,
73
+ digestEnabled: true,
68
74
  corrections: [],
69
75
  sources: {},
70
76
  };
@@ -203,6 +209,29 @@ function parseSourceSettings(
203
209
  // the schema minimum (CLAUDE.md rule 45).
204
210
  const maxMemoriesPerDay = maxPerDayRaw ?? defaults.maxMemoriesPerDay;
205
211
 
212
+ const parseUnitInterval = (value: unknown, name: string, fallback: number): number => {
213
+ if (value === undefined) return fallback;
214
+ const coerced = coerceNumber(value);
215
+ if (coerced === undefined || coerced < 0 || coerced > 1) {
216
+ throw new Error(
217
+ `${keyPath}.${name} must be a number between 0 and 1 (got ${JSON.stringify(value)})`,
218
+ );
219
+ }
220
+ return coerced;
221
+ };
222
+ const sourceTrust = parseUnitInterval(raw.sourceTrust, "sourceTrust", defaults.sourceTrust);
223
+ const autoApproveTrust = parseUnitInterval(
224
+ raw.autoApproveTrust,
225
+ "autoApproveTrust",
226
+ defaults.autoApproveTrust,
227
+ );
228
+ const reviewTrust = parseUnitInterval(raw.reviewTrust, "reviewTrust", defaults.reviewTrust);
229
+ if (reviewTrust >= autoApproveTrust) {
230
+ throw new Error(
231
+ `${keyPath}.reviewTrust (${reviewTrust}) must be below autoApproveTrust (${autoApproveTrust})`,
232
+ );
233
+ }
234
+
206
235
  const rawCleanup =
207
236
  raw.cleanup === undefined ? {} : requireObject(raw.cleanup, `${keyPath}.cleanup`);
208
237
  const cleanup: WearableCleanupSettings = {
@@ -240,6 +269,9 @@ function parseSourceSettings(
240
269
  MEMORY_MODES,
241
270
  defaults.memoryMode,
242
271
  ),
272
+ sourceTrust,
273
+ autoApproveTrust,
274
+ reviewTrust,
243
275
  minConfidence,
244
276
  minImportance: parseEnum(
245
277
  raw.minImportance,