@remnic/core 9.3.690 → 9.3.691

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 (281) hide show
  1. package/dist/access-boundary.d.ts +5 -5
  2. package/dist/access-boundary.js +18 -18
  3. package/dist/access-cli.js +44 -44
  4. package/dist/access-http.d.ts +5 -5
  5. package/dist/access-http.js +24 -24
  6. package/dist/access-mcp.d.ts +5 -5
  7. package/dist/access-mcp.js +21 -21
  8. package/dist/access-operations.d.ts +5 -5
  9. package/dist/access-operations.js +20 -20
  10. package/dist/access-schema.js +3 -3
  11. package/dist/{access-service-Dujr3MTm.d.ts → access-service-CKnFdxH-.d.ts} +2 -2
  12. package/dist/access-service.d.ts +5 -5
  13. package/dist/access-service.js +17 -17
  14. package/dist/access-surface-catalog.d.ts +5 -5
  15. package/dist/action-confidence.d.ts +1 -1
  16. package/dist/active-memory-bridge.d.ts +1 -1
  17. package/dist/active-recall.d.ts +1 -1
  18. package/dist/active-recall.js +1 -1
  19. package/dist/adapters/index.js +4 -4
  20. package/dist/adapters/registry.js +2 -2
  21. package/dist/{auto-sync-NUQWSFQD.js → auto-sync-RWXT6P5M.js} +5 -5
  22. package/dist/behavior-learner.d.ts +1 -1
  23. package/dist/behavior-signals.d.ts +1 -1
  24. package/dist/bootstrap.d.ts +4 -4
  25. package/dist/briefing.d.ts +1 -1
  26. package/dist/briefing.js +5 -5
  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/calibration.js +2 -2
  31. package/dist/capabilities.d.ts +1 -1
  32. package/dist/{catalog-CKPtJ114.d.ts → catalog-BEWLjdOr.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 +8 -8
  36. package/dist/{chunk-GTDH3IUH.js → chunk-2D27ODNX.js} +2 -2
  37. package/dist/{chunk-3K37VPM3.js → chunk-3BRA3N5A.js} +2 -2
  38. package/dist/{chunk-RTFAZOIR.js → chunk-3VVH6ZQW.js} +2 -2
  39. package/dist/{chunk-FIVDN2SM.js → chunk-4RGWCRIJ.js} +4 -4
  40. package/dist/{chunk-AGJH5ISO.js → chunk-5KBNNUXS.js} +2 -2
  41. package/dist/{chunk-X7RLU5CR.js → chunk-66HROLW5.js} +2 -2
  42. package/dist/{chunk-NSVXK7M5.js → chunk-7UVDIWLL.js} +4 -4
  43. package/dist/{chunk-UPIBE2DK.js → chunk-ADUAF5EV.js} +2 -2
  44. package/dist/{chunk-LLONI6PY.js → chunk-AFWEUTMS.js} +2 -2
  45. package/dist/{chunk-CWE74HRG.js → chunk-D3DNGQNQ.js} +3 -3
  46. package/dist/{chunk-ZUDM75KG.js → chunk-DCWIQFNA.js} +4 -4
  47. package/dist/{chunk-NGFEWFNK.js → chunk-DQHZA7Y3.js} +1 -1
  48. package/dist/chunk-DQHZA7Y3.js.map +1 -0
  49. package/dist/{chunk-OBXTMFZQ.js → chunk-ECZPWSB5.js} +2 -2
  50. package/dist/{chunk-BFVPIKDY.js → chunk-GCOSQBQ2.js} +3 -3
  51. package/dist/{chunk-LXIEXSHU.js → chunk-IPJD7WJH.js} +2 -2
  52. package/dist/{chunk-KQAFEZQX.js → chunk-IPLYGWQF.js} +5 -5
  53. package/dist/{chunk-MDYG7VI7.js → chunk-IREVVFTM.js} +10 -1
  54. package/dist/{chunk-MDYG7VI7.js.map → chunk-IREVVFTM.js.map} +1 -1
  55. package/dist/{chunk-RKNJBZ55.js → chunk-JBPKEARU.js} +4 -4
  56. package/dist/{chunk-WROKD3XC.js → chunk-K7I24ZO2.js} +24 -24
  57. package/dist/{chunk-Z7KILAOU.js → chunk-KO6OL4I7.js} +20 -20
  58. package/dist/{chunk-SB6CQTKP.js → chunk-MCV2DD6F.js} +2 -2
  59. package/dist/{chunk-3FC6LW6T.js → chunk-MRFVMSTR.js} +2 -2
  60. package/dist/{chunk-WDXCNJSF.js → chunk-MXZWKOOR.js} +2 -2
  61. package/dist/{chunk-XKUKJIOY.js → chunk-NCRDCTEJ.js} +7 -7
  62. package/dist/{chunk-RGNEARXW.js → chunk-NUZ3N445.js} +7 -7
  63. package/dist/{chunk-CP2NZQLT.js → chunk-OOO7ZKOD.js} +6 -6
  64. package/dist/{chunk-PHZKALOE.js → chunk-QFG23CRE.js} +2 -2
  65. package/dist/{chunk-UDJLF3BO.js → chunk-QLRYXOAD.js} +2 -2
  66. package/dist/{chunk-ZU7N3S6V.js → chunk-QNG35H27.js} +2 -2
  67. package/dist/{chunk-A4HH2EWA.js → chunk-QVG4LAQO.js} +2 -2
  68. package/dist/{chunk-54PVJDO5.js → chunk-SAC5V6JT.js} +2 -2
  69. package/dist/{chunk-CE6CBRCV.js → chunk-TJ5IIQIR.js} +56 -45
  70. package/dist/chunk-TJ5IIQIR.js.map +1 -0
  71. package/dist/{chunk-OMKUJTVJ.js → chunk-TSGREOYY.js} +5 -5
  72. package/dist/{chunk-2N6UNJSX.js → chunk-U2OBZSGG.js} +2 -2
  73. package/dist/{chunk-BKAMHZYR.js → chunk-UOCLRM74.js} +2 -2
  74. package/dist/{chunk-A7UZR6RA.js → chunk-UTUYAPLY.js} +14 -1
  75. package/dist/chunk-UTUYAPLY.js.map +1 -0
  76. package/dist/{chunk-TYF3D4MS.js → chunk-UUMYB3FR.js} +2 -2
  77. package/dist/{chunk-CUNTLEJP.js → chunk-VFVG4NS2.js} +30 -9
  78. package/dist/chunk-VFVG4NS2.js.map +1 -0
  79. package/dist/{chunk-46URPRE6.js → chunk-VH2DHBHG.js} +2 -2
  80. package/dist/{chunk-UD5OKH4J.js → chunk-W4ELOUNX.js} +2 -2
  81. package/dist/{chunk-GR77Z2BM.js → chunk-WIKNVFBS.js} +2 -2
  82. package/dist/{chunk-67MMWC74.js → chunk-ZLXGFAML.js} +2 -2
  83. package/dist/{cli-BkDp6WNi.d.ts → cli-CrSW_KRq.d.ts} +3 -3
  84. package/dist/cli.d.ts +6 -6
  85. package/dist/cli.js +38 -38
  86. package/dist/compounding/engine.d.ts +1 -1
  87. package/dist/compounding/engine.js +5 -5
  88. package/dist/compounding/preference-consolidator.d.ts +1 -1
  89. package/dist/compression-optimizer.d.ts +1 -1
  90. package/dist/config.d.ts +1 -1
  91. package/dist/config.js +1 -1
  92. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  93. package/dist/connectors/codex-materialize-runner.js +5 -5
  94. package/dist/connectors/codex-materialize.d.ts +1 -1
  95. package/dist/connectors/index.d.ts +1 -1
  96. package/dist/connectors/index.js +5 -5
  97. package/dist/consolidation-provenance-check.d.ts +1 -1
  98. package/dist/consolidation-undo.d.ts +1 -1
  99. package/dist/contradiction/index.d.ts +1 -1
  100. package/dist/contradiction/index.js +4 -4
  101. package/dist/conversation-index/backend.d.ts +1 -1
  102. package/dist/conversation-index/backend.js +2 -2
  103. package/dist/conversation-index/chunker.d.ts +1 -1
  104. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  105. package/dist/conversation-index/indexer.d.ts +1 -1
  106. package/dist/conversation-index/search.d.ts +1 -1
  107. package/dist/day-summary.d.ts +1 -1
  108. package/dist/delinearize.d.ts +1 -1
  109. package/dist/direct-answer-wiring.d.ts +1 -1
  110. package/dist/direct-answer.d.ts +1 -1
  111. package/dist/embedding-fallback.d.ts +1 -1
  112. package/dist/enrichment/index.d.ts +1 -1
  113. package/dist/entity-retrieval.d.ts +1 -1
  114. package/dist/entity-retrieval.js +5 -5
  115. package/dist/entity-schema.d.ts +1 -1
  116. package/dist/event-time.d.ts +35 -0
  117. package/dist/event-time.js +325 -0
  118. package/dist/event-time.js.map +1 -0
  119. package/dist/explicit-capture.d.ts +4 -4
  120. package/dist/extraction-judge-telemetry.d.ts +1 -1
  121. package/dist/extraction-judge-training.d.ts +1 -1
  122. package/dist/extraction-judge.d.ts +1 -1
  123. package/dist/extraction-judge.js +3 -3
  124. package/dist/extraction.d.ts +1 -1
  125. package/dist/extraction.js +3 -3
  126. package/dist/fallback-llm.d.ts +1 -1
  127. package/dist/fallback-llm.js +2 -2
  128. package/dist/identity-continuity.d.ts +1 -1
  129. package/dist/importance.d.ts +1 -1
  130. package/dist/index.d.ts +9 -9
  131. package/dist/index.js +72 -72
  132. package/dist/intent.d.ts +1 -1
  133. package/dist/lcm/engine.d.ts +1 -1
  134. package/dist/lcm/index.d.ts +1 -1
  135. package/dist/lcm/tools.d.ts +1 -1
  136. package/dist/lifecycle.d.ts +1 -1
  137. package/dist/live-connectors-runner.d.ts +1 -1
  138. package/dist/local-llm.d.ts +1 -1
  139. package/dist/maintenance/memory-governance.d.ts +1 -1
  140. package/dist/maintenance/memory-governance.js +5 -5
  141. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +5 -5
  142. package/dist/maintenance/rebuild-memory-projection.js +6 -6
  143. package/dist/mcp-memory-inspector-app.d.ts +5 -5
  144. package/dist/memory-action-policy.d.ts +1 -1
  145. package/dist/memory-cache.d.ts +1 -1
  146. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  147. package/dist/memory-projection-store.d.ts +1 -1
  148. package/dist/memory-provenance.d.ts +1 -1
  149. package/dist/memory-worth-outcomes.d.ts +1 -1
  150. package/dist/models-json.d.ts +1 -1
  151. package/dist/namespaces/migrate.d.ts +2 -2
  152. package/dist/namespaces/migrate.js +10 -10
  153. package/dist/namespaces/principal.d.ts +1 -1
  154. package/dist/namespaces/search.d.ts +1 -1
  155. package/dist/namespaces/search.js +4 -4
  156. package/dist/namespaces/storage.d.ts +2 -2
  157. package/dist/namespaces/storage.js +5 -5
  158. package/dist/native-knowledge.d.ts +1 -1
  159. package/dist/operator-toolkit.d.ts +1 -1
  160. package/dist/operator-toolkit.js +14 -14
  161. package/dist/{orchestrator-B7ixmUkP.d.ts → orchestrator-DvswGK76.d.ts} +3 -3
  162. package/dist/orchestrator.d.ts +4 -4
  163. package/dist/orchestrator.js +34 -34
  164. package/dist/patterns-cli.d.ts +1 -1
  165. package/dist/policy-runtime.d.ts +1 -1
  166. package/dist/provenance.d.ts +1 -1
  167. package/dist/qmd-recall-cache.d.ts +1 -1
  168. package/dist/qmd.d.ts +1 -1
  169. package/dist/recall-disclosure-escalation.d.ts +1 -1
  170. package/dist/recall-explain-renderer.d.ts +1 -1
  171. package/dist/recall-explain-renderer.js +3 -3
  172. package/dist/recall-planner-llm.d.ts +1 -1
  173. package/dist/recall-planner-llm.js +2 -2
  174. package/dist/recall-state.d.ts +1 -1
  175. package/dist/recall-tag-filter.d.ts +1 -1
  176. package/dist/recall-xray-cli.d.ts +1 -1
  177. package/dist/recall-xray-cli.js +4 -4
  178. package/dist/recall-xray-renderer.d.ts +1 -1
  179. package/dist/recall-xray-renderer.js +3 -3
  180. package/dist/recall-xray.d.ts +1 -1
  181. package/dist/recall-xray.js +2 -2
  182. package/dist/resolve-auth-token.d.ts +1 -1
  183. package/dist/resume-bundles.js +2 -2
  184. package/dist/retrieval-agents.d.ts +1 -1
  185. package/dist/retrieval-tiers.d.ts +1 -1
  186. package/dist/routing/engine.d.ts +1 -1
  187. package/dist/routing/store.d.ts +1 -1
  188. package/dist/search/embed-helper.d.ts +1 -1
  189. package/dist/search/factory.d.ts +1 -1
  190. package/dist/search/factory.js +3 -3
  191. package/dist/search/index.d.ts +1 -1
  192. package/dist/search/index.js +3 -3
  193. package/dist/search/lancedb-backend.d.ts +1 -1
  194. package/dist/search/meilisearch-backend.d.ts +1 -1
  195. package/dist/search/noop-backend.d.ts +1 -1
  196. package/dist/search/orama-backend.d.ts +1 -1
  197. package/dist/search/port.d.ts +1 -1
  198. package/dist/search/remote-backend.d.ts +1 -1
  199. package/dist/{semantic-consolidation-CWch5uM7.d.ts → semantic-consolidation-D5U0Mrdb.d.ts} +1 -1
  200. package/dist/semantic-consolidation.d.ts +2 -2
  201. package/dist/semantic-consolidation.js +6 -6
  202. package/dist/semantic-rule-promotion.js +5 -5
  203. package/dist/semantic-rule-verifier.d.ts +1 -1
  204. package/dist/semantic-rule-verifier.js +5 -5
  205. package/dist/session-observer-bands.d.ts +1 -1
  206. package/dist/session-observer-state.d.ts +1 -1
  207. package/dist/shared-context/manager.d.ts +1 -1
  208. package/dist/signal.d.ts +1 -1
  209. package/dist/storage.d.ts +3 -1
  210. package/dist/storage.js +4 -4
  211. package/dist/summarizer.d.ts +1 -1
  212. package/dist/summarizer.js +3 -3
  213. package/dist/summary-snapshot.d.ts +1 -1
  214. package/dist/temporal-supersession.d.ts +1 -1
  215. package/dist/temporal-supersession.js +2 -2
  216. package/dist/temporal-validity.d.ts +22 -2
  217. package/dist/temporal-validity.js +3 -1
  218. package/dist/threading.d.ts +1 -1
  219. package/dist/tier-migration.d.ts +1 -1
  220. package/dist/tier-routing.d.ts +1 -1
  221. package/dist/topics.d.ts +1 -1
  222. package/dist/transcript.d.ts +1 -1
  223. package/dist/transfer/autodetect.js +1 -1
  224. package/dist/transfer/backup.js +1 -1
  225. package/dist/transfer/capsule-export.js +2 -2
  226. package/dist/{types-Dm5xxVrr.d.ts → types-2NoBoRBM.d.ts} +38 -0
  227. package/dist/types.d.ts +1 -1
  228. package/dist/types.js +1 -1
  229. package/dist/utility-runtime.d.ts +1 -1
  230. package/dist/verified-recall.js +5 -5
  231. package/package.json +2 -2
  232. package/src/bitemporal-frontmatter.test.ts +177 -0
  233. package/src/config.ts +13 -0
  234. package/src/event-time.test.ts +514 -0
  235. package/src/event-time.ts +548 -0
  236. package/src/orchestrator.ts +27 -1
  237. package/src/storage.ts +34 -0
  238. package/src/temporal-validity.ts +34 -0
  239. package/src/types.ts +38 -0
  240. package/dist/chunk-A7UZR6RA.js.map +0 -1
  241. package/dist/chunk-CE6CBRCV.js.map +0 -1
  242. package/dist/chunk-CUNTLEJP.js.map +0 -1
  243. package/dist/chunk-NGFEWFNK.js.map +0 -1
  244. /package/dist/{auto-sync-NUQWSFQD.js.map → auto-sync-RWXT6P5M.js.map} +0 -0
  245. /package/dist/{chunk-GTDH3IUH.js.map → chunk-2D27ODNX.js.map} +0 -0
  246. /package/dist/{chunk-3K37VPM3.js.map → chunk-3BRA3N5A.js.map} +0 -0
  247. /package/dist/{chunk-RTFAZOIR.js.map → chunk-3VVH6ZQW.js.map} +0 -0
  248. /package/dist/{chunk-FIVDN2SM.js.map → chunk-4RGWCRIJ.js.map} +0 -0
  249. /package/dist/{chunk-AGJH5ISO.js.map → chunk-5KBNNUXS.js.map} +0 -0
  250. /package/dist/{chunk-X7RLU5CR.js.map → chunk-66HROLW5.js.map} +0 -0
  251. /package/dist/{chunk-NSVXK7M5.js.map → chunk-7UVDIWLL.js.map} +0 -0
  252. /package/dist/{chunk-UPIBE2DK.js.map → chunk-ADUAF5EV.js.map} +0 -0
  253. /package/dist/{chunk-LLONI6PY.js.map → chunk-AFWEUTMS.js.map} +0 -0
  254. /package/dist/{chunk-CWE74HRG.js.map → chunk-D3DNGQNQ.js.map} +0 -0
  255. /package/dist/{chunk-ZUDM75KG.js.map → chunk-DCWIQFNA.js.map} +0 -0
  256. /package/dist/{chunk-OBXTMFZQ.js.map → chunk-ECZPWSB5.js.map} +0 -0
  257. /package/dist/{chunk-BFVPIKDY.js.map → chunk-GCOSQBQ2.js.map} +0 -0
  258. /package/dist/{chunk-LXIEXSHU.js.map → chunk-IPJD7WJH.js.map} +0 -0
  259. /package/dist/{chunk-KQAFEZQX.js.map → chunk-IPLYGWQF.js.map} +0 -0
  260. /package/dist/{chunk-RKNJBZ55.js.map → chunk-JBPKEARU.js.map} +0 -0
  261. /package/dist/{chunk-WROKD3XC.js.map → chunk-K7I24ZO2.js.map} +0 -0
  262. /package/dist/{chunk-Z7KILAOU.js.map → chunk-KO6OL4I7.js.map} +0 -0
  263. /package/dist/{chunk-SB6CQTKP.js.map → chunk-MCV2DD6F.js.map} +0 -0
  264. /package/dist/{chunk-3FC6LW6T.js.map → chunk-MRFVMSTR.js.map} +0 -0
  265. /package/dist/{chunk-WDXCNJSF.js.map → chunk-MXZWKOOR.js.map} +0 -0
  266. /package/dist/{chunk-XKUKJIOY.js.map → chunk-NCRDCTEJ.js.map} +0 -0
  267. /package/dist/{chunk-RGNEARXW.js.map → chunk-NUZ3N445.js.map} +0 -0
  268. /package/dist/{chunk-CP2NZQLT.js.map → chunk-OOO7ZKOD.js.map} +0 -0
  269. /package/dist/{chunk-PHZKALOE.js.map → chunk-QFG23CRE.js.map} +0 -0
  270. /package/dist/{chunk-UDJLF3BO.js.map → chunk-QLRYXOAD.js.map} +0 -0
  271. /package/dist/{chunk-ZU7N3S6V.js.map → chunk-QNG35H27.js.map} +0 -0
  272. /package/dist/{chunk-A4HH2EWA.js.map → chunk-QVG4LAQO.js.map} +0 -0
  273. /package/dist/{chunk-54PVJDO5.js.map → chunk-SAC5V6JT.js.map} +0 -0
  274. /package/dist/{chunk-OMKUJTVJ.js.map → chunk-TSGREOYY.js.map} +0 -0
  275. /package/dist/{chunk-2N6UNJSX.js.map → chunk-U2OBZSGG.js.map} +0 -0
  276. /package/dist/{chunk-BKAMHZYR.js.map → chunk-UOCLRM74.js.map} +0 -0
  277. /package/dist/{chunk-TYF3D4MS.js.map → chunk-UUMYB3FR.js.map} +0 -0
  278. /package/dist/{chunk-46URPRE6.js.map → chunk-VH2DHBHG.js.map} +0 -0
  279. /package/dist/{chunk-UD5OKH4J.js.map → chunk-W4ELOUNX.js.map} +0 -0
  280. /package/dist/{chunk-GR77Z2BM.js.map → chunk-WIKNVFBS.js.map} +0 -0
  281. /package/dist/{chunk-67MMWC74.js.map → chunk-ZLXGFAML.js.map} +0 -0
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  exportCapsule,
3
3
  isValidCapsuleSince
4
- } from "../chunk-KQAFEZQX.js";
4
+ } from "../chunk-IPLYGWQF.js";
5
+ import "../chunk-J4EB7DNW.js";
5
6
  import "../chunk-WEHSQBFR.js";
