@remnic/core 9.7.10 → 9.7.12

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 (297) hide show
  1. package/dist/access-admin-ops-surface.d.ts +6 -6
  2. package/dist/access-admin-ops-surface.js +7 -7
  3. package/dist/access-boundary.d.ts +7 -7
  4. package/dist/access-boundary.js +8 -8
  5. package/dist/access-cli.js +31 -31
  6. package/dist/access-http.d.ts +8 -7
  7. package/dist/access-http.js +12 -12
  8. package/dist/access-identity-continuity-surface.d.ts +5 -5
  9. package/dist/access-identity-continuity-surface.js +7 -7
  10. package/dist/access-lcm-surface.d.ts +6 -6
  11. package/dist/access-lcm-surface.js +7 -7
  12. package/dist/access-mcp.d.ts +6 -6
  13. package/dist/access-mcp.js +11 -11
  14. package/dist/access-observe-write-surface.d.ts +6 -6
  15. package/dist/access-observe-write-surface.js +7 -7
  16. package/dist/access-operations-batch.js +9 -9
  17. package/dist/access-operations.d.ts +10 -10
  18. package/dist/access-operations.js +10 -10
  19. package/dist/access-recall-surface.d.ts +6 -6
  20. package/dist/access-recall-surface.js +7 -7
  21. package/dist/access-schema.d.ts +64 -64
  22. package/dist/{access-service-DSuzikHQ.d.ts → access-service-tHd3eQpd.d.ts} +4 -4
  23. package/dist/access-service.d.ts +6 -6
  24. package/dist/access-service.js +7 -7
  25. package/dist/access-surface-catalog.d.ts +6 -6
  26. package/dist/access-surface-catalog.js +2 -0
  27. package/dist/access-surface-catalog.js.map +1 -1
  28. package/dist/action-confidence.d.ts +1 -1
  29. package/dist/active-memory-bridge.d.ts +1 -1
  30. package/dist/active-recall.d.ts +1 -1
  31. package/dist/active-recall.js +1 -1
  32. package/dist/behavior-learner.d.ts +1 -1
  33. package/dist/behavior-signals.d.ts +1 -1
  34. package/dist/bootstrap.d.ts +5 -5
  35. package/dist/briefing.d.ts +2 -2
  36. package/dist/briefing.js +3 -3
  37. package/dist/buffer-surprise-report.d.ts +1 -1
  38. package/dist/buffer.d.ts +2 -2
  39. package/dist/bulk-import/index.d.ts +3 -3
  40. package/dist/calibration.d.ts +1 -1
  41. package/dist/capabilities.d.ts +1 -1
  42. package/dist/{catalog-BNwjACa5.d.ts → catalog-DEMiw6HZ.d.ts} +48 -1
  43. package/dist/causal-behavior.d.ts +1 -1
  44. package/dist/causal-consolidation.d.ts +1 -1
  45. package/dist/causal-consolidation.js +4 -4
  46. package/dist/causal-trajectory-graph.d.ts +1 -1
  47. package/dist/{chunk-U4KHQTJ6.js → chunk-2AL7N3BH.js} +4 -2
  48. package/dist/{chunk-U4KHQTJ6.js.map → chunk-2AL7N3BH.js.map} +1 -1
  49. package/dist/{chunk-L4H6MQ7I.js → chunk-2RSL6YRA.js} +2 -2
  50. package/dist/{chunk-7EX4YOKH.js → chunk-2ZPQUTMW.js} +4 -4
  51. package/dist/{chunk-673NPXE3.js → chunk-3SIC3E65.js} +2 -2
  52. package/dist/{chunk-OVMS3DCB.js → chunk-675YU5IK.js} +2 -2
  53. package/dist/{chunk-7LMEY5KZ.js → chunk-6N7R7TR2.js} +34 -1
  54. package/dist/chunk-6N7R7TR2.js.map +1 -0
  55. package/dist/{chunk-7CKS4AXY.js → chunk-AOWPZ7TM.js} +17 -17
  56. package/dist/{chunk-TGBJ2OMK.js → chunk-BQTSGK5Y.js} +2 -2
  57. package/dist/{chunk-UZRIKUFS.js → chunk-CE3GMHT4.js} +4 -2
  58. package/dist/chunk-CE3GMHT4.js.map +1 -0
  59. package/dist/{chunk-YXOAQAH2.js → chunk-CLFY35ED.js} +3 -3
  60. package/dist/{chunk-HQ7QZJM5.js → chunk-D4TLWDYR.js} +2 -2
  61. package/dist/{chunk-LQKITFGB.js → chunk-FUUF7FMX.js} +2 -2
  62. package/dist/{chunk-3ZVFLMFQ.js → chunk-G5PVJJRA.js} +1 -1
  63. package/dist/chunk-G5PVJJRA.js.map +1 -0
  64. package/dist/{chunk-MXRMNKSY.js → chunk-I3GKTDM2.js} +3 -3
  65. package/dist/{chunk-EQF5763Z.js → chunk-IQULRIZM.js} +2 -2
  66. package/dist/{chunk-DJCKXI4M.js → chunk-NVXQTRBL.js} +2 -2
  67. package/dist/{chunk-VDLMAJXS.js → chunk-OCY3CRPG.js} +3 -3
  68. package/dist/{chunk-YLTG6BO4.js → chunk-OIFZII6J.js} +2 -2
  69. package/dist/{chunk-XF4KOVDK.js → chunk-PA6DMYEK.js} +6 -6
  70. package/dist/{chunk-3OQ4IZJN.js → chunk-QPZCAVDC.js} +7 -7
  71. package/dist/{chunk-DLWYAN6A.js → chunk-T6U7HDIY.js} +2 -2
  72. package/dist/chunk-TITSEN2M.js +1794 -0
  73. package/dist/chunk-TITSEN2M.js.map +1 -0
  74. package/dist/{chunk-JZM5QUTE.js → chunk-TMGK6YE7.js} +171 -9
  75. package/dist/chunk-TMGK6YE7.js.map +1 -0
  76. package/dist/{chunk-KXLRMM35.js → chunk-TRH533CA.js} +30 -7
  77. package/dist/chunk-TRH533CA.js.map +1 -0
  78. package/dist/{chunk-UTDA43TB.js → chunk-TWGGNUWJ.js} +2 -2
  79. package/dist/{chunk-SBFDL2EQ.js → chunk-UTZW3X2R.js} +2 -2
  80. package/dist/{chunk-SECMZACR.js → chunk-XUQUBZ7O.js} +2 -2
  81. package/dist/{chunk-N3LWQJ6Y.js → chunk-YI7XUXLX.js} +309 -16
  82. package/dist/chunk-YI7XUXLX.js.map +1 -0
  83. package/dist/{chunk-QVALQE4P.js → chunk-ZASJ53ML.js} +128 -10
  84. package/dist/chunk-ZASJ53ML.js.map +1 -0
  85. package/dist/{chunk-WUDBMLC6.js → chunk-ZC3HG22I.js} +2 -2
  86. package/dist/{chunk-VCEH5UYS.js → chunk-ZRXSHGXT.js} +2 -2
  87. package/dist/{cli-DACyuK8-.d.ts → cli-D8Tsa4Sh.d.ts} +5 -5
  88. package/dist/cli.d.ts +8 -8
  89. package/dist/cli.js +25 -25
  90. package/dist/compounding/engine.d.ts +2 -2
  91. package/dist/compounding/engine.js +3 -3
  92. package/dist/compounding/preference-consolidator.d.ts +1 -1
  93. package/dist/compression-optimizer.d.ts +1 -1
  94. package/dist/config.d.ts +1 -1
  95. package/dist/config.js +1 -1
  96. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  97. package/dist/connectors/codex-materialize-runner.js +3 -3
  98. package/dist/connectors/codex-materialize.d.ts +1 -1
  99. package/dist/connectors/index.d.ts +1 -1
  100. package/dist/connectors/index.js +3 -3
  101. package/dist/consolidation-provenance-check.d.ts +2 -2
  102. package/dist/consolidation-undo.d.ts +2 -2
  103. package/dist/contradiction/index.d.ts +2 -2
  104. package/dist/conversation-index/backend.d.ts +1 -1
  105. package/dist/conversation-index/chunker.d.ts +1 -1
  106. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  107. package/dist/conversation-index/indexer.d.ts +1 -1
  108. package/dist/conversation-index/search.d.ts +1 -1
  109. package/dist/day-summary.d.ts +1 -1
  110. package/dist/delinearize.d.ts +1 -1
  111. package/dist/direct-answer-wiring.d.ts +1 -1
  112. package/dist/direct-answer.d.ts +1 -1
  113. package/dist/embedding-fallback.d.ts +1 -1
  114. package/dist/enrichment/index.d.ts +1 -1
  115. package/dist/entity-retrieval.d.ts +2 -2
  116. package/dist/entity-retrieval.js +3 -3
  117. package/dist/entity-schema.d.ts +1 -1
  118. package/dist/explicit-capture.d.ts +5 -5
  119. package/dist/extraction-faithfulness.d.ts +1 -1
  120. package/dist/extraction-judge-telemetry.d.ts +1 -1
  121. package/dist/extraction-judge-training.d.ts +1 -1
  122. package/dist/extraction-judge.d.ts +1 -1
  123. package/dist/extraction.d.ts +1 -1
  124. package/dist/fallback-llm.d.ts +1 -1
  125. package/dist/graph-dashboard-diff.d.ts +1 -1
  126. package/dist/graph-dashboard-key.d.ts +1 -1
  127. package/dist/graph-dashboard-parser.d.ts +1 -1
  128. package/dist/graph-edge-reinforcement.d.ts +1 -1
  129. package/dist/graph-snapshot.d.ts +1 -1
  130. package/dist/graph.d.ts +1 -1
  131. package/dist/identity-continuity.d.ts +1 -1
  132. package/dist/importance.d.ts +1 -1
  133. package/dist/importers/index.d.ts +1 -1
  134. package/dist/in-flight-reads.d.ts +1 -1
  135. package/dist/index.d.ts +4002 -16
  136. package/dist/index.js +78 -31
  137. package/dist/intent.d.ts +1 -1
  138. package/dist/lcm/engine.d.ts +1 -1
  139. package/dist/lcm/index.d.ts +1 -1
  140. package/dist/lcm/tools.d.ts +1 -1
  141. package/dist/lifecycle.d.ts +1 -1
  142. package/dist/live-connectors-runner.d.ts +1 -1
  143. package/dist/local-llm.d.ts +1 -1
  144. package/dist/local-model-endpoint.d.ts +1 -1
  145. package/dist/maintenance/memory-governance.d.ts +1 -1
  146. package/dist/maintenance/memory-governance.js +3 -3
  147. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  148. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  149. package/dist/mcp-memory-inspector-app.d.ts +6 -6
  150. package/dist/memory-action-policy.d.ts +1 -1
  151. package/dist/memory-cache.d.ts +1 -1
  152. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  153. package/dist/memory-projection-store.d.ts +1 -1
  154. package/dist/memory-provenance.d.ts +1 -1
  155. package/dist/memory-worth-outcomes.d.ts +2 -2
  156. package/dist/models-json.d.ts +1 -1
  157. package/dist/namespaces/migrate.d.ts +3 -3
  158. package/dist/namespaces/migrate.js +4 -4
  159. package/dist/namespaces/principal.d.ts +1 -1
  160. package/dist/namespaces/search.d.ts +1 -1
  161. package/dist/namespaces/storage.d.ts +3 -3
  162. package/dist/namespaces/storage.js +3 -3
  163. package/dist/native-knowledge.d.ts +1 -1
  164. package/dist/operator-toolkit.d.ts +2 -2
  165. package/dist/operator-toolkit.js +8 -8
  166. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  167. package/dist/orchestration/maintenance.d.ts +2 -2
  168. package/dist/orchestration/maintenance.js +5 -5
  169. package/dist/{orchestrator-D83AvrPf.d.ts → orchestrator-B_WXBmuE.d.ts} +4 -4
  170. package/dist/orchestrator.d.ts +5 -5
  171. package/dist/orchestrator.js +31 -31
  172. package/dist/patterns-cli.d.ts +1 -1
  173. package/dist/{pipeline-BSqGpYl1.d.ts → pipeline-Dvtvt141.d.ts} +1 -1
  174. package/dist/policy-runtime.d.ts +1 -1
  175. package/dist/provenance.d.ts +1 -1
  176. package/dist/{qmd-CutnpRVe.d.ts → qmd-DwBLh_hl.d.ts} +1 -1
  177. package/dist/qmd-preflight.d.ts +2 -2
  178. package/dist/qmd-recall-cache.d.ts +1 -1
  179. package/dist/qmd.d.ts +2 -2
  180. package/dist/recall-disclosure-escalation.d.ts +1 -1
  181. package/dist/recall-explain-renderer.d.ts +1 -1
  182. package/dist/recall-explain-renderer.js +3 -3
  183. package/dist/recall-planner-llm.d.ts +1 -1
  184. package/dist/recall-state.d.ts +1 -1
  185. package/dist/recall-tag-filter.d.ts +1 -1
  186. package/dist/recall-timings.d.ts +1 -1
  187. package/dist/recall-xray-cli.d.ts +1 -1
  188. package/dist/recall-xray-cli.js +4 -4
  189. package/dist/recall-xray-renderer.d.ts +1 -1
  190. package/dist/recall-xray-renderer.js +3 -3
  191. package/dist/recall-xray.d.ts +1 -1
  192. package/dist/recall-xray.js +2 -2
  193. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  194. package/dist/replay/normalizers/claude.d.ts +1 -1
  195. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  196. package/dist/replay/normalizers/shared.d.ts +1 -1
  197. package/dist/replay/runner.d.ts +1 -1
  198. package/dist/replay/types.d.ts +1 -1
  199. package/dist/resolve-auth-token.d.ts +1 -1
  200. package/dist/resume-bundles.js +2 -2
  201. package/dist/retrieval-agents.d.ts +2 -2
  202. package/dist/retrieval-tiers.d.ts +1 -1
  203. package/dist/routing/engine.d.ts +1 -1
  204. package/dist/routing/store.d.ts +1 -1
  205. package/dist/schemas.d.ts +52 -52
  206. package/dist/search/embed-helper.d.ts +1 -1
  207. package/dist/search/factory.d.ts +1 -1
  208. package/dist/search/index.d.ts +1 -1
  209. package/dist/search/lancedb-backend.d.ts +1 -1
  210. package/dist/search/meilisearch-backend.d.ts +1 -1
  211. package/dist/search/noop-backend.d.ts +1 -1
  212. package/dist/search/orama-backend.d.ts +1 -1
  213. package/dist/search/port.d.ts +1 -1
  214. package/dist/search/remote-backend.d.ts +1 -1
  215. package/dist/{semantic-consolidation-btIVRC4l.d.ts → semantic-consolidation-Dia_6FOn.d.ts} +1 -1
  216. package/dist/semantic-consolidation.d.ts +2 -2
  217. package/dist/semantic-consolidation.js +4 -4
  218. package/dist/semantic-rule-promotion.js +3 -3
  219. package/dist/semantic-rule-verifier.d.ts +1 -1
  220. package/dist/semantic-rule-verifier.js +3 -3
  221. package/dist/session-observer-bands.d.ts +1 -1
  222. package/dist/session-observer-state.d.ts +1 -1
  223. package/dist/shared-context/manager.d.ts +9 -9
  224. package/dist/signal.d.ts +1 -1
  225. package/dist/{storage-BVv_Mqa0.d.ts → storage-RshM7i8-.d.ts} +18 -1
  226. package/dist/storage.d.ts +2 -2
  227. package/dist/storage.js +2 -2
  228. package/dist/summarizer.d.ts +1 -1
  229. package/dist/summary-snapshot.d.ts +1 -1
  230. package/dist/temporal-supersession.d.ts +2 -2
  231. package/dist/temporal-timeline-recall.d.ts +1 -1
  232. package/dist/temporal-validity.d.ts +1 -1
  233. package/dist/threading.d.ts +1 -1
  234. package/dist/tier-migration.d.ts +2 -2
  235. package/dist/tier-routing.d.ts +1 -1
  236. package/dist/topics.d.ts +1 -1
  237. package/dist/transcript.d.ts +1 -1
  238. package/dist/transfer/types.d.ts +66 -66
  239. package/dist/trust-score-stage.d.ts +1 -1
  240. package/dist/trust-score.d.ts +1 -1
  241. package/dist/{types-Cmkz7csa.d.ts → types-CHSXOq7s.d.ts} +34 -0
  242. package/dist/types.d.ts +1 -1
  243. package/dist/types.js +1 -1
  244. package/dist/utility-runtime.d.ts +1 -1
  245. package/dist/verified-recall.js +3 -3
  246. package/package.json +2 -2
  247. package/src/access-boundary.ts +2 -0
  248. package/src/access-http.ts +147 -6
  249. package/src/access-mcp-cancellation.test.ts +2 -2
  250. package/src/access-operations.ts +2 -0
  251. package/src/access-surface-catalog.ts +2 -0
  252. package/src/config.test.ts +44 -0
  253. package/src/config.ts +43 -0
  254. package/src/index.ts +53 -0
  255. package/src/namespaces/catalog.test.ts +258 -0
  256. package/src/namespaces/catalog.ts +235 -10
  257. package/src/namespaces/storage.ts +9 -0
  258. package/src/orchestrator.ts +3 -0
  259. package/src/relay/mission-access.test.ts +379 -0
  260. package/src/relay/mission-access.ts +125 -0
  261. package/src/relay/mission-fixture.ts +301 -0
  262. package/src/relay/mission.test.ts +964 -0
  263. package/src/relay/mission.ts +1725 -0
  264. package/src/storage-catalog-touch-gating.test.ts +70 -0
  265. package/src/storage.ts +31 -5
  266. package/src/types.ts +34 -0
  267. package/dist/chunk-3ZVFLMFQ.js.map +0 -1
  268. package/dist/chunk-7LMEY5KZ.js.map +0 -1
  269. package/dist/chunk-FNJX2O6G.js +0 -467
  270. package/dist/chunk-FNJX2O6G.js.map +0 -1
  271. package/dist/chunk-JZM5QUTE.js.map +0 -1
  272. package/dist/chunk-KXLRMM35.js.map +0 -1
  273. package/dist/chunk-N3LWQJ6Y.js.map +0 -1
  274. package/dist/chunk-QVALQE4P.js.map +0 -1
  275. package/dist/chunk-UZRIKUFS.js.map +0 -1
  276. /package/dist/{chunk-L4H6MQ7I.js.map → chunk-2RSL6YRA.js.map} +0 -0
  277. /package/dist/{chunk-7EX4YOKH.js.map → chunk-2ZPQUTMW.js.map} +0 -0
  278. /package/dist/{chunk-673NPXE3.js.map → chunk-3SIC3E65.js.map} +0 -0
  279. /package/dist/{chunk-OVMS3DCB.js.map → chunk-675YU5IK.js.map} +0 -0
  280. /package/dist/{chunk-7CKS4AXY.js.map → chunk-AOWPZ7TM.js.map} +0 -0
  281. /package/dist/{chunk-TGBJ2OMK.js.map → chunk-BQTSGK5Y.js.map} +0 -0
  282. /package/dist/{chunk-YXOAQAH2.js.map → chunk-CLFY35ED.js.map} +0 -0
  283. /package/dist/{chunk-HQ7QZJM5.js.map → chunk-D4TLWDYR.js.map} +0 -0
  284. /package/dist/{chunk-LQKITFGB.js.map → chunk-FUUF7FMX.js.map} +0 -0
  285. /package/dist/{chunk-MXRMNKSY.js.map → chunk-I3GKTDM2.js.map} +0 -0
  286. /package/dist/{chunk-EQF5763Z.js.map → chunk-IQULRIZM.js.map} +0 -0
  287. /package/dist/{chunk-DJCKXI4M.js.map → chunk-NVXQTRBL.js.map} +0 -0
  288. /package/dist/{chunk-VDLMAJXS.js.map → chunk-OCY3CRPG.js.map} +0 -0
  289. /package/dist/{chunk-YLTG6BO4.js.map → chunk-OIFZII6J.js.map} +0 -0
  290. /package/dist/{chunk-XF4KOVDK.js.map → chunk-PA6DMYEK.js.map} +0 -0
  291. /package/dist/{chunk-3OQ4IZJN.js.map → chunk-QPZCAVDC.js.map} +0 -0
  292. /package/dist/{chunk-DLWYAN6A.js.map → chunk-T6U7HDIY.js.map} +0 -0
  293. /package/dist/{chunk-UTDA43TB.js.map → chunk-TWGGNUWJ.js.map} +0 -0
  294. /package/dist/{chunk-SBFDL2EQ.js.map → chunk-UTZW3X2R.js.map} +0 -0
  295. /package/dist/{chunk-SECMZACR.js.map → chunk-XUQUBZ7O.js.map} +0 -0
  296. /package/dist/{chunk-WUDBMLC6.js.map → chunk-ZC3HG22I.js.map} +0 -0
  297. /package/dist/{chunk-VCEH5UYS.js.map → chunk-ZRXSHGXT.js.map} +0 -0
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  compareVerifiedEpisodeResults,
3
3
  searchVerifiedEpisodes
