@remnic/core 9.3.725 → 9.3.726

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 (170) hide show
  1. package/dist/access-boundary.js +26 -25
  2. package/dist/access-cli.js +64 -62
  3. package/dist/access-cli.js.map +1 -1
  4. package/dist/access-http.js +33 -32
  5. package/dist/access-mcp.js +30 -29
  6. package/dist/access-operations-batch.js +27 -26
  7. package/dist/access-operations.js +29 -28
  8. package/dist/access-schema.js +3 -3
  9. package/dist/access-service.js +25 -24
  10. package/dist/active-recall.js +1 -1
  11. package/dist/adapters/index.js +4 -4
  12. package/dist/adapters/registry.js +2 -2
  13. package/dist/briefing.js +6 -5
  14. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-GWVG7LGC.js} +2 -2
  15. package/dist/causal-consolidation.js +7 -6
  16. package/dist/causal-consolidation.js.map +1 -1
  17. package/dist/{chunk-C6BWLYW5.js → chunk-2NBP25BG.js} +7 -7
  18. package/dist/{chunk-YUYPWJD3.js → chunk-3MS3QVX6.js} +2 -2
  19. package/dist/{chunk-FVZ2ISIX.js → chunk-3TUT4PWB.js} +2 -2
  20. package/dist/{chunk-HCVWF657.js → chunk-53EEQYE5.js} +7 -7
  21. package/dist/{chunk-TAPSNIMA.js → chunk-5CEJH5ZN.js} +4 -4
  22. package/dist/{chunk-D7EBTQ24.js → chunk-5NWYQUQC.js} +2 -2
  23. package/dist/{chunk-NT36GU6X.js → chunk-5OOA7SGX.js} +2 -2
  24. package/dist/{chunk-KQAFEZQX.js → chunk-5W7CTZ2E.js} +4 -4
  25. package/dist/{chunk-QR67FU5G.js → chunk-6AFVIOVZ.js} +2 -2
  26. package/dist/{chunk-UBHVAGO7.js → chunk-6WAJQKBS.js} +2 -2
  27. package/dist/{chunk-6CWGS2LY.js → chunk-7NS7AWMZ.js} +3 -3
  28. package/dist/{chunk-T55EGZSJ.js → chunk-BB57OZWC.js} +2 -2
  29. package/dist/{chunk-YQMPUYHE.js → chunk-BBIE7W52.js} +2 -2
  30. package/dist/{chunk-WAFDHKES.js → chunk-BEUCACTV.js} +2 -2
  31. package/dist/{chunk-4SF232E6.js → chunk-BIA7ELIB.js} +17 -5
  32. package/dist/chunk-BIA7ELIB.js.map +1 -0
  33. package/dist/{chunk-GZQXOQQ2.js → chunk-DCKNMLEQ.js} +4 -4
  34. package/dist/{chunk-ZUDM75KG.js → chunk-DCWIQFNA.js} +4 -4
  35. package/dist/{chunk-VI5SGGXB.js → chunk-DQXPJ6HD.js} +4 -4
  36. package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
  37. package/dist/{chunk-Z3FGC3QE.js → chunk-EZNDNMRH.js} +139 -30
  38. package/dist/chunk-EZNDNMRH.js.map +1 -0
  39. package/dist/{chunk-FACTVMXQ.js → chunk-FO3HO52S.js} +2 -2
  40. package/dist/{chunk-RKNJBZ55.js → chunk-JBPKEARU.js} +4 -4
  41. package/dist/{chunk-JJJCVCCQ.js → chunk-JPUT5NGH.js} +2 -2
  42. package/dist/{chunk-5OPYYPJN.js → chunk-K4ZNARDO.js} +2 -2
  43. package/dist/{chunk-4WZ3J7M6.js → chunk-KJR66XOM.js} +2 -2
  44. package/dist/{chunk-LD53WPMU.js → chunk-LQ6JI4VH.js} +4 -4
  45. package/dist/chunk-LTHVM4XN.js +109 -0
  46. package/dist/chunk-LTHVM4XN.js.map +1 -0
  47. package/dist/{chunk-4R3CGCI5.js → chunk-MQVKHFIU.js} +16 -13
  48. package/dist/chunk-MQVKHFIU.js.map +1 -0
  49. package/dist/{chunk-FXCIOLRB.js → chunk-NPL7VDM6.js} +2 -2
  50. package/dist/{chunk-KLFYKC3K.js → chunk-OAHOL3ZC.js} +112 -72
  51. package/dist/chunk-OAHOL3ZC.js.map +1 -0
  52. package/dist/{chunk-2NLLXCJG.js → chunk-OWHERGF2.js} +2 -2
  53. package/dist/{chunk-I2HL5M6T.js → chunk-PLG6JHQS.js} +42 -42
  54. package/dist/{chunk-KGZF2VO3.js → chunk-Q6D75LVH.js} +15 -15
  55. package/dist/{chunk-SC2YAWRF.js → chunk-RRHHQYJS.js} +2 -2
  56. package/dist/{chunk-J334N6QV.js → chunk-TA3Y6GEX.js} +2 -2
  57. package/dist/{chunk-FN6QP7JQ.js → chunk-TQQH2FTX.js} +4 -4
  58. package/dist/{chunk-DF3I6JGP.js → chunk-UKTDXTWX.js} +15 -15
  59. package/dist/{chunk-ARV3AUOM.js → chunk-UNNDFYUX.js} +5 -5
  60. package/dist/{chunk-ZK2L72VN.js → chunk-UQSVUEN2.js} +2 -2
  61. package/dist/{chunk-X7Y7WX73.js → chunk-UVYI6VIX.js} +1 -1
  62. package/dist/{chunk-H7HUQIY7.js → chunk-V7CMKMHM.js} +3 -3
  63. package/dist/chunk-W5H6ZRPT.js +14 -0
  64. package/dist/chunk-W5H6ZRPT.js.map +1 -0
  65. package/dist/{chunk-TT5U3UDO.js → chunk-WGTWGDR5.js} +5 -5
  66. package/dist/{chunk-YQGHW5ML.js → chunk-WRFKZEO6.js} +4 -4
  67. package/dist/{chunk-WM7DNKBD.js → chunk-YTZ3VGC7.js} +2 -2
  68. package/dist/cli.js +54 -53
  69. package/dist/compounding/engine.js +6 -5
  70. package/dist/config.js +1 -1
  71. package/dist/connectors/codex-materialize-runner.js +6 -5
  72. package/dist/connectors/index.js +6 -5
  73. package/dist/content-hash.d.ts +14 -0
  74. package/dist/content-hash.js +10 -0
  75. package/dist/content-hash.js.map +1 -0
  76. package/dist/conversation-index/backend.js +2 -2
  77. package/dist/dashboard-runtime.js +2 -2
  78. package/dist/entity-retrieval.js +6 -5
  79. package/dist/extraction-redaction-rules.d.ts +33 -0
  80. package/dist/extraction-redaction-rules.js +14 -0
  81. package/dist/extraction-redaction-rules.js.map +1 -0
  82. package/dist/extraction.js +2 -2
  83. package/dist/{forget-OEE5OELK.js → forget-WYLR4ZFV.js} +2 -2
  84. package/dist/index.js +102 -100
  85. package/dist/index.js.map +1 -1
  86. package/dist/lcm/index.js +3 -3
  87. package/dist/maintenance/memory-governance.js +6 -5
  88. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +6 -5
  89. package/dist/maintenance/rebuild-memory-projection.js +7 -6
  90. package/dist/namespaces/migrate.js +16 -15
  91. package/dist/namespaces/search.js +9 -9
  92. package/dist/namespaces/storage.js +6 -5
  93. package/dist/operator-toolkit.js +24 -23
  94. package/dist/orchestration/maintenance.js +8 -7
  95. package/dist/orchestrator.js +48 -46
  96. package/dist/resume-bundles.js +2 -2
  97. package/dist/search/factory.js +8 -8
  98. package/dist/search/index.js +12 -12
  99. package/dist/search/lancedb-backend.js +2 -2
  100. package/dist/search/meilisearch-backend.js +2 -2
  101. package/dist/search/orama-backend.js +2 -2
  102. package/dist/semantic-consolidation.js +7 -6
  103. package/dist/semantic-rule-promotion.js +6 -5
  104. package/dist/semantic-rule-verifier.js +6 -5
  105. package/dist/storage.d.ts +2 -2
  106. package/dist/storage.js +6 -5
  107. package/dist/transfer/backup.js +2 -2
  108. package/dist/transfer/capsule-export.js +2 -2
  109. package/dist/transfer/capsule-import.js +2 -2
  110. package/dist/verified-recall.js +6 -5
  111. package/package.json +2 -2
  112. package/src/config.test.ts +50 -0
  113. package/src/config.ts +21 -4
  114. package/src/content-hash.ts +24 -0
  115. package/src/correction/correction-access-wiring.ts +104 -19
  116. package/src/correction/correction-contract.ts +68 -10
  117. package/src/correction/correction-executor.test.ts +112 -2
  118. package/src/correction/correction-executor.ts +65 -5
  119. package/src/correction/correction-planner.test.ts +47 -0
  120. package/src/correction/correction-planner.ts +40 -1
  121. package/src/correction/correction-storage-integration.test.ts +183 -0
  122. package/src/extraction-redaction-rules.test.ts +213 -0
  123. package/src/extraction-redaction-rules.ts +208 -0
  124. package/src/orchestrator.ts +52 -1
  125. package/src/storage.ts +6 -10
  126. package/dist/chunk-4R3CGCI5.js.map +0 -1
  127. package/dist/chunk-4SF232E6.js.map +0 -1
  128. package/dist/chunk-KLFYKC3K.js.map +0 -1
  129. package/dist/chunk-Z3FGC3QE.js.map +0 -1
  130. /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-GWVG7LGC.js.map} +0 -0
  131. /package/dist/{chunk-C6BWLYW5.js.map → chunk-2NBP25BG.js.map} +0 -0
  132. /package/dist/{chunk-YUYPWJD3.js.map → chunk-3MS3QVX6.js.map} +0 -0
  133. /package/dist/{chunk-FVZ2ISIX.js.map → chunk-3TUT4PWB.js.map} +0 -0
  134. /package/dist/{chunk-HCVWF657.js.map → chunk-53EEQYE5.js.map} +0 -0
  135. /package/dist/{chunk-TAPSNIMA.js.map → chunk-5CEJH5ZN.js.map} +0 -0
  136. /package/dist/{chunk-D7EBTQ24.js.map → chunk-5NWYQUQC.js.map} +0 -0
  137. /package/dist/{chunk-NT36GU6X.js.map → chunk-5OOA7SGX.js.map} +0 -0
  138. /package/dist/{chunk-KQAFEZQX.js.map → chunk-5W7CTZ2E.js.map} +0 -0
  139. /package/dist/{chunk-QR67FU5G.js.map → chunk-6AFVIOVZ.js.map} +0 -0
  140. /package/dist/{chunk-UBHVAGO7.js.map → chunk-6WAJQKBS.js.map} +0 -0
  141. /package/dist/{chunk-6CWGS2LY.js.map → chunk-7NS7AWMZ.js.map} +0 -0
  142. /package/dist/{chunk-T55EGZSJ.js.map → chunk-BB57OZWC.js.map} +0 -0
  143. /package/dist/{chunk-YQMPUYHE.js.map → chunk-BBIE7W52.js.map} +0 -0
  144. /package/dist/{chunk-WAFDHKES.js.map → chunk-BEUCACTV.js.map} +0 -0
  145. /package/dist/{chunk-GZQXOQQ2.js.map → chunk-DCKNMLEQ.js.map} +0 -0
  146. /package/dist/{chunk-ZUDM75KG.js.map → chunk-DCWIQFNA.js.map} +0 -0
  147. /package/dist/{chunk-VI5SGGXB.js.map → chunk-DQXPJ6HD.js.map} +0 -0
  148. /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
  149. /package/dist/{chunk-FACTVMXQ.js.map → chunk-FO3HO52S.js.map} +0 -0
  150. /package/dist/{chunk-RKNJBZ55.js.map → chunk-JBPKEARU.js.map} +0 -0
  151. /package/dist/{chunk-JJJCVCCQ.js.map → chunk-JPUT5NGH.js.map} +0 -0
  152. /package/dist/{chunk-5OPYYPJN.js.map → chunk-K4ZNARDO.js.map} +0 -0
  153. /package/dist/{chunk-4WZ3J7M6.js.map → chunk-KJR66XOM.js.map} +0 -0
  154. /package/dist/{chunk-LD53WPMU.js.map → chunk-LQ6JI4VH.js.map} +0 -0
  155. /package/dist/{chunk-FXCIOLRB.js.map → chunk-NPL7VDM6.js.map} +0 -0
  156. /package/dist/{chunk-2NLLXCJG.js.map → chunk-OWHERGF2.js.map} +0 -0
  157. /package/dist/{chunk-I2HL5M6T.js.map → chunk-PLG6JHQS.js.map} +0 -0
  158. /package/dist/{chunk-KGZF2VO3.js.map → chunk-Q6D75LVH.js.map} +0 -0
  159. /package/dist/{chunk-SC2YAWRF.js.map → chunk-RRHHQYJS.js.map} +0 -0
  160. /package/dist/{chunk-J334N6QV.js.map → chunk-TA3Y6GEX.js.map} +0 -0
  161. /package/dist/{chunk-FN6QP7JQ.js.map → chunk-TQQH2FTX.js.map} +0 -0
  162. /package/dist/{chunk-DF3I6JGP.js.map → chunk-UKTDXTWX.js.map} +0 -0
  163. /package/dist/{chunk-ARV3AUOM.js.map → chunk-UNNDFYUX.js.map} +0 -0
  164. /package/dist/{chunk-ZK2L72VN.js.map → chunk-UQSVUEN2.js.map} +0 -0
  165. /package/dist/{chunk-X7Y7WX73.js.map → chunk-UVYI6VIX.js.map} +0 -0
  166. /package/dist/{chunk-H7HUQIY7.js.map → chunk-V7CMKMHM.js.map} +0 -0
  167. /package/dist/{chunk-TT5U3UDO.js.map → chunk-WGTWGDR5.js.map} +0 -0
  168. /package/dist/{chunk-YQGHW5ML.js.map → chunk-WRFKZEO6.js.map} +0 -0
  169. /package/dist/{chunk-WM7DNKBD.js.map → chunk-YTZ3VGC7.js.map} +0 -0
  170. /package/dist/{forget-OEE5OELK.js.map → forget-WYLR4ZFV.js.map} +0 -0
