@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
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  LanceDbBackend
3
- } from "../chunk-TAPSNIMA.js";
4
- import "../chunk-CINZGPSJ.js";
3
+ } from "../chunk-5CEJH5ZN.js";
5
4
  import "../chunk-AER6MT24.js";
5
+ import "../chunk-CINZGPSJ.js";
6
6
  import "../chunk-YNQ6DFSV.js";
7
7
  import "../chunk-5GPPACXK.js";
8
8
  import "../chunk-VS2IYZRU.js";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  MeilisearchBackend
3
- } from "../chunk-YQGHW5ML.js";
4
- import "../chunk-CINZGPSJ.js";
3
+ } from "../chunk-WRFKZEO6.js";
5
4
  import "../chunk-AER6MT24.js";
5
+ import "../chunk-CINZGPSJ.js";
6
6
  import "../chunk-YNQ6DFSV.js";
7
7
  import "../chunk-5GPPACXK.js";
8
8
  import "../chunk-VS2IYZRU.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  OramaBackend,
3
3
  resolveOramaCollectionDbFilePath
4
- } from "../chunk-LD53WPMU.js";
5
- import "../chunk-CINZGPSJ.js";
4
+ } from "../chunk-LQ6JI4VH.js";
6
5
  import "../chunk-AER6MT24.js";
6
+ import "../chunk-CINZGPSJ.js";
7
7
  import "../chunk-YNQ6DFSV.js";
8
8
  import "../chunk-5GPPACXK.js";
9
9
  import "../chunk-VS2IYZRU.js";
@@ -7,24 +7,24 @@ import {
7
7
  materializeAfterSemanticConsolidation,
8
8
  parseConsolidationResponse,
9
9
  parseOperatorAwareConsolidationResponse
10
- } from "./chunk-JJJCVCCQ.js";
11
- import "./chunk-ZK2L72VN.js";
10
+ } from "./chunk-JPUT5NGH.js";
11
+ import "./chunk-UQSVUEN2.js";
12
12
  import "./chunk-UUH4YQOF.js";
13
13
  import {
14
14
  resolveExtensionsRoot
15
15
  } from "./chunk-JLNBQWZ2.js";
16
16
  import "./chunk-3UXOZBHV.js";
17
17
  import "./chunk-ZBJMUXZH.js";
18
- import "./chunk-4R3CGCI5.js";
19
- import "./chunk-L2B3EE7B.js";
18
+ import "./chunk-MQVKHFIU.js";
20
19
  import "./chunk-M7XQSUBB.js";
20
+ import "./chunk-L2B3EE7B.js";
21
21
  import "./chunk-5UZXUTVO.js";
22
22
  import "./chunk-5GPPACXK.js";
23
+ import "./chunk-SVOZFLIQ.js";
24
+ import "./chunk-LTJAMRGI.js";
23
25
  import "./chunk-TKZ3AL5V.js";
24
26
  import "./chunk-6CIAGZ6X.js";
25
27
  import "./chunk-J6A3CX5N.js";
26
- import "./chunk-SVOZFLIQ.js";
27
- import "./chunk-LTJAMRGI.js";
28
28
  import "./chunk-7AG54AF3.js";
29
29
  import "./chunk-AWJ2FHCF.js";
30
30
  import "./chunk-42JKGUFJ.js";
@@ -43,6 +43,7 @@ import {
43
43
  isValidDerivedFromEntry
44
44
  } from "./chunk-G7D6GZ5J.js";
45
45
  import "./chunk-VF4XKTX3.js";
46
+ import "./chunk-W5H6ZRPT.js";
46
47
  import "./chunk-VUA4S7P6.js";
47
48
  import "./chunk-IQVQJJL7.js";
48
49
  import "./chunk-L2EXJQJP.js";
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  promoteSemanticRuleFromMemory,
3
3
  setSemanticRulePromotionTestHooks
4
- } from "./chunk-FACTVMXQ.js";
5
- import "./chunk-4R3CGCI5.js";
6
- import "./chunk-L2B3EE7B.js";
4
+ } from "./chunk-FO3HO52S.js";
5
+ import "./chunk-MQVKHFIU.js";
7
6
  import "./chunk-M7XQSUBB.js";
