@remnic/core 9.3.705 → 9.3.706

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 (259) hide show
  1. package/dist/access-boundary.d.ts +5 -5
  2. package/dist/access-boundary.js +10 -10
  3. package/dist/access-cli.js +26 -25
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.d.ts +5 -5
  6. package/dist/access-http.js +14 -14
  7. package/dist/access-mcp.d.ts +5 -5
  8. package/dist/access-mcp.js +13 -13
  9. package/dist/access-operations-batch.js +11 -11
  10. package/dist/access-operations.d.ts +5 -5
  11. package/dist/access-operations.js +12 -12
  12. package/dist/{access-service-C8hc8N2i.d.ts → access-service-j1c1gptF.d.ts} +3 -3
  13. package/dist/access-service.d.ts +5 -5
  14. package/dist/access-service.js +9 -9
  15. package/dist/access-surface-catalog.d.ts +5 -5
  16. package/dist/action-confidence.d.ts +1 -1
  17. package/dist/active-memory-bridge.d.ts +1 -1
  18. package/dist/active-recall.d.ts +1 -1
  19. package/dist/behavior-learner.d.ts +1 -1
  20. package/dist/behavior-signals.d.ts +1 -1
  21. package/dist/bootstrap.d.ts +4 -4
  22. package/dist/briefing.d.ts +1 -1
  23. package/dist/briefing.js +5 -5
  24. package/dist/buffer-surprise-report.d.ts +1 -1
  25. package/dist/buffer.d.ts +1 -1
  26. package/dist/calibration.d.ts +1 -1
  27. package/dist/capabilities.d.ts +1 -1
  28. package/dist/{catalog-CAeU0e1C.d.ts → catalog-CKxilpzS.d.ts} +1 -1
  29. package/dist/causal-behavior.d.ts +1 -1
  30. package/dist/causal-consolidation.d.ts +1 -1
  31. package/dist/causal-consolidation.js +6 -6
  32. package/dist/{chunk-JZCKDTAS.js → chunk-24FGNOQS.js} +3 -3
  33. package/dist/{chunk-C2EHWNP2.js → chunk-2VQYHHWB.js} +9 -3
  34. package/dist/chunk-2VQYHHWB.js.map +1 -0
  35. package/dist/{chunk-47LPHBIP.js → chunk-3PTOZJOI.js} +2 -2
  36. package/dist/{chunk-2SYPOX45.js → chunk-4DZATVK5.js} +3 -3
  37. package/dist/{chunk-S5APSA3U.js → chunk-4E2QCH46.js} +2 -2
  38. package/dist/{chunk-KKK7YTYN.js → chunk-5GSUBCZM.js} +6 -2
  39. package/dist/chunk-5GSUBCZM.js.map +1 -0
  40. package/dist/{chunk-5DTWZ66X.js → chunk-66TSLESZ.js} +2 -2
  41. package/dist/{chunk-IREVVFTM.js → chunk-6CIAGZ6X.js} +9 -1
  42. package/dist/chunk-6CIAGZ6X.js.map +1 -0
  43. package/dist/{chunk-Y4PMATX2.js → chunk-6HPJMR5I.js} +2 -2
  44. package/dist/{chunk-M5MWSG4S.js → chunk-BGAHTI4C.js} +5 -5
  45. package/dist/{chunk-OM6ETLLH.js → chunk-C63MK3WL.js} +2 -2
  46. package/dist/{chunk-GT4VBKM4.js → chunk-EJDAXR7O.js} +5 -5
  47. package/dist/{chunk-ULVM34NP.js → chunk-ESMY4RJ4.js} +2 -2
  48. package/dist/{chunk-MNH2OODZ.js → chunk-GKI6LX5L.js} +2 -2
  49. package/dist/{chunk-KZMMAVR2.js → chunk-HIV5E57C.js} +2 -2
  50. package/dist/{chunk-SFOAQQDJ.js → chunk-IONFO7UK.js} +3 -3
  51. package/dist/{chunk-BMKGG7GC.js → chunk-IVCQW4C4.js} +2 -2
  52. package/dist/chunk-M7R5R6OJ.js +355 -0
  53. package/dist/chunk-M7R5R6OJ.js.map +1 -0
  54. package/dist/{chunk-IX3UQT4H.js → chunk-MLLTU5FX.js} +1 -1
  55. package/dist/chunk-MLLTU5FX.js.map +1 -0
  56. package/dist/{chunk-NFGJBEPT.js → chunk-MRX6ZXHZ.js} +2 -2
  57. package/dist/{chunk-GI3MTYDU.js → chunk-N75N5SNX.js} +3 -3
  58. package/dist/{chunk-BKBSE3BU.js → chunk-NM6TSEGQ.js} +2 -2
  59. package/dist/{chunk-S3WYRPSA.js → chunk-PDJQVAGM.js} +68 -31
  60. package/dist/chunk-PDJQVAGM.js.map +1 -0
  61. package/dist/{chunk-SY6WG6DB.js → chunk-RH2OSRQY.js} +2 -2
  62. package/dist/{chunk-YTMDF6S7.js → chunk-SPETAWFE.js} +2 -2
  63. package/dist/{chunk-JHAYR2JY.js → chunk-STYMKPFT.js} +7 -7
  64. package/dist/{chunk-OMNTQPZO.js → chunk-TKZ3AL5V.js} +2 -2
  65. package/dist/{chunk-IFR23TC5.js → chunk-VYZNWH4J.js} +37 -6
  66. package/dist/chunk-VYZNWH4J.js.map +1 -0
  67. package/dist/{chunk-KFU2SKDD.js → chunk-W2S3Z5MT.js} +2 -2
  68. package/dist/{chunk-6GJ2WQRK.js → chunk-W2WQ4LE7.js} +2 -2
  69. package/dist/{chunk-7ARKLLCV.js → chunk-WDH3KUZU.js} +2 -2
  70. package/dist/{chunk-7L54YZUI.js → chunk-WQADZ3ZY.js} +17 -17
  71. package/dist/{chunk-HEHPVBWA.js → chunk-WSWYIKXX.js} +4 -4
  72. package/dist/{chunk-WN4GHSDH.js → chunk-XKMDDM7P.js} +2 -2
  73. package/dist/{chunk-LY4FJLPT.js → chunk-Y6YHAGQP.js} +2 -2
  74. package/dist/{cli-ChE0XlJY.d.ts → cli-CbT-pyM4.d.ts} +3 -3
  75. package/dist/cli.d.ts +6 -6
  76. package/dist/cli.js +26 -26
  77. package/dist/compounding/engine.d.ts +1 -1
  78. package/dist/compounding/engine.js +5 -5
  79. package/dist/compounding/preference-consolidator.d.ts +1 -1
  80. package/dist/compression-optimizer.d.ts +1 -1
  81. package/dist/config.d.ts +1 -1
  82. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  83. package/dist/connectors/codex-materialize-runner.js +5 -5
  84. package/dist/connectors/codex-materialize.d.ts +1 -1
  85. package/dist/connectors/index.d.ts +1 -1
  86. package/dist/connectors/index.js +5 -5
  87. package/dist/consolidation-provenance-check.d.ts +1 -1
  88. package/dist/consolidation-undo.d.ts +1 -1
  89. package/dist/contradiction/index.d.ts +1 -1
  90. package/dist/conversation-index/backend.d.ts +1 -1
  91. package/dist/conversation-index/chunker.d.ts +1 -1
  92. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  93. package/dist/conversation-index/indexer.d.ts +1 -1
  94. package/dist/conversation-index/search.d.ts +1 -1
  95. package/dist/day-summary.d.ts +1 -1
  96. package/dist/delinearize.d.ts +1 -1
  97. package/dist/direct-answer-wiring.d.ts +1 -1
  98. package/dist/direct-answer.d.ts +1 -1
  99. package/dist/embedding-fallback.d.ts +1 -1
  100. package/dist/enrichment/index.d.ts +1 -1
  101. package/dist/entity-retrieval.d.ts +1 -1
  102. package/dist/entity-retrieval.js +5 -5
  103. package/dist/entity-schema.d.ts +1 -1
  104. package/dist/event-time.d.ts +35 -1
  105. package/dist/event-time.js +6 -320
  106. package/dist/event-time.js.map +1 -1
  107. package/dist/explicit-capture.d.ts +4 -4
  108. package/dist/extraction-faithfulness.d.ts +1 -1
  109. package/dist/extraction-judge-telemetry.d.ts +1 -1
  110. package/dist/extraction-judge-training.d.ts +1 -1
  111. package/dist/extraction-judge.d.ts +1 -1
  112. package/dist/extraction.d.ts +10 -1
  113. package/dist/extraction.js +2 -2
  114. package/dist/fallback-llm.d.ts +1 -1
  115. package/dist/{forget-6SOIPUMQ.js → forget-U66KPDPY.js} +3 -3
  116. package/dist/identity-continuity.d.ts +1 -1
  117. package/dist/importance.d.ts +1 -1
  118. package/dist/index.d.ts +9 -9
  119. package/dist/index.js +35 -34
  120. package/dist/index.js.map +1 -1
  121. package/dist/intent.d.ts +1 -1
  122. package/dist/lcm/engine.d.ts +1 -1
  123. package/dist/lcm/index.d.ts +1 -1
  124. package/dist/lcm/tools.d.ts +1 -1
  125. package/dist/lifecycle.d.ts +1 -1
  126. package/dist/live-connectors-runner.d.ts +1 -1
  127. package/dist/local-llm.d.ts +1 -1
  128. package/dist/maintenance/memory-governance.d.ts +1 -1
  129. package/dist/maintenance/memory-governance.js +5 -5
  130. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +5 -5
  131. package/dist/maintenance/rebuild-memory-projection.js +6 -6
  132. package/dist/mcp-memory-inspector-app.d.ts +5 -5
  133. package/dist/memory-action-policy.d.ts +1 -1
  134. package/dist/memory-cache.d.ts +1 -1
  135. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  136. package/dist/memory-projection-store.d.ts +1 -1
  137. package/dist/memory-provenance.d.ts +1 -1
  138. package/dist/memory-worth-outcomes.d.ts +1 -1
  139. package/dist/models-json.d.ts +1 -1
  140. package/dist/namespaces/migrate.d.ts +2 -2
  141. package/dist/namespaces/migrate.js +6 -6
  142. package/dist/namespaces/principal.d.ts +1 -1
  143. package/dist/namespaces/search.d.ts +1 -1
  144. package/dist/namespaces/storage.d.ts +2 -2
  145. package/dist/namespaces/storage.js +5 -5
  146. package/dist/native-knowledge.d.ts +1 -1
  147. package/dist/operator-toolkit.d.ts +1 -1
  148. package/dist/operator-toolkit.js +10 -10
  149. package/dist/orchestration/maintenance.d.ts +2 -2
  150. package/dist/orchestration/maintenance.js +7 -7
  151. package/dist/{orchestrator-m_PnhyHj.d.ts → orchestrator-D4ovYV3x.d.ts} +3 -3
  152. package/dist/orchestrator.d.ts +4 -4
  153. package/dist/orchestrator.js +20 -19
  154. package/dist/patterns-cli.d.ts +1 -1
  155. package/dist/policy-runtime.d.ts +1 -1
  156. package/dist/provenance.d.ts +1 -1
  157. package/dist/qmd-recall-cache.d.ts +1 -1
  158. package/dist/qmd.d.ts +1 -1
  159. package/dist/recall-disclosure-escalation.d.ts +1 -1
  160. package/dist/recall-explain-renderer.d.ts +1 -1
  161. package/dist/recall-explain-renderer.js +3 -3
  162. package/dist/recall-planner-llm.d.ts +1 -1
  163. package/dist/recall-state.d.ts +1 -1
  164. package/dist/recall-tag-filter.d.ts +1 -1
  165. package/dist/recall-xray-cli.d.ts +1 -1
  166. package/dist/recall-xray-cli.js +4 -4
  167. package/dist/recall-xray-renderer.d.ts +1 -1
  168. package/dist/recall-xray-renderer.js +3 -3
  169. package/dist/recall-xray.d.ts +1 -1
  170. package/dist/recall-xray.js +2 -2
  171. package/dist/resolve-auth-token.d.ts +1 -1
  172. package/dist/retrieval-agents.d.ts +1 -1
  173. package/dist/retrieval-tiers.d.ts +1 -1
  174. package/dist/routing/engine.d.ts +1 -1
  175. package/dist/routing/store.d.ts +1 -1
  176. package/dist/schemas.d.ts +38 -0
  177. package/dist/schemas.js +1 -1
  178. package/dist/search/embed-helper.d.ts +1 -1
  179. package/dist/search/factory.d.ts +1 -1
  180. package/dist/search/index.d.ts +1 -1
  181. package/dist/search/lancedb-backend.d.ts +1 -1
  182. package/dist/search/meilisearch-backend.d.ts +1 -1
  183. package/dist/search/noop-backend.d.ts +1 -1
  184. package/dist/search/orama-backend.d.ts +1 -1
  185. package/dist/search/port.d.ts +1 -1
  186. package/dist/search/remote-backend.d.ts +1 -1
  187. package/dist/{semantic-consolidation-DVBbq6Wr.d.ts → semantic-consolidation-DyMUCsfN.d.ts} +1 -1
  188. package/dist/semantic-consolidation.d.ts +2 -2
  189. package/dist/semantic-consolidation.js +6 -6
  190. package/dist/semantic-rule-promotion.js +5 -5
  191. package/dist/semantic-rule-verifier.d.ts +1 -1
  192. package/dist/semantic-rule-verifier.js +5 -5
  193. package/dist/session-observer-bands.d.ts +1 -1
  194. package/dist/session-observer-state.d.ts +1 -1
  195. package/dist/shared-context/manager.d.ts +1 -1
  196. package/dist/signal.d.ts +1 -1
  197. package/dist/storage.d.ts +5 -1
  198. package/dist/storage.js +4 -4
  199. package/dist/summarizer.d.ts +1 -1
  200. package/dist/summary-snapshot.d.ts +1 -1
  201. package/dist/temporal-supersession.d.ts +1 -1
  202. package/dist/temporal-supersession.js +2 -2
  203. package/dist/temporal-validity.d.ts +2 -2
  204. package/dist/temporal-validity.js +1 -1
  205. package/dist/threading.d.ts +1 -1
  206. package/dist/tier-migration.d.ts +1 -1
  207. package/dist/tier-routing.d.ts +1 -1
  208. package/dist/topics.d.ts +1 -1
  209. package/dist/transcript.d.ts +1 -1
  210. package/dist/{types-CJrvHJjx.d.ts → types-Couvz-L3.d.ts} +12 -2
  211. package/dist/types.d.ts +1 -1
  212. package/dist/types.js +1 -1
  213. package/dist/utility-runtime.d.ts +1 -1
  214. package/dist/verified-recall.js +5 -5
  215. package/package.json +2 -2
  216. package/src/event-time.ts +73 -0
  217. package/src/extraction-eventtime-wiring.test.ts +269 -0
  218. package/src/extraction.ts +50 -3
  219. package/src/orchestrator.ts +71 -17
  220. package/src/schemas.ts +12 -0
  221. package/src/storage.ts +13 -2
  222. package/src/temporal-validity.test.ts +33 -0
  223. package/src/temporal-validity.ts +24 -1
  224. package/src/types.ts +12 -2
  225. package/dist/chunk-C2EHWNP2.js.map +0 -1
  226. package/dist/chunk-IFR23TC5.js.map +0 -1
  227. package/dist/chunk-IREVVFTM.js.map +0 -1
  228. package/dist/chunk-IX3UQT4H.js.map +0 -1
  229. package/dist/chunk-KKK7YTYN.js.map +0 -1
  230. package/dist/chunk-S3WYRPSA.js.map +0 -1
  231. /package/dist/{chunk-JZCKDTAS.js.map → chunk-24FGNOQS.js.map} +0 -0
  232. /package/dist/{chunk-47LPHBIP.js.map → chunk-3PTOZJOI.js.map} +0 -0
  233. /package/dist/{chunk-2SYPOX45.js.map → chunk-4DZATVK5.js.map} +0 -0
  234. /package/dist/{chunk-S5APSA3U.js.map → chunk-4E2QCH46.js.map} +0 -0
  235. /package/dist/{chunk-5DTWZ66X.js.map → chunk-66TSLESZ.js.map} +0 -0
  236. /package/dist/{chunk-Y4PMATX2.js.map → chunk-6HPJMR5I.js.map} +0 -0
  237. /package/dist/{chunk-M5MWSG4S.js.map → chunk-BGAHTI4C.js.map} +0 -0
  238. /package/dist/{chunk-OM6ETLLH.js.map → chunk-C63MK3WL.js.map} +0 -0
  239. /package/dist/{chunk-GT4VBKM4.js.map → chunk-EJDAXR7O.js.map} +0 -0
  240. /package/dist/{chunk-ULVM34NP.js.map → chunk-ESMY4RJ4.js.map} +0 -0
  241. /package/dist/{chunk-MNH2OODZ.js.map → chunk-GKI6LX5L.js.map} +0 -0
  242. /package/dist/{chunk-KZMMAVR2.js.map → chunk-HIV5E57C.js.map} +0 -0
  243. /package/dist/{chunk-SFOAQQDJ.js.map → chunk-IONFO7UK.js.map} +0 -0
  244. /package/dist/{chunk-BMKGG7GC.js.map → chunk-IVCQW4C4.js.map} +0 -0
  245. /package/dist/{chunk-NFGJBEPT.js.map → chunk-MRX6ZXHZ.js.map} +0 -0
  246. /package/dist/{chunk-GI3MTYDU.js.map → chunk-N75N5SNX.js.map} +0 -0
  247. /package/dist/{chunk-BKBSE3BU.js.map → chunk-NM6TSEGQ.js.map} +0 -0
  248. /package/dist/{chunk-SY6WG6DB.js.map → chunk-RH2OSRQY.js.map} +0 -0
  249. /package/dist/{chunk-YTMDF6S7.js.map → chunk-SPETAWFE.js.map} +0 -0
  250. /package/dist/{chunk-JHAYR2JY.js.map → chunk-STYMKPFT.js.map} +0 -0
  251. /package/dist/{chunk-OMNTQPZO.js.map → chunk-TKZ3AL5V.js.map} +0 -0
  252. /package/dist/{chunk-KFU2SKDD.js.map → chunk-W2S3Z5MT.js.map} +0 -0
  253. /package/dist/{chunk-6GJ2WQRK.js.map → chunk-W2WQ4LE7.js.map} +0 -0
  254. /package/dist/{chunk-7ARKLLCV.js.map → chunk-WDH3KUZU.js.map} +0 -0
  255. /package/dist/{chunk-7L54YZUI.js.map → chunk-WQADZ3ZY.js.map} +0 -0
  256. /package/dist/{chunk-HEHPVBWA.js.map → chunk-WSWYIKXX.js.map} +0 -0
  257. /package/dist/{chunk-WN4GHSDH.js.map → chunk-XKMDDM7P.js.map} +0 -0
  258. /package/dist/{chunk-LY4FJLPT.js.map → chunk-Y6YHAGQP.js.map} +0 -0
  259. /package/dist/{forget-6SOIPUMQ.js.map → forget-U66KPDPY.js.map} +0 -0
