@remnic/core 10.0.49 → 10.0.51

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 (415) hide show
  1. package/dist/access-admin-ops-surface.js +49 -48
  2. package/dist/access-authorization-probe.js +50 -49
  3. package/dist/access-boundary.d.ts +6 -1
  4. package/dist/access-boundary.d.ts.map +1 -1
  5. package/dist/access-boundary.js +49 -48
  6. package/dist/access-cli.js +120 -119
  7. package/dist/access-cli.js.map +1 -1
  8. package/dist/access-errors.d.ts.map +1 -1
  9. package/dist/access-errors.js +1 -1
  10. package/dist/access-extraction-force-flush.js +49 -48
  11. package/dist/access-http-briefing.d.ts +2 -0
  12. package/dist/access-http-briefing.d.ts.map +1 -1
  13. package/dist/access-http-briefing.js +50 -49
  14. package/dist/access-http-query.js +51 -50
  15. package/dist/access-http.d.ts.map +1 -1
  16. package/dist/access-http.js +70 -69
  17. package/dist/access-identity-continuity-surface.js +49 -48
  18. package/dist/access-lcm-surface.js +49 -48
  19. package/dist/access-mcp.js +60 -59
  20. package/dist/access-memory-search-fanout.js +2 -2
  21. package/dist/access-namespace-preflight.js +49 -48
  22. package/dist/access-observe-write-category.d.ts +1 -1
  23. package/dist/access-observe-write-category.d.ts.map +1 -1
  24. package/dist/access-observe-write-category.js +10 -10
  25. package/dist/access-observe-write-surface.d.ts.map +1 -1
  26. package/dist/access-observe-write-surface.js +49 -48
  27. package/dist/access-offline-manifest.js +6 -6
  28. package/dist/access-operations-batch.js +50 -49
  29. package/dist/access-operations.js +57 -56
  30. package/dist/access-recall-concurrency.js +49 -48
  31. package/dist/access-recall-diagnostics.js +2 -2
  32. package/dist/access-recall-response.js +49 -48
  33. package/dist/access-recall-surface.js +49 -48
  34. package/dist/access-schema.d.ts +245 -773
  35. package/dist/access-schema.d.ts.map +1 -1
  36. package/dist/access-schema.js +6 -6
  37. package/dist/access-service.d.ts +5 -0
  38. package/dist/access-service.d.ts.map +1 -1
  39. package/dist/access-service.js +49 -48
  40. package/dist/access-surface-catalog.js +51 -50
  41. package/dist/access-surface-catalog.js.map +1 -1
  42. package/dist/access-token-capabilities.js +2 -2
  43. package/dist/active-recall.js +16 -16
  44. package/dist/{auto-sync-BNCBMU6H.js → auto-sync-UQQ6YJSB.js} +3 -3
  45. package/dist/briefing-deadline.d.ts +7 -0
  46. package/dist/briefing-deadline.d.ts.map +1 -0
  47. package/dist/briefing-deadline.js +13 -0
  48. package/dist/briefing-window.d.ts +12 -4
  49. package/dist/briefing-window.d.ts.map +1 -1
  50. package/dist/briefing-window.js +3 -1
  51. package/dist/briefing.d.ts +2 -0
  52. package/dist/briefing.d.ts.map +1 -1
  53. package/dist/briefing.js +12 -11
  54. package/dist/buffer.js +3 -3
  55. package/dist/calibration.js +2 -2
  56. package/dist/{capsule-merge-RNQUP2VL.js → capsule-merge-D4BTIJGK.js} +3 -3
  57. package/dist/causal-consolidation.js +11 -11
  58. package/dist/{chunk-ESDOQEJM.js → chunk-2AKIVSHP.js} +2 -2
  59. package/dist/{chunk-BWF3KNSQ.js → chunk-2EXF6IIB.js} +2 -2
  60. package/dist/{chunk-AGCEJDG2.js → chunk-2ONKXEC7.js} +3 -3
  61. package/dist/{chunk-3NYIXVCT.js → chunk-2S6JADBB.js} +2 -2
  62. package/dist/chunk-2S6JADBB.js.map +1 -0
  63. package/dist/{chunk-ZSEFGDCI.js → chunk-2TGIKMMZ.js} +2 -2
  64. package/dist/{chunk-MCS4LIXP.js → chunk-43TUWQNR.js} +2 -2
  65. package/dist/{chunk-Q6PYCPHO.js → chunk-44EUCSG4.js} +2 -2
  66. package/dist/{chunk-2J6BIOVN.js → chunk-4FM35YIA.js} +3 -3
  67. package/dist/{chunk-2NLCDNGA.js → chunk-564YP3DW.js} +2 -2
  68. package/dist/{chunk-YY6PWFUC.js → chunk-6ZAU7LAR.js} +3 -3
  69. package/dist/{chunk-HCPVL6SF.js → chunk-72CBJ5VP.js} +3 -3
  70. package/dist/{chunk-AF4UIHON.js → chunk-74AY3S7U.js} +9 -9
  71. package/dist/{chunk-N6EM7ESC.js → chunk-75BK4XGV.js} +27 -19
  72. package/dist/chunk-75BK4XGV.js.map +1 -0
  73. package/dist/{chunk-5IDQVE4U.js → chunk-A3UFV4K3.js} +6 -6
  74. package/dist/{chunk-LWRIGKFM.js → chunk-A5L5KGDI.js} +19 -1
  75. package/dist/chunk-A5L5KGDI.js.map +1 -0
  76. package/dist/{chunk-RZDDNH63.js → chunk-A6JDT6QF.js} +27 -15
  77. package/dist/chunk-A6JDT6QF.js.map +1 -0
  78. package/dist/{chunk-XFND63OB.js → chunk-AHGOOZUC.js} +2 -2
  79. package/dist/{chunk-A7AISUJI.js → chunk-AJG2TAMR.js} +2 -2
  80. package/dist/{chunk-2BY56HE6.js → chunk-AZLD4CKG.js} +36 -36
  81. package/dist/{chunk-E47UQBYW.js → chunk-B35EQQ7L.js} +3 -3
  82. package/dist/{chunk-E6UNM67F.js → chunk-B6SPPYGJ.js} +2 -2
  83. package/dist/{chunk-CMOYD5CA.js → chunk-CCL2OXFO.js} +2 -2
  84. package/dist/{chunk-SVJ5JVZO.js → chunk-CK6GCGMX.js} +4 -4
  85. package/dist/{chunk-QZK6HG4J.js → chunk-DF6ZF2BN.js} +3 -3
  86. package/dist/{chunk-CPBYKOTC.js → chunk-DJFULNXK.js} +4 -4
  87. package/dist/{chunk-VGRBKEBH.js → chunk-DQOGZZJA.js} +3 -3
  88. package/dist/{chunk-YB3WN6XA.js → chunk-EC2KVA27.js} +12 -12
  89. package/dist/{chunk-FRXS6SC7.js → chunk-EKUI7I2X.js} +20 -4
  90. package/dist/chunk-EKUI7I2X.js.map +1 -0
  91. package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
  92. package/dist/{chunk-WIBWONL4.js → chunk-EZS6QJNC.js} +2 -2
  93. package/dist/{chunk-C7WDWD35.js → chunk-FNNGWN3O.js} +5 -5
  94. package/dist/{chunk-PBWJVRKE.js → chunk-FT75AQ74.js} +3 -3
  95. package/dist/{chunk-VY6BD5KB.js → chunk-G6A3SGCE.js} +14 -12
  96. package/dist/chunk-G6A3SGCE.js.map +1 -0
  97. package/dist/{chunk-O4CA53UY.js → chunk-GBGU5OZP.js} +111 -104
  98. package/dist/chunk-GBGU5OZP.js.map +1 -0
  99. package/dist/{chunk-WJCAAVZX.js → chunk-GE3ZX6YK.js} +2 -2
  100. package/dist/{chunk-3PVKV3XL.js → chunk-HCIRR3BA.js} +3 -3
  101. package/dist/{chunk-BJTFLP3J.js → chunk-HEF4BRMT.js} +3 -3
  102. package/dist/{chunk-BMG3SAXA.js → chunk-HQUYENKK.js} +9 -12
  103. package/dist/chunk-HQUYENKK.js.map +1 -0
  104. package/dist/{chunk-6UDLN4IA.js → chunk-I6ORDT54.js} +2 -2
  105. package/dist/{chunk-N5PISU26.js → chunk-IN6U2BS5.js} +2 -2
  106. package/dist/{chunk-3INLTKTW.js → chunk-IUQXRRJB.js} +4 -4
  107. package/dist/{chunk-6W3QH3QW.js → chunk-JIJAWTRK.js} +388 -292
  108. package/dist/chunk-JIJAWTRK.js.map +1 -0
  109. package/dist/{chunk-4KS4IHKH.js → chunk-JX3E4XCW.js} +2 -2
  110. package/dist/{chunk-SW3WHVKN.js → chunk-KAJYSO3U.js} +2 -2
  111. package/dist/{chunk-D76AHITY.js → chunk-KETS5A62.js} +2 -2
  112. package/dist/{chunk-LCHFINL4.js → chunk-KIWO4327.js} +2 -2
  113. package/dist/{chunk-FC3ZFEXF.js → chunk-KJ3MDX4V.js} +2 -2
  114. package/dist/{chunk-7LCGFUMB.js → chunk-KQAFEZQX.js} +4 -4
  115. package/dist/{chunk-6TIVVOVU.js → chunk-L3EFYRYK.js} +9 -9
  116. package/dist/{chunk-3MUKQQ7A.js → chunk-LGEH473S.js} +24 -29
  117. package/dist/chunk-LGEH473S.js.map +1 -0
  118. package/dist/{chunk-X52SXKVC.js → chunk-LMB47UM6.js} +2 -2
  119. package/dist/{chunk-A3WXV7YU.js → chunk-LWMLBVGB.js} +2 -2
  120. package/dist/{chunk-KMTMMBEB.js → chunk-MC7PXJDP.js} +7 -7
  121. package/dist/{chunk-NMOEOQV4.js → chunk-MUNYUSBU.js} +2 -2
  122. package/dist/{chunk-VKUMKVEU.js → chunk-OCRLJJOV.js} +5 -5
  123. package/dist/{chunk-XSJL62LE.js → chunk-ON77FQXH.js} +2 -2
  124. package/dist/{chunk-C3HRYVGD.js → chunk-POJRFSJM.js} +3 -3
  125. package/dist/{chunk-LKRXGOQW.js → chunk-QA3Y2O6H.js} +2 -2
  126. package/dist/{chunk-23ZLN5X6.js → chunk-QT5MGENX.js} +14 -6
  127. package/dist/chunk-QT5MGENX.js.map +1 -0
  128. package/dist/{chunk-QFTNWDJ6.js → chunk-RA7YRL6H.js} +2 -2
  129. package/dist/{chunk-WQFHHJWK.js → chunk-RJDYDF5K.js} +4 -4
  130. package/dist/{chunk-E3DL3CAL.js → chunk-ROAKLYOL.js} +2 -2
  131. package/dist/{chunk-YFXRLRKP.js → chunk-S4OZKPBS.js} +7 -11
  132. package/dist/{chunk-YFXRLRKP.js.map → chunk-S4OZKPBS.js.map} +1 -1
  133. package/dist/{chunk-NWIT3U2N.js → chunk-S5CQI2KF.js} +2 -2
  134. package/dist/{chunk-P6P35FY4.js → chunk-SDESKFKT.js} +2 -2
  135. package/dist/{chunk-OD7ZXCUF.js → chunk-SFRBUBUZ.js} +10 -10
  136. package/dist/{chunk-7XFQSQYS.js → chunk-SHNM7RIT.js} +5 -4
  137. package/dist/chunk-SHNM7RIT.js.map +1 -0
  138. package/dist/{chunk-NH37SP6V.js → chunk-SJD334AG.js} +81 -78
  139. package/dist/chunk-SJD334AG.js.map +1 -0
  140. package/dist/{chunk-O7GNSHFF.js → chunk-SPTPBKZX.js} +2 -2
  141. package/dist/{chunk-HI53EK3Y.js → chunk-TC55M5PO.js} +2 -2
  142. package/dist/{chunk-SA6P2KS3.js → chunk-TEH5MDX5.js} +33 -17
  143. package/dist/chunk-TEH5MDX5.js.map +1 -0
  144. package/dist/{chunk-FOKTW6GY.js → chunk-UCLJTGP3.js} +2 -2
  145. package/dist/{chunk-FYZXZUGU.js → chunk-UQBOPCDK.js} +2 -2
  146. package/dist/{chunk-SUKPM6DV.js → chunk-UWMZT2TY.js} +47 -4
  147. package/dist/chunk-UWMZT2TY.js.map +1 -0
  148. package/dist/{chunk-754XN6LX.js → chunk-V27FK6D6.js} +2 -2
  149. package/dist/{chunk-DM6SOROF.js → chunk-V6Z4NAJZ.js} +2 -2
  150. package/dist/{chunk-5FNZ3G6X.js → chunk-VKQI47DJ.js} +4 -4
  151. package/dist/{chunk-NUK5XU3P.js → chunk-VUMWVYMR.js} +28 -13
  152. package/dist/chunk-VUMWVYMR.js.map +1 -0
  153. package/dist/{chunk-MPJDQC4G.js → chunk-WJCXUE2J.js} +2 -2
  154. package/dist/{chunk-VCBS5GRQ.js → chunk-WY66J4PI.js} +2 -2
  155. package/dist/chunk-X2KO4FK5.js +40 -0
  156. package/dist/chunk-X2KO4FK5.js.map +1 -0
  157. package/dist/{chunk-OOOX5C4X.js → chunk-XL2EE5W3.js} +4 -4
  158. package/dist/{chunk-V4GPFCJ7.js → chunk-XWJUFER3.js} +3 -3
  159. package/dist/{chunk-CZVNOTLR.js → chunk-XXR4A33N.js} +2 -2
  160. package/dist/{chunk-CRJX4OMN.js → chunk-Y3T5KQCR.js} +2 -2
  161. package/dist/{chunk-KNCR7APE.js → chunk-Y77FXULH.js} +8 -8
  162. package/dist/{chunk-2AV2U2SZ.js → chunk-YDIOMDBW.js} +2 -2
  163. package/dist/{chunk-IG747LRN.js → chunk-YO2JEX2Z.js} +2 -2
  164. package/dist/{chunk-HDT3DMUF.js → chunk-ZKK3VMWU.js} +2 -2
  165. package/dist/cli.js +92 -91
  166. package/dist/coding/export-okf-codegraph.js +9 -9
  167. package/dist/compounding/engine.js +11 -11
  168. package/dist/config.js +16 -16
  169. package/dist/connectors/codex-materialize-runner.js +10 -10
  170. package/dist/connectors/index.js +14 -14
  171. package/dist/consolidation-provenance-check.js +4 -4
  172. package/dist/consolidation-undo.js +2 -2
  173. package/dist/convergence-refresh.js +12 -12
  174. package/dist/corpus-watermark.js +14 -14
  175. package/dist/correction/passive-correction-notifications.d.ts +1 -1
  176. package/dist/correction/passive-correction-notifications.d.ts.map +1 -1
  177. package/dist/dashboard-runtime.js +2 -2
  178. package/dist/deep-recall-config.js +2 -2
  179. package/dist/deep-recall-http-glue.js +9 -9
  180. package/dist/{entity-canonical-id-migration-2YOLMOFC.js → entity-canonical-id-migration-F3JVG6K6.js} +3 -3
  181. package/dist/entity-canonical-id-migration-F3JVG6K6.js.map +1 -0
  182. package/dist/entity-retrieval.js +11 -11
  183. package/dist/explicit-capture.js +2 -2
  184. package/dist/external-wiki-access.js +50 -49
  185. package/dist/extraction-span-wire.d.ts.map +1 -1
  186. package/dist/extraction-span-wire.js +1 -1
  187. package/dist/extraction.js +22 -22
  188. package/dist/{first-start-migration-QVD22WWS.js → first-start-migration-A6PHIBUQ.js} +4 -4
  189. package/dist/harmonic-retrieval.js +10 -10
  190. package/dist/index.d.ts +1 -0
  191. package/dist/index.d.ts.map +1 -1
  192. package/dist/index.js +143 -135
  193. package/dist/lcm/engine.js +2 -2
  194. package/dist/lcm/index.js +5 -5
  195. package/dist/local-llm.js +2 -2
  196. package/dist/location/index.js +16 -16
  197. package/dist/location/tagging.d.ts +7 -5
  198. package/dist/location/tagging.d.ts.map +1 -1
  199. package/dist/maintenance/memory-governance.js +10 -10
  200. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
  201. package/dist/maintenance/rebuild-memory-projection-runner.js +12 -12
  202. package/dist/maintenance/rebuild-memory-projection.js +11 -11
  203. package/dist/memory-browse-http-glue.js +2 -2
  204. package/dist/memory-browse-operations.js +50 -49
  205. package/dist/namespaces/migrate.js +11 -11
  206. package/dist/namespaces/storage.js +10 -10
  207. package/dist/offline-sync-file-io.d.ts +15 -0
  208. package/dist/offline-sync-file-io.d.ts.map +1 -1
  209. package/dist/offline-sync-file-io.js +9 -1
  210. package/dist/offline-sync-impression-drain.js +2 -2
  211. package/dist/offline-sync-snapshot-stream.js +4 -4
  212. package/dist/offline-sync-upload-staging.js +2 -2
  213. package/dist/offline-sync.d.ts.map +1 -1
  214. package/dist/offline-sync.js +3 -3
  215. package/dist/operator-doctor-corpus.js +17 -17
  216. package/dist/operator-doctor-replica.js +4 -4
  217. package/dist/operator-toolkit.js +29 -29
  218. package/dist/orchestration/maintenance.js +25 -25
  219. package/dist/orchestrator.d.ts +1 -0
  220. package/dist/orchestrator.d.ts.map +1 -1
  221. package/dist/orchestrator.js +122 -121
  222. package/dist/page-versioning.js +2 -2
  223. package/dist/recall-navigation-http-glue.js +2 -2
  224. package/dist/recall-navigation-operations.js +50 -49
  225. package/dist/recall-navigation.js +49 -48
  226. package/dist/relay/mission.d.ts +731 -3403
  227. package/dist/relay/mission.d.ts.map +1 -1
  228. package/dist/replica-divergence.js +3 -3
  229. package/dist/resume-bundles.js +17 -17
  230. package/dist/schemas.d.ts +346 -1771
  231. package/dist/schemas.d.ts.map +1 -1
  232. package/dist/semantic-consolidation.js +15 -15
  233. package/dist/semantic-rule-promotion.js +10 -10
  234. package/dist/semantic-rule-verifier.js +10 -10
  235. package/dist/shared-context/manager.d.ts +13 -33
  236. package/dist/shared-context/manager.d.ts.map +1 -1
  237. package/dist/source-agent-qualifier.js +18 -18
  238. package/dist/standup/build.js +11 -11
  239. package/dist/storage/entity-canonical-id-migration-adapter.d.ts +1 -0
  240. package/dist/storage/entity-canonical-id-migration-adapter.d.ts.map +1 -1
  241. package/dist/storage/entity-canonical-id-migration.d.ts +7 -0
  242. package/dist/storage/entity-canonical-id-migration.d.ts.map +1 -1
  243. package/dist/storage/entity-canonical-id-references.d.ts +2 -0
  244. package/dist/storage/entity-canonical-id-references.d.ts.map +1 -1
  245. package/dist/storage/entity-migration-completion-cache.d.ts +46 -0
  246. package/dist/storage/entity-migration-completion-cache.d.ts.map +1 -0
  247. package/dist/storage/entity-store.d.ts +1 -8
  248. package/dist/storage/entity-store.d.ts.map +1 -1
  249. package/dist/storage/memory-read-store.d.ts +3 -2
  250. package/dist/storage/memory-read-store.d.ts.map +1 -1
  251. package/dist/storage/windowed-memory-read.d.ts +6 -0
  252. package/dist/storage/windowed-memory-read.d.ts.map +1 -1
  253. package/dist/storage.d.ts +2 -0
  254. package/dist/storage.d.ts.map +1 -1
  255. package/dist/storage.js +9 -9
  256. package/dist/summarizer.js +3 -3
  257. package/dist/support-passport/access-operations.d.ts +51 -51
  258. package/dist/support-passport/contracts.d.ts +85 -126
  259. package/dist/support-passport/contracts.d.ts.map +1 -1
  260. package/dist/support-passport/generated-batch.d.ts +3 -17
  261. package/dist/support-passport/generated-batch.d.ts.map +1 -1
  262. package/dist/support-passport/grant-contracts.d.ts +75 -381
  263. package/dist/support-passport/grant-contracts.d.ts.map +1 -1
  264. package/dist/support-passport/index.js +52 -51
  265. package/dist/support-passport/model-audit.d.ts +17 -82
  266. package/dist/support-passport/model-audit.d.ts.map +1 -1
  267. package/dist/support-passport/model-bridge.d.ts +12 -51
  268. package/dist/support-passport/model-bridge.d.ts.map +1 -1
  269. package/dist/support-passport/model-contracts.d.ts +53 -192
  270. package/dist/support-passport/model-contracts.d.ts.map +1 -1
  271. package/dist/tokens.js +3 -3
  272. package/dist/transfer/capsule-export.js +2 -2
  273. package/dist/transfer/capsule-import.js +4 -4
  274. package/dist/transfer/export-okf.js +10 -10
  275. package/dist/transfer/types.d.ts +32 -737
  276. package/dist/transfer/types.d.ts.map +1 -1
  277. package/dist/verified-recall.js +10 -10
  278. package/dist/who-knows-cli.js +12 -12
  279. package/dist/who-knows.js +11 -11
  280. package/package.json +3 -4
  281. package/src/access-boundary.test.ts +14 -0
  282. package/src/access-boundary.ts +48 -42
  283. package/src/access-category-alias.test.ts +9 -7
  284. package/src/access-errors.test.ts +21 -9
  285. package/src/access-errors.ts +45 -31
  286. package/src/access-http-briefing.ts +4 -0
  287. package/src/access-http.test.ts +41 -12
  288. package/src/access-http.ts +6 -0
  289. package/src/access-observe-write-category.ts +1 -1
  290. package/src/access-observe-write-surface.ts +24 -19
  291. package/src/access-operations-batch.ts +18 -2
  292. package/src/access-schema.ts +13 -17
  293. package/src/access-service.ts +5 -0
  294. package/src/briefing-abort.test.ts +173 -0
  295. package/src/briefing-deadline.test.ts +84 -0
  296. package/src/briefing-deadline.ts +33 -0
  297. package/src/briefing-window-abort.test.ts +47 -0
  298. package/src/briefing-window.ts +33 -4
  299. package/src/briefing.ts +23 -16
  300. package/src/correction/passive-correction-notifications-abort.test.ts +42 -0
  301. package/src/correction/passive-correction-notifications.ts +4 -0
  302. package/src/entity-lazy-compatibility.test.ts +229 -0
  303. package/src/entity-migration-completion-notification.test.ts +148 -0
  304. package/src/extraction-scope-source-agent.test.ts +6 -6
  305. package/src/extraction-span-wire.test.ts +28 -0
  306. package/src/extraction-span-wire.ts +34 -6
  307. package/src/index.ts +1 -1
  308. package/src/location/tagging.ts +14 -12
  309. package/src/offline-sync-file-io.ts +61 -2
  310. package/src/offline-sync.test.ts +313 -20
  311. package/src/offline-sync.ts +43 -21
  312. package/src/orchestrator-init.test.ts +49 -1
  313. package/src/orchestrator.ts +9 -8
  314. package/src/storage/entity-canonical-id-migration-adapter.ts +16 -1
  315. package/src/storage/entity-canonical-id-migration.ts +19 -10
  316. package/src/storage/entity-canonical-id-references.ts +24 -0
  317. package/src/storage/entity-migration-completion-cache.nofollow.test.ts +223 -0
  318. package/src/storage/entity-migration-completion-cache.ts +153 -0
  319. package/src/storage/entity-store.ts +58 -86
  320. package/src/storage/memory-read-store.ts +9 -3
  321. package/src/storage/windowed-memory-read.ts +8 -0
  322. package/src/storage-startup-nonblocking-migration.test.ts +183 -0
  323. package/src/storage.ts +7 -2
  324. package/src/testing/subjects/entity-migration-completion-cache.test.ts +90 -0
  325. package/dist/chunk-23ZLN5X6.js.map +0 -1
  326. package/dist/chunk-3MUKQQ7A.js.map +0 -1
  327. package/dist/chunk-3NYIXVCT.js.map +0 -1
  328. package/dist/chunk-6W3QH3QW.js.map +0 -1
  329. package/dist/chunk-7XFQSQYS.js.map +0 -1
  330. package/dist/chunk-BMG3SAXA.js.map +0 -1
  331. package/dist/chunk-FRXS6SC7.js.map +0 -1
  332. package/dist/chunk-LWRIGKFM.js.map +0 -1
  333. package/dist/chunk-N6EM7ESC.js.map +0 -1
  334. package/dist/chunk-NH37SP6V.js.map +0 -1
  335. package/dist/chunk-NUK5XU3P.js.map +0 -1
  336. package/dist/chunk-O4CA53UY.js.map +0 -1
  337. package/dist/chunk-RZDDNH63.js.map +0 -1
  338. package/dist/chunk-SA6P2KS3.js.map +0 -1
  339. package/dist/chunk-SUKPM6DV.js.map +0 -1
  340. package/dist/chunk-VY6BD5KB.js.map +0 -1
  341. /package/dist/{auto-sync-BNCBMU6H.js.map → auto-sync-UQQ6YJSB.js.map} +0 -0
  342. /package/dist/{entity-canonical-id-migration-2YOLMOFC.js.map → briefing-deadline.js.map} +0 -0
  343. /package/dist/{capsule-merge-RNQUP2VL.js.map → capsule-merge-D4BTIJGK.js.map} +0 -0
  344. /package/dist/{chunk-ESDOQEJM.js.map → chunk-2AKIVSHP.js.map} +0 -0
  345. /package/dist/{chunk-BWF3KNSQ.js.map → chunk-2EXF6IIB.js.map} +0 -0
  346. /package/dist/{chunk-AGCEJDG2.js.map → chunk-2ONKXEC7.js.map} +0 -0
  347. /package/dist/{chunk-ZSEFGDCI.js.map → chunk-2TGIKMMZ.js.map} +0 -0
  348. /package/dist/{chunk-MCS4LIXP.js.map → chunk-43TUWQNR.js.map} +0 -0
  349. /package/dist/{chunk-Q6PYCPHO.js.map → chunk-44EUCSG4.js.map} +0 -0
  350. /package/dist/{chunk-2J6BIOVN.js.map → chunk-4FM35YIA.js.map} +0 -0
  351. /package/dist/{chunk-2NLCDNGA.js.map → chunk-564YP3DW.js.map} +0 -0
  352. /package/dist/{chunk-YY6PWFUC.js.map → chunk-6ZAU7LAR.js.map} +0 -0
  353. /package/dist/{chunk-HCPVL6SF.js.map → chunk-72CBJ5VP.js.map} +0 -0
  354. /package/dist/{chunk-AF4UIHON.js.map → chunk-74AY3S7U.js.map} +0 -0
  355. /package/dist/{chunk-5IDQVE4U.js.map → chunk-A3UFV4K3.js.map} +0 -0
  356. /package/dist/{chunk-XFND63OB.js.map → chunk-AHGOOZUC.js.map} +0 -0
  357. /package/dist/{chunk-A7AISUJI.js.map → chunk-AJG2TAMR.js.map} +0 -0
  358. /package/dist/{chunk-2BY56HE6.js.map → chunk-AZLD4CKG.js.map} +0 -0
  359. /package/dist/{chunk-E47UQBYW.js.map → chunk-B35EQQ7L.js.map} +0 -0
  360. /package/dist/{chunk-E6UNM67F.js.map → chunk-B6SPPYGJ.js.map} +0 -0
  361. /package/dist/{chunk-CMOYD5CA.js.map → chunk-CCL2OXFO.js.map} +0 -0
  362. /package/dist/{chunk-SVJ5JVZO.js.map → chunk-CK6GCGMX.js.map} +0 -0
  363. /package/dist/{chunk-QZK6HG4J.js.map → chunk-DF6ZF2BN.js.map} +0 -0
  364. /package/dist/{chunk-CPBYKOTC.js.map → chunk-DJFULNXK.js.map} +0 -0
  365. /package/dist/{chunk-VGRBKEBH.js.map → chunk-DQOGZZJA.js.map} +0 -0
  366. /package/dist/{chunk-YB3WN6XA.js.map → chunk-EC2KVA27.js.map} +0 -0
  367. /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
  368. /package/dist/{chunk-WIBWONL4.js.map → chunk-EZS6QJNC.js.map} +0 -0
  369. /package/dist/{chunk-C7WDWD35.js.map → chunk-FNNGWN3O.js.map} +0 -0
  370. /package/dist/{chunk-PBWJVRKE.js.map → chunk-FT75AQ74.js.map} +0 -0
  371. /package/dist/{chunk-WJCAAVZX.js.map → chunk-GE3ZX6YK.js.map} +0 -0
  372. /package/dist/{chunk-3PVKV3XL.js.map → chunk-HCIRR3BA.js.map} +0 -0
  373. /package/dist/{chunk-BJTFLP3J.js.map → chunk-HEF4BRMT.js.map} +0 -0
  374. /package/dist/{chunk-6UDLN4IA.js.map → chunk-I6ORDT54.js.map} +0 -0
  375. /package/dist/{chunk-N5PISU26.js.map → chunk-IN6U2BS5.js.map} +0 -0
  376. /package/dist/{chunk-3INLTKTW.js.map → chunk-IUQXRRJB.js.map} +0 -0
  377. /package/dist/{chunk-4KS4IHKH.js.map → chunk-JX3E4XCW.js.map} +0 -0
  378. /package/dist/{chunk-SW3WHVKN.js.map → chunk-KAJYSO3U.js.map} +0 -0
  379. /package/dist/{chunk-D76AHITY.js.map → chunk-KETS5A62.js.map} +0 -0
  380. /package/dist/{chunk-LCHFINL4.js.map → chunk-KIWO4327.js.map} +0 -0
  381. /package/dist/{chunk-FC3ZFEXF.js.map → chunk-KJ3MDX4V.js.map} +0 -0
  382. /package/dist/{chunk-7LCGFUMB.js.map → chunk-KQAFEZQX.js.map} +0 -0
  383. /package/dist/{chunk-6TIVVOVU.js.map → chunk-L3EFYRYK.js.map} +0 -0
  384. /package/dist/{chunk-X52SXKVC.js.map → chunk-LMB47UM6.js.map} +0 -0
  385. /package/dist/{chunk-A3WXV7YU.js.map → chunk-LWMLBVGB.js.map} +0 -0
  386. /package/dist/{chunk-KMTMMBEB.js.map → chunk-MC7PXJDP.js.map} +0 -0
  387. /package/dist/{chunk-NMOEOQV4.js.map → chunk-MUNYUSBU.js.map} +0 -0
  388. /package/dist/{chunk-VKUMKVEU.js.map → chunk-OCRLJJOV.js.map} +0 -0
  389. /package/dist/{chunk-XSJL62LE.js.map → chunk-ON77FQXH.js.map} +0 -0
  390. /package/dist/{chunk-C3HRYVGD.js.map → chunk-POJRFSJM.js.map} +0 -0
  391. /package/dist/{chunk-LKRXGOQW.js.map → chunk-QA3Y2O6H.js.map} +0 -0
  392. /package/dist/{chunk-QFTNWDJ6.js.map → chunk-RA7YRL6H.js.map} +0 -0
  393. /package/dist/{chunk-WQFHHJWK.js.map → chunk-RJDYDF5K.js.map} +0 -0
  394. /package/dist/{chunk-E3DL3CAL.js.map → chunk-ROAKLYOL.js.map} +0 -0
  395. /package/dist/{chunk-NWIT3U2N.js.map → chunk-S5CQI2KF.js.map} +0 -0
  396. /package/dist/{chunk-P6P35FY4.js.map → chunk-SDESKFKT.js.map} +0 -0
  397. /package/dist/{chunk-OD7ZXCUF.js.map → chunk-SFRBUBUZ.js.map} +0 -0
  398. /package/dist/{chunk-O7GNSHFF.js.map → chunk-SPTPBKZX.js.map} +0 -0
  399. /package/dist/{chunk-HI53EK3Y.js.map → chunk-TC55M5PO.js.map} +0 -0
  400. /package/dist/{chunk-FOKTW6GY.js.map → chunk-UCLJTGP3.js.map} +0 -0
  401. /package/dist/{chunk-FYZXZUGU.js.map → chunk-UQBOPCDK.js.map} +0 -0
  402. /package/dist/{chunk-754XN6LX.js.map → chunk-V27FK6D6.js.map} +0 -0
  403. /package/dist/{chunk-DM6SOROF.js.map → chunk-V6Z4NAJZ.js.map} +0 -0
  404. /package/dist/{chunk-5FNZ3G6X.js.map → chunk-VKQI47DJ.js.map} +0 -0
  405. /package/dist/{chunk-MPJDQC4G.js.map → chunk-WJCXUE2J.js.map} +0 -0
  406. /package/dist/{chunk-VCBS5GRQ.js.map → chunk-WY66J4PI.js.map} +0 -0
  407. /package/dist/{chunk-OOOX5C4X.js.map → chunk-XL2EE5W3.js.map} +0 -0
  408. /package/dist/{chunk-V4GPFCJ7.js.map → chunk-XWJUFER3.js.map} +0 -0
  409. /package/dist/{chunk-CZVNOTLR.js.map → chunk-XXR4A33N.js.map} +0 -0
  410. /package/dist/{chunk-CRJX4OMN.js.map → chunk-Y3T5KQCR.js.map} +0 -0
  411. /package/dist/{chunk-KNCR7APE.js.map → chunk-Y77FXULH.js.map} +0 -0
  412. /package/dist/{chunk-2AV2U2SZ.js.map → chunk-YDIOMDBW.js.map} +0 -0
  413. /package/dist/{chunk-IG747LRN.js.map → chunk-YO2JEX2Z.js.map} +0 -0
  414. /package/dist/{chunk-HDT3DMUF.js.map → chunk-ZKK3VMWU.js.map} +0 -0
  415. /package/dist/{first-start-migration-QVD22WWS.js.map → first-start-migration-A6PHIBUQ.js.map} +0 -0