7
+ import "./chunk-L2B3EE7B.js";
8
8
  import "./chunk-5UZXUTVO.js";
9
9
  import "./chunk-5GPPACXK.js";
10
+ import "./chunk-SVOZFLIQ.js";
11
+ import "./chunk-LTJAMRGI.js";
10
12
  import "./chunk-TKZ3AL5V.js";
11
13
  import "./chunk-6CIAGZ6X.js";
12
14
  import "./chunk-J6A3CX5N.js";
13
- import "./chunk-SVOZFLIQ.js";
14
- import "./chunk-LTJAMRGI.js";
15
15
  import "./chunk-7AG54AF3.js";
16
16
  import "./chunk-AWJ2FHCF.js";
17
17
  import "./chunk-42JKGUFJ.js";
@@ -25,6 +25,7 @@ import "./chunk-6OIDDKAA.js";
25
25
  import "./chunk-XGTBNVIU.js";
26
26
  import "./chunk-G7D6GZ5J.js";
27
27
  import "./chunk-VF4XKTX3.js";
28
+ import "./chunk-W5H6ZRPT.js";
28
29
  import "./chunk-VUA4S7P6.js";
29
30
  import "./chunk-IQVQJJL7.js";
30
31
  import "./chunk-L2EXJQJP.js";
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  compareVerifiedSemanticRuleResults,
3
3
  searchVerifiedSemanticRules
4
- } from "./chunk-T55EGZSJ.js";
4
+ } from "./chunk-BB57OZWC.js";
5
5
  import "./chunk-ZBJMUXZH.js";
6
- import "./chunk-4R3CGCI5.js";
7
- import "./chunk-L2B3EE7B.js";
6
+ import "./chunk-MQVKHFIU.js";
8
7
  import "./chunk-M7XQSUBB.js";
8
+ import "./chunk-L2B3EE7B.js";
9
9
  import "./chunk-5UZXUTVO.js";
10
10
  import "./chunk-5GPPACXK.js";
11
+ import "./chunk-SVOZFLIQ.js";
12
+ import "./chunk-LTJAMRGI.js";
11
13
  import "./chunk-TKZ3AL5V.js";
12
14
  import "./chunk-6CIAGZ6X.js";
13
15
  import "./chunk-J6A3CX5N.js";
14
- import "./chunk-SVOZFLIQ.js";
15
- import "./chunk-LTJAMRGI.js";
16
16
  import "./chunk-7AG54AF3.js";
17
17
  import "./chunk-AWJ2FHCF.js";
18
18
  import "./chunk-42JKGUFJ.js";
@@ -26,6 +26,7 @@ import "./chunk-6OIDDKAA.js";
26
26
  import "./chunk-XGTBNVIU.js";
27
27
  import "./chunk-G7D6GZ5J.js";
28
28
  import "./chunk-VF4XKTX3.js";
29
+ import "./chunk-W5H6ZRPT.js";
29
30
  import "./chunk-VUA4S7P6.js";
30
31
  import "./chunk-IQVQJJL7.js";
31
32
  import "./chunk-L2EXJQJP.js";
package/dist/storage.d.ts CHANGED
@@ -351,9 +351,9 @@ declare class ContentHashIndex {
351
351
  * Not part of the public API — prefer `add(content)` for external callers.
352
352
  */
353
353
  addByHash(hash: string): void;
354
- /** Normalize content and compute SHA-256 hash. */
354
+ /** Normalize content (delegates to content-hash.ts for a single source of truth). */
355
355
  static normalizeContent(content: string): string;
356
- /** Normalize content and compute SHA-256 hash. */
356
+ /** Compute SHA-256 hash (delegates to content-hash.ts for a single source of truth). */
357
357
  static computeHash(content: string): string;
358
358
  }
359
359
 