4
- } from "./chunk-YLTG6BO4.js";
4
+ } from "./chunk-OIFZII6J.js";
5
5
  import "./chunk-2A3OXAP2.js";
6
6
  import "./chunk-ZBJMUXZH.js";
7
- import "./chunk-KXLRMM35.js";
7
+ import "./chunk-TRH533CA.js";
8
8
  import "./chunk-L2B3EE7B.js";
9
9
  import "./chunk-B3ABVQ36.js";
10
10
  import "./chunk-5UZXUTVO.js";
@@ -15,7 +15,7 @@ import "./chunk-6CIAGZ6X.js";
15
15
  import "./chunk-J6A3CX5N.js";
16
16
  import "./chunk-4KJLYTLS.js";
17
17
  import "./chunk-SVOZFLIQ.js";
18
- import "./chunk-3ZVFLMFQ.js";
18
+ import "./chunk-G5PVJJRA.js";
19
19
  import "./chunk-RULE4VG5.js";
20
20
  import "./chunk-SCU65EZI.js";
21
21
  import "./chunk-RHOZ5LLO.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "9.7.10",
3
+ "version": "9.7.12",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -3010,7 +3010,7 @@
3010
3010
  "core"
3011
3011
  ],
3012
3012
  "peerDependencies": {
3013
- "@remnic/coding-graph": "^9.7.10"
3013
+ "@remnic/coding-graph": "^9.7.12"
3014
3014
  },
