@mneme-ai/core 0.8.4 → 0.10.0

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 (272) hide show
  1. package/dist/entities/go-parser.d.ts +47 -0
  2. package/dist/entities/go-parser.d.ts.map +1 -0
  3. package/dist/entities/go-parser.js +315 -0
  4. package/dist/entities/go-parser.js.map +1 -0
  5. package/dist/entities/go-parser.test.d.ts +2 -0
  6. package/dist/entities/go-parser.test.d.ts.map +1 -0
  7. package/dist/entities/go-parser.test.js +147 -0
  8. package/dist/entities/go-parser.test.js.map +1 -0
  9. package/dist/entities/index.d.ts +1 -0
  10. package/dist/entities/index.d.ts.map +1 -1
  11. package/dist/entities/index.js +1 -0
  12. package/dist/entities/index.js.map +1 -1
  13. package/dist/index.d.ts +3 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +3 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/indexer/indexer.d.ts +12 -0
  18. package/dist/indexer/indexer.d.ts.map +1 -1
  19. package/dist/indexer/indexer.js +28 -1
  20. package/dist/indexer/indexer.js.map +1 -1
  21. package/dist/insights/bus-factor.d.ts +58 -0
  22. package/dist/insights/bus-factor.d.ts.map +1 -0
  23. package/dist/insights/bus-factor.js +117 -0
  24. package/dist/insights/bus-factor.js.map +1 -0
  25. package/dist/insights/bus-factor.test.d.ts +2 -0
  26. package/dist/insights/bus-factor.test.d.ts.map +1 -0
  27. package/dist/insights/bus-factor.test.js +149 -0
  28. package/dist/insights/bus-factor.test.js.map +1 -0
  29. package/dist/insights/commit-coach.d.ts +80 -0
  30. package/dist/insights/commit-coach.d.ts.map +1 -0
  31. package/dist/insights/commit-coach.js +230 -0
  32. package/dist/insights/commit-coach.js.map +1 -0
  33. package/dist/insights/commit-coach.test.d.ts +2 -0
  34. package/dist/insights/commit-coach.test.d.ts.map +1 -0
  35. package/dist/insights/commit-coach.test.js +163 -0
  36. package/dist/insights/commit-coach.test.js.map +1 -0
  37. package/dist/insights/crystal-ball.d.ts +76 -0
  38. package/dist/insights/crystal-ball.d.ts.map +1 -0
  39. package/dist/insights/crystal-ball.js +219 -0
  40. package/dist/insights/crystal-ball.js.map +1 -0
  41. package/dist/insights/crystal-ball.test.d.ts +2 -0
  42. package/dist/insights/crystal-ball.test.d.ts.map +1 -0
  43. package/dist/insights/crystal-ball.test.js +157 -0
  44. package/dist/insights/crystal-ball.test.js.map +1 -0
  45. package/dist/insights/decisions.d.ts +38 -0
  46. package/dist/insights/decisions.d.ts.map +1 -0
  47. package/dist/insights/decisions.js +125 -0
  48. package/dist/insights/decisions.js.map +1 -0
  49. package/dist/insights/decisions.test.d.ts +2 -0
  50. package/dist/insights/decisions.test.d.ts.map +1 -0
  51. package/dist/insights/decisions.test.js +141 -0
  52. package/dist/insights/decisions.test.js.map +1 -0
  53. package/dist/insights/dream.d.ts +71 -0
  54. package/dist/insights/dream.d.ts.map +1 -0
  55. package/dist/insights/dream.js +235 -0
  56. package/dist/insights/dream.js.map +1 -0
  57. package/dist/insights/dream.test.d.ts +2 -0
  58. package/dist/insights/dream.test.d.ts.map +1 -0
  59. package/dist/insights/dream.test.js +127 -0
  60. package/dist/insights/dream.test.js.map +1 -0
  61. package/dist/insights/index.d.ts +21 -0
  62. package/dist/insights/index.d.ts.map +1 -0
  63. package/dist/insights/index.js +21 -0
  64. package/dist/insights/index.js.map +1 -0
  65. package/dist/insights/obsidian.d.ts +42 -0
  66. package/dist/insights/obsidian.d.ts.map +1 -0
  67. package/dist/insights/obsidian.js +263 -0
  68. package/dist/insights/obsidian.js.map +1 -0
  69. package/dist/insights/obsidian.test.d.ts +2 -0
  70. package/dist/insights/obsidian.test.d.ts.map +1 -0
  71. package/dist/insights/obsidian.test.js +241 -0
  72. package/dist/insights/obsidian.test.js.map +1 -0
  73. package/dist/insights/paradox.d.ts +36 -0
  74. package/dist/insights/paradox.d.ts.map +1 -0
  75. package/dist/insights/paradox.js +201 -0
  76. package/dist/insights/paradox.js.map +1 -0
  77. package/dist/insights/paradox.test.d.ts +2 -0
  78. package/dist/insights/paradox.test.d.ts.map +1 -0
  79. package/dist/insights/paradox.test.js +88 -0
  80. package/dist/insights/paradox.test.js.map +1 -0
  81. package/dist/insights/regret.d.ts +57 -0
  82. package/dist/insights/regret.d.ts.map +1 -0
  83. package/dist/insights/regret.js +137 -0
  84. package/dist/insights/regret.js.map +1 -0
  85. package/dist/insights/regret.test.d.ts +2 -0
  86. package/dist/insights/regret.test.d.ts.map +1 -0
  87. package/dist/insights/regret.test.js +153 -0
  88. package/dist/insights/regret.test.js.map +1 -0
  89. package/dist/insights/stack-trace.d.ts +40 -0
  90. package/dist/insights/stack-trace.d.ts.map +1 -0
  91. package/dist/insights/stack-trace.js +127 -0
  92. package/dist/insights/stack-trace.js.map +1 -0
  93. package/dist/insights/stack-trace.test.d.ts +2 -0
  94. package/dist/insights/stack-trace.test.d.ts.map +1 -0
  95. package/dist/insights/stack-trace.test.js +103 -0
  96. package/dist/insights/stack-trace.test.js.map +1 -0
  97. package/dist/insights/story.d.ts +34 -0
  98. package/dist/insights/story.d.ts.map +1 -0
  99. package/dist/insights/story.js +100 -0
  100. package/dist/insights/story.js.map +1 -0
  101. package/dist/insights/story.test.d.ts +2 -0
  102. package/dist/insights/story.test.d.ts.map +1 -0
  103. package/dist/insights/story.test.js +99 -0
  104. package/dist/insights/story.test.js.map +1 -0
  105. package/dist/insights/suggest.d.ts +29 -0
  106. package/dist/insights/suggest.d.ts.map +1 -0
  107. package/dist/insights/suggest.js +93 -0
  108. package/dist/insights/suggest.js.map +1 -0
  109. package/dist/insights/suggest.test.d.ts +2 -0
  110. package/dist/insights/suggest.test.d.ts.map +1 -0
  111. package/dist/insights/suggest.test.js +71 -0
  112. package/dist/insights/suggest.test.js.map +1 -0
  113. package/dist/insights/who-knows.d.ts +66 -0
  114. package/dist/insights/who-knows.d.ts.map +1 -0
  115. package/dist/insights/who-knows.js +125 -0
  116. package/dist/insights/who-knows.js.map +1 -0
  117. package/dist/insights/who-knows.test.d.ts +2 -0
  118. package/dist/insights/who-knows.test.d.ts.map +1 -0
  119. package/dist/insights/who-knows.test.js +109 -0
  120. package/dist/insights/who-knows.test.js.map +1 -0
  121. package/dist/quant/alpha.d.ts +87 -0
  122. package/dist/quant/alpha.d.ts.map +1 -0
  123. package/dist/quant/alpha.js +103 -0
  124. package/dist/quant/alpha.js.map +1 -0
  125. package/dist/quant/alpha.test.d.ts +2 -0
  126. package/dist/quant/alpha.test.d.ts.map +1 -0
  127. package/dist/quant/alpha.test.js +147 -0
  128. package/dist/quant/alpha.test.js.map +1 -0
  129. package/dist/quant/backtest.d.ts +57 -0
  130. package/dist/quant/backtest.d.ts.map +1 -0
  131. package/dist/quant/backtest.js +90 -0
  132. package/dist/quant/backtest.js.map +1 -0
  133. package/dist/quant/backtest.test.d.ts +2 -0
  134. package/dist/quant/backtest.test.d.ts.map +1 -0
  135. package/dist/quant/backtest.test.js +133 -0
  136. package/dist/quant/backtest.test.js.map +1 -0
  137. package/dist/quant/black-swan.d.ts +45 -0
  138. package/dist/quant/black-swan.d.ts.map +1 -0
  139. package/dist/quant/black-swan.js +112 -0
  140. package/dist/quant/black-swan.js.map +1 -0
  141. package/dist/quant/black-swan.test.d.ts +2 -0
  142. package/dist/quant/black-swan.test.d.ts.map +1 -0
  143. package/dist/quant/black-swan.test.js +131 -0
  144. package/dist/quant/black-swan.test.js.map +1 -0
  145. package/dist/quant/correlation-matrix.d.ts +54 -0
  146. package/dist/quant/correlation-matrix.d.ts.map +1 -0
  147. package/dist/quant/correlation-matrix.js +103 -0
  148. package/dist/quant/correlation-matrix.js.map +1 -0
  149. package/dist/quant/correlation-matrix.test.d.ts +2 -0
  150. package/dist/quant/correlation-matrix.test.d.ts.map +1 -0
  151. package/dist/quant/correlation-matrix.test.js +118 -0
  152. package/dist/quant/correlation-matrix.test.js.map +1 -0
  153. package/dist/quant/drawdown.d.ts +51 -0
  154. package/dist/quant/drawdown.d.ts.map +1 -0
  155. package/dist/quant/drawdown.js +96 -0
  156. package/dist/quant/drawdown.js.map +1 -0
  157. package/dist/quant/drawdown.test.d.ts +2 -0
  158. package/dist/quant/drawdown.test.d.ts.map +1 -0
  159. package/dist/quant/drawdown.test.js +166 -0
  160. package/dist/quant/drawdown.test.js.map +1 -0
  161. package/dist/quant/greek.d.ts +55 -0
  162. package/dist/quant/greek.d.ts.map +1 -0
  163. package/dist/quant/greek.js +157 -0
  164. package/dist/quant/greek.js.map +1 -0
  165. package/dist/quant/greek.test.d.ts +2 -0
  166. package/dist/quant/greek.test.d.ts.map +1 -0
  167. package/dist/quant/greek.test.js +138 -0
  168. package/dist/quant/greek.test.js.map +1 -0
  169. package/dist/quant/implied-volatility.d.ts +65 -0
  170. package/dist/quant/implied-volatility.d.ts.map +1 -0
  171. package/dist/quant/implied-volatility.js +149 -0
  172. package/dist/quant/implied-volatility.js.map +1 -0
  173. package/dist/quant/implied-volatility.test.d.ts +2 -0
  174. package/dist/quant/implied-volatility.test.d.ts.map +1 -0
  175. package/dist/quant/implied-volatility.test.js +127 -0
  176. package/dist/quant/implied-volatility.test.js.map +1 -0
  177. package/dist/quant/index.d.ts +28 -0
  178. package/dist/quant/index.d.ts.map +1 -0
  179. package/dist/quant/index.js +28 -0
  180. package/dist/quant/index.js.map +1 -0
  181. package/dist/quant/insider-trading.d.ts +56 -0
  182. package/dist/quant/insider-trading.d.ts.map +1 -0
  183. package/dist/quant/insider-trading.js +129 -0
  184. package/dist/quant/insider-trading.js.map +1 -0
  185. package/dist/quant/insider-trading.test.d.ts +2 -0
  186. package/dist/quant/insider-trading.test.d.ts.map +1 -0
  187. package/dist/quant/insider-trading.test.js +130 -0
  188. package/dist/quant/insider-trading.test.js.map +1 -0
  189. package/dist/quant/moneyball.d.ts +48 -0
  190. package/dist/quant/moneyball.d.ts.map +1 -0
  191. package/dist/quant/moneyball.js +110 -0
  192. package/dist/quant/moneyball.js.map +1 -0
  193. package/dist/quant/moneyball.test.d.ts +2 -0
  194. package/dist/quant/moneyball.test.d.ts.map +1 -0
  195. package/dist/quant/moneyball.test.js +137 -0
  196. package/dist/quant/moneyball.test.js.map +1 -0
  197. package/dist/quant/tax-loss-harvest.d.ts +59 -0
  198. package/dist/quant/tax-loss-harvest.d.ts.map +1 -0
  199. package/dist/quant/tax-loss-harvest.js +126 -0
  200. package/dist/quant/tax-loss-harvest.js.map +1 -0
  201. package/dist/quant/tax-loss-harvest.test.d.ts +2 -0
  202. package/dist/quant/tax-loss-harvest.test.d.ts.map +1 -0
  203. package/dist/quant/tax-loss-harvest.test.js +126 -0
  204. package/dist/quant/tax-loss-harvest.test.js.map +1 -0
  205. package/dist/retrieve/index.d.ts +2 -0
  206. package/dist/retrieve/index.d.ts.map +1 -1
  207. package/dist/retrieve/index.js +2 -0
  208. package/dist/retrieve/index.js.map +1 -1
  209. package/dist/retrieve/intent.d.ts +32 -0
  210. package/dist/retrieve/intent.d.ts.map +1 -0
  211. package/dist/retrieve/intent.js +104 -0
  212. package/dist/retrieve/intent.js.map +1 -0
  213. package/dist/retrieve/intent.test.d.ts +2 -0
  214. package/dist/retrieve/intent.test.d.ts.map +1 -0
  215. package/dist/retrieve/intent.test.js +106 -0
  216. package/dist/retrieve/intent.test.js.map +1 -0
  217. package/dist/retrieve/search.d.ts +30 -0
  218. package/dist/retrieve/search.d.ts.map +1 -1
  219. package/dist/retrieve/search.js +48 -0
  220. package/dist/retrieve/search.js.map +1 -1
  221. package/dist/retrieve/search.test.js +84 -1
  222. package/dist/retrieve/search.test.js.map +1 -1
  223. package/dist/retrieve/synthesize.d.ts +57 -0
  224. package/dist/retrieve/synthesize.d.ts.map +1 -0
  225. package/dist/retrieve/synthesize.js +191 -0
  226. package/dist/retrieve/synthesize.js.map +1 -0
  227. package/dist/retrieve/synthesize.test.d.ts +2 -0
  228. package/dist/retrieve/synthesize.test.d.ts.map +1 -0
  229. package/dist/retrieve/synthesize.test.js +127 -0
  230. package/dist/retrieve/synthesize.test.js.map +1 -0
  231. package/dist/store/schema.d.ts +2 -2
  232. package/dist/store/schema.d.ts.map +1 -1
  233. package/dist/store/schema.js +60 -2
  234. package/dist/store/schema.js.map +1 -1
  235. package/dist/store/sqlite.d.ts +2 -0
  236. package/dist/store/sqlite.d.ts.map +1 -1
  237. package/dist/store/sqlite.js +24 -0
  238. package/dist/store/sqlite.js.map +1 -1
  239. package/dist/store/sqlite.test.js +1 -1
  240. package/dist/util/index.d.ts +2 -0
  241. package/dist/util/index.d.ts.map +1 -1
  242. package/dist/util/index.js +2 -1
  243. package/dist/util/index.js.map +1 -1
  244. package/dist/util/redact.d.ts +58 -0
  245. package/dist/util/redact.d.ts.map +1 -0
  246. package/dist/util/redact.js +129 -0
  247. package/dist/util/redact.js.map +1 -0
  248. package/dist/util/redact.test.d.ts +2 -0
  249. package/dist/util/redact.test.d.ts.map +1 -0
  250. package/dist/util/redact.test.js +148 -0
  251. package/dist/util/redact.test.js.map +1 -0
  252. package/dist/wisdom/calibrator.d.ts +43 -0
  253. package/dist/wisdom/calibrator.d.ts.map +1 -0
  254. package/dist/wisdom/calibrator.js +120 -0
  255. package/dist/wisdom/calibrator.js.map +1 -0
  256. package/dist/wisdom/feedback.d.ts +45 -0
  257. package/dist/wisdom/feedback.d.ts.map +1 -0
  258. package/dist/wisdom/feedback.js +116 -0
  259. package/dist/wisdom/feedback.js.map +1 -0
  260. package/dist/wisdom/index.d.ts +15 -0
  261. package/dist/wisdom/index.d.ts.map +1 -0
  262. package/dist/wisdom/index.js +15 -0
  263. package/dist/wisdom/index.js.map +1 -0
  264. package/dist/wisdom/types.d.ts +67 -0
  265. package/dist/wisdom/types.d.ts.map +1 -0
  266. package/dist/wisdom/types.js +20 -0
  267. package/dist/wisdom/types.js.map +1 -0
  268. package/dist/wisdom/wisdom.test.d.ts +2 -0
  269. package/dist/wisdom/wisdom.test.d.ts.map +1 -0
  270. package/dist/wisdom/wisdom.test.js +144 -0
  271. package/dist/wisdom/wisdom.test.js.map +1 -0
  272. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backtest.js","sourceRoot":"","sources":["../../src/quant/backtest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=backtest.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backtest.test.d.ts","sourceRoot":"","sources":["../../src/quant/backtest.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,133 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { backtest, classifyVerdict, badge } from "./backtest.js";
