@remnic/core 9.3.729 → 9.3.730

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 (345) hide show
  1. package/dist/access-boundary.d.ts +6 -5
  2. package/dist/access-boundary.js +13 -13
  3. package/dist/access-cli.js +34 -33
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.d.ts +6 -5
  6. package/dist/access-http.js +19 -19
  7. package/dist/access-mcp.d.ts +6 -5
  8. package/dist/access-mcp.js +18 -18
  9. package/dist/access-operations-batch.js +16 -16
  10. package/dist/access-operations.d.ts +11 -10
  11. package/dist/access-operations.js +17 -17
  12. package/dist/access-schema.d.ts +42 -42
  13. package/dist/{access-service-BXMJqkTA.d.ts → access-service-Byoe3HsT.d.ts} +18 -3
  14. package/dist/access-service.d.ts +6 -5
  15. package/dist/access-service.js +12 -12
  16. package/dist/access-surface-catalog.d.ts +6 -5
  17. package/dist/action-confidence.d.ts +1 -1
  18. package/dist/active-memory-bridge.d.ts +1 -1
  19. package/dist/active-recall.d.ts +1 -1
  20. package/dist/active-recall.js +2 -2
  21. package/dist/{auto-sync-F3KCSQFJ.js → auto-sync-G3V5AN4C.js} +2 -2
  22. package/dist/behavior-learner.d.ts +1 -1
  23. package/dist/behavior-signals.d.ts +1 -1
  24. package/dist/bootstrap.d.ts +5 -4
  25. package/dist/briefing.d.ts +1 -1
  26. package/dist/briefing.js +3 -3
  27. package/dist/buffer-surprise-report.d.ts +1 -1
  28. package/dist/buffer.d.ts +1 -1
  29. package/dist/calibration.d.ts +1 -1
  30. package/dist/capabilities.d.ts +55 -2
  31. package/dist/capabilities.js +5 -1
  32. package/dist/{catalog-bMczlO2G.d.ts → catalog-DM1nk7cM.d.ts} +1 -1
  33. package/dist/causal-behavior.d.ts +1 -1
  34. package/dist/causal-consolidation.d.ts +1 -1
  35. package/dist/causal-consolidation.js +4 -4
  36. package/dist/causal-trajectory-graph.d.ts +1 -1
  37. package/dist/{chunk-4NOI577P.js → chunk-24ZLC5QN.js} +2 -2
  38. package/dist/{chunk-DMQWV6SQ.js → chunk-5RZOFIDL.js} +2 -2
  39. package/dist/{chunk-UM5AWJNQ.js → chunk-646B5ERJ.js} +62 -37
  40. package/dist/chunk-646B5ERJ.js.map +1 -0
  41. package/dist/{chunk-H5BWGCRZ.js → chunk-6TUWSUUD.js} +51 -47
  42. package/dist/{chunk-H5BWGCRZ.js.map → chunk-6TUWSUUD.js.map} +1 -1
  43. package/dist/{chunk-36SEDFAU.js → chunk-C5WN74HH.js} +2 -2
  44. package/dist/{chunk-MLKWJOAJ.js → chunk-CGPHMNL4.js} +2 -2
  45. package/dist/{chunk-R6OVFAX6.js → chunk-DJECGBBM.js} +7 -2
  46. package/dist/{chunk-R6OVFAX6.js.map → chunk-DJECGBBM.js.map} +1 -1
  47. package/dist/{chunk-3RCBIOOJ.js → chunk-ESF7TRYJ.js} +18 -2
  48. package/dist/{chunk-3RCBIOOJ.js.map → chunk-ESF7TRYJ.js.map} +1 -1
  49. package/dist/{chunk-EY6MDMHK.js → chunk-F6OEXJQQ.js} +2 -2
  50. package/dist/{chunk-M4V2JVSZ.js → chunk-FFUCCKPN.js} +2 -2
  51. package/dist/{chunk-O6YH5F47.js → chunk-FYWUNVFZ.js} +8 -8
  52. package/dist/{chunk-37436GML.js → chunk-GEXI357K.js} +2 -2
  53. package/dist/{chunk-YGIQORJ3.js → chunk-GGL34GCW.js} +3 -3
  54. package/dist/{chunk-4H4F3BFL.js → chunk-GXTYEG7Q.js} +3 -3
  55. package/dist/{chunk-4H4F3BFL.js.map → chunk-GXTYEG7Q.js.map} +1 -1
  56. package/dist/{chunk-WAS3NV46.js → chunk-H3MB3F62.js} +2 -2
  57. package/dist/{chunk-UTHQPSRC.js → chunk-HHNSLPX7.js} +11 -8
  58. package/dist/chunk-HHNSLPX7.js.map +1 -0
  59. package/dist/{chunk-76NHR6ZL.js → chunk-HJWQJUKQ.js} +4 -4
  60. package/dist/{chunk-Y4YD5TYW.js → chunk-IIBFCZA7.js} +3 -3
  61. package/dist/{chunk-UVPL565C.js → chunk-IQOEW5YV.js} +2 -2
  62. package/dist/{chunk-V4GNSDFH.js → chunk-KQYGNGON.js} +2 -2
  63. package/dist/{chunk-CBWI22JN.js → chunk-KSJCXXOU.js} +2 -2
  64. package/dist/{chunk-M4AYVEWS.js → chunk-LUCARK4W.js} +12 -11
  65. package/dist/chunk-LUCARK4W.js.map +1 -0
  66. package/dist/{chunk-I5REUWLH.js → chunk-NIZQH6AU.js} +3 -3
  67. package/dist/{chunk-4ESAR77N.js → chunk-NOU77OHX.js} +2 -2
  68. package/dist/{chunk-BQCHEV7O.js → chunk-O4ZIBPIW.js} +3 -3
  69. package/dist/{chunk-HOHVIVDR.js → chunk-OBJUKYDO.js} +2 -2
  70. package/dist/{chunk-YKBHOBJK.js → chunk-OEHCMALU.js} +56 -4
  71. package/dist/chunk-OEHCMALU.js.map +1 -0
  72. package/dist/{chunk-YOLZS7NY.js → chunk-OTQE66IX.js} +2 -2
  73. package/dist/{chunk-HEDZUSCS.js → chunk-OUITHS6V.js} +246 -368
  74. package/dist/chunk-OUITHS6V.js.map +1 -0
  75. package/dist/{chunk-4T3BMHKD.js → chunk-OZECYVGI.js} +20 -7
  76. package/dist/chunk-OZECYVGI.js.map +1 -0
  77. package/dist/{chunk-C2PG7IEH.js → chunk-P3VJCTVE.js} +2 -2
  78. package/dist/{chunk-EH5ED3C6.js → chunk-PMAQRUN4.js} +4 -4
  79. package/dist/chunk-PMAQRUN4.js.map +1 -0
  80. package/dist/{chunk-7RLCCNHU.js → chunk-Q6BAA57B.js} +4 -3
  81. package/dist/chunk-Q6BAA57B.js.map +1 -0
  82. package/dist/{chunk-HGNOCPZX.js → chunk-QZHF4BWN.js} +6 -6
  83. package/dist/chunk-SYX73XD7.js +283 -0
  84. package/dist/chunk-SYX73XD7.js.map +1 -0
  85. package/dist/{chunk-ASKXIAHD.js → chunk-WDJCZQB4.js} +2 -2
  86. package/dist/{chunk-AQLOP5F4.js → chunk-WNGXQMRI.js} +95 -6
  87. package/dist/chunk-WNGXQMRI.js.map +1 -0
  88. package/dist/{chunk-JYLFZWUX.js → chunk-XYUFGHUW.js} +2 -2
  89. package/dist/{chunk-3TSTGI6F.js → chunk-ZQUAVZNG.js} +2 -2
  90. package/dist/{chunk-4NR2PDZ5.js → chunk-ZVHRSR2R.js} +14 -4
  91. package/dist/chunk-ZVHRSR2R.js.map +1 -0
  92. package/dist/{cli-DmAiDd8A.d.ts → cli-Dt-tuiYH.d.ts} +3 -3
  93. package/dist/cli.d.ts +7 -6
  94. package/dist/cli.js +35 -35
  95. package/dist/compounding/engine.d.ts +12 -1
  96. package/dist/compounding/engine.js +3 -3
  97. package/dist/compounding/preference-consolidator.d.ts +1 -1
  98. package/dist/compression-optimizer.d.ts +1 -1
  99. package/dist/config.d.ts +1 -1
  100. package/dist/config.js +2 -2
  101. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  102. package/dist/connectors/codex-materialize-runner.js +3 -3
  103. package/dist/connectors/codex-materialize.d.ts +1 -1
  104. package/dist/connectors/index.d.ts +1 -1
  105. package/dist/connectors/index.js +3 -3
  106. package/dist/consolidation-provenance-check.d.ts +1 -1
  107. package/dist/consolidation-undo.d.ts +1 -1
  108. package/dist/contradiction/index.d.ts +1 -1
  109. package/dist/contradiction/index.js +1 -1
  110. package/dist/conversation-index/backend.d.ts +1 -1
  111. package/dist/conversation-index/chunker.d.ts +1 -1
  112. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  113. package/dist/conversation-index/indexer.d.ts +1 -1
  114. package/dist/conversation-index/search.d.ts +1 -1
  115. package/dist/day-summary.d.ts +1 -1
  116. package/dist/delinearize.d.ts +1 -1
  117. package/dist/direct-answer-wiring.d.ts +1 -1
  118. package/dist/direct-answer.d.ts +1 -1
  119. package/dist/embedding-fallback.d.ts +1 -1
  120. package/dist/embedding-fallback.js +2 -2
  121. package/dist/enrichment/index.d.ts +1 -1
  122. package/dist/entity-retrieval.d.ts +1 -1
  123. package/dist/entity-retrieval.js +3 -3
  124. package/dist/entity-schema.d.ts +1 -1
  125. package/dist/explicit-capture.d.ts +6 -4
  126. package/dist/explicit-capture.js +1 -1
  127. package/dist/extraction-faithfulness.d.ts +1 -1
  128. package/dist/extraction-judge-telemetry.d.ts +1 -1
  129. package/dist/extraction-judge-training.d.ts +1 -1
  130. package/dist/extraction-judge.d.ts +1 -1
  131. package/dist/extraction.d.ts +1 -1
  132. package/dist/extraction.js +3 -3
  133. package/dist/fallback-llm.d.ts +1 -1
  134. package/dist/{first-start-migration-22LPFHD5.js → first-start-migration-OOR57AYR.js} +2 -2
  135. package/dist/graph-dashboard-diff.d.ts +1 -1
  136. package/dist/graph-dashboard-key.d.ts +1 -1
  137. package/dist/graph-dashboard-parser.d.ts +1 -1
  138. package/dist/graph-edge-reinforcement.d.ts +1 -1
  139. package/dist/graph-snapshot.d.ts +1 -1
  140. package/dist/graph.d.ts +1 -1
  141. package/dist/identity-continuity.d.ts +1 -1
  142. package/dist/importance.d.ts +1 -1
  143. package/dist/index.d.ts +296 -11
  144. package/dist/index.js +359 -47
  145. package/dist/index.js.map +1 -1
  146. package/dist/intent.d.ts +1 -1
  147. package/dist/lcm/engine.d.ts +1 -1
  148. package/dist/lcm/index.d.ts +1 -1
  149. package/dist/lcm/tools.d.ts +1 -1
  150. package/dist/lifecycle.d.ts +1 -1
  151. package/dist/live-connectors-runner.d.ts +1 -1
  152. package/dist/local-llm.d.ts +1 -1
  153. package/dist/local-model-endpoint.d.ts +1 -1
  154. package/dist/maintenance/memory-governance.d.ts +1 -1
  155. package/dist/maintenance/memory-governance.js +3 -3
  156. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  157. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  158. package/dist/mcp-memory-inspector-app.d.ts +6 -5
  159. package/dist/memory-action-policy.d.ts +1 -1
  160. package/dist/memory-cache.d.ts +1 -1
  161. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  162. package/dist/memory-projection-store.d.ts +1 -1
  163. package/dist/memory-provenance.d.ts +1 -1
  164. package/dist/memory-worth-outcomes.d.ts +1 -1
  165. package/dist/models-json.d.ts +1 -1
  166. package/dist/namespaces/migrate.d.ts +2 -2
  167. package/dist/namespaces/migrate.js +9 -9
  168. package/dist/namespaces/principal.d.ts +1 -1
  169. package/dist/namespaces/search.d.ts +1 -1
  170. package/dist/namespaces/search.js +5 -5
  171. package/dist/namespaces/storage.d.ts +2 -2
  172. package/dist/namespaces/storage.js +3 -3
  173. package/dist/native-knowledge.d.ts +1 -1
  174. package/dist/operator-toolkit.d.ts +1 -1
  175. package/dist/operator-toolkit.js +14 -14
  176. package/dist/orchestration/compression-guideline-coordinator.d.ts +105 -0
  177. package/dist/orchestration/compression-guideline-coordinator.js +12 -0
  178. package/dist/orchestration/maintenance.d.ts +2 -2
  179. package/dist/orchestration/maintenance.js +5 -5
  180. package/dist/{orchestrator-BR0sGsME.d.ts → orchestrator-B4KjaOtY.d.ts} +24 -8
  181. package/dist/orchestrator.d.ts +5 -4
  182. package/dist/orchestrator.js +28 -26
  183. package/dist/patterns-cli.d.ts +1 -1
  184. package/dist/policy-runtime.d.ts +1 -1
  185. package/dist/provenance.d.ts +1 -1
  186. package/dist/provenance.js +1 -1
  187. package/dist/qmd-recall-cache.d.ts +1 -1
  188. package/dist/qmd.d.ts +1 -1
  189. package/dist/recall-disclosure-escalation.d.ts +1 -1
  190. package/dist/recall-explain-renderer.d.ts +1 -1
  191. package/dist/recall-planner-llm.d.ts +1 -1
  192. package/dist/recall-state.d.ts +1 -1
  193. package/dist/recall-tag-filter.d.ts +1 -1
  194. package/dist/recall-xray-cli.d.ts +1 -1
  195. package/dist/recall-xray-renderer.d.ts +1 -1
  196. package/dist/recall-xray.d.ts +1 -1
  197. package/dist/{resolution-MN36NW5P.js → resolution-33PIX3TT.js} +2 -2
  198. package/dist/resolution-33PIX3TT.js.map +1 -0
  199. package/dist/resolve-auth-token.d.ts +1 -1
  200. package/dist/resume-bundles.js +3 -3
  201. package/dist/retrieval-agents.d.ts +1 -1
  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 +84 -84
  206. package/dist/search/embed-helper.d.ts +1 -1
  207. package/dist/search/embed-helper.js +2 -2
  208. package/dist/search/factory.d.ts +1 -1
  209. package/dist/search/factory.js +4 -4
  210. package/dist/search/index.d.ts +1 -1
  211. package/dist/search/index.js +8 -8
  212. package/dist/search/lancedb-backend.d.ts +1 -1
  213. package/dist/search/meilisearch-backend.d.ts +1 -1
  214. package/dist/search/noop-backend.d.ts +1 -1
  215. package/dist/search/orama-backend.d.ts +1 -1
  216. package/dist/search/port.d.ts +1 -1
  217. package/dist/search/remote-backend.d.ts +1 -1
  218. package/dist/{semantic-consolidation-Cl15ksZy.d.ts → semantic-consolidation-CstTvHPo.d.ts} +1 -1
  219. package/dist/semantic-consolidation.d.ts +2 -2
  220. package/dist/semantic-consolidation.js +4 -4
  221. package/dist/semantic-rule-promotion.js +3 -3
  222. package/dist/semantic-rule-verifier.d.ts +1 -1
  223. package/dist/semantic-rule-verifier.js +3 -3
  224. package/dist/session-observer-bands.d.ts +1 -1
  225. package/dist/session-observer-state.d.ts +1 -1
  226. package/dist/shared-context/manager.d.ts +3 -3
  227. package/dist/signal.d.ts +1 -1
  228. package/dist/storage.d.ts +22 -3
  229. package/dist/storage.js +2 -2
  230. package/dist/summarizer.d.ts +1 -1
  231. package/dist/summary-snapshot.d.ts +1 -1
  232. package/dist/temporal-supersession.d.ts +1 -1
  233. package/dist/temporal-validity.d.ts +1 -1
  234. package/dist/threading.d.ts +1 -1
  235. package/dist/tier-migration.d.ts +1 -1
  236. package/dist/tier-routing.d.ts +1 -1
  237. package/dist/topics.d.ts +1 -1
  238. package/dist/transcript.d.ts +1 -1
  239. package/dist/transfer/types.d.ts +46 -46
  240. package/dist/trust-score-stage.d.ts +1 -1
  241. package/dist/trust-score.d.ts +1 -1
  242. package/dist/{types-ChQb9D6s.d.ts → types-VkxElCHR.d.ts} +8 -1
  243. package/dist/types.d.ts +1 -1
  244. package/dist/utility-runtime.d.ts +1 -1
  245. package/dist/verified-recall.js +3 -3
  246. package/package.json +12 -2
  247. package/src/access-service-coding-write.test.ts +2 -2
  248. package/src/access-service.ts +33 -14
  249. package/src/bitemporal-dedup-backfill.test.ts +10 -10
  250. package/src/bitemporal-frontmatter.test.ts +3 -3
  251. package/src/capabilities.test.ts +185 -0
  252. package/src/capabilities.ts +110 -0
  253. package/src/cli/creation-ledger-commands.ts +22 -21
  254. package/src/coding/architecture-surfaces.test.ts +25 -1
  255. package/src/coding/architecture-surfaces.ts +47 -19
  256. package/src/coding/decision-surfaces.ts +12 -3
  257. package/src/coding/review-context-structural.test.ts +303 -0
  258. package/src/coding/review-context.ts +79 -0
  259. package/src/coding/structural-context.test.ts +259 -0
  260. package/src/coding/structural-context.ts +315 -0
  261. package/src/coding/structural-subprocess-provider.test.ts +430 -0
  262. package/src/coding/structural-subprocess-provider.ts +355 -0
  263. package/src/compounding/engine.test.ts +90 -0
  264. package/src/compounding/engine.ts +25 -1
  265. package/src/contradiction/contradiction.test.ts +1 -1
  266. package/src/contradiction/resolution.ts +9 -1
  267. package/src/correction/correction-access-wiring.ts +21 -3
  268. package/src/correction/correction-contract.ts +7 -0
  269. package/src/correction/correction-planner.test.ts +231 -0
  270. package/src/correction/correction-planner.ts +73 -0
  271. package/src/correction/correction-service.ts +29 -0
  272. package/src/correction/correction-storage-integration.test.ts +2 -2
  273. package/src/dedup/semantic.test.ts +1 -1
  274. package/src/explicit-capture.ts +7 -4
  275. package/src/extraction-eventtime-wiring.test.ts +3 -3
  276. package/src/extraction-redaction-rules.test.ts +172 -0
  277. package/src/index.ts +29 -0
  278. package/src/maintenance/forget.test.ts +1 -1
  279. package/src/maintenance/memory-governance.test.ts +1 -1
  280. package/src/maintenance/pattern-reinforcement.test.ts +2 -2
  281. package/src/operator-toolkit.ts +4 -3
  282. package/src/orchestration/compression-guideline-coordinator.ts +449 -0
  283. package/src/orchestrator.ts +345 -464
  284. package/src/procedural/procedure-miner.test.ts +2 -2
  285. package/src/provenance-extraction.test.ts +382 -4
  286. package/src/provenance.ts +158 -22
  287. package/src/recall-handles-wiring.test.ts +1 -1
  288. package/src/search/factory.ts +4 -3
  289. package/src/semantic-rule-promotion.ts +1 -1
  290. package/src/source-attribution-roundtrip.test.ts +2 -2
  291. package/src/storage-contract/atomicity.test.ts +1 -1
  292. package/src/storage-contract/cache-coherence.test.ts +2 -2
  293. package/src/storage-contract/content-hash.test.ts +1 -1
  294. package/src/storage-contract/namespace-routing.test.ts +1 -1
  295. package/src/storage-contract/round-trip.test.ts +3 -3
  296. package/src/storage.ts +23 -2
  297. package/src/temporal-supersession.test.ts +12 -11
  298. package/src/temporal-validity.test.ts +11 -11
  299. package/src/wearables/cli.test.ts +30 -0
  300. package/src/wearables/cli.ts +3 -0
  301. package/src/wearables/memory-gen.test.ts +57 -1
  302. package/src/wearables/memory-gen.ts +31 -7
  303. package/src/wearables/pipeline.test.ts +40 -1
  304. package/src/wearables/pipeline.ts +4 -0
  305. package/src/wearables/service.test.ts +2 -2
  306. package/src/wearables/storage-io.test.ts +3 -3
  307. package/src/wearables/types.ts +7 -0
  308. package/dist/chunk-4NR2PDZ5.js.map +0 -1
  309. package/dist/chunk-4T3BMHKD.js.map +0 -1
  310. package/dist/chunk-7RLCCNHU.js.map +0 -1
  311. package/dist/chunk-AQLOP5F4.js.map +0 -1
  312. package/dist/chunk-EH5ED3C6.js.map +0 -1
  313. package/dist/chunk-HEDZUSCS.js.map +0 -1
  314. package/dist/chunk-M4AYVEWS.js.map +0 -1
  315. package/dist/chunk-UM5AWJNQ.js.map +0 -1
  316. package/dist/chunk-UTHQPSRC.js.map +0 -1
  317. package/dist/chunk-YKBHOBJK.js.map +0 -1
  318. /package/dist/{auto-sync-F3KCSQFJ.js.map → auto-sync-G3V5AN4C.js.map} +0 -0
  319. /package/dist/{chunk-4NOI577P.js.map → chunk-24ZLC5QN.js.map} +0 -0
  320. /package/dist/{chunk-DMQWV6SQ.js.map → chunk-5RZOFIDL.js.map} +0 -0
  321. /package/dist/{chunk-36SEDFAU.js.map → chunk-C5WN74HH.js.map} +0 -0
  322. /package/dist/{chunk-MLKWJOAJ.js.map → chunk-CGPHMNL4.js.map} +0 -0
  323. /package/dist/{chunk-EY6MDMHK.js.map → chunk-F6OEXJQQ.js.map} +0 -0
  324. /package/dist/{chunk-M4V2JVSZ.js.map → chunk-FFUCCKPN.js.map} +0 -0
  325. /package/dist/{chunk-O6YH5F47.js.map → chunk-FYWUNVFZ.js.map} +0 -0
  326. /package/dist/{chunk-37436GML.js.map → chunk-GEXI357K.js.map} +0 -0
  327. /package/dist/{chunk-YGIQORJ3.js.map → chunk-GGL34GCW.js.map} +0 -0
  328. /package/dist/{chunk-WAS3NV46.js.map → chunk-H3MB3F62.js.map} +0 -0
  329. /package/dist/{chunk-76NHR6ZL.js.map → chunk-HJWQJUKQ.js.map} +0 -0
  330. /package/dist/{chunk-Y4YD5TYW.js.map → chunk-IIBFCZA7.js.map} +0 -0
  331. /package/dist/{chunk-UVPL565C.js.map → chunk-IQOEW5YV.js.map} +0 -0
  332. /package/dist/{chunk-V4GNSDFH.js.map → chunk-KQYGNGON.js.map} +0 -0
  333. /package/dist/{chunk-CBWI22JN.js.map → chunk-KSJCXXOU.js.map} +0 -0
  334. /package/dist/{chunk-I5REUWLH.js.map → chunk-NIZQH6AU.js.map} +0 -0
  335. /package/dist/{chunk-4ESAR77N.js.map → chunk-NOU77OHX.js.map} +0 -0
  336. /package/dist/{chunk-BQCHEV7O.js.map → chunk-O4ZIBPIW.js.map} +0 -0
  337. /package/dist/{chunk-HOHVIVDR.js.map → chunk-OBJUKYDO.js.map} +0 -0
  338. /package/dist/{chunk-YOLZS7NY.js.map → chunk-OTQE66IX.js.map} +0 -0
  339. /package/dist/{chunk-C2PG7IEH.js.map → chunk-P3VJCTVE.js.map} +0 -0
  340. /package/dist/{chunk-HGNOCPZX.js.map → chunk-QZHF4BWN.js.map} +0 -0
  341. /package/dist/{chunk-ASKXIAHD.js.map → chunk-WDJCZQB4.js.map} +0 -0
  342. /package/dist/{chunk-JYLFZWUX.js.map → chunk-XYUFGHUW.js.map} +0 -0
  343. /package/dist/{chunk-3TSTGI6F.js.map → chunk-ZQUAVZNG.js.map} +0 -0
  344. /package/dist/{first-start-migration-22LPFHD5.js.map → first-start-migration-OOR57AYR.js.map} +0 -0
  345. /package/dist/{resolution-MN36NW5P.js.map → orchestration/compression-guideline-coordinator.js.map} +0 -0
