@remnic/core 9.3.653 → 9.3.655

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 (273) hide show
  1. package/dist/access-cli.js +24 -24
  2. package/dist/access-http.d.ts +4 -4
  3. package/dist/access-http.js +17 -17
  4. package/dist/access-mcp.d.ts +4 -4
  5. package/dist/access-mcp.js +16 -16
  6. package/dist/access-schema.d.ts +12 -12
  7. package/dist/{access-service-CdJFd3_b.d.ts → access-service-BEJvriUt.d.ts} +11 -2
  8. package/dist/access-service.d.ts +4 -4
  9. package/dist/access-service.js +15 -15
  10. package/dist/action-confidence.d.ts +1 -1
  11. package/dist/active-memory-bridge.d.ts +1 -1
  12. package/dist/active-recall.d.ts +1 -1
  13. package/dist/active-recall.js +1 -1
  14. package/dist/behavior-learner.d.ts +1 -1
  15. package/dist/behavior-signals.d.ts +1 -1
  16. package/dist/bootstrap.d.ts +3 -3
  17. package/dist/briefing.d.ts +1 -1
  18. package/dist/briefing.js +3 -3
  19. package/dist/buffer-surprise-report.d.ts +1 -1
  20. package/dist/buffer.d.ts +1 -1
  21. package/dist/calibration.d.ts +1 -1
  22. package/dist/causal-behavior.d.ts +1 -1
  23. package/dist/causal-consolidation.d.ts +1 -1
  24. package/dist/causal-consolidation.js +4 -4
  25. package/dist/{chunk-GI45G4BK.js → chunk-2RCGZ67B.js} +4 -4
  26. package/dist/{chunk-BEMWL2FZ.js → chunk-54LOUIBE.js} +2 -2
  27. package/dist/{chunk-E3J6O6N7.js → chunk-55ZMNKMQ.js} +20 -9
  28. package/dist/{chunk-E3J6O6N7.js.map → chunk-55ZMNKMQ.js.map} +1 -1
  29. package/dist/{chunk-7WEB3FLJ.js → chunk-5PLUC5OB.js} +2 -2
  30. package/dist/{chunk-SPMZZUEJ.js → chunk-5QD3QD76.js} +2684 -401
  31. package/dist/chunk-5QD3QD76.js.map +1 -0
  32. package/dist/{chunk-WLGE6KEO.js → chunk-67G4T7KI.js} +3 -3
  33. package/dist/{chunk-JX2RINDR.js → chunk-6G5JEN55.js} +2 -2
  34. package/dist/{chunk-R3PQUPQ4.js → chunk-6IMKOIZ6.js} +85 -3
  35. package/dist/chunk-6IMKOIZ6.js.map +1 -0
  36. package/dist/{chunk-KJDKZVF3.js → chunk-A3Y37UWI.js} +3 -3
  37. package/dist/{chunk-CFOCZPIQ.js → chunk-BGKXTVNG.js} +2 -2
  38. package/dist/{chunk-QQHIQ7JD.js → chunk-COVZLGMR.js} +87 -18
  39. package/dist/chunk-COVZLGMR.js.map +1 -0
  40. package/dist/{chunk-JVRPJ7D4.js → chunk-EKQMQQ3U.js} +48 -12
  41. package/dist/chunk-EKQMQQ3U.js.map +1 -0
  42. package/dist/{chunk-H3PHZLMF.js → chunk-GKKAXVAJ.js} +20 -11
  43. package/dist/chunk-GKKAXVAJ.js.map +1 -0
  44. package/dist/{chunk-JBHXMCYN.js → chunk-GRYAECRV.js} +2 -2
  45. package/dist/{chunk-EHQLDFSH.js → chunk-IQ53ZSXV.js} +2 -2
  46. package/dist/{chunk-C63WC454.js → chunk-KOI765XP.js} +125 -1
  47. package/dist/chunk-KOI765XP.js.map +1 -0
  48. package/dist/{chunk-IVYSVAC6.js → chunk-KZZ4YAEC.js} +2 -2
  49. package/dist/{chunk-2DGQLOOM.js → chunk-M3VYPE2H.js} +1 -1
  50. package/dist/{chunk-2DGQLOOM.js.map → chunk-M3VYPE2H.js.map} +1 -1
  51. package/dist/{chunk-JF7SFXTG.js → chunk-NCSJKK23.js} +2 -2
  52. package/dist/{chunk-XMN6MMTU.js → chunk-NRBGRZW4.js} +2 -2
  53. package/dist/{chunk-NOBL7OUP.js → chunk-OKW6F5S5.js} +12 -5
  54. package/dist/{chunk-NOBL7OUP.js.map → chunk-OKW6F5S5.js.map} +1 -1
  55. package/dist/{chunk-BNFRL6QW.js → chunk-PTMJ2FH2.js} +2 -2
  56. package/dist/{chunk-KWM33SPU.js → chunk-PVE7KSQP.js} +2 -2
  57. package/dist/{chunk-EW52H5EM.js → chunk-QDVQ4AN2.js} +12 -5
  58. package/dist/chunk-QDVQ4AN2.js.map +1 -0
  59. package/dist/{chunk-PYWNNF2I.js → chunk-QRSKPI62.js} +99 -66
  60. package/dist/chunk-QRSKPI62.js.map +1 -0
  61. package/dist/{chunk-YM3LR4LS.js → chunk-SSSXWIBP.js} +5 -5
  62. package/dist/{chunk-C43KEWEV.js → chunk-TDZSSJV4.js} +1 -1
  63. package/dist/chunk-TDZSSJV4.js.map +1 -0
  64. package/dist/{chunk-Y7NWBBHV.js → chunk-TEO46GMM.js} +2 -2
  65. package/dist/{chunk-AJE7FJVE.js → chunk-UCEABZZN.js} +2 -2
  66. package/dist/{chunk-IENGGY2C.js → chunk-UCEDY5M7.js} +2 -2
  67. package/dist/{chunk-PRQXUSQV.js → chunk-UYNFWZWG.js} +2 -2
  68. package/dist/{chunk-V4UDXYGG.js → chunk-WDTUYOLS.js} +2 -2
  69. package/dist/{chunk-RZOBQ23O.js → chunk-XOFXKASO.js} +2 -2
  70. package/dist/chunk-XRKQOQLY.js +212 -0
  71. package/dist/chunk-XRKQOQLY.js.map +1 -0
  72. package/dist/{chunk-WTI35CVJ.js → chunk-YYN3LIYA.js} +5 -5
  73. package/dist/{cli-DDo7Qgs-.d.ts → cli-BGahB_d3.d.ts} +3 -3
  74. package/dist/cli.d.ts +5 -5
  75. package/dist/cli.js +29 -29
  76. package/dist/compounding/engine.d.ts +1 -1
  77. package/dist/compounding/engine.js +3 -3
  78. package/dist/compounding/preference-consolidator.d.ts +1 -1
  79. package/dist/compression-optimizer.d.ts +1 -1
  80. package/dist/config.d.ts +1 -1
  81. package/dist/config.js +1 -1
  82. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  83. package/dist/connectors/codex-materialize-runner.js +3 -3
  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 +3 -3
  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 +19 -1
  90. package/dist/contradiction/index.js +1 -1
  91. package/dist/conversation-index/backend.d.ts +1 -1
  92. package/dist/conversation-index/chunker.d.ts +1 -1
  93. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  94. package/dist/conversation-index/indexer.d.ts +1 -1
  95. package/dist/conversation-index/search.d.ts +1 -1
  96. package/dist/day-summary.d.ts +1 -1
  97. package/dist/delinearize.d.ts +1 -1
  98. package/dist/direct-answer-wiring.d.ts +1 -1
  99. package/dist/direct-answer.d.ts +1 -1
  100. package/dist/embedding-fallback.d.ts +1 -1
  101. package/dist/enrichment/index.d.ts +1 -1
  102. package/dist/entity-retrieval.d.ts +1 -1
  103. package/dist/entity-retrieval.js +3 -3
  104. package/dist/entity-schema.d.ts +1 -1
  105. package/dist/explicit-capture.d.ts +3 -3
  106. package/dist/explicit-capture.js +1 -1
  107. package/dist/extraction-judge-telemetry.d.ts +1 -1
  108. package/dist/extraction-judge-training.d.ts +1 -1
  109. package/dist/extraction-judge.d.ts +1 -1
  110. package/dist/extraction.d.ts +1 -1
  111. package/dist/fallback-llm.d.ts +1 -1
  112. package/dist/identity-continuity.d.ts +1 -1
  113. package/dist/importance.d.ts +1 -1
  114. package/dist/index.d.ts +8 -8
  115. package/dist/index.js +37 -35
  116. package/dist/index.js.map +1 -1
  117. package/dist/intent.d.ts +1 -1
  118. package/dist/lcm/engine.d.ts +1 -1
  119. package/dist/lcm/index.d.ts +1 -1
  120. package/dist/lcm/tools.d.ts +1 -1
  121. package/dist/lifecycle.d.ts +1 -1
  122. package/dist/live-connectors-runner.d.ts +1 -1
  123. package/dist/local-llm.d.ts +1 -1
  124. package/dist/maintenance/memory-governance.d.ts +1 -1
  125. package/dist/maintenance/memory-governance.js +3 -3
  126. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  127. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  128. package/dist/mcp-memory-inspector-app.d.ts +4 -4
  129. package/dist/memory-action-policy.d.ts +1 -1
  130. package/dist/memory-cache.d.ts +1 -1
  131. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  132. package/dist/memory-projection-store.d.ts +1 -1
  133. package/dist/memory-provenance.d.ts +1 -1
  134. package/dist/memory-worth-outcomes.d.ts +1 -1
  135. package/dist/models-json.d.ts +1 -1
  136. package/dist/namespaces/migrate.d.ts +1 -1
  137. package/dist/namespaces/migrate.js +11 -11
  138. package/dist/namespaces/principal.d.ts +1 -1
  139. package/dist/namespaces/search.d.ts +15 -4
  140. package/dist/namespaces/search.js +7 -7
  141. package/dist/namespaces/storage.d.ts +52 -3
  142. package/dist/namespaces/storage.js +9 -5
  143. package/dist/native-knowledge.d.ts +1 -1
  144. package/dist/operator-toolkit.d.ts +1 -1
  145. package/dist/operator-toolkit.js +14 -14
  146. package/dist/{orchestrator-8fTZsa0y.d.ts → orchestrator-BgzZlWxH.d.ts} +500 -3
  147. package/dist/orchestrator.d.ts +3 -3
  148. package/dist/orchestrator.js +20 -20
  149. package/dist/patterns-cli.d.ts +1 -1
  150. package/dist/policy-runtime.d.ts +1 -1
  151. package/dist/qmd-recall-cache.d.ts +1 -1
  152. package/dist/qmd.d.ts +5 -1
  153. package/dist/qmd.js +2 -2
  154. package/dist/recall-disclosure-escalation.d.ts +1 -1
  155. package/dist/recall-explain-renderer.d.ts +1 -1
  156. package/dist/recall-explain-renderer.js +3 -3
  157. package/dist/recall-planner-llm.d.ts +1 -1
  158. package/dist/recall-state.d.ts +1 -1
  159. package/dist/recall-tag-filter.d.ts +1 -1
  160. package/dist/recall-xray-cli.d.ts +1 -1
  161. package/dist/recall-xray-cli.js +4 -4
  162. package/dist/recall-xray-renderer.d.ts +1 -1
  163. package/dist/recall-xray-renderer.js +3 -3
  164. package/dist/recall-xray.d.ts +1 -1
  165. package/dist/recall-xray.js +2 -2
  166. package/dist/{resolution-3SAP4SH2.js → resolution-IDTEBJFS.js} +2 -2
  167. package/dist/resolve-auth-token.d.ts +1 -1
  168. package/dist/resume-bundles.js +2 -2
  169. package/dist/retrieval-agents.d.ts +1 -1
  170. package/dist/retrieval-tiers.d.ts +1 -1
  171. package/dist/routing/engine.d.ts +1 -1
  172. package/dist/routing/store.d.ts +1 -1
  173. package/dist/schemas.d.ts +22 -22
  174. package/dist/search/embed-helper.d.ts +1 -1
  175. package/dist/search/factory.d.ts +1 -1
  176. package/dist/search/factory.js +6 -6
  177. package/dist/search/index.d.ts +1 -1
  178. package/dist/search/index.js +6 -6
  179. package/dist/search/lancedb-backend.d.ts +1 -1
  180. package/dist/search/lancedb-backend.js +2 -2
  181. package/dist/search/meilisearch-backend.d.ts +1 -1
  182. package/dist/search/meilisearch-backend.js +2 -2
  183. package/dist/search/noop-backend.d.ts +1 -1
  184. package/dist/search/orama-backend.d.ts +1 -1
  185. package/dist/search/orama-backend.js +2 -2
  186. package/dist/search/port.d.ts +17 -1
  187. package/dist/search/port.js +1 -1
  188. package/dist/search/remote-backend.d.ts +1 -1
  189. package/dist/{semantic-consolidation-DKdYzQOg.d.ts → semantic-consolidation-Z8d_uMq8.d.ts} +1 -1
  190. package/dist/semantic-consolidation.d.ts +2 -2
  191. package/dist/semantic-consolidation.js +4 -4
  192. package/dist/semantic-rule-promotion.js +3 -3
  193. package/dist/semantic-rule-verifier.d.ts +1 -1
  194. package/dist/semantic-rule-verifier.js +3 -3
  195. package/dist/session-observer-bands.d.ts +1 -1
  196. package/dist/session-observer-state.d.ts +1 -1
  197. package/dist/shared-context/manager.d.ts +1 -1
  198. package/dist/signal.d.ts +1 -1
  199. package/dist/storage.d.ts +1 -1
  200. package/dist/storage.js +2 -2
  201. package/dist/summarizer.d.ts +1 -1
  202. package/dist/summary-snapshot.d.ts +1 -1
  203. package/dist/temporal-supersession.d.ts +1 -1
  204. package/dist/temporal-validity.d.ts +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/transfer/types.d.ts +12 -12
  211. package/dist/{types-D8yUmSik.d.ts → types-2OPlQWJG.d.ts} +23 -0
  212. package/dist/types.d.ts +1 -1
  213. package/dist/types.js +1 -1
  214. package/dist/utility-runtime.d.ts +1 -1
  215. package/dist/verified-recall.js +3 -3
  216. package/package.json +1 -1
  217. package/src/access-http.ts +7 -0
  218. package/src/access-mcp.ts +7 -0
  219. package/src/access-service.ts +12 -0
  220. package/src/cli.ts +104 -0
  221. package/src/config.test.ts +109 -0
  222. package/src/config.ts +164 -0
  223. package/src/contradiction/contradiction.test.ts +284 -0
  224. package/src/contradiction/resolution.ts +151 -4
  225. package/src/explicit-capture.ts +31 -10
  226. package/src/index.ts +10 -0
  227. package/src/maintenance/namespace-planner.test.ts +1120 -0
  228. package/src/maintenance/namespace-planner.ts +893 -0
  229. package/src/namespaces/catalog.test.ts +3356 -0
  230. package/src/namespaces/catalog.ts +2123 -0
  231. package/src/namespaces/search.test.ts +130 -2
  232. package/src/namespaces/search.ts +71 -10
  233. package/src/namespaces/storage.ts +210 -30
  234. package/src/orchestrator-flush.test.ts +720 -0
  235. package/src/orchestrator.ts +881 -239
  236. package/src/qmd-client.test.ts +59 -0
  237. package/src/qmd.ts +124 -84
  238. package/src/search/port.ts +16 -0
  239. package/src/types.ts +23 -0
  240. package/dist/chunk-C43KEWEV.js.map +0 -1
  241. package/dist/chunk-C63WC454.js.map +0 -1
  242. package/dist/chunk-EW52H5EM.js.map +0 -1
  243. package/dist/chunk-H3PHZLMF.js.map +0 -1
  244. package/dist/chunk-JVRPJ7D4.js.map +0 -1
  245. package/dist/chunk-ORGWWNJG.js +0 -131
  246. package/dist/chunk-ORGWWNJG.js.map +0 -1
  247. package/dist/chunk-PYWNNF2I.js.map +0 -1
  248. package/dist/chunk-QQHIQ7JD.js.map +0 -1
  249. package/dist/chunk-R3PQUPQ4.js.map +0 -1
  250. package/dist/chunk-SPMZZUEJ.js.map +0 -1
  251. /package/dist/{chunk-GI45G4BK.js.map → chunk-2RCGZ67B.js.map} +0 -0
  252. /package/dist/{chunk-BEMWL2FZ.js.map → chunk-54LOUIBE.js.map} +0 -0
  253. /package/dist/{chunk-7WEB3FLJ.js.map → chunk-5PLUC5OB.js.map} +0 -0
  254. /package/dist/{chunk-WLGE6KEO.js.map → chunk-67G4T7KI.js.map} +0 -0
  255. /package/dist/{chunk-JX2RINDR.js.map → chunk-6G5JEN55.js.map} +0 -0
  256. /package/dist/{chunk-KJDKZVF3.js.map → chunk-A3Y37UWI.js.map} +0 -0
  257. /package/dist/{chunk-CFOCZPIQ.js.map → chunk-BGKXTVNG.js.map} +0 -0
  258. /package/dist/{chunk-JBHXMCYN.js.map → chunk-GRYAECRV.js.map} +0 -0
  259. /package/dist/{chunk-EHQLDFSH.js.map → chunk-IQ53ZSXV.js.map} +0 -0
  260. /package/dist/{chunk-IVYSVAC6.js.map → chunk-KZZ4YAEC.js.map} +0 -0
  261. /package/dist/{chunk-JF7SFXTG.js.map → chunk-NCSJKK23.js.map} +0 -0
  262. /package/dist/{chunk-XMN6MMTU.js.map → chunk-NRBGRZW4.js.map} +0 -0
  263. /package/dist/{chunk-BNFRL6QW.js.map → chunk-PTMJ2FH2.js.map} +0 -0
  264. /package/dist/{chunk-KWM33SPU.js.map → chunk-PVE7KSQP.js.map} +0 -0
  265. /package/dist/{chunk-YM3LR4LS.js.map → chunk-SSSXWIBP.js.map} +0 -0
  266. /package/dist/{chunk-Y7NWBBHV.js.map → chunk-TEO46GMM.js.map} +0 -0
  267. /package/dist/{chunk-AJE7FJVE.js.map → chunk-UCEABZZN.js.map} +0 -0
  268. /package/dist/{chunk-IENGGY2C.js.map → chunk-UCEDY5M7.js.map} +0 -0
  269. /package/dist/{chunk-PRQXUSQV.js.map → chunk-UYNFWZWG.js.map} +0 -0
  270. /package/dist/{chunk-V4UDXYGG.js.map → chunk-WDTUYOLS.js.map} +0 -0
  271. /package/dist/{chunk-RZOBQ23O.js.map → chunk-XOFXKASO.js.map} +0 -0
  272. /package/dist/{chunk-WTI35CVJ.js.map → chunk-YYN3LIYA.js.map} +0 -0
  273. /package/dist/{resolution-3SAP4SH2.js.map → resolution-IDTEBJFS.js.map} +0 -0
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  parseXrayFormat
3
- } from "./chunk-IENGGY2C.js";
3
+ } from "./chunk-UCEDY5M7.js";
4
4
  import {
5
5
  RECALL_DISCLOSURE_LEVELS,
6
6
  isRecallDisclosure
7
- } from "./chunk-C43KEWEV.js";
7
+ } from "./chunk-TDZSSJV4.js";
8
8
 