@@ -19,14 +19,14 @@ import {
19
19
  import {
20
20
  LocalLlmClient
21
21
  } from "./chunk-24D66MMN.js";
22
- import {
23
- delinearize
24
- } from "./chunk-VEWZZM3H.js";
25
22
  import {
26
23
  buildExtensionsFooterForSummary,
27
24
  formatDaySummaryMemories,
28
25
  loadDaySummaryPrompt
29
26
  } from "./chunk-EO5QWINU.js";
27
+ import {
28
+ delinearize
29
+ } from "./chunk-VEWZZM3H.js";
30
30
  import {
31
31
  applyWorkExtractionBoundary
32
32
  } from "./chunk-EI6V5UXY.js";
@@ -2422,4 +2422,4 @@ ${memoryList}` }
2422
2422
  export {
2423
2423
  ExtractionEngine
2424
2424
  };
2425
- //# sourceMappingURL=chunk-GZQXOQQ2.js.map
2425
+ //# sourceMappingURL=chunk-DCKNMLEQ.js.map
@@ -1,3 +1,6 @@
1
+ import {
2
+ failOpenFaissHealth
3
+ } from "./chunk-XBZQRZ6G.js";
1
4
  import {
2
5
  rebuildConversationChunksFailOpen,
3
6
  upsertConversationChunksFailOpen
@@ -6,9 +9,6 @@ import {
6
9
  searchConversationIndex,
7
10
  searchConversationIndexFaissFailOpen
8
11
  } from "./chunk-SJHM6I4J.js";
9
- import {
10
- failOpenFaissHealth
11
- } from "./chunk-XBZQRZ6G.js";
12
12
 
13
13
  // src/conversation-index/backend.ts
14
14
  function createConversationIndexBackend(options) {
@@ -235,4 +235,4 @@ function createFaissBackend(getFaiss) {
235
235
  export {
236
236
  createConversationIndexBackend
237
237
  };
238
- //# sourceMappingURL=chunk-ZUDM75KG.js.map
238
+ //# sourceMappingURL=chunk-DCWIQFNA.js.map
@@ -21,16 +21,16 @@ import {
21
21
  } from "./chunk-T4WDJPEZ.js";
22
22
  import {
23
23
  defineOperation
24
- } from "./chunk-NT36GU6X.js";
24
+ } from "./chunk-5OOA7SGX.js";
25
25
  import {
26
26
  EngramAccessInputError
27
- } from "./chunk-KGZF2VO3.js";
27
+ } from "./chunk-Q6D75LVH.js";
28
28
  import {
29
29
  projectTagProjectId
30
30
  } from "./chunk-J6BH2OBA.js";
31
31
  import {
32
32
  validateBriefingFormat
33
- } from "./chunk-4WZ3J7M6.js";
33
+ } from "./chunk-KJR66XOM.js";
34
34
  import {
35
35
  resolvePrincipal
36
36
  } from "./chunk-UZYLX7M6.js";
@@ -417,4 +417,4 @@ defineOperation({ name: "offline_sync_snapshot_stream", description: "SSE stream
417
417
  defineOperation({ name: "graph_events", description: "SSE graph events.", schema: strictSchema({}), handler: async (_i, _ctx) => ({ result: { stream: "sse" } }) });
418
418
  defineOperation({ name: "chat_message", description: "Chat message.", schema: strictSchema({ message: S.str, chatSessionId: S.str }), handler: async (_i, _ctx) => ({ result: { ok: true } }) });
419
419
  defineOperation({ name: "chat_events", description: "SSE chat events.", schema: strictSchema({}), handler: async (_i, _ctx) => ({ result: { stream: "sse" } }) });
420
- //# sourceMappingURL=chunk-VI5SGGXB.js.map
420
+ //# sourceMappingURL=chunk-DQXPJ6HD.js.map
@@ -1,9 +1,9 @@
1
- import {
2
- diffGraphSnapshots
3
- } from "./chunk-AUDJPF4N.js";
4
1
  import {
5
2
  graphSnapshotFromMemoryDir
6
3
  } from "./chunk-44442YCH.js";
4
+ import {
5
+ diffGraphSnapshots
6
+ } from "./chunk-AUDJPF4N.js";
7
7
 
8
8
  // src/dashboard-runtime.ts
9
9
  import { createHash, timingSafeEqual } from "crypto";
@@ -370,4 +370,4 @@ var GraphDashboardServer = class {
370
370
  export {
371
371
  GraphDashboardServer
372
372
  };
373
- //# sourceMappingURL=chunk-YNDLCWXS.js.map
373
+ //# sourceMappingURL=chunk-EZ25VE3G.js.map
@@ -1,12 +1,21 @@
1
1
  import {
2
2
  enqueuePassiveCorrectionNotification
3
- } from "./chunk-4WZ3J7M6.js";
3
+ } from "./chunk-KJR66XOM.js";
4
4
  import {
5
5
  stripAttributesSuffix
6
6
  } from "./chunk-SVOZFLIQ.js";
7
7
  import {
8
8
  serializeMutations
9
9
  } from "./chunk-LTJAMRGI.js";
10
+ import {
11
+ supersessionKeysForFact
12
+ } from "./chunk-TKZ3AL5V.js";
13
+ import {
14
+ computeContentHash
15
+ } from "./chunk-W5H6ZRPT.js";
16
+ import {
17
+ sanitizeMemoryContent
18
+ } from "./chunk-5GKPFL3S.js";
10
19
  import {
11
20
  log
12
21
  } from "./chunk-NU3CSQ4H.js";
@@ -79,22 +88,68 @@ function validateRedactionPattern(pattern) {
79
88
  `redaction_rule.pattern exceeds the ${REDACTION_PATTERN_MAX}-character bound.`
80
89
  );
81
90
  }
82
- if (isRegexLike(trimmed) && isOverlyBroadRegex(trimmed)) {
91
+ if (isRegexLike(trimmed) && isUnsafeRedactionRegex(trimmed)) {
83
92
  throw new CorrectionContractError(
84
- "redaction_rule.pattern is too broad \u2014 use a bounded literal or a more specific pattern."
93
+ "redaction_rule.pattern is unsafe \u2014 use a bounded literal or a regex without nested quantifiers / overlapping alternation."
85
94
  );
86
95
  }
96
+ if (isRegexLike(trimmed)) {
97
+ const regexBody = trimmed.slice(1, -1);
98
+ if (regexBody.length === 0) {
99
+ throw new CorrectionContractError("redaction_rule.pattern body is empty \u2014 use a non-empty regex.");
100
+ }
101
+ try {
102
+ if (new RegExp(regexBody).test("")) {
103
+ throw new CorrectionContractError(
104
+ "redaction_rule.pattern matches the empty string \u2014 it would withhold every fact."
105
+ );
106
+ }
107
+ } catch (e) {
108
+ if (e instanceof CorrectionContractError) throw e;
109
+ }
110
+ }
87
111
  return trimmed;
88
112
  }
89
113
  function isRegexLike(pattern) {
90
- if (pattern.startsWith("/") && pattern.endsWith("/") && pattern.length >= 2) return true;
91
- return /[\\^$.|?*+()[\]{}]/.test(pattern);
114
+ return pattern.startsWith("/") && pattern.endsWith("/") && pattern.length >= 2;
92
115
  }
93
- function isOverlyBroadRegex(pattern) {
116
+ function isUnsafeRedactionRegex(pattern) {
94
117
  const body = pattern.startsWith("/") && pattern.endsWith("/") ? pattern.slice(1, -1) : pattern;
95
118
  if (/(?:^|[^\\])\(\.\*\)|(?:^|[^\\])\.\*|(?:^|[^\\])\.\+|^\.([^*+]?)$/.test(body)) {
96
119
  return true;
97
120
  }
121
+ if (body.length > 512) return true;
122
+ for (let i = 0; i < body.length; i++) {
123
+ if (body[i] !== "(") continue;
124
+ let depth = 1;
125
+ let j = i + 1;
126
+ while (j < body.length && depth > 0) {
127
+ if (body[j] === "\\") {
128
+ j += 2;
129
+ continue;
130
+ }
131
+ if (body[j] === "(") depth++;
132
+ else if (body[j] === ")") depth--;
133
+ j++;
134
+ }
135
+ if (depth !== 0) continue;
136
+ const afterGroup = body[j];
137
+ if (afterGroup !== "+" && afterGroup !== "*" && afterGroup !== "{") continue;
138
+ const groupBody = body.slice(i + 1, j - 1);
139
+ if (/[+*?]$/.test(groupBody) || /\{\d+,?\d*\}[+*?]?$/.test(groupBody)) {
140
+ return true;
141
+ }
142
+ if (groupBody.includes("|")) {
143
+ const branches = groupBody.split("|");
144
+ if (branches.length >= 2) {
145
+ const firstChars = new Set(branches.map((b) => b[0]).filter(Boolean));
146
+ if (firstChars.size < branches.filter((b) => b.length > 0).length) {
147
+ return true;
148
+ }
149
+ }
150
+ }
151
+ i = j;
152
+ }
98
153
  return false;
99
154
  }
100
155
  function validateCorrectionAction(action) {
@@ -198,11 +253,13 @@ var CorrectionContractError = class extends Error {
198
253
 
199
254
  // src/correction/correction-access-wiring.ts
200
255
  import path2 from "path";
256
+ import { createHash } from "crypto";
201
257
  import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
202
258
 
203
259
  // src/correction/correction-planner.ts
204
260
  import { mkdir, readFile, rename, unlink, readdir, writeFile } from "fs/promises";
205
261
  import path from "path";
262
+ var REDACTED_REQUEST_TEXT = "[redacted \u2014 never-store/redaction correction text withheld from the pending-plan file]";
206
263
  var CorrectionPlanner = class {
207
264
  constructor(deps) {
208
265
  this.deps = deps;
@@ -386,10 +443,12 @@ var CorrectionPlanner = class {
386
443
  async persist(plan) {
387
444
  const dir = await this.pendingDir(plan.namespace);
388
445
  const target = path.join(dir, `${plan.planId}.json`);
446
+ const sensitive = plan.classification === "never_store" || plan.actions.some((a) => a.kind === "redaction_rule");
447
+ const persistedPlan = sensitive ? { ...plan, request: { ...plan.request, text: REDACTED_REQUEST_TEXT } } : plan;
389
448
  await serializeMutations(`correction-plan:${target}`, async () => {
390
449
  await mkdir(dir, { recursive: true });
391
450
  const tmp = `${target}.${process.pid}.${Date.now().toString(36)}.tmp`;
392
- await writeFile(tmp, `${JSON.stringify(plan)}
451
+ await writeFile(tmp, `${JSON.stringify(persistedPlan)}
393
452
  `, "utf-8");
394
453
  await rename(tmp, target);
395
454
  });