@@ -62,7 +62,7 @@ test("procedure mining deduplicates by full cluster hash instead of truncated cl
62
62
  written.push({
63
63
  structuredAttributes: options.structuredAttributes ?? {},
64
64
  });
65
- return `procedure-${written.length}`;
65
+ return { id: `procedure-${written.length}`, tombstoneBlocked: false };
66
66
  },
67
67
  } as unknown as StorageManager;
68
68
 
@@ -123,7 +123,7 @@ test("procedure mining serializes concurrent writes for the same cluster", async
123
123
  written.push({
124
124
  structuredAttributes: options.structuredAttributes ?? {},
125
125
  });
126
- return `procedure-${written.length}`;
126
+ return { id: `procedure-${written.length}`, tombstoneBlocked: false };
127
127
  },
128
128
  } as unknown as StorageManager;
129
129
 
@@ -224,7 +224,7 @@ test("end-to-end: fact with verified sources survives write → readAllMemories"
224
224
  },
225
225
  ];
226
226
 
227
- const memoryId = await storage.writeMemory("fact", "Production DB uses pgBouncer.", {
227
+ const { id: memoryId } = await storage.writeMemory("fact", "Production DB uses pgBouncer.", {
228
228
  confidence: 0.9,
229
229
  tags: ["infra"],
230
230
  sources,
@@ -254,7 +254,7 @@ test("end-to-end: fact without provenance fields is legacy-compatible (undefined
254
254
  const storage = new StorageManager(dir);
255
255
  await storage.ensureDirectories();
256
256
 
257
- const memoryId = await storage.writeMemory("fact", "A fact with no provenance.", {
257
+ const { id: memoryId } = await storage.writeMemory("fact", "A fact with no provenance.", {
258
258
  confidence: 0.9,
259
259
  tags: [],
260
260
  });
@@ -278,7 +278,7 @@ test("end-to-end: verified tag without sources downgrades to none on read", asyn
278
278
  // Write a fact with provenance="verified" but NO sources. The serialize
279
279
  // invariant (PR1) must downgrade to "none" so downstream surfaces never
280
280
  // see an ungrounded "verified" tag.
281
- const memoryId = await storage.writeMemory("fact", "A tagged fact with no evidence.", {
281
+ const { id: memoryId } = await storage.writeMemory("fact", "A tagged fact with no evidence.", {
282
282
  confidence: 0.9,
283
283
  tags: [],
284
284
  provenance: "verified",
@@ -363,7 +363,7 @@ test("end-to-end: verified source with non-ISO turn timestamp survives write →
363
363
  );
364
364
  assert.equal(built.provenance, "verified");
365
365
 
366
- const memoryId = await storage.writeMemory("fact", "Production DB uses pgBouncer.", {
366
+ const { id: memoryId } = await storage.writeMemory("fact", "Production DB uses pgBouncer.", {
367
367
  confidence: 0.9,
368
368
  tags: ["infra"],
369
369
  sources: built.sources,
@@ -1102,3 +1102,381 @@ test("toStrictIsoTimestamp path: full month name is preserved (issue #1657, code
1102
1102
  "full-name textual month must not fall back to the epoch (it was accepted, not rejected)",
1103
1103
  );
1104
1104
  });
1105
+
1106
+ // ---------------------------------------------------------------------------
1107
+ // Regression: issue #1723 — complete-but-unusual-punctuation year-led dates
1108
+ // (e.g. "2026 May, 10", "2026, May 10", "2026 Jan. 15") parse correctly via
1109
+ // Date.parse (correct calendar day, no fabrication), but the strict
1110
+ // single-char separator shape in parseYearLedDatePrefix over-rejected them,
1111
+ // dropping a correctly-located source to the unverified epoch fallback. The
1112
+ // separator shape is relaxed to a run of non-alphanumeric chars so any
1113
+ // complete, calendar-valid date is accepted while the three-component +
1114
+ // valid-day + day-not-the-hour invariants are preserved (#1657 stays green).
1115
+ // ---------------------------------------------------------------------------
1116
+
1117
+ test("toStrictIsoTimestamp path: punctuation-tail 'YYYY Month, DD' is preserved (issue #1723)", () => {
1118
+ // "2026 May, 10 12:00:00" parses to May 10 via Date.parse (correct calendar
1119
+ // day, no fabrication). Pre-fix the comma+space separator shape was rejected
1120
+ // by the single-char guard, dropping a correctly-located source to unverified.
1121
+ const turns = [
1122
+ makeTurn("We migrated the production database to pgBouncer.", {
1123
+ timestamp: "2026 May, 10 12:00:00" as unknown as string,
1124
+ }),
1125
+ ];
1126
+ const result = buildFactProvenance(
1127
+ "migrated the production database to pgBouncer",
1128
+ turns,
1129
+ DEFAULT_CONFIG,
1130
+ );
1131
+ assert.equal(result.provenance, "verified", "complete punctuation-tail date must stay verified");
1132
+ assert.ok(result.sources);
1133
+ const observedAt = result.sources![0]!.observedAt;
1134
+ assert.match(
1135
+ observedAt,
1136
+ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/,
1137
+ "punctuation-tail observedAt must normalize to strict ISO",
1138
+ );
1139
+ assert.notEqual(
1140
+ observedAt,
1141
+ new Date(0).toISOString(),
1142
+ "punctuation-tail date must not fall back to the epoch (it was accepted, not rejected)",
1143
+ );
1144
+ });
1145
+
1146
+ test("toStrictIsoTimestamp path: punctuation-tail 'YYYY, Month DD' is preserved (issue #1723)", () => {
1147
+ // "2026, May 10 12:00:00" — comma+space between year and month. Same class
1148
+ // as the comma-after-month form: complete, calendar-valid, over-rejected.
1149
+ const turns = [
1150
+ makeTurn("We migrated the production database to pgBouncer.", {
1151
+ timestamp: "2026, May 10 12:00:00" as unknown as string,
1152
+ }),
1153
+ ];
1154
+ const result = buildFactProvenance(
1155
+ "migrated the production database to pgBouncer",
1156
+ turns,
1157
+ DEFAULT_CONFIG,
1158
+ );
1159
+ assert.equal(result.provenance, "verified", "comma-after-year date must stay verified");
1160
+ assert.ok(result.sources);
1161
+ assert.notEqual(
1162
+ result.sources![0]!.observedAt,
1163
+ new Date(0).toISOString(),
1164
+ "comma-after-year date must not fall back to the epoch",
1165
+ );
1166
+ });
1167
+
1168
+ test("toStrictIsoTimestamp path: punctuation-tail 'YYYY Mon. DD' is preserved (issue #1723)", () => {
1169
+ // "2026 Jan. 15 12:00:00" — period+space between month and day. Same class.
1170
+ const turns = [
1171
+ makeTurn("We migrated the production database to pgBouncer.", {
1172
+ timestamp: "2026 Jan. 15 12:00:00" as unknown as string,
1173
+ }),
1174
+ ];
1175
+ const result = buildFactProvenance(
1176
+ "migrated the production database to pgBouncer",
1177
+ turns,
1178
+ DEFAULT_CONFIG,
1179
+ );
1180
+ assert.equal(result.provenance, "verified", "period-after-month date must stay verified");
1181
+ assert.ok(result.sources);
1182
+ assert.notEqual(
1183
+ result.sources![0]!.observedAt,
1184
+ new Date(0).toISOString(),
1185
+ "period-after-month date must not fall back to the epoch",
1186
+ );
1187
+ });
1188
+
1189
+ test("toStrictIsoTimestamp path: date-only punctuation-tail 'YYYY Month, DD' is preserved (issue #1723, codex)", () => {
1190
+ // "2026 May, 10" (no time component) parses to May 10 via Date.parse but
1191
+ // contains no -/:/T, so pre-fix the bare-number guard dropped it to
1192
+ // unverified before parseYearLedDatePrefix was ever reached. The guard now
1193
+ // admits a complete, calendar-valid year-led date even without a time
1194
+ // separator, so the correctly-located source stays verified.
1195
+ const turns = [
1196
+ makeTurn("We migrated the production database to pgBouncer.", {
1197
+ timestamp: "2026 May, 10" as unknown as string,
1198
+ }),
1199
+ ];
1200
+ const result = buildFactProvenance(
1201
+ "migrated the production database to pgBouncer",
1202
+ turns,
1203
+ DEFAULT_CONFIG,
1204
+ );
1205
+ assert.equal(result.provenance, "verified", "date-only punctuation-tail date must stay verified");
1206
+ assert.ok(result.sources);
1207
+ assert.notEqual(
1208
+ result.sources![0]!.observedAt,
1209
+ new Date(0).toISOString(),
1210
+ "date-only punctuation-tail date must not fall back to the epoch",
1211
+ );
1212
+ });
1213
+
1214
+ test("toStrictIsoTimestamp path: bare numeric string still rejected after #1723 broadening (non-regression)", () => {
1215
+ // The bare-number guard must still reject "123" / "2026" (Date.parse-able
1216
+ // plain numbers with no date structure) so they never round-trip into a fake
1217
+ // epoch. The #1723 broadening only admits COMPLETE year-led dates.
1218
+ const turns = [
1219
+ makeTurn("We migrated the production database to pgBouncer.", {
1220
+ timestamp: "2026" as unknown as string,
1221
+ }),
1222
+ ];
1223
+ const result = buildFactProvenance(
1224
+ "migrated the production database to pgBouncer",
1225
+ turns,
1226
+ DEFAULT_CONFIG,
1227
+ );
1228
+ assert.equal(result.provenance, "unverified");
1229
+ assert.equal(
1230
+ result.sources![0]!.observedAt,
1231
+ new Date(0).toISOString(),
1232
+ "bare-year string must fall back to epoch, not round-trip into a fake date",
1233
+ );
1234
+ });
1235
+
1236
+ test("toStrictIsoTimestamp path: parenthesized-month fabrication is rejected (issue #1723, codex r2)", () => {
1237
+ // "2026 (May) 10 12:00:00" parses as a valid May 10 PREFIX (year, "May",
1238
+ // day 10) but Date.parse reads it as October 1 — the round-trip would
1239
+ // persist October while the guard "validated" May (fabrication). The
1240
+ // agreement check compares the prefix y/m against Date.parse's own
1241
+ // interpretation and rejects on disagreement.
1242
+ const turns = [
1243
+ makeTurn("We migrated the production database to pgBouncer.", {
1244
+ timestamp: "2026 (May) 10 12:00:00" as unknown as string,
1245
+ }),
1246
+ ];
1247
+ const result = buildFactProvenance(
1248
+ "migrated the production database to pgBouncer",
1249
+ turns,
1250
+ DEFAULT_CONFIG,
1251
+ );
1252
+ assert.equal(result.provenance, "unverified", "parenthesized-month fabrication must be rejected");
1253
+ assert.ok(result.sources);
1254
+ assert.notEqual(
1255
+ result.sources![0]!.observedAt,
1256
+ "2026-10-01T12:00:00.000Z",
1257
+ "must not persist Date.parse's October interpretation while validating May",
1258
+ );
1259
+ assert.equal(
1260
+ result.sources![0]!.observedAt,
1261
+ new Date(0).toISOString(),
1262
+ "disagreeing punctuation form falls back to epoch",
1263
+ );
1264
+ });
1265
+
1266
+ test("toStrictIsoTimestamp path: parenthesized-day fabrication is rejected (issue #1723, codex r3)", () => {
1267
+ // "2026 May (10) 12:00:00" matches the prefix as May 10 and Date.parse agrees
1268
+ // on year+month (May 2026) but reads day 1 (it ignores the parenthesized
1269
+ // "(10)"), so a month-only check would still fabricate observedAt = May 1.
1270
+ // The agreement check must compare the full (y, m, d) tuple.
1271
+ const turns = [
1272
+ makeTurn("We migrated the production database to pgBouncer.", {
1273
+ timestamp: "2026 May (10) 12:00:00" as unknown as string,
1274
+ }),
1275
+ ];
1276
+ const result = buildFactProvenance(
1277
+ "migrated the production database to pgBouncer",
1278
+ turns,
1279
+ DEFAULT_CONFIG,
1280
+ );
1281
+ assert.equal(result.provenance, "unverified", "parenthesized-day fabrication must be rejected");
1282
+ assert.ok(result.sources);
1283
+ assert.notEqual(
1284
+ result.sources![0]!.observedAt,
1285
+ "2026-05-01T12:00:00.000Z",
1286
+ "must not persist Date.parse's day-1 interpretation while validating day 10",
1287
+ );
1288
+ assert.equal(
1289
+ result.sources![0]!.observedAt,
1290
+ new Date(0).toISOString(),
1291
+ "day-disagreeing punctuation form falls back to epoch",
1292
+ );
1293
+ });
1294
+
1295
+ test("toStrictIsoTimestamp path: explicit-offset timestamp crossing UTC day boundary stays verified (issue #1723, codex r4)", () => {
1296
+ // "2026-05-10 00:30:00 +05:00" parses to a UTC instant on May 9 (the offset
1297
+ // shifts the instant across the UTC day boundary), but the prefix date is May
1298
+ // 10 in the +05:00 frame. The agreement check must compare in the source's
1299
+ // explicit offset frame, not the UTC/local frame, so this legitimate
1300
+ // offset-bearing timestamp stays verified (pre-fix the strict UTC/local
1301
+ // comparison wrongly rejected it).
1302
+ const turns = [
1303
+ makeTurn("We migrated the production database to pgBouncer.", {
1304
+ timestamp: "2026-05-10 00:30:00 +05:00" as unknown as string,
1305
+ }),
1306
+ ];
1307
+ const result = buildFactProvenance(
1308
+ "migrated the production database to pgBouncer",
1309
+ turns,
1310
+ DEFAULT_CONFIG,
1311
+ );
1312
+ assert.equal(result.provenance, "verified", "explicit-offset timestamp must stay verified");
1313
+ assert.ok(result.sources);
1314
+ assert.match(
1315
+ result.sources![0]!.observedAt,
1316
+ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/,
1317
+ "offset timestamp normalizes to strict ISO",
1318
+ );
1319
+ assert.notEqual(
1320
+ result.sources![0]!.observedAt,
1321
+ new Date(0).toISOString(),
1322
+ "offset timestamp must not fall back to the epoch",
1323
+ );
1324
+ });
1325
+
1326
+ test("toStrictIsoTimestamp path: offset-bearing punctuation fabrication still rejected (issue #1723, codex r4)", () => {
1327
+ // "2026 (May) 10 12:00:00 +05:00" carries an offset AND exotic punctuation.
1328
+ // The agreement check compares in the +05:00 frame: prefix (2026,5,10) vs
1329
+ // Date.parse's October reading shifted to +05:00 — they still disagree, so
1330
+ // the fabrication is rejected even with an offset present.
1331
+ const turns = [
1332
+ makeTurn("We migrated the production database to pgBouncer.", {
1333
+ timestamp: "2026 (May) 10 12:00:00 +05:00" as unknown as string,
1334
+ }),
1335
+ ];
1336
+ const result = buildFactProvenance(
1337
+ "migrated the production database to pgBouncer",
1338
+ turns,
1339
+ DEFAULT_CONFIG,
1340
+ );
1341
+ assert.equal(result.provenance, "unverified", "offset-bearing fabrication must be rejected");
1342
+ assert.equal(
1343
+ result.sources![0]!.observedAt,
1344
+ new Date(0).toISOString(),
1345
+ "offset-bearing fabrication falls back to epoch",
1346
+ );
1347
+ });
1348
+
1349
+ test("toStrictIsoTimestamp path: single-digit explicit offset stays verified (issue #1723, codex r5)", () => {
1350
+ // "+5:00" (single-digit offset hour) parses to the same instant as "+05:00"
1351
+ // and crosses the UTC day boundary; the offset extractor must recognize the
1352
+ // single-digit form so the agreement check compares in the +05:00 frame.
1353
+ const turns = [
1354
+ makeTurn("We migrated the production database to pgBouncer.", {
1355
+ timestamp: "2026-05-10 00:30:00 +5:00" as unknown as string,
1356
+ }),
1357
+ ];
1358
+ const result = buildFactProvenance(
1359
+ "migrated the production database to pgBouncer",
1360
+ turns,
1361
+ DEFAULT_CONFIG,
1362
+ );
1363
+ assert.equal(result.provenance, "verified", "single-digit offset timestamp must stay verified");
1364
+ assert.ok(result.sources);
1365
+ assert.notEqual(
1366
+ result.sources![0]!.observedAt,
1367
+ new Date(0).toISOString(),
1368
+ "single-digit offset timestamp must not fall back to the epoch",
1369
+ );
1370
+ });
1371
+
1372
+ test("toStrictIsoTimestamp path: date-only and numeric dates not misread as offsets (issue #1723, codex r5 non-regression)", () => {
1373
+ // The offset extractor must not misread date digits as an offset (e.g. the
1374
+ // "-0510" in "2026-0510" or the "-2026" tail of "05-10-2026"). These forms
1375
+ // have no real offset, so they must be handled by the offset-free path —
1376
+ // a complete valid date stays verified, a bare invalid one is rejected, but
1377
+ // neither is silently mistreated as offset-bearing.
1378
+ const turnsOk = [
1379
+ makeTurn("We migrated the production database to pgBouncer.", {
1380
+ timestamp: "2026-05-03" as unknown as string,
1381
+ }),
1382
+ ];
1383
+ const resultOk = buildFactProvenance(
1384
+ "migrated the production database to pgBouncer",
1385
+ turnsOk,
1386
+ DEFAULT_CONFIG,
1387
+ );
1388
+ assert.equal(resultOk.provenance, "verified", "plain date must not be misread as offset-bearing");
1389
+ assert.notEqual(resultOk.sources![0]!.observedAt, new Date(0).toISOString());
1390
+ });
1391
+
1392
+ test("toStrictIsoTimestamp path: GMT+HHMM offset minutes preserved (issue #1723, codex r6)", () => {
1393
+ // "GMT+0530" is +5:30, not +5:00 — the extractor must try the 4-digit HHMM
1394
+ // form before the bare-hour form so the minutes are not dropped.
1395
+ const turns = [
1396
+ makeTurn("We migrated the production database to pgBouncer.", {
1397
+ timestamp: "2026 May 10 00:15:00 GMT+0530" as unknown as string,
1398
+ }),
1399
+ ];
1400
+ const result = buildFactProvenance(
1401
+ "migrated the production database to pgBouncer",
1402
+ turns,
1403
+ DEFAULT_CONFIG,
1404
+ );
1405
+ assert.equal(result.provenance, "verified", "GMT+HHMM offset timestamp must stay verified");
1406
+ assert.ok(result.sources);
1407
+ assert.notEqual(
1408
+ result.sources![0]!.observedAt,
1409
+ new Date(0).toISOString(),
1410
+ "GMT+HHMM offset timestamp must not fall back to the epoch",
1411
+ );
1412
+ });
1413
+
1414
+ test("toStrictIsoTimestamp path: offset glued to seconds stays verified (issue #1723, cursor r6)", () => {
1415
+ // "00:30:00+05:00" — the offset is glued to the seconds field with no space.
1416
+ // The extractor must detect it (via the ":SS" lookbehind) so the agreement
1417
+ // check compares in the +05:00 frame, not UTC/local.
1418
+ const turns = [
1419
+ makeTurn("We migrated the production database to pgBouncer.", {
1420
+ timestamp: "2026-05-10 00:30:00+05:00" as unknown as string,
1421
+ }),
1422
+ ];
1423
+ const result = buildFactProvenance(
1424
+ "migrated the production database to pgBouncer",
1425
+ turns,
1426
+ DEFAULT_CONFIG,
1427
+ );
1428
+ assert.equal(result.provenance, "verified", "glued-offset timestamp must stay verified");
1429
+ assert.ok(result.sources);
1430
+ assert.notEqual(
1431
+ result.sources![0]!.observedAt,
1432
+ new Date(0).toISOString(),
1433
+ "glued-offset timestamp must not fall back to the epoch",
1434
+ );
1435
+ });
1436
+
1437
+ test("toStrictIsoTimestamp path: glued bare-hour offset stays verified (issue #1723, codex r7)", () => {
1438
+ // "00:15:00+5" — a bare-hour offset glued to the seconds field. The extractor
1439
+ // must detect it (via the ":SS" lookbehind, bare-hour alternative) so the
1440
+ // agreement check compares in the +05:00 frame.
1441
+ const turns = [
1442
+ makeTurn("We migrated the production database to pgBouncer.", {
1443
+ timestamp: "2026 May 10 00:15:00+5" as unknown as string,
1444
+ }),
1445
+ ];
1446
+ const result = buildFactProvenance(
1447
+ "migrated the production database to pgBouncer",
1448
+ turns,
1449
+ DEFAULT_CONFIG,
1450
+ );
1451
+ assert.equal(result.provenance, "verified", "glued bare-hour offset must stay verified");
1452
+ assert.ok(result.sources);
1453
+ assert.notEqual(
1454
+ result.sources![0]!.observedAt,
1455
+ new Date(0).toISOString(),
1456
+ "glued bare-hour offset must not fall back to the epoch",
1457
+ );
1458
+ });
1459
+
1460
+ test("toStrictIsoTimestamp path: named US timezone abbreviation stays verified (issue #1723, codex r8)", () => {
1461
+ // "2026 May 10 23:30:00 PST" — Date.parse reads PST as -8, so on a UTC
1462
+ // process the instant lands on May 11 UTC. The prefix date is May 10 in the
1463
+ // PST frame; the extractor must recognize the named zone so the agreement
1464
+ // check compares in the -8 frame.
1465
+ const turns = [
1466
+ makeTurn("We migrated the production database to pgBouncer.", {
1467
+ timestamp: "2026 May 10 23:30:00 PST" as unknown as string,
1468
+ }),
1469
+ ];
1470
+ const result = buildFactProvenance(
1471
+ "migrated the production database to pgBouncer",
1472
+ turns,
1473
+ DEFAULT_CONFIG,
1474
+ );
1475
+ assert.equal(result.provenance, "verified", "named-zone timestamp must stay verified");
1476
+ assert.ok(result.sources);
1477
+ assert.notEqual(
1478
+ result.sources![0]!.observedAt,
1479
+ new Date(0).toISOString(),
1480
+ "named-zone timestamp must not fall back to the epoch",
1481
+ );
1482
+ });
package/src/provenance.ts CHANGED
@@ -197,22 +197,47 @@ function toStrictIsoTimestamp(ts: string | undefined | null): string | undefined
197
197
  if (isStrictIsoTimestamp(value)) return value;
198
198
  const parsed = Date.parse(value);
199
199
  if (Number.isNaN(parsed)) return undefined;
200
+ // Year-led date guard (issues #1657 + #1723). `parseYearLedDatePrefix`
201
+ // recognizes a COMPLETE, calendar-valid year-led prefix — numeric OR textual
202
+ // month — with real date-separator RUNS of non-alphanumeric, non-colon chars
203
+ // (so complete-but-unusual-punctuation dates like "2026 May, 10",
204
+ // "2026, May 10", "2026 Jan. 15" are accepted), the day-not-the-hour
205
+ // invariant via the `(?![\d:])` lookahead, and a calendar-valid day. This
206
+ // single rule subsumes the prior partial-numeric ("2026-05"), textual-partial
207
+ // ("2026-Jan"), and calendar-overflow ("2026-02-30", "2026-Feb-30") checks
208
+ // and extends them to textual months — Date.parse silently fills missing
209
+ // components and rolls overflow, fabricating observedAt, so a non-complete
210
+ // or invalid year-led prefix is rejected. Non-year-led shapes
211
+ // ("Jan 15 2026", "02/30/2026") fall through to Date.parse / the mdy check.
212
+ const yearLedPrefix = parseYearLedDatePrefix(value);
213
+ // Agreement check (issue #1723 codex r2/r3/r4): exotic punctuation can make
214
+ // the prefix structure disagree with Date.parse's own interpretation — e.g.
215
+ // "2026 (May) 10" parses as a valid May 10 PREFIX but Date.parse reads
216
+ // October 1; "2026 May (10)" agrees on month but Date.parse reads day 1 — so
217
+ // the round-trip would persist a fabricated observedAt while the guard
218
+ // "validated" a different date. Require Date.parse's interpretation to match
219
+ // the prefix's FULL (y, m, d) tuple. Offset-bearing inputs compare in the
220
+ // source's explicit offset frame (the prefix date is offset-local, so a UTC
221
+ // instant legitimately falls on an adjacent UTC/local day); offset-free
222
+ // inputs compare both the local and UTC frames (Date.parse uses UTC for ISO
223
+ // date-only strings and local for non-ISO — a single frame would wrongly
224
+ // reject legitimate month/day-boundary dates that shift across timezones).
225
+ const yearLedAgrees = yearLedAgreesWithDateParse(parsed, value, yearLedPrefix);
226
+ const validYearLed = yearLedPrefix !== null && yearLedAgrees;
200
227
  // Reject bare-year / numeric-only strings that Date.parse accepts (e.g.
201
228
  // "123") — isStrictIsoTimestamp already rejected them, and the round-trip
202
229
  // below would otherwise resurrect them. Require at least one date/time
203
- // separator so a plain number never round-trips into a fake epoch.
204
- if (!/[-:T]/.test(value)) return undefined;
230
+ // separator so a plain number never round-trips into a fake epoch — UNLESS
231
+ // the value is itself a complete, calendar-valid year-led date that
232
+ // Date.parse agrees with (issue #1723: a date-only punctuated textual form
233
+ // like "2026 May, 10" has no -/:/T yet parses to the correct calendar day).
234
+ if (!/[-:T]/.test(value) && !validYearLed) {
235
+ return undefined;
236
+ }
205
237
  // Reject year-led timestamps that are not a COMPLETE, calendar-valid date
206
- // (issue #1657). Date.parse silently fills missing components ("2026-05" ->
207
- // May 1, "2026-Jan" -> Jan 1) and rolls overflow ("2026-02-30" and
208
- // "2026-Feb-30" -> March 2), fabricating observedAt. `parseYearLedDatePrefix`
209
- // requires a complete three-component date — numeric OR textual month — with
210
- // real date separators (not T/:, and not the space that precedes a time
211
- // component, so the hour is never captured as the day) and a calendar-valid
212
- // day, in one rule (subsumes the prior partial-numeric and numeric-overflow
213
- // checks, and extends them to textual months). Non-year-led shapes
214
- // ("Jan 15 2026", "02/30/2026") fall through to Date.parse / the mdy check.
215
- if (/^\d{4}\D/.test(value) && parseYearLedDatePrefix(value) === null) {
238
+ // Date.parse agrees with (covers partial, overflow, AND the punctuation
239
+ // misinterpretation above).
240
+ if (/^\d{4}\D/.test(value) && !validYearLed) {
216
241
  return undefined;
217
242
  }
218
243
  // Also validate M/D/Y or D/M/Y formats (provider/import common shapes:
@@ -268,18 +293,22 @@ const MONTH_NAMES: Record<string, number> = {
268
293
 
269
294
  /**
270
295
  * Parse a complete, calendar-valid year-led date prefix from `s`
271
- * (issue #1657): `YYYY <sep> (MM | MonthName) <sep> DD` where the separators
272
- * are real date separators (non-digit, non-T, non-colon) and the day is a
273
- * true calendar day not the hour before a `:` time separator (the
274
- * `(?![\d:])` lookahead rejects "2026-05 10:00" capturing "10" as the day).
275
- * Returns the numeric components for a complete, valid date; `null` for an
276
- * incomplete ("2026-05", "2026-Jan"), overflowed ("2026-02-30",
277
- * "2026-Feb-30"), or non-year-led prefix. Centralizes the fabricated-date
278
- * rejection for the toStrictIsoTimestamp normalization path across numeric
279
- * and textual months in one rule.
296
+ * (issue #1657, relaxed in #1723): `YYYY <sep> (MM | MonthName) <sep> DD`
297
+ * where each separator is a RUN of non-alphanumeric, non-colon chars (so a
298
+ * complete date with any punctuation "2026 May, 10", "2026, May 10",
299
+ * "2026 Jan. 15" is accepted; the run excludes letters so a textual month
300
+ * is never consumed by the separator, and excludes the colon so the date/time
301
+ * boundary stays clean) and the day is a true calendar day — not the hour
302
+ * before a `:` time separator (the `(?![\d:])` lookahead rejects
303
+ * "2026-05 10:00" capturing "10" as the day). Returns the numeric components
304
+ * for a complete, valid date; `null` for an incomplete ("2026-05",
305
+ * "2026-Jan"), overflowed ("2026-02-30", "2026-Feb-30"), or non-year-led
306
+ * prefix. Centralizes the fabricated-date rejection for the
307
+ * toStrictIsoTimestamp normalization path across numeric and textual months
308
+ * in one rule.
280
309
  */
281
310
  function parseYearLedDatePrefix(s: string): { y: number; mo: number; da: number } | null {
282
- const m = /^(\d{4})[^0-9T](\d{1,2}|[A-Za-z]{3,})[^0-9T:](\d{1,2})(?![\d:])/.exec(s);
311
+ const m = /^(\d{4})[^0-9A-Za-z]+(\d{1,2}|[A-Za-z]{3,})[^0-9A-Za-z:]+(\d{1,2})(?![\d:])/.exec(s);
283
312
  if (!m) return null;
284
313
  const y = Number(m[1]);
285
314
  const da = Number(m[3]);
@@ -288,6 +317,113 @@ function parseYearLedDatePrefix(s: string): { y: number; mo: number; da: number
288
317
  return { y, mo, da };
289
318
  }
290
319
 
320
+ /**
321
+ * Extract an explicit timezone offset (ms east of UTC) from a non-strict-ISO
322
+ * timestamp, or `null` if none is present (issue #1723 codex r4). Recognizes
323
+ * the offset forms `Date.parse` accepts for non-ISO year-led dates: a trailing
324
+ * `±HH:MM` / `±HHMM`, and a `GMT`/`UTC` token optionally followed by
325
+ * `±HHMM` (bare `GMT`/`UTC` ⇒ offset 0). Strict ISO `Z` forms are handled
326
+ * by `isStrictIsoTimestamp` before this point, so they never reach here.
327
+ */
328
+ /**
329
+ * Named timezone abbreviations Node's `Date.parse` accepts for non-ISO dates
330
+ * (issue #1723 codex r8). V8 recognizes a fixed set of US zones; each maps to a
331
+ * fixed offset (the abbreviation itself encodes standard vs daylight, so PST is
332
+ * always -8 and PDT always -7 regardless of the calendar date). Other named
333
+ * zones (CET/CEST/JST/…) return NaN from `Date.parse` and never reach here.
334
+ */
335
+ const NAMED_ZONE_OFFSETS_MS: Record<string, number> = {
336
+ PST: -8 * 60, PDT: -7 * 60,
337
+ MST: -7 * 60, MDT: -6 * 60,
338
+ CST: -6 * 60, CDT: -5 * 60,
339
+ EST: -5 * 60, EDT: -4 * 60,
340
+ };
341
+
342
+ function explicitOffsetMs(value: string): number | null {
343
+ // Recognize the offset forms Date.parse accepts for non-ISO year-led dates,
344
+ // returning ms east of UTC or null. Tries each shape in order; a stray run
345
+ // of date digits can never pose as an offset because (a) trailing numeric
346
+ // offsets must be preceded by whitespace or glued to a ":SS" seconds field
347
+ // (lookbehind), and (b) every candidate is range-validated (|hh| ≤ 14,
348
+ // mm < 59).
349
+ // Named US zone abbreviation (PST/EST/EDT/…), trailing token (codex r8).
350
+ const nz = /\b([A-Z]{3,4})\s*$/.exec(value);
351
+ if (nz && NAMED_ZONE_OFFSETS_MS[nz[1]] !== undefined) {
352
+ return NAMED_ZONE_OFFSETS_MS[nz[1]] * 60_000;
353
+ }
354
+ const tryOff = (sign: string | undefined, hh: number, mm: number): number | null => {
355
+ if (hh > 14 || mm > 59) return null;
356
+ return (sign === "-" ? -1 : 1) * (hh * 60 + mm) * 60_000;
357
+ };
358
+ let m: RegExpExecArray | null;
359
+ // GMT/UTC token: colon form, then ±HHMM (4-digit, before bare hour so
360
+ // "GMT+0530" is not read as "+05"), then bare hour, then the bare token
361
+ // itself (offset 0).
362
+ if (
363
+ (m = /\b(?:GMT|UTC)\b\s*([+-])?(\d{1,2}):(\d{2})/i.exec(value)) ||
364
+ (m = /\b(?:GMT|UTC)\b\s*([+-])?(\d{2})(\d{2})/i.exec(value))
365
+ ) {
366
+ const r = tryOff(m[1], Number(m[2]), Number(m[3]));
367
+ if (r !== null) return r;
368
+ }
369
+ if ((m = /\b(?:GMT|UTC)\b\s*([+-])?(\d{1,2})\b/i.exec(value))) {
370
+ const r = tryOff(m[1], Number(m[2]), 0);
371
+ if (r !== null) return r;
372
+ }
373
+ if (/\b(?:GMT|UTC)\b/i.test(value)) return 0;
374
+ // Trailing numeric offset: whitespace-delimited OR glued to a ":SS"
375
+ // seconds field (lookbehind), so date digits ("-0510" in "2026-0510") are
376
+ // never misread as an offset. Colon form, then ±HHMM, then bare hour — each
377
+ // for BOTH the whitespace and glued contexts.
378
+ if (
379
+ (m = /(?:\s|(?<=:\d{2}))([+-])(\d{1,2}):(\d{2})\s*$/.exec(value)) ||
380
+ (m = /(?:\s|(?<=:\d{2}))([+-])(\d{2})(\d{2})\s*$/.exec(value)) ||
381
+ (m = /(?:\s|(?<=:\d{2}))([+-])(\d{1,2})\s*$/.exec(value))
382
+ ) {
383
+ const r = tryOff(m[1], Number(m[2]), m[3] ? Number(m[3]) : 0);
384
+ if (r !== null) return r;
385
+ }
386
+ return null;
387
+ }
388
+
389
+ /**
390
+ * Verify `Date.parse`'s interpretation of `value` agrees with the year-led
391
+ * `prefix` components `(y, m, d)` (issue #1723 codex r2/r3/r4). Returns
392
+ * `false` when `prefix` is `null` (no complete year-led date). Otherwise
393
+ * compares the FULL tuple so punctuation that shifts the month OR the day is
394
+ * caught. Offset-bearing inputs are compared in the source's explicit offset
395
+ * frame (the prefix date is offset-local, so the same instant legitimately
396
+ * lands on an adjacent UTC/local day); offset-free inputs accept either the
397
+ * local or UTC frame, because `Date.parse` uses UTC for ISO date-only strings
398
+ * and local for non-ISO forms.
399
+ */
400
+ function yearLedAgreesWithDateParse(
401
+ parsed: number,
402
+ value: string,
403
+ prefix: { y: number; mo: number; da: number } | null,
404
+ ): boolean {
405
+ if (prefix === null) return false;
406
+ const off = explicitOffsetMs(value);
407
+ if (off !== null) {
408
+ const shifted = new Date(parsed + off);
409
+ return (
410
+ shifted.getUTCFullYear() === prefix.y &&
411
+ shifted.getUTCMonth() + 1 === prefix.mo &&
412
+ shifted.getUTCDate() === prefix.da
413
+ );
414
+ }
415
+ const pd = new Date(parsed);
416
+ const localMatch =
417
+ pd.getFullYear() === prefix.y &&
418
+ pd.getMonth() + 1 === prefix.mo &&
419
+ pd.getDate() === prefix.da;
420
+ const utcMatch =
421
+ pd.getUTCFullYear() === prefix.y &&
422
+ pd.getUTCMonth() + 1 === prefix.mo &&
423
+ pd.getUTCDate() === prefix.da;
424
+ return localMatch || utcMatch;
425
+ }
426
+
291
427
  /**
292
428
  * Zod schema for a single `ProvenanceSource` entry (issue #1575). Parsed
293
429
  * JSON from frontmatter is external data, so each entry is validated here
@@ -355,7 +355,7 @@ test("memoryGet resolves a handle to the underlying memory via sessionKey", asyn
355
355
  // cite its handle. writeMemory returns the persisted id directly.
356
356
  const defaultNs = orchestrator.config.defaultNamespace;
357
357
  const storage = await orchestrator.getStorage(defaultNs);
358
- const writtenId = await storage.writeMemory(
358
+ const { id: writtenId } = await storage.writeMemory(
359
359
  "fact",
360
360
  "The API rate limit is 1000 rpm.",
361
361
  { confidence: 0.9, source: "test" },