9
9
  // src/recall-xray-cli.ts
10
10
  function parseXrayDisclosureFlag(value) {
@@ -50,4 +50,4 @@ export {
50
50
  parseXrayBudgetFlag,
51
51
  parseXrayCliOptions
52
52
  };
53
- //# sourceMappingURL=chunk-WLGE6KEO.js.map
53
+ //# sourceMappingURL=chunk-67G4T7KI.js.map
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-CINZGPSJ.js";
8
8
  import {
9
9
  resolveEnsureCollectionArgs
10
- } from "./chunk-2DGQLOOM.js";
10
+ } from "./chunk-M3VYPE2H.js";
11
11
  import {
12
12
  log
13
13
  } from "./chunk-2ODBA7MQ.js";
@@ -245,4 +245,4 @@ function isMeilisearchIndexNotFoundError(err) {
245
245
  export {
246
246
  MeilisearchBackend
247
247
  };
248
- //# sourceMappingURL=chunk-JX2RINDR.js.map
248
+ //# sourceMappingURL=chunk-6G5JEN55.js.map
@@ -33,6 +33,34 @@ async function executeResolution(memoryDir, storage, pairId, verb, options = {})
33
33
  let message = "";
34
34
  let supersedeFailed = false;
35
35
  let rollbackAfterResolveFailure = null;
36
+ let recordCatalogWriteTouch = null;
37
+ const buildCatalogTouch = () => {
38
+ if (!options.onMergedMemoryWritten) return null;
39
+ const onMergedMemoryWritten = options.onMergedMemoryWritten;
40
+ const namespace = pair.namespace;
41
+ const storageDir = resolutionStorage.dir;
42
+ return () => onMergedMemoryWritten(namespace, storageDir);
43
+ };
44
+ const catalogWriteTouch = buildCatalogTouch();
45
+ const recordCatalogWriteTouchSafely = (context, touch = catalogWriteTouch) => {
46
+ if (!touch) return;
47
+ try {
48
+ touch();
49
+ } catch (err) {
50
+ log.warn(
51
+ "[contradiction-resolution] catalog write touch failed for pair=%s context=%s: %s",
52
+ pairId,
53
+ context,
54
+ err instanceof Error ? err.message : err
55
+ );
56
+ }
57
+ };
58
+ const touchCatalogIfRollbackLeftChange = async (context, snapshots, replacement) => {
59
+ if (!catalogWriteTouch) return;
60
+ if (await rollbackLeftDurableMutation(resolutionStorage, snapshots, replacement)) {
61
+ recordCatalogWriteTouchSafely(context);
62
+ }
63
+ };
36
64
  switch (verb) {
37
65
  case "keep-a": {
38
66
  const keepTarget = await validateKeepTarget(resolutionStorage, pairId, idA);
@@ -46,10 +74,14 @@ async function executeResolution(memoryDir, storage, pairId, verb, options = {})
46
74
  if (ok) {
47
75
  affectedIds.push(idB);
48
76
  rollbackAfterResolveFailure = async () => restoreMemorySnapshot(resolutionStorage, sourceB, "contradiction-resolution:keep-a-rollback");
77
+ recordCatalogWriteTouch = catalogWriteTouch;
49
78
  message = `Kept ${idA}, superseded ${idB}`;
50
79
  } else {
51
80
  supersedeFailed = true;
52
81
  const rolledBack = sourceB ? await restoreMemorySnapshot(resolutionStorage, sourceB, "contradiction-resolution:keep-a-rollback") : false;
82
+ if (sourceB && !rolledBack) {
83
+ await touchCatalogIfRollbackLeftChange("keep-a-rollback-incomplete", [sourceB]);
84
+ }
53
85
  message = rolledBack ? `Supersede failed for ${idB}; restored ${idB} and did not resolve` : `Supersede failed for ${idB}; rollback incomplete for ${idB} and pair is not resolved`;
54
86
  }
55
87
  break;
@@ -66,10 +98,14 @@ async function executeResolution(memoryDir, storage, pairId, verb, options = {})
66
98
  if (ok) {
67
99
  affectedIds.push(idA);
68
100
  rollbackAfterResolveFailure = async () => restoreMemorySnapshot(resolutionStorage, sourceA, "contradiction-resolution:keep-b-rollback");
101
+ recordCatalogWriteTouch = catalogWriteTouch;
69
102
  message = `Kept ${idB}, superseded ${idA}`;
70
103
  } else {
71
104
  supersedeFailed = true;
72
105
  const rolledBack = sourceA ? await restoreMemorySnapshot(resolutionStorage, sourceA, "contradiction-resolution:keep-b-rollback") : false;
106
+ if (sourceA && !rolledBack) {
107
+ await touchCatalogIfRollbackLeftChange("keep-b-rollback-incomplete", [sourceA]);
108
+ }
73
109
  message = rolledBack ? `Supersede failed for ${idA}; restored ${idA} and did not resolve` : `Supersede failed for ${idA}; rollback incomplete for ${idA} and pair is not resolved`;
74
110
  }
75
111
  break;
@@ -88,6 +124,8 @@ async function executeResolution(memoryDir, storage, pairId, verb, options = {})
88
124
  message = rolledBackA ? `Merge failed for ${idA}; restored ${idA} and did not resolve` : `Merge failed for ${idA}; rollback incomplete for ${idA} and pair is not resolved`;
89
125
  if (rolledBackA) {
90
126
  await cleanupCreatedReplacement(resolutionStorage, replacement);
127
+ } else {
128
+ await touchCatalogIfRollbackLeftChange("merge-first-rollback-incomplete", [replacement.sourceA], replacement);
91
129
  }
92
130
  break;
93
131
  }
@@ -102,6 +140,12 @@ async function executeResolution(memoryDir, storage, pairId, verb, options = {})
102
140
  ].filter(Boolean).join(", ")} and pair is not resolved`;
103
141
  if (rolledBackA && rolledBackB) {
104
142
  await cleanupCreatedReplacement(resolutionStorage, replacement);
143
+ } else {
144
+ await touchCatalogIfRollbackLeftChange(
145
+ "merge-second-rollback-incomplete",
146
+ [replacement.sourceA, replacement.sourceB],
147
+ replacement
148
+ );
105
149
  }
106
150
  break;
107
151
  }
@@ -114,6 +158,7 @@ async function executeResolution(memoryDir, storage, pairId, verb, options = {})
114
158
  }
115
159
  return rolledBackA && rolledBackB;
116
160
  };
161
+ recordCatalogWriteTouch = catalogWriteTouch;
117
162
  message = `Both memories superseded by merged ${replacement.mergedId}`;
118
163
  break;
119
164
  }
@@ -142,10 +187,15 @@ async function executeResolution(memoryDir, storage, pairId, verb, options = {})
142
187
  if (rollbackAfterResolveFailure) {
143
188
  const rolledBack = await rollbackAfterResolveFailure();
144
189
  affectedIds.length = 0;
145
- message = rolledBack ? `Resolution persistence failed; rolled back memory changes and did not resolve ${pairId}` : `Resolution persistence failed; rollback incomplete and pair is not resolved`;
190
+ message = rolledBack ? `Resolution persistence failed; rolled back memory changes and did not resolve ${pairId}` : "Resolution persistence failed; rollback incomplete and pair is not resolved";
191
+ if (!rolledBack && recordCatalogWriteTouch) {
192
+ recordCatalogWriteTouchSafely("resolve-persistence-rollback-incomplete", recordCatalogWriteTouch);
193
+ }
146
194
  } else {
147
- message = `Resolution persistence failed; pair is not resolved`;
195
+ message = "Resolution persistence failed; pair is not resolved";
148
196
  }
197
+ } else if (recordCatalogWriteTouch) {
198
+ recordCatalogWriteTouchSafely("resolved", recordCatalogWriteTouch);
149
199
  }
150
200
  }
151
201
  log.info("[contradiction-resolution] pair=%s verb=%s affected=%d", pairId, verb, affectedIds.length);
@@ -257,6 +307,38 @@ async function restoreMemorySnapshot(storage, memory, reasonCode = "contradictio
257
307
  return false;
258
308
  }
259
309
  }
310
+ async function rollbackLeftDurableMutation(storage, snapshots, replacement) {
311
+ for (const snapshot of snapshots) {
312
+ try {
313
+ const current = await storage.getMemoryById(snapshot.frontmatter.id);
314
+ if (!current) return true;
315
+ if (supersessionStateChanged(current, snapshot)) return true;
316
+ } catch (err) {
317
+ log.warn(
318
+ "[contradiction-resolution] rollback inspection failed for %s: %s",
319
+ snapshot.frontmatter.id,
320
+ err instanceof Error ? err.message : err
321
+ );
322
+ return true;
323
+ }
324
+ }
325
+ if (replacement?.created) {
326
+ try {
327
+ return await storage.getMemoryById(replacement.mergedId) !== null;
328
+ } catch (err) {
329
+ log.warn(
330
+ "[contradiction-resolution] rollback replacement inspection failed for %s: %s",
331
+ replacement.mergedId,
332
+ err instanceof Error ? err.message : err
333
+ );
334
+ return true;
335
+ }
336
+ }
337
+ return false;
338
+ }
339
+ function supersessionStateChanged(current, snapshot) {
340
+ return current.frontmatter.status !== snapshot.frontmatter.status || current.frontmatter.supersededBy !== snapshot.frontmatter.supersededBy || current.frontmatter.supersededAt !== snapshot.frontmatter.supersededAt;
341
+ }
260
342
  async function cleanupCreatedReplacement(storage, replacement) {
261
343
  if (!replacement.created) return;
262
344
  await cleanupMemoryId(storage, replacement.mergedId);
@@ -299,4 +381,4 @@ export {
299
381
  isValidResolutionVerb,
300
382
  executeResolution
301
383
  };
302
- //# sourceMappingURL=chunk-R3PQUPQ4.js.map
384
+ //# sourceMappingURL=chunk-6IMKOIZ6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/contradiction/resolution.ts"],"sourcesContent":["/**\n * Resolution Verbs — executes user-chosen resolution actions on contradiction pairs (issue #520).\n *\n * All resolution paths delegate to StorageManager.supersedeMemory. Do not\n * reimplement supersession logic here (rule 22: deduplicate resolution).\n */\n\nimport { log } from \"../logger.js\";\nimport type { StorageManager } from \"../storage.js\";\nimport type { MemoryCategory, MemoryFile } from \"../types.js\";\nimport type { ResolutionVerb } from \"./contradiction-review.js\";\nimport { readPair, resolvePair } from \"./contradiction-review.js\";\n\nexport interface ResolutionResult {\n pairId: string;\n verb: ResolutionVerb;\n /** Memory IDs affected by the resolution. */\n affectedIds: string[];\n /** Human-readable status. */\n message: string;\n}\n\nexport interface ExecuteResolutionOptions {\n /** Existing merged memory to supersede both source memories to. */\n mergedMemoryId?: string;\n /** Content for a new merged memory. Required for merge when mergedMemoryId is omitted. */\n mergedContent?: string;\n /** Category for a newly created merged memory. Defaults to the shared source category, or fact. */\n mergedCategory?: MemoryCategory;\n /** Resolve storage for the pair namespace, or the default namespace for legacy unscoped pairs. */\n storageForNamespace?: (namespace: string | undefined) => StorageManager | Promise<StorageManager>;\n /**\n * Best-effort hook invoked after a contradiction resolution leaves a durable\n * mutation in the namespace's memory files (issue #1499 sweep, NH1dX / NH3X3).\n * Every mutating verb — `merge` (creates a new memory and supersedes both\n * sources), `keep-a`, and `keep-b` (supersede the losing source + rewrite\n * frontmatter) — writes directly to the pair's (possibly DYNAMIC) namespace\n * storage, bypassing the extraction write path that records catalog writes. So\n * without this the namespace's `lastWriteAt` stays stale and QMD maintenance /\n * `writtenSince` can skip a namespace whose only post-write mutation is\n * resolving a contradiction. It fires after the resolution commits, or after a\n * failed resolution/rollback path when durable memory changes are still left on\n * disk. If a failure rolls back cleanly, this is never called, so the catalog\n * never records a write that did not survive (rule #25). Non-mutating verbs\n * (`both-valid`, `needs-more-context`) never trigger it. Callers wire this to\n * `Orchestrator.recordCatalogWrite(namespace, storageDir)`. Must be\n * failure-tolerant: it is fire-and-forget and must never affect resolution.\n */\n onMergedMemoryWritten?: (namespace: string | undefined, storageDir: string) => void;\n}\n\nconst VALID_VERBS: ResolutionVerb[] = [\"keep-a\", \"keep-b\", \"merge\", \"both-valid\", \"needs-more-context\"];\n\nexport function isValidResolutionVerb(value: string): value is ResolutionVerb {\n return VALID_VERBS.includes(value as ResolutionVerb);\n}\n\n/**\n * Execute a resolution verb on a contradiction pair.\n *\n * - `keep-a`: Supersede B, keep A active.\n * - `keep-b`: Supersede A, keep B active.\n * - `merge`: Create or verify a real merged memory, then supersede both inputs.\n * - `both-valid`: Mark pair as reviewed; no memories are superseded.\n * - `needs-more-context`: Defer; no action, short cooldown.\n */\nexport async function executeResolution(\n memoryDir: string,\n storage: StorageManager,\n pairId: string,\n verb: ResolutionVerb,\n options: ExecuteResolutionOptions = {},\n): Promise<ResolutionResult> {\n if (typeof verb !== \"string\" || !isValidResolutionVerb(verb)) {\n throw new Error(`Invalid contradiction resolution verb: ${String(verb)}`);\n }\n\n const pair = readPair(memoryDir, pairId);\n if (!pair) {\n return { pairId, verb, affectedIds: [], message: `Pair ${pairId} not found` };\n }\n\n if (pair.namespace && !options.storageForNamespace) {\n throw new Error(\n \"contradiction resolution requires storageForNamespace for namespaced pairs so callers resolve the correct namespace storage\",\n );\n }\n\n const resolutionStorage = options.storageForNamespace\n ? await options.storageForNamespace(pair.namespace)\n : storage;\n\n if (pair.resolution && pair.resolution !== \"needs-more-context\") {\n return { pairId, verb, affectedIds: [], message: `Pair already resolved with verb \"${pair.resolution}\"` };\n }\n\n const [idA, idB] = pair.memoryIds;\n const affectedIds: string[] = [];\n let message = \"\";\n let supersedeFailed = false;\n let rollbackAfterResolveFailure: (() => Promise<boolean>) | null = null;\n // Deferred catalog-write touch for any resolution that leaves durable namespace\n // memory mutations (issue #1499 sweep, NH1dX / NH3X3). Rule #25: never record a\n // catalog touch for a write that is fully rolled back. Successful mutating\n // resolutions invoke it after `resolvePair` persists. Failed paths invoke it\n // only when rollback inspection shows the namespace still differs from the\n // pre-mutation snapshot.\n let recordCatalogWriteTouch: (() => void) | null = null;\n // Returns the deferred touch fn for a mutating verb (or null when the caller\n // wired no catalog hook), so each branch assigns `recordCatalogWriteTouch`\n // directly in the function body — keeping TS control-flow narrowing intact at\n // the post-commit invocation below.\n const buildCatalogTouch = (): (() => void) | null => {\n if (!options.onMergedMemoryWritten) return null;\n const onMergedMemoryWritten = options.onMergedMemoryWritten;\n const namespace = pair.namespace;\n const storageDir = resolutionStorage.dir;\n return () => onMergedMemoryWritten(namespace, storageDir);\n };\n const catalogWriteTouch = buildCatalogTouch();\n const recordCatalogWriteTouchSafely = (context: string, touch = catalogWriteTouch): void => {\n if (!touch) return;\n try {\n touch();\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] catalog write touch failed for pair=%s context=%s: %s\",\n pairId,\n context,\n err instanceof Error ? err.message : err,\n );\n }\n };\n const touchCatalogIfRollbackLeftChange = async (\n context: string,\n snapshots: MemoryFile[],\n replacement?: Extract<MergeReplacement, { ok: true }>,\n ): Promise<void> => {\n if (!catalogWriteTouch) return;\n if (await rollbackLeftDurableMutation(resolutionStorage, snapshots, replacement)) {\n recordCatalogWriteTouchSafely(context);\n }\n };\n\n switch (verb) {\n case \"keep-a\": {\n const keepTarget = await validateKeepTarget(resolutionStorage, pairId, idA);\n if (!keepTarget.ok) {\n supersedeFailed = true;\n message = keepTarget.message;\n break;\n }\n const sourceB = await loadSourceSnapshot(resolutionStorage, idB);\n const ok = sourceB\n ? await supersedeSafe(resolutionStorage, idB, idA, \"contradiction-resolution:keep-a\")\n : false;\n if (ok) {\n affectedIds.push(idB);\n rollbackAfterResolveFailure = async () =>\n restoreMemorySnapshot(resolutionStorage, sourceB!, \"contradiction-resolution:keep-a-rollback\");\n // keep-a superseded idB in this namespace — record a catalog touch once\n // the resolution durably commits (NH3X3).\n recordCatalogWriteTouch = catalogWriteTouch;\n message = `Kept ${idA}, superseded ${idB}`;\n }\n else {\n supersedeFailed = true;\n const rolledBack = sourceB\n ? await restoreMemorySnapshot(resolutionStorage, sourceB, \"contradiction-resolution:keep-a-rollback\")\n : false;\n if (sourceB && !rolledBack) {\n await touchCatalogIfRollbackLeftChange(\"keep-a-rollback-incomplete\", [sourceB]);\n }\n message = rolledBack\n ? `Supersede failed for ${idB}; restored ${idB} and did not resolve`\n : `Supersede failed for ${idB}; rollback incomplete for ${idB} and pair is not resolved`;\n }\n break;\n }\n case \"keep-b\": {\n const keepTarget = await validateKeepTarget(resolutionStorage, pairId, idB);\n if (!keepTarget.ok) {\n supersedeFailed = true;\n message = keepTarget.message;\n break;\n }\n const sourceA = await loadSourceSnapshot(resolutionStorage, idA);\n const ok = sourceA\n ? await supersedeSafe(resolutionStorage, idA, idB, \"contradiction-resolution:keep-b\")\n : false;\n if (ok) {\n affectedIds.push(idA);\n rollbackAfterResolveFailure = async () =>\n restoreMemorySnapshot(resolutionStorage, sourceA!, \"contradiction-resolution:keep-b-rollback\");\n // keep-b superseded idA in this namespace — record a catalog touch once\n // the resolution durably commits (NH3X3).\n recordCatalogWriteTouch = catalogWriteTouch;\n message = `Kept ${idB}, superseded ${idA}`;\n }\n else {\n supersedeFailed = true;\n const rolledBack = sourceA\n ? await restoreMemorySnapshot(resolutionStorage, sourceA, \"contradiction-resolution:keep-b-rollback\")\n : false;\n if (sourceA && !rolledBack) {\n await touchCatalogIfRollbackLeftChange(\"keep-b-rollback-incomplete\", [sourceA]);\n }\n message = rolledBack\n ? `Supersede failed for ${idA}; restored ${idA} and did not resolve`\n : `Supersede failed for ${idA}; rollback incomplete for ${idA} and pair is not resolved`;\n }\n break;\n }\n case \"merge\": {\n const replacement = await prepareMergeReplacement(resolutionStorage, pairId, idA, idB, options);\n if (!replacement.ok) {\n supersedeFailed = true;\n message = replacement.message;\n break;\n }\n\n const okA = await supersedeSafe(resolutionStorage, idA, replacement.mergedId, \"contradiction-resolution:merge\");\n if (!okA) {\n supersedeFailed = true;\n const rolledBackA = await restoreMemorySnapshot(resolutionStorage, replacement.sourceA);\n message = rolledBackA\n ? `Merge failed for ${idA}; restored ${idA} and did not resolve`\n : `Merge failed for ${idA}; rollback incomplete for ${idA} and pair is not resolved`;\n if (rolledBackA) {\n await cleanupCreatedReplacement(resolutionStorage, replacement);\n }\n else {\n await touchCatalogIfRollbackLeftChange(\"merge-first-rollback-incomplete\", [replacement.sourceA], replacement);\n }\n break;\n }\n\n const okB = await supersedeSafe(resolutionStorage, idB, replacement.mergedId, \"contradiction-resolution:merge\");\n if (!okB) {\n supersedeFailed = true;\n const rolledBackA = await restoreMemorySnapshot(resolutionStorage, replacement.sourceA);\n const rolledBackB = await restoreMemorySnapshot(resolutionStorage, replacement.sourceB);\n message = rolledBackA && rolledBackB\n ? `Merge failed for ${idB}; restored ${idA} and ${idB} and did not resolve`\n : `Merge failed for ${idB}; rollback incomplete for ${[\n rolledBackA ? undefined : idA,\n rolledBackB ? undefined : idB,\n ].filter(Boolean).join(\", \")} and pair is not resolved`;\n if (rolledBackA && rolledBackB) {\n await cleanupCreatedReplacement(resolutionStorage, replacement);\n }\n else {\n await touchCatalogIfRollbackLeftChange(\n \"merge-second-rollback-incomplete\",\n [replacement.sourceA, replacement.sourceB],\n replacement,\n );\n }\n break;\n }\n\n affectedIds.push(idA, idB);\n rollbackAfterResolveFailure = async () => {\n const rolledBackA = await restoreMemorySnapshot(resolutionStorage, replacement.sourceA);\n const rolledBackB = await restoreMemorySnapshot(resolutionStorage, replacement.sourceB);\n if (rolledBackA && rolledBackB) {\n await cleanupCreatedReplacement(resolutionStorage, replacement);\n }\n return rolledBackA && rolledBackB;\n };\n // Catalog write touch (issue #1499 sweep): the merge supersedes BOTH sources\n // (and, when created, writes a fresh merged memory) in the pair's (possibly\n // dynamic) namespace storage — but the resolution is not durable yet\n // (resolvePair persists below, and a failure rolls the merge back). Defer\n // the touch so it fires ONLY after the resolution commits past the rollback\n // point (NH1dX, rule #25). Arm it for EVERY successful merge — even reusing\n // an existing merged-id still supersedes both sources, a namespace mutation\n // that must refresh `lastWriteAt` (NH3X3). Otherwise a dynamic namespace\n // whose only durable mutation is a contradiction merge stays invisible to\n // QMD maintenance / `writtenSince`. Best-effort on the caller side.\n recordCatalogWriteTouch = catalogWriteTouch;\n message = `Both memories superseded by merged ${replacement.mergedId}`;\n break;\n }\n case \"both-valid\": {\n message = \"Pair marked as both-valid; cooldown applied\";\n break;\n }\n case \"needs-more-context\": {\n message = \"Deferred; no action taken, short cooldown applied\";\n break;\n }\n }\n\n if (!supersedeFailed) {\n let resolved = false;\n try {\n resolved = resolvePair(memoryDir, pairId, verb) !== null;\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] failed to persist pair=%s verb=%s: %s\",\n pairId,\n verb,\n err instanceof Error ? err.message : err,\n );\n }\n if (!resolved) {\n if (rollbackAfterResolveFailure) {\n const rolledBack = await rollbackAfterResolveFailure();\n affectedIds.length = 0;\n message = rolledBack\n ? `Resolution persistence failed; rolled back memory changes and did not resolve ${pairId}`\n : \"Resolution persistence failed; rollback incomplete and pair is not resolved\";\n if (!rolledBack && recordCatalogWriteTouch) {\n recordCatalogWriteTouchSafely(\"resolve-persistence-rollback-incomplete\", recordCatalogWriteTouch);\n }\n } else {\n message = \"Resolution persistence failed; pair is not resolved\";\n }\n } else if (recordCatalogWriteTouch) {\n // The resolution durably committed (memory mutated AND the resolution\n // persisted past the rollback point). Only now is it safe to record the\n // catalog write for the namespace mutation (NH1dX / NH3X3, rule #25).\n // Best-effort: the caller's callback swallows errors; guard here so a\n // throwing callback never derails a successful resolution.\n recordCatalogWriteTouchSafely(\"resolved\", recordCatalogWriteTouch);\n }\n }\n log.info(\"[contradiction-resolution] pair=%s verb=%s affected=%d\", pairId, verb, affectedIds.length);\n return { pairId, verb, affectedIds, message };\n}\n\ntype MergeReplacement =\n | {\n ok: true;\n mergedId: string;\n sourceA: MemoryFile;\n sourceB: MemoryFile;\n created: boolean;\n }\n | {\n ok: false;\n message: string;\n };\n\nasync function prepareMergeReplacement(\n storage: StorageManager,\n pairId: string,\n idA: string,\n idB: string,\n options: ExecuteResolutionOptions,\n): Promise<MergeReplacement> {\n const sourceA = await storage.getMemoryById(idA);\n const sourceB = await storage.getMemoryById(idB);\n if (!sourceA || !sourceB) {\n return { ok: false, message: `Merge requires both source memories to exist; not resolving ${pairId}` };\n }\n\n const requestedMergedId = options.mergedMemoryId?.trim();\n if (requestedMergedId) {\n if (requestedMergedId === idA || requestedMergedId === idB) {\n return { ok: false, message: \"Merge replacement must be distinct from both source memories; not resolving\" };\n }\n const replacement = await storage.getMemoryById(requestedMergedId);\n if (!replacement) {\n return { ok: false, message: `Merged memory ${requestedMergedId} not found; not resolving` };\n }\n const replacementStatus = replacement.frontmatter.status ?? \"active\";\n if (replacementStatus !== \"active\") {\n return {\n ok: false,\n message: `Merged memory ${requestedMergedId} is ${replacementStatus}; not resolving`,\n };\n }\n return { ok: true, mergedId: requestedMergedId, sourceA, sourceB, created: false };\n }\n\n const mergedContent = options.mergedContent;\n if (typeof mergedContent !== \"string\" || mergedContent.trim().length === 0) {\n return {\n ok: false,\n message: \"Merge requires mergedMemoryId or mergedContent; no memories changed\",\n };\n }\n\n const category = options.mergedCategory ?? mergedMemoryCategory(sourceA, sourceB);\n let mergedId: string;\n try {\n mergedId = await storage.writeMemory(category, mergedContent, {\n actor: \"contradiction-resolution\",\n confidence: Math.min(sourceA.frontmatter.confidence ?? 0.8, sourceB.frontmatter.confidence ?? 0.8),\n tags: [\"contradiction-resolution\", \"merge\"],\n source: \"contradiction-resolution\",\n lineage: [idA, idB],\n derivedVia: \"merge\",\n });\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] merged memory creation failed for %s: %s\",\n pairId,\n err instanceof Error ? err.message : err,\n );\n return { ok: false, message: `Merged memory could not be created; not resolving ${pairId}` };\n }\n const replacement = await storage.getMemoryById(mergedId);\n if (!replacement) {\n await cleanupMemoryId(storage, mergedId);\n return { ok: false, message: `Merged memory ${mergedId} could not be verified; not resolving` };\n }\n return { ok: true, mergedId, sourceA, sourceB, created: true };\n}\n\nfunction mergedMemoryCategory(sourceA: MemoryFile, sourceB: MemoryFile): MemoryCategory {\n return sourceA.frontmatter.category === sourceB.frontmatter.category\n ? sourceA.frontmatter.category\n : \"fact\";\n}\n\ntype KeepTargetValidation =\n | { ok: true }\n | { ok: false; message: string };\n\nasync function validateKeepTarget(\n storage: StorageManager,\n pairId: string,\n keepId: string,\n): Promise<KeepTargetValidation> {\n const target = await loadSourceSnapshot(storage, keepId);\n if (!target) {\n return { ok: false, message: `Kept memory ${keepId} not found; not resolving ${pairId}` };\n }\n\n const status = target.frontmatter.status ?? \"active\";\n if (status !== \"active\") {\n return { ok: false, message: `Kept memory ${keepId} is ${status}; not resolving ${pairId}` };\n }\n\n return { ok: true };\n}\n\nasync function loadSourceSnapshot(storage: StorageManager, memoryId: string): Promise<MemoryFile | null> {\n try {\n return await storage.getMemoryById(memoryId);\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] source snapshot failed for %s: %s\",\n memoryId,\n err instanceof Error ? err.message : err,\n );\n return null;\n }\n}\n\nasync function restoreMemorySnapshot(\n storage: StorageManager,\n memory: MemoryFile,\n reasonCode = \"contradiction-resolution:merge-rollback\",\n): Promise<boolean> {\n try {\n const current = await storage.getMemoryById(memory.frontmatter.id);\n if (!current) return false;\n const restoredFrontmatter: Partial<MemoryFile[\"frontmatter\"]> = {\n ...memory.frontmatter,\n status: memory.frontmatter.status,\n supersededBy: memory.frontmatter.supersededBy,\n supersededAt: memory.frontmatter.supersededAt,\n };\n return await storage.writeMemoryFrontmatter(current, restoredFrontmatter, {\n actor: \"contradiction-resolution\",\n reasonCode,\n });\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] rollback failed for %s: %s\",\n memory.frontmatter.id,\n err instanceof Error ? err.message : err,\n );\n return false;\n }\n}\n\nasync function rollbackLeftDurableMutation(\n storage: StorageManager,\n snapshots: MemoryFile[],\n replacement?: Extract<MergeReplacement, { ok: true }>,\n): Promise<boolean> {\n for (const snapshot of snapshots) {\n try {\n const current = await storage.getMemoryById(snapshot.frontmatter.id);\n if (!current) return true;\n if (supersessionStateChanged(current, snapshot)) return true;\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] rollback inspection failed for %s: %s\",\n snapshot.frontmatter.id,\n err instanceof Error ? err.message : err,\n );\n return true;\n }\n }\n\n if (replacement?.created) {\n try {\n return (await storage.getMemoryById(replacement.mergedId)) !== null;\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] rollback replacement inspection failed for %s: %s\",\n replacement.mergedId,\n err instanceof Error ? err.message : err,\n );\n return true;\n }\n }\n\n return false;\n}\n\nfunction supersessionStateChanged(current: MemoryFile, snapshot: MemoryFile): boolean {\n return (\n current.frontmatter.status !== snapshot.frontmatter.status ||\n current.frontmatter.supersededBy !== snapshot.frontmatter.supersededBy ||\n current.frontmatter.supersededAt !== snapshot.frontmatter.supersededAt\n );\n}\n\nasync function cleanupCreatedReplacement(storage: StorageManager, replacement: Extract<MergeReplacement, { ok: true }>): Promise<void> {\n if (!replacement.created) return;\n await cleanupMemoryId(storage, replacement.mergedId);\n}\n\nasync function cleanupMemoryId(storage: StorageManager, memoryId: string): Promise<void> {\n try {\n const memory = await storage.getMemoryById(memoryId);\n const invalidated = await storage.invalidateMemory(memoryId);\n if (invalidated && memory?.frontmatter.category === \"fact\") {\n await storage.removeFactContentHashesForMemories([memory]);\n }\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] cleanup failed for merged memory %s: %s\",\n memoryId,\n err instanceof Error ? err.message : err,\n );\n }\n}\n\nasync function supersedeSafe(\n storage: StorageManager,\n oldId: string,\n newId: string,\n reason: string,\n): Promise<boolean> {\n try {\n const result = await storage.supersedeMemory(oldId, newId, reason);\n if (result === false) {\n log.warn(\"[contradiction-resolution] supersede returned false for %s → %s\", oldId, newId);\n return false;\n }\n return true;\n } catch (err) {\n log.warn(\n \"[contradiction-resolution] supersede failed %s → %s: %s\",\n oldId,\n newId,\n err instanceof Error ? err.message : err,\n );\n return false;\n }\n}\n"],"mappings":"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","names":["replacement"]}
@@ -10,10 +10,10 @@ import {
10
10
  import {
11
11
  listMemoryGovernanceRuns,
12
12
  readMemoryGovernanceRunArtifact
13
- } from "./chunk-V4UDXYGG.js";
13
+ } from "./chunk-WDTUYOLS.js";
14
14
  import {
15
15
  StorageManager
16
- } from "./chunk-Y7NWBBHV.js";
16
+ } from "./chunk-TEO46GMM.js";
17
17
  import {
18
18
  MEMORY_LIFECYCLE_EVENT_SORT_ORDER,
19
19
  buildLifecycleEventsForMemory,
@@ -929,4 +929,4 @@ export {
929
929
  verifyMemoryProjection,
930
930
  repairMemoryProjection
931
931
  };
932
- //# sourceMappingURL=chunk-KJDKZVF3.js.map
932
+ //# sourceMappingURL=chunk-A3Y37UWI.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runPostConsolidationMaterialize
3
- } from "./chunk-IVYSVAC6.js";
3
+ } from "./chunk-KZZ4YAEC.js";
4
4
  import {
5
5
  discoverMemoryExtensions,
6
6
  renderExtensionsBlock,
@@ -217,4 +217,4 @@ export {
217
217
  buildExtensionsBlockForConsolidation,
218
218
  materializeAfterSemanticConsolidation
219
219
  };
220
- //# sourceMappingURL=chunk-CFOCZPIQ.js.map
220
+ //# sourceMappingURL=chunk-BGKXTVNG.js.map
@@ -44,12 +44,12 @@ import {
44
44
  } from "./chunk-HOJZMQ4J.js";
45
45
  import {
46
46
  rebuildMemoryLifecycleLedger
47
- } from "./chunk-KWM33SPU.js";
47
+ } from "./chunk-PVE7KSQP.js";
48
48
  import {
49
49
  rebuildMemoryProjection,
50
50
  repairMemoryProjection,
51
51
  verifyMemoryProjection
52
- } from "./chunk-KJDKZVF3.js";
52
+ } from "./chunk-A3Y37UWI.js";
53
53
  import {
54
54
  rebuildObservations
55
55
  } from "./chunk-LZZNTPLR.js";