@@ -121,6 +121,7 @@ import {
121
121
  shouldFilterSupersededFromRecall,
122
122
  } from "./temporal-supersession.js";
123
123
  import { isValidAsOf, isValidityExpiredNow } from "./temporal-validity.js";
124
+ import { resolveFactEventTime } from "./event-time.js";
124
125
  import { RelevanceStore } from "./relevance.js";
125
126
  import { NegativeExampleStore } from "./negative.js";
126
127
  import {
@@ -12150,10 +12151,16 @@ export class Orchestrator {
12150
12151
  : typeof sessionKey === "string" && sessionKey.length > 0
12151
12152
  ? sessionKey
12152
12153
  : "default";
12154
+ const captureTimestamp = new Date().toISOString();
12153
12155
  const turn: BufferTurn = {
12154
12156
  role,
12155
12157
  content,
12156
- timestamp: new Date().toISOString(),
12158
+ timestamp: captureTimestamp,
12159
+ // #1578: anchor live-capture turns to wall-clock when bi-temporal is on;
12160
+ // replay/import turns carry sourceValidAt explicitly (codex P1).
12161
+ ...(this.config.temporalBiTemporal
12162
+ ? { sourceValidAt: captureTimestamp }
12163
+ : {}),
12157
12164
  sessionKey,
12158
12165
  logicalSessionKey: options.logicalSessionKey ?? bufferKey,
12159
12166
  providerThreadId: options.providerThreadId ?? null,
@@ -13922,6 +13929,11 @@ export class Orchestrator {
13922
13929
  intentEntityTypes?: string[];
13923
13930
  memoryKind?: MemoryFrontmatter["memoryKind"];
13924
13931
  validAt?: string;
13932
+ // #1578 — bi-temporal bounds + ingestion provenance forwarded to profile-
13933
+ // target copies (same defect class as shared promotion; cursor bugbot).
13934
+ invalidAt?: string;
13935
+ observedAt?: string;
13936
+ eventTimeSource?: "extracted" | "assumed";
13925
13937
  source: string;
13926
13938
  sources?: ProvenanceSource[];
13927
13939
  provenance?: "verified" | "unverified" | "none";
@@ -13980,6 +13992,10 @@ export class Orchestrator {
13980
13992
  intentEntityTypes: options.intentEntityTypes,
13981
13993
  memoryKind: options.memoryKind,
13982
13994
  validAt: options.validAt,
13995
+ // #1578 — forward bi-temporal bounds + ingestion provenance.
13996
+ ...(options.invalidAt ? { invalidAt: options.invalidAt } : {}),
13997
+ ...(options.observedAt ? { observedAt: options.observedAt } : {}),
13998
+ ...(options.eventTimeSource ? { eventTimeSource: options.eventTimeSource } : {}),
13983
13999
  contentHashSource: options.category === "fact" ? dedupContent : rawContent,
13984
14000
  ...(options.sources && options.sources.length > 0 ? { sources: options.sources } : {}),
13985
14001
  ...(options.provenance ? { provenance: options.provenance } : {}),
@@ -13999,7 +14015,7 @@ export class Orchestrator {
13999
14015
  entityRef: options.entityRef,
14000
14016
  structuredAttributes: options.structuredAttributes,
14001
14017
  createdAt: supersessionOrderingAt(options.validAt),
14002
- enabled: true,
14018
+ enabled: !(options.eventTimeSource === "extracted" && !options.validAt),
14003
14019
  });
14004
14020
  } catch (profileSupersessionErr) {
14005
14021
  log.warn(
@@ -14042,6 +14058,12 @@ export class Orchestrator {
14042
14058
  intentEntityTypes?: string[];
14043
14059
  memoryKind?: MemoryFrontmatter["memoryKind"];
14044
14060
  validAt?: string;
14061
+ // #1578 — bi-temporal bounds + ingestion provenance forwarded to the
14062
+ // shared-namespace copy so shared recall honours the same invalid_at
14063
+ // window as the source fact (cursor bugbot).
14064
+ invalidAt?: string;
14065
+ observedAt?: string;
14066
+ eventTimeSource?: "extracted" | "assumed";
14045
14067
  source: string;
14046
14068
  /** Claim-level provenance spans (issue #1575 PR 2). */
14047
14069
  sources?: ProvenanceSource[];
@@ -14196,7 +14218,7 @@ export class Orchestrator {
14196
14218
  entityRef: options.entityRef,
14197
14219
  structuredAttributes: options.structuredAttributes,
14198
14220
  createdAt: supersessionOrderingAt(options.validAt),
14199
- enabled: true,
14221
+ enabled: !(options.eventTimeSource === "extracted" && !options.validAt),
14200
14222
  useCallerTimestamp: true,
14201
14223
  });
14202
14224
  // Catalog touch (issue #1499 — codex P2 NElSf): this dedup branch
@@ -14271,6 +14293,10 @@ export class Orchestrator {
14271
14293
  intentEntityTypes: options.intentEntityTypes,
14272
14294
  memoryKind: options.memoryKind,
14273
14295
  validAt: options.validAt,
14296
+ // #1578 — forward bi-temporal bounds + ingestion provenance.
14297
+ ...(options.invalidAt ? { invalidAt: options.invalidAt } : {}),
14298
+ ...(options.observedAt ? { observedAt: options.observedAt } : {}),
14299
+ ...(options.eventTimeSource ? { eventTimeSource: options.eventTimeSource } : {}),
14274
14300
  contentHashSource: options.category === "fact" ? dedupContent : rawContent,
14275
14301
  // Claim-level provenance spans (issue #1575 PR 2).
14276
14302
  ...(options.sources && options.sources.length > 0 ? { sources: options.sources } : {}),
@@ -14296,7 +14322,7 @@ export class Orchestrator {
14296
14322
  entityRef: options.entityRef,
14297
14323
  structuredAttributes: options.structuredAttributes,
14298
14324
  createdAt: supersessionOrderingAt(options.validAt),
14299
- enabled: true,
14325
+ enabled: !(options.eventTimeSource === "extracted" && !options.validAt),
14300
14326
  });
14301
14327
  } catch (sharedSupersessionErr) {
14302
14328
  log.warn(
@@ -14677,7 +14703,7 @@ export class Orchestrator {
14677
14703
  typeof (fact as any).confidence === "number"
14678
14704
  ? (fact as any).confidence
14679
14705
  : 0.7;
14680
-
14706
+ const biTemporal = this.config.temporalBiTemporal && sourceContext?.validAt ? resolveFactEventTime(fact.eventTime, sourceContext.validAt) : undefined;
14681
14707
  // Content-hash dedup check (v6.0)
14682
14708
  //
14683
14709
  // Canonicalize pre-tagged facts before hashing (Codex P2 — issue #369).
@@ -15159,7 +15185,6 @@ export class Orchestrator {
15159
15185
  // back, leaving a dangling deindex with no replacement reference.
15160
15186
  // Child chunks intentionally do NOT carry supersedes; only the
15161
15187
  // parent represents the logical memory unit.
15162
- //
15163
15188
  // Canonicalize contentHashSource before writing (Thread 3 — Codex P2,
15164
15189
  // issue #369). If fact.content already carries an inline citation
15165
15190
  // (e.g. re-processed or relayed fact), strip it so contentHashSource
@@ -15187,7 +15212,8 @@ export class Orchestrator {
15187
15212
  intentEntityTypes: inferredIntent?.entityTypes,
15188
15213
  memoryKind,
15189
15214
  structuredAttributes: fact.structuredAttributes,
15190
- validAt: sourceContext?.validAt,
15215
+ validAt: biTemporal ? biTemporal.validFrom : sourceContext?.validAt,
15216
+ ...(biTemporal ? { observedAt: biTemporal.observedAt, eventTimeSource: biTemporal.eventTimeSource, ...(biTemporal.validUntil ? { invalidAt: biTemporal.validUntil } : {}) } : {}),
15191
15217
  contentHashSource: rawChunkedContent,
15192
15218
  // Faithfulness gate (issue #1576).
15193
15219
  ...(faithfulnessFm ? { faithfulness: faithfulnessFm } : {}),
@@ -15229,7 +15255,17 @@ export class Orchestrator {
15229
15255
  intentActionType: inferredIntent?.actionType,
15230
15256
  intentEntityTypes: inferredIntent?.entityTypes,
15231
15257
  memoryKind,
15232
- validAt: sourceContext?.validAt,
15258
+ validAt: biTemporal ? biTemporal.validFrom : sourceContext?.validAt,
15259
+ // #1578: propagate end bound + provenance to chunks (cursor bugbot).
15260
+ ...(biTemporal
15261
+ ? {
15262
+ observedAt: biTemporal.observedAt,
15263
+ eventTimeSource: biTemporal.eventTimeSource,
15264
+ ...(biTemporal.validUntil
15265
+ ? { invalidAt: biTemporal.validUntil }
15266
+ : {}),
15267
+ }
15268
+ : {}),
15233
15269
  // Faithfulness gate (issue #1576): propagate the parent
15234
15270
  // fact's verdict + enforce status so a pending_review fact
15235
15271
  // is not indexed as active through its chunks (chatgpt P2).
@@ -15287,8 +15323,12 @@ export class Orchestrator {
15287
15323
  newMemoryId: parentId,
15288
15324
  entityRef: supersessionEntityRef,
15289
15325
  structuredAttributes: fact.structuredAttributes,
15290
- createdAt: supersessionOrderingAt(sourceContext?.validAt),
15291
- enabled: this.config.temporalSupersessionEnabled,
15326
+ createdAt: supersessionOrderingAt(biTemporal?.validFrom ?? sourceContext?.validAt),
15327
+ // #1578 r3: an extracted end-only bound (validFrom absent) is
15328
+ // historical, not a new authoritative state — never let it
15329
+ // supersede a later active fact (codex P1 on :15534).
15330
+ enabled: this.config.temporalSupersessionEnabled &&
15331
+ !(biTemporal && !biTemporal.validFrom),
15292
15332
  });
15293
15333
  } catch (err) {
15294
15334
  log.warn(`temporal-supersession (chunked): unexpected error: ${err}`);
@@ -15311,7 +15351,14 @@ export class Orchestrator {
15311
15351
  intentActionType: inferredIntent?.actionType,
15312
15352
  intentEntityTypes: inferredIntent?.entityTypes,
15313
15353
  memoryKind,
15314
- validAt: sourceContext?.validAt,
15354
+ validAt: biTemporal ? biTemporal.validFrom : sourceContext?.validAt,
15355
+ ...(biTemporal
15356
+ ? {
15357
+ observedAt: biTemporal.observedAt,
15358
+ eventTimeSource: biTemporal.eventTimeSource,
15359
+ ...(biTemporal.validUntil ? { invalidAt: biTemporal.validUntil } : {}),
15360
+ }
15361
+ : {}),
15315
15362
  source: extractionWriteSource,
15316
15363
  ...(fact.sources && fact.sources.length > 0 ? { sources: fact.sources } : {}),
15317
15364
  ...(fact.provenance ? { provenance: fact.provenance } : {}),
@@ -15444,13 +15491,11 @@ export class Orchestrator {
15444
15491
  : undefined;
15445
15492
 
15446
15493
  // Normal write (no chunking)
15447
- //
15448
15494
  // Compute the cited content once so that writeMemory and writeArtifact
15449
15495
  // (when verbatim artifacts are enabled) share the same citation timestamp.
15450
15496
  // Calling applyInlineCitation twice on the same raw content would produce
15451
15497
  // two different timestamps, creating duplicate citations with divergent
15452
15498
  // provenance metadata on the memory and artifact copies of the same fact.
15453
- //
15454
15499
  // Pass the RAW (pre-citation) fact as `contentHashSource` so the
15455
15500
  // fact-content hash index records the hash of the canonical fact text
15456
15501
  // rather than the citation-annotated variant. When inline attribution is
@@ -15483,7 +15528,8 @@ export class Orchestrator {
15483
15528
  intentEntityTypes: inferredIntent?.entityTypes,
15484
15529
  memoryKind,
15485
15530
  structuredAttributes: fact.structuredAttributes,
15486
- validAt: sourceContext?.validAt,
15531
+ validAt: biTemporal ? biTemporal.validFrom : sourceContext?.validAt,
15532
+ ...(biTemporal ? { observedAt: biTemporal.observedAt, eventTimeSource: biTemporal.eventTimeSource, ...(biTemporal.validUntil ? { invalidAt: biTemporal.validUntil } : {}) } : {}),
15487
15533
  contentHashSource: writeCategory === "fact" ? fact.content : undefined,
15488
15534
  // Faithfulness gate (issue #1576).
15489
15535
  ...(faithfulnessFm ? { faithfulness: faithfulnessFm } : {}),
@@ -15516,8 +15562,9 @@ export class Orchestrator {
15516
15562
  newMemoryId: memoryId,
15517
15563
  entityRef: supersessionEntityRef,
15518
15564
  structuredAttributes: fact.structuredAttributes,
15519
- createdAt: supersessionOrderingAt(sourceContext?.validAt),
15520
- enabled: this.config.temporalSupersessionEnabled,
15565
+ createdAt: supersessionOrderingAt(biTemporal?.validFrom ?? sourceContext?.validAt),
15566
+ enabled: this.config.temporalSupersessionEnabled &&
15567
+ !(biTemporal && !biTemporal.validFrom),
15521
15568
  });
15522
15569
  } catch (err) {
15523
15570
  log.warn(`temporal-supersession: unexpected error: ${err}`);
@@ -15564,7 +15611,14 @@ export class Orchestrator {
15564
15611
  intentActionType: inferredIntent?.actionType,
15565
15612
  intentEntityTypes: inferredIntent?.entityTypes,
15566
15613
  memoryKind,
15567
- validAt: sourceContext?.validAt,
15614
+ validAt: biTemporal ? biTemporal.validFrom : sourceContext?.validAt,
15615
+ ...(biTemporal
15616
+ ? {
15617
+ observedAt: biTemporal.observedAt,
15618
+ eventTimeSource: biTemporal.eventTimeSource,
15619
+ ...(biTemporal.validUntil ? { invalidAt: biTemporal.validUntil } : {}),
15620
+ }
15621
+ : {}),
15568
15622
  source: extractionWriteSource,
15569
15623
  ...(fact.sources && fact.sources.length > 0 ? { sources: fact.sources } : {}),
15570
15624
  ...(fact.provenance ? { provenance: fact.provenance } : {}),
package/src/schemas.ts CHANGED
@@ -166,6 +166,18 @@ export const ExtractedFactSchema = z.object({
166
166
  .describe(
167
167
  'For category "reasoning_trace" only: a stored solution chain with ordered steps, a final answer, and an optional observed outcome. Require at least two steps.',
168
168
  ),
169
+ eventTime: z
170
+ .string()
171
+ .optional()
172
+ .nullable()
173
+ .describe(
174
+ 'Optional event-time expression for bi-temporal validity (#1578). An ISO date ("2025-03-01") or a relative expression verbatim ("last March", "yesterday", "since 2024", "until 2025-06-01"). Resolved against the source turn timestamp at write time — NOT wall-clock. Omit when the fact has no explicit temporal anchor.',
175
+ ),
176
+ event_time: z
177
+ .string()
178
+ .optional()
179
+ .nullable()
180
+ .describe("Alias for eventTime (snake_case). Gateway-tolerance shim (#1578)."),
169
181
  }).superRefine((value, ctx) => {
170
182
  if (value.category === "procedure" && (!Array.isArray(value.procedureSteps) || value.procedureSteps.length < 2)) {
171
183
  ctx.addIssue({
package/src/storage.ts CHANGED
@@ -3580,6 +3580,7 @@ export class StorageManager {
3580
3580
  // or assumed from the ingestion anchor. Both validate on serialize.
3581
3581
  observedAt?: string;
3582
3582
  eventTimeSource?: "extracted" | "assumed";
3583
+ invalidAt?: string;
3583
3584
  structuredAttributes?: Record<string, string>;
3584
3585
  /**
3585
3586
  * When provided, this string is used as the source for the fact-content
@@ -3665,6 +3666,7 @@ export class StorageManager {
3665
3666
  valid_at: validAt,
3666
3667
  observedAt,
3667
3668
  eventTimeSource: options.eventTimeSource,
3669
+ invalid_at: normalizeMemoryWriteTimestamp("invalidAt", options.invalidAt),
3668
3670
  structuredAttributes: options.structuredAttributes,
3669
3671
  };
3670
3672
  if (options.status !== undefined) {
@@ -4504,12 +4506,10 @@ export class StorageManager {
4504
4506
  // is disabled, missing, or unhealthy. RECALL_FALLBACK_DIRS is the single
4505
4507
  // source of truth derived from ALL_CATEGORY_DIRS (shared with
4506
4508
  // ensureDirectories() and the write routing in utils/category-dir.ts).
4507
- //
4508
4509
  // These paths resolve identically to the legacy this.factsDir /
4509
4510
  // this.correctionsDir / this.proceduresDir / this.reasoningTracesDir
4510
4511
  // getters (all `path.join(this.baseDir, <dir>)`), so the scan stays
4511
4512
  // namespace-aware: this.baseDir is per-namespace, set by the storage router.
4512
- //
4513
4513
  // Deliberately EXCLUDED (issue #1497 + PR #1503 review): the non-category
4514
4514
  // content dirs that ensureDirectories() also creates — entities/, state/,
4515
4515
  // artifacts/, identity/, config/ — plus the root profile.md, AND the
@@ -7359,6 +7359,12 @@ export class StorageManager {
7359
7359
  sources?: ProvenanceSource[];
7360
7360
  /** Coarse provenance tag (issue #1575 PR 2), propagated from the parent. */
7361
7361
  provenance?: "verified" | "unverified" | "none";
7362
+ // Issue #1578 — bi-temporal bounds + ingestion provenance propagated from
7363
+ // the parent fact so an independently-surfaced chunk expires at the same
7364
+ // invalid_at window and carries the same observed-at anchor.
7365
+ invalidAt?: string;
7366
+ observedAt?: string;
7367
+ eventTimeSource?: "extracted" | "assumed";
7362
7368
  } = {},
7363
7369
  ): Promise<string> {
7364
7370
  await this.ensureDirectories();
@@ -7368,6 +7374,8 @@ export class StorageManager {
7368
7374
  const conf = options.confidence ?? 0.8;
7369
7375
  const tier = confidenceTier(conf);
7370
7376
  const validAt = normalizeMemoryWriteTimestamp("validAt", options.validAt);
7377
+ const chunkInvalidAt = normalizeMemoryWriteTimestamp("invalidAt", options.invalidAt);
7378
+ const chunkObservedAt = normalizeMemoryWriteTimestamp("observedAt", options.observedAt);
7371
7379
 
7372
7380
  const fm: MemoryFrontmatter = {
7373
7381
  id,
@@ -7388,6 +7396,9 @@ export class StorageManager {
7388
7396
  intentEntityTypes: options.intentEntityTypes,
7389
7397
  memoryKind: options.memoryKind,
7390
7398
  valid_at: validAt,
7399
+ invalid_at: chunkInvalidAt,
7400
+ observedAt: chunkObservedAt,
7401
+ eventTimeSource: options.eventTimeSource,
7391
7402
  ...(options.status ? { status: options.status } : {}),
7392
7403
  ...(options.faithfulness ? { faithfulness: options.faithfulness } : {}),
7393
7404
  ...(options.sources ? { sources: options.sources } : {}),
@@ -410,6 +410,39 @@ test("isValidAsOf: half-open interval [valid_at, invalid_at)", () => {
410
410
  assert.equal(isValidAsOf(fm, Date.parse("2026-01-01T00:00:00.000Z")), false);
411
411
  });
412
412
 
413
+ test("isValidAsOf: extracted end-only bound is open-start (-inf, invalid_at] (#1578 r3)", () => {
414
+ // An extracted fact like "we used MongoDB until June 2025" resolves to
415
+ // validUntil only (no validFrom); valid_at is absent, eventTimeSource is
416
+ // "extracted". The interval must be open-start so historical as_of queries
417
+ // before ingestion still see it, rather than defaulting valid_at to created.
418
+ const fm = {
419
+ invalid_at: "2025-07-01T00:00:00.000Z",
420
+ created: "2025-08-15T00:00:00.000Z",
421
+ eventTimeSource: "extracted" as const,
422
+ };
423
+ // Well before ingestion/created — still authoritative (open start).
424
+ assert.equal(isValidAsOf(fm, Date.parse("2024-01-01T00:00:00.000Z")), true);
425
+ // Mid-window — authoritative.
426
+ assert.equal(isValidAsOf(fm, Date.parse("2025-06-15T00:00:00.000Z")), true);
427
+ // Exactly at invalid_at — NOT authoritative (exclusive upper bound).
428
+ assert.equal(isValidAsOf(fm, Date.parse("2025-07-01T00:00:00.000Z")), false);
429
+ // After invalid_at — not authoritative.
430
+ assert.equal(isValidAsOf(fm, Date.parse("2026-01-01T00:00:00.000Z")), false);
431
+ });
432
+
433
+ test("isValidAsOf: legacy memory without eventTimeSource keeps created fallback (#1578 r3)", () => {
434
+ // A legacy memory with invalid_at but no eventTimeSource must NOT become
435
+ // open-start — it keeps the pre-#1578 [created, invalid_at) behaviour so
436
+ // supersession/backfill semantics are unchanged.
437
+ const fm = {
438
+ invalid_at: "2025-12-31T00:00:00.000Z",
439
+ created: "2025-06-01T00:00:00.000Z",
440
+ };
441
+ // Before created — not authoritative (legacy behaviour preserved).
442
+ assert.equal(isValidAsOf(fm, Date.parse("2025-05-01T00:00:00.000Z")), false);
443
+ assert.equal(isValidAsOf(fm, Date.parse("2025-09-01T00:00:00.000Z")), true);
444
+ });
445
+
413
446
  test("isValidAsOf: timezone-suffixed ISO strings compare via Date.parse, not lexicographic", () => {
414
447
  // Two strings that order differently lexicographically vs as Dates.
415
448
  // 2025-01-01T00:00:00+02:00 == 2024-12-31T22:00:00Z
@@ -82,11 +82,34 @@ export function effectiveInvalidAt(
82
82
  export function isValidAsOf(
83
83
  fm: Pick<
84
84
  MemoryFrontmatter,
85
- "valid_at" | "invalid_at" | "created" | "supersededAt" | "status"
85
+ | "valid_at"
86
+ | "invalid_at"
87
+ | "created"
88
+ | "supersededAt"
89
+ | "status"
90
+ | "eventTimeSource"
86
91
  >,
87
92
  asOfMs: number,
88
93
  ): boolean {
89
94
  if (!Number.isFinite(asOfMs)) return true;
95
+ // Open-start bi-temporal interval (#1578 r3): an extracted end-only bound
96
+ // (eventTimeSource "extracted", no valid_at, has invalid_at) is true from
97
+ // the indefinite past. Without this, effectiveValidAt falls back to
98
+ // `created` and a historical as_of before ingestion hides a fact that was
99
+ // actually true up until invalid_at (chatgpt-codex thread on
100
+ // orchestrator.ts:15533). Gated on eventTimeSource so legacy memories
101
+ // (no bi-temporal provenance) keep the created-anchor fallback.
102
+ const explicitValidAt = fm.valid_at?.trim();
103
+ if (
104
+ (!explicitValidAt || explicitValidAt.length === 0) &&
105
+ fm.eventTimeSource === "extracted"
106
+ ) {
107
+ const invalidAt = effectiveInvalidAt(fm);
108
+ if (invalidAt !== undefined) {
109
+ const invalidAtMs = Date.parse(invalidAt);
110
+ if (Number.isFinite(invalidAtMs)) return invalidAtMs > asOfMs;
111
+ }
112
+ }
90
113
  const validAtMs = Date.parse(effectiveValidAt(fm));
91
114
  if (!Number.isFinite(validAtMs)) return false;
92
115
  if (validAtMs > asOfMs) return false;
package/src/types.ts CHANGED
@@ -810,8 +810,9 @@ export interface PluginConfig {
810
810
  * Turn on to exclude validity-expired facts from default injection
811
811
  * candidates (they remain findable by explicit search and `as_of`
812
812
  * queries). Storage round-trips `observedAt`/`eventTimeSource`; the
813
- * extraction prompt `resolveEventTime` write-time wiring lands in a
814
- * follow-on PR, so new extractions are not yet event-time-resolved.
813
+ * extraction prompt emits an optional per-fact `eventTime` expression
814
+ * and `resolveFactEventTime` resolves it against the source turn
815
+ * timestamp at write time (#1578 PR2).
815
816
  */
816
817
  temporalBiTemporal: boolean;
817
818
  /**
@@ -2893,6 +2894,15 @@ export interface ExtractedFact {
2893
2894
  * walked through. Persisted under reasoning-traces/.
2894
2895
  */
2895
2896
  reasoningTrace?: ExtractedReasoningTrace;
2897
+ /**
2898
+ * Optional event-time expression for bi-temporal validity (#1578 PR2).
2899
+ * Verbatim temporal anchor extracted from the conversation ("2025-03-01",
2900
+ * "last March", "since 2024", "until 2025-06-01"). Resolved against the
2901
+ * source turn timestamp at write time by `resolveFactEventTime` — never
2902
+ * re-resolved at read. Absent when the fact carries no temporal anchor or
2903
+ * when `temporal.biTemporal` is off.
2904
+ */
2905
+ eventTime?: string;
2896
2906
  }
2897
2907
 
2898
2908
  export interface ExtractedReasoningTraceStep {