@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.
- package/dist/entities/go-parser.d.ts +47 -0
- package/dist/entities/go-parser.d.ts.map +1 -0
- package/dist/entities/go-parser.js +315 -0
- package/dist/entities/go-parser.js.map +1 -0
- package/dist/entities/go-parser.test.d.ts +2 -0
- package/dist/entities/go-parser.test.d.ts.map +1 -0
- package/dist/entities/go-parser.test.js +147 -0
- package/dist/entities/go-parser.test.js.map +1 -0
- package/dist/entities/index.d.ts +1 -0
- package/dist/entities/index.d.ts.map +1 -1
- package/dist/entities/index.js +1 -0
- package/dist/entities/index.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/indexer/indexer.d.ts +12 -0
- package/dist/indexer/indexer.d.ts.map +1 -1
- package/dist/indexer/indexer.js +28 -1
- package/dist/indexer/indexer.js.map +1 -1
- package/dist/insights/bus-factor.d.ts +58 -0
- package/dist/insights/bus-factor.d.ts.map +1 -0
- package/dist/insights/bus-factor.js +117 -0
- package/dist/insights/bus-factor.js.map +1 -0
- package/dist/insights/bus-factor.test.d.ts +2 -0
- package/dist/insights/bus-factor.test.d.ts.map +1 -0
- package/dist/insights/bus-factor.test.js +149 -0
- package/dist/insights/bus-factor.test.js.map +1 -0
- package/dist/insights/commit-coach.d.ts +80 -0
- package/dist/insights/commit-coach.d.ts.map +1 -0
- package/dist/insights/commit-coach.js +230 -0
- package/dist/insights/commit-coach.js.map +1 -0
- package/dist/insights/commit-coach.test.d.ts +2 -0
- package/dist/insights/commit-coach.test.d.ts.map +1 -0
- package/dist/insights/commit-coach.test.js +163 -0
- package/dist/insights/commit-coach.test.js.map +1 -0
- package/dist/insights/crystal-ball.d.ts +76 -0
- package/dist/insights/crystal-ball.d.ts.map +1 -0
- package/dist/insights/crystal-ball.js +219 -0
- package/dist/insights/crystal-ball.js.map +1 -0
- package/dist/insights/crystal-ball.test.d.ts +2 -0
- package/dist/insights/crystal-ball.test.d.ts.map +1 -0
- package/dist/insights/crystal-ball.test.js +157 -0
- package/dist/insights/crystal-ball.test.js.map +1 -0
- package/dist/insights/decisions.d.ts +38 -0
- package/dist/insights/decisions.d.ts.map +1 -0
- package/dist/insights/decisions.js +125 -0
- package/dist/insights/decisions.js.map +1 -0
- package/dist/insights/decisions.test.d.ts +2 -0
- package/dist/insights/decisions.test.d.ts.map +1 -0
- package/dist/insights/decisions.test.js +141 -0
- package/dist/insights/decisions.test.js.map +1 -0
- package/dist/insights/dream.d.ts +71 -0
- package/dist/insights/dream.d.ts.map +1 -0
- package/dist/insights/dream.js +235 -0
- package/dist/insights/dream.js.map +1 -0
- package/dist/insights/dream.test.d.ts +2 -0
- package/dist/insights/dream.test.d.ts.map +1 -0
- package/dist/insights/dream.test.js +127 -0
- package/dist/insights/dream.test.js.map +1 -0
- package/dist/insights/index.d.ts +21 -0
- package/dist/insights/index.d.ts.map +1 -0
- package/dist/insights/index.js +21 -0
- package/dist/insights/index.js.map +1 -0
- package/dist/insights/obsidian.d.ts +42 -0
- package/dist/insights/obsidian.d.ts.map +1 -0
- package/dist/insights/obsidian.js +263 -0
- package/dist/insights/obsidian.js.map +1 -0
- package/dist/insights/obsidian.test.d.ts +2 -0
- package/dist/insights/obsidian.test.d.ts.map +1 -0
- package/dist/insights/obsidian.test.js +241 -0
- package/dist/insights/obsidian.test.js.map +1 -0
- package/dist/insights/paradox.d.ts +36 -0
- package/dist/insights/paradox.d.ts.map +1 -0
- package/dist/insights/paradox.js +201 -0
- package/dist/insights/paradox.js.map +1 -0
- package/dist/insights/paradox.test.d.ts +2 -0
- package/dist/insights/paradox.test.d.ts.map +1 -0
- package/dist/insights/paradox.test.js +88 -0
- package/dist/insights/paradox.test.js.map +1 -0
- package/dist/insights/regret.d.ts +57 -0
- package/dist/insights/regret.d.ts.map +1 -0
- package/dist/insights/regret.js +137 -0
- package/dist/insights/regret.js.map +1 -0
- package/dist/insights/regret.test.d.ts +2 -0
- package/dist/insights/regret.test.d.ts.map +1 -0
- package/dist/insights/regret.test.js +153 -0
- package/dist/insights/regret.test.js.map +1 -0
- package/dist/insights/stack-trace.d.ts +40 -0
- package/dist/insights/stack-trace.d.ts.map +1 -0
- package/dist/insights/stack-trace.js +127 -0
- package/dist/insights/stack-trace.js.map +1 -0
- package/dist/insights/stack-trace.test.d.ts +2 -0
- package/dist/insights/stack-trace.test.d.ts.map +1 -0
- package/dist/insights/stack-trace.test.js +103 -0
- package/dist/insights/stack-trace.test.js.map +1 -0
- package/dist/insights/story.d.ts +34 -0
- package/dist/insights/story.d.ts.map +1 -0
- package/dist/insights/story.js +100 -0
- package/dist/insights/story.js.map +1 -0
- package/dist/insights/story.test.d.ts +2 -0
- package/dist/insights/story.test.d.ts.map +1 -0
- package/dist/insights/story.test.js +99 -0
- package/dist/insights/story.test.js.map +1 -0
- package/dist/insights/suggest.d.ts +29 -0
- package/dist/insights/suggest.d.ts.map +1 -0
- package/dist/insights/suggest.js +93 -0
- package/dist/insights/suggest.js.map +1 -0
- package/dist/insights/suggest.test.d.ts +2 -0
- package/dist/insights/suggest.test.d.ts.map +1 -0
- package/dist/insights/suggest.test.js +71 -0
- package/dist/insights/suggest.test.js.map +1 -0
- package/dist/insights/who-knows.d.ts +66 -0
- package/dist/insights/who-knows.d.ts.map +1 -0
- package/dist/insights/who-knows.js +125 -0
- package/dist/insights/who-knows.js.map +1 -0
- package/dist/insights/who-knows.test.d.ts +2 -0
- package/dist/insights/who-knows.test.d.ts.map +1 -0
- package/dist/insights/who-knows.test.js +109 -0
- package/dist/insights/who-knows.test.js.map +1 -0
- package/dist/quant/alpha.d.ts +87 -0
- package/dist/quant/alpha.d.ts.map +1 -0
- package/dist/quant/alpha.js +103 -0
- package/dist/quant/alpha.js.map +1 -0
- package/dist/quant/alpha.test.d.ts +2 -0
- package/dist/quant/alpha.test.d.ts.map +1 -0
- package/dist/quant/alpha.test.js +147 -0
- package/dist/quant/alpha.test.js.map +1 -0
- package/dist/quant/backtest.d.ts +57 -0
- package/dist/quant/backtest.d.ts.map +1 -0
- package/dist/quant/backtest.js +90 -0
- package/dist/quant/backtest.js.map +1 -0
- package/dist/quant/backtest.test.d.ts +2 -0
- package/dist/quant/backtest.test.d.ts.map +1 -0
- package/dist/quant/backtest.test.js +133 -0
- package/dist/quant/backtest.test.js.map +1 -0
- package/dist/quant/black-swan.d.ts +45 -0
- package/dist/quant/black-swan.d.ts.map +1 -0
- package/dist/quant/black-swan.js +112 -0
- package/dist/quant/black-swan.js.map +1 -0
- package/dist/quant/black-swan.test.d.ts +2 -0
- package/dist/quant/black-swan.test.d.ts.map +1 -0
- package/dist/quant/black-swan.test.js +131 -0
- package/dist/quant/black-swan.test.js.map +1 -0
- package/dist/quant/correlation-matrix.d.ts +54 -0
- package/dist/quant/correlation-matrix.d.ts.map +1 -0
- package/dist/quant/correlation-matrix.js +103 -0
- package/dist/quant/correlation-matrix.js.map +1 -0
- package/dist/quant/correlation-matrix.test.d.ts +2 -0
- package/dist/quant/correlation-matrix.test.d.ts.map +1 -0
- package/dist/quant/correlation-matrix.test.js +118 -0
- package/dist/quant/correlation-matrix.test.js.map +1 -0
- package/dist/quant/drawdown.d.ts +51 -0
- package/dist/quant/drawdown.d.ts.map +1 -0
- package/dist/quant/drawdown.js +96 -0
- package/dist/quant/drawdown.js.map +1 -0
- package/dist/quant/drawdown.test.d.ts +2 -0
- package/dist/quant/drawdown.test.d.ts.map +1 -0
- package/dist/quant/drawdown.test.js +166 -0
- package/dist/quant/drawdown.test.js.map +1 -0
- package/dist/quant/greek.d.ts +55 -0
- package/dist/quant/greek.d.ts.map +1 -0
- package/dist/quant/greek.js +157 -0
- package/dist/quant/greek.js.map +1 -0
- package/dist/quant/greek.test.d.ts +2 -0
- package/dist/quant/greek.test.d.ts.map +1 -0
- package/dist/quant/greek.test.js +138 -0
- package/dist/quant/greek.test.js.map +1 -0
- package/dist/quant/implied-volatility.d.ts +65 -0
- package/dist/quant/implied-volatility.d.ts.map +1 -0
- package/dist/quant/implied-volatility.js +149 -0
- package/dist/quant/implied-volatility.js.map +1 -0
- package/dist/quant/implied-volatility.test.d.ts +2 -0
- package/dist/quant/implied-volatility.test.d.ts.map +1 -0
- package/dist/quant/implied-volatility.test.js +127 -0
- package/dist/quant/implied-volatility.test.js.map +1 -0
- package/dist/quant/index.d.ts +28 -0
- package/dist/quant/index.d.ts.map +1 -0
- package/dist/quant/index.js +28 -0
- package/dist/quant/index.js.map +1 -0
- package/dist/quant/insider-trading.d.ts +56 -0
- package/dist/quant/insider-trading.d.ts.map +1 -0
- package/dist/quant/insider-trading.js +129 -0
- package/dist/quant/insider-trading.js.map +1 -0
- package/dist/quant/insider-trading.test.d.ts +2 -0
- package/dist/quant/insider-trading.test.d.ts.map +1 -0
- package/dist/quant/insider-trading.test.js +130 -0
- package/dist/quant/insider-trading.test.js.map +1 -0
- package/dist/quant/moneyball.d.ts +48 -0
- package/dist/quant/moneyball.d.ts.map +1 -0
- package/dist/quant/moneyball.js +110 -0
- package/dist/quant/moneyball.js.map +1 -0
- package/dist/quant/moneyball.test.d.ts +2 -0
- package/dist/quant/moneyball.test.d.ts.map +1 -0
- package/dist/quant/moneyball.test.js +137 -0
- package/dist/quant/moneyball.test.js.map +1 -0
- package/dist/quant/tax-loss-harvest.d.ts +59 -0
- package/dist/quant/tax-loss-harvest.d.ts.map +1 -0
- package/dist/quant/tax-loss-harvest.js +126 -0
- package/dist/quant/tax-loss-harvest.js.map +1 -0
- package/dist/quant/tax-loss-harvest.test.d.ts +2 -0
- package/dist/quant/tax-loss-harvest.test.d.ts.map +1 -0
- package/dist/quant/tax-loss-harvest.test.js +126 -0
- package/dist/quant/tax-loss-harvest.test.js.map +1 -0
- package/dist/retrieve/index.d.ts +2 -0
- package/dist/retrieve/index.d.ts.map +1 -1
- package/dist/retrieve/index.js +2 -0
- package/dist/retrieve/index.js.map +1 -1
- package/dist/retrieve/intent.d.ts +32 -0
- package/dist/retrieve/intent.d.ts.map +1 -0
- package/dist/retrieve/intent.js +104 -0
- package/dist/retrieve/intent.js.map +1 -0
- package/dist/retrieve/intent.test.d.ts +2 -0
- package/dist/retrieve/intent.test.d.ts.map +1 -0
- package/dist/retrieve/intent.test.js +106 -0
- package/dist/retrieve/intent.test.js.map +1 -0
- package/dist/retrieve/search.d.ts +30 -0
- package/dist/retrieve/search.d.ts.map +1 -1
- package/dist/retrieve/search.js +48 -0
- package/dist/retrieve/search.js.map +1 -1
- package/dist/retrieve/search.test.js +84 -1
- package/dist/retrieve/search.test.js.map +1 -1
- package/dist/retrieve/synthesize.d.ts +57 -0
- package/dist/retrieve/synthesize.d.ts.map +1 -0
- package/dist/retrieve/synthesize.js +191 -0
- package/dist/retrieve/synthesize.js.map +1 -0
- package/dist/retrieve/synthesize.test.d.ts +2 -0
- package/dist/retrieve/synthesize.test.d.ts.map +1 -0
- package/dist/retrieve/synthesize.test.js +127 -0
- package/dist/retrieve/synthesize.test.js.map +1 -0
- package/dist/store/schema.d.ts +2 -2
- package/dist/store/schema.d.ts.map +1 -1
- package/dist/store/schema.js +60 -2
- package/dist/store/schema.js.map +1 -1
- package/dist/store/sqlite.d.ts +2 -0
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +24 -0
- package/dist/store/sqlite.js.map +1 -1
- package/dist/store/sqlite.test.js +1 -1
- package/dist/util/index.d.ts +2 -0
- package/dist/util/index.d.ts.map +1 -1
- package/dist/util/index.js +2 -1
- package/dist/util/index.js.map +1 -1
- package/dist/util/redact.d.ts +58 -0
- package/dist/util/redact.d.ts.map +1 -0
- package/dist/util/redact.js +129 -0
- package/dist/util/redact.js.map +1 -0
- package/dist/util/redact.test.d.ts +2 -0
- package/dist/util/redact.test.d.ts.map +1 -0
- package/dist/util/redact.test.js +148 -0
- package/dist/util/redact.test.js.map +1 -0
- package/dist/wisdom/calibrator.d.ts +43 -0
- package/dist/wisdom/calibrator.d.ts.map +1 -0
- package/dist/wisdom/calibrator.js +120 -0
- package/dist/wisdom/calibrator.js.map +1 -0
- package/dist/wisdom/feedback.d.ts +45 -0
- package/dist/wisdom/feedback.d.ts.map +1 -0
- package/dist/wisdom/feedback.js +116 -0
- package/dist/wisdom/feedback.js.map +1 -0
- package/dist/wisdom/index.d.ts +15 -0
- package/dist/wisdom/index.d.ts.map +1 -0
- package/dist/wisdom/index.js +15 -0
- package/dist/wisdom/index.js.map +1 -0
- package/dist/wisdom/types.d.ts +67 -0
- package/dist/wisdom/types.d.ts.map +1 -0
- package/dist/wisdom/types.js +20 -0
- package/dist/wisdom/types.js.map +1 -0
- package/dist/wisdom/wisdom.test.d.ts +2 -0
- package/dist/wisdom/wisdom.test.d.ts.map +1 -0
- package/dist/wisdom/wisdom.test.js +144 -0
- package/dist/wisdom/wisdom.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mneme greek` — sensitivity analysis (Δ Γ Θ ν) for a codebase.
|
|
3
|
+
*
|
|
4
|
+
* Δ DELTA — sensitivity to the top contributor (% knowledge lost if X quits)
|
|
5
|
+
* Γ GAMMA — acceleration of risk (super-linear scaling of bug rate vs PR rate)
|
|
6
|
+
* Θ THETA — time decay (untouched files lose coverage over time)
|
|
7
|
+
* ν VEGA — sensitivity to dependency volatility (placeholder for now)
|
|
8
|
+
*
|
|
9
|
+
* Pure analysis. Delta + Gamma are required and computed from store data.
|
|
10
|
+
* Theta is best-effort (depends on coverage indexed). Vega returns null
|
|
11
|
+
* unless dependency manifest data is available — honestly.
|
|
12
|
+
*/
|
|
13
|
+
export function computeDelta(store, opts = {}) {
|
|
14
|
+
const topN = opts.topN ?? 5;
|
|
15
|
+
// Pull file-author distribution.
|
|
16
|
+
const rows = store.db
|
|
17
|
+
.prepare(`SELECT
|
|
18
|
+
fc.path AS path,
|
|
19
|
+
c.author_name AS author_name,
|
|
20
|
+
c.author_email AS author_email,
|
|
21
|
+
COUNT(*) AS touches
|
|
22
|
+
FROM file_changes fc
|
|
23
|
+
JOIN commits c ON c.hash = fc.commit_hash
|
|
24
|
+
GROUP BY fc.path, c.author_name, c.author_email`)
|
|
25
|
+
.all();
|
|
26
|
+
// Per-file totals.
|
|
27
|
+
const fileTotals = new Map();
|
|
28
|
+
for (const r of rows)
|
|
29
|
+
fileTotals.set(r.path, (fileTotals.get(r.path) ?? 0) + r.touches);
|
|
30
|
+
// Per-(file, author) — find top owner per file.
|
|
31
|
+
const topOwnerPerFile = new Map();
|
|
32
|
+
for (const r of rows) {
|
|
33
|
+
const cur = topOwnerPerFile.get(r.path);
|
|
34
|
+
if (!cur || r.touches > cur.touches) {
|
|
35
|
+
topOwnerPerFile.set(r.path, { name: r.author_name, email: r.author_email, touches: r.touches });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const byAuthor = new Map();
|
|
39
|
+
let totalFiles = 0;
|
|
40
|
+
for (const [file, top] of topOwnerPerFile) {
|
|
41
|
+
totalFiles += 1;
|
|
42
|
+
const total = fileTotals.get(file) ?? 1;
|
|
43
|
+
if (top.touches / total < 0.75)
|
|
44
|
+
continue;
|
|
45
|
+
const key = `${top.name}|${top.email}`;
|
|
46
|
+
if (!byAuthor.has(key))
|
|
47
|
+
byAuthor.set(key, { name: top.name, email: top.email, ownedFiles: [] });
|
|
48
|
+
byAuthor.get(key).ownedFiles.push(file);
|
|
49
|
+
}
|
|
50
|
+
const results = [];
|
|
51
|
+
for (const b of byAuthor.values()) {
|
|
52
|
+
const knowledgeLossPct = totalFiles === 0 ? 0 : Math.round((b.ownedFiles.length / totalFiles) * 100);
|
|
53
|
+
results.push({
|
|
54
|
+
name: b.name,
|
|
55
|
+
email: b.email,
|
|
56
|
+
ownedFiles: b.ownedFiles,
|
|
57
|
+
knowledgeLossPct,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
results.sort((a, b) => b.ownedFiles.length - a.ownedFiles.length);
|
|
61
|
+
return results.slice(0, topN);
|
|
62
|
+
}
|
|
63
|
+
const FIX_RE = /^(fix|hotfix|bug|revert|patch)[(:]/i;
|
|
64
|
+
export function computeGamma(store) {
|
|
65
|
+
const commitRows = store.db
|
|
66
|
+
.prepare(`SELECT subject, author_date FROM commits`)
|
|
67
|
+
.all();
|
|
68
|
+
if (commitRows.length === 0) {
|
|
69
|
+
return { riskAcceleration: 0, weeks: 0, interpretation: "No commits indexed yet." };
|
|
70
|
+
}
|
|
71
|
+
// Bucket by ISO week.
|
|
72
|
+
const buckets = new Map();
|
|
73
|
+
for (const r of commitRows) {
|
|
74
|
+
const week = isoWeek(new Date(r.author_date));
|
|
75
|
+
if (!buckets.has(week))
|
|
76
|
+
buckets.set(week, { total: 0, fixes: 0 });
|
|
77
|
+
const b = buckets.get(week);
|
|
78
|
+
b.total += 1;
|
|
79
|
+
if (FIX_RE.test(r.subject))
|
|
80
|
+
b.fixes += 1;
|
|
81
|
+
}
|
|
82
|
+
// Linear regression: x = total commits, y = fix commits.
|
|
83
|
+
const points = [...buckets.values()].filter((b) => b.total > 0);
|
|
84
|
+
if (points.length < 3) {
|
|
85
|
+
return {
|
|
86
|
+
riskAcceleration: 0,
|
|
87
|
+
weeks: points.length,
|
|
88
|
+
interpretation: `Only ${points.length} weeks of data — need 3+ for meaningful gamma.`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const n = points.length;
|
|
92
|
+
const sumX = points.reduce((s, p) => s + p.total, 0);
|
|
93
|
+
const sumY = points.reduce((s, p) => s + p.fixes, 0);
|
|
94
|
+
const sumXY = points.reduce((s, p) => s + p.total * p.fixes, 0);
|
|
95
|
+
const sumX2 = points.reduce((s, p) => s + p.total * p.total, 0);
|
|
96
|
+
const denom = n * sumX2 - sumX * sumX;
|
|
97
|
+
const slope = denom === 0 ? 0 : (n * sumXY - sumX * sumY) / denom;
|
|
98
|
+
return {
|
|
99
|
+
riskAcceleration: Math.round(slope * 1000) / 1000,
|
|
100
|
+
weeks: n,
|
|
101
|
+
interpretation: buildGammaInterpretation(slope, n),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function buildGammaInterpretation(slope, weeks) {
|
|
105
|
+
if (slope > 0.3) {
|
|
106
|
+
return `Super-linear risk: each extra commit per week adds ${(slope * 100).toFixed(0)}% more fixes. Scaling team velocity will likely increase bug rate disproportionately.`;
|
|
107
|
+
}
|
|
108
|
+
if (slope > 0.15) {
|
|
109
|
+
return `Risk scales linearly with velocity (slope ${slope.toFixed(2)}). Sustainable but watch for super-linear inflection.`;
|
|
110
|
+
}
|
|
111
|
+
return `Low risk acceleration (slope ${slope.toFixed(2)}). Velocity does not strongly predict bug rate over ${weeks} weeks.`;
|
|
112
|
+
}
|
|
113
|
+
function isoWeek(d) {
|
|
114
|
+
// ISO week format: YYYY-Www
|
|
115
|
+
const target = new Date(d.valueOf());
|
|
116
|
+
const dayNr = (d.getUTCDay() + 6) % 7;
|
|
117
|
+
target.setUTCDate(target.getUTCDate() - dayNr + 3);
|
|
118
|
+
const firstThursday = target.valueOf();
|
|
119
|
+
target.setUTCMonth(0, 1);
|
|
120
|
+
if (target.getUTCDay() !== 4) {
|
|
121
|
+
target.setUTCMonth(0, 1 + ((4 - target.getUTCDay() + 7) % 7));
|
|
122
|
+
}
|
|
123
|
+
const weekNumber = 1 + Math.ceil((firstThursday - target.valueOf()) / (7 * 86_400_000));
|
|
124
|
+
return `${d.getUTCFullYear()}-W${String(weekNumber).padStart(2, "0")}`;
|
|
125
|
+
}
|
|
126
|
+
export function computeTheta(store, opts = {}) {
|
|
127
|
+
const now = opts.now ?? new Date();
|
|
128
|
+
const rows = store.db
|
|
129
|
+
.prepare(`SELECT fc.path, MAX(c.author_date) AS last_touch
|
|
130
|
+
FROM file_changes fc
|
|
131
|
+
JOIN commits c ON c.hash = fc.commit_hash
|
|
132
|
+
GROUP BY fc.path`)
|
|
133
|
+
.all();
|
|
134
|
+
const STALE_DAYS = 180;
|
|
135
|
+
const staleAges = [];
|
|
136
|
+
for (const r of rows) {
|
|
137
|
+
const days = (now.getTime() - new Date(r.last_touch).getTime()) / 86_400_000;
|
|
138
|
+
if (days >= STALE_DAYS)
|
|
139
|
+
staleAges.push(days);
|
|
140
|
+
}
|
|
141
|
+
const avg = staleAges.length === 0 ? 0 : Math.round(staleAges.reduce((s, x) => s + x, 0) / staleAges.length);
|
|
142
|
+
return {
|
|
143
|
+
staleFiles: staleAges.length,
|
|
144
|
+
avgStaleDays: avg,
|
|
145
|
+
interpretation: staleAges.length === 0
|
|
146
|
+
? "No stale files — codebase is recently active."
|
|
147
|
+
: `${staleAges.length} files untouched for ≥ 6 months (avg ${avg} days). Schedule review or remove via mneme tax-loss-harvest.`,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
export function computeGreeks(store, opts = {}) {
|
|
151
|
+
return {
|
|
152
|
+
delta: computeDelta(store),
|
|
153
|
+
gamma: computeGamma(store),
|
|
154
|
+
theta: computeTheta(store, opts),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=greek.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"greek.js","sourceRoot":"","sources":["../../src/quant/greek.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"greek.test.d.ts","sourceRoot":"","sources":["../../src/quant/greek.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,138 @@
|
|
|
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 { computeDelta, computeGamma, computeTheta, computeGreeks } from "./greek.js";
|
|
7
|
+
let tmpDir;
|
|
8
|
+
let store;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
tmpDir = mkdtempSync(join(tmpdir(), "mneme-greek-"));
|
|
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, author, date, subject, files) => ({
|
|
18
|
+
hash,
|
|
19
|
+
shortHash: hash.slice(0, 7),
|
|
20
|
+
authorName: author,
|
|
21
|
+
authorEmail: `${author}@x`,
|
|
22
|
+
authorDate: `${date}T00:00:00Z`,
|
|
23
|
+
committerDate: `${date}T00:00:00Z`,
|
|
24
|
+
subject,
|
|
25
|
+
body: "",
|
|
26
|
+
parents: [],
|
|
27
|
+
files,
|
|
28
|
+
});
|
|
29
|
+
function seed(commits) {
|
|
30
|
+
store.upsertCommits(commits);
|
|
31
|
+
for (const c of commits) {
|
|
32
|
+
store.upsertFileChanges(c.files.map((f) => ({ commitHash: c.hash, path: f, changeKind: "M", insertions: 1, deletions: 0 })));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
describe("computeDelta — knowledge loss per top contributor", () => {
|
|
36
|
+
it("flags author who owns ≥ 75% of a file", () => {
|
|
37
|
+
seed([
|
|
38
|
+
cmt("a1", "alice", "2024-08-01", "x", ["src/auth.ts"]),
|
|
39
|
+
cmt("a2", "alice", "2024-08-02", "x", ["src/auth.ts"]),
|
|
40
|
+
cmt("a3", "alice", "2024-08-03", "x", ["src/auth.ts"]),
|
|
41
|
+
cmt("b1", "bob", "2024-08-04", "x", ["src/auth.ts"]),
|
|
42
|
+
]);
|
|
43
|
+
const result = computeDelta(store);
|
|
44
|
+
const alice = result.find((d) => d.name === "alice");
|
|
45
|
+
expect(alice).toBeDefined();
|
|
46
|
+
expect(alice.ownedFiles).toContain("src/auth.ts");
|
|
47
|
+
});
|
|
48
|
+
it("does NOT flag when no author dominates ≥ 75%", () => {
|
|
49
|
+
seed([
|
|
50
|
+
cmt("a1", "alice", "2024-08-01", "x", ["src/x.ts"]),
|
|
51
|
+
cmt("a2", "alice", "2024-08-02", "x", ["src/x.ts"]),
|
|
52
|
+
cmt("b1", "bob", "2024-08-03", "x", ["src/x.ts"]),
|
|
53
|
+
cmt("b2", "bob", "2024-08-04", "x", ["src/x.ts"]),
|
|
54
|
+
]);
|
|
55
|
+
const result = computeDelta(store);
|
|
56
|
+
expect(result.length === 0 || result.every((r) => !r.ownedFiles.includes("src/x.ts"))).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
it("computes knowledgeLossPct as fraction of total files", () => {
|
|
59
|
+
seed([
|
|
60
|
+
cmt("a1", "alice", "2024-08-01", "x", ["src/a.ts"]),
|
|
61
|
+
cmt("a2", "alice", "2024-08-02", "x", ["src/a.ts"]),
|
|
62
|
+
cmt("a3", "alice", "2024-08-03", "x", ["src/a.ts"]),
|
|
63
|
+
cmt("b1", "bob", "2024-08-04", "x", ["src/b.ts"]),
|
|
64
|
+
]);
|
|
65
|
+
const result = computeDelta(store);
|
|
66
|
+
const alice = result.find((d) => d.name === "alice");
|
|
67
|
+
// alice owns 1 of 2 total files = 50%
|
|
68
|
+
expect(alice.knowledgeLossPct).toBe(50);
|
|
69
|
+
});
|
|
70
|
+
it("respects topN cap", () => {
|
|
71
|
+
const commits = [];
|
|
72
|
+
for (let i = 0; i < 30; i++) {
|
|
73
|
+
const day = String((i % 28) + 1).padStart(2, "0");
|
|
74
|
+
commits.push(cmt(`a${i}`.padEnd(7, "x"), `dev${i}`, `2024-08-${day}`, "x", [`f${i}.ts`]));
|
|
75
|
+
}
|
|
76
|
+
seed(commits);
|
|
77
|
+
expect(computeDelta(store, { topN: 5 }).length).toBeLessThanOrEqual(5);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe("computeGamma — risk acceleration via linear regression", () => {
|
|
81
|
+
it("returns 0 with helpful message when too few weeks", () => {
|
|
82
|
+
seed([cmt("a1", "alice", "2024-08-01", "feat: x", [])]);
|
|
83
|
+
const g = computeGamma(store);
|
|
84
|
+
expect(g.weeks).toBeLessThanOrEqual(1);
|
|
85
|
+
expect(g.interpretation.toLowerCase()).toMatch(/no commits|need|few/);
|
|
86
|
+
});
|
|
87
|
+
it("super-linear interpretation when slope > 0.3", () => {
|
|
88
|
+
// Construct weeks where fix count grows fast with total
|
|
89
|
+
const commits = [];
|
|
90
|
+
// Week 1: 2 commits, 0 fixes
|
|
91
|
+
commits.push(cmt("c1", "a", "2024-01-01", "feat: x", []));
|
|
92
|
+
commits.push(cmt("c2", "a", "2024-01-02", "feat: y", []));
|
|
93
|
+
// Week 2: 4 commits, 1 fix
|
|
94
|
+
commits.push(cmt("c3", "a", "2024-01-08", "feat: 1", []));
|
|
95
|
+
commits.push(cmt("c4", "a", "2024-01-09", "feat: 2", []));
|
|
96
|
+
commits.push(cmt("c5", "a", "2024-01-10", "feat: 3", []));
|
|
97
|
+
commits.push(cmt("c6", "a", "2024-01-11", "fix: 1", []));
|
|
98
|
+
// Week 3: 8 commits, 4 fixes
|
|
99
|
+
for (let i = 0; i < 4; i++)
|
|
100
|
+
commits.push(cmt(`f${i}`.padEnd(7, "x"), "a", `2024-01-${15 + i}`, "feat", []));
|
|
101
|
+
for (let i = 0; i < 4; i++)
|
|
102
|
+
commits.push(cmt(`x${i}`.padEnd(7, "x"), "a", `2024-01-${15 + i}`, "fix: y", []));
|
|
103
|
+
seed(commits);
|
|
104
|
+
const g = computeGamma(store);
|
|
105
|
+
expect(g.weeks).toBeGreaterThanOrEqual(3);
|
|
106
|
+
expect(g.riskAcceleration).toBeGreaterThan(0);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe("computeTheta — time decay / stale files", () => {
|
|
110
|
+
it("counts files untouched for ≥ 6 months", () => {
|
|
111
|
+
seed([
|
|
112
|
+
cmt("a1", "alice", "2024-01-01", "x", ["src/legacy.ts"]),
|
|
113
|
+
cmt("a2", "alice", "2024-08-01", "x", ["src/active.ts"]),
|
|
114
|
+
]);
|
|
115
|
+
const theta = computeTheta(store, { now: new Date("2024-12-01T00:00:00Z") });
|
|
116
|
+
expect(theta.staleFiles).toBe(1);
|
|
117
|
+
expect(theta.avgStaleDays).toBeGreaterThan(180);
|
|
118
|
+
});
|
|
119
|
+
it("returns zero when all files are recently touched", () => {
|
|
120
|
+
seed([
|
|
121
|
+
cmt("a1", "alice", "2024-11-01", "x", ["src/x.ts"]),
|
|
122
|
+
cmt("a2", "alice", "2024-11-02", "x", ["src/y.ts"]),
|
|
123
|
+
]);
|
|
124
|
+
const theta = computeTheta(store, { now: new Date("2024-12-01T00:00:00Z") });
|
|
125
|
+
expect(theta.staleFiles).toBe(0);
|
|
126
|
+
expect(theta.interpretation.toLowerCase()).toMatch(/recently|no stale/);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe("computeGreeks — composite report", () => {
|
|
130
|
+
it("returns all three (delta, gamma, theta)", () => {
|
|
131
|
+
seed([cmt("a1", "alice", "2024-08-01", "feat: x", ["src/x.ts"])]);
|
|
132
|
+
const r = computeGreeks(store);
|
|
133
|
+
expect(r.delta).toBeDefined();
|
|
134
|
+
expect(r.gamma).toBeDefined();
|
|
135
|
+
expect(r.theta).toBeDefined();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
//# sourceMappingURL=greek.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"greek.test.js","sourceRoot":"","sources":["../../src/quant/greek.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mneme implied-volatility` — predict project chaos from commit message TONE.
|
|
3
|
+
*
|
|
4
|
+
* Wall Street's "implied volatility" measures market expectation of future
|
|
5
|
+
* turbulence FROM option prices, before realized volatility shows up in
|
|
6
|
+
* actual price moves. We do the same with commit messages: signals that
|
|
7
|
+
* predict bug-rate spikes BEFORE the bugs actually land.
|
|
8
|
+
*
|
|
9
|
+
* Tone signals (per commit):
|
|
10
|
+
* • exclamation density: !!! → urgency
|
|
11
|
+
* • all-caps words: BROKEN, ARGH → frustration
|
|
12
|
+
* • emoji density: 🔥💀⚠️ → emotional load
|
|
13
|
+
* • profanity (mild): wtf, ugh → friction
|
|
14
|
+
* • hedging language: "kinda", "should work?", "maybe" → uncertainty
|
|
15
|
+
*
|
|
16
|
+
* Aggregate per week → IV index (0-100). Backtests against subsequent
|
|
17
|
+
* fix-commit rate to validate.
|
|
18
|
+
*/
|
|
19
|
+
import type { Commit } from "../types.js";
|
|
20
|
+
export interface CommitTone {
|
|
21
|
+
/** Hash of the commit. */
|
|
22
|
+
hash: string;
|
|
23
|
+
date: string;
|
|
24
|
+
/** Number of consecutive '!' marks. */
|
|
25
|
+
exclamationScore: number;
|
|
26
|
+
/** Number of all-caps words (≥ 3 chars). */
|
|
27
|
+
allCapsScore: number;
|
|
28
|
+
/** Estimated number of emoji code points. */
|
|
29
|
+
emojiScore: number;
|
|
30
|
+
/** Mild-profanity / frustration markers. */
|
|
31
|
+
frictionScore: number;
|
|
32
|
+
/** Hedging / uncertainty markers. */
|
|
33
|
+
hedgeScore: number;
|
|
34
|
+
/** Aggregate tone (0..1) — calibrated weight of all signals. */
|
|
35
|
+
toneScore: number;
|
|
36
|
+
}
|
|
37
|
+
export interface VolatilityWindow {
|
|
38
|
+
/** ISO week label e.g. "2024-W32". */
|
|
39
|
+
week: string;
|
|
40
|
+
/** Average tone across commits in this window. */
|
|
41
|
+
avgTone: number;
|
|
42
|
+
/** Number of commits in the window. */
|
|
43
|
+
commitCount: number;
|
|
44
|
+
/** Volatility index (0..100) = avgTone × 100. */
|
|
45
|
+
iv: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Score the tone of a single commit subject + body. Pure function.
|
|
49
|
+
*/
|
|
50
|
+
export declare function scoreTone(c: Commit): CommitTone;
|
|
51
|
+
/**
|
|
52
|
+
* Aggregate tones into weekly volatility windows.
|
|
53
|
+
*/
|
|
54
|
+
export declare function impliedVolatility(commits: Commit[]): VolatilityWindow[];
|
|
55
|
+
export interface VolatilitySummary {
|
|
56
|
+
windows: VolatilityWindow[];
|
|
57
|
+
/** Latest IV (most recent week). */
|
|
58
|
+
latestIV: number;
|
|
59
|
+
/** Trend over the last 4 weeks: rising / falling / flat. */
|
|
60
|
+
trend: "rising" | "falling" | "flat" | "insufficient-data";
|
|
61
|
+
/** A 1-line interpretation. */
|
|
62
|
+
interpretation: string;
|
|
63
|
+
}
|
|
64
|
+
export declare function summarizeVolatility(commits: Commit[]): VolatilitySummary;
|
|
65
|
+
//# sourceMappingURL=implied-volatility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"implied-volatility.d.ts","sourceRoot":"","sources":["../../src/quant/implied-volatility.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,UAAU;IACzB,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,gBAAgB,EAAE,MAAM,CAAC;IACzB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,aAAa,EAAE,MAAM,CAAC;IACtB,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,EAAE,EAAE,MAAM,CAAC;CACZ;AAmBD;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAmD/C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAwBvE;AAeD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,mBAAmB,CAAC;IAC3D,+BAA+B;IAC/B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAexE"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mneme implied-volatility` — predict project chaos from commit message TONE.
|
|
3
|
+
*
|
|
4
|
+
* Wall Street's "implied volatility" measures market expectation of future
|
|
5
|
+
* turbulence FROM option prices, before realized volatility shows up in
|
|
6
|
+
* actual price moves. We do the same with commit messages: signals that
|
|
7
|
+
* predict bug-rate spikes BEFORE the bugs actually land.
|
|
8
|
+
*
|
|
9
|
+
* Tone signals (per commit):
|
|
10
|
+
* • exclamation density: !!! → urgency
|
|
11
|
+
* • all-caps words: BROKEN, ARGH → frustration
|
|
12
|
+
* • emoji density: 🔥💀⚠️ → emotional load
|
|
13
|
+
* • profanity (mild): wtf, ugh → friction
|
|
14
|
+
* • hedging language: "kinda", "should work?", "maybe" → uncertainty
|
|
15
|
+
*
|
|
16
|
+
* Aggregate per week → IV index (0-100). Backtests against subsequent
|
|
17
|
+
* fix-commit rate to validate.
|
|
18
|
+
*/
|
|
19
|
+
const FRICTION_WORDS = new Set([
|
|
20
|
+
"wtf", "ugh", "argh", "ffs", "damn", "shit", "fuck", "fucking",
|
|
21
|
+
"wth", "omg", "yikes", "oof", "ouch",
|
|
22
|
+
"broken", "borked", "fucked", "cursed",
|
|
23
|
+
]);
|
|
24
|
+
const HEDGE_WORDS = new Set([
|
|
25
|
+
"maybe", "probably", "kinda", "sorta", "perhaps",
|
|
26
|
+
"should", "might", "could", "hopefully", "fingers",
|
|
27
|
+
"untested", "experimental", "tentative", "wip",
|
|
28
|
+
]);
|
|
29
|
+
const ALL_CAPS_WORD_RE = /\b[A-Z]{3,}\b/g;
|
|
30
|
+
const EXCLAMATION_RE = /!+/g;
|
|
31
|
+
// Heuristic emoji match: any code point ≥ U+2600 not in regular Latin block
|
|
32
|
+
const EMOJI_RE = /[\u{1F300}-\u{1FAFF}\u{2600}-\u{27BF}]/gu;
|
|
33
|
+
/**
|
|
34
|
+
* Score the tone of a single commit subject + body. Pure function.
|
|
35
|
+
*/
|
|
36
|
+
export function scoreTone(c) {
|
|
37
|
+
const text = `${c.subject} ${c.body || ""}`;
|
|
38
|
+
// Exclamation density: count sequences of '!' (any count of !!!! is one event).
|
|
39
|
+
let exMatches = 0;
|
|
40
|
+
for (const m of text.matchAll(EXCLAMATION_RE)) {
|
|
41
|
+
exMatches += m[0].length; // double-count !!!!
|
|
42
|
+
}
|
|
43
|
+
// All-caps words.
|
|
44
|
+
const capMatches = text.match(ALL_CAPS_WORD_RE) ?? [];
|
|
45
|
+
const allCapsScore = capMatches.length;
|
|
46
|
+
// Emoji.
|
|
47
|
+
const emoji = text.match(EMOJI_RE) ?? [];
|
|
48
|
+
// Friction words.
|
|
49
|
+
const lower = text.toLowerCase();
|
|
50
|
+
let frictionScore = 0;
|
|
51
|
+
for (const w of FRICTION_WORDS) {
|
|
52
|
+
const re = new RegExp(`\\b${w}\\b`, "g");
|
|
53
|
+
const m = lower.match(re);
|
|
54
|
+
if (m)
|
|
55
|
+
frictionScore += m.length;
|
|
56
|
+
}
|
|
57
|
+
// Hedge words.
|
|
58
|
+
let hedgeScore = 0;
|
|
59
|
+
for (const w of HEDGE_WORDS) {
|
|
60
|
+
const re = new RegExp(`\\b${w}\\b`, "g");
|
|
61
|
+
const m = lower.match(re);
|
|
62
|
+
if (m)
|
|
63
|
+
hedgeScore += m.length;
|
|
64
|
+
}
|
|
65
|
+
// Calibrated tone score (0..1).
|
|
66
|
+
const raw = 0.25 * Math.min(exMatches, 5) / 5 +
|
|
67
|
+
0.20 * Math.min(allCapsScore, 5) / 5 +
|
|
68
|
+
0.15 * Math.min(emoji.length, 5) / 5 +
|
|
69
|
+
0.25 * Math.min(frictionScore, 3) / 3 +
|
|
70
|
+
0.15 * Math.min(hedgeScore, 3) / 3;
|
|
71
|
+
return {
|
|
72
|
+
hash: c.hash,
|
|
73
|
+
date: c.authorDate.slice(0, 10),
|
|
74
|
+
exclamationScore: exMatches,
|
|
75
|
+
allCapsScore,
|
|
76
|
+
emojiScore: emoji.length,
|
|
77
|
+
frictionScore,
|
|
78
|
+
hedgeScore,
|
|
79
|
+
toneScore: Math.min(1, raw),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Aggregate tones into weekly volatility windows.
|
|
84
|
+
*/
|
|
85
|
+
export function impliedVolatility(commits) {
|
|
86
|
+
if (commits.length === 0)
|
|
87
|
+
return [];
|
|
88
|
+
const tones = commits.map(scoreTone);
|
|
89
|
+
const buckets = new Map();
|
|
90
|
+
for (const t of tones) {
|
|
91
|
+
const week = isoWeek(new Date(t.date));
|
|
92
|
+
if (!buckets.has(week))
|
|
93
|
+
buckets.set(week, { sum: 0, count: 0 });
|
|
94
|
+
const b = buckets.get(week);
|
|
95
|
+
b.sum += t.toneScore;
|
|
96
|
+
b.count += 1;
|
|
97
|
+
}
|
|
98
|
+
const windows = [];
|
|
99
|
+
for (const [week, b] of buckets) {
|
|
100
|
+
const avgTone = b.sum / b.count;
|
|
101
|
+
windows.push({
|
|
102
|
+
week,
|
|
103
|
+
avgTone: Math.round(avgTone * 1000) / 1000,
|
|
104
|
+
commitCount: b.count,
|
|
105
|
+
iv: Math.round(avgTone * 100),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
windows.sort((a, b) => a.week.localeCompare(b.week));
|
|
109
|
+
return windows;
|
|
110
|
+
}
|
|
111
|
+
function isoWeek(d) {
|
|
112
|
+
const target = new Date(d.valueOf());
|
|
113
|
+
const dayNr = (d.getUTCDay() + 6) % 7;
|
|
114
|
+
target.setUTCDate(target.getUTCDate() - dayNr + 3);
|
|
115
|
+
const firstThursday = target.valueOf();
|
|
116
|
+
target.setUTCMonth(0, 1);
|
|
117
|
+
if (target.getUTCDay() !== 4) {
|
|
118
|
+
target.setUTCMonth(0, 1 + ((4 - target.getUTCDay() + 7) % 7));
|
|
119
|
+
}
|
|
120
|
+
const weekNumber = 1 + Math.ceil((firstThursday - target.valueOf()) / (7 * 86_400_000));
|
|
121
|
+
return `${d.getUTCFullYear()}-W${String(weekNumber).padStart(2, "0")}`;
|
|
122
|
+
}
|
|
123
|
+
export function summarizeVolatility(commits) {
|
|
124
|
+
const windows = impliedVolatility(commits);
|
|
125
|
+
if (windows.length === 0) {
|
|
126
|
+
return { windows: [], latestIV: 0, trend: "insufficient-data", interpretation: "No commits indexed." };
|
|
127
|
+
}
|
|
128
|
+
const latest = windows[windows.length - 1].iv;
|
|
129
|
+
let trend = "insufficient-data";
|
|
130
|
+
if (windows.length >= 4) {
|
|
131
|
+
const recent = windows.slice(-4).map((w) => w.iv);
|
|
132
|
+
const first = recent[0];
|
|
133
|
+
const last = recent[recent.length - 1];
|
|
134
|
+
const delta = last - first;
|
|
135
|
+
trend = delta > 5 ? "rising" : delta < -5 ? "falling" : "flat";
|
|
136
|
+
}
|
|
137
|
+
return { windows, latestIV: latest, trend, interpretation: buildVolInterpretation(latest, trend) };
|
|
138
|
+
}
|
|
139
|
+
function buildVolInterpretation(iv, trend) {
|
|
140
|
+
if (trend === "rising" && iv >= 30) {
|
|
141
|
+
return `IV is ${iv} (rising) — commit message tone is signaling stress. Expect more bug fixes in the next 1-2 weeks.`;
|
|
142
|
+
}
|
|
143
|
+
if (iv >= 50)
|
|
144
|
+
return `IV is ${iv} (very high). Team is in firefighting mode.`;
|
|
145
|
+
if (iv <= 10 && trend === "flat")
|
|
146
|
+
return `IV is ${iv} (low + flat). Calm waters; commits are unemotional.`;
|
|
147
|
+
return `IV is ${iv} (${trend}). Watch for rising trends as a leading indicator of bugs.`;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=implied-volatility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"implied-volatility.js","sourceRoot":"","sources":["../../src/quant/implied-volatility.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"implied-volatility.test.d.ts","sourceRoot":"","sources":["../../src/quant/implied-volatility.test.ts"],"names":[],"mappings":""}
|