@mneme-ai/core 0.9.0 → 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/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.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/index.d.ts +5 -0
- package/dist/insights/index.d.ts.map +1 -1
- package/dist/insights/index.js +5 -0
- package/dist/insights/index.js.map +1 -1
- 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/who-knows.d.ts +18 -0
- package/dist/insights/who-knows.d.ts.map +1 -1
- package/dist/insights/who-knows.js +29 -0
- package/dist/insights/who-knows.js.map +1 -1
- package/dist/insights/who-knows.test.js +63 -1
- package/dist/insights/who-knows.test.js.map +1 -1
- 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/synthesize.d.ts.map +1 -1
- package/dist/retrieve/synthesize.js +56 -25
- package/dist/retrieve/synthesize.js.map +1 -1
- package/dist/retrieve/synthesize.test.js +26 -15
- package/dist/retrieve/synthesize.test.js.map +1 -1
- package/dist/store/schema.d.ts +2 -2
- package/dist/store/schema.d.ts.map +1 -1
- package/dist/store/schema.js +6 -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/package.json +1 -1
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { detectRegrets, summarizeRegrets } from "./regret.js";
|
|
3
|
+
const cmt = (hash, date, subject, body = "", files = []) => ({
|
|
4
|
+
hash,
|
|
5
|
+
shortHash: hash.slice(0, 7),
|
|
6
|
+
authorName: "alice",
|
|
7
|
+
authorEmail: "alice@x",
|
|
8
|
+
authorDate: `${date}T12:00:00Z`,
|
|
9
|
+
committerDate: `${date}T12:00:00Z`,
|
|
10
|
+
subject,
|
|
11
|
+
body,
|
|
12
|
+
parents: [],
|
|
13
|
+
files,
|
|
14
|
+
});
|
|
15
|
+
describe("detectRegrets — revert (strongest signal)", () => {
|
|
16
|
+
it("detects explicit revert that names the shipped commit hash", () => {
|
|
17
|
+
const commits = [
|
|
18
|
+
cmt("a1b2c3d", "2024-08-01", "feat: enable HTTP/3", "", ["src/edge.ts"]),
|
|
19
|
+
cmt("e4f5g6h", "2024-08-03", "Revert \"feat: enable HTTP/3\"", "Reverts a1b2c3d — broke mobile", ["src/edge.ts"]),
|
|
20
|
+
];
|
|
21
|
+
const regrets = detectRegrets(commits, { windowDays: 7 });
|
|
22
|
+
expect(regrets).toHaveLength(1);
|
|
23
|
+
expect(regrets[0].kind).toBe("revert");
|
|
24
|
+
expect(regrets[0].daysToFix).toBeCloseTo(2, 0);
|
|
25
|
+
});
|
|
26
|
+
it("detects revert from shared-files heuristic when subject is generic", () => {
|
|
27
|
+
const commits = [
|
|
28
|
+
cmt("a1", "2024-08-01", "feat: new caching", "", ["src/cache.ts"]),
|
|
29
|
+
cmt("a2", "2024-08-04", "revert caching change", "", ["src/cache.ts"]),
|
|
30
|
+
];
|
|
31
|
+
expect(detectRegrets(commits)[0].kind).toBe("revert");
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe("detectRegrets — hotfix and fix kinds", () => {
|
|
35
|
+
it("flags hotfix when follow-up has 'hotfix' marker AND shares files", () => {
|
|
36
|
+
const commits = [
|
|
37
|
+
cmt("a1", "2024-08-01", "refactor: simplify session middleware", "", ["src/auth.ts"]),
|
|
38
|
+
cmt("a2", "2024-08-01", "hotfix: CSRF check disappeared in refactor", "", ["src/auth.ts"]),
|
|
39
|
+
];
|
|
40
|
+
expect(detectRegrets(commits)[0].kind).toBe("hotfix");
|
|
41
|
+
});
|
|
42
|
+
it("flags 'fix' kind when follow-up is a generic fix touching same files", () => {
|
|
43
|
+
const commits = [
|
|
44
|
+
cmt("a1", "2024-08-01", "perf: cache user lookup", "", ["src/users.ts"]),
|
|
45
|
+
cmt("a2", "2024-08-04", "fix: cache invalidation race", "", ["src/users.ts"]),
|
|
46
|
+
];
|
|
47
|
+
expect(detectRegrets(commits)[0].kind).toBe("fix");
|
|
48
|
+
});
|
|
49
|
+
it("doesn't double-flag commits that ARE themselves fixes", () => {
|
|
50
|
+
const commits = [
|
|
51
|
+
cmt("a1", "2024-08-01", "fix: typo", "", ["README.md"]),
|
|
52
|
+
cmt("a2", "2024-08-02", "fix: another typo", "", ["README.md"]),
|
|
53
|
+
];
|
|
54
|
+
// Neither is a regret — both are fix-shaped subjects.
|
|
55
|
+
expect(detectRegrets(commits)).toEqual([]);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe("detectRegrets — window enforcement", () => {
|
|
59
|
+
it("respects the windowDays cutoff", () => {
|
|
60
|
+
const commits = [
|
|
61
|
+
cmt("a1", "2024-08-01", "feat: thing", "", ["x.ts"]),
|
|
62
|
+
cmt("a2", "2024-08-15", "fix: thing broke", "", ["x.ts"]), // 14 days later
|
|
63
|
+
];
|
|
64
|
+
expect(detectRegrets(commits, { windowDays: 7 })).toEqual([]);
|
|
65
|
+
expect(detectRegrets(commits, { windowDays: 30 })).toHaveLength(1);
|
|
66
|
+
});
|
|
67
|
+
it("respects minDaysToFix lower bound (filter out same-day micro-fixes)", () => {
|
|
68
|
+
const commits = [
|
|
69
|
+
cmt("a1", "2024-08-01", "feat: thing", "", ["x.ts"]),
|
|
70
|
+
cmt("a2", "2024-08-01", "fix: typo", "", ["x.ts"]),
|
|
71
|
+
];
|
|
72
|
+
expect(detectRegrets(commits, { minDaysToFix: 1 })).toEqual([]);
|
|
73
|
+
expect(detectRegrets(commits, { minDaysToFix: 0 })).toHaveLength(1);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe("detectRegrets — only one regret per shipped commit", () => {
|
|
77
|
+
it("returns the first follow-up only (avoids double-counting)", () => {
|
|
78
|
+
const commits = [
|
|
79
|
+
cmt("a1", "2024-08-01", "feat: thing", "", ["x.ts"]),
|
|
80
|
+
cmt("a2", "2024-08-02", "fix: first attempt at fix", "", ["x.ts"]),
|
|
81
|
+
cmt("a3", "2024-08-04", "fix: second attempt", "", ["x.ts"]),
|
|
82
|
+
];
|
|
83
|
+
const regrets = detectRegrets(commits);
|
|
84
|
+
expect(regrets).toHaveLength(1);
|
|
85
|
+
expect(regrets[0].followup.shortHash).toBe("a2");
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe("detectRegrets — output ordering and content", () => {
|
|
89
|
+
it("sorts results by ship date descending (newest regret first)", () => {
|
|
90
|
+
const commits = [
|
|
91
|
+
cmt("old1", "2024-01-01", "feat: a", "", ["x.ts"]),
|
|
92
|
+
cmt("old2", "2024-01-02", "fix: a broke", "", ["x.ts"]),
|
|
93
|
+
cmt("new1", "2024-08-01", "feat: b", "", ["y.ts"]),
|
|
94
|
+
cmt("new2", "2024-08-03", "fix: b broke", "", ["y.ts"]),
|
|
95
|
+
];
|
|
96
|
+
const regrets = detectRegrets(commits);
|
|
97
|
+
expect(regrets).toHaveLength(2);
|
|
98
|
+
expect(regrets[0].shipped.shortHash).toBe("new1");
|
|
99
|
+
expect(regrets[1].shipped.shortHash).toBe("old1");
|
|
100
|
+
});
|
|
101
|
+
it("attaches a lesson string when the follow-up body has explanatory text", () => {
|
|
102
|
+
const commits = [
|
|
103
|
+
cmt("a1", "2024-08-01", "feat: thing", "", ["x.ts"]),
|
|
104
|
+
cmt("a2", "2024-08-02", "fix: thing crashed", "the cache invalidation was racing with the eviction sweep", ["x.ts"]),
|
|
105
|
+
];
|
|
106
|
+
const r = detectRegrets(commits)[0];
|
|
107
|
+
expect(r.lesson).toContain("cache invalidation");
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe("summarizeRegrets — repo-level metrics", () => {
|
|
111
|
+
it("computes regretRate over non-fix shipped commits", () => {
|
|
112
|
+
const commits = [
|
|
113
|
+
cmt("a1", "2024-08-01", "feat: A", "", ["x.ts"]),
|
|
114
|
+
cmt("a2", "2024-08-02", "fix: A broke", "", ["x.ts"]),
|
|
115
|
+
cmt("a3", "2024-08-03", "feat: B", "", ["y.ts"]),
|
|
116
|
+
cmt("a4", "2024-08-04", "feat: C", "", ["z.ts"]),
|
|
117
|
+
];
|
|
118
|
+
const regrets = detectRegrets(commits);
|
|
119
|
+
const summary = summarizeRegrets(commits, regrets);
|
|
120
|
+
// Non-fix shipped: a1, a3, a4 → 3 candidates. 1 regret. → 1/3 ≈ 0.33
|
|
121
|
+
expect(summary.totalShipped).toBe(3);
|
|
122
|
+
expect(summary.totalRegrets).toBe(1);
|
|
123
|
+
expect(summary.regretRate).toBeCloseTo(1 / 3, 2);
|
|
124
|
+
});
|
|
125
|
+
it("counts byKind correctly", () => {
|
|
126
|
+
const commits = [
|
|
127
|
+
cmt("a1", "2024-08-01", "feat: A", "", ["x.ts"]),
|
|
128
|
+
cmt("a2", "2024-08-02", "Revert \"feat: A\"", "", ["x.ts"]),
|
|
129
|
+
cmt("a3", "2024-08-03", "feat: B", "", ["y.ts"]),
|
|
130
|
+
cmt("a4", "2024-08-04", "hotfix: B explosion", "", ["y.ts"]),
|
|
131
|
+
];
|
|
132
|
+
const regrets = detectRegrets(commits);
|
|
133
|
+
const summary = summarizeRegrets(commits, regrets);
|
|
134
|
+
expect(summary.byKind.revert).toBe(1);
|
|
135
|
+
expect(summary.byKind.hotfix).toBe(1);
|
|
136
|
+
});
|
|
137
|
+
it("reports averageDaysToFix", () => {
|
|
138
|
+
const commits = [
|
|
139
|
+
cmt("a1", "2024-08-01", "feat: A", "", ["x.ts"]),
|
|
140
|
+
cmt("a2", "2024-08-03", "fix: A", "", ["x.ts"]), // 2 days
|
|
141
|
+
cmt("a3", "2024-08-10", "feat: B", "", ["y.ts"]),
|
|
142
|
+
cmt("a4", "2024-08-14", "fix: B", "", ["y.ts"]), // 4 days
|
|
143
|
+
];
|
|
144
|
+
const summary = summarizeRegrets(commits, detectRegrets(commits));
|
|
145
|
+
expect(summary.averageDaysToFix).toBeCloseTo(3, 1);
|
|
146
|
+
});
|
|
147
|
+
it("returns 0 metrics when there are no regrets", () => {
|
|
148
|
+
const summary = summarizeRegrets([cmt("a", "2024-08-01", "feat: stable", "", ["x"])], []);
|
|
149
|
+
expect(summary.regretRate).toBe(0);
|
|
150
|
+
expect(summary.averageDaysToFix).toBe(0);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
//# sourceMappingURL=regret.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regret.test.js","sourceRoot":"","sources":["../../src/insights/regret.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -45,4 +45,22 @@ export declare function whoKnows(store: MnemeStore, opts: WhoKnowsOptions): Expe
|
|
|
45
45
|
/** log-based commit weight × recency multiplier. Pure function, easy to test. */
|
|
46
46
|
export declare function scoreCandidate(commitCount: number, lastTouchIso: string, now: Date): number;
|
|
47
47
|
export declare function tierOf(commitCount: number, lastTouchIso: string, now: Date): ExpertCandidate["tier"];
|
|
48
|
+
/**
|
|
49
|
+
* Verdict-shaped summary built from the full candidate list. Surfaces the
|
|
50
|
+
* single most likely person to ask + a confidence percentage + a fallback
|
|
51
|
+
* recommendation, instead of letting the user scan a list of names.
|
|
52
|
+
*/
|
|
53
|
+
export interface ExpertVerdict {
|
|
54
|
+
/** The single most likely expert (or undefined when no candidates). */
|
|
55
|
+
topExpert?: ExpertCandidate;
|
|
56
|
+
/** Confidence percentage 0..100 — share of total commits attributed to the top. */
|
|
57
|
+
confidencePct: number;
|
|
58
|
+
/** Backup expert if the top is stale or has insufficient share. */
|
|
59
|
+
backup?: ExpertCandidate;
|
|
60
|
+
/** A 1-line risk note when the top expert is stale or shares too thinly. */
|
|
61
|
+
risk?: string;
|
|
62
|
+
/** Total commits matched across all candidates (sum of commitCount). */
|
|
63
|
+
totalCommits: number;
|
|
64
|
+
}
|
|
65
|
+
export declare function whoKnowsVerdict(candidates: ExpertCandidate[]): ExpertVerdict;
|
|
48
66
|
//# sourceMappingURL=who-knows.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"who-knows.d.ts","sourceRoot":"","sources":["../../src/insights/who-knows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,IAAI,EAAE,YAAY,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,CAAC;CACxD;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAKD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,eAAe,GAAG,eAAe,EAAE,CA6DpF;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,MAAM,CAQ3F;AAED,wBAAgB,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,eAAe,CAAC,MAAM,CAAC,CAOpG"}
|
|
1
|
+
{"version":3,"file":"who-knows.d.ts","sourceRoot":"","sources":["../../src/insights/who-knows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,IAAI,EAAE,YAAY,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,CAAC;CACxD;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAKD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,eAAe,GAAG,eAAe,EAAE,CA6DpF;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,MAAM,CAQ3F;AAED,wBAAgB,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,eAAe,CAAC,MAAM,CAAC,CAOpG;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,uEAAuE;IACvE,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,mFAAmF;IACnF,aAAa,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,eAAe,EAAE,GAAG,aAAa,CAoB5E"}
|
|
@@ -93,4 +93,33 @@ export function tierOf(commitCount, lastTouchIso, now) {
|
|
|
93
93
|
return "stale";
|
|
94
94
|
return "occasional";
|
|
95
95
|
}
|
|
96
|
+
export function whoKnowsVerdict(candidates) {
|
|
97
|
+
if (candidates.length === 0) {
|
|
98
|
+
return { confidencePct: 0, totalCommits: 0 };
|
|
99
|
+
}
|
|
100
|
+
const sorted = [...candidates].sort((a, b) => b.score - a.score);
|
|
101
|
+
const top = sorted[0];
|
|
102
|
+
const total = candidates.reduce((s, c) => s + c.commitCount, 0);
|
|
103
|
+
const pct = total === 0 ? 0 : Math.round((top.commitCount / total) * 100);
|
|
104
|
+
const backup = sorted[1];
|
|
105
|
+
let risk;
|
|
106
|
+
if (top.tier === "stale") {
|
|
107
|
+
risk = `Top expert is STALE — last touched ${formatDaysAgo(top.lastTouch)} ago. Consider asking ${backup?.name ?? "someone with recent activity"} instead.`;
|
|
108
|
+
}
|
|
109
|
+
else if (pct < 30 && candidates.length >= 3) {
|
|
110
|
+
risk = `No single dominant expert — ${candidates.length} people share the work. Knowledge is well-distributed but no one will know everything.`;
|
|
111
|
+
}
|
|
112
|
+
else if (top.commitCount === 1) {
|
|
113
|
+
risk = "Top expert touched the topic only once — treat as weak signal.";
|
|
114
|
+
}
|
|
115
|
+
return { topExpert: top, confidencePct: pct, backup, risk, totalCommits: total };
|
|
116
|
+
}
|
|
117
|
+
function formatDaysAgo(iso) {
|
|
118
|
+
const d = (Date.now() - new Date(iso).getTime()) / 86_400_000;
|
|
119
|
+
if (d < 30)
|
|
120
|
+
return `${Math.round(d)}d`;
|
|
121
|
+
if (d < 365)
|
|
122
|
+
return `${Math.round(d / 30)}mo`;
|
|
123
|
+
return `${(d / 365).toFixed(1)}y`;
|
|
124
|
+
}
|
|
96
125
|
//# sourceMappingURL=who-knows.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"who-knows.js","sourceRoot":"","sources":["../../src/insights/who-knows.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"who-knows.js","sourceRoot":"","sources":["../../src/insights/who-knows.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { scoreCandidate, tierOf } from "./who-knows.js";
|
|
2
|
+
import { scoreCandidate, tierOf, whoKnowsVerdict } from "./who-knows.js";
|
|
3
3
|
const today = new Date("2026-05-04T00:00:00Z");
|
|
4
4
|
const daysAgo = (n) => new Date(today.getTime() - n * 86_400_000).toISOString();
|
|
5
5
|
describe("scoreCandidate — pure scoring function", () => {
|
|
@@ -44,4 +44,66 @@ describe("tierOf — readable expert tier", () => {
|
|
|
44
44
|
expect(tierOf(1, daysAgo(40), today)).toBe("occasional");
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
|
+
describe("whoKnowsVerdict — turns a list of candidates into a single verdict", () => {
|
|
48
|
+
const cand = (overrides) => ({
|
|
49
|
+
name: "alice",
|
|
50
|
+
email: "alice@x",
|
|
51
|
+
commitCount: 10,
|
|
52
|
+
lastTouch: daysAgo(5),
|
|
53
|
+
filesTouched: 20,
|
|
54
|
+
score: 3.0,
|
|
55
|
+
tier: "active",
|
|
56
|
+
...overrides,
|
|
57
|
+
});
|
|
58
|
+
it("returns empty verdict for empty candidate list", () => {
|
|
59
|
+
const v = whoKnowsVerdict([]);
|
|
60
|
+
expect(v.topExpert).toBeUndefined();
|
|
61
|
+
expect(v.confidencePct).toBe(0);
|
|
62
|
+
expect(v.totalCommits).toBe(0);
|
|
63
|
+
});
|
|
64
|
+
it("picks the highest-score candidate as topExpert", () => {
|
|
65
|
+
const v = whoKnowsVerdict([
|
|
66
|
+
cand({ name: "alice", score: 4.0, commitCount: 15 }),
|
|
67
|
+
cand({ name: "bob", score: 2.0, commitCount: 5 }),
|
|
68
|
+
]);
|
|
69
|
+
expect(v.topExpert?.name).toBe("alice");
|
|
70
|
+
expect(v.backup?.name).toBe("bob");
|
|
71
|
+
});
|
|
72
|
+
it("computes confidencePct as share of total commits", () => {
|
|
73
|
+
const v = whoKnowsVerdict([
|
|
74
|
+
cand({ name: "alice", score: 4.0, commitCount: 15 }),
|
|
75
|
+
cand({ name: "bob", score: 2.0, commitCount: 5 }),
|
|
76
|
+
]);
|
|
77
|
+
expect(v.confidencePct).toBe(75);
|
|
78
|
+
});
|
|
79
|
+
it("flags risk when top expert is stale", () => {
|
|
80
|
+
const v = whoKnowsVerdict([
|
|
81
|
+
cand({ name: "alice", tier: "stale", lastTouch: daysAgo(300), commitCount: 20 }),
|
|
82
|
+
cand({ name: "bob", tier: "active", lastTouch: daysAgo(5), commitCount: 5 }),
|
|
83
|
+
]);
|
|
84
|
+
expect(v.risk?.toLowerCase()).toContain("stale");
|
|
85
|
+
expect(v.risk).toContain("bob"); // suggests backup
|
|
86
|
+
});
|
|
87
|
+
it("flags risk when no dominant expert (well-distributed)", () => {
|
|
88
|
+
const v = whoKnowsVerdict([
|
|
89
|
+
cand({ name: "alice", commitCount: 4, score: 1.5 }),
|
|
90
|
+
cand({ name: "bob", commitCount: 4, score: 1.4 }),
|
|
91
|
+
cand({ name: "carol", commitCount: 4, score: 1.3 }),
|
|
92
|
+
cand({ name: "dave", commitCount: 4, score: 1.2 }),
|
|
93
|
+
]);
|
|
94
|
+
expect(v.confidencePct).toBe(25);
|
|
95
|
+
expect(v.risk?.toLowerCase()).toContain("distributed");
|
|
96
|
+
});
|
|
97
|
+
it("flags risk when top expert touched once", () => {
|
|
98
|
+
const v = whoKnowsVerdict([cand({ name: "alice", commitCount: 1 })]);
|
|
99
|
+
expect(v.risk?.toLowerCase()).toContain("once");
|
|
100
|
+
});
|
|
101
|
+
it("no risk when top expert is definitive + recent", () => {
|
|
102
|
+
const v = whoKnowsVerdict([
|
|
103
|
+
cand({ name: "alice", tier: "definitive", commitCount: 20, lastTouch: daysAgo(5), score: 5 }),
|
|
104
|
+
cand({ name: "bob", commitCount: 2, score: 1, tier: "occasional" }),
|
|
105
|
+
]);
|
|
106
|
+
expect(v.risk).toBeUndefined();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
47
109
|
//# sourceMappingURL=who-knows.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"who-knows.test.js","sourceRoot":"","sources":["../../src/insights/who-knows.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"who-knows.test.js","sourceRoot":"","sources":["../../src/insights/who-knows.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,eAAe,EAAwB,MAAM,gBAAgB,CAAC;AAE/F,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC;AAC/C,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;AAExF,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACtD,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACrD,MAAM,GAAG,GAAG,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QACpD,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,IAAI,GAAG,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QACpD,MAAM,KAAK,GAAG,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,GAAG,GAAG,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACvD,iEAAiE;QACjE,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,OAAO,GAAG,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;QACzD,MAAM,OAAO,GAAG,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QACxD,uCAAuC;QACvC,MAAM,CAAC,OAAO,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,OAAO,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;IAC7C,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oEAAoE,EAAE,GAAG,EAAE;IAClF,MAAM,IAAI,GAAG,CAAC,SAAmC,EAAmB,EAAE,CAAC,CAAC;QACtE,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,SAAS;QAChB,WAAW,EAAE,EAAE;QACf,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;QACrB,YAAY,EAAE,EAAE;QAChB,KAAK,EAAE,GAAG;QACV,IAAI,EAAE,QAAQ;QACd,GAAG,SAAS;KACb,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;QAC9B,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,aAAa,EAAE,CAAC;QACpC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,GAAG,eAAe,CAAC;YACxB,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;YACpD,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;SAClD,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,GAAG,eAAe,CAAC;YACxB,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;YACpD,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;SAClD,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,GAAG,eAAe,CAAC;YACxB,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;YAChF,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;SAC7E,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,CAAC,GAAG,eAAe,CAAC;YACxB,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;YACnD,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;YACjD,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;YACnD,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;SACnD,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,GAAG,eAAe,CAAC;YACxB,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;YAC7F,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;SACpE,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mneme alpha` — Kelly criterion for technical debt allocation.
|
|
3
|
+
*
|
|
4
|
+
* Each refactor/TD item is a "bet" with (expected payoff, variance).
|
|
5
|
+
* Kelly optimal fraction maximizes long-run growth: f* = edge / variance.
|
|
6
|
+
* In practice, we use FRACTIONAL Kelly (×0.25) to limit blow-up risk —
|
|
7
|
+
* the same lever Edward Thorp used to win Wall Street.
|
|
8
|
+
*
|
|
9
|
+
* Pure math + small heuristics for estimating edge/variance from history.
|
|
10
|
+
* No LLM. The CLI takes a JSON list of items OR auto-extracts from
|
|
11
|
+
* `mneme regret` + `mneme bus-factor` + `mneme paradox` data.
|
|
12
|
+
*/
|
|
13
|
+
export interface DebtItem {
|
|
14
|
+
/** Stable id — drives sorting + reporting. */
|
|
15
|
+
id: string;
|
|
16
|
+
/** Human-readable name shown in output. */
|
|
17
|
+
name: string;
|
|
18
|
+
/**
|
|
19
|
+
* Edge — expected return as a fraction. Positive = improves codebase
|
|
20
|
+
* (smaller diff sizes, fewer regrets, better velocity). Negative =
|
|
21
|
+
* outright wasteful (the item costs more than it returns).
|
|
22
|
+
*/
|
|
23
|
+
edge: number;
|
|
24
|
+
/**
|
|
25
|
+
* Variance — squared volatility of the outcome. Higher = riskier bet,
|
|
26
|
+
* more dispersion in possible outcomes. Tiny number (0..1) — interpret
|
|
27
|
+
* as fraction-squared.
|
|
28
|
+
*/
|
|
29
|
+
variance: number;
|
|
30
|
+
/** Estimated dev-days to complete. */
|
|
31
|
+
effortDays: number;
|
|
32
|
+
}
|
|
33
|
+
export interface KellyAllocation extends DebtItem {
|
|
34
|
+
/** Raw Kelly fraction f* = edge / variance. May be > 1 or negative. */
|
|
35
|
+
rawKelly: number;
|
|
36
|
+
/** Fractional Kelly (clamped to [0, 0.5] after multiplier). */
|
|
37
|
+
kellyFraction: number;
|
|
38
|
+
/** Allocated dev-days for this item out of the budget. */
|
|
39
|
+
allocatedDays: number;
|
|
40
|
+
/** Sort tier for display. */
|
|
41
|
+
tier: "skip" | "small" | "core" | "outsized";
|
|
42
|
+
}
|
|
43
|
+
export interface KellyResult {
|
|
44
|
+
items: KellyAllocation[];
|
|
45
|
+
totalAllocated: number;
|
|
46
|
+
budgetDays: number;
|
|
47
|
+
reserveDays: number;
|
|
48
|
+
/** Kelly multiplier used. 0.25 by default — conservative. */
|
|
49
|
+
kellyMultiplier: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Compute Kelly-optimal allocation for a list of debt items.
|
|
53
|
+
*
|
|
54
|
+
* Algorithm:
|
|
55
|
+
* 1. raw_kelly_i = edge_i / variance_i (the canonical Kelly formula)
|
|
56
|
+
* 2. fractional_kelly_i = raw_kelly_i × multiplier (default 0.25)
|
|
57
|
+
* 3. clamp to [0, 0.5] — never bet > 50% of budget on one item
|
|
58
|
+
* 4. zero out negative-edge items (don't hold a losing bet)
|
|
59
|
+
* 5. normalize so allocations sum to ≤ budgetDays (leave reserve)
|
|
60
|
+
* 6. allocate dev-days proportionally
|
|
61
|
+
*/
|
|
62
|
+
export declare function kellyAllocate(items: DebtItem[], opts?: {
|
|
63
|
+
budgetDays: number;
|
|
64
|
+
multiplier?: number;
|
|
65
|
+
reserveFraction?: number;
|
|
66
|
+
}): KellyResult;
|
|
67
|
+
export declare function classifyTier(kellyFraction: number, edge: number): KellyAllocation["tier"];
|
|
68
|
+
/**
|
|
69
|
+
* Estimate edge from historical data: a refactor's edge is the difference
|
|
70
|
+
* in (regret rate, bug rate, churn velocity) between BEFORE and AFTER
|
|
71
|
+
* similar past refactors in the same module.
|
|
72
|
+
*
|
|
73
|
+
* The CLI calls this with regret data + commit-coach signals; here we
|
|
74
|
+
* just expose the algorithm so it's testable in isolation.
|
|
75
|
+
*/
|
|
76
|
+
export declare function estimateEdge(opts: {
|
|
77
|
+
pastRegretRate: number;
|
|
78
|
+
pastChurnPerDay: number;
|
|
79
|
+
postRefactorRegretRate: number;
|
|
80
|
+
postRefactorChurnPerDay: number;
|
|
81
|
+
}): number;
|
|
82
|
+
/**
|
|
83
|
+
* Estimate variance — historical variance of payoff across similar past
|
|
84
|
+
* refactors. Higher when past outcomes were inconsistent.
|
|
85
|
+
*/
|
|
86
|
+
export declare function estimateVariance(historicalPayoffs: number[]): number;
|
|
87
|
+
//# sourceMappingURL=alpha.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alpha.d.ts","sourceRoot":"","sources":["../../src/quant/alpha.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,QAAQ;IACvB,8CAA8C;IAC9C,EAAE,EAAE,MAAM,CAAC;IACX,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAgB,SAAQ,QAAQ;IAC/C,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,aAAa,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,CAAC;CAC9C;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,QAAQ,EAAE,EACjB,IAAI,GAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAuB,GAC/F,WAAW,CA6Cb;AAED,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAMzF;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,uBAAuB,EAAE,MAAM,CAAC;CACjC,GAAG,MAAM,CAKT;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,iBAAiB,EAAE,MAAM,EAAE,GAAG,MAAM,CAMpE"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mneme alpha` — Kelly criterion for technical debt allocation.
|
|
3
|
+
*
|
|
4
|
+
* Each refactor/TD item is a "bet" with (expected payoff, variance).
|
|
5
|
+
* Kelly optimal fraction maximizes long-run growth: f* = edge / variance.
|
|
6
|
+
* In practice, we use FRACTIONAL Kelly (×0.25) to limit blow-up risk —
|
|
7
|
+
* the same lever Edward Thorp used to win Wall Street.
|
|
8
|
+
*
|
|
9
|
+
* Pure math + small heuristics for estimating edge/variance from history.
|
|
10
|
+
* No LLM. The CLI takes a JSON list of items OR auto-extracts from
|
|
11
|
+
* `mneme regret` + `mneme bus-factor` + `mneme paradox` data.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Compute Kelly-optimal allocation for a list of debt items.
|
|
15
|
+
*
|
|
16
|
+
* Algorithm:
|
|
17
|
+
* 1. raw_kelly_i = edge_i / variance_i (the canonical Kelly formula)
|
|
18
|
+
* 2. fractional_kelly_i = raw_kelly_i × multiplier (default 0.25)
|
|
19
|
+
* 3. clamp to [0, 0.5] — never bet > 50% of budget on one item
|
|
20
|
+
* 4. zero out negative-edge items (don't hold a losing bet)
|
|
21
|
+
* 5. normalize so allocations sum to ≤ budgetDays (leave reserve)
|
|
22
|
+
* 6. allocate dev-days proportionally
|
|
23
|
+
*/
|
|
24
|
+
export function kellyAllocate(items, opts = { budgetDays: 25 }) {
|
|
25
|
+
const multiplier = opts.multiplier ?? 0.25;
|
|
26
|
+
const reserveFrac = opts.reserveFraction ?? 0.2;
|
|
27
|
+
const budget = Math.max(0, opts.budgetDays);
|
|
28
|
+
// 1. Raw + fractional Kelly per item.
|
|
29
|
+
const computed = items.map((item) => {
|
|
30
|
+
// Avoid division-by-zero — variance of 0 is unrealistic; treat as floor.
|
|
31
|
+
const v = Math.max(item.variance, 1e-6);
|
|
32
|
+
const rawKelly = item.edge / v;
|
|
33
|
+
let frac = rawKelly * multiplier;
|
|
34
|
+
if (frac < 0)
|
|
35
|
+
frac = 0; // never bet on a losing item
|
|
36
|
+
if (frac > 0.5)
|
|
37
|
+
frac = 0.5; // never bet > 50% on one item
|
|
38
|
+
return { ...item, rawKelly, kellyFraction: frac };
|
|
39
|
+
});
|
|
40
|
+
// 2. Normalize fractions to sum ≤ (1 - reserveFrac).
|
|
41
|
+
const totalFrac = computed.reduce((s, c) => s + c.kellyFraction, 0);
|
|
42
|
+
const targetTotal = 1 - reserveFrac;
|
|
43
|
+
const scale = totalFrac > targetTotal ? targetTotal / totalFrac : 1;
|
|
44
|
+
// 3. Allocate dev-days.
|
|
45
|
+
let allocatedSum = 0;
|
|
46
|
+
const allocations = computed.map((c) => {
|
|
47
|
+
const adjusted = c.kellyFraction * scale;
|
|
48
|
+
const allocatedDays = Math.round(budget * adjusted * 10) / 10;
|
|
49
|
+
allocatedSum += allocatedDays;
|
|
50
|
+
return {
|
|
51
|
+
...c,
|
|
52
|
+
kellyFraction: adjusted,
|
|
53
|
+
allocatedDays,
|
|
54
|
+
tier: classifyTier(adjusted, c.edge),
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
// 4. Sort by allocated days desc — biggest bets first.
|
|
58
|
+
allocations.sort((a, b) => b.allocatedDays - a.allocatedDays);
|
|
59
|
+
return {
|
|
60
|
+
items: allocations,
|
|
61
|
+
totalAllocated: Math.round(allocatedSum * 10) / 10,
|
|
62
|
+
budgetDays: budget,
|
|
63
|
+
reserveDays: Math.round((budget - allocatedSum) * 10) / 10,
|
|
64
|
+
kellyMultiplier: multiplier,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function classifyTier(kellyFraction, edge) {
|
|
68
|
+
if (edge < 0)
|
|
69
|
+
return "skip";
|
|
70
|
+
if (kellyFraction >= 0.2)
|
|
71
|
+
return "outsized";
|
|
72
|
+
if (kellyFraction >= 0.1)
|
|
73
|
+
return "core";
|
|
74
|
+
if (kellyFraction > 0)
|
|
75
|
+
return "small";
|
|
76
|
+
return "skip";
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Estimate edge from historical data: a refactor's edge is the difference
|
|
80
|
+
* in (regret rate, bug rate, churn velocity) between BEFORE and AFTER
|
|
81
|
+
* similar past refactors in the same module.
|
|
82
|
+
*
|
|
83
|
+
* The CLI calls this with regret data + commit-coach signals; here we
|
|
84
|
+
* just expose the algorithm so it's testable in isolation.
|
|
85
|
+
*/
|
|
86
|
+
export function estimateEdge(opts) {
|
|
87
|
+
const regretImprovement = opts.pastRegretRate - opts.postRefactorRegretRate;
|
|
88
|
+
const churnImprovement = (opts.pastChurnPerDay - opts.postRefactorChurnPerDay) / Math.max(opts.pastChurnPerDay, 0.001);
|
|
89
|
+
// Weighted: regret matters more (bugs hurt more than churn).
|
|
90
|
+
return 0.7 * regretImprovement + 0.3 * churnImprovement;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Estimate variance — historical variance of payoff across similar past
|
|
94
|
+
* refactors. Higher when past outcomes were inconsistent.
|
|
95
|
+
*/
|
|
96
|
+
export function estimateVariance(historicalPayoffs) {
|
|
97
|
+
if (historicalPayoffs.length < 2)
|
|
98
|
+
return 0.1; // unknown — assume mid-range
|
|
99
|
+
const mean = historicalPayoffs.reduce((s, x) => s + x, 0) / historicalPayoffs.length;
|
|
100
|
+
const variance = historicalPayoffs.reduce((s, x) => s + (x - mean) * (x - mean), 0) / historicalPayoffs.length;
|
|
101
|
+
return Math.max(variance, 1e-6);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=alpha.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alpha.js","sourceRoot":"","sources":["../../src/quant/alpha.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alpha.test.d.ts","sourceRoot":"","sources":["../../src/quant/alpha.test.ts"],"names":[],"mappings":""}
|