package/dist/storage.js CHANGED
@@ -8,18 +8,18 @@ import {
8
8
  normalizeEntityName,
9
9
  parseEntityFile,
10
10
  serializeEntityFile
11
- } from "./chunk-4R3CGCI5.js";
12
- import "./chunk-L2B3EE7B.js";
11
+ } from "./chunk-MQVKHFIU.js";
13
12
  import "./chunk-M7XQSUBB.js";
13
+ import "./chunk-L2B3EE7B.js";
14
14
  import "./chunk-5UZXUTVO.js";
15
15
  import "./chunk-5GPPACXK.js";
16
- import "./chunk-TKZ3AL5V.js";
17
- import "./chunk-6CIAGZ6X.js";
18
- import "./chunk-J6A3CX5N.js";
19
16
  import {
20
17
  stripAttributesSuffix
21
18
  } from "./chunk-SVOZFLIQ.js";
22
19
  import "./chunk-LTJAMRGI.js";
20
+ import "./chunk-TKZ3AL5V.js";
21
+ import "./chunk-6CIAGZ6X.js";
22
+ import "./chunk-J6A3CX5N.js";
23
23
  import "./chunk-7AG54AF3.js";
24
24
  import "./chunk-AWJ2FHCF.js";
25
25
  import "./chunk-42JKGUFJ.js";
@@ -33,6 +33,7 @@ import "./chunk-6OIDDKAA.js";
33
33
  import "./chunk-XGTBNVIU.js";
34
34
  import "./chunk-G7D6GZ5J.js";
35
35
  import "./chunk-VF4XKTX3.js";
36
+ import "./chunk-W5H6ZRPT.js";
36
37
  import "./chunk-VUA4S7P6.js";
37
38
  import "./chunk-IQVQJJL7.js";
38
39
  import "./chunk-L2EXJQJP.js";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  backupMemoryDir
3
- } from "../chunk-2NLLXCJG.js";
3
+ } from "../chunk-OWHERGF2.js";
4
4
  import "../chunk-765K3SAT.js";
5
- import "../chunk-X7Y7WX73.js";
5
+ import "../chunk-UVYI6VIX.js";
6
6
  import "../chunk-J4EB7DNW.js";
7
7
  import "../chunk-UI3NYK34.js";
8
8
  import "../chunk-GCGJW34D.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  exportCapsule,
3
3
  isValidCapsuleSince
4
- } from "../chunk-KQAFEZQX.js";
4
+ } from "../chunk-5W7CTZ2E.js";
5
+ import "../chunk-UVYI6VIX.js";
5
6
  import "../chunk-WEHSQBFR.js";
6
- import "../chunk-X7Y7WX73.js";
7
7
  import "../chunk-J4EB7DNW.js";
8
8
  import "../chunk-UI3NYK34.js";
9
9
  import "../chunk-GCGJW34D.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  importCapsule
3
- } from "../chunk-ARV3AUOM.js";
3
+ } from "../chunk-UNNDFYUX.js";
4
4
  import "../chunk-VF4XKTX3.js";
5
+ import "../chunk-UVYI6VIX.js";
5
6
  import "../chunk-WEHSQBFR.js";
6
- import "../chunk-X7Y7WX73.js";
7
7
  import "../chunk-GCGJW34D.js";
8
8
  import "../chunk-BJMBJZ2Y.js";
9
9
  import "../chunk-UKJAGEXH.js";
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  compareVerifiedEpisodeResults,
3
3
  searchVerifiedEpisodes
4
- } from "./chunk-FXCIOLRB.js";
4
+ } from "./chunk-NPL7VDM6.js";
5
5
  import "./chunk-7FL4CNPV.js";
6
6
  import "./chunk-ZBJMUXZH.js";
7
- import "./chunk-4R3CGCI5.js";
8
- import "./chunk-L2B3EE7B.js";
7
+ import "./chunk-MQVKHFIU.js";
9
8
  import "./chunk-M7XQSUBB.js";
9
+ import "./chunk-L2B3EE7B.js";
10
10
  import "./chunk-5UZXUTVO.js";
11
11
  import "./chunk-5GPPACXK.js";
12
+ import "./chunk-SVOZFLIQ.js";
13
+ import "./chunk-LTJAMRGI.js";
12
14
  import "./chunk-TKZ3AL5V.js";