@@ -74,7 +74,7 @@ import {
74
74
  } from "./chunk-EVWIEEKZ.js";
75
75
  import {
76
76
  promoteSemanticRuleFromMemory
77
- } from "./chunk-EHQLDFSH.js";
77
+ } from "./chunk-IQ53ZSXV.js";
78
78
  import {
79
79
  resolveAgentAccessAuthToken
80
80
  } from "./chunk-TGQ2NTWH.js";
@@ -82,10 +82,10 @@ import {
82
82
  buildResumeBundleFromState,
83
83
  getResumeBundleStatus,
84
84
  recordResumeBundle
85
- } from "./chunk-RZOBQ23O.js";
85
+ } from "./chunk-XOFXKASO.js";
86
86
  import {
87
87
  parseXrayCliOptions
88
- } from "./chunk-WLGE6KEO.js";
88
+ } from "./chunk-67G4T7KI.js";
89
89
  import {
90
90
  runBenchmarkRecall,
91
91
  runOperatorConfigReview,
@@ -93,12 +93,12 @@ import {
93
93
  runOperatorInventory,
94
94
  runOperatorRepair,
95
95
  runOperatorSetup
96
- } from "./chunk-WTI35CVJ.js";
96
+ } from "./chunk-YYN3LIYA.js";
97
97
  import {
98
98
  listNamespaces,
99
99
  runNamespaceMigration,
100
100
  verifyNamespaces
101
- } from "./chunk-GI45G4BK.js";
101
+ } from "./chunk-2RCGZ67B.js";
102
102
  import {
103
103
  collectPatternMemories,
104
104
  explainPatternMemory,
@@ -128,13 +128,13 @@ import {
128
128
  } from "./chunk-TERNBNJB.js";
129
129
  import {
130
130
  searchVerifiedEpisodes
131
- } from "./chunk-JF7SFXTG.js";
131
+ } from "./chunk-NCSJKK23.js";
132
132
  import {
133
133
  ThreadingManager
134
134
  } from "./chunk-W4RVMTHR.js";