3
+ describe("backtest — confusion matrix counts", () => {
4
+ it("perfect predictor — all TP, no FP/FN", () => {
5
+ const r = backtest([
6
+ { id: "a", predicted: true, actual: true },
7
+ { id: "b", predicted: true, actual: true },
8
+ { id: "c", predicted: false, actual: false },
9
+ { id: "d", predicted: false, actual: false },
10
+ ]);
11
+ expect(r.truePositives).toBe(2);
12
+ expect(r.falsePositives).toBe(0);
13
+ expect(r.trueNegatives).toBe(2);
14
+ expect(r.falseNegatives).toBe(0);
15
+ expect(r.precision).toBe(1);
16
+ expect(r.recall).toBe(1);
17
+ expect(r.f1).toBe(1);
18
+ });
19
+ it("worst predictor — all FP and FN", () => {
20
+ const r = backtest([
21
+ { id: "a", predicted: true, actual: false },
22
+ { id: "b", predicted: true, actual: false },
23
+ { id: "c", predicted: false, actual: true },
24
+ { id: "d", predicted: false, actual: true },
25
+ ]);
26
+ expect(r.truePositives).toBe(0);
27
+ expect(r.precision).toBe(0);
28
+ expect(r.recall).toBe(0);
29
+ expect(r.f1).toBe(0);
30
+ });
31
+ it("balanced realistic case", () => {
32
+ // 14 samples, 6 predicted high-risk, 4 of those actually had incidents
33
+ // 8 predicted clean, 2 actually had incidents
34
+ // Total positives: 6 (4 + 2)
35
+ const samples = [
36
+ { id: "1", predicted: true, actual: true },
37
+ { id: "2", predicted: true, actual: true },
38
+ { id: "3", predicted: true, actual: true },
39
+ { id: "4", predicted: true, actual: true },
40
+ { id: "5", predicted: true, actual: false },
41
+ { id: "6", predicted: true, actual: false },
42
+ { id: "7", predicted: false, actual: true },
43
+ { id: "8", predicted: false, actual: true },
44
+ { id: "9", predicted: false, actual: false },
45
+ { id: "10", predicted: false, actual: false },
46
+ { id: "11", predicted: false, actual: false },
47
+ { id: "12", predicted: false, actual: false },
48
+ { id: "13", predicted: false, actual: false },
49
+ { id: "14", predicted: false, actual: false },
50
+ ];
51
+ const r = backtest(samples);
52
+ expect(r.precision).toBeCloseTo(4 / 6, 4);
53
+ expect(r.recall).toBeCloseTo(4 / 6, 4);
54
+ expect(r.f1).toBeCloseTo(4 / 6, 4);
55
+ expect(r.baseRate).toBeCloseTo(6 / 14, 4);
56
+ expect(r.lift).toBeCloseTo((4 / 6) / (6 / 14), 4);
57
+ });
58
+ });
59
+ describe("backtest — edge cases", () => {
60
+ it("empty input returns zeros + no-edge verdict", () => {
61
+ const r = backtest([]);
62
+ expect(r.n).toBe(0);
63
+ expect(r.precision).toBe(0);
64
+ expect(r.recall).toBe(0);
65
+ expect(r.f1).toBe(0);
66
+ expect(r.verdict).toBe("no-edge");
67
+ });
68
+ it("no positive predictions → precision = 0 (avoids div by zero)", () => {
69
+ const r = backtest([
70
+ { id: "1", predicted: false, actual: false },
71
+ { id: "2", predicted: false, actual: true },
72
+ ]);
73
+ expect(r.precision).toBe(0);
74
+ });
75
+ it("no actual positives → recall = 0", () => {
76
+ const r = backtest([
77
+ { id: "1", predicted: true, actual: false },
78
+ { id: "2", predicted: false, actual: false },
79
+ ]);
80
+ expect(r.recall).toBe(0);
81
+ });
82
+ });
83
+ describe("classifyVerdict — tier from lift × precision × recall", () => {
84
+ it("strong-edge for high precision + recall + 2.5× lift", () => {
85
+ expect(classifyVerdict(3, 0.7, 0.6, 20)).toBe("strong-edge");
86
+ });
87
+ it("real-edge for moderate metrics", () => {
88
+ expect(classifyVerdict(1.8, 0.5, 0.4, 20)).toBe("real-edge");
89
+ });
90
+ it("weak for lift ≥ 1.1 only", () => {
91
+ expect(classifyVerdict(1.2, 0.3, 0.3, 20)).toBe("weak");
92
+ });
93
+ it("no-edge for too-small samples", () => {
94
+ expect(classifyVerdict(5, 0.9, 0.9, 4)).toBe("no-edge");
95
+ });
96
+ it("no-edge when no lift over random", () => {
97
+ expect(classifyVerdict(0.9, 0.3, 0.3, 20)).toBe("no-edge");
98
+ });
99
+ });
100
+ describe("badge — one-line summary string", () => {
101
+ it("includes F1, lift, and n", () => {
102
+ const r = backtest([
103
+ { id: "1", predicted: true, actual: true },
104
+ { id: "2", predicted: true, actual: false },
105
+ { id: "3", predicted: false, actual: false },
106
+ { id: "4", predicted: false, actual: false },
107
+ { id: "5", predicted: false, actual: false },
108
+ ]);
109
+ const b = badge(r);
110
+ expect(b).toMatch(/F1 = \d/);
111
+ expect(b).toMatch(/× lift/);
112
+ expect(b).toMatch(/n=5/);
113
+ });
114
+ });
115
+ describe("backtest — conclusion text adapts to verdict", () => {
116
+ it("no-edge mentions sample size for small n", () => {
117
+ const r = backtest([{ id: "1", predicted: true, actual: true }]);
118
+ expect(r.conclusion.toLowerCase()).toContain("sample");
119
+ });
120
+ it("strong-edge says 'trust' or 'real predictive'", () => {
121
+ // build samples with strong edge: lift ≥ 2.5, precision ≥ 0.6, recall ≥ 0.5
122
+ const samples = [
123
+ ...Array.from({ length: 8 }, (_, i) => ({ id: `tp${i}`, predicted: true, actual: true })),
124
+ ...Array.from({ length: 2 }, (_, i) => ({ id: `fp${i}`, predicted: true, actual: false })),
125
+ ...Array.from({ length: 4 }, (_, i) => ({ id: `fn${i}`, predicted: false, actual: true })),
126
+ ...Array.from({ length: 36 }, (_, i) => ({ id: `tn${i}`, predicted: false, actual: false })),
127
+ ];
128
+ const r = backtest(samples);
129
+ expect(r.verdict).toBe("strong-edge");
130
+ expect(r.conclusion.toLowerCase()).toMatch(/trust|strong/);
131
+ });
132
+ });
133
+ //# sourceMappingURL=backtest.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backtest.test.js","sourceRoot":"","sources":["../../src/quant/backtest.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * `mneme black-swan` — find rare-but-catastrophic file patterns.
3
+ *
4
+ * Inspired by Taleb: real risk lives in the tail. Files touched rarely
5
+ * but tied to high-severity incidents are far more dangerous than
6
+ * frequently-touched files with proportional bug counts.
7
+ *
8
+ * tail_risk = log(avg_severity + 1) × (1 / max(touch_frequency, 1))
9
+ *
10
+ * Files surface ranked by tail_risk — the silent assassins that look
11
+ * stable but explode when touched.
12
+ *
13
+ * Pure store-backed analysis. No LLM.
14
+ */
15
+ import type { MnemeStore } from "../store/sqlite.js";
16
+ export interface BlackSwanCandidate {
17
+ filePath: string;
18
+ /** Total commits that ever touched this file. */
19
+ touchCount: number;
20
+ /** Days since the last touch. */
21
+ daysSinceTouch: number;
22
+ /** Number of incidents associated with this file. */
23
+ incidentCount: number;
24
+ /** Mean severity (1=low, 5=critical). */
25
+ avgSeverity: number;
26
+ /** Tail-risk score — see formula above. */
27
+ tailRisk: number;
28
+ /** Tier label for output. */
29
+ tier: "deceptive-calm" | "elevated" | "watch" | "background";
30
+ /** A 1-line operational recommendation. */
31
+ recommendation: string;
32
+ }
33
+ /**
34
+ * Walk every indexed file, compute touch frequency + linked-incident
35
+ * severity, and rank by tail risk. Conservative defaults: files with
36
+ * < incidents are skipped (no tail without trouble).
37
+ */
38
+ export declare function findBlackSwans(store: MnemeStore, opts?: {
39
+ topN?: number;
40
+ minIncidents?: number;
41
+ maxTouches?: number;
42
+ now?: Date;
43
+ }): BlackSwanCandidate[];
44
+ export declare function classifyBlackSwanTier(tailRisk: number, touches: number, avgSeverity: number): BlackSwanCandidate["tier"];
45
+ //# sourceMappingURL=black-swan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"black-swan.d.ts","sourceRoot":"","sources":["../../src/quant/black-swan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,qDAAqD;IACrD,aAAa,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,IAAI,EAAE,gBAAgB,GAAG,UAAU,GAAG,OAAO,GAAG,YAAY,CAAC;IAC7D,2CAA2C;IAC3C,cAAc,EAAE,MAAM,CAAC;CACxB;AAUD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,IAAI,CAAA;CAAO,GACnF,kBAAkB,EAAE,CAiEtB;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,kBAAkB,CAAC,MAAM,CAAC,CAK5B"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * `mneme black-swan` — find rare-but-catastrophic file patterns.
3
+ *
4
+ * Inspired by Taleb: real risk lives in the tail. Files touched rarely
5
+ * but tied to high-severity incidents are far more dangerous than
6
+ * frequently-touched files with proportional bug counts.
7
+ *
8
+ * tail_risk = log(avg_severity + 1) × (1 / max(touch_frequency, 1))
9
+ *
10
+ * Files surface ranked by tail_risk — the silent assassins that look
11
+ * stable but explode when touched.
12
+ *
13
+ * Pure store-backed analysis. No LLM.
14
+ */
15
+ const SEVERITY_RANK = {
16
+ critical: 5,
17
+ high: 4,
18
+ medium: 3,
19
+ low: 2,
20
+ info: 1,
21
+ };
22
+ /**
23
+ * Walk every indexed file, compute touch frequency + linked-incident
24
+ * severity, and rank by tail risk. Conservative defaults: files with
25
+ * < incidents are skipped (no tail without trouble).
26
+ */
27
+ export function findBlackSwans(store, opts = {}) {
28
+ const topN = opts.topN ?? 10;
29
+ const minIncidents = opts.minIncidents ?? 1;
30
+ const maxTouches = opts.maxTouches ?? 30;
31
+ const now = opts.now ?? new Date();
32
+ // Pull file → (touch count, last touch).
33
+ const fileRows = store.db
34
+ .prepare(`SELECT
35
+ fc.path AS path,
36
+ COUNT(*) AS touches,
37
+ MAX(c.author_date) AS last_touch
38
+ FROM file_changes fc
39
+ JOIN commits c ON c.hash = fc.commit_hash
40
+ GROUP BY fc.path
41
+ HAVING touches <= ?`)
42
+ .all(maxTouches);
43
+ // Pull file → incidents (parsed from incidents.affected_files).
44
+ const incidentRows = store.db
45
+ .prepare(`SELECT severity, affected_files FROM incidents`)
46
+ .all();
47
+ // Build file → { incidentCount, severities[] }
48
+ const incidentsByFile = new Map();
49
+ for (const r of incidentRows) {
50
+ if (!r.affected_files)
51
+ continue;
52
+ let files = [];
53
+ try {
54
+ const parsed = JSON.parse(r.affected_files);
55
+ if (Array.isArray(parsed))
56
+ files = parsed.filter((x) => typeof x === "string");
57
+ }
58
+ catch {
59
+ // Fallback: comma-separated paths
60
+ files = r.affected_files.split(",").map((s) => s.trim()).filter(Boolean);
61
+ }
62
+ const sev = SEVERITY_RANK[r.severity?.toLowerCase()] ?? 3;
63
+ for (const f of files) {
64
+ if (!incidentsByFile.has(f))
65
+ incidentsByFile.set(f, []);
66
+ incidentsByFile.get(f).push(sev);
67
+ }
68
+ }
69
+ const candidates = [];
70
+ for (const r of fileRows) {
71
+ const sevs = incidentsByFile.get(r.path) ?? [];
72
+ if (sevs.length < minIncidents)
73
+ continue;
74
+ const avgSeverity = sevs.reduce((s, x) => s + x, 0) / sevs.length;
75
+ const daysSinceTouch = (now.getTime() - new Date(r.last_touch).getTime()) / 86_400_000;
76
+ const tailRisk = Math.log(avgSeverity + 1) * (1 / Math.max(r.touches, 1));
77
+ candidates.push({
78
+ filePath: r.path,
79
+ touchCount: r.touches,
80
+ daysSinceTouch: Math.round(daysSinceTouch),
81
+ incidentCount: sevs.length,
82
+ avgSeverity: Math.round(avgSeverity * 10) / 10,
83
+ tailRisk,
84
+ tier: classifyBlackSwanTier(tailRisk, r.touches, avgSeverity),
85
+ recommendation: buildBlackSwanRecommendation(r.touches, avgSeverity, daysSinceTouch),
86
+ });
87
+ }
88
+ candidates.sort((a, b) => b.tailRisk - a.tailRisk);
89
+ return candidates.slice(0, topN);
90
+ }
91
+ export function classifyBlackSwanTier(tailRisk, touches, avgSeverity) {
92
+ if (tailRisk >= 0.8 && touches <= 3 && avgSeverity >= 4)
93
+ return "deceptive-calm";
94
+ if (tailRisk >= 0.5 && avgSeverity >= 3)
95
+ return "elevated";
96
+ if (tailRisk >= 0.2)
97
+ return "watch";
98
+ return "background";
99
+ }
100
+ function buildBlackSwanRecommendation(touches, avgSeverity, daysSinceTouch) {
101
+ if (touches <= 2 && avgSeverity >= 4) {
102
+ return "Mandatory pair-program + canary deploy. This file LOOKS stable but its track record is catastrophic.";
103
+ }
104
+ if (avgSeverity >= 4) {
105
+ return "Code-freeze without 2 reviewers + load test required. High tail risk on edits.";
106
+ }
107
+ if (daysSinceTouch > 365) {
108
+ return "Untouched for 1+ year. Schedule a review session before the next change.";
109
+ }
110
+ return "Monitor closely. Run mneme blast on any commit that touches this file.";
111
+ }
112
+ //# sourceMappingURL=black-swan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"black-swan.js","sourceRoot":"","sources":["../../src/quant/black-swan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=black-swan.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"black-swan.test.d.ts","sourceRoot":"","sources":["../../src/quant/black-swan.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,131 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdtempSync, rmSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import { MnemeStore } from "../store/sqlite.js";
6
+ import { findBlackSwans, classifyBlackSwanTier } from "./black-swan.js";
7
+ let tmpDir;
8
+ let store;
9
+ beforeEach(() => {
10
+ tmpDir = mkdtempSync(join(tmpdir(), "mneme-bs-"));
11
+ store = new MnemeStore(join(tmpDir, "mneme.db"));
12
+ });
13
+ afterEach(() => {
14
+ store.close();
15
+ rmSync(tmpDir, { recursive: true, force: true });
16
+ });
17
+ const cmt = (hash, date, files) => ({
18
+ hash,
19
+ shortHash: hash.slice(0, 7),
20
+ authorName: "alice",
21
+ authorEmail: "a@x",
22
+ authorDate: `${date}T00:00:00Z`,
23
+ committerDate: `${date}T00:00:00Z`,
24
+ subject: "commit",
25
+ body: "",
26
+ parents: [],
27
+ files,
28
+ });
29
+ function seedCommits(commits) {
30
+ store.upsertCommits(commits);
31
+ for (const c of commits) {
32
+ store.upsertFileChanges(c.files.map((f) => ({
33
+ commitHash: c.hash,
34
+ path: f,
35
+ changeKind: "M",
36
+ insertions: 1,
37
+ deletions: 0,
38
+ })));
39
+ }
40
+ }
41
+ function seedIncident(severity, affectedFiles) {
42
+ store.db
43
+ .prepare(`INSERT INTO incidents (id, source, title, occurred_at, severity, affected_files)
44
+ VALUES (?, 'manual', ?, ?, ?, ?)`)
45
+ .run(`inc-${Math.random()}`, "test", "2024-12-01T00:00:00Z", severity, JSON.stringify(affectedFiles));
46
+ }
47
+ describe("classifyBlackSwanTier", () => {
48
+ it('"deceptive-calm" for high tail risk + few touches + critical severity', () => {
49
+ expect(classifyBlackSwanTier(1.5, 2, 4.5)).toBe("deceptive-calm");
50
+ });
51
+ it('"elevated" for moderate tail risk + medium severity', () => {
52
+ expect(classifyBlackSwanTier(0.6, 5, 3.0)).toBe("elevated");
53
+ });
54
+ it('"watch" for low tail risk', () => {
55
+ expect(classifyBlackSwanTier(0.3, 10, 2.0)).toBe("watch");
56
+ });
57
+ it('"background" for tiny tail risk', () => {
58
+ expect(classifyBlackSwanTier(0.05, 30, 1.5)).toBe("background");
59
+ });
60
+ });
61
+ describe("findBlackSwans — basic detection", () => {
62
+ it("returns empty array when no incidents are linked to files", () => {
63
+ seedCommits([cmt("a1", "2024-01-01", ["src/x.ts"])]);
64
+ expect(findBlackSwans(store)).toEqual([]);
65
+ });
66
+ it("flags a low-touch + high-severity file as deceptive-calm", () => {
67
+ seedCommits([
68
+ cmt("a1", "2024-01-01", ["src/refund.ts"]),
69
+ cmt("a2", "2024-06-01", ["src/refund.ts"]),
70
+ ]);
71
+ seedIncident("critical", ["src/refund.ts"]);
72
+ seedIncident("critical", ["src/refund.ts"]);
73
+ const candidates = findBlackSwans(store, { now: new Date("2024-12-01T00:00:00Z") });
74
+ const refund = candidates.find((c) => c.filePath === "src/refund.ts");
75
+ expect(refund).toBeDefined();
76
+ expect(refund.incidentCount).toBe(2);
77
+ expect(refund.avgSeverity).toBe(5);
78
+ expect(refund.tier).toBe("deceptive-calm");
79
+ });
80
+ it("respects maxTouches filter — high-traffic files are NOT black swans", () => {
81
+ const commits = Array.from({ length: 100 }, (_, i) => cmt(`a${i}`.padEnd(7, "x"), `2024-${String(((i % 12) + 1)).padStart(2, "0")}-01`, ["src/hot.ts"]));
82
+ seedCommits(commits);
83
+ seedIncident("critical", ["src/hot.ts"]);
84
+ expect(findBlackSwans(store, { maxTouches: 30 }).find((c) => c.filePath === "src/hot.ts")).toBeUndefined();
85
+ });
86
+ it("respects minIncidents filter (default 1)", () => {
87
+ seedCommits([cmt("a1", "2024-01-01", ["src/never-broke.ts"])]);
88
+ // No incident seeded — should be excluded
89
+ expect(findBlackSwans(store).find((c) => c.filePath === "src/never-broke.ts")).toBeUndefined();
90
+ });
91
+ it("sorts by tailRisk descending", () => {
92
+ seedCommits([
93
+ cmt("a1", "2024-01-01", ["src/calm.ts"]),
94
+ cmt("a2", "2024-02-01", ["src/calm.ts"]),
95
+ cmt("b1", "2024-01-01", ["src/medium.ts"]),
96
+ cmt("b2", "2024-02-01", ["src/medium.ts"]),
97
+ cmt("b3", "2024-03-01", ["src/medium.ts"]),
98
+ cmt("b4", "2024-04-01", ["src/medium.ts"]),
99
+ cmt("b5", "2024-05-01", ["src/medium.ts"]),
100
+ ]);
101
+ seedIncident("critical", ["src/calm.ts"]); // severity 5, 2 touches → high tail
102
+ seedIncident("medium", ["src/medium.ts"]); // severity 3, 5 touches → low tail
103
+ const candidates = findBlackSwans(store);
104
+ expect(candidates[0].filePath).toBe("src/calm.ts");
105
+ });
106
+ it("respects topN cap", () => {
107
+ for (let i = 0; i < 30; i++) {
108
+ seedCommits([cmt(`x${i}`.padEnd(7, "x"), "2024-01-01", [`src/f${i}.ts`])]);
109
+ seedIncident("critical", [`src/f${i}.ts`]);
110
+ }
111
+ expect(findBlackSwans(store, { topN: 5 }).length).toBeLessThanOrEqual(5);
112
+ });
113
+ });
114
+ describe("findBlackSwans — recommendation text", () => {
115
+ it("recommends pair-program + canary for low-touch + critical files", () => {
116
+ seedCommits([cmt("a1", "2024-01-01", ["src/refund.ts"])]);
117
+ seedIncident("critical", ["src/refund.ts"]);
118
+ const c = findBlackSwans(store)[0];
119
+ expect(c.recommendation.toLowerCase()).toMatch(/pair-program|canary/);
120
+ });
121
+ it("recommends review session for files untouched > 1 year", () => {
122
+ seedCommits([
123
+ cmt("a1", "2022-01-01", ["src/legacy.ts"]),
124
+ cmt("a2", "2022-02-01", ["src/legacy.ts"]),
125
+ ]);
126
+ seedIncident("medium", ["src/legacy.ts"]);
127
+ const c = findBlackSwans(store, { now: new Date("2024-12-01T00:00:00Z") }).find((x) => x.filePath === "src/legacy.ts");
128
+ expect(c.recommendation.toLowerCase()).toMatch(/review|untouched/);
129
+ });
130
+ });
131
+ //# sourceMappingURL=black-swan.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"black-swan.test.js","sourceRoot":"","sources":["../../src/quant/black-swan.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * `mneme correlation-matrix` — find HIDDEN coupling between files.
3
+ *
4
+ * Static analysis catches imports. This catches *behavioral coupling*:
5
+ * "every time file X is touched, file Y has a bug fix within N days,
6
+ * even though X and Y don't import each other."
7
+ *
8
+ * Why this is novel: most tools see static dependency graphs (X imports
9
+ * Y). Behavioral graphs reveal architectural smells that imports don't:
10
+ * a config table that EVERY service silently depends on, an undocumented
11
+ * shared state, an order-of-operations contract.
12
+ *
13
+ * Output: ranked file-pair coupling with statistical significance score.
14
+ *
15
+ * Pure analysis. No LLM.
16
+ */
17
+ import type { Commit } from "../types.js";
18
+ export interface CouplingPair {
19
+ fileA: string;
20
+ fileB: string;
21
+ /** Total commits that touched A. */
22
+ countA: number;
23
+ /** Total commits that touched B. */
24
+ countB: number;
25
+ /** Commits that touched A AND B together. */
26
+ coOccurrences: number;
27
+ /** Jaccard similarity = co_occurrences / (A + B - co_occurrences). */
28
+ jaccard: number;
29
+ /** Lift = P(B|A) / P(B) — how much MORE likely B is touched given A. */
30
+ lift: number;
31
+ /** Tier label. */
32
+ tier: "tight" | "strong" | "moderate" | "weak";
33
+ /** Plain-English interpretation. */
34
+ interpretation: string;
35
+ }
36
+ export interface CorrelationOptions {
37
+ /** Minimum total touches per file to consider. */
38
+ minFileTouches?: number;
39
+ /** Minimum co-occurrences to surface a pair. */
40
+ minCoOccurrences?: number;
41
+ /** Top-N pairs to return. */
42
+ topN?: number;
43
+ /** Skip pairs where lift below this. */
44
+ minLift?: number;
45
+ }
46
+ /**
47
+ * Build the file-pair coupling matrix from commit history.
48
+ *
49
+ * Algorithm: for each commit, mark every pair (file_i, file_j) as co-touched.
50
+ * Aggregate counts; compute Jaccard + lift per pair.
51
+ */
52
+ export declare function correlationMatrix(commits: Commit[], opts?: CorrelationOptions): CouplingPair[];
53
+ export declare function classifyCouplingTier(jaccard: number, lift: number): CouplingPair["tier"];
54
+ //# sourceMappingURL=correlation-matrix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlation-matrix.d.ts","sourceRoot":"","sources":["../../src/quant/correlation-matrix.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,aAAa,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;IAC/C,oCAAoC;IACpC,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gDAAgD;IAChD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,kBAAuB,GAAG,YAAY,EAAE,CAwDlG;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAQxF"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * `mneme correlation-matrix` — find HIDDEN coupling between files.
3
+ *
4
+ * Static analysis catches imports. This catches *behavioral coupling*:
5
+ * "every time file X is touched, file Y has a bug fix within N days,
6
+ * even though X and Y don't import each other."
7
+ *
8
+ * Why this is novel: most tools see static dependency graphs (X imports
9
+ * Y). Behavioral graphs reveal architectural smells that imports don't:
10
+ * a config table that EVERY service silently depends on, an undocumented
11
+ * shared state, an order-of-operations contract.
12
+ *
13
+ * Output: ranked file-pair coupling with statistical significance score.
14
+ *
15
+ * Pure analysis. No LLM.
16
+ */
17
+ /**
18
+ * Build the file-pair coupling matrix from commit history.
19
+ *
20
+ * Algorithm: for each commit, mark every pair (file_i, file_j) as co-touched.
21
+ * Aggregate counts; compute Jaccard + lift per pair.
22
+ */
23
+ export function correlationMatrix(commits, opts = {}) {
24
+ const minTouches = opts.minFileTouches ?? 3;
25
+ const minCo = opts.minCoOccurrences ?? 2;
26
+ const topN = opts.topN ?? 20;
27
+ const minLift = opts.minLift ?? 1.5;
28
+ // Step 1: per-file count.
29
+ const fileCount = new Map();
30
+ for (const c of commits) {
31
+ for (const f of c.files ?? [])
32
+ fileCount.set(f, (fileCount.get(f) ?? 0) + 1);
33
+ }
34
+ // Filter to files with enough activity.
35
+ const eligible = new Set();
36
+ for (const [f, n] of fileCount)
37
+ if (n >= minTouches)
38
+ eligible.add(f);
39
+ // Step 2: per-pair co-occurrence.
40
+ const pairKey = (a, b) => (a < b ? `${a}|${b}` : `${b}|${a}`);
41
+ const pairCount = new Map();
42
+ for (const c of commits) {
43
+ const files = (c.files ?? []).filter((f) => eligible.has(f));
44
+ for (let i = 0; i < files.length; i++) {
45
+ for (let j = i + 1; j < files.length; j++) {
46
+ const k = pairKey(files[i], files[j]);
47
+ pairCount.set(k, (pairCount.get(k) ?? 0) + 1);
48
+ }
49
+ }
50
+ }
51
+ const totalCommits = commits.length;
52
+ const pairs = [];
53
+ for (const [k, n] of pairCount) {
54
+ if (n < minCo)
55
+ continue;
56
+ const [a, b] = k.split("|");
57
+ const A = fileCount.get(a);
58
+ const B = fileCount.get(b);
59
+ const jaccard = n / (A + B - n);
60
+ // P(B|A) = n / A; P(B) = B / totalCommits; lift = (n/A) / (B/totalCommits)
61
+ const lift = totalCommits === 0 || A === 0 || B === 0 ? 0 : (n / A) / (B / totalCommits);
62
+ if (lift < minLift)
63
+ continue;
64
+ pairs.push({
65
+ fileA: a,
66
+ fileB: b,
67
+ countA: A,
68
+ countB: B,
69
+ coOccurrences: n,
70
+ jaccard,
71
+ lift,
72
+ tier: classifyCouplingTier(jaccard, lift),
73
+ interpretation: buildCouplingInterpretation(jaccard, lift, n),
74
+ });
75
+ }
76
+ pairs.sort((a, b) => b.lift - a.lift || b.jaccard - a.jaccard);
77
+ return pairs.slice(0, topN);
78
+ }
79
+ export function classifyCouplingTier(jaccard, lift) {
80
+ // 'tight' = perfect jaccard (≥ 0.9) OR (jaccard ≥ 0.6 AND lift ≥ 5).
81
+ // Real codebases rarely hit lift ≥ 5; jaccard 1.0 is a stronger signal
82
+ // than lift alone — fully co-touched files deserve the 'tight' label.
83
+ if (jaccard >= 0.9 || (jaccard >= 0.6 && lift >= 5))
84
+ return "tight";
85
+ if (jaccard >= 0.4 || lift >= 3)
86
+ return "strong";
87
+ if (jaccard >= 0.2 || lift >= 2)
88
+ return "moderate";
89
+ return "weak";
90
+ }
91
+ function buildCouplingInterpretation(jaccard, lift, co) {
92
+ if (jaccard >= 0.6) {
93
+ return `Tight behavioral coupling (Jaccard ${jaccard.toFixed(2)}). These files almost always change together. Likely candidates for a single module.`;
94
+ }
95
+ if (lift >= 5) {
96
+ return `${lift.toFixed(1)}× more likely than random to be touched together (${co} co-occurrences). Hidden dependency worth investigating.`;
97
+ }
98
+ if (jaccard >= 0.3) {
99
+ return `Moderate coupling (Jaccard ${jaccard.toFixed(2)}). Watch for accidental shared state.`;
100
+ }
101
+ return `Weak signal — ${co} shared touches with lift ${lift.toFixed(1)}×.`;
102
+ }
103
+ //# sourceMappingURL=correlation-matrix.js.map