13
15
  import "./chunk-6CIAGZ6X.js";
14
16
  import "./chunk-J6A3CX5N.js";
15
- import "./chunk-SVOZFLIQ.js";
16
- import "./chunk-LTJAMRGI.js";
17
17
  import "./chunk-7AG54AF3.js";
18
18
  import "./chunk-AWJ2FHCF.js";
19
19
  import "./chunk-42JKGUFJ.js";
@@ -27,6 +27,7 @@ import "./chunk-6OIDDKAA.js";
27
27
  import "./chunk-XGTBNVIU.js";
28
28
  import "./chunk-G7D6GZ5J.js";
29
29
  import "./chunk-VF4XKTX3.js";
30
+ import "./chunk-W5H6ZRPT.js";
30
31
  import "./chunk-VUA4S7P6.js";
31
32
  import "./chunk-IQVQJJL7.js";
32
33
  import "./chunk-L2EXJQJP.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "9.3.725",
3
+ "version": "9.3.726",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -2966,7 +2966,7 @@
2966
2966
  "core"
2967
2967
  ],
2968
2968
  "peerDependencies": {
2969
- "@remnic/coding-graph": "^9.3.725"
2969
+ "@remnic/coding-graph": "^9.3.726"
2970
2970
  },
2971
2971
  "peerDependenciesMeta": {
2972
2972
  "@remnic/coding-graph": {
@@ -2092,3 +2092,53 @@ test("parseConfig rejects invalid correction.enabled instead of silently enablin
2092
2092
  assert.equal(parseConfig({ correctionEnabled: "0" }).correctionEnabled, false);
2093
2093
  assert.equal(parseConfig({}).correctionEnabled, true);
2094
2094
  });
2095
+
2096
+ test("parseConfig rejects invalid correction.planTtlHours instead of silently defaulting (#1678)", () => {
2097
+ // Nested form: correction.planTtlHours.
2098
+ for (const value of [0, -1, 0.5, "0", "-5", "abc", true, null]) {
2099
+ assert.throws(
2100
+ () => parseConfig({ correction: { planTtlHours: value } } as Record<string, unknown>),
2101
+ /Invalid correction\.planTtlHours/,
2102
+ `nested planTtlHours=${JSON.stringify(value)} should throw`,
2103
+ );
2104
+ }
2105
+ // Flat form: correctionPlanTtlHours.
2106
+ for (const value of [0, -3, "abc", true]) {
2107
+ assert.throws(
2108
+ () => parseConfig({ correctionPlanTtlHours: value } as Record<string, unknown>),
2109
+ /Invalid correction\.planTtlHours/,
2110
+ `flat correctionPlanTtlHours=${JSON.stringify(value)} should throw`,
2111
+ );
2112
+ }
2113
+ // Valid values resolve (no regression on the happy path).
2114
+ assert.equal(parseConfig({ correction: { planTtlHours: 48 } }).correctionPlanTtlHours, 48);
2115
+ assert.equal(parseConfig({ correctionPlanTtlHours: 12 }).correctionPlanTtlHours, 12);
2116
+ assert.equal(parseConfig({}).correctionPlanTtlHours, 24, "absent → documented default");
2117
+ });
2118
+
2119
+ test("parseConfig correction.maxAffected rejects non-integers (Number.isInteger, #1678)", () => {
2120
+ // The error message says "integer" — 3.7 must be rejected, not silently floored to 3.
2121
+ for (const value of [3.7, 2.5, "1.5", 0.99]) {
2122
+ assert.throws(
2123
+ () => parseConfig({ correction: { maxAffected: value } } as Record<string, unknown>),
2124
+ /Invalid correction\.maxAffected/,
2125
+ `maxAffected=${JSON.stringify(value)} should throw (non-integer)`,
2126
+ );
2127
+ }
2128
+ for (const value of [0, -1, "abc"]) {
2129
+ assert.throws(
2130
+ () => parseConfig({ correction: { maxAffected: value } } as Record<string, unknown>),
2131
+ /Invalid correction\.maxAffected/,
2132
+ `maxAffected=${JSON.stringify(value)} should throw`,
2133
+ );
2134
+ }
2135
+ // Flat form.
2136
+ assert.throws(
2137
+ () => parseConfig({ correctionMaxAffected: 4.2 } as Record<string, unknown>),
2138
+ /Invalid correction\.maxAffected/,
2139
+ );
2140
+ // Valid integers resolve.
2141
+ assert.equal(parseConfig({ correction: { maxAffected: 5 } }).correctionMaxAffected, 5);
2142
+ assert.equal(parseConfig({ correctionMaxAffected: 20 }).correctionMaxAffected, 20);
2143
+ assert.equal(parseConfig({}).correctionMaxAffected, 10, "absent → documented default");
2144
+ });
package/src/config.ts CHANGED
@@ -2130,17 +2130,34 @@ export function parseConfig(
2130
2130
  const raw = rawNested !== undefined ? rawNested : cfg.correctionMaxAffected;
2131
2131
  if (raw === undefined || raw === null) return 10;
2132
2132
  const n = coerceNumber(raw);
2133
- if (n === undefined || !Number.isFinite(n) || n < 1) {
2133
+ // #1678 (thread Oiup6): the error message says "integer" enforce it
2134
+ // with Number.isInteger so 3.7 is rejected rather than silently floored.
2135
+ if (n === undefined || !Number.isFinite(n) || n < 1 || !Number.isInteger(n)) {
2134
2136
  throw new Error(`Invalid correction.maxAffected: expected an integer >= 1, got ${JSON.stringify(raw)}`);
2135
2137
  }
2136
- return Math.floor(n);
2138
+ return n;
2137
2139
  })(),
2138
2140
  correctionPlanTtlHours: (() => {
2139
2141
  const nested = (cfg.correction as Record<string, unknown> | undefined)?.planTtlHours;
2140
2142
  const fromNested = nested !== undefined ? coerceNumber(nested) : undefined;
2141
- if (fromNested !== undefined && fromNested > 0) return fromNested;
2143
+ if (fromNested !== undefined && fromNested >= 1) return fromNested;
2144
+ // #1678 (threads Ohtvi/Ohyvf): reject invalid (0/negative/non-numeric)
2145
+ // instead of silently defaulting to 24h — completes the config-reject
2146
+ // class already enforced for enabled/applyRequiresConfirm/maxAffected.
2147
+ if (nested !== undefined && fromNested === undefined) {
2148
+ throw new Error(`Invalid correction.planTtlHours: expected a number >= 1, got ${JSON.stringify(nested)}`);
2149
+ }
2150
+ if (fromNested !== undefined && fromNested < 1) {
2151
+ throw new Error(`Invalid correction.planTtlHours: expected a number >= 1, got ${JSON.stringify(nested)}`);
2152
+ }
2142
2153
  const fromFlat = coerceNumber(cfg.correctionPlanTtlHours);
2143
- if (fromFlat !== undefined && fromFlat > 0) return fromFlat;
2154
+ if (fromFlat !== undefined && fromFlat >= 1) return fromFlat;
2155
+ if (cfg.correctionPlanTtlHours !== undefined && fromFlat === undefined) {
2156
+ throw new Error(`Invalid correction.planTtlHours: expected a number >= 1, got ${JSON.stringify(cfg.correctionPlanTtlHours)}`);
2157
+ }
2158
+ if (fromFlat !== undefined && fromFlat < 1) {
2159
+ throw new Error(`Invalid correction.planTtlHours: expected a number >= 1, got ${JSON.stringify(cfg.correctionPlanTtlHours)}`);
2160
+ }
2144
2161
  return 24;
2145
2162
  })(),
2146
2163
  // Passive correction capture (issue #1581). Parsed from
@@ -0,0 +1,24 @@
1
+ /**
2
+ * content-hash.ts — standalone content normalization + SHA-256 hashing.
3
+ *
4
+ * Extracted from `ContentHashIndex` (storage.ts) so correction modules and
5
+ * other consumers can hash content WITHOUT importing the storage god file
6
+ * (issue #1533 directStorageImports ratchet). The static methods on
7
+ * `ContentHashIndex` delegate here to guarantee identical results.
8
+ */
9
+
10
+ import { createHash } from "node:crypto";
11
+
12
+ /** Normalize content: lowercase, strip non-alphanumerics, collapse whitespace. */
13
+ export function normalizeContent(content: string): string {
14
+ return content
15
+ .toLowerCase()
16
+ .replace(/[^a-z0-9\s]/g, " ")
17
+ .replace(/\s+/g, " ")
18
+ .trim();
19
+ }
20
+
21
+ /** Normalize content and compute SHA-256 hash. */
22
+ export function computeContentHash(content: string): string {
23
+ return createHash("sha256").update(normalizeContent(content)).digest("hex");
24
+ }
@@ -21,10 +21,14 @@
21
21
  */
22
22
 
23
23
  import path from "node:path";
24
+ import { createHash } from "node:crypto";
24
25
  import { mkdir, writeFile } from "node:fs/promises";
25
26
  import type { Orchestrator } from "../orchestrator.js";
26
27
  import type { MemoryFile, MemoryStatus, PluginConfig } from "../types.js";
27
28
  import { stripAttributesSuffix } from "../structured-attributes.js";
29
+ import { supersessionKeysForFact } from "../temporal-supersession.js";
30
+ import { computeContentHash } from "../content-hash.js";
31
+ import { sanitizeMemoryContent } from "../sanitize.js";
28
32
  import {
29
33
  CorrectionContractError,
30
34
  validateCorrectionAction,
@@ -168,7 +172,7 @@ async function searchMemories(
168
172
  const storage = await wiring.orchestrator.getStorage(ns);
169
173
  const all = await storage.readAllMemories();
170
174
  for (const m of all) {
171
- if (m.frontmatter.status && m.frontmatter.status !== "active") continue;
175
+ if (!isEligibleCorrectionCandidate(m)) continue;
172
176
  const hay = `${m.content} ${m.frontmatter.tags?.join(" ") ?? ""}`.toLowerCase();
173
177
  let hits = 0;
174
178
  for (const tok of tokens) {
@@ -265,7 +269,7 @@ async function expandEntityNeighbors(
265
269
  for (const m of all) {
266
270
  if (out.length >= limit) break;
267
271
  if (seen.has(m.frontmatter.id)) continue;
268
- if (m.frontmatter.status && m.frontmatter.status !== "active") continue;
272
+ if (!isEligibleCorrectionCandidate(m)) continue;
269
273
  if (m.frontmatter.entityRef && seedRefs.has(m.frontmatter.entityRef)) {
270
274
  out.push(toCandidate(m, ns, 0.5));
271
275
  seen.add(m.frontmatter.id);
@@ -427,9 +431,22 @@ async function applyEditMemory(
427
431
  // The StorageManager's writeMemoryFrontmatter snapshots the prior version
428
432
  // internally when page-versioning is configured (issue #371), so every edit
429
433
  // is revertable without the correction layer forking versioning logic.
434
+ //
435
+ // #1672 item 3: recompute the contentHash from the patched body so the
436
+ // dedup index + tombstone exact tier match the NEW content. writeMemory
437
+ // computes this at write time, but writeMemoryFrontmatter preserves the
438
+ // prior frontmatter hash — without this the hash no longer matches the
439
+ // patched body and a later re-extraction of the same fact dedup-misses.
440
+ const contentHashForPatch =
441
+ existing.frontmatter.category === "fact"
442
+ ? computeContentHash(sanitizeMemoryContent(patch).text)
443
+ : undefined;
430
444
  await storage.writeMemoryFrontmatter(
431
445
  { ...existing, content: patch },
432
- { updated: new Date().toISOString() },
446
+ {
447
+ updated: new Date().toISOString(),
448
+ ...(contentHashForPatch ? { contentHash: contentHashForPatch } : {}),
449
+ },
433
450
  );
434
451
  return memoryId;
435
452
  }
@@ -535,6 +552,8 @@ async function appendTombstoneFn(
535
552
  rawContent: string;
536
553
  entityRef?: string;
537
554
  supersessionKey?: string;
555
+ supersessionKeys?: string[];
556
+ contentHash?: string;
538
557
  },
539
558
  ): Promise<string | null> {
540
559
  const storage = await wiring.orchestrator.getStorage(namespace);
@@ -550,20 +569,46 @@ async function appendTombstoneFn(
550
569
  typeof storage.isTombstonesEnabled === "function"
551
570
  ? storage.isTombstonesEnabled()
552
571
  : true;
553
- const result = await storage.appendTombstone({
554
- reason: input.reason,
555
- createdBy: "user_correction",
556
- sourceMemoryId: input.sourceMemoryId,
557
- rawContent: input.rawContent,
558
- ...(input.entityRef ? { entityRef: input.entityRef } : {}),
559
- ...(input.supersessionKey ? { supersessionKey: input.supersessionKey } : {}),
560
- });
561
- if (result === null && enabled) {
562
- throw new CorrectionContractError(
563
- `tombstone persistence failed for memory ${input.sourceMemoryId} (tombstones enabled but store returned null — I/O error swallowed)`,
564
- );
572
+ // #1672 item 4: emit one tombstone per derived supersession key (mirrors
573
+ // temporal-supersession / forget / pattern-reinforcement) so a paraphrased
574
+ // re-observation placing the attribute at a different key position is still
575
+ // blocked at the keyed tier. When no keys are derived, emit a single
576
+ // content-only tombstone. Each carries the canonical contentHash so the
577
+ // exact tier also matches re-extraction.
578
+ const keys =
579
+ input.supersessionKeys && input.supersessionKeys.length > 0
580
+ ? input.supersessionKeys
581
+ : input.supersessionKey
582
+ ? [input.supersessionKey]
583
+ : [undefined];
584
+ const writtenIds: string[] = [];
585
+ let firstId: string | null = null;
586
+ for (const key of keys) {
587
+ const result = await storage.appendTombstone({
588
+ reason: input.reason,
589
+ createdBy: "user_correction",
590
+ sourceMemoryId: input.sourceMemoryId,
591
+ rawContent: input.rawContent,
592
+ ...(input.entityRef ? { entityRef: input.entityRef } : {}),
593
+ ...(key ? { supersessionKey: key } : {}),
594
+ ...(input.contentHash ? { contentHash: input.contentHash } : {}),
595
+ });
596
+ if (result === null && enabled) {
597
+ // Rollback already-written tombstones so a partial multi-key failure
598
+ // does not leave incomplete resurrection blocking for the still-active
599
+ // memory (review thread #1). Best-effort — a dangling tombstone is the
600
+ // safer failure mode (false-positive block vs. false-negative leak).
601
+ for (const id of writtenIds) {
602
+ try { await storage.revokeTombstone(id, "user_correction"); } catch { /* best-effort */ }
603
+ }
604
+ throw new CorrectionContractError(
605
+ `tombstone persistence failed for memory ${input.sourceMemoryId} (tombstones enabled but store returned null — I/O error swallowed)`,
606
+ );
607
+ }
608
+ if (firstId === null) firstId = result;
609
+ if (result) writtenIds.push(result);
565
610
  }
566
- return result;
611
+ return firstId;
567
612
  }
568
613
 
569
614
  async function registerRedactionRuleFn(
@@ -576,9 +621,14 @@ async function registerRedactionRuleFn(
576
621
  const storage = await wiring.orchestrator.getStorage(namespace);
577
622
  const dir = path.join(storage.dir, "state", "corrections", "redaction-rules");
578
623
  await mkdir(dir, { recursive: true });
579
- // Idempotent: filename is a slug of the pattern so re-registering the same
580
- // pattern overwrites rather than duplicates.
581
- const slug = pattern.replace(/[^a-zA-Z0-9]+/g, "-").slice(0, 64) || "rule";
624
+ // Idempotent: filename is a slug + short hash of the full pattern so
625
+ // re-registering the same pattern overwrites rather than duplicates, while
626
+ // distinct patterns that slug identically (e.g. "abc+def" vs "abc.def"
627
+ // "abc-def") no longer collide and silently remove each other's enforcement
628
+ // (review thread P1).
629
+ const slugBase = pattern.replace(/[^a-zA-Z0-9]+/g, "-").slice(0, 48) || "rule";
630
+ const patternHash = createHash("sha256").update(pattern).digest("hex").slice(0, 16);
631
+ const slug = `${slugBase}-${patternHash}`;
582
632
  await writeFile(
583
633
  path.join(dir, `${slug}.json`),
584
634
  `${JSON.stringify({ pattern, namespace, createdAt: new Date().toISOString() })}\n`,
@@ -686,6 +736,22 @@ function toCandidate(m: MemoryFile, namespace: string, score: number): PlannerCa
686
736
  } satisfies PlannerCandidate & { namespace?: string };
687
737
  }
688
738
 
739
+ /**
740
+ * Lifecycle-aware eligibility for a correction candidate (#1672 item 2). A
741
+ * memory is eligible only when it is `status: "active"` AND not archived.
742
+ * Planning a correction against a memory that was archived via the
743
+ * `archivedAt`/archive path but still marked active would surface stale
744
+ * content the user already set aside — and apply would reject the rescope
745
+ * (non-active source) or supersede a fact the user intended gone. Both the
746
+ * status flip and the archive timestamp are checked so the candidate set
747
+ * stays consistent with the rescope/retire apply-time guards.
748
+ */
749
+ function isEligibleCorrectionCandidate(m: MemoryFile): boolean {
750
+ if (m.frontmatter.status && m.frontmatter.status !== "active") return false;
751
+ if (typeof m.frontmatter.archivedAt === "string" && m.frontmatter.archivedAt.length > 0) return false;
752
+ return true;
753
+ }
754
+
689
755
  function toExecutorMemory(m: MemoryFile): ExecutorMemory {
690
756
  const fm = m.frontmatter;
691
757
  // The tombstone hash must use the ORIGINAL unsuffixed body: writeMemory
@@ -693,12 +759,27 @@ function toExecutorMemory(m: MemoryFile): ExecutorMemory {
693
759
  // hashing m.content would never match the pre-suffix content hash (thread
694
760
  // OhX2N, rule 23). Strip the suffix when attributes are present.
695
761
  const rawBody = fm.structuredAttributes ? stripAttributesSuffix(m.content) : m.content;
762
+ // #1672 item 4: derive the full supersession-key set from the memory's
763
+ // structuredAttributes so the tombstone's keyed tier blocks paraphrased
764
+ // re-observations that place the attribute at a different key position
765
+ // (mirrors temporal-supersession's per-key emission). Also forward the
766
+ // canonical contentHash so the exact tier matches re-extraction without
767
+ // recomputing from a citation-annotated body.
768
+ const supersessionKeys = supersessionKeysForFact({
769
+ entityRef: fm.entityRef,
770
+ structuredAttributes: fm.structuredAttributes,
771
+ });
696
772
  return {
697
773
  memoryId: fm.id,
698
774
  content: m.content,
699
775
  category: fm.category,
700
776
  rawContent: rawBody,
701
777
  ...(fm.entityRef ? { entityRef: fm.entityRef } : {}),
778
+ ...(supersessionKeys.length > 0 ? { supersessionKeys } : {}),
779
+ ...(supersessionKeys.length > 0 ? { supersessionKey: supersessionKeys[0] } : {}),
780
+ ...(typeof fm.contentHash === "string" && fm.contentHash.length > 0
781
+ ? { contentHash: fm.contentHash }
782
+ : {}),
702
783
  } satisfies ExecutorMemory;
703
784
  }
704
785
 
@@ -884,4 +965,8 @@ export {
884
965
  buildClassifyPrompt,
885
966
  CLASSIFY_SYSTEM_PROMPT,
886
967
  parseClassifyResponse,
968
+ // #1672: exported for focused storage-integration regression tests.
969
+ isEligibleCorrectionCandidate,
970
+ applyEditMemory,
971
+ appendTombstoneFn,
887
972
  };