6
7
  import "../chunk-X7Y7WX73.js";
7
- import "../chunk-J4EB7DNW.js";
8
8
  import "../chunk-BJMBJZ2Y.js";
9
9
  import "../chunk-UKJAGEXH.js";
10
10
  import "../chunk-FP2373TW.js";
@@ -1062,6 +1062,25 @@ interface PluginConfig {
1062
1062
  * filtered out.
1063
1063
  */
1064
1064
  temporalSupersessionIncludeInRecall: boolean;
1065
+ /**
1066
+ * Bi-temporal validity master gate (issue #1578). When `false` (default),
1067
+ * the recall validity-injection filter and `asOf` semantics behave
1068
+ * byte-identically to pre-#1578.
1069
+ *
1070
+ * Turn on to exclude validity-expired facts from default injection
1071
+ * candidates (they remain findable by explicit search and `as_of`
1072
+ * queries). Storage round-trips `observedAt`/`eventTimeSource`; the
1073
+ * extraction prompt → `resolveEventTime` write-time wiring lands in a
1074
+ * follow-on PR, so new extractions are not yet event-time-resolved.
1075
+ */
1076
+ temporalBiTemporal: boolean;
1077
+ /**
1078
+ * Escape hatch for the bi-temporal injection filter (issue #1578). When
1079
+ * `true`, facts whose `[valid_at, invalid_at)` interval ended before now
1080
+ * are kept in injection candidates even with `temporalBiTemporal` on — some
1081
+ * deployments prefer the older (always-inject) behavior. Default `false`.
1082
+ */
1083
+ temporalExpiredInInjection: boolean;
1065
1084
  /**
1066
1085
  * When true, recall checks whether a single validated memory in a
1067
1086
  * high-trust taxonomy bucket can answer the query before invoking QMD.
@@ -2570,6 +2589,25 @@ interface MemoryFrontmatter {
2570
2589
  * point in time.
2571
2590
  */
2572
2591
  invalid_at?: string;
2592
+ /**
2593
+ * Ingestion time (issue #1578) — when Remnic *learned* this fact.
2594
+ * Distinct from `created` (file creation) and `valid_at` (event-time
2595
+ * start). Aligns with the source turn timestamp (#1575
2596
+ * `sources[].observedAt`). When `eventTimeSource === "assumed"`,
2597
+ * `valid_at` is copied from this value.
2598
+ */
2599
+ observedAt?: string;
2600
+ /**
2601
+ * Provenance of the event-time interval (issue #1578).
2602
+ * - `"extracted"` — a per-fact `eventTime` expression was resolved
2603
+ * against the source turn's timestamp and produced `valid_at` /
2604
+ * `invalid_at`.
2605
+ * - `"assumed"` — no resolvable expression; `valid_at` was copied from
2606
+ * `observedAt` (the ingestion anchor).
2607
+ * Absent on memories written before #1578; readers treat absent as
2608
+ * `"assumed"` for display purposes.
2609
+ */
2610
+ eventTimeSource?: "extracted" | "assumed";
2573
2611
  /**
2574
2612
  * Timestamp when the operator explicitly forgot this memory
2575
2613
  * (issue #686 PR 4/6). Set by `remnic forget <id>`. Memories with
package/dist/types.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import './types-ByK7T3L6.js';
2
2
  import './index-DJ9QWMw-.js';
3
- export { y as AccessTrackingEntry, A as ActiveRecallChatType, d as ActiveRecallModelFallbackPolicy, b as ActiveRecallPromptStyle, a as ActiveRecallQueryMode, c as ActiveRecallThinking, a7 as AgentAccessAuthToken, b6 as AgentAccessHttpConfig, b7 as AgentDefaultsConfig, b8 as AgentPersona, f as AgentPersonaModelConfig, b9 as BehaviorLoopAdjustment, e as BehaviorLoopPolicyState, ba as BehaviorSignalDirection, B as BehaviorSignalEvent, bb as BehaviorSignalType, aL as BootstrapOptions, aM as BootstrapResult, W as BriefingActiveThread, bc as BriefingCalendarSourceError, aS as BriefingConfig, S as BriefingFocus, O as BriefingFollowup, aT as BriefingOpenCommitment, Y as BriefingRecentEntity, X as BriefingResult, N as BriefingSections, aU as BriefingWindow, bd as BufferEntryState, k as BufferState, o as BufferSurpriseEvent, Z as BufferTurn, V as CalendarEvent, U as CalendarSource, be as CaptureMode, $ as Checkpoint, bf as CodexCliReasoningEffort, bg as CodexCompactionFlushMode, aV as CodexCompatConfig, bh as CodexConnectorConfig, aK as CodingContext, bi as CodingKnowledgeConfig, aP as CodingModeConfig, bj as CompressionGuidelineActivationState, a9 as CompressionGuidelineOptimizerActionSummary, a8 as CompressionGuidelineOptimizerEventCounts, aa as CompressionGuidelineOptimizerRuleUpdate, bk as CompressionGuidelineOptimizerSourceWindow, C as CompressionGuidelineOptimizerState, bl as ConfidenceTier, bm as ConsolidationAction, bn as ConsolidationItem, aN as ConsolidationObservation, ag as ConsolidationResult, s as ContinuityImprovementLoop, r as ContinuityIncidentCloseInput, p as ContinuityIncidentOpenInput, q as ContinuityIncidentRecord, bo as ContinuityIncidentState, bp as ContinuityLoopCadence, u as ContinuityLoopReviewInput, bq as ContinuityLoopStatus, t as ContinuityLoopUpsertInput, br as ContradictionScanConfig, au as ConversationThread, bs as CronConversationRecallMode, bt as CronRecallMode, aW as DEFAULT_RECALL_DISCLOSURE, ah as DaySummaryResult, bu as DreamingConfig, bv as DreamingNarrativePromptStyle, bw as DreamsDeepSleepConfig, bx as DreamsLightSleepConfig, ay as DreamsPhase, by as DreamsPhaseStatus, bz as DreamsPhasesConfig, bA as DreamsRemConfig, az as DreamsRunResult, ax as DreamsStatusResult, bB as EngramTraceEvent, w as EntityActivityEntry, x as EntityFile, ac as EntityMention, v as EntityRelationship, ad as EntitySchemaDefinition, ae as EntitySchemaSectionDefinition, E as EntityStructuredSection, aO as EntityTimelineEntry, aX as ExtractedFact, bC as ExtractedProcedureStep, bD as ExtractedQuestion, bE as ExtractedReasoningTrace, bF as ExtractedReasoningTraceStep, bG as ExtractedRelationship, bH as ExtractionPassSource, af as ExtractionResult, F as FileHygieneConfig, G as GatewayConfig, bI as GitHubLiveConnectorConfig, bJ as GmailLiveConnectorConfig, bK as GoogleDriveLiveConnectorConfig, bL as HeartbeatConfig, bM as HeartbeatDetectionMode, a0 as HourlySummary, J as IdentityInjectionMode, a5 as ImportanceLevel, I as ImportanceScore, a2 as LifecycleState, L as LiveConnectorsConfig, bN as LlmTraceCallback, bO as LlmTraceEvent, ak as MemoryActionEligibilityContext, aY as MemoryActionEligibilitySource, m as MemoryActionEvent, bP as MemoryActionOutcome, bQ as MemoryActionPolicyDecision, al as MemoryActionPolicyResult, bR as MemoryActionStatus, ab as MemoryActionType, M as MemoryCategory, g as MemoryFile, j as MemoryFrontmatter, ai as MemoryIntent, n as MemoryLifecycleEvent, am as MemoryLifecycleEventType, an as MemoryLifecycleStateSummary, i as MemoryLink, bS as MemoryLinkType, aZ as MemoryObservation, bT as MemoryOsPresetName, z as MemoryProjectionCurrentState, a_ as MemoryScope, h as MemoryStatus, D as MemorySummary, l as MetaState, bU as ModelApi, bV as ModelDefinitionConfig, bW as ModelProviderAuthMode, ao as ModelProviderConfig, bX as NamespacePolicy, ap as NativeKnowledgeConfig, bY as NativeKnowledgeFolderRuleConfig, bZ as NativeKnowledgeObsidianVaultConfig, b_ as NativeKnowledgeOpenClawWorkspaceConfig, b$ as NotionLiveConnectorConfig, P as PluginConfig, a4 as PolicyClass, c0 as PrincipalFromSessionKeyMode, c1 as PrincipalRule, c2 as ProceduralConfig, aq as ProvenanceConfig, ar as ProvenanceSource, aj as QmdSearchExplain, Q as QmdSearchResult, c3 as QuestionEntry, a$ as RECALL_DISCLOSURE_LEVELS, c4 as ReasoningEffort, K as RecallDisclosure, c5 as RecallPipelineConfig, H as RecallPlanMode, c6 as RecallSectionConfig, R as RecallTierExplain, c7 as RecallTraceEvent, c8 as RelevanceFeedback, as as RetrievalTier, c9 as SPECULATIVE_TTL_DAYS, ca as ScopeProfileAutoPromoteConfig, cb as ScopeProfileConfig, av as ScopeProfileLayerId, aw as ScopeProfilePromotionTarget, cc as ScopeProfileTeamProjectConfig, cd as ScopeTeamConfig, ce as ScoredEntity, a6 as SecretRef, cf as SemanticChunkingConfigShape, a1 as SessionObserverBandConfig, cg as SignalLevel, at as SignalScanResult, ch as SlotBehaviorConfig, ci as SlotMismatchMode, T as TopicScore, _ as TranscriptEntry, cj as TriggerMode, a3 as VerificationState, ck as confidenceTier, b5 as isRecallDisclosure } from './types-Dm5xxVrr.js';
3
+ export { y as AccessTrackingEntry, A as ActiveRecallChatType, d as ActiveRecallModelFallbackPolicy, b as ActiveRecallPromptStyle, a as ActiveRecallQueryMode, c as ActiveRecallThinking, a7 as AgentAccessAuthToken, b6 as AgentAccessHttpConfig, b7 as AgentDefaultsConfig, b8 as AgentPersona, f as AgentPersonaModelConfig, b9 as BehaviorLoopAdjustment, e as BehaviorLoopPolicyState, ba as BehaviorSignalDirection, B as BehaviorSignalEvent, bb as BehaviorSignalType, aL as BootstrapOptions, aM as BootstrapResult, W as BriefingActiveThread, bc as BriefingCalendarSourceError, aS as BriefingConfig, S as BriefingFocus, O as BriefingFollowup, aT as BriefingOpenCommitment, Y as BriefingRecentEntity, X as BriefingResult, N as BriefingSections, aU as BriefingWindow, bd as BufferEntryState, k as BufferState, o as BufferSurpriseEvent, Z as BufferTurn, V as CalendarEvent, U as CalendarSource, be as CaptureMode, $ as Checkpoint, bf as CodexCliReasoningEffort, bg as CodexCompactionFlushMode, aV as CodexCompatConfig, bh as CodexConnectorConfig, aK as CodingContext, bi as CodingKnowledgeConfig, aP as CodingModeConfig, bj as CompressionGuidelineActivationState, a9 as CompressionGuidelineOptimizerActionSummary, a8 as CompressionGuidelineOptimizerEventCounts, aa as CompressionGuidelineOptimizerRuleUpdate, bk as CompressionGuidelineOptimizerSourceWindow, C as CompressionGuidelineOptimizerState, bl as ConfidenceTier, bm as ConsolidationAction, bn as ConsolidationItem, aN as ConsolidationObservation, ag as ConsolidationResult, s as ContinuityImprovementLoop, r as ContinuityIncidentCloseInput, p as ContinuityIncidentOpenInput, q as ContinuityIncidentRecord, bo as ContinuityIncidentState, bp as ContinuityLoopCadence, u as ContinuityLoopReviewInput, bq as ContinuityLoopStatus, t as ContinuityLoopUpsertInput, br as ContradictionScanConfig, au as ConversationThread, bs as CronConversationRecallMode, bt as CronRecallMode, aW as DEFAULT_RECALL_DISCLOSURE, ah as DaySummaryResult, bu as DreamingConfig, bv as DreamingNarrativePromptStyle, bw as DreamsDeepSleepConfig, bx as DreamsLightSleepConfig, ay as DreamsPhase, by as DreamsPhaseStatus, bz as DreamsPhasesConfig, bA as DreamsRemConfig, az as DreamsRunResult, ax as DreamsStatusResult, bB as EngramTraceEvent, w as EntityActivityEntry, x as EntityFile, ac as EntityMention, v as EntityRelationship, ad as EntitySchemaDefinition, ae as EntitySchemaSectionDefinition, E as EntityStructuredSection, aO as EntityTimelineEntry, aX as ExtractedFact, bC as ExtractedProcedureStep, bD as ExtractedQuestion, bE as ExtractedReasoningTrace, bF as ExtractedReasoningTraceStep, bG as ExtractedRelationship, bH as ExtractionPassSource, af as ExtractionResult, F as FileHygieneConfig, G as GatewayConfig, bI as GitHubLiveConnectorConfig, bJ as GmailLiveConnectorConfig, bK as GoogleDriveLiveConnectorConfig, bL as HeartbeatConfig, bM as HeartbeatDetectionMode, a0 as HourlySummary, J as IdentityInjectionMode, a5 as ImportanceLevel, I as ImportanceScore, a2 as LifecycleState, L as LiveConnectorsConfig, bN as LlmTraceCallback, bO as LlmTraceEvent, ak as MemoryActionEligibilityContext, aY as MemoryActionEligibilitySource, m as MemoryActionEvent, bP as MemoryActionOutcome, bQ as MemoryActionPolicyDecision, al as MemoryActionPolicyResult, bR as MemoryActionStatus, ab as MemoryActionType, M as MemoryCategory, g as MemoryFile, j as MemoryFrontmatter, ai as MemoryIntent, n as MemoryLifecycleEvent, am as MemoryLifecycleEventType, an as MemoryLifecycleStateSummary, i as MemoryLink, bS as MemoryLinkType, aZ as MemoryObservation, bT as MemoryOsPresetName, z as MemoryProjectionCurrentState, a_ as MemoryScope, h as MemoryStatus, D as MemorySummary, l as MetaState, bU as ModelApi, bV as ModelDefinitionConfig, bW as ModelProviderAuthMode, ao as ModelProviderConfig, bX as NamespacePolicy, ap as NativeKnowledgeConfig, bY as NativeKnowledgeFolderRuleConfig, bZ as NativeKnowledgeObsidianVaultConfig, b_ as NativeKnowledgeOpenClawWorkspaceConfig, b$ as NotionLiveConnectorConfig, P as PluginConfig, a4 as PolicyClass, c0 as PrincipalFromSessionKeyMode, c1 as PrincipalRule, c2 as ProceduralConfig, aq as ProvenanceConfig, ar as ProvenanceSource, aj as QmdSearchExplain, Q as QmdSearchResult, c3 as QuestionEntry, a$ as RECALL_DISCLOSURE_LEVELS, c4 as ReasoningEffort, K as RecallDisclosure, c5 as RecallPipelineConfig, H as RecallPlanMode, c6 as RecallSectionConfig, R as RecallTierExplain, c7 as RecallTraceEvent, c8 as RelevanceFeedback, as as RetrievalTier, c9 as SPECULATIVE_TTL_DAYS, ca as ScopeProfileAutoPromoteConfig, cb as ScopeProfileConfig, av as ScopeProfileLayerId, aw as ScopeProfilePromotionTarget, cc as ScopeProfileTeamProjectConfig, cd as ScopeTeamConfig, ce as ScoredEntity, a6 as SecretRef, cf as SemanticChunkingConfigShape, a1 as SessionObserverBandConfig, cg as SignalLevel, at as SignalScanResult, ch as SlotBehaviorConfig, ci as SlotMismatchMode, T as TopicScore, _ as TranscriptEntry, cj as TriggerMode, a3 as VerificationState, ck as confidenceTier, b5 as isRecallDisclosure } from './types-2NoBoRBM.js';
package/dist/types.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  SPECULATIVE_TTL_DAYS,
5
5
  confidenceTier,
6
6
  isRecallDisclosure
7
- } from "./chunk-NGFEWFNK.js";
7
+ } from "./chunk-DQHZA7Y3.js";
8
8
  import "./chunk-PZ5AY32C.js";
9
9
  export {
10
10
  DEFAULT_RECALL_DISCLOSURE,
@@ -1,5 +1,5 @@
1
1
  import { TierRoutingPolicy } from './tier-routing.js';
2
- import './types-Dm5xxVrr.js';
2
+ import './types-2NoBoRBM.js';
3
3
  import './types-ByK7T3L6.js';
4
4
  import './index-DJ9QWMw-.js';
5
5
  import './lifecycle.js';
@@ -1,23 +1,23 @@
1
1
  import {
2
2
  compareVerifiedEpisodeResults,
3
3
  searchVerifiedEpisodes
4
- } from "./chunk-RTFAZOIR.js";
4
+ } from "./chunk-3VVH6ZQW.js";
5
5
  import "./chunk-7FL4CNPV.js";
6
- import "./chunk-CUNTLEJP.js";
6
+ import "./chunk-VFVG4NS2.js";
7
7
  import "./chunk-M7XQSUBB.js";
8
8
  import "./chunk-5UZXUTVO.js";
9
9
  import "./chunk-5GPPACXK.js";
10
10
  import "./chunk-SVOZFLIQ.js";
11
11
  import "./chunk-J6A3CX5N.js";
12
- import "./chunk-NGFEWFNK.js";
12
+ import "./chunk-DQHZA7Y3.js";
13
+ import "./chunk-SCU65EZI.js";
13
14
  import "./chunk-MB5RSUW6.js";
14
15
  import "./chunk-6KYMPV2O.js";
15
16
  import "./chunk-AWJ2FHCF.js";
16
17
  import "./chunk-42JKGUFJ.js";
17
18
  import "./chunk-RULE4VG5.js";
18
- import "./chunk-SCU65EZI.js";
19
- import "./chunk-DM2T26WE.js";
20
19
  import "./chunk-LDXUBPMO.js";
20
+ import "./chunk-DM2T26WE.js";
21
21
  import "./chunk-FVQJYWH7.js";
22
22
  import "./chunk-G7D6GZ5J.js";
23
23
  import "./chunk-VF4XKTX3.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "9.3.690",
3
+ "version": "9.3.691",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -2931,7 +2931,7 @@
2931
2931
  "core"
2932
2932
  ],
2933
2933
  "peerDependencies": {
2934
- "@remnic/coding-graph": "^9.3.690"
2934
+ "@remnic/coding-graph": "^9.3.691"
2935
2935
  },
2936
2936
  "peerDependenciesMeta": {
2937
2937
  "@remnic/coding-graph": {
@@ -0,0 +1,177 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { mkdtemp, rm } from "node:fs/promises";
6
+
7
+ import { StorageManager } from "./storage.js";
8
+ import { isValidityExpiredNow } from "./temporal-validity.js";
9
+
10
+ /**
11
+ * Issue #1578 PR 1 — bi-temporal validity frontmatter round-trip + injection
12
+ * filter unit tests.
13
+ *
14
+ * These tests pin the on-disk contract added by #1578 (`observedAt`,
15
+ * `eventTimeSource`) AND prove the pre-existing temporal/lifecycle fields
16
+ * (`created`, `updated`, `source`, `valid_at`, `invalid_at`, `forgottenAt`)
17
+ * round-trip unchanged alongside them — i.e. the parser was not corrupted by
18
+ * the additive change. Every test goes through the public StorageManager API
19
+ * (`writeMemory` + `writeMemoryFrontmatter`, both of which route through the
20
+ * `serializeFrontmatter` chokepoint) so the serialize → parse round trip is
21
+ * exercised end to end.
22
+ *
23
+ * The injection filter (`isValidityExpiredNow`) is a pure function, so it is
24
+ * unit-tested directly with minimal frontmatter fragments.
25
+ */
26
+
27
+ const OBSERVED = "2026-06-20T14:02:11.000Z";
28
+ const VALID_FROM = "2026-03-01T00:00:00.000Z";
29
+ const VALID_UNTIL = "2026-06-15T00:00:00.000Z";
30
+
31
+ test("round-trip: observedAt + eventTimeSource + valid_at survive write → readAllMemories", async () => {
32
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-bitemporal-rt-"));
33
+ try {
34
+ const storage = new StorageManager(dir);
35
+ await storage.ensureDirectories();
36
+
37
+ const id = await storage.writeMemory("fact", "We moved offices in March.", {
38
+ observedAt: OBSERVED,
39
+ eventTimeSource: "extracted",
40
+ validAt: VALID_FROM,
41
+ });
42
+
43
+ const memories = await storage.readAllMemories();
44
+ const written = memories.find((m) => m.frontmatter.id === id);
45
+ assert.ok(written, "fact must be discoverable after write");
46
+ assert.equal(written!.frontmatter.observedAt, OBSERVED);
47
+ assert.equal(written!.frontmatter.eventTimeSource, "extracted");
48
+ assert.equal(written!.frontmatter.valid_at, VALID_FROM);
49
+ // The auto-set baseline fields must remain present and well-formed.
50
+ assert.ok(typeof written!.frontmatter.created === "string" && written!.frontmatter.created!.length > 0);
51
+ assert.ok(typeof written!.frontmatter.updated === "string" && written!.frontmatter.updated!.length > 0);
52
+ assert.equal(written!.frontmatter.source, "extraction");
53
+ } finally {
54
+ await rm(dir, { recursive: true, force: true });
55
+ }
56
+ });
57
+
58
+ test("round-trip: invalid_at + forgottenAt coexist with observedAt/eventTimeSource (parser not corrupted)", async () => {
59
+ // Exercises the full serialize→parse round trip through the
60
+ // writeMemoryFrontmatter chokepoint for the fields writeMemory does not
61
+ // accept as options (invalid_at, forgottenAt). This is the direct
62
+ // regression guard for the "frontmatter parser corruption" risk: every
63
+ // pre-existing field must survive alongside the new bi-temporal fields,
64
+ // with no field dropped or duplicated.
65
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-bitemporal-coexist-"));
66
+ try {
67
+ const storage = new StorageManager(dir);
68
+ await storage.ensureDirectories();
69
+
70
+ const id = await storage.writeMemory("fact", "Old stack was Node 18.", {
71
+ observedAt: OBSERVED,
72
+ eventTimeSource: "assumed",
73
+ validAt: VALID_FROM,
74
+ });
75
+
76
+ const before = await storage.readAllMemories();
77
+ const memory = before.find((m) => m.frontmatter.id === id);
78
+ assert.ok(memory);
79
+
80
+ const ok = await storage.writeMemoryFrontmatter(memory!, {
81
+ invalid_at: VALID_UNTIL,
82
+ forgottenAt: "2026-07-01T00:00:00.000Z",
83
+ });
84
+ assert.equal(ok, true);
85
+
86
+ const after = await storage.readAllMemories();
87
+ const patched = after.find((m) => m.frontmatter.id === id);
88
+ assert.ok(patched, "patched fact must be readable");
89
+ const fm = patched!.frontmatter;
90
+ // New bi-temporal fields.
91
+ assert.equal(fm.observedAt, OBSERVED);
92
+ assert.equal(fm.eventTimeSource, "assumed");
93
+ // Pre-existing temporal/lifecycle fields — all present, correct values.
94
+ assert.equal(fm.valid_at, VALID_FROM);
95
+ assert.equal(fm.invalid_at, VALID_UNTIL);
96
+ assert.equal(fm.forgottenAt, "2026-07-01T00:00:00.000Z");
97
+ // Baseline identity fields untouched by the patch.
98
+ assert.ok(typeof fm.created === "string" && fm.created!.length > 0);
99
+ assert.ok(typeof fm.source === "string" && fm.source!.length > 0);
100
+ } finally {
101
+ await rm(dir, { recursive: true, force: true });
102
+ }
103
+ });
104
+
105
+ test("legacy memory without bi-temporal fields reads cleanly — observedAt/eventTimeSource undefined", async () => {
106
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-bitemporal-legacy-"));
107
+ try {
108
+ const storage = new StorageManager(dir);
109
+ await storage.ensureDirectories();
110
+
111
+ const id = await storage.writeMemory("fact", "Legacy fact pre-dating #1578.");
112
+
113
+ const memories = await storage.readAllMemories();
114
+ const written = memories.find((m) => m.frontmatter.id === id);
115
+ assert.ok(written);
116
+ assert.equal(written!.frontmatter.observedAt, undefined);
117
+ assert.equal(written!.frontmatter.eventTimeSource, undefined);
118
+ } finally {
119
+ await rm(dir, { recursive: true, force: true });
120
+ }
121
+ });
122
+
123
+ test("garbage observedAt is rejected on write — corrupt timestamps cannot leak to disk", async () => {
124
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-bitemporal-reject-"));
125
+ try {
126
+ const storage = new StorageManager(dir);
127
+ await storage.ensureDirectories();
128
+
129
+ await assert.rejects(
130
+ () => storage.writeMemory("fact", "Bad observedAt.", { observedAt: "not-a-timestamp" }),
131
+ /observedAt must be a valid ISO timestamp/,
132
+ );
133
+ } finally {
134
+ await rm(dir, { recursive: true, force: true });
135
+ }
136
+ });
137
+
138
+ test("isValidityExpiredNow: absent invalid_at → never expired (still valid)", () => {
139
+ assert.equal(isValidityExpiredNow({ invalid_at: undefined }, Date.now()), false);
140
+ assert.equal(isValidityExpiredNow({ invalid_at: "" }, Date.now()), false);
141
+ });
142
+
143
+ test("isValidityExpiredNow: invalid_at in the past → expired (interval ended)", () => {
144
+ const now = Date.parse("2026-06-20T00:00:00.000Z");
145
+ assert.equal(
146
+ isValidityExpiredNow({ invalid_at: "2026-06-15T00:00:00.000Z" }, now),
147
+ true,
148
+ );
149
+ });
150
+
151
+ test("isValidityExpiredNow: invalid_at in the future → not expired (still within window)", () => {
152
+ const now = Date.parse("2026-06-20T00:00:00.000Z");
153
+ assert.equal(
154
+ isValidityExpiredNow({ invalid_at: "2026-12-31T00:00:00.000Z" }, now),
155
+ false,
156
+ );
157
+ });
158
+
159
+ test("isValidityExpiredNow: exclusive end — invalid_at == now is EXPIRED ([from, until) ended)", () => {
160
+ const boundary = Date.parse("2026-06-15T00:00:00.000Z");
161
+ // At the exact exclusive boundary the interval has ended.
162
+ assert.equal(
163
+ isValidityExpiredNow({ invalid_at: "2026-06-15T00:00:00.000Z" }, boundary),
164
+ true,
165
+ );
166
+ });
167
+
168
+ test("isValidityExpiredNow: status-orthogonal — considers invalid_at only, ignores status", () => {
169
+ // The filter must be status-orthogonal (issue pitfall matrix): an `active`
170
+ // memory can be validity-expired. isValidityExpiredNow only receives the
171
+ // invalid_at field, so status never enters the decision.
172
+ const now = Date.parse("2026-06-20T00:00:00.000Z");
173
+ assert.equal(
174
+ isValidityExpiredNow({ invalid_at: "2026-06-15T00:00:00.000Z" }, now),
175
+ true,
176
+ );
177
+ });
package/src/config.ts CHANGED
@@ -2084,6 +2084,19 @@ export function parseConfig(
2084
2084
  temporalSupersessionEnabled: cfg.temporalSupersessionEnabled !== false, // On by default
2085
2085
  temporalSupersessionIncludeInRecall:
2086
2086
  cfg.temporalSupersessionIncludeInRecall === true, // Off by default
2087
+ // Bi-temporal validity (issue #1578). Default `false` so recall behaves
2088
+ // byte-identically to pre-#1578 until an operator opts in. Uses coerceBool
2089
+ // (same as recallDirectAnswerEnabled below) so CLI string "true" works.
2090
+ //
2091
+ // CURRENT scope (this PR): the recall injection filter (expired-validity
2092
+ // facts leave default injection but stay findable by explicit search and
2093
+ // as_of queries) + the observedAt/eventTimeSource storage fields. The
2094
+ // extraction prompt → resolveEventTime write-time wiring lands in a
2095
+ // follow-on PR; until then, enabling the gate exercises the filter and
2096
+ // storage round-trip but new extractions are not yet event-time-resolved
2097
+ // (docs kept honest — review: wire resolver before exposing the gate).
2098
+ temporalBiTemporal: coerceBool(cfg.temporalBiTemporal) ?? false,
2099
+ temporalExpiredInInjection: coerceBool(cfg.temporalExpiredInInjection) ?? false,
2087
2100
  // Direct-answer retrieval tier (issue #518). Default off so the
2088
2101
  // recall path keeps least-privileged behavior unless operators
2089
2102
  // explicitly opt in.