@@ -451,6 +510,11 @@ var CorrectionPlanner = class {
451
510
  const plan = parsePlan(raw);
452
511
  if (!plan) return;
453
512
  plan.status = status;
513
+ if (status !== "applying") {
514
+ plan.actions = plan.actions.map(
515
+ (a) => a.kind === "redaction_rule" ? { ...a, pattern: "[redacted \u2014 pattern applied]" } : a
516
+ );
517
+ }
454
518
  const tmp = `${file}.${process.pid}.${Date.now().toString(36)}.tmp`;
455
519
  await writeFile(tmp, `${JSON.stringify(plan)}
456
520
  `, "utf-8");
@@ -652,7 +716,7 @@ var CorrectionExecutor = class {
652
716
  continue;
653
717
  }
654
718
  const destId = await this.deps.rescopeMemory(namespace, action.memoryId, action.toNamespace);
655
- results.push({ action, status: "applied", memoryId: action.memoryId });
719
+ results.push({ action, status: "applied", memoryId: destId });
656
720
  appliedTouched.push(action.memoryId);
657
721
  try {
658
722
  await this.deps.propagate(action.toNamespace, [destId]);
@@ -726,7 +790,14 @@ var CorrectionExecutor = class {
726
790
  sourceMemoryId: memoryId,
727
791
  rawContent: memory.rawContent,
728
792
  ...memory.entityRef ? { entityRef: memory.entityRef } : {},
729
- ...memory.supersessionKey ? { supersessionKey: memory.supersessionKey } : {}
793
+ ...memory.supersessionKey ? { supersessionKey: memory.supersessionKey } : {},
794
+ // #1672 item 4: carry the canonical contentHash (exact tier) and the
795
+ // full supersession-key set (keyed tier) so paraphrased re-observations
796
+ // of the same supersession identity are blocked, not just the literal
797
+ // body. Without these the tombstone projected from a structured fact
798
+ // dropped both fields and the fact could resurrect.
799
+ ...memory.contentHash ? { contentHash: memory.contentHash } : {},
800
+ ...memory.supersessionKeys && memory.supersessionKeys.length > 0 ? { supersessionKeys: memory.supersessionKeys } : {}
730
801
  });
731
802
  await this.deps.retireMemory(namespace, memoryId, {
732
803
  status: reason === "supersession" ? "superseded" : "retracted",
@@ -745,9 +816,15 @@ var CorrectionExecutor = class {
745
816
  }
746
817
  }
747
818
  };
819
+ var CORRECTION_ERROR_MAX = 500;
820
+ function sanitizeErrorMessage(raw) {
821
+ const stripped = raw.replace(/(^|[\s:'"(])\/(?:[^\s'">)\\]+\/)+[^\s'">)\\]*/g, "$1<path>").replace(/(^|[\s:'"(])[A-Za-z]:\\[^\s'">)\\]+(?:\\[^\s'">) ]*)*/g, "$1<path>");
822
+ const trimmed = stripped.trim();
823
+ return trimmed.length > CORRECTION_ERROR_MAX ? `${trimmed.slice(0, CORRECTION_ERROR_MAX)}\u2026` : trimmed;
824
+ }
748
825
  function errMsg(err) {
749
- if (err instanceof Error) return err.message;
750
- return String(err);
826
+ const raw = err instanceof Error ? err.message : String(err);
827
+ return sanitizeErrorMessage(raw);
751
828
  }