3015
3015
  "peerDependenciesMeta": {
3016
3016
  "@remnic/coding-graph": {
@@ -102,6 +102,8 @@ export const OPERATION_NAMES = [
102
102
  "shared_context_write_output",
103
103
  "shared_feedback_record",
104
104
  "shared_priorities_append",
105
+ "relay_mission_append",
106
+ "relay_mission_read",
105
107
  "shared_context_cross_signals_run",
106
108
  "shared_context_curate_daily",
107
109
  "compounding_weekly_synthesize",
@@ -53,6 +53,7 @@ import { handleChatMessage, handleChatEventsSSE } from "./chat/chat-http.js";
53
53
  import { cleanupExpiredChatSessions, enforceChatSessionNamespace } from "./chat/chat-session.js";
54
54
  import { isDefaultReviewNamespace, listPairs, readPair } from "./contradiction/contradiction-review.js";
55
55
  import { isValidResolutionVerb, executeResolution } from "./contradiction/resolution.js";
56
+ import { RelayMissionStoreError } from "./relay/mission.js";
56
57
 
57
58
  export interface AccessHttpReadinessState {
58
59
  ready: boolean;
@@ -339,6 +340,22 @@ function decodePeerIdSegment(raw: string): string {
339
340
  }
340
341
  }
341
342
 
343
+ function decodeRelayMissionIdSegment(raw: string): string {
344
+ try {
345
+ return decodeURIComponent(raw);
346
+ } catch {
347
+ throw new EngramAccessInputError(
348
+ "missionId path segment is not valid percent-encoded input",
349
+ );
350
+ }
351
+ }
352
+
353
+ function rejectBlankRelayNamespace(value: string | null | undefined): void {
354
+ if (value !== undefined && value !== null && value.trim().length === 0) {
355
+ throw new EngramAccessInputError("Relay namespace must not be blank when provided");
356
+ }
357
+ }
358
+
342
359
  function codingContextFromProjectTag(projectTag: string): {
343
360
  projectId: string;
344
361
  branch: string | null;
@@ -378,7 +395,7 @@ export class EngramAccessHttpServer {
378
395
  res: ServerResponse,
379
396
  ctx: { authorized: boolean },
380
397
  ) => Promise<boolean>;
381
- private readonly writeRequestTimestamps: number[] = [];
398
+ private readonly writeRequestSlots: Array<{ readonly recordedAt: number }> = [];
382
399
  private readonly writeRateLimitMaxRequests: number;
383
400
  private readonly writeRateLimitWindowMs: number;
384
401
  private readonly mcpServer: EngramMcpServer;
@@ -499,6 +516,20 @@ export class EngramAccessHttpServer {
499
516
  this.respondJson(res, 400, { error: err.message, code: "correction_contract_error" });
500
517
  return;
501
518
  }
519
+ if (err instanceof RelayMissionStoreError) {
520
+ const status = err.code === "idempotency_conflict"
521
+ ? 409
522
+ : err.code === "limit_exceeded"
523
+ ? 413
524
+ : err.code === "lock_unavailable"
525
+ ? 503
526
+ : 500;
527
+ this.respondJson(res, status, {
528
+ error: status >= 500 ? "relay_backend_unavailable" : err.message,
529
+ code: `relay_${err.code}`,
530
+ });
531
+ return;
532
+ }
502
533
  if (res.headersSent) {
503
534
  res.destroy(err as Error);
504
535
  return;
@@ -1670,6 +1701,103 @@ export class EngramAccessHttpServer {
1670
1701
  return;
1671
1702
  }
1672
1703
 
1704
+ // Remnic Relay mission receipts (issue #1966). These two routes share the
1705
+ // access-boundary schemas and namespace-resolved storage contract. The
1706
+ // browser receives an already-reduced snapshot; it never scans general
1707
+ // memories, recall logs, or production state.
1708
+ const relayEventMatch = /^\/engram\/v1\/relay\/missions\/([^/]+)\/events$/.exec(pathname);
1709
+ if (req.method === "POST" && relayEventMatch) {
1710
+ const missionId = decodeRelayMissionIdSegment(relayEventMatch[1] ?? "");
1711
+ const body = await this.readJsonBody(req);
1712
+ const unexpectedFields = Object.keys(body).filter(
1713
+ (key) => key !== "namespace" && key !== "event",
1714
+ );
1715
+ if (unexpectedFields.length > 0) {
1716
+ throw new EngramAccessInputError(
1717
+ `Relay append body contains unexpected field(s): ${unexpectedFields.sort().join(", ")}`,
1718
+ );
1719
+ }
1720
+ if (!Object.prototype.hasOwnProperty.call(body, "event")) {
1721
+ throw new EngramAccessInputError("Relay append body must contain an event object");
1722
+ }
1723
+ if (
1724
+ Object.prototype.hasOwnProperty.call(body, "namespace") &&
1725
+ body.namespace !== undefined &&
1726
+ body.namespace !== null &&
1727
+ typeof body.namespace !== "string"
1728
+ ) {
1729
+ throw new EngramAccessInputError("namespace must be a string when provided");
1730
+ }
1731
+ rejectBlankRelayNamespace(
1732
+ typeof body.namespace === "string" ? body.namespace : undefined,
1733
+ );
1734
+ const namespace = this.resolveNamespace(
1735
+ req,
1736
+ typeof body.namespace === "string" ? body.namespace : undefined,
1737
+ );
1738
+ const op = getOperation("relay_mission_append");
1739
+ if (!op) {
1740
+ throw new Error("access-boundary: operation not registered: relay_mission_append");
1741
+ }
1742
+ let releaseWriteQuota: (() => void) | undefined;
1743
+ try {
1744
+ const output = (await op.run(
1745
+ { missionId, namespace, event: body.event },
1746
+ {
1747
+ service: this.service,
1748
+ authenticatedPrincipal: this.resolveRequestPrincipal(req),
1749
+ hooks: {
1750
+ enforceWriteQuota: () => {
1751
+ releaseWriteQuota ??= this.reserveWriteRateLimitSlot();
1752
+ },
1753
+ },
1754
+ },
1755
+ )) as { result: { appended: boolean; replayed: boolean; event: unknown } };
1756
+ if (output.result.appended) {
1757
+ // The reservation is now the committed quota hit. Do not record a
1758
+ // second timestamp after the append returns.
1759
+ releaseWriteQuota = undefined;
1760
+ }
1761
+ this.respondJson(res, output.result.appended ? 201 : 200, output.result);
1762
+ } finally {
1763
+ // Replays never invoke the hook. If a future store path invokes it but
1764
+ // does not append, or persistence throws after reservation, return the
1765
+ // slot so a failed write cannot exhaust the rolling window.
1766
+ releaseWriteQuota?.();
1767
+ }
1768
+ return;
1769
+ }
1770
+
1771
+ const relayMissionMatch = /^\/engram\/v1\/relay\/missions\/([^/]+)$/.exec(pathname);
1772
+ if (req.method === "GET" && relayMissionMatch) {
1773
+ const missionId = decodeRelayMissionIdSegment(relayMissionMatch[1] ?? "");
1774
+ rejectBlankRelayNamespace(parsed.searchParams.get("namespace"));
1775
+ const namespace = this.resolveNamespace(
1776
+ req,
1777
+ parsed.searchParams.get("namespace") ?? undefined,
1778
+ );
1779
+ const op = getOperation("relay_mission_read");
1780
+ if (!op) {
1781
+ throw new Error("access-boundary: operation not registered: relay_mission_read");
1782
+ }
1783
+ const output = (await op.run(
1784
+ {
1785
+ missionId,
1786
+ namespace,
1787
+ since: parsed.searchParams.get("since") ?? undefined,
1788
+ until: parsed.searchParams.get("until") ?? undefined,
1789
+ limit: parsed.searchParams.get("limit") ?? undefined,
1790
+ },
1791
+ {
1792
+ service: this.service,
1793
+ authenticatedPrincipal: this.resolveRequestPrincipal(req),
1794
+ },
1795
+ )) as { result: unknown };
1796
+ res.setHeader("cache-control", "no-store");
1797
+ this.respondJson(res, 200, output.result);
1798
+ return;
1799
+ }
1800
+
1673
1801
  if (req.method === "POST" && pathname === "/engram/v1/memories") {
1674
1802
  // Migrated through the access boundary (issue #1525): the registry
1675
1803
  // entry owns schema validation, normalization, and service dispatch.
@@ -3711,18 +3839,31 @@ export class EngramAccessHttpServer {
3711
3839
  private ensureWriteRateLimitAvailable(): void {
3712
3840
  const now = Date.now();
3713
3841
  while (
3714
- this.writeRequestTimestamps.length > 0 &&
3715
- now - (this.writeRequestTimestamps[0] ?? 0) > this.writeRateLimitWindowMs
3842
+ this.writeRequestSlots.length > 0 &&
3843
+ now - (this.writeRequestSlots[0]?.recordedAt ?? 0) > this.writeRateLimitWindowMs
3716
3844
  ) {
3717
- this.writeRequestTimestamps.shift();
3845
+ this.writeRequestSlots.shift();
3718
3846
  }
3719
- if (this.writeRequestTimestamps.length >= this.writeRateLimitMaxRequests) {
3847
+ if (this.writeRequestSlots.length >= this.writeRateLimitMaxRequests) {
3720
3848
  throw new HttpError(429, "write_rate_limited", "write_rate_limited");
3721
3849
  }
3722
3850
  }
3723
3851
 
3724
3852
  private recordWriteRateLimitHit(): void {
3725
- this.writeRequestTimestamps.push(Date.now());
3853
+ this.writeRequestSlots.push({ recordedAt: Date.now() });
3854
+ }
3855
+
3856
+ private reserveWriteRateLimitSlot(): () => void {
3857
+ this.ensureWriteRateLimitAvailable();
3858
+ const slot = { recordedAt: Date.now() };
3859
+ this.writeRequestSlots.push(slot);
3860
+ let active = true;
3861
+ return () => {
3862
+ if (!active) return;
3863
+ active = false;
3864
+ const index = this.writeRequestSlots.indexOf(slot);
3865
+ if (index >= 0) this.writeRequestSlots.splice(index, 1);
3866
+ };
3726
3867
  }
3727
3868
 
3728
3869
  private shouldCountWriteRateLimit(response: { dryRun?: boolean; idempotencyReplay?: boolean }): boolean {
@@ -282,7 +282,7 @@ test("MCP write quota is recorded after commit even when the client disconnects
282
282
  });
283
283
  const serverHost = server as unknown as {
284
284
  mcpServer: EngramMcpServer;
285
- writeRequestTimestamps: number[];
285
+ writeRequestSlots: Array<{ readonly recordedAt: number }>;
286
286
  };
287
287
  const originalHandleRequest = serverHost.mcpServer.handleRequest.bind(serverHost.mcpServer);
288
288
  serverHost.mcpServer.handleRequest = async (request, options) => {
@@ -318,7 +318,7 @@ test("MCP write quota is recorded after commit even when the client disconnects
318
318
 
319
319
  await waitFor(operationSettled.promise);
320
320
  await new Promise<void>((resolve) => setImmediate(resolve));
321
- assert.equal(serverHost.writeRequestTimestamps.length, 1);
321
+ assert.equal(serverHost.writeRequestSlots.length, 1);
322
322
  assert.equal(responseStarted, false, "the disconnected client must not receive the committed write response");
323
323
  } finally {
324
324
  releaseOperation.resolve();
@@ -678,6 +678,8 @@ export const codegraphIngestTracesOperation = defineOperation<
678
678
  // Batch-migrated operations (issue #1525): registers all remaining
679
679
  // handlers through the boundary as a side effect of importing this module.
680
680
  import "./access-operations-batch.js";
681
+ // Remnic Relay mission evidence operations (issue #1966).
682
+ import "./relay/mission-access.js";
681
683
 
682
684
  export const REGISTERED_OPERATIONS = [
683
685
  memoryGetOperation.spec.name,
@@ -193,6 +193,8 @@ export const HTTP_ROUTES: readonly HttpRouteEntry[] = [
193
193
  { method: "POST", pathname: "/engram/v1/lcm/compaction/flush", operation: "lcm_compaction_flush" },
194
194
  { method: "POST", pathname: "/engram/v1/lcm/compaction/record", operation: "lcm_compaction_record" },
195
195
  { method: "GET", pathname: "/engram/v1/lcm/status", operation: "lcm_status" },
196
+ { method: "GET", pathname: "/engram/v1/relay/missions/:id", operation: "relay_mission_read" },
197
+ { method: "POST", pathname: "/engram/v1/relay/missions/:id/events", operation: "relay_mission_append" },
196
198
  // Correction Contract (issue #1580) — plan/apply/pending.
197
199
  { method: "POST", pathname: "/engram/v1/correction/plan", operation: "memory_correct_plan" },
198
200
  { method: "POST", pathname: "/engram/v1/correction/apply", operation: "memory_correct_apply" },
@@ -2161,3 +2161,47 @@ test("parseConfig rejects non-positive extraction retry/breaker numerics and fal
2161
2161
  assert.equal(c.extractionBreakerAuthCooldownMs, 1_800_000, "non-positive auth cooldown -> default");
2162
2162
  assert.deepEqual(c.extractionRetryScheduleMs, [60_000, 300_000, 1_800_000, 7_200_000], "schedule with non-positive entry -> default");
2163
2163
  });
2164
+
2165
+ test("parseConfig namespace-catalog touch-path knobs: defaults, 0-accepting numerics, and validation (#1903)", () => {
2166
+ // Documented defaults when absent.
2167
+ const d = parseConfig({});
2168
+ assert.equal(d.namespacesCatalogCompactBytes, 16 * 1024 * 1024, "compactBytes default 16 MB");
2169
+ assert.equal(d.namespacesCatalogReadTouchCoalesceMs, 60_000, "read coalesce default 60000ms");
2170
+ assert.equal(d.namespacesCatalogWriteTouchCoalesceMs, 1_000, "write coalesce default 1000ms");
2171
+ assert.equal(d.namespacesCatalogTouchStateWrites, false, "state-write touch default false");
2172
+
2173
+ // 0 is an accepted disable switch for every numeric (resolveNonNegativeIntegerConfig).
2174
+ assert.equal(parseConfig({ namespacesCatalogCompactBytes: 0 }).namespacesCatalogCompactBytes, 0);
2175
+ assert.equal(parseConfig({ namespacesCatalogReadTouchCoalesceMs: 0 }).namespacesCatalogReadTouchCoalesceMs, 0);
2176
+ assert.equal(parseConfig({ namespacesCatalogWriteTouchCoalesceMs: 0 }).namespacesCatalogWriteTouchCoalesceMs, 0);
2177
+
2178
+ // Positive integers pass through; CLI/env numeric strings coerce.
2179
+ assert.equal(parseConfig({ namespacesCatalogCompactBytes: 4096 }).namespacesCatalogCompactBytes, 4096);
2180
+ assert.equal(parseConfig({ namespacesCatalogReadTouchCoalesceMs: "30000" }).namespacesCatalogReadTouchCoalesceMs, 30_000);
2181
+
2182
+ // Boolean-like coercion for the state-write toggle (gotcha #36).
2183
+ assert.equal(parseConfig({ namespacesCatalogTouchStateWrites: true }).namespacesCatalogTouchStateWrites, true);
2184
+ assert.equal(parseConfig({ namespacesCatalogTouchStateWrites: "true" }).namespacesCatalogTouchStateWrites, true);
2185
+ assert.equal(parseConfig({ namespacesCatalogTouchStateWrites: "off" }).namespacesCatalogTouchStateWrites, false);
2186
+
2187
+ // Negative and non-integer numerics are rejected with the documented message.
2188
+ for (const key of [
2189
+ "namespacesCatalogCompactBytes",
2190
+ "namespacesCatalogReadTouchCoalesceMs",
2191
+ "namespacesCatalogWriteTouchCoalesceMs",
2192
+ ]) {
2193
+ for (const bad of [-1, 1.5, "1.5", "abc", Number.NaN, Infinity]) {
2194
+ assert.throws(
2195
+ () => parseConfig({ [key]: bad }),
2196
+ new RegExp(`${key} must be a non-negative integer`),
2197
+ `${key}=${JSON.stringify(bad)} should throw`,
2198
+ );
2199
+ }
2200
+ }
2201
+
2202
+ // A present-but-malformed boolean toggle fails fast (gotcha #51).
2203
+ assert.throws(
2204
+ () => parseConfig({ namespacesCatalogTouchStateWrites: "maybe" }),
2205
+ /namespacesCatalogTouchStateWrites must be a boolean-like value/,
2206
+ );
2207
+ });
package/src/config.ts CHANGED
@@ -435,6 +435,26 @@ function resolvePositiveIntegerConfig(
435
435
  return coerced;
436
436
  }
437
437
 
438
+ function resolveNonNegativeIntegerConfig(
439
+ value: unknown,
440
+ defaultValue: number,
441
+ keyName: string,
442
+ ): number {
443
+ if (value === undefined || value === null) return defaultValue;
444
+ const coerced = coerceNumber(value);
445
+ if (
446
+ coerced === undefined ||
447
+ !Number.isFinite(coerced) ||
448
+ !Number.isInteger(coerced) ||
449
+ coerced < 0
450
+ ) {
451
+ throw new Error(
452
+ `${keyName} must be a non-negative integer; got ${JSON.stringify(value)}`,
453
+ );
454
+ }
455
+ return coerced;
456
+ }
457
+
438
458
  export function isOpenaiApiKeyDisabled(value: unknown): boolean {
439
459
  return value === false || (typeof value === "string" && value.trim().toLowerCase() === "false");
440
460
  }
@@ -2934,6 +2954,29 @@ export function parseConfig(
2934
2954
  // silently defaulting to enabled (CLAUDE.md rule #51); default to enabled
2935
2955
  // only when the value is absent.
2936
2956
  namespaceCatalogEnabled: resolveNamespaceCatalogEnabled(cfg.namespaceCatalogEnabled, rawOperatorConfig, runtimeSet),
2957
+ // Namespace catalog touch-path performance knobs (issue #1903). Numerics use
2958
+ // resolveNonNegativeIntegerConfig so 0 is an accepted disable switch; a
2959
+ // present-but-invalid value (negative/non-integer) is REJECTED (rule #51).
2960
+ namespacesCatalogCompactBytes: resolveNonNegativeIntegerConfig(
2961
+ cfg.namespacesCatalogCompactBytes,
2962
+ 16 * 1024 * 1024,
2963
+ "namespacesCatalogCompactBytes",
2964
+ ),
2965
+ namespacesCatalogReadTouchCoalesceMs: resolveNonNegativeIntegerConfig(
2966
+ cfg.namespacesCatalogReadTouchCoalesceMs,
2967
+ 60_000,
2968
+ "namespacesCatalogReadTouchCoalesceMs",
2969
+ ),
2970
+ namespacesCatalogWriteTouchCoalesceMs: resolveNonNegativeIntegerConfig(
2971
+ cfg.namespacesCatalogWriteTouchCoalesceMs,
2972
+ 1_000,
2973
+ "namespacesCatalogWriteTouchCoalesceMs",
2974
+ ),
2975
+ namespacesCatalogTouchStateWrites: resolveBooleanConfig(
2976
+ cfg.namespacesCatalogTouchStateWrites,
2977
+ false,
2978
+ "namespacesCatalogTouchStateWrites",
2979
+ ),
2937
2980
  // NOTE: namespace identifiers are intentionally NOT sanitized here — the
2938
2981
  // codebase rejects unsafe namespaces at the point of use (see
2939
2982
  // codex-materialize-runner and NamespaceStorageRouter / resolveNamespaceDir),
package/src/index.ts CHANGED
@@ -387,6 +387,59 @@ export {
387
387
  } from "./access-http.js";
388
388
  export { EngramMcpServer } from "./access-mcp.js";
389
389
 
390
+ // Remnic Relay — host-agnostic mission evidence and receipt contract.
391
+ export {
392
+ RELAY_MISSION_DEFAULT_EVENT_LIMIT,
393
+ RELAY_MISSION_MAX_EVENT_LIMIT,
394
+ RELAY_MISSION_MAX_EVENTS,
395
+ RELAY_MISSION_MAX_FILE_BYTES,
396
+ RELAY_MISSION_MAX_LINE_BYTES,
397
+ RELAY_MISSION_SCHEMA_VERSION,
398
+ RelayEvidenceRefSchema,
399
+ RelayMissionEventInputSchema,
400
+ RelayMissionEventSchema,
401
+ RelayMissionPayloadSchema,
402
+ RelayMissionReadOptionsSchema,
403
+ RelayMissionStore,
404
+ RelayMissionStoreError,
405
+ compareRelayEvents,
406
+ reduceRelayMission,
407
+ relayMissionReceiptDigest,
408
+ type RelayAgentOutputSnapshot,
409
+ type RelayAgentSnapshot,
410
+ type RelayConflictSnapshot,
411
+ type RelayCorrectionSnapshot,
412
+ type RelayDecisionSnapshot,
413
+ type RelayEvidenceRef,
414
+ type RelayMissionAppendResult,
415
+ type RelayMissionEvent,
416
+ type RelayMissionEventInput,
417
+ type RelayMissionPayload,
418
+ type RelayMissionReadOptions,
419
+ type RelayMissionSnapshot,
420
+ type RelayMissionStatus,
421
+ type RelayMissionStoreErrorCode,
422
+ type RelayMissionStoreOptions,
423
+ type RelayPropagationSnapshot,
424
+ type RelayRecallSnapshot,
425
+ type RelayTestSnapshot,
426
+ } from "./relay/mission.js";
427
+ export {
428
+ RELAY_DEMO_MISSION_ID,
429
+ RELAY_DEMO_NAMESPACE,
430
+ createRelayMissionFixture,
431
+ } from "./relay/mission-fixture.js";
432
+ export {
433
+ appendRelayMissionEvent,
434
+ readRelayMission,
435
+ relayMissionAppendOperation,
436
+ relayMissionReadOperation,
437
+ type RelayMissionAppendAccessInput,
438
+ type RelayMissionAppendAccessOutput,
439
+ type RelayMissionReadAccessInput,
440
+ type RelayMissionReadAccessOutput,
441
+ } from "./relay/mission-access.js";
442
+
390
443
  // agentAccessHttp.authToken SecretRef resolution (issue #757). Exposed so
391
444
  // host-specific bootstrap code (the OpenClaw plugin in `src/index.ts`, the
392
445
  // standalone server, the CLI) can resolve a SecretRef to a literal bearer