135
135
  import {
136
136
  searchVerifiedSemanticRules
137
- } from "./chunk-AJE7FJVE.js";
137
+ } from "./chunk-UCEABZZN.js";
138
138
  import {
139
139
  getWorkProductLedgerStatus,
140
140
  recordWorkProductLedgerEntry,
@@ -210,22 +210,22 @@ import {
210
210
  } from "./chunk-UQ7RN5HK.js";
211
211
  import {
212
212
  parseConfig
213
- } from "./chunk-C63WC454.js";
213
+ } from "./chunk-KOI765XP.js";
214
214
  import {
215
215
  getAbstractionNodeStoreStatus
216
216
  } from "./chunk-OADWQ5CR.js";
217
217
  import {
218
218
  EngramAccessHttpServer
219
- } from "./chunk-EW52H5EM.js";
219
+ } from "./chunk-QDVQ4AN2.js";
220
220
  import {
221
221
  WearablesInputError
222
222
  } from "./chunk-7WV3F5DQ.js";
223
223
  import {
224
224
  EngramMcpServer
225
- } from "./chunk-NOBL7OUP.js";
225
+ } from "./chunk-OKW6F5S5.js";
226
226
  import {
227
227
  EngramAccessService
228
- } from "./chunk-E3J6O6N7.js";
228
+ } from "./chunk-55ZMNKMQ.js";
229
229
  import {
230
230
  WorkStorage
231
231
  } from "./chunk-GDB4J2H3.js";
