@remnic/core 9.65.6 → 9.65.7

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 (506) hide show
  1. package/dist/access-admin-ops-surface.d.ts +11 -11
  2. package/dist/access-admin-ops-surface.js +31 -31
  3. package/dist/access-audit.js +2 -2
  4. package/dist/access-authorization-probe.d.ts +11 -11
  5. package/dist/access-authorization-probe.js +32 -32
  6. package/dist/access-boundary.d.ts +11 -11
  7. package/dist/access-boundary.js +31 -31
  8. package/dist/access-cli.js +111 -106
  9. package/dist/access-cli.js.map +1 -1
  10. package/dist/access-coding-context-resolution.d.ts +1 -1
  11. package/dist/access-extraction-force-flush.d.ts +11 -11
  12. package/dist/access-extraction-force-flush.js +31 -31
  13. package/dist/access-health-types.d.ts +1 -1
  14. package/dist/access-http-lcm-compaction.d.ts +11 -11
  15. package/dist/access-http-lifecycle-flush.d.ts +11 -11
  16. package/dist/access-http-offline-stream.d.ts +11 -11
  17. package/dist/access-http-query.d.ts +2 -2
  18. package/dist/access-http-query.js +33 -33
  19. package/dist/access-http.d.ts +13 -18
  20. package/dist/access-http.js +50 -48
  21. package/dist/access-identity-continuity-surface.d.ts +9 -9
  22. package/dist/access-identity-continuity-surface.js +31 -31
  23. package/dist/access-lcm-surface.d.ts +11 -11
  24. package/dist/access-lcm-surface.js +31 -31
  25. package/dist/access-mcp-output-schemas.js +1 -1
  26. package/dist/access-mcp.d.ts +11 -11
  27. package/dist/access-mcp.js +42 -40
  28. package/dist/access-memory-search-fanout.d.ts +2 -2
  29. package/dist/{access-namespace-preflight-D_6mo8ms.d.ts → access-namespace-preflight-8VYKmRX0.d.ts} +1 -1
  30. package/dist/access-namespace-preflight.d.ts +3 -3
  31. package/dist/access-namespace-preflight.js +31 -31
  32. package/dist/access-observe-write-surface.d.ts +11 -11
  33. package/dist/access-observe-write-surface.js +31 -31
  34. package/dist/access-offline-manifest.d.ts +9 -9
  35. package/dist/access-operations-batch.js +34 -34
  36. package/dist/access-operations.d.ts +12 -12
  37. package/dist/access-operations.js +39 -37
  38. package/dist/access-recall-concurrency.d.ts +11 -11
  39. package/dist/access-recall-concurrency.js +31 -31
  40. package/dist/access-recall-response.d.ts +11 -11
  41. package/dist/access-recall-response.js +31 -31
  42. package/dist/access-recall-surface.d.ts +11 -11
  43. package/dist/access-recall-surface.js +31 -31
  44. package/dist/access-schema.js +3 -3
  45. package/dist/{access-service-sbiNS5UB.d.ts → access-service-Crk__Git.d.ts} +8 -8
  46. package/dist/access-service-helpers.d.ts +11 -11
  47. package/dist/access-service.d.ts +11 -11
  48. package/dist/access-service.js +31 -31
  49. package/dist/access-surface-catalog.d.ts +11 -11
  50. package/dist/access-surface-catalog.js +43 -33
  51. package/dist/access-surface-catalog.js.map +1 -1
  52. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  53. package/dist/action-confidence.d.ts +1 -1
  54. package/dist/active-memory-bridge.d.ts +1 -1
  55. package/dist/active-recall.d.ts +1 -1
  56. package/dist/active-recall.js +4 -4
  57. package/dist/adapters/index.js +4 -4
  58. package/dist/adapters/registry.js +2 -2
  59. package/dist/ambient-provenance.d.ts +1 -1
  60. package/dist/artifact-search.d.ts +1 -1
  61. package/dist/behavior-learner.d.ts +1 -1
  62. package/dist/behavior-signals.d.ts +1 -1
  63. package/dist/bootstrap.d.ts +9 -9
  64. package/dist/briefing-window.d.ts +2 -2
  65. package/dist/briefing.d.ts +2 -2
  66. package/dist/briefing.js +10 -10
  67. package/dist/buffer-surprise-report.d.ts +1 -1
  68. package/dist/buffer-turn-helpers.d.ts +1 -1
  69. package/dist/buffer.d.ts +2 -2
  70. package/dist/bulk-import/index.d.ts +3 -3
  71. package/dist/calibration.d.ts +1 -1
  72. package/dist/capabilities.d.ts +1 -1
  73. package/dist/{capsule-crypto-GWVG7LGC.js → capsule-crypto-7FJQINUR.js} +2 -2
  74. package/dist/{catalog-DO_7zfkv.d.ts → catalog-DybwVNW3.d.ts} +1 -1
  75. package/dist/causal-behavior.d.ts +1 -1
  76. package/dist/causal-behavior.js +2 -2
  77. package/dist/causal-chain.js +2 -2
  78. package/dist/causal-consolidation.d.ts +1 -1
  79. package/dist/causal-consolidation.js +13 -13
  80. package/dist/causal-retrieval.js +2 -2
  81. package/dist/causal-trajectory-graph.d.ts +1 -1
  82. package/dist/causal-trajectory-graph.js +2 -2
  83. package/dist/causal-trajectory.js +1 -1
  84. package/dist/{chunk-OWHERGF2.js → chunk-2NLLXCJG.js} +2 -2
  85. package/dist/{chunk-NZPFCP5A.js → chunk-2PSX5BJU.js} +2 -2
  86. package/dist/chunk-3BCULS4U.js +1093 -0
  87. package/dist/chunk-3BCULS4U.js.map +1 -0
  88. package/dist/{chunk-W6J4POB6.js → chunk-3RI5Y7KU.js} +2 -2
  89. package/dist/{chunk-H7BZBSP6.js → chunk-52II7PB6.js} +4 -4
  90. package/dist/{chunk-IF4EY26E.js → chunk-5DH6PG4B.js} +2 -2
  91. package/dist/{chunk-M4AHBM72.js → chunk-5HERQ5FX.js} +10 -10
  92. package/dist/{chunk-IRXMJLTW.js → chunk-5HK3CJAR.js} +2 -2
  93. package/dist/{chunk-XAWIL7TC.js → chunk-5S4LQOPE.js} +2 -2
  94. package/dist/{chunk-IDQ6DKXC.js → chunk-5VPQSRQO.js} +3 -3
  95. package/dist/{chunk-ROEAEANL.js → chunk-6CPUQ5D6.js} +10 -10
  96. package/dist/{chunk-SR7JIRAR.js → chunk-7F27PCSN.js} +2 -2
  97. package/dist/{chunk-7OZSHBWK.js → chunk-7TCGNUVP.js} +2 -2
  98. package/dist/{chunk-KBOG7FJV.js → chunk-7WR462EM.js} +2 -2
  99. package/dist/{chunk-AYAZWXJI.js → chunk-A32YEQAM.js} +2 -2
  100. package/dist/{chunk-5GIZM4RX.js → chunk-ACOC27BB.js} +2 -2
  101. package/dist/{chunk-5W7MKXMU.js → chunk-AFR6AIM4.js} +144 -78
  102. package/dist/chunk-AFR6AIM4.js.map +1 -0
  103. package/dist/{chunk-OMZLBT4B.js → chunk-ANJXPFRS.js} +47 -26
  104. package/dist/chunk-ANJXPFRS.js.map +1 -0
  105. package/dist/{chunk-FC7TIRFS.js → chunk-AX7UXCHJ.js} +6 -1
  106. package/dist/chunk-AX7UXCHJ.js.map +1 -0
  107. package/dist/{chunk-6LS5OX3U.js → chunk-BJTHRFFC.js} +6 -6
  108. package/dist/chunk-BWGCOLEL.js +61 -0
  109. package/dist/chunk-BWGCOLEL.js.map +1 -0
  110. package/dist/{chunk-PGW64IFQ.js → chunk-CFGU52XJ.js} +2 -2
  111. package/dist/{chunk-DPNXADEI.js → chunk-D4QVPP3G.js} +2 -2
  112. package/dist/{chunk-2RXUZVPU.js → chunk-EOHKUWXW.js} +2 -2
  113. package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
  114. package/dist/{chunk-ZK4BFABK.js → chunk-F635GAL7.js} +4 -4
  115. package/dist/{chunk-HWVNYNIV.js → chunk-F6QHHRWP.js} +2 -2
  116. package/dist/{chunk-YUTTMSC7.js → chunk-FMQ4MOQO.js} +89 -26
  117. package/dist/chunk-FMQ4MOQO.js.map +1 -0
  118. package/dist/{chunk-LDBFXD4F.js → chunk-FP7YTTVO.js} +3 -1
  119. package/dist/chunk-FP7YTTVO.js.map +1 -0
  120. package/dist/{chunk-O4BAGJDN.js → chunk-GEPACVWN.js} +2 -2
  121. package/dist/{chunk-XZBXINXZ.js → chunk-GIC6BASP.js} +4 -4
  122. package/dist/{chunk-PP7R754B.js → chunk-GPFZFCRN.js} +1 -1
  123. package/dist/{chunk-LSYD7GHZ.js → chunk-GTSVEEP3.js} +2 -2
  124. package/dist/{chunk-RQ2EQRRR.js → chunk-I4343FIA.js} +79 -6
  125. package/dist/chunk-I4343FIA.js.map +1 -0
  126. package/dist/{chunk-YWBOOBDP.js → chunk-I7EX6KSH.js} +58 -58
  127. package/dist/{chunk-3I22VWB3.js → chunk-IP4ZNT4U.js} +2 -2
  128. package/dist/{chunk-AXGFOFNY.js → chunk-IY7UXD3J.js} +2 -2
  129. package/dist/{chunk-6FUMA6AA.js → chunk-JAQXUGLN.js} +2 -2
  130. package/dist/{chunk-RKNJBZ55.js → chunk-JBPKEARU.js} +4 -4
  131. package/dist/chunk-JCCWJHOP.js +240 -0
  132. package/dist/chunk-JCCWJHOP.js.map +1 -0
  133. package/dist/{chunk-5W7CTZ2E.js → chunk-KQAFEZQX.js} +4 -4
  134. package/dist/{chunk-D2YNNDML.js → chunk-KWIGDKM2.js} +2 -2
  135. package/dist/{chunk-2JHRCWHT.js → chunk-LLQCM2U2.js} +85 -85
  136. package/dist/{chunk-OLBZ2WGG.js → chunk-LTBKKSCX.js} +2 -2
  137. package/dist/{chunk-RACZB5HT.js → chunk-N37X5RU7.js} +4 -4
  138. package/dist/{chunk-FEO2CDXR.js → chunk-NG3MBQV4.js} +2 -2
  139. package/dist/{chunk-AG46P24C.js → chunk-NNBZS3DY.js} +4 -4
  140. package/dist/{chunk-JGG5HVI2.js → chunk-OPGL46PX.js} +2 -2
  141. package/dist/{chunk-OUKBMQ2O.js → chunk-PD66CVSD.js} +2 -2
  142. package/dist/{chunk-7SSRXEZJ.js → chunk-PDDSFELN.js} +2 -2
  143. package/dist/{chunk-MVIYRRVJ.js → chunk-PMVPCZJZ.js} +5 -5
  144. package/dist/{chunk-D35XLYQ7.js → chunk-RGCF4XNH.js} +9 -9
  145. package/dist/{chunk-PNAGNVGK.js → chunk-RQE4TITU.js} +35 -30
  146. package/dist/chunk-RQE4TITU.js.map +1 -0
  147. package/dist/{chunk-X2DWBWOX.js → chunk-S3K2CIK5.js} +2 -2
  148. package/dist/{chunk-TWBQQ3FT.js → chunk-SEA6M7SS.js} +2 -2
  149. package/dist/{chunk-DYO24BNB.js → chunk-SVVIASVX.js} +2 -2
  150. package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
  151. package/dist/{chunk-4K7IW3F7.js → chunk-UD7UNYRD.js} +34 -3
  152. package/dist/chunk-UD7UNYRD.js.map +1 -0
  153. package/dist/chunk-ULM7JCDH.js +154 -0
  154. package/dist/chunk-ULM7JCDH.js.map +1 -0
  155. package/dist/{chunk-NLUCDKLT.js → chunk-VKCAHCBI.js} +2 -2
  156. package/dist/{chunk-BXXOPKT5.js → chunk-VXVZ2GM3.js} +2 -2
  157. package/dist/chunk-W2UOAATB.js +521 -0
  158. package/dist/chunk-W2UOAATB.js.map +1 -0
  159. package/dist/{chunk-JFWZRUKP.js → chunk-WTOZBZNN.js} +3 -3
  160. package/dist/{chunk-UVYI6VIX.js → chunk-X7Y7WX73.js} +1 -1
  161. package/dist/{chunk-5TG4MU2U.js → chunk-YKWFK7XA.js} +5 -5
  162. package/dist/{chunk-BIJAWZYW.js → chunk-YMOPYG3K.js} +6 -6
  163. package/dist/{chunk-XUZ5CIEE.js → chunk-YRVAKONL.js} +1 -1
  164. package/dist/{chunk-53MZQEBD.js → chunk-YWSQD2IB.js} +2 -2
  165. package/dist/{chunk-US4IRASK.js → chunk-Z4U3UN56.js} +2 -2
  166. package/dist/{chunk-QMZY3GG6.js → chunk-ZAOHJDKH.js} +3 -3
  167. package/dist/{chunk-ZXUZ54Z5.js → chunk-ZIJDI4CP.js} +2 -2
  168. package/dist/{cli-Bfgo0n1L.d.ts → cli-B322UMvB.d.ts} +5 -5
  169. package/dist/cli.d.ts +13 -13
  170. package/dist/cli.js +75 -74
  171. package/dist/coding/pre-action-gate.d.ts +1 -1
  172. package/dist/coding/pre-action-gate.js +2 -2
  173. package/dist/compounding/engine.d.ts +2 -2
  174. package/dist/compounding/engine.js +10 -10
  175. package/dist/compounding/preference-consolidator.d.ts +1 -1
  176. package/dist/compression-optimizer.d.ts +1 -1
  177. package/dist/config.d.ts +1 -1
  178. package/dist/config.js +4 -4
  179. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  180. package/dist/connectors/codex-materialize-runner.js +10 -10
  181. package/dist/connectors/codex-materialize.d.ts +1 -1
  182. package/dist/connectors/index.d.ts +1 -1
  183. package/dist/connectors/index.js +10 -10
  184. package/dist/consolidation-provenance-check.d.ts +2 -2
  185. package/dist/consolidation-undo.d.ts +2 -2
  186. package/dist/contradiction/index.d.ts +3 -3
  187. package/dist/converge-config.d.ts +1 -1
  188. package/dist/convergence-refresh.d.ts +2 -2
  189. package/dist/convergence-refresh.js +12 -12
  190. package/dist/conversation-index/backend.d.ts +1 -1
  191. package/dist/conversation-index/chunker.d.ts +1 -1
  192. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  193. package/dist/conversation-index/indexer.d.ts +1 -1
  194. package/dist/conversation-index/search.d.ts +1 -1
  195. package/dist/corpus-watermark.d.ts +1 -1
  196. package/dist/corpus-watermark.js +12 -12
  197. package/dist/cross-lingual-recall.d.ts +1 -1
  198. package/dist/dashboard-runtime.js +2 -2
  199. package/dist/day-summary.d.ts +1 -1
  200. package/dist/delinearize.d.ts +1 -1
  201. package/dist/dependency-propagation-config.d.ts +1 -1
  202. package/dist/{dependency-propagation-delivery-D23_x-s5.d.ts → dependency-propagation-delivery-BGcNairQ.d.ts} +1 -1
  203. package/dist/direct-answer-wiring.d.ts +1 -1
  204. package/dist/direct-answer.d.ts +1 -1
  205. package/dist/embedding-fallback.d.ts +1 -1
  206. package/dist/enrichment/index.d.ts +1 -1
  207. package/dist/entity-origin-fields.d.ts +1 -1
  208. package/dist/entity-retrieval.d.ts +2 -2
  209. package/dist/entity-retrieval.js +10 -10
  210. package/dist/entity-schema.d.ts +1 -1
  211. package/dist/episodic-context.d.ts +1 -1
  212. package/dist/eval-trajectory-contracts.d.ts +256 -0
  213. package/dist/eval-trajectory-contracts.js +56 -0
  214. package/dist/eval-trajectory-store.d.ts +39 -0
  215. package/dist/eval-trajectory-store.js +19 -0
  216. package/dist/eval-trajectory-store.js.map +1 -0
  217. package/dist/eval-trajectory.d.ts +67 -0
  218. package/dist/eval-trajectory.js +46 -0
  219. package/dist/eval-trajectory.js.map +1 -0
  220. package/dist/event-order-recall.js +2 -2
  221. package/dist/explicit-capture.d.ts +9 -9
  222. package/dist/external-wiki-access.d.ts +11 -11
  223. package/dist/external-wiki-access.js +32 -32
  224. package/dist/external-wiki-collection-registration.d.ts +1 -1
  225. package/dist/external-wiki-collection.d.ts +1 -1
  226. package/dist/external-wiki-mcp-tools.d.ts +11 -11
  227. package/dist/extraction-error-classification.d.ts +1 -1
  228. package/dist/extraction-faithfulness.d.ts +1 -1
  229. package/dist/extraction-judge-telemetry.d.ts +1 -1
  230. package/dist/extraction-judge-training.d.ts +1 -1
  231. package/dist/extraction-judge.d.ts +1 -1
  232. package/dist/extraction-liveness.d.ts +1 -1
  233. package/dist/extraction-normalization.d.ts +1 -1
  234. package/dist/extraction-prompt.d.ts +1 -1
  235. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  236. package/dist/extraction-source-grounding.d.ts +1 -1
  237. package/dist/extraction.d.ts +1 -1
  238. package/dist/extraction.js +12 -12
  239. package/dist/fallback-llm.d.ts +1 -1
  240. package/dist/graph-dashboard-diff.d.ts +1 -1
  241. package/dist/graph-dashboard-key.d.ts +1 -1
  242. package/dist/graph-dashboard-parser.d.ts +1 -1
  243. package/dist/{graph-edge-decay-FXGELBFA.js → graph-edge-decay-A4SDFMMS.js} +4 -4
  244. package/dist/graph-edge-decay-A4SDFMMS.js.map +1 -0
  245. package/dist/graph-edge-reinforcement.d.ts +1 -1
  246. package/dist/graph-path-reconstruction.d.ts +1 -1
  247. package/dist/graph-path-scoring.d.ts +1 -1
  248. package/dist/graph-snapshot.d.ts +1 -1
  249. package/dist/graph-snapshot.js +3 -3
  250. package/dist/graph.d.ts +1 -1
  251. package/dist/graph.js +3 -3
  252. package/dist/harmonic-retrieval.js +1 -1
  253. package/dist/importance.d.ts +1 -1
  254. package/dist/importers/index.d.ts +1 -1
  255. package/dist/in-flight-reads.d.ts +1 -1
  256. package/dist/{index--QhGIXF2.d.ts → index-By2QUAMh.d.ts} +2 -2
  257. package/dist/index.d.ts +26 -23
  258. package/dist/index.js +184 -142
  259. package/dist/intent.d.ts +1 -1
  260. package/dist/lcm/engine.d.ts +1 -1
  261. package/dist/lcm/engine.js +4 -4
  262. package/dist/lcm/index.d.ts +1 -1
  263. package/dist/lcm/index.js +13 -13
  264. package/dist/lcm/tools.d.ts +1 -1
  265. package/dist/lifecycle.d.ts +1 -1
  266. package/dist/live-connectors-runner.d.ts +1 -1
  267. package/dist/local-llm.d.ts +1 -1
  268. package/dist/local-model-endpoint.d.ts +1 -1
  269. package/dist/location/index.d.ts +128 -1
  270. package/dist/location/index.js +60 -750
  271. package/dist/location/index.js.map +1 -1
  272. package/dist/maintenance/memory-governance.d.ts +1 -1
  273. package/dist/maintenance/memory-governance.js +10 -10
  274. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  275. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
  276. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  277. package/dist/maintenance/rebuild-memory-projection.js +11 -11
  278. package/dist/{maintenance-PFvY1Pw_.d.ts → maintenance-Dm2McrIx.d.ts} +4 -3
  279. package/dist/mcp-memory-inspector-app.d.ts +11 -11
  280. package/dist/mcp-read-only-tools.js +1 -1
  281. package/dist/memory-action-policy.d.ts +1 -1
  282. package/dist/memory-cache.d.ts +1 -1
  283. package/dist/memory-controller.d.ts +1 -1
  284. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  285. package/dist/memory-projection-store.d.ts +1 -1
  286. package/dist/memory-provenance.d.ts +1 -1
  287. package/dist/memory-snapshot.d.ts +1 -1
  288. package/dist/memory-subject-cli.d.ts +11 -11
  289. package/dist/memory-subject.d.ts +11 -11
  290. package/dist/memory-worth-outcomes.d.ts +47 -3
  291. package/dist/memory-worth-outcomes.js +5 -3
  292. package/dist/models-json.d.ts +1 -1
  293. package/dist/namespaces/migrate.d.ts +3 -3
  294. package/dist/namespaces/migrate.js +11 -11
  295. package/dist/namespaces/principal.d.ts +1 -1
  296. package/dist/namespaces/search.d.ts +1 -1
  297. package/dist/namespaces/search.js +7 -7
  298. package/dist/namespaces/storage.d.ts +3 -3
  299. package/dist/namespaces/storage.js +10 -10
  300. package/dist/native-knowledge.d.ts +1 -1
  301. package/dist/offline-sync-impression-drain.d.ts +1 -1
  302. package/dist/operator-doctor-corpus.d.ts +1 -1
  303. package/dist/operator-doctor-corpus.js +13 -13
  304. package/dist/operator-doctor-replica.d.ts +1 -1
  305. package/dist/operator-toolkit.d.ts +3 -3
  306. package/dist/operator-toolkit.js +24 -24
  307. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  308. package/dist/orchestration/maintenance.d.ts +4 -4
  309. package/dist/orchestration/maintenance.js +18 -16
  310. package/dist/{orchestrator-4wzJrPVm.d.ts → orchestrator-Co1DyfuP.d.ts} +8 -8
  311. package/dist/orchestrator.d.ts +9 -9
  312. package/dist/orchestrator.js +111 -106
  313. package/dist/patterns-cli.d.ts +1 -1
  314. package/dist/{pipeline-CgXgdIrF.d.ts → pipeline-DotMnb6y.d.ts} +1 -1
  315. package/dist/policy-runtime.d.ts +1 -1
  316. package/dist/proactive-contention.d.ts +1 -1
  317. package/dist/provenance.d.ts +1 -1
  318. package/dist/{public-http-BP3VQDl5.d.ts → public-http-PJRtnSi-.d.ts} +1 -1
  319. package/dist/{qmd-BppGGxsi.d.ts → qmd-BP0n11fR.d.ts} +1 -1
  320. package/dist/qmd-preflight.d.ts +2 -2
  321. package/dist/qmd-recall-cache.d.ts +1 -1
  322. package/dist/qmd.d.ts +2 -2
  323. package/dist/recall-concurrency-config.d.ts +1 -1
  324. package/dist/recall-disclosure-escalation.d.ts +1 -1
  325. package/dist/recall-explain-renderer.d.ts +1 -1
  326. package/dist/recall-memory-map.d.ts +1 -1
  327. package/dist/recall-planner-llm.d.ts +1 -1
  328. package/dist/recall-state.d.ts +1 -1
  329. package/dist/recall-tag-filter.d.ts +1 -1
  330. package/dist/recall-timings.d.ts +1 -1
  331. package/dist/recall-xray-cli.d.ts +1 -1
  332. package/dist/recall-xray-renderer.d.ts +1 -1
  333. package/dist/recall-xray.d.ts +1 -1
  334. package/dist/reconcile/cursor.d.ts +1 -1
  335. package/dist/reconcile/manifest.d.ts +1 -1
  336. package/dist/reconcile/plan.d.ts +1 -1
  337. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  338. package/dist/replay/normalizers/claude.d.ts +1 -1
  339. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  340. package/dist/replay/normalizers/shared.d.ts +1 -1
  341. package/dist/replay/runner.d.ts +1 -1
  342. package/dist/replay/types.d.ts +1 -1
  343. package/dist/replica-divergence.d.ts +1 -1
  344. package/dist/replica-peers-config.d.ts +1 -1
  345. package/dist/resolve-auth-token.d.ts +1 -1
  346. package/dist/resume-bundles.js +5 -5
  347. package/dist/retrieval-agents.d.ts +2 -2
  348. package/dist/retrieval-tiers.d.ts +1 -1
  349. package/dist/routing/engine.d.ts +1 -1
  350. package/dist/routing/store.d.ts +1 -1
  351. package/dist/salvage-envelope.d.ts +1 -1
  352. package/dist/{scope-profiles-ChZUtxDU.d.ts → scope-profiles-6ChZKTy-.d.ts} +1 -1
  353. package/dist/search/embed-helper.d.ts +1 -1
  354. package/dist/search/factory.d.ts +1 -1
  355. package/dist/search/factory.js +6 -6
  356. package/dist/search/index.d.ts +1 -1
  357. package/dist/search/index.js +10 -10
  358. package/dist/search/lancedb-backend.d.ts +1 -1
  359. package/dist/search/lancedb-backend.js +2 -2
  360. package/dist/search/meilisearch-backend.d.ts +1 -1
  361. package/dist/search/meilisearch-backend.js +2 -2
  362. package/dist/search/noop-backend.d.ts +1 -1
  363. package/dist/search/orama-backend.d.ts +1 -1
  364. package/dist/search/orama-backend.js +2 -2
  365. package/dist/search/port.d.ts +1 -1
  366. package/dist/search/remote-backend.d.ts +1 -1
  367. package/dist/{semantic-consolidation-mSPwQSmF.d.ts → semantic-consolidation-DziYcW5J.d.ts} +1 -1
  368. package/dist/semantic-consolidation.d.ts +2 -2
  369. package/dist/semantic-consolidation.js +11 -11
  370. package/dist/semantic-rule-promotion.js +10 -10
  371. package/dist/semantic-rule-verifier.d.ts +1 -1
  372. package/dist/semantic-rule-verifier.js +10 -10
  373. package/dist/{service-BICWLwSP.d.ts → service-C7rIBuK_.d.ts} +2 -2
  374. package/dist/session-observer-bands.d.ts +1 -1
  375. package/dist/session-observer-state.d.ts +1 -1
  376. package/dist/shared-context/manager.d.ts +1 -1
  377. package/dist/signal.d.ts +1 -1
  378. package/dist/source-agent-qualifier.d.ts +1 -1
  379. package/dist/source-agent-qualifier.js +10 -10
  380. package/dist/{storage-B7urx1K3.d.ts → storage-B1hEx8Xg.d.ts} +1 -1
  381. package/dist/storage.d.ts +2 -2
  382. package/dist/storage.js +9 -9
  383. package/dist/subject-config.d.ts +1 -1
  384. package/dist/summarizer.d.ts +1 -1
  385. package/dist/summary-snapshot.d.ts +1 -1
  386. package/dist/support-passport/index.d.ts +14 -14
  387. package/dist/support-passport/index.js +34 -34
  388. package/dist/temporal-supersession.d.ts +2 -2
  389. package/dist/temporal-timeline-recall.d.ts +1 -1
  390. package/dist/temporal-validity.d.ts +1 -1
  391. package/dist/threading.d.ts +1 -1
  392. package/dist/tier-migration.d.ts +2 -2
  393. package/dist/tier-routing.d.ts +1 -1
  394. package/dist/topics.d.ts +1 -1
  395. package/dist/transcript.d.ts +1 -1
  396. package/dist/transfer/backup.js +2 -2
  397. package/dist/transfer/capsule-export.js +2 -2
  398. package/dist/transfer/capsule-import.js +2 -2
  399. package/dist/trust-score-stage.d.ts +1 -1
  400. package/dist/trust-score.d.ts +1 -1
  401. package/dist/{types-ETU5N6nB.d.ts → types-BHDNxGTT.d.ts} +1 -1
  402. package/dist/types.d.ts +1 -1
  403. package/dist/utility-runtime.d.ts +1 -1
  404. package/dist/verified-recall.js +10 -10
  405. package/dist/who-knows-cli.d.ts +11 -11
  406. package/dist/who-knows-cli.js +11 -11
  407. package/dist/who-knows.d.ts +11 -11
  408. package/dist/who-knows.js +10 -10
  409. package/dist/write-envelope.d.ts +1 -1
  410. package/package.json +2 -2
  411. package/src/access-boundary.ts +5 -0
  412. package/src/access-http.ts +15 -16
  413. package/src/access-mcp-output-schemas.ts +5 -0
  414. package/src/access-mcp.ts +6 -6
  415. package/src/access-operations.ts +2 -0
  416. package/src/access-surface-catalog.ts +10 -0
  417. package/src/eval-trajectory-contracts.ts +411 -0
  418. package/src/eval-trajectory-store.ts +306 -0
  419. package/src/eval-trajectory.test.ts +534 -0
  420. package/src/eval-trajectory.ts +773 -0
  421. package/src/index.ts +2 -0
  422. package/src/location/access-operations.ts +84 -0
  423. package/src/location/http-glue.test.ts +100 -0
  424. package/src/location/http-glue.ts +85 -0
  425. package/src/location/index.ts +3 -0
  426. package/src/location/mcp-tools.ts +82 -0
  427. package/src/location/provider-setup.test.ts +106 -0
  428. package/src/location/provider-setup.ts +103 -0
  429. package/src/location/scheduler.test.ts +113 -0
  430. package/src/location/scheduler.ts +98 -0
  431. package/src/location/surfaces.test.ts +241 -0
  432. package/src/location/surfaces.ts +329 -0
  433. package/src/maintenance/day-summary-cron.ts +45 -0
  434. package/src/mcp-read-only-tools.ts +2 -0
  435. package/src/memory-worth-outcomes.test.ts +53 -18
  436. package/src/memory-worth-outcomes.ts +91 -9
  437. package/src/orchestration/maintenance.ts +22 -30
  438. package/src/wearables/http-glue.ts +28 -0
  439. package/dist/chunk-4K7IW3F7.js.map +0 -1
  440. package/dist/chunk-5W7MKXMU.js.map +0 -1
  441. package/dist/chunk-FC7TIRFS.js.map +0 -1
  442. package/dist/chunk-LDBFXD4F.js.map +0 -1
  443. package/dist/chunk-OMZLBT4B.js.map +0 -1
  444. package/dist/chunk-PNAGNVGK.js.map +0 -1
  445. package/dist/chunk-RQ2EQRRR.js.map +0 -1
  446. package/dist/chunk-YUTTMSC7.js.map +0 -1
  447. /package/dist/{capsule-crypto-GWVG7LGC.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
  448. /package/dist/{chunk-OWHERGF2.js.map → chunk-2NLLXCJG.js.map} +0 -0
  449. /package/dist/{chunk-NZPFCP5A.js.map → chunk-2PSX5BJU.js.map} +0 -0
  450. /package/dist/{chunk-W6J4POB6.js.map → chunk-3RI5Y7KU.js.map} +0 -0
  451. /package/dist/{chunk-H7BZBSP6.js.map → chunk-52II7PB6.js.map} +0 -0
  452. /package/dist/{chunk-IF4EY26E.js.map → chunk-5DH6PG4B.js.map} +0 -0
  453. /package/dist/{chunk-M4AHBM72.js.map → chunk-5HERQ5FX.js.map} +0 -0
  454. /package/dist/{chunk-IRXMJLTW.js.map → chunk-5HK3CJAR.js.map} +0 -0
  455. /package/dist/{chunk-XAWIL7TC.js.map → chunk-5S4LQOPE.js.map} +0 -0
  456. /package/dist/{chunk-IDQ6DKXC.js.map → chunk-5VPQSRQO.js.map} +0 -0
  457. /package/dist/{chunk-ROEAEANL.js.map → chunk-6CPUQ5D6.js.map} +0 -0
  458. /package/dist/{chunk-SR7JIRAR.js.map → chunk-7F27PCSN.js.map} +0 -0
  459. /package/dist/{chunk-7OZSHBWK.js.map → chunk-7TCGNUVP.js.map} +0 -0
  460. /package/dist/{chunk-KBOG7FJV.js.map → chunk-7WR462EM.js.map} +0 -0
  461. /package/dist/{chunk-AYAZWXJI.js.map → chunk-A32YEQAM.js.map} +0 -0
  462. /package/dist/{chunk-5GIZM4RX.js.map → chunk-ACOC27BB.js.map} +0 -0
  463. /package/dist/{chunk-6LS5OX3U.js.map → chunk-BJTHRFFC.js.map} +0 -0
  464. /package/dist/{chunk-PGW64IFQ.js.map → chunk-CFGU52XJ.js.map} +0 -0
  465. /package/dist/{chunk-DPNXADEI.js.map → chunk-D4QVPP3G.js.map} +0 -0
  466. /package/dist/{chunk-2RXUZVPU.js.map → chunk-EOHKUWXW.js.map} +0 -0
  467. /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
  468. /package/dist/{chunk-ZK4BFABK.js.map → chunk-F635GAL7.js.map} +0 -0
  469. /package/dist/{chunk-HWVNYNIV.js.map → chunk-F6QHHRWP.js.map} +0 -0
  470. /package/dist/{chunk-O4BAGJDN.js.map → chunk-GEPACVWN.js.map} +0 -0
  471. /package/dist/{chunk-XZBXINXZ.js.map → chunk-GIC6BASP.js.map} +0 -0
  472. /package/dist/{chunk-PP7R754B.js.map → chunk-GPFZFCRN.js.map} +0 -0
  473. /package/dist/{chunk-LSYD7GHZ.js.map → chunk-GTSVEEP3.js.map} +0 -0
  474. /package/dist/{chunk-YWBOOBDP.js.map → chunk-I7EX6KSH.js.map} +0 -0
  475. /package/dist/{chunk-3I22VWB3.js.map → chunk-IP4ZNT4U.js.map} +0 -0
  476. /package/dist/{chunk-AXGFOFNY.js.map → chunk-IY7UXD3J.js.map} +0 -0
  477. /package/dist/{chunk-6FUMA6AA.js.map → chunk-JAQXUGLN.js.map} +0 -0
  478. /package/dist/{chunk-RKNJBZ55.js.map → chunk-JBPKEARU.js.map} +0 -0
  479. /package/dist/{chunk-5W7CTZ2E.js.map → chunk-KQAFEZQX.js.map} +0 -0
  480. /package/dist/{chunk-D2YNNDML.js.map → chunk-KWIGDKM2.js.map} +0 -0
  481. /package/dist/{chunk-2JHRCWHT.js.map → chunk-LLQCM2U2.js.map} +0 -0
  482. /package/dist/{chunk-OLBZ2WGG.js.map → chunk-LTBKKSCX.js.map} +0 -0
  483. /package/dist/{chunk-RACZB5HT.js.map → chunk-N37X5RU7.js.map} +0 -0
  484. /package/dist/{chunk-FEO2CDXR.js.map → chunk-NG3MBQV4.js.map} +0 -0
  485. /package/dist/{chunk-AG46P24C.js.map → chunk-NNBZS3DY.js.map} +0 -0
  486. /package/dist/{chunk-JGG5HVI2.js.map → chunk-OPGL46PX.js.map} +0 -0
  487. /package/dist/{chunk-OUKBMQ2O.js.map → chunk-PD66CVSD.js.map} +0 -0
  488. /package/dist/{chunk-7SSRXEZJ.js.map → chunk-PDDSFELN.js.map} +0 -0
  489. /package/dist/{chunk-MVIYRRVJ.js.map → chunk-PMVPCZJZ.js.map} +0 -0
  490. /package/dist/{chunk-D35XLYQ7.js.map → chunk-RGCF4XNH.js.map} +0 -0
  491. /package/dist/{chunk-X2DWBWOX.js.map → chunk-S3K2CIK5.js.map} +0 -0
  492. /package/dist/{chunk-TWBQQ3FT.js.map → chunk-SEA6M7SS.js.map} +0 -0
  493. /package/dist/{chunk-DYO24BNB.js.map → chunk-SVVIASVX.js.map} +0 -0
  494. /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
  495. /package/dist/{chunk-NLUCDKLT.js.map → chunk-VKCAHCBI.js.map} +0 -0
  496. /package/dist/{chunk-BXXOPKT5.js.map → chunk-VXVZ2GM3.js.map} +0 -0
  497. /package/dist/{chunk-JFWZRUKP.js.map → chunk-WTOZBZNN.js.map} +0 -0
  498. /package/dist/{chunk-UVYI6VIX.js.map → chunk-X7Y7WX73.js.map} +0 -0
  499. /package/dist/{chunk-5TG4MU2U.js.map → chunk-YKWFK7XA.js.map} +0 -0
  500. /package/dist/{chunk-BIJAWZYW.js.map → chunk-YMOPYG3K.js.map} +0 -0
  501. /package/dist/{chunk-XUZ5CIEE.js.map → chunk-YRVAKONL.js.map} +0 -0
  502. /package/dist/{chunk-53MZQEBD.js.map → chunk-YWSQD2IB.js.map} +0 -0
  503. /package/dist/{chunk-US4IRASK.js.map → chunk-Z4U3UN56.js.map} +0 -0
  504. /package/dist/{chunk-QMZY3GG6.js.map → chunk-ZAOHJDKH.js.map} +0 -0
  505. /package/dist/{chunk-ZXUZ54Z5.js.map → chunk-ZIJDI4CP.js.map} +0 -0
  506. /package/dist/{graph-edge-decay-FXGELBFA.js.map → eval-trajectory-contracts.js.map} +0 -0
@@ -0,0 +1,773 @@
1
+ /**
2
+ * Issue #2345 — privacy-safe action-to-outcome trajectory evaluator (offline slice).
3
+ *
4
+ * Pure, local, deterministic evaluator that joins sanitized action rows to
5
+ * delayed outcome rows inside ONE namespace and ONE bounded time window, then
6
+ * emits a redacted shadow artifact (digests, enums, numbers, counts only).
7
+ *
8
+ * This module never:
9
+ * - reads live stores (inputs are synthetic or caller-sanitized rows),
10
+ * - calls a model or network,
11
+ * - mutates memories, counters, utility runtime, or policy decisions.
12
+ *
13
+ * Delivery note (issue "Delivery order"): schema + offline path first. The
14
+ * live `EvalTrajectoryReader` projections and eval-queue wiring arrive with
15
+ * #2348; this module ships the contract they will feed.
16
+ *
17
+ * Contracts and shared helpers live in `eval-trajectory-contracts.ts`;
18
+ * validation, persistence, and the promotion gate live in
19
+ * `eval-trajectory-store.ts`. Both are re-exported here so consumers import
20
+ * one public surface.
21
+ */
22
+
23
+ import assert from "node:assert/strict";
24
+ import {
25
+ DEFAULT_EVAL_TRAJECTORY_OUTCOME_WINDOW_MS,
26
+ EVAL_TRAJECTORY_REPORT_SCHEMA_VERSION,
27
+ type EvalActionInput,
28
+ type EvalActionOutcomeRow,
29
+ type EvalActionProjection,
30
+ type EvalOutcomeInput,
31
+ type EvalOutcomeProjection,
32
+ type EvalStaleUseEvidence,
33
+ type EvalStaleUseEvidenceInput,
34
+ type EvalTrajectoryAggregates,
35
+ type EvalTrajectoryJoinKind,
36
+ type EvalTrajectoryMetricName,
37
+ type EvalTrajectoryRejectionReason,
38
+ type EvalTrajectoryReport,
39
+ type EvalTrajectoryRowStatus,
40
+ type EvalTrajectoryRunConfig,
41
+ STALE_LIFECYCLE_STATES,
42
+ STALE_OUTCOMES,
43
+ canonicalJson,
44
+ compareRows,
45
+ compareStrings,
46
+ digestOf,
47
+ isFiniteNumber,
48
+ isIsoTimestamp,
49
+ isMemoryActionType,
50
+ isNonEmptyString,
51
+ resolveEvalTrajectoryRunConfig,
52
+ serializeEvalTrajectoryReport,
53
+ sha256Hex,
54
+ } from "./eval-trajectory-contracts.js";
55
+ import type { MemoryActionType } from "./types.js";
56
+
57
+ export {
58
+ DEFAULT_EVAL_TRAJECTORY_MAX_FUTURE_SKEW_MS,
59
+ DEFAULT_EVAL_TRAJECTORY_MAX_ROWS,
60
+ DEFAULT_EVAL_TRAJECTORY_OUTCOME_WINDOW_MS,
61
+ DEFAULT_EVAL_TRAJECTORY_REPORT_MAX_AGE_MS,
62
+ DEFAULT_EVAL_TRAJECTORY_WEIGHTS,
63
+ EVAL_TRAJECTORY_PROMOTION_THRESHOLDS,
64
+ EVAL_TRAJECTORY_REPORT_SCHEMA_VERSION,
65
+ MAX_EVAL_TRAJECTORY_ROWS_LIMIT,
66
+ resolveEvalTrajectoryRunConfig,
67
+ serializeEvalTrajectoryReport,
68
+ type EvalActionInput,
69
+ type EvalActionProjection,
70
+ type EvalOutcomeInput,
71
+ type EvalOutcomeProjection,
72
+ type EvalStaleUseEvidence,
73
+ type EvalStaleUseEvidenceInput,
74
+ type EvalStaleUseLifecycleState,
75
+ type EvalStaleUseOutcome,
76
+ type EvalTrajectoryAggregates,
77
+ type EvalTrajectoryJoinKind,
78
+ type EvalTrajectoryMetricName,
79
+ type EvalTrajectoryOutcomeSource,
80
+ type EvalTrajectoryRejectionReason,
81
+ type EvalTrajectoryReport,
82
+ type EvalTrajectoryRowStatus,
83
+ type EvalTrajectoryRunConfig,
84
+ type EvalTrajectoryTaskResult,
85
+ type EvalTrajectoryWeights,
86
+ type UnifiedMemoryPromotionReport,
87
+ type UnifiedMemoryPromotionState,
88
+ } from "./eval-trajectory-contracts.js";
89
+ export * from "./eval-trajectory-store.js";
90
+
91
+ /**
92
+ * Future live-reader seam (#2348). Must receive a trusted principal and a
93
+ * resolved namespace, verify access, and return sanitized rows only.
94
+ */
95
+ export interface EvalTrajectoryReaderResult {
96
+ actions: EvalActionInput[];
97
+ outcomes: EvalOutcomeInput[];
98
+ staleUseEvidence: EvalStaleUseEvidenceInput[];
99
+ }
100
+
101
+ export type EvalTrajectoryReader = (input: {
102
+ trustedPrincipal: string;
103
+ resolvedNamespace: string;
104
+ asOf: string;
105
+ }) => Promise<EvalTrajectoryReaderResult> | EvalTrajectoryReaderResult;
106
+
107
+ /** Synthetic reader over caller-supplied clean rows (tests, offline runs). */
108
+ export function createSyntheticEvalTrajectoryReader(rows: EvalTrajectoryReaderResult): EvalTrajectoryReader {
109
+ return () => rows;
110
+ }
111
+
112
+ // ---------------------------------------------------------------------------
113
+ // Input normalization with per-reason rejection counting
114
+ // ---------------------------------------------------------------------------
115
+
116
+ function emptyRejectionCounts(): Record<EvalTrajectoryRejectionReason, number> {
117
+ return {
118
+ missing_action_id: 0,
119
+ namespace_mismatch: 0,
120
+ invalid_timestamp: 0,
121
+ future_beyond_skew: 0,
122
+ malformed_row: 0,
123
+ invalid_context_budget: 0,
124
+ duplicate_row: 0,
125
+ max_rows_exceeded: 0,
126
+ };
127
+ }
128
+
129
+ interface NormalizeContext {
130
+ namespace: string;
131
+ namespaceDigest: string;
132
+ salt: string;
133
+ asOfMs: number;
134
+ config: EvalTrajectoryRunConfig;
135
+ rejections: Record<EvalTrajectoryRejectionReason, number>;
136
+ }
137
+
138
+ function normalizeAction(raw: unknown, context: NormalizeContext): EvalActionProjection | null {
139
+ if (typeof raw !== "object" || raw === null) {
140
+ context.rejections.malformed_row += 1;
141
+ return null;
142
+ }
143
+ const row = raw as Partial<EvalActionInput>;
144
+ if (!isNonEmptyString(row.actionId)) {
145
+ context.rejections.missing_action_id += 1;
146
+ return null;
147
+ }
148
+ if (row.namespace !== context.namespace) {
149
+ context.rejections.namespace_mismatch += 1;
150
+ return null;
151
+ }
152
+ if (!isIsoTimestamp(row.actionAt)) {
153
+ context.rejections.invalid_timestamp += 1;
154
+ return null;
155
+ }
156
+ if (Date.parse(row.actionAt) > context.asOfMs + context.config.maxFutureSkewMs) {
157
+ context.rejections.future_beyond_skew += 1;
158
+ return null;
159
+ }
160
+ if (!isMemoryActionType(row.action)) {
161
+ context.rejections.malformed_row += 1;
162
+ return null;
163
+ }
164
+ const immediateStatus = row.immediateStatus;
165
+ if (immediateStatus !== "applied" && immediateStatus !== "skipped" && immediateStatus !== "failed") {
166
+ context.rejections.malformed_row += 1;
167
+ return null;
168
+ }
169
+ if (
170
+ row.policyDecision !== undefined &&
171
+ row.policyDecision !== "allow" &&
172
+ row.policyDecision !== "defer" &&
173
+ row.policyDecision !== "deny"
174
+ ) {
175
+ context.rejections.malformed_row += 1;
176
+ return null;
177
+ }
178
+
179
+ const tokensPresent =
180
+ row.contextTokensBefore !== undefined ||
181
+ row.contextTokensAfter !== undefined ||
182
+ row.contextTokenBudget !== undefined;
183
+ let contextTokenCost: number | null = null;
184
+ if (tokensPresent) {
185
+ const before = row.contextTokensBefore;
186
+ const after = row.contextTokensAfter;
187
+ const budget = row.contextTokenBudget;
188
+ if (
189
+ (before !== undefined && (!isFiniteNumber(before) || before < 0)) ||
190
+ (after !== undefined && (!isFiniteNumber(after) || after < 0)) ||
191
+ budget === undefined ||
192
+ !isFiniteNumber(budget)
193
+ ) {
194
+ context.rejections.malformed_row += 1;
195
+ return null;
196
+ }
197
+ if (budget === 0) {
198
+ context.rejections.invalid_context_budget += 1;
199
+ return null;
200
+ }
201
+ contextTokenCost = after === undefined ? null : Math.min(1, Math.max(0, after / Math.max(1, budget)));
202
+ }
203
+
204
+ const appliedDeny = immediateStatus === "applied" && row.policyDecision === "deny";
205
+ const trustViolation: 0 | 1 =
206
+ appliedDeny || row.replayMismatch === true || row.missingReversibleGuard === true || row.outsideEligibility === true
207
+ ? 1
208
+ : 0;
209
+
210
+ return {
211
+ schemaVersion: 1,
212
+ actionDigest: digestOf(context.salt, {
213
+ kind: "action",
214
+ namespace: context.namespace,
215
+ actionId: row.actionId,
216
+ }),
217
+ namespaceDigest: context.namespaceDigest,
218
+ actionAt: row.actionAt,
219
+ action: row.action,
220
+ immediateStatus,
221
+ policyDecision: row.policyDecision ?? null,
222
+ policyVersion: isNonEmptyString(row.policyVersion) ? row.policyVersion : null,
223
+ source: isNonEmptyString(row.subsystem) ? row.subsystem : null,
224
+ actionIdDigest: digestOf(context.salt, {
225
+ kind: "actionId",
226
+ namespace: context.namespace,
227
+ actionId: row.actionId,
228
+ }),
229
+ sessionKeyDigest: isNonEmptyString(row.sessionKey)
230
+ ? digestOf(context.salt, { kind: "sessionKey", namespace: context.namespace, sessionKey: row.sessionKey })
231
+ : null,
232
+ memoryIdDigest: isNonEmptyString(row.memoryId)
233
+ ? digestOf(context.salt, { kind: "memoryId", namespace: context.namespace, memoryId: row.memoryId })
234
+ : null,
235
+ trajectoryIdDigest: isNonEmptyString(row.trajectoryId)
236
+ ? digestOf(context.salt, {
237
+ kind: "trajectoryId",
238
+ namespace: context.namespace,
239
+ trajectoryId: row.trajectoryId,
240
+ })
241
+ : null,
242
+ contextTokenCost,
243
+ trustViolation,
244
+ };
245
+ }
246
+
247
+ function normalizeOutcome(raw: unknown, context: NormalizeContext): EvalOutcomeProjection | null {
248
+ if (typeof raw !== "object" || raw === null) {
249
+ context.rejections.malformed_row += 1;
250
+ return null;
251
+ }
252
+ const row = raw as Partial<EvalOutcomeInput>;
253
+ if (!isNonEmptyString(row.outcomeId)) {
254
+ context.rejections.malformed_row += 1;
255
+ return null;
256
+ }
257
+ if (row.namespace !== context.namespace) {
258
+ context.rejections.namespace_mismatch += 1;
259
+ return null;
260
+ }
261
+ if (row.source !== "eval_artifact" && row.source !== "causal_trajectory" && row.source !== "memory_outcome") {
262
+ context.rejections.malformed_row += 1;
263
+ return null;
264
+ }
265
+ if (!isIsoTimestamp(row.outcomeAt)) {
266
+ context.rejections.invalid_timestamp += 1;
267
+ return null;
268
+ }
269
+ if (Date.parse(row.outcomeAt) > context.asOfMs + context.config.maxFutureSkewMs) {
270
+ context.rejections.future_beyond_skew += 1;
271
+ return null;
272
+ }
273
+ if (row.result !== undefined && row.result !== "success" && row.result !== "partial" && row.result !== "failure") {
274
+ context.rejections.malformed_row += 1;
275
+ return null;
276
+ }
277
+ const hasJoinKey =
278
+ isNonEmptyString(row.actionId) ||
279
+ isNonEmptyString(row.trajectoryId) ||
280
+ isNonEmptyString(row.sessionKey) ||
281
+ (isNonEmptyString(row.memoryId) && isNonEmptyString(row.sessionKey));
282
+ if (!hasJoinKey) {
283
+ context.rejections.malformed_row += 1;
284
+ return null;
285
+ }
286
+
287
+ const value =
288
+ row.result === undefined || row.source === "memory_outcome"
289
+ ? null
290
+ : row.result === "success"
291
+ ? 1
292
+ : row.result === "partial"
293
+ ? 0.5
294
+ : 0;
295
+ const ref = row.actionId ?? row.trajectoryId ?? row.memoryId ?? row.sessionKey ?? row.outcomeId;
296
+
297
+ return {
298
+ schemaVersion: 1,
299
+ outcomeDigest: digestOf(context.salt, {
300
+ kind: "outcome",
301
+ namespace: context.namespace,
302
+ outcomeId: row.outcomeId,
303
+ }),
304
+ namespaceDigest: context.namespaceDigest,
305
+ recordedAt: row.outcomeAt,
306
+ kind: row.source,
307
+ value,
308
+ sourceRefDigest: digestOf(context.salt, { kind: "sourceRef", namespace: context.namespace, ref }),
309
+ actionIdDigest: isNonEmptyString(row.actionId)
310
+ ? digestOf(context.salt, { kind: "actionId", namespace: context.namespace, actionId: row.actionId })
311
+ : null,
312
+ trajectoryIdDigest: isNonEmptyString(row.trajectoryId)
313
+ ? digestOf(context.salt, {
314
+ kind: "trajectoryId",
315
+ namespace: context.namespace,
316
+ trajectoryId: row.trajectoryId,
317
+ })
318
+ : null,
319
+ memoryIdDigest: isNonEmptyString(row.memoryId)
320
+ ? digestOf(context.salt, { kind: "memoryId", namespace: context.namespace, memoryId: row.memoryId })
321
+ : null,
322
+ sessionKeyDigest: isNonEmptyString(row.sessionKey)
323
+ ? digestOf(context.salt, { kind: "sessionKey", namespace: context.namespace, sessionKey: row.sessionKey })
324
+ : null,
325
+ };
326
+ }
327
+
328
+ function normalizeStaleEvidence(raw: unknown, context: NormalizeContext): EvalStaleUseEvidence | null {
329
+ if (typeof raw !== "object" || raw === null) {
330
+ context.rejections.malformed_row += 1;
331
+ return null;
332
+ }
333
+ const row = raw as Partial<EvalStaleUseEvidenceInput>;
334
+ if (!isNonEmptyString(row.actionId) || !isNonEmptyString(row.memoryId)) {
335
+ context.rejections.malformed_row += 1;
336
+ return null;
337
+ }
338
+ if (row.namespace !== context.namespace) {
339
+ context.rejections.namespace_mismatch += 1;
340
+ return null;
341
+ }
342
+ if (typeof row.lifecycleState !== "string" || STALE_LIFECYCLE_STATES[row.lifecycleState] !== true) {
343
+ context.rejections.malformed_row += 1;
344
+ return null;
345
+ }
346
+ if (!isIsoTimestamp(row.usedAt) || typeof row.outcome !== "string" || STALE_OUTCOMES[row.outcome] !== true) {
347
+ context.rejections.malformed_row += 1;
348
+ return null;
349
+ }
350
+ return {
351
+ schemaVersion: 1,
352
+ actionDigest: digestOf(context.salt, {
353
+ kind: "action",
354
+ namespace: context.namespace,
355
+ actionId: row.actionId,
356
+ }),
357
+ memoryDigest: digestOf(context.salt, {
358
+ kind: "memoryId",
359
+ namespace: context.namespace,
360
+ memoryId: row.memoryId,
361
+ }),
362
+ lifecycleState: row.lifecycleState,
363
+ usedAt: row.usedAt,
364
+ outcome: row.outcome,
365
+ };
366
+ }
367
+
368
+ // ---------------------------------------------------------------------------
369
+ // Join + metric core
370
+ // ---------------------------------------------------------------------------
371
+
372
+ interface JoinCandidateLevel {
373
+ kind: EvalTrajectoryJoinKind;
374
+ matches: (action: EvalActionProjection, outcome: EvalOutcomeProjection) => boolean;
375
+ }
376
+
377
+ const JOIN_LEVELS: JoinCandidateLevel[] = [
378
+ {
379
+ kind: "action_id",
380
+ matches: (action, outcome) => outcome.actionIdDigest !== null && outcome.actionIdDigest === action.actionIdDigest,
381
+ },
382
+ {
383
+ kind: "trajectory_id",
384
+ matches: (action, outcome) =>
385
+ action.trajectoryIdDigest !== null &&
386
+ outcome.trajectoryIdDigest !== null &&
387
+ outcome.trajectoryIdDigest === action.trajectoryIdDigest,
388
+ },
389
+ {
390
+ kind: "memory_scope",
391
+ matches: (action, outcome) =>
392
+ outcome.kind === "memory_outcome" &&
393
+ action.memoryIdDigest !== null &&
394
+ outcome.memoryIdDigest !== null &&
395
+ outcome.memoryIdDigest === action.memoryIdDigest &&
396
+ action.sessionKeyDigest !== null &&
397
+ outcome.sessionKeyDigest !== null &&
398
+ outcome.sessionKeyDigest === action.sessionKeyDigest,
399
+ },
400
+ {
401
+ kind: "session_scope",
402
+ matches: (action, outcome) =>
403
+ outcome.kind !== "memory_outcome" &&
404
+ action.sessionKeyDigest !== null &&
405
+ outcome.sessionKeyDigest !== null &&
406
+ outcome.sessionKeyDigest === action.sessionKeyDigest,
407
+ },
408
+ ];
409
+
410
+ /** Half-open delayed window: `actionAt < outcomeAt < actionAt + outcomeWindowMs`. */
411
+ function outcomeInWindow(
412
+ action: EvalActionProjection,
413
+ outcome: EvalOutcomeProjection,
414
+ config: EvalTrajectoryRunConfig
415
+ ): boolean {
416
+ const outcomeMs = Date.parse(outcome.recordedAt);
417
+ return Date.parse(action.actionAt) < outcomeMs && outcomeMs < Date.parse(action.actionAt) + config.outcomeWindowMs;
418
+ }
419
+
420
+ function anyKeyMatch(action: EvalActionProjection, outcome: EvalOutcomeProjection): boolean {
421
+ return JOIN_LEVELS.some((level) => level.matches(action, outcome));
422
+ }
423
+
424
+ function staleHarmFor(action: EvalActionProjection, evidence: EvalStaleUseEvidence[]): 0 | 0.5 | 1 {
425
+ let harm: 0 | 0.5 | 1 = 0;
426
+ for (const item of evidence) {
427
+ if (item.actionDigest !== action.actionDigest) continue;
428
+ if (item.lifecycleState !== "stale" && item.lifecycleState !== "archived") continue;
429
+ if (Date.parse(item.usedAt) <= Date.parse(action.actionAt)) continue;
430
+ if (item.outcome === "failure") return 1;
431
+ if (item.outcome === "partial" || item.outcome === "unknown") harm = 0.5;
432
+ }
433
+ return harm;
434
+ }
435
+
436
+ function buildRow(
437
+ action: EvalActionProjection,
438
+ outcomes: EvalOutcomeProjection[],
439
+ evidence: EvalStaleUseEvidence[],
440
+ config: EvalTrajectoryRunConfig,
441
+ asOfMs: number
442
+ ): EvalActionOutcomeRow {
443
+ let selected: EvalOutcomeProjection | null = null;
444
+ let joinKind: EvalTrajectoryJoinKind | null = null;
445
+ let ambiguous = false;
446
+
447
+ for (const level of JOIN_LEVELS) {
448
+ const inWindow = outcomes.filter(
449
+ (outcome) =>
450
+ level.matches(action, outcome) &&
451
+ outcomeInWindow(action, outcome, config) &&
452
+ Date.parse(outcome.recordedAt) <= asOfMs
453
+ );
454
+ if (inWindow.length === 1) {
455
+ selected = inWindow[0] ?? null;
456
+ joinKind = level.kind;
457
+ break;
458
+ }
459
+ if (inWindow.length > 1) {
460
+ ambiguous = true;
461
+ joinKind = level.kind;
462
+ break;
463
+ }
464
+ }
465
+
466
+ let status: EvalTrajectoryRowStatus;
467
+ let outcomeDigest: string | null = null;
468
+ let outcomeRecordedAt: string | null = null;
469
+ let lateProjection: EvalOutcomeProjection | null = null;
470
+ if (ambiguous) {
471
+ status = "ambiguous";
472
+ } else if (selected !== null) {
473
+ status = "joined";
474
+ outcomeDigest = selected.outcomeDigest;
475
+ outcomeRecordedAt = selected.recordedAt;
476
+ } else {
477
+ const keyMatches = outcomes.filter((outcome) => anyKeyMatch(action, outcome));
478
+ // Prefer the in-data off-window result when one exists; a future result
479
+ // (recorded after asOf) is reported but never matched.
480
+ const lateCandidates = keyMatches
481
+ .filter(
482
+ (outcome) =>
483
+ Date.parse(outcome.recordedAt) >= Date.parse(action.actionAt) + config.outcomeWindowMs &&
484
+ Date.parse(outcome.recordedAt) <= asOfMs
485
+ )
486
+ .sort((a, b) => compareStrings(a.recordedAt, b.recordedAt));
487
+ lateProjection = lateCandidates.length > 0 ? (lateCandidates[lateCandidates.length - 1] ?? null) : null;
488
+ if (lateProjection !== null) {
489
+ status = "late_outcome";
490
+ outcomeDigest = lateProjection.outcomeDigest;
491
+ outcomeRecordedAt = lateProjection.recordedAt;
492
+ } else if (keyMatches.some((outcome) => Date.parse(outcome.recordedAt) > asOfMs)) {
493
+ status = "future_outcome";
494
+ } else {
495
+ status = "missing_within_window";
496
+ }
497
+ }
498
+
499
+ // Only task-source outcomes carry a task value; memory outcomes never do.
500
+ const matched = selected ?? (status === "late_outcome" ? lateProjection : null);
501
+ const taskOutcome: number | null =
502
+ status === "joined" || status === "late_outcome"
503
+ ? matched !== null && matched.kind !== "memory_outcome"
504
+ ? matched.value
505
+ : null
506
+ : null;
507
+
508
+ const staleMemoryHarm = staleHarmFor(action, evidence);
509
+ const weights = config.weights;
510
+ const missingDimensions: EvalTrajectoryMetricName[] = [];
511
+ if (taskOutcome === null && weights.task > 0) missingDimensions.push("taskOutcome");
512
+ if (action.contextTokenCost === null && weights.context > 0) missingDimensions.push("contextTokenCost");
513
+
514
+ const actionConditionedUtility =
515
+ status !== "joined" || missingDimensions.length > 0
516
+ ? null
517
+ : Math.min(
518
+ 1,
519
+ Math.max(
520
+ -1,
521
+ weights.task * (taskOutcome ?? 0) -
522
+ weights.context * (action.contextTokenCost ?? 0) -
523
+ weights.trust * action.trustViolation -
524
+ weights.stale * staleMemoryHarm
525
+ )
526
+ );
527
+
528
+ return {
529
+ schemaVersion: 1,
530
+ actionDigest: action.actionDigest,
531
+ outcomeDigest: status === "future_outcome" ? null : outcomeDigest,
532
+ join: status === "joined" || status === "ambiguous" ? joinKind : null,
533
+ status,
534
+ outcomeRecordedAt: status === "future_outcome" ? null : outcomeRecordedAt,
535
+ taskOutcome,
536
+ contextTokenCost: action.contextTokenCost,
537
+ trustViolation: action.trustViolation,
538
+ staleMemoryHarm,
539
+ actionConditionedUtility,
540
+ missingDimensions,
541
+ };
542
+ }
543
+
544
+ // ---------------------------------------------------------------------------
545
+ // Report builder (pure — no I/O, no model, no memory writes)
546
+ // ---------------------------------------------------------------------------
547
+
548
+ export interface BuildEvalTrajectoryReportOptions {
549
+ /** Single resolved namespace for the whole run. Never "all namespaces". */
550
+ namespace: string;
551
+ asOf: string;
552
+ /** Per-run salt. Required, never exported. */
553
+ salt: string;
554
+ actions: unknown[];
555
+ outcomes?: unknown[];
556
+ staleUseEvidence?: unknown[];
557
+ config?: Partial<EvalTrajectoryRunConfig>;
558
+ }
559
+
560
+ export function buildEvalTrajectoryReport(options: BuildEvalTrajectoryReportOptions): EvalTrajectoryReport {
561
+ if (!isNonEmptyString(options.namespace)) throw new Error("eval trajectory run requires a namespace");
562
+ if (!isNonEmptyString(options.salt)) throw new Error("eval trajectory run requires a salt");
563
+ if (!isIsoTimestamp(options.asOf)) throw new Error("asOf must be a normalized ISO-8601 UTC timestamp");
564
+ const config = resolveEvalTrajectoryRunConfig(options.config);
565
+ const asOfMs = Date.parse(options.asOf);
566
+ const context: NormalizeContext = {
567
+ namespace: options.namespace,
568
+ namespaceDigest: digestOf(options.salt, { kind: "namespace", namespace: options.namespace }),
569
+ salt: options.salt,
570
+ asOfMs,
571
+ config,
572
+ rejections: emptyRejectionCounts(),
573
+ };
574
+
575
+ const actions: EvalActionProjection[] = [];
576
+ const seenActionDigests = new Set<string>();
577
+ for (const raw of options.actions ?? []) {
578
+ const projection = normalizeAction(raw, context);
579
+ if (projection === null) continue;
580
+ if (seenActionDigests.has(projection.actionDigest)) {
581
+ context.rejections.duplicate_row += 1;
582
+ continue;
583
+ }
584
+ seenActionDigests.add(projection.actionDigest);
585
+ actions.push(projection);
586
+ }
587
+ actions.sort((a, b) => compareStrings(a.actionDigest, b.actionDigest));
588
+ if (actions.length > config.maxRows) {
589
+ context.rejections.max_rows_exceeded += actions.length - config.maxRows;
590
+ actions.length = config.maxRows;
591
+ }
592
+
593
+ const outcomes: EvalOutcomeProjection[] = [];
594
+ const seenOutcomeDigests = new Set<string>();
595
+ for (const raw of options.outcomes ?? []) {
596
+ const projection = normalizeOutcome(raw, context);
597
+ if (projection === null) continue;
598
+ if (seenOutcomeDigests.has(projection.outcomeDigest)) {
599
+ context.rejections.duplicate_row += 1;
600
+ continue;
601
+ }
602
+ seenOutcomeDigests.add(projection.outcomeDigest);
603
+ outcomes.push(projection);
604
+ }
605
+ outcomes.sort((a, b) => compareStrings(a.outcomeDigest, b.outcomeDigest));
606
+
607
+ const evidence: EvalStaleUseEvidence[] = [];
608
+ for (const raw of options.staleUseEvidence ?? []) {
609
+ const projection = normalizeStaleEvidence(raw, context);
610
+ if (projection !== null) evidence.push(projection);
611
+ }
612
+ evidence.sort((a, b) => {
613
+ const byUsedAt = compareStrings(a.usedAt, b.usedAt);
614
+ if (byUsedAt !== 0) return byUsedAt;
615
+ return compareStrings(a.memoryDigest, b.memoryDigest);
616
+ });
617
+
618
+ const rows = actions.map((action) => buildRow(action, outcomes, evidence, config, asOfMs));
619
+ rows.sort(compareRows);
620
+
621
+ const inputFingerprint = sha256Hex(
622
+ canonicalJson({
623
+ schemaVersion: EVAL_TRAJECTORY_REPORT_SCHEMA_VERSION,
624
+ namespace: options.namespace,
625
+ asOf: options.asOf,
626
+ salt: options.salt,
627
+ config,
628
+ actions,
629
+ outcomes,
630
+ evidence,
631
+ })
632
+ );
633
+ const reportId = sha256Hex(
634
+ canonicalJson({
635
+ kind: "eval-trajectory-report",
636
+ inputFingerprint,
637
+ namespaceDigest: context.namespaceDigest,
638
+ asOf: options.asOf,
639
+ })
640
+ );
641
+
642
+ const report: EvalTrajectoryReport = {
643
+ schemaVersion: EVAL_TRAJECTORY_REPORT_SCHEMA_VERSION,
644
+ reportId,
645
+ namespaceDigest: context.namespaceDigest,
646
+ asOf: options.asOf,
647
+ config,
648
+ sourceCounts: { actions: actions.length, outcomes: outcomes.length, staleUseEvidence: evidence.length },
649
+ rejectionCounts: context.rejections,
650
+ rows,
651
+ aggregates: computeAggregates(rows, actions),
652
+ inputFingerprint,
653
+ contentHash: "",
654
+ };
655
+ report.contentHash = sha256Hex(canonicalJson({ ...report, contentHash: undefined }));
656
+ return report;
657
+ }
658
+
659
+ function computeAggregates(rows: EvalActionOutcomeRow[], actions: EvalActionProjection[]): EvalTrajectoryAggregates {
660
+ const statusCounts: Record<EvalTrajectoryRowStatus, number> = {
661
+ joined: 0,
662
+ ambiguous: 0,
663
+ late_outcome: 0,
664
+ future_outcome: 0,
665
+ missing_within_window: 0,
666
+ };
667
+ for (const row of rows) statusCounts[row.status] += 1;
668
+
669
+ const digestToAction = new Map(actions.map((action) => [action.actionDigest, action]));
670
+ const joinedRows = rows.filter((row) => row.status === "joined");
671
+ const mean = (values: number[]): number | null =>
672
+ values.length === 0 ? null : values.reduce((sum, value) => sum + value, 0) / values.length;
673
+
674
+ interface GroupTally {
675
+ rowCount: number;
676
+ utilitySum: number;
677
+ utilityCount: number;
678
+ }
679
+ const bump = (map: Map<string, GroupTally>, key: string, utility: number | null): void => {
680
+ const tally = map.get(key) ?? { rowCount: 0, utilitySum: 0, utilityCount: 0 };
681
+ tally.rowCount += 1;
682
+ if (utility !== null) {
683
+ tally.utilitySum += utility;
684
+ tally.utilityCount += 1;
685
+ }
686
+ map.set(key, tally);
687
+ };
688
+ const byActionMap = new Map<string, GroupTally>();
689
+ const byPolicyMap = new Map<string, GroupTally>();
690
+ for (const row of joinedRows) {
691
+ const action = digestToAction.get(row.actionDigest);
692
+ if (!action) continue;
693
+ bump(byActionMap, action.action, row.actionConditionedUtility);
694
+ bump(byPolicyMap, action.policyDecision ?? "unrecorded", row.actionConditionedUtility);
695
+ }
696
+
697
+ const reachDenominator = rows.length - statusCounts.future_outcome;
698
+ return {
699
+ rowCount: rows.length,
700
+ statusCounts,
701
+ metricMeans: {
702
+ taskOutcome: mean(joinedRows.map((row) => row.taskOutcome).filter(isFiniteNumber)),
703
+ contextTokenCost: mean(joinedRows.map((row) => row.contextTokenCost).filter(isFiniteNumber)),
704
+ trustViolation: mean(joinedRows.map((row) => row.trustViolation).filter(isFiniteNumber)),
705
+ staleMemoryHarm: mean(joinedRows.map((row) => row.staleMemoryHarm).filter(isFiniteNumber)),
706
+ actionConditionedUtility: mean(joinedRows.map((row) => row.actionConditionedUtility).filter(isFiniteNumber)),
707
+ },
708
+ coverage: {
709
+ reach: reachDenominator > 0 ? statusCounts.joined / reachDenominator : null,
710
+ joined: statusCounts.joined,
711
+ missingWithinWindow: statusCounts.missing_within_window,
712
+ lateOutcome: statusCounts.late_outcome,
713
+ futureOutcome: statusCounts.future_outcome,
714
+ ambiguous: statusCounts.ambiguous,
715
+ excludedFromMeans: rows.length - statusCounts.joined,
716
+ },
717
+ byAction: [...byActionMap.entries()]
718
+ .sort(([a], [b]) => compareStrings(a, b))
719
+ .map(([action, tally]) => ({
720
+ action: action as MemoryActionType,
721
+ rowCount: tally.rowCount,
722
+ meanUtility: tally.utilityCount > 0 ? tally.utilitySum / tally.utilityCount : null,
723
+ })),
724
+ byPolicyDecision: [...byPolicyMap.entries()]
725
+ .sort(([a], [b]) => compareStrings(a, b))
726
+ .map(([policyDecision, tally]) => ({
727
+ policyDecision,
728
+ rowCount: tally.rowCount,
729
+ meanUtility: tally.utilityCount > 0 ? tally.utilitySum / tally.utilityCount : null,
730
+ })),
731
+ };
732
+ }
733
+
734
+ // ---------------------------------------------------------------------------
735
+ // Self-check (minimal made-up fixture): npx tsx packages/remnic-core/src/eval-trajectory.ts
736
+ // ---------------------------------------------------------------------------
737
+
738
+ if (process.argv[1]?.endsWith("eval-trajectory.ts") === true) {
739
+ const report = buildEvalTrajectoryReport({
740
+ namespace: "self-check",
741
+ asOf: "2026-08-15T00:00:00.000Z",
742
+ salt: "self-check-salt",
743
+ actions: [
744
+ {
745
+ schemaVersion: 1,
746
+ actionId: "act-1",
747
+ namespace: "self-check",
748
+ actionAt: "2026-08-10T00:00:00.000Z",
749
+ action: "store_note",
750
+ immediateStatus: "applied",
751
+ sessionKey: "agent:main",
752
+ },
753
+ ],
754
+ outcomes: [
755
+ {
756
+ schemaVersion: 1,
757
+ namespace: "self-check",
758
+ outcomeId: "out-1",
759
+ outcomeAt: "2026-08-12T00:00:00.000Z",
760
+ source: "causal_trajectory",
761
+ result: "partial",
762
+ sessionKey: "agent:main",
763
+ },
764
+ ],
765
+ });
766
+ const row = report.rows[0];
767
+ assert.equal(row?.status, "joined", "self-check row must join");
768
+ assert.equal(row?.taskOutcome, 0.5, "partial must score 0.5");
769
+ assert.equal(report.aggregates.coverage.reach, 1, "reach must be 1");
770
+ assert.ok(serializeEvalTrajectoryReport(report).includes('"contentHash"'), "report must serialize");
771
+ assert.ok(DEFAULT_EVAL_TRAJECTORY_OUTCOME_WINDOW_MS === 604_800_000, "default window must stay 7 days");
772
+ console.log("eval-trajectory self-check OK");
773
+ }