752
829
 
753
830
  // src/correction/correction-service.ts
@@ -868,7 +945,7 @@ async function searchMemories(wiring, text, namespaces, limit) {
868
945
  const storage = await wiring.orchestrator.getStorage(ns);
869
946
  const all = await storage.readAllMemories();
870
947
  for (const m of all) {
871
- if (m.frontmatter.status && m.frontmatter.status !== "active") continue;
948
+ if (!isEligibleCorrectionCandidate(m)) continue;
872
949
  const hay = `${m.content} ${m.frontmatter.tags?.join(" ") ?? ""}`.toLowerCase();
873
950
  let hits = 0;
874
951
  for (const tok of tokens) {
@@ -1016,7 +1093,7 @@ async function expandEntityNeighbors(wiring, seedIds, namespaces, limit) {
1016
1093
  for (const m of all) {
1017
1094
  if (out.length >= limit) break;
1018
1095
  if (seen.has(m.frontmatter.id)) continue;
1019
- if (m.frontmatter.status && m.frontmatter.status !== "active") continue;
1096
+ if (!isEligibleCorrectionCandidate(m)) continue;
1020
1097
  if (m.frontmatter.entityRef && seedRefs.has(m.frontmatter.entityRef)) {
1021
1098
  out.push(toCandidate(m, ns, 0.5));
1022
1099
  seen.add(m.frontmatter.id);
@@ -1107,9 +1184,13 @@ async function applyEditMemory(wiring, namespace, memoryId, patch) {
1107
1184
  const storage = await wiring.orchestrator.getStorage(namespace);
1108
1185
  const existing = await storage.getMemoryById(memoryId);
1109
1186
  if (!existing) throw new CorrectionContractError(`memory not found for edit: ${memoryId}`);
1187
+ const contentHashForPatch = existing.frontmatter.category === "fact" ? computeContentHash(sanitizeMemoryContent(patch).text) : void 0;
1110
1188
  await storage.writeMemoryFrontmatter(
1111
1189
  { ...existing, content: patch },
1112
- { updated: (/* @__PURE__ */ new Date()).toISOString() }
1190
+ {
1191
+ updated: (/* @__PURE__ */ new Date()).toISOString(),
1192
+ ...contentHashForPatch ? { contentHash: contentHashForPatch } : {}
1193
+ }
1113
1194
  );
1114
1195
  return memoryId;
1115
1196
  }
@@ -1173,26 +1254,42 @@ async function rescopeMemoryFn(wiring, namespace, memoryId, toNamespace) {
1173
1254
  async function appendTombstoneFn(wiring, namespace, input) {
1174
1255
  const storage = await wiring.orchestrator.getStorage(namespace);
1175
1256
  const enabled = typeof storage.isTombstonesEnabled === "function" ? storage.isTombstonesEnabled() : true;
1176
- const result = await storage.appendTombstone({
1177
- reason: input.reason,
1178
- createdBy: "user_correction",
1179
- sourceMemoryId: input.sourceMemoryId,
1180
- rawContent: input.rawContent,
1181
- ...input.entityRef ? { entityRef: input.entityRef } : {},
1182
- ...input.supersessionKey ? { supersessionKey: input.supersessionKey } : {}
1183
- });
1184
- if (result === null && enabled) {
1185
- throw new CorrectionContractError(
1186
- `tombstone persistence failed for memory ${input.sourceMemoryId} (tombstones enabled but store returned null \u2014 I/O error swallowed)`
1187
- );
1257
+ const keys = input.supersessionKeys && input.supersessionKeys.length > 0 ? input.supersessionKeys : input.supersessionKey ? [input.supersessionKey] : [void 0];
1258
+ const writtenIds = [];
1259
+ let firstId = null;
1260
+ for (const key of keys) {
1261
+ const result = await storage.appendTombstone({
1262
+ reason: input.reason,
1263
+ createdBy: "user_correction",
1264
+ sourceMemoryId: input.sourceMemoryId,
1265
+ rawContent: input.rawContent,
1266
+ ...input.entityRef ? { entityRef: input.entityRef } : {},
1267
+ ...key ? { supersessionKey: key } : {},
1268
+ ...input.contentHash ? { contentHash: input.contentHash } : {}
1269
+ });
1270
+ if (result === null && enabled) {
1271
+ for (const id of writtenIds) {
1272
+ try {
1273
+ await storage.revokeTombstone(id, "user_correction");
1274
+ } catch {
1275
+ }
1276
+ }
1277
+ throw new CorrectionContractError(
1278
+ `tombstone persistence failed for memory ${input.sourceMemoryId} (tombstones enabled but store returned null \u2014 I/O error swallowed)`
1279
+ );
1280
+ }
1281
+ if (firstId === null) firstId = result;
1282
+ if (result) writtenIds.push(result);
1188
1283
  }
1189
- return result;
1284
+ return firstId;
1190
1285
  }
1191
1286
  async function registerRedactionRuleFn(wiring, namespace, pattern) {
1192
1287
  const storage = await wiring.orchestrator.getStorage(namespace);
1193
1288
  const dir = path2.join(storage.dir, "state", "corrections", "redaction-rules");
1194
1289
  await mkdir2(dir, { recursive: true });
1195
- const slug = pattern.replace(/[^a-zA-Z0-9]+/g, "-").slice(0, 64) || "rule";
1290
+ const slugBase = pattern.replace(/[^a-zA-Z0-9]+/g, "-").slice(0, 48) || "rule";
1291
+ const patternHash = createHash("sha256").update(pattern).digest("hex").slice(0, 16);
1292
+ const slug = `${slugBase}-${patternHash}`;
1196
1293
  await writeFile2(
1197
1294
  path2.join(dir, `${slug}.json`),
1198
1295
  `${JSON.stringify({ pattern, namespace, createdAt: (/* @__PURE__ */ new Date()).toISOString() })}
@@ -1252,15 +1349,27 @@ function toCandidate(m, namespace, score) {
1252
1349
  // candidate for diff rendering if needed.
1253
1350
  };
1254
1351
  }
1352
+ function isEligibleCorrectionCandidate(m) {
1353
+ if (m.frontmatter.status && m.frontmatter.status !== "active") return false;
1354
+ if (typeof m.frontmatter.archivedAt === "string" && m.frontmatter.archivedAt.length > 0) return false;
1355
+ return true;
1356
+ }
1255
1357
  function toExecutorMemory(m) {
1256
1358
  const fm = m.frontmatter;
1257
1359
  const rawBody = fm.structuredAttributes ? stripAttributesSuffix(m.content) : m.content;
1360
+ const supersessionKeys = supersessionKeysForFact({
1361
+ entityRef: fm.entityRef,
1362
+ structuredAttributes: fm.structuredAttributes
1363
+ });
1258
1364
  return {
1259
1365
  memoryId: fm.id,
1260
1366
  content: m.content,
1261
1367
  category: fm.category,
1262
1368
  rawContent: rawBody,
1263
- ...fm.entityRef ? { entityRef: fm.entityRef } : {}
1369
+ ...fm.entityRef ? { entityRef: fm.entityRef } : {},
1370
+ ...supersessionKeys.length > 0 ? { supersessionKeys } : {},
1371
+ ...supersessionKeys.length > 0 ? { supersessionKey: supersessionKeys[0] } : {},
1372
+ ...typeof fm.contentHash === "string" && fm.contentHash.length > 0 ? { contentHash: fm.contentHash } : {}
1264
1373
  };
1265
1374
  }
1266
1375
  function isCorrectionFeatureEnabled(config) {
@@ -1685,4 +1794,4 @@ export {
1685
1794
  capturePassiveCorrections,
1686
1795
  clusterByKey
1687
1796
  };
1688
- //# sourceMappingURL=chunk-Z3FGC3QE.js.map
1797
+ //# sourceMappingURL=chunk-EZNDNMRH.js.map