@@ -233,13 +233,13 @@ import {
233
233
  parseRecallExplainFormat,
234
234
  renderRecallExplain,
235
235
  renderXray
236
- } from "./chunk-IENGGY2C.js";
236
+ } from "./chunk-UCEDY5M7.js";
237
237
  import {
238
238
  listMemoryGovernanceRuns,
239
239
  readMemoryGovernanceRunArtifact,
240
240
  restoreMemoryGovernanceRun,
241
241
  runMemoryGovernance
242
- } from "./chunk-V4UDXYGG.js";
242
+ } from "./chunk-WDTUYOLS.js";
243
243
  import {
244
244
  getTrustZoneStoreStatus,
245
245
  promoteTrustZoneRecord,
@@ -254,7 +254,7 @@ import {
254
254
  import {
255
255
  RECALL_DISCLOSURE_LEVELS,
256
256
  isRecallDisclosure
257
- } from "./chunk-C43KEWEV.js";
257
+ } from "./chunk-TDZSSJV4.js";
258
258
  import {
259
259
  getCausalTrajectoryStoreStatus
260
260
  } from "./chunk-SSOMTUCA.js";
@@ -3288,6 +3288,68 @@ function registerCli(api, orchestrator, registerOptions = {}) {
3288
3288
  }
3289
3289
  console.log("\nOK");
3290
3290
  });