@@ -15,11 +15,13 @@ import {
15
15
  EngramAccessInputError,
16
16
  type EngramAccessRecallRequest,
17
17
  type EngramAccessService,
18
+ type EngramAccessBriefingRequest,
18
19
  } from "./access-service.js";
19
20
  import {
20
21
  tokenCapabilityStore,
21
22
  type TokenCapabilities,
22
23
  } from "./access-token-capabilities.js";
24
+ import { BriefingTimeoutError } from "./briefing-deadline.js";
23
25
  import { parseConfig } from "./config.js";
24
26
  import { readPair, writePair } from "./contradiction/contradiction-review.js";
25
27
  import { createChatSession } from "./chat/chat-session.js";
@@ -859,17 +861,23 @@ test("HTTP briefing endpoint dispatches through the briefing operation", async (
859
861
  assert.equal(body.format, "markdown");
860
862
  assert.equal(body.markdown, "# Briefing");
861
863
  assert.deepEqual(body.json.sections.activeThreads, []);
862
- assert.deepEqual(calls, [
863
- {
864
- since: "24h",
865
- focus: undefined,
866
- includeLocation: undefined,
867
- namespace: "team",
868
- format: "markdown",
869
- maxFollowups: 5,
870
- principal: "panel-user",
871
- },
872
- ]);
864
+ assert.equal(calls.length, 1);
865
+ // SAFETY: the registered handler builds this request after validating the HTTP body; assertions below check its values.
866
+ const captured = calls[0] as EngramAccessBriefingRequest;
867
+ const { abortSignal, ...briefingRequest } = captured;
868
+ assert.ok(
869
+ abortSignal instanceof AbortSignal,
870
+ "the briefing request carries the HTTP request lifetime signal",
871
+ );
872
+ assert.deepEqual(briefingRequest, {
873
+ since: "24h",
874
+ focus: undefined,
875
+ includeLocation: undefined,
876
+ namespace: "team",
877
+ format: "markdown",
878
+ maxFollowups: 5,
879
+ principal: "panel-user",
880
+ });
873
881
 
874
882
  const invalid = await fetch(
875
883
  `http://127.0.0.1:${status.port}/engram/v1/briefing`,
@@ -890,6 +898,27 @@ test("HTTP briefing endpoint dispatches through the briefing operation", async (
890
898
  }
891
899
  });
892
900
 
901
+ test("HTTP briefing endpoint answers 504 briefing_timeout when the request budget is exhausted", async () => {
902
+ const service: EngramAccessService = Object.assign(Object.create(null), {
903
+ briefing: async () => {
904
+ throw new BriefingTimeoutError(30_000);
905
+ },
906
+ });
907
+ const server = new EngramAccessHttpServer({ service, port: 0, authToken: "test-token", adminConsoleEnabled: false });
908
+ const status = await server.start();
909
+ try {
910
+ const response = await fetch(`http://127.0.0.1:${status.port}/engram/v1/briefing`, {
911
+ method: "POST",
912
+ headers: { authorization: "Bearer test-token", "content-type": "application/json" },
913
+ body: JSON.stringify({}),
914
+ });
915
+ assert.equal(response.status, 504);
916
+ assert.deepEqual(await response.json(), { error: "briefing timed out after 30000ms", code: "briefing_timeout" });
917
+ } finally {
918
+ await server.stop();
919
+ }
920
+ });
921
+
893
922
  test("HTTP contradiction scan uses writable namespace resolver", async () => {
894
923
  const resolverCalls: Array<{
895
924
  namespace: string | undefined;
@@ -2136,7 +2165,7 @@ test("HTTP offline snapshot rejects out-of-range baseline mtimes as validation e
2136
2165
  assert.equal(response.status, 400);
2137
2166
  assert.equal(body.code, "validation_error");
2138
2167
  assert.equal(body.details?.[0]?.field, "baseFiles.0.mtimeMs");
2139
- assert.match(body.details?.[0]?.message ?? "", /less than or equal/);
2168
+ assert.match(body.details?.[0]?.message ?? "", /<=8640000000000000/);
2140
2169
  assert.equal(calls, 0);
2141
2170
  } finally {
2142
2171
  await server.stop();
@@ -10,6 +10,7 @@ import { log } from "./logger.js";
10
10
  import { resolveNamespaceCapabilities } from "./capabilities.js";
11
11
  import { WriteRateLimiter, type WriteRateLimitReservation } from "./write-rate-limiter.js";
12
12
  import { abortError, isAbortError } from "./abort-error.js";
13
+ import { BriefingTimeoutError } from "./briefing-deadline.js";
13
14
  import { EngramAccessForbiddenError } from "./access-errors.js";
14
15
  import {
15
16
  EngramAccessInputError,
@@ -500,6 +501,10 @@ export class EngramAccessHttpServer extends ReviewDeckAccessHttpBase {
500
501
  res.once("close", abortDisconnectedRequest);
501
502
  correlationIdStore.run(correlationId, () => {
502
503
  void this.handle(req, res, correlationId, abortController.signal).catch((err) => {
504
+ if (err instanceof BriefingTimeoutError) {
505
+ this.respondJson(res, 504, { error: err.message, code: "briefing_timeout" });
506
+ return;
507
+ }
503
508
  if (isAbortError(err)) {
504
509
  if (!res.destroyed && !res.writableEnded) {
505
510
  res.end();
@@ -1979,6 +1984,7 @@ export class EngramAccessHttpServer extends ReviewDeckAccessHttpBase {
1979
1984
  service: this.service,
1980
1985
  principal: this.resolveRequestPrincipal(req),
1981
1986
  respondJson: (status, payload) => this.respondJson(res, status, payload),
1987
+ abortSignal,
1982
1988
  });
1983
1989
  return;
1984
1990
  }
@@ -15,7 +15,7 @@ import {
15
15
  } from "./access-schema.js";
16
16
 
17
17
  export { reapplyCategoryCoercion };
18
- export { applyBriefingLocationContext } from "./location/tagging.js";
18
+ export { buildWithBriefingLocation } from "./location/tagging.js";
19
19
 
20
20
  export function splitCanonicalWriteRequest<T extends { rawCategory?: string; category?: string }>(
21
21
  request: T,
@@ -29,8 +29,9 @@ import {
29
29
  type MemoryScopePlan,
30
30
  NamespaceNotWritableError,
31
31
  } from "./access-service.js";
32
- import { applyBriefingLocationContext, reapplyCategoryCoercion, splitCanonicalWriteRequest } from "./access-observe-write-category.js";
32
+ import { buildWithBriefingLocation, reapplyCategoryCoercion, splitCanonicalWriteRequest } from "./access-observe-write-category.js";
33
33
  import { abortError } from "./abort-error.js";
34
+ import { withBriefingDeadline } from "./briefing-deadline.js";
34
35
  import { extractionForceFlush } from "./access-extraction-force-flush.js";
35
36
  import { ObserveTranscriptPersister, observeTranscriptSessionKey } from "./access-observe-transcript.js";
36
37
  import { FileCalendarSource, buildBriefing, parseBriefingFocus, parseBriefingWindow } from "./briefing.js";
@@ -410,7 +411,6 @@ export class AccessObserveWriteSurface {
410
411
  }
411
412
 
412
413
  const namespace = this.deps.resolveReadableNamespace(request.namespace, request.principal);
413
- const storage = await this.deps.orchestrator.getStorage(namespace);
414
414
 
415
415
  const token =
416
416
  typeof request.since === "string" && request.since.trim().length > 0
@@ -457,23 +457,28 @@ export class AccessObserveWriteSurface {
457
457
  ? new FileCalendarSource(config.briefing.calendarSource)
458
458
  : undefined;
459
459
 
460
- const result = await applyBriefingLocationContext(await buildBriefing({
461
- storage,
462
- namespace,
463
- window,
464
- focus,
465
- calendarSource,
466
- maxFollowups,
467
- allowLlm: config.briefing.llmFollowups,
468
- openaiApiKey: config.openaiApiKey,
469
- openaiBaseUrl: config.openaiBaseUrl,
470
- model: config.model,
471
- // Without a direct OpenAI key, route follow-ups through the configured
472
- // LLM chain (gateway model source or local LLM) — same fallback every
473
- // other LLM feature uses. A configured key keeps its precedence so
474
- // existing deployments are unchanged.
475
- followupGenerator: config.openaiApiKey ? undefined : this.deps.orchestrator.briefingChainFollowupGenerator,
476
- }), request.includeLocation, storage.dir, window.from.toISOString(), config.location);
460
+ // Storage acquisition and the briefing body share one request budget.
461
+ const result = await withBriefingDeadline(async (signal) => {
462
+ const storage = await this.deps.orchestrator.getStorage(namespace);
463
+ return buildWithBriefingLocation(request.includeLocation, storage.dir, window.from.toISOString(), config.location, () => buildBriefing({
464
+ storage,
465
+ namespace,
466
+ window,
467
+ focus,
468
+ calendarSource,
469
+ maxFollowups,
470
+ allowLlm: config.briefing.llmFollowups,
471
+ openaiApiKey: config.openaiApiKey,
472
+ openaiBaseUrl: config.openaiBaseUrl,
473
+ model: config.model,
474
+ // Without a direct OpenAI key, route follow-ups through the configured
475
+ // LLM chain (gateway model source or local LLM) — same fallback every
476
+ // other LLM feature uses. A configured key keeps its precedence so
477
+ // existing deployments are unchanged.
478
+ followupGenerator: config.openaiApiKey ? undefined : this.deps.orchestrator.briefingChainFollowupGenerator,
479
+ abortSignal: signal,
480
+ }));
481
+ }, request.abortSignal);
477
482
 
478
483
  return {
479
484
  format,
@@ -23,7 +23,7 @@ import {
23
23
  retainedCategoryAlias,
24
24
  suggestionSubmitRequestSchema,
25
25
  } from "./access-schema.js";
26
- import { EngramAccessInputError, type EngramAccessService } from "./access-service.js";
26
+ import { EngramAccessInputError, type EngramAccessService, type EngramAccessBriefingRequest } from "./access-service.js";
27
27
  import { enforceNamespaceAllowList, tokenCapabilityStore } from "./access-token-capabilities.js";
28
28
  import { projectTagProjectId } from "./coding/coding-namespace.js";
29
29
  import {
@@ -381,7 +381,23 @@ defineOperation({ name: "memory_promote", description: "Promote memory.", schema
381
381
  defineOperation({ name: "memory_outcome", description: "Record outcome.", schema: strictSchema({ memoryId: S.str, outcome: S.str, namespace: S.str, sessionKey: S.str, timestamp: S.str }), handler: async (input, ctx) => { const o = optStr(input.outcome); if (o !== "success" && o !== "failure") throw new EngramAccessInputError("memory_outcome: outcome must be \"success\" or \"failure\"; got " + JSON.stringify(o)); return { result: await ctx.service.memoryOutcome({ memoryId: optStr(input.memoryId) ?? "", outcome: o, namespace: optStr(input.namespace), sessionKey: optStr(input.sessionKey), timestamp: optStr(input.timestamp), principal: ctx.authenticatedPrincipal }) }; } });
382
382
  defineOperation({ name: "memory_action_apply", description: "Apply action.", schema: strictSchema({ action: S.str, outcome: S.str, reason: S.str, memoryId: S.str, namespace: S.str, sessionKey: S.str, content: S.str, category: S.str, linkTargetId: S.str, linkType: S.str, linkStrength: S.num, artifactType: S.str, execute: S.bool, sourcePrompt: S.str, dryRun: S.bool }), handler: async (input, ctx) => ({ result: await ctx.service.memoryActionApply({ action: optStr(input.action) ?? "", outcome: optStr(input.outcome), reason: optStr(input.reason), memoryId: optStr(input.memoryId) ?? "", namespace: optStr(input.namespace), sessionKey: optStr(input.sessionKey), content: optStr(input.content), category: optStr(input.category), linkTargetId: optStr(input.linkTargetId), linkType: optStr(input.linkType), linkStrength: optNum(input.linkStrength), artifactType: optStr(input.artifactType), execute: optBool(input.execute), sourcePrompt: optStr(input.sourcePrompt), dryRun: input.dryRun === true, principal: ctx.authenticatedPrincipal }) }) });
383
383
  defineOperation({ name: "context_checkpoint", description: "Context checkpoint.", schema: strictSchema({ sessionKey: S.str, context: S.str, namespace: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.contextCheckpoint({ sessionKey: optStr(input.sessionKey) ?? "", context: optStr(input.context) ?? "", namespace: optStr(input.namespace), principal: ctx.authenticatedPrincipal }) }) });
384
- defineOperation({ name: "briefing", description: "Daily briefing.", schema: strictSchema({ since: S.str, focus: S.str, namespace: S.str, includeLocation: S.bool, format: S.str, maxFollowups: S.num }), handler: async (input, ctx) => { const rf = optStr(input.format); const fe = validateBriefingFormat(rf); if (fe) throw new EngramAccessInputError(fe); return { result: await ctx.service.briefing({ since: optStr(input.since), focus: optStr(input.focus), namespace: optStr(input.namespace), includeLocation: optBool(input.includeLocation), format: rf as "json" | "markdown" | undefined, maxFollowups: optNum(input.maxFollowups), principal: ctx.authenticatedPrincipal }) }; } });
384
+ defineOperation({
385
+ name: "briefing", description: "Daily briefing.",
386
+ schema: strictSchema({ since: S.str, focus: S.str, namespace: S.str, includeLocation: S.bool, format: S.str, maxFollowups: S.num }),
387
+ handler: async (input, ctx) => {
388
+ const rf = optStr(input.format);
389
+ const fe = validateBriefingFormat(rf);
390
+ if (fe) throw new EngramAccessInputError(fe);
391
+ // SAFETY: validateBriefingFormat rejects every format except json, markdown, or undefined.
392
+ const request: EngramAccessBriefingRequest = {
393
+ since: optStr(input.since), focus: optStr(input.focus), namespace: optStr(input.namespace),
394
+ includeLocation: optBool(input.includeLocation), format: rf as "json" | "markdown" | undefined,
395
+ maxFollowups: optNum(input.maxFollowups), principal: ctx.authenticatedPrincipal,
396
+ };
397
+ if (ctx.abortSignal) request.abortSignal = ctx.abortSignal;
398
+ return { result: await ctx.service.briefing(request) };
399
+ },
400
+ });
385
401
 
386
402
  // === CONTRADICTION/REVIEW ===
387
403
  defineOperation({ name: "review_list", description: "List review pairs.", schema: strictSchema({ filter: S.str, namespace: S.str, limit: S.num }),
@@ -369,11 +369,7 @@ export function reapplyCategoryCoercion<T extends object>(
369
369
  const categoryWireSchema = z.enum(
370
370
  [...MEMORY_CATEGORY_CANONICAL_INPUT, ...MEMORY_CATEGORY_ALIAS_INPUT],
371
371
  {
372
- errorMap: () => ({
373
- message:
374
- `category must be one of: ${[...MEMORY_CATEGORY_CANONICAL_INPUT, ...MEMORY_CATEGORY_ALIAS_INPUT].join(", ")}; ` +
375
- 'for project state/facts use "fact"',
376
- }),
372
+ error: `category must be one of: ${[...MEMORY_CATEGORY_CANONICAL_INPUT, ...MEMORY_CATEGORY_ALIAS_INPUT].join(", ")}; for project state/facts use "fact"`,
377
373
  },
378
374
  );
379
375
 
@@ -454,7 +450,7 @@ export const reviewDispositionRequestSchema = z.object({
454
450
  export const trustZonePromoteRequestSchema = z.object({
455
451
  recordId: z.string().trim().min(1, "recordId is required"),
456
452
  targetZone: z.enum(["working", "trusted"], {
457
- errorMap: () => ({ message: "targetZone must be 'working' or 'trusted'" }),
453
+ error: "targetZone must be 'working' or 'trusted'",
458
454
  }),
459
455
  promotionReason: z.string().trim().min(1, "promotionReason is required"),
460
456
  recordedAt: z.string().trim().optional(),
@@ -662,16 +658,13 @@ export const offlineSyncSnapshotRequestSchema = z.object({
662
658
  .optional(),
663
659
  });
664
660
 
665
- export const offlineSyncApplyRequestSchema = z
666
- .object({
667
- namespace: namespaceSchema,
668
- changeset: z.unknown(),
669
- returnCurrentFiles: z.boolean().optional(),
670
- })
671
- .refine((value) => value.changeset !== undefined && value.changeset !== null, {
672
- message: "changeset is required",
673
- path: ["changeset"],
674
- });
661
+ export const offlineSyncApplyRequestSchema = z.object({
662
+ namespace: namespaceSchema,
663
+ // zod 4: refine messages cannot override its synthesized nonoptional check,
664
+ // so presence is enforced on the field itself.
665
+ changeset: z.custom<unknown>((value) => value !== undefined && value !== null, "changeset is required"),
666
+ returnCurrentFiles: z.boolean().optional(),
667
+ });
675
668
 
676
669
  export const offlineSyncFilesRequestSchema = z.object({
677
670
  namespace: namespaceSchema,
@@ -693,8 +686,11 @@ export const offlineSyncFileContentRequestSchema = z.object({
693
686
  // Action confidence
694
687
  // ---------------------------------------------------------------------------
695
688
 
689
+ // Outer .optional() keeps the inferred property optional: a transform-typed
690
+ // property becomes required-with-undefined under zod 4 inference, breaking
691
+ // object literals that legitimately omit the key.
696
692
  const nullableOptional = <T extends z.ZodTypeAny>(schema: T) =>
697
- schema.optional().nullable().transform((value) => value ?? undefined);
693
+ schema.nullable().transform((value) => value ?? undefined).optional();
698
694
 
699
695
  const actionConfidenceRuleSchema = z
700
696
  .object({
@@ -507,6 +507,11 @@ export interface EngramAccessBriefingRequest extends LocationContextRequestOptio
507
507
  maxFollowups?: number;
508
508
  /** Caller principal for namespace access checks. Transport-bound — never from untrusted payloads. */
509
509
  principal?: string;
510
+ /**
511
+ * Transport request lifetime. When it aborts, the briefing stops and
512
+ * rejects with that AbortError instead of running on (issue #3139).
513
+ */
514
+ abortSignal?: AbortSignal;
510
515
  }
511
516
 
512
517
  /** Response for `remnic_briefing`. */
@@ -0,0 +1,173 @@
1
+ import assert from "node:assert/strict";
2
+ import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import test, { type TestContext } from "node:test";
6
+ import { abortError } from "./abort-error.js";
7
+ import fs from "node:fs/promises";
8
+ import { syncBuiltinESMExports } from "node:module";
9
+ import { AccessObserveWriteSurface } from "./access-observe-write-surface.js";
10
+ import { Orchestrator } from "./orchestrator.js";
11
+ import { buildBriefing, type ParsedBriefingWindow } from "./briefing.js";
12
+ import type { CorpusReadOptions } from "./corpus-read-cancellation.js";
13
+ import { StorageManager } from "./storage.js";
14
+ import type { WindowedMemoryReadOptions, WindowedMemoryReadResult } from "./storage/windowed-memory-read.js";
15
+ import type { EntityFile, MemoryFile } from "./types.js";
16
+
17
+ const WINDOW: ParsedBriefingWindow = {
18
+ from: new Date("2026-04-10T00:00:00.000Z"),
19
+ to: new Date("2026-04-11T00:00:00.000Z"),
20
+ label: "test-window",
21
+ };
22
+ const MEMORY: MemoryFile = {
23
+ path: "/synthetic/mem.md",
24
+ frontmatter: {
25
+ id: "synthetic-mem",
26
+ category: "fact",
27
+ created: "2026-04-10T01:00:00.000Z",
28
+ updated: "2026-04-10T02:00:00.000Z",
29
+ source: "test",
30
+ confidence: 0.9,
31
+ confidenceTier: "explicit",
32
+ tags: [],
33
+ },
34
+ content: "synthetic briefing memory",
35
+ };
36
+ const ENTITY: EntityFile = {
37
+ name: "SyntheticEntity",
38
+ type: "project",
39
+ updated: "2026-04-10T03:00:00.000Z",
40
+ facts: ["synthetic fact"],
41
+ timeline: [],
42
+ relationships: [],
43
+ activity: [],
44
+ aliases: [],
45
+ };
46
+
47
+ function makeStorage(t: TestContext): StorageManager {
48
+ const dir = mkdtempSync(path.join(os.tmpdir(), "remnic-briefing-abort-"));
49
+ t.after(() => rmSync(dir, { recursive: true, force: true }));
50
+ const storage = new StorageManager(dir);
51
+ t.mock.method(storage, "readMemoriesWindow", async (_options: WindowedMemoryReadOptions) => ({
52
+ memories: [MEMORY],
53
+ filePaths: [MEMORY.path],
54
+ }));
55
+ t.mock.method(storage, "readAllEntityFiles", async (_options?: CorpusReadOptions) => [ENTITY]);
56
+ return storage;
57
+ }
58
+
59
+ function makeStallingStorage(t: TestContext) {
60
+ const storage = makeStorage(t);
61
+ const fallback = Promise.withResolvers<void>();
62
+ // The fallback releases broken signal plumbing too, so the regression cannot hang.
63
+ t.mock.method(
64
+ storage,
65
+ "readMemoriesWindow",
66
+ (options: WindowedMemoryReadOptions): Promise<WindowedMemoryReadResult> => {
67
+ const signal = options.abortSignal;
68
+ if (!signal) return fallback.promise.then(() => ({ memories: [], filePaths: [] }));
69
+ const read = Promise.withResolvers<WindowedMemoryReadResult>();
70
+ const onAbort = () => read.reject(abortError("corpus read aborted"));
71
+ if (signal.aborted) {
72
+ onAbort();
73
+ return read.promise;
74
+ }
75
+ signal.addEventListener("abort", onAbort, { once: true });
76
+ void fallback.promise.then(() => {
77
+ signal.removeEventListener("abort", onAbort);
78
+ read.resolve({ memories: [], filePaths: [] });
79
+ });
80
+ return read.promise;
81
+ }
82
+ );
83
+ return { storage, releaseFallback: fallback.resolve };
84
+ }
85
+
86
+ test("buildBriefing rejects with an AbortError when the caller's cancel signal fires mid-read", async (t) => {
87
+ const { storage, releaseFallback } = makeStallingStorage(t);
88
+ const controller = new AbortController();
89
+ const call = buildBriefing({ storage, window: WINDOW, allowLlm: false, abortSignal: controller.signal });
90
+ controller.abort();
91
+ releaseFallback();
92
+ await assert.rejects(call, { name: "AbortError", message: /abort|cancel/i });
93
+ });
94
+
95
+ test("buildBriefing rejects when the caller's cancel signal is already aborted", async (t) => {
96
+ const { storage, releaseFallback } = makeStallingStorage(t);
97
+ const controller = new AbortController();
98
+ controller.abort();
99
+ const call = buildBriefing({ storage, window: WINDOW, allowLlm: false, abortSignal: controller.signal });
100
+ releaseFallback();
101
+ await assert.rejects(call, { name: "AbortError" });
102
+ });
103
+
104
+ test("a cancelled briefing does not drain the correction-notification queue", async (t) => {
105
+ const storage = makeStorage(t);
106
+ const queueDir = path.join(storage.dir, "state", "corrections");
107
+ mkdirSync(queueDir, { recursive: true });
108
+ const queueFile = path.join(queueDir, "notifications.jsonl");
109
+ writeFileSync(
110
+ queueFile,
111
+ `${JSON.stringify({ planId: "synthetic-plan", summary: "synthetic correction", undoCommand: "remnic correct plan synthetic-plan", createdAt: "2026-04-10T04:00:00.000Z" })}\n`
112
+ );
113
+ const controller = new AbortController();
114
+ const call = buildBriefing({
115
+ storage,
116
+ window: WINDOW,
117
+ abortSignal: controller.signal,
118
+ // Cancel after reads, just before the queue-draining phase.
119
+ followupGenerator: async () => {
120
+ controller.abort();
121
+ return [];
122
+ },
123
+ });
124
+ await assert.rejects(call, { name: "AbortError" });
125
+ assert.ok(existsSync(queueFile), "a cancelled briefing must not consume correction notifications");
126
+ });
127
+
128
+ test("buildBriefing returns a non-empty briefing when nothing is cancelled", async (t) => {
129
+ const result = await buildBriefing({ storage: makeStorage(t), window: WINDOW, allowLlm: false });
130
+ assert.equal(result.sections.activeThreads.length, 1);
131
+ assert.equal(result.sections.recentEntities.length, 1);
132
+ assert.ok(result.markdown.length > 0);
133
+ assert.deepEqual(result.window, { from: "2026-04-10T00:00:00.000Z", to: "2026-04-11T00:00:00.000Z" });
134
+ });
135
+
136
+ test("an HTTP/MCP briefing cancelled during the location read keeps the notification queue", async (t) => {
137
+ const storage = makeStorage(t);
138
+ const queueDir = path.join(storage.dir, "state", "corrections");
139
+ mkdirSync(queueDir, { recursive: true });
140
+ const queueFile = path.join(queueDir, "notifications.jsonl");
141
+ writeFileSync(
142
+ queueFile,
143
+ `${JSON.stringify({ planId: "synthetic-plan", summary: "synthetic correction", undoCommand: "remnic correct plan synthetic-plan", createdAt: "2026-04-10T04:00:00.000Z" })}\n`
144
+ );
145
+ const controller = new AbortController();
146
+ const read: (file: string, encoding: "utf-8") => Promise<string> = fs.readFile;
147
+ t.mock.method(fs, "readFile", async (file: string) => {
148
+ if (file.endsWith(path.join("state", "locations", "sync.json"))) controller.abort(abortError("deadline"));
149
+ return read(file, "utf-8");
150
+ });
151
+ syncBuiltinESMExports();
152
+ t.after(() => {
153
+ t.mock.restoreAll();
154
+ syncBuiltinESMExports();
155
+ });
156
+ // Object.create yields untyped values, so no assertion is needed: briefing() reads only these members.
157
+ const orchestrator: Orchestrator = Object.assign(Object.create(Orchestrator.prototype), {
158
+ config: {
159
+ briefing: { enabled: true, defaultWindow: "24h", defaultFormat: "markdown", maxFollowups: 0, llmFollowups: false },
160
+ location: { enabled: true, tagging: { enabled: true }, timezone: "UTC" },
161
+ },
162
+ getStorage: async () => storage,
163
+ });
164
+ const surface = new AccessObserveWriteSurface(
165
+ Object.assign(Object.create(null), { orchestrator, resolveReadableNamespace: () => "default" }),
166
+ );
167
+
168
+ await assert.rejects(
169
+ surface.briefing({ includeLocation: true, abortSignal: controller.signal }),
170
+ { name: "AbortError" },
171
+ );
172
+ assert.ok(existsSync(queueFile), "a briefing cancelled during the location read must not consume notifications");
173
+ });
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Issue #3139 — the briefing's default deadline.
3
+ *
4
+ * The budget is a server-side limit, not a client cancellation: exhausting it
5
+ * must surface as an explicit TimeoutError, never as an empty result.
6
+ */
7
+
8
+ import assert from "node:assert/strict";
9
+ import test from "node:test";
10
+
11
+ import {
12
+ BRIEFING_DEADLINE_MS,
13
+ BriefingTimeoutError,
14
+ withBriefingDeadline,
15
+ } from "./briefing-deadline.js";
16
+
17
+ test("withBriefingDeadline rejects with a TimeoutError when the default budget is exhausted", async (t) => {
18
+ t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 0 });
19
+
20
+ const pending = withBriefingDeadline(
21
+ () => Promise.withResolvers<never>().promise,
22
+ );
23
+
24
+ t.mock.timers.tick(BRIEFING_DEADLINE_MS);
25
+
26
+ await assert.rejects(pending, (err) => {
27
+ assert.ok(
28
+ err instanceof BriefingTimeoutError,
29
+ "budget exhaustion must surface as a timeout",
30
+ );
31
+ assert.equal(err.name, "TimeoutError");
32
+ assert.equal(err.deadlineMs, BRIEFING_DEADLINE_MS);
33
+ return true;
34
+ });
35
+ });
36
+
37
+ test("withBriefingDeadline clears its timer once the run settles", async (t) => {
38
+ t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 0 });
39
+ let observed: AbortSignal | undefined;
40
+
41
+ const result = await withBriefingDeadline(async (signal) => {
42
+ observed = signal;
43
+ return "briefing";
44
+ });
45
+
46
+ assert.equal(result, "briefing");
47
+ t.mock.timers.tick(BRIEFING_DEADLINE_MS);
48
+ assert.equal(
49
+ observed?.aborted,
50
+ false,
51
+ "the budget timer must be cleared when the run settles, not left to fire afterwards",
52
+ );
53
+ });
54
+
55
+ test("withBriefingDeadline preserves work failures and clears their timer", async (t) => {
56
+ t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 0 });
57
+ const failure = new Error("synthetic work failure");
58
+ const signals: AbortSignal[] = [];
59
+
60
+ const pending = withBriefingDeadline(async (signal) => {
61
+ signals.push(signal);
62
+ throw failure;
63
+ });
64
+
65
+ await assert.rejects(pending, (err) => err === failure);
66
+ assert.equal(signals.length, 1);
67
+ t.mock.timers.tick(BRIEFING_DEADLINE_MS);
68
+ assert.equal(signals[0].aborted, false);
69
+ });
70
+
71
+ test("withBriefingDeadline normalizes arbitrary caller cancellation to AbortError", async () => {
72
+ const controller = new AbortController();
73
+ const pending = withBriefingDeadline(
74
+ () => Promise.withResolvers<never>().promise,
75
+ controller.signal,
76
+ );
77
+ controller.abort(new Error("synthetic caller cancellation"));
78
+
79
+ await assert.rejects(pending, (err) => {
80
+ assert.ok(err instanceof Error);
81
+ assert.equal(err.name, "AbortError");
82
+ return true;
83
+ });
84
+ });
@@ -0,0 +1,33 @@
1
+ import { isAbortError, raceAbort } from "./abort-error.js";
2
+
3
+ export const BRIEFING_DEADLINE_MS = 30_000;
4
+
5
+ export class BriefingTimeoutError extends Error {
6
+ constructor(readonly deadlineMs: number) {
7
+ super(`briefing timed out after ${deadlineMs}ms`);
8
+ this.name = "TimeoutError";
9
+ }
10
+ }
11
+
12
+ export async function withBriefingDeadline<T>(
13
+ run: (signal: AbortSignal) => Promise<T>,
14
+ abortSignal?: AbortSignal
15
+ ): Promise<T> {
16
+ const controller = new AbortController();
17
+ const signal = abortSignal ? AbortSignal.any([abortSignal, controller.signal]) : controller.signal;
18
+ const timer = setTimeout(
19
+ () => controller.abort(new BriefingTimeoutError(BRIEFING_DEADLINE_MS)),
20
+ BRIEFING_DEADLINE_MS
21
+ );
22
+ try {
23
+ signal.throwIfAborted();
24
+ return await raceAbort(run(signal), signal, "briefing aborted");
25
+ } catch (err) {
26
+ // raceAbort normalizes cancellation; retain the distinct deadline reason.
27
+ const reason: unknown = signal.reason;
28
+ if (signal.aborted && (reason instanceof BriefingTimeoutError || isAbortError(reason))) throw reason;
29
+ throw err;
30
+ } finally {
31
+ clearTimeout(timer);
32
+ }
33
+ }
@@ -0,0 +1,47 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { safeReadMemories } from "./briefing-window.js";
4
+ import type { CorpusReadOptions } from "./corpus-read-cancellation.js";
5
+ import type { MemoryFile } from "./types.js";
6
+
7
+ test("caller cancellation reaches the signal-aware legacy briefing scan", async () => {
8
+ const controller = new AbortController();
9
+ const started = Promise.withResolvers<AbortSignal>();
10
+ const release = Promise.withResolvers<void>();
11
+ const reader = {
12
+ supportsAbortSignal: true,
13
+ async readAllMemories(options?: CorpusReadOptions): Promise<MemoryFile[]> {
14
+ assert.ok(options?.abortSignal);
15
+ started.resolve(options.abortSignal);
16
+ await release.promise;
17
+ options.abortSignal.throwIfAborted();
18
+ return [];
19
+ },
20
+ };
21
+ const result = safeReadMemories(
22
+ reader,
23
+ {
24
+ from: new Date("2026-04-10T00:00:00.000Z"),
25
+ to: new Date("2026-04-11T00:00:00.000Z"),
26
+ label: "yesterday",
27
+ },
28
+ { signal: controller.signal }
29
+ ).then(
30
+ () => ({ ok: true as const }),
31
+ (error) => ({ ok: false as const, error })
32
+ );
33
+ try {
34
+ const scanSignal = await started.promise;
35
+ assert.equal(scanSignal.aborted, false);
36
+ controller.abort();
37
+ release.resolve();
38
+ const outcome = await result;
39
+ assert.equal(outcome.ok, false, "a cancelled scan must reject, not return an empty corpus");
40
+ assert.ok(outcome.error instanceof Error);
41
+ assert.equal(outcome.error.name, "AbortError");
42
+ assert.equal(scanSignal.aborted, true, "the underlying scan must stop too");
43
+ } finally {
44
+ release.resolve();
45
+ await result;
46
+ }
47
+ });