3291
+ namespacesCmd.command("rebuild").description(
3292
+ "Rebuild the namespace catalog from disk (issue #1499). Scans configured + dynamic namespace roots safely and rewrites <memoryDir>/state/namespaces.jsonl"
3293
+ ).option("--dry-run", "Show the rebuilt catalog without writing it").option("--apply", "Write the rebuilt catalog to disk").option("--json", "Emit the rebuild result as JSON").action(async (optionsRaw) => {
3294
+ const options = optionsRaw && typeof optionsRaw === "object" ? optionsRaw : {};
3295
+ if (options.dryRun === true && options.apply === true) {
3296
+ throw new Error("Pass only one of --dry-run or --apply, not both.");
3297
+ }
3298
+ const dryRun = options.apply !== true;
3299
+ if (!orchestrator.namespaceCatalog.enabled) {
3300
+ const note = "Namespace catalog is inert: it only runs when namespacesEnabled is true and namespaceCatalogEnabled is not false.";
3301
+ if (options.json === true) {
3302
+ console.log(
3303
+ JSON.stringify(
3304
+ { dryRun, enabled: false, applied: false, records: [], skipped: [], note },
3305
+ null,
3306
+ 2
3307
+ )
3308
+ );
3309
+ } else {
3310
+ console.log(note);
3311
+ }
3312
+ if (!dryRun) {
3313
+ process.exitCode = 1;
3314
+ }
3315
+ return;
3316
+ }
3317
+ const result = await orchestrator.namespaceCatalog.rebuildFromDisk({ dryRun });
3318
+ if (options.json === true) {
3319
+ console.log(JSON.stringify({ enabled: true, ...result }, null, 2));
3320
+ if (!dryRun && result.applied === false) {
3321
+ process.exitCode = 1;
3322
+ }
3323
+ return;
3324
+ }
3325
+ console.log("=== Namespace Catalog Rebuild ===\n");
3326
+ console.log(`mode: ${dryRun ? "dry-run" : "apply"}`);
3327
+ console.log(`namespaces: ${result.records.length}`);
3328
+ for (const record of result.records) {
3329
+ console.log(
3330
+ `${record.namespace}
3331
+ kind: ${record.kind}
3332
+ storage: ${record.storageDir}
3333
+ discovered-by: ${record.discoveredBy}`
3334
+ );
3335
+ }
3336
+ if (result.skipped.length > 0) {
3337
+ console.log("\nSkipped / ambiguous roots:");
3338
+ for (const skip of result.skipped) {
3339
+ console.log(`- ${skip.token} (${skip.reason})${skip.detail ? `: ${skip.detail}` : ""}`);
3340
+ }
3341
+ }
3342
+ if (dryRun) {
3343
+ console.log("\nDRY RUN");
3344
+ } else if (result.applied) {
3345
+ console.log("\nOK");
3346
+ } else {
3347
+ console.log(
3348
+ "\nNOT APPLIED: another rebuild holds the lock; the catalog was NOT rewritten. Retry shortly."
3349
+ );
3350
+ process.exitCode = 1;
3351
+ }
3352
+ });
3291
3353
  cmd.command("export").description("Export Remnic memory to JSON, Markdown bundle, or SQLite").option("--format <format>", "Export format: json|md|sqlite", "json").option("--out <path>", "Output path (dir for json/md, file for sqlite)").option("--include-transcripts", "Include transcripts in export (default: false)").option("--namespace <ns>", "Namespace to export (v3.0+, default: config defaultNamespace)", "").action(async (...args) => {
3292
3354
  const options = args[0] ?? {};
3293
3355
  const format = String(options.format ?? "json");
@@ -6478,7 +6540,7 @@ Semantic consolidation complete. clusters=${result.clustersFound}, consolidated=
6478
6540
  console.error("--verb is required. Must be one of: keep-a, keep-b, merge, both-valid, needs-more-context");
6479
6541
  process.exit(1);
6480
6542
  }
6481
- const { isValidResolutionVerb, executeResolution } = await import("./resolution-3SAP4SH2.js");
6543
+ const { isValidResolutionVerb, executeResolution } = await import("./resolution-IDTEBJFS.js");
6482
6544
  if (!isValidResolutionVerb(verb)) {
6483
6545
  console.error(`Invalid verb: ${verb}. Must be one of: keep-a, keep-b, merge, both-valid, needs-more-context`);
6484
6546
  process.exit(1);
@@ -6495,6 +6557,13 @@ Semantic consolidation complete. clusters=${result.clustersFound}, consolidated=
6495
6557
  return orchestrator.storage;
6496
6558
  }
6497
6559
  return orchestrator.getStorageForNamespace(requested || orchestrator.config.defaultNamespace);
6560
+ },
6561
+ // Catalog write touch (issue #1499 sweep): a contradiction merge can
6562
+ // write a new memory to a dynamic namespace via the CLI resolve path,
6563
+ // bypassing the extraction write path. Record it so QMD maintenance /
6564
+ // writtenSince don't miss the write. Best-effort and failure-tolerant.
6565
+ onMergedMemoryWritten: (namespace, storageDir) => {
6566
+ orchestrator.recordCatalogWrite(namespace, storageDir);
6498
6567
  }
6499
6568
  });
6500
6569
  console.log(result.message);
@@ -7212,4 +7281,4 @@ export {
7212
7281
  resolveMemoryDirForNamespace,
7213
7282
  registerCli
7214
7283
  };
7215
- //# sourceMappingURL=chunk-QQHIQ7JD.js.map
7284
+ //# sourceMappingURL=chunk-COVZLGMR.js.map