@mneme-ai/core 0.26.0 → 0.27.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/audit/baseline.d.ts +92 -0
- package/dist/audit/baseline.d.ts.map +1 -0
- package/dist/audit/baseline.js +276 -0
- package/dist/audit/baseline.js.map +1 -0
- package/dist/audit/baseline.test.d.ts +2 -0
- package/dist/audit/baseline.test.d.ts.map +1 -0
- package/dist/audit/baseline.test.js +180 -0
- package/dist/audit/baseline.test.js.map +1 -0
- package/dist/audit/certify.d.ts +139 -0
- package/dist/audit/certify.d.ts.map +1 -0
- package/dist/audit/certify.js +295 -0
- package/dist/audit/certify.js.map +1 -0
- package/dist/audit/certify.test.d.ts +2 -0
- package/dist/audit/certify.test.d.ts.map +1 -0
- package/dist/audit/certify.test.js +324 -0
- package/dist/audit/certify.test.js.map +1 -0
- package/dist/audit/index.d.ts +14 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +14 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/trace.d.ts +88 -0
- package/dist/audit/trace.d.ts.map +1 -0
- package/dist/audit/trace.js +173 -0
- package/dist/audit/trace.js.map +1 -0
- package/dist/audit/trace.test.d.ts +2 -0
- package/dist/audit/trace.test.d.ts.map +1 -0
- package/dist/audit/trace.test.js +198 -0
- package/dist/audit/trace.test.js.map +1 -0
- package/dist/audit/verify.d.ts +61 -0
- package/dist/audit/verify.d.ts.map +1 -0
- package/dist/audit/verify.js +278 -0
- package/dist/audit/verify.js.map +1 -0
- package/dist/audit/verify.test.d.ts +2 -0
- package/dist/audit/verify.test.d.ts.map +1 -0
- package/dist/audit/verify.test.js +129 -0
- package/dist/audit/verify.test.js.map +1 -0
- 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/retrieve/intent.d.ts.map +1 -1
- package/dist/retrieve/intent.js +16 -0
- package/dist/retrieve/intent.js.map +1 -1
- package/dist/retrieve/intent.test.js +23 -0
- package/dist/retrieve/intent.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.test.d.ts","sourceRoot":"","sources":["../../src/audit/trace.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { COMMIT_SEP, DEFAULT_VENDOR_RULES, aiCommitCount, aiVendorBreakdown, detectAiVendor, parseCommitLog, parseShortstat, traceSession, } from "./trace.js";
|
|
3
|
+
describe("audit/trace — detectAiVendor", () => {
|
|
4
|
+
it("detects Claude from Co-Authored-By trailer", () => {
|
|
5
|
+
const r = detectAiVendor({
|
|
6
|
+
message: "fix: bug\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
|
|
7
|
+
authorEmail: "alice@example.com",
|
|
8
|
+
});
|
|
9
|
+
expect(r?.vendor).toBe("claude");
|
|
10
|
+
expect(r?.confidence).toBeGreaterThan(0.9);
|
|
11
|
+
});
|
|
12
|
+
it("detects Claude from anthropic email even if message is silent", () => {
|
|
13
|
+
const r = detectAiVendor({
|
|
14
|
+
message: "fix typo",
|
|
15
|
+
authorEmail: "noreply@anthropic.com",
|
|
16
|
+
});
|
|
17
|
+
expect(r?.vendor).toBe("claude");
|
|
18
|
+
});
|
|
19
|
+
it("detects Cursor from [Cursor] tag", () => {
|
|
20
|
+
const r = detectAiVendor({
|
|
21
|
+
message: "[Cursor] refactor handler",
|
|
22
|
+
authorEmail: "dev@example.com",
|
|
23
|
+
});
|
|
24
|
+
expect(r?.vendor).toBe("cursor");
|
|
25
|
+
});
|
|
26
|
+
it("detects Codex from 'Generated by Codex' line", () => {
|
|
27
|
+
const r = detectAiVendor({
|
|
28
|
+
message: "Generated by Codex.\n\nadd retry logic",
|
|
29
|
+
authorEmail: "dev@example.com",
|
|
30
|
+
});
|
|
31
|
+
expect(r?.vendor).toBe("codex");
|
|
32
|
+
});
|
|
33
|
+
it("detects Devin from message OR email", () => {
|
|
34
|
+
expect(detectAiVendor({
|
|
35
|
+
message: "(via devin.ai)",
|
|
36
|
+
authorEmail: "dev@example.com",
|
|
37
|
+
})?.vendor).toBe("devin");
|
|
38
|
+
expect(detectAiVendor({
|
|
39
|
+
message: "patch",
|
|
40
|
+
authorEmail: "agent@devin.ai",
|
|
41
|
+
})?.vendor).toBe("devin");
|
|
42
|
+
});
|
|
43
|
+
it("detects Sweep, Aider, Copilot", () => {
|
|
44
|
+
expect(detectAiVendor({
|
|
45
|
+
message: "Auto-PR by sweep.dev",
|
|
46
|
+
authorEmail: "x@x.com",
|
|
47
|
+
})?.vendor).toBe("sweep");
|
|
48
|
+
expect(detectAiVendor({
|
|
49
|
+
message: "via aider session",
|
|
50
|
+
authorEmail: "x@x.com",
|
|
51
|
+
})?.vendor).toBe("aider");
|
|
52
|
+
expect(detectAiVendor({
|
|
53
|
+
message: "fix\n\nCo-Authored-By: GitHub Copilot <copilot@github.com>",
|
|
54
|
+
authorEmail: "x@x.com",
|
|
55
|
+
})?.vendor).toBe("copilot");
|
|
56
|
+
});
|
|
57
|
+
it("returns undefined for human commits with no AI signal", () => {
|
|
58
|
+
expect(detectAiVendor({
|
|
59
|
+
message: "fix: a real bug",
|
|
60
|
+
authorEmail: "alice@example.com",
|
|
61
|
+
})).toBeUndefined();
|
|
62
|
+
});
|
|
63
|
+
it("DEFAULT_VENDOR_RULES is non-empty and covers the canonical vendors", () => {
|
|
64
|
+
const vendors = new Set(DEFAULT_VENDOR_RULES.map((r) => r.vendor));
|
|
65
|
+
for (const v of ["claude", "cursor", "codex", "devin", "sweep"]) {
|
|
66
|
+
expect(vendors.has(v)).toBe(true);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe("audit/trace — parseCommitLog", () => {
|
|
71
|
+
it("parses a single commit block", () => {
|
|
72
|
+
const block = `aaaaaaa\tAlice\talice@x.com\tfix: bug\n${COMMIT_SEP}\n`;
|
|
73
|
+
const out = parseCommitLog(block);
|
|
74
|
+
expect(out).toHaveLength(1);
|
|
75
|
+
expect(out[0].hash).toBe("aaaaaaa");
|
|
76
|
+
expect(out[0].author).toBe("Alice");
|
|
77
|
+
expect(out[0].shortHash).toBe("aaaaaaa");
|
|
78
|
+
});
|
|
79
|
+
it("attaches AI detection per commit", () => {
|
|
80
|
+
const raw = `aaa\tAlice\tnoreply@anthropic.com\tfix: stuff\n${COMMIT_SEP}\n` +
|
|
81
|
+
`bbb\tBob\tbob@x.com\trefactor\n${COMMIT_SEP}\n`;
|
|
82
|
+
const out = parseCommitLog(raw);
|
|
83
|
+
expect(out).toHaveLength(2);
|
|
84
|
+
expect(out[0].likelyAI?.vendor).toBe("claude");
|
|
85
|
+
expect(out[1].likelyAI).toBeUndefined();
|
|
86
|
+
});
|
|
87
|
+
it("returns [] for empty input", () => {
|
|
88
|
+
expect(parseCommitLog("")).toEqual([]);
|
|
89
|
+
expect(parseCommitLog(" \n\n ")).toEqual([]);
|
|
90
|
+
});
|
|
91
|
+
it("captures multi-line body", () => {
|
|
92
|
+
const raw = `aaa\tAlice\talice@x.com\tfix: thing\nbody line 1\nbody line 2\n${COMMIT_SEP}\n`;
|
|
93
|
+
const out = parseCommitLog(raw);
|
|
94
|
+
expect(out[0].message).toContain("body line 1");
|
|
95
|
+
expect(out[0].message).toContain("body line 2");
|
|
96
|
+
});
|
|
97
|
+
it("skips malformed header lines", () => {
|
|
98
|
+
const raw = `not-enough-tabs\n${COMMIT_SEP}\naaa\tAlice\talice@x.com\tok\n${COMMIT_SEP}\n`;
|
|
99
|
+
const out = parseCommitLog(raw);
|
|
100
|
+
expect(out).toHaveLength(1);
|
|
101
|
+
expect(out[0].hash).toBe("aaa");
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
describe("audit/trace — parseShortstat", () => {
|
|
105
|
+
it("parses standard --shortstat output", () => {
|
|
106
|
+
const s = " 4 files changed, 32 insertions(+), 7 deletions(-)";
|
|
107
|
+
expect(parseShortstat(s)).toEqual({ insertions: 32, deletions: 7 });
|
|
108
|
+
});
|
|
109
|
+
it("handles insertions-only", () => {
|
|
110
|
+
const s = " 1 file changed, 5 insertions(+)";
|
|
111
|
+
expect(parseShortstat(s)).toEqual({ insertions: 5, deletions: 0 });
|
|
112
|
+
});
|
|
113
|
+
it("returns zeros on empty input", () => {
|
|
114
|
+
expect(parseShortstat("")).toEqual({ insertions: 0, deletions: 0 });
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
describe("audit/trace — traceSession (mocked GitRunner)", () => {
|
|
118
|
+
function makeRunner(responses) {
|
|
119
|
+
return {
|
|
120
|
+
run(_cwd, args) {
|
|
121
|
+
const key = args.join(" ");
|
|
122
|
+
for (const [k, v] of Object.entries(responses)) {
|
|
123
|
+
if (key.startsWith(k))
|
|
124
|
+
return v;
|
|
125
|
+
}
|
|
126
|
+
return "";
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
it("returns empty trace when HEAD == baseline", async () => {
|
|
131
|
+
const runner = makeRunner({ "rev-parse HEAD": "abc\n" });
|
|
132
|
+
const t = await traceSession("/repo", "abc", runner);
|
|
133
|
+
expect(t.commits).toEqual([]);
|
|
134
|
+
expect(t.insertions).toBe(0);
|
|
135
|
+
expect(t.deletions).toBe(0);
|
|
136
|
+
expect(t.fromHash).toBe("abc");
|
|
137
|
+
expect(t.toHash).toBe("abc");
|
|
138
|
+
});
|
|
139
|
+
it("collects commits, files, and stats since baseline", async () => {
|
|
140
|
+
const runner = makeRunner({
|
|
141
|
+
"rev-parse HEAD": "newhead\n",
|
|
142
|
+
"log abc..HEAD": `aaa\tAlice\tnoreply@anthropic.com\tfix\n${COMMIT_SEP}\n` +
|
|
143
|
+
`bbb\tBob\tbob@x.com\trefactor\n${COMMIT_SEP}\n`,
|
|
144
|
+
"diff --shortstat abc..HEAD": " 2 files changed, 10 insertions(+), 3 deletions(-)",
|
|
145
|
+
"diff --name-only abc..HEAD": "src/a.ts\nsrc/b.ts\n",
|
|
146
|
+
});
|
|
147
|
+
const t = await traceSession("/repo", "abc", runner);
|
|
148
|
+
expect(t.commits).toHaveLength(2);
|
|
149
|
+
expect(t.commits[0].likelyAI?.vendor).toBe("claude");
|
|
150
|
+
expect(t.filesChanged).toEqual(["src/a.ts", "src/b.ts"]);
|
|
151
|
+
expect(t.insertions).toBe(10);
|
|
152
|
+
expect(t.deletions).toBe(3);
|
|
153
|
+
expect(t.fromHash).toBe("abc");
|
|
154
|
+
expect(t.toHash).toBe("newhead");
|
|
155
|
+
});
|
|
156
|
+
it("dedupes file paths across commits", async () => {
|
|
157
|
+
const runner = makeRunner({
|
|
158
|
+
"rev-parse HEAD": "newhead\n",
|
|
159
|
+
"log abc..HEAD": `aaa\tA\ta@x.com\tedit\n${COMMIT_SEP}\n`,
|
|
160
|
+
"diff --shortstat abc..HEAD": "",
|
|
161
|
+
"diff --name-only abc..HEAD": "src/a.ts\nsrc/a.ts\nsrc/b.ts\n",
|
|
162
|
+
});
|
|
163
|
+
const t = await traceSession("/repo", "abc", runner);
|
|
164
|
+
expect(t.filesChanged).toEqual(["src/a.ts", "src/b.ts"]);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
describe("audit/trace — aggregations", () => {
|
|
168
|
+
it("aiCommitCount + aiVendorBreakdown work together", () => {
|
|
169
|
+
const trace = {
|
|
170
|
+
fromHash: "x",
|
|
171
|
+
toHash: "y",
|
|
172
|
+
commits: [
|
|
173
|
+
{ hash: "1", shortHash: "1", author: "A", authorEmail: "a", message: "m", likelyAI: { vendor: "claude", confidence: 0.95 } },
|
|
174
|
+
{ hash: "2", shortHash: "2", author: "B", authorEmail: "b", message: "m", likelyAI: { vendor: "claude", confidence: 0.95 } },
|
|
175
|
+
{ hash: "3", shortHash: "3", author: "C", authorEmail: "c", message: "m", likelyAI: { vendor: "cursor", confidence: 0.9 } },
|
|
176
|
+
{ hash: "4", shortHash: "4", author: "D", authorEmail: "d", message: "m" },
|
|
177
|
+
],
|
|
178
|
+
filesChanged: [],
|
|
179
|
+
insertions: 0,
|
|
180
|
+
deletions: 0,
|
|
181
|
+
};
|
|
182
|
+
expect(aiCommitCount(trace)).toBe(3);
|
|
183
|
+
const b = aiVendorBreakdown(trace);
|
|
184
|
+
expect(b[0]).toEqual({ vendor: "claude", count: 2 });
|
|
185
|
+
expect(b[1]).toEqual({ vendor: "cursor", count: 1 });
|
|
186
|
+
});
|
|
187
|
+
it("aiVendorBreakdown returns [] when no AI commits", () => {
|
|
188
|
+
expect(aiVendorBreakdown({
|
|
189
|
+
fromHash: "x",
|
|
190
|
+
toHash: "y",
|
|
191
|
+
commits: [{ hash: "1", shortHash: "1", author: "A", authorEmail: "a", message: "m" }],
|
|
192
|
+
filesChanged: [],
|
|
193
|
+
insertions: 0,
|
|
194
|
+
deletions: 0,
|
|
195
|
+
})).toEqual([]);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
//# sourceMappingURL=trace.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.test.js","sourceRoot":"","sources":["../../src/audit/trace.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Session Audit — VERIFY module.
|
|
3
|
+
*
|
|
4
|
+
* "Leviathan-style narrative check" — compare the AI's COMMIT MESSAGE
|
|
5
|
+
* (the draft) against the actual git diff (the strict target). Every
|
|
6
|
+
* claim the AI made must be supported by the change set; un-supported
|
|
7
|
+
* claims are flagged "contradicted" so reviewers see exactly what was
|
|
8
|
+
* over-promised.
|
|
9
|
+
*
|
|
10
|
+
* Inspired by `verifyAnswerLeviathan` in `retrieve/leviathan.ts`:
|
|
11
|
+
* draft/target speculative-decoding loop, single pass, no re-draft.
|
|
12
|
+
*
|
|
13
|
+
* Pure functions. No I/O.
|
|
14
|
+
*/
|
|
15
|
+
export type ClaimKind = "additive" | "fix" | "negation" | "scope" | "other";
|
|
16
|
+
export interface ClaimVerdictRow {
|
|
17
|
+
claim: string;
|
|
18
|
+
verdict: "verified" | "contradicted" | "unverifiable";
|
|
19
|
+
reason: string;
|
|
20
|
+
}
|
|
21
|
+
export interface NarrativeCheck {
|
|
22
|
+
commitHash: string;
|
|
23
|
+
/** Claims extracted from the commit message. */
|
|
24
|
+
claims: Array<{
|
|
25
|
+
text: string;
|
|
26
|
+
kind: ClaimKind;
|
|
27
|
+
}>;
|
|
28
|
+
/** Files actually touched in the diff. */
|
|
29
|
+
filesTouched: string[];
|
|
30
|
+
/** Per-claim verifications. */
|
|
31
|
+
verifications: ClaimVerdictRow[];
|
|
32
|
+
/** Fraction of verifiable claims that verified — `unverifiable` excluded. */
|
|
33
|
+
narrativeTrustScore: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Split the commit message into claim sentences. We use a permissive
|
|
37
|
+
* sentence splitter (period / newline) and skip anything that looks
|
|
38
|
+
* like trailers (`Co-Authored-By:`, `Signed-off-by:`, etc.) since those
|
|
39
|
+
* aren't claims about the diff.
|
|
40
|
+
*
|
|
41
|
+
* Subtlety: we DON'T treat `.` as a sentence boundary when it's inside
|
|
42
|
+
* what looks like a file path (`db.ts`, `src/foo.ts`). Otherwise the
|
|
43
|
+
* negation claim "no change to db.ts" gets split into useless fragments.
|
|
44
|
+
*/
|
|
45
|
+
export declare function extractClaimSentences(message: string): string[];
|
|
46
|
+
/** Classify a single sentence into a coarse claim kind. */
|
|
47
|
+
export declare function classifyClaim(sentence: string): ClaimKind;
|
|
48
|
+
/** Best-effort: does any file in `filesTouched` end with `path` (or contain it)? */
|
|
49
|
+
export declare function fileTouched(filesTouched: string[], path: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Run the narrative check. Returns per-claim verdicts and an aggregate
|
|
52
|
+
* trust score. When no claims are verifiable (all "unverifiable"), we
|
|
53
|
+
* default trust to 1.0 (the message simply didn't make a checkable
|
|
54
|
+
* promise — refusing to score that as a failure).
|
|
55
|
+
*/
|
|
56
|
+
export declare function verifyNarrative(commitMessage: string, diff: string, filesTouched: string[], commitHash?: string): NarrativeCheck;
|
|
57
|
+
/** Convenience: aggregate trust across many commits (mean of per-commit scores). */
|
|
58
|
+
export declare function aggregateNarrativeTrust(checks: NarrativeCheck[]): number;
|
|
59
|
+
/** Did any commit in the set have a contradicted claim? */
|
|
60
|
+
export declare function hasContradiction(checks: NarrativeCheck[]): boolean;
|
|
61
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/audit/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,KAAK,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,CAAC;AAE5E,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,UAAU,GAAG,cAAc,GAAG,cAAc,CAAC;IACtD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IACjD,0CAA0C;IAC1C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,+BAA+B;IAC/B,aAAa,EAAE,eAAe,EAAE,CAAC;IACjC,6EAA6E;IAC7E,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AA0BD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAoB/D;AAED,2DAA2D;AAC3D,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAMzD;AAeD,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CASzE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EAAE,EACtB,UAAU,GAAE,MAAW,GACtB,cAAc,CA4BhB;AA6HD,oFAAoF;AACpF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,CAIxE;AAED,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAOlE"}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Session Audit — VERIFY module.
|
|
3
|
+
*
|
|
4
|
+
* "Leviathan-style narrative check" — compare the AI's COMMIT MESSAGE
|
|
5
|
+
* (the draft) against the actual git diff (the strict target). Every
|
|
6
|
+
* claim the AI made must be supported by the change set; un-supported
|
|
7
|
+
* claims are flagged "contradicted" so reviewers see exactly what was
|
|
8
|
+
* over-promised.
|
|
9
|
+
*
|
|
10
|
+
* Inspired by `verifyAnswerLeviathan` in `retrieve/leviathan.ts`:
|
|
11
|
+
* draft/target speculative-decoding loop, single pass, no re-draft.
|
|
12
|
+
*
|
|
13
|
+
* Pure functions. No I/O.
|
|
14
|
+
*/
|
|
15
|
+
const NEGATION_RES = [
|
|
16
|
+
/\bno\s+changes?\s+to\s+([\w./\-]+)/i,
|
|
17
|
+
/\bdoes\s+not\s+touch\s+([\w./\-]+)/i,
|
|
18
|
+
/\bwithout\s+modifying\s+([\w./\-]+)/i,
|
|
19
|
+
/\bleav(?:e|ing|es)\s+([\w./\-]+)\s+(?:alone|unchanged)/i,
|
|
20
|
+
];
|
|
21
|
+
const ADDITIVE_RES = [
|
|
22
|
+
/\badds?\s+([\w]+(?:\s+\w+){0,3})/i,
|
|
23
|
+
/\bintroduces?\s+([\w]+(?:\s+\w+){0,3})/i,
|
|
24
|
+
/\bcreates?\s+([\w]+(?:\s+\w+){0,3})/i,
|
|
25
|
+
/\bnew\s+(?:function|class|module|file)\s+([\w$]+)/i,
|
|
26
|
+
];
|
|
27
|
+
const FIX_RES = [
|
|
28
|
+
/\bfix(?:es|ed)?\s+(?:a\s+)?(typo|bug|crash|regression|race|leak|null)/i,
|
|
29
|
+
/\bcorrects?\s+(?:a\s+)?(typo|bug|crash|regression|race|leak|null)/i,
|
|
30
|
+
];
|
|
31
|
+
const SCOPE_RES = [
|
|
32
|
+
/\bonly\s+(?:touches|modifies|affects)\s+([\w./\-]+)/i,
|
|
33
|
+
/\bjust\s+a?\s*(typo|comment|docstring)/i,
|
|
34
|
+
];
|
|
35
|
+
/**
|
|
36
|
+
* Split the commit message into claim sentences. We use a permissive
|
|
37
|
+
* sentence splitter (period / newline) and skip anything that looks
|
|
38
|
+
* like trailers (`Co-Authored-By:`, `Signed-off-by:`, etc.) since those
|
|
39
|
+
* aren't claims about the diff.
|
|
40
|
+
*
|
|
41
|
+
* Subtlety: we DON'T treat `.` as a sentence boundary when it's inside
|
|
42
|
+
* what looks like a file path (`db.ts`, `src/foo.ts`). Otherwise the
|
|
43
|
+
* negation claim "no change to db.ts" gets split into useless fragments.
|
|
44
|
+
*/
|
|
45
|
+
export function extractClaimSentences(message) {
|
|
46
|
+
if (!message)
|
|
47
|
+
return [];
|
|
48
|
+
const out = [];
|
|
49
|
+
for (const line of message.split(/\n+/)) {
|
|
50
|
+
const trimmed = line.trim();
|
|
51
|
+
if (!trimmed)
|
|
52
|
+
continue;
|
|
53
|
+
if (/^[A-Z][\w-]+:\s/.test(trimmed))
|
|
54
|
+
continue; // trailers
|
|
55
|
+
if (/^\s*[*-]\s/.test(trimmed)) {
|
|
56
|
+
out.push(trimmed.replace(/^\s*[*-]\s+/, "").trim());
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
// Sentence boundary: `[.!?]` followed by whitespace OR end-of-line.
|
|
60
|
+
// This preserves filename dots like "db.ts" inside a sentence.
|
|
61
|
+
const parts = trimmed
|
|
62
|
+
.split(/[.!?]+(?=\s|$)/)
|
|
63
|
+
.map((s) => s.trim())
|
|
64
|
+
.filter((s) => s.length >= 5);
|
|
65
|
+
out.push(...parts);
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
/** Classify a single sentence into a coarse claim kind. */
|
|
70
|
+
export function classifyClaim(sentence) {
|
|
71
|
+
for (const re of NEGATION_RES)
|
|
72
|
+
if (re.test(sentence))
|
|
73
|
+
return "negation";
|
|
74
|
+
for (const re of FIX_RES)
|
|
75
|
+
if (re.test(sentence))
|
|
76
|
+
return "fix";
|
|
77
|
+
for (const re of ADDITIVE_RES)
|
|
78
|
+
if (re.test(sentence))
|
|
79
|
+
return "additive";
|
|
80
|
+
for (const re of SCOPE_RES)
|
|
81
|
+
if (re.test(sentence))
|
|
82
|
+
return "scope";
|
|
83
|
+
return "other";
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Extract a file/path mention from a sentence — only `foo/bar.ts`-style
|
|
87
|
+
* tokens (must contain a dot OR a slash). We use this for negation +
|
|
88
|
+
* scope claims.
|
|
89
|
+
*/
|
|
90
|
+
function extractPath(sentence) {
|
|
91
|
+
const m = sentence.match(/\b([\w./\-]+(?:\.\w+|\/[\w./\-]+))\b/);
|
|
92
|
+
if (!m)
|
|
93
|
+
return undefined;
|
|
94
|
+
const tok = m[1] ?? "";
|
|
95
|
+
if (!/[./]/.test(tok))
|
|
96
|
+
return undefined;
|
|
97
|
+
return tok;
|
|
98
|
+
}
|
|
99
|
+
/** Best-effort: does any file in `filesTouched` end with `path` (or contain it)? */
|
|
100
|
+
export function fileTouched(filesTouched, path) {
|
|
101
|
+
const norm = path.replace(/^\.\//, "").toLowerCase();
|
|
102
|
+
for (const f of filesTouched) {
|
|
103
|
+
const lf = f.toLowerCase();
|
|
104
|
+
if (lf === norm)
|
|
105
|
+
return true;
|
|
106
|
+
if (lf.endsWith("/" + norm))
|
|
107
|
+
return true;
|
|
108
|
+
if (norm.includes("/") && lf.includes(norm))
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Run the narrative check. Returns per-claim verdicts and an aggregate
|
|
115
|
+
* trust score. When no claims are verifiable (all "unverifiable"), we
|
|
116
|
+
* default trust to 1.0 (the message simply didn't make a checkable
|
|
117
|
+
* promise — refusing to score that as a failure).
|
|
118
|
+
*/
|
|
119
|
+
export function verifyNarrative(commitMessage, diff, filesTouched, commitHash = "") {
|
|
120
|
+
const sentences = extractClaimSentences(commitMessage);
|
|
121
|
+
const claims = sentences.map((text) => ({ text, kind: classifyClaim(text) }));
|
|
122
|
+
const verifications = [];
|
|
123
|
+
// Counters for the trust score.
|
|
124
|
+
let verifiable = 0;
|
|
125
|
+
let verified = 0;
|
|
126
|
+
for (const claim of claims) {
|
|
127
|
+
const v = verifyOneClaim(claim, diff, filesTouched);
|
|
128
|
+
verifications.push(v);
|
|
129
|
+
if (v.verdict !== "unverifiable") {
|
|
130
|
+
verifiable += 1;
|
|
131
|
+
if (v.verdict === "verified")
|
|
132
|
+
verified += 1;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const narrativeTrustScore = verifiable === 0 ? 1.0 : Number((verified / verifiable).toFixed(2));
|
|
136
|
+
return {
|
|
137
|
+
commitHash,
|
|
138
|
+
claims,
|
|
139
|
+
filesTouched,
|
|
140
|
+
verifications,
|
|
141
|
+
narrativeTrustScore,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function verifyOneClaim(claim, diff, filesTouched) {
|
|
145
|
+
const text = claim.text;
|
|
146
|
+
switch (claim.kind) {
|
|
147
|
+
case "negation": {
|
|
148
|
+
// "no change to X" → contradicted iff X is in filesTouched.
|
|
149
|
+
const path = extractPath(text);
|
|
150
|
+
if (!path) {
|
|
151
|
+
return {
|
|
152
|
+
claim: text,
|
|
153
|
+
verdict: "unverifiable",
|
|
154
|
+
reason: "negation claim with no specific file/path to check",
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (fileTouched(filesTouched, path)) {
|
|
158
|
+
return {
|
|
159
|
+
claim: text,
|
|
160
|
+
verdict: "contradicted",
|
|
161
|
+
reason: `claim says "${path}" untouched, but diff modifies it`,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
claim: text,
|
|
166
|
+
verdict: "verified",
|
|
167
|
+
reason: `path "${path}" is not in the diff`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
case "additive": {
|
|
171
|
+
// Look for a `+function|class|interface|export <name>` line in the diff.
|
|
172
|
+
const tokens = text.match(/\b(?:function|class|interface|module|export|file)\s+([A-Za-z_$][\w$]*)/i);
|
|
173
|
+
const named = tokens ? tokens[1] : undefined;
|
|
174
|
+
if (named) {
|
|
175
|
+
const re = new RegExp(`^\\+.*\\b${escapeRe(named)}\\b`, "m");
|
|
176
|
+
if (re.test(diff)) {
|
|
177
|
+
return {
|
|
178
|
+
claim: text,
|
|
179
|
+
verdict: "verified",
|
|
180
|
+
reason: `diff contains an additive line referencing "${named}"`,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
claim: text,
|
|
185
|
+
verdict: "contradicted",
|
|
186
|
+
reason: `claim says "added ${named}" but no additive line references that name`,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
// No specific token — just sanity check there ARE additions.
|
|
190
|
+
if (!/^\+/m.test(diff)) {
|
|
191
|
+
return {
|
|
192
|
+
claim: text,
|
|
193
|
+
verdict: "contradicted",
|
|
194
|
+
reason: "claim says additive but diff has no `+` lines",
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
claim: text,
|
|
199
|
+
verdict: "unverifiable",
|
|
200
|
+
reason: "additive claim is too generic to verify against diff",
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
case "fix": {
|
|
204
|
+
// "fix typo" but diff is huge → suspicious; we mark unverifiable
|
|
205
|
+
// unless the whole diff is tiny (then verified).
|
|
206
|
+
const addLines = (diff.match(/^\+/gm) ?? []).length;
|
|
207
|
+
const delLines = (diff.match(/^-/gm) ?? []).length;
|
|
208
|
+
const churn = addLines + delLines;
|
|
209
|
+
// heuristic: typo fix should be < 20 lines of churn.
|
|
210
|
+
if (/typo/i.test(text) && churn > 20) {
|
|
211
|
+
return {
|
|
212
|
+
claim: text,
|
|
213
|
+
verdict: "contradicted",
|
|
214
|
+
reason: `claim is "fix typo" but diff has ${churn} +/- lines (suspicious)`,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
claim: text,
|
|
219
|
+
verdict: churn > 0 ? "verified" : "contradicted",
|
|
220
|
+
reason: churn > 0
|
|
221
|
+
? `diff has ${churn} +/- lines consistent with a fix`
|
|
222
|
+
: "claim says fix but diff is empty",
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
case "scope": {
|
|
226
|
+
const path = extractPath(text);
|
|
227
|
+
if (!path) {
|
|
228
|
+
return {
|
|
229
|
+
claim: text,
|
|
230
|
+
verdict: "unverifiable",
|
|
231
|
+
reason: "scope claim has no specific file to check",
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// "only touches X" → fail iff any file outside X is touched.
|
|
235
|
+
const stray = filesTouched.find((f) => !fileTouched([f], path));
|
|
236
|
+
if (stray) {
|
|
237
|
+
return {
|
|
238
|
+
claim: text,
|
|
239
|
+
verdict: "contradicted",
|
|
240
|
+
reason: `claim says "only ${path}" but diff also touches "${stray}"`,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
claim: text,
|
|
245
|
+
verdict: "verified",
|
|
246
|
+
reason: `every touched file matches the scope "${path}"`,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
case "other":
|
|
250
|
+
default:
|
|
251
|
+
return {
|
|
252
|
+
claim: text,
|
|
253
|
+
verdict: "unverifiable",
|
|
254
|
+
reason: "no rule matches this claim shape",
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function escapeRe(s) {
|
|
259
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
260
|
+
}
|
|
261
|
+
/** Convenience: aggregate trust across many commits (mean of per-commit scores). */
|
|
262
|
+
export function aggregateNarrativeTrust(checks) {
|
|
263
|
+
if (checks.length === 0)
|
|
264
|
+
return 1.0;
|
|
265
|
+
const sum = checks.reduce((s, c) => s + c.narrativeTrustScore, 0);
|
|
266
|
+
return Number((sum / checks.length).toFixed(2));
|
|
267
|
+
}
|
|
268
|
+
/** Did any commit in the set have a contradicted claim? */
|
|
269
|
+
export function hasContradiction(checks) {
|
|
270
|
+
for (const c of checks) {
|
|
271
|
+
for (const v of c.verifications) {
|
|
272
|
+
if (v.verdict === "contradicted")
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/audit/verify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.test.d.ts","sourceRoot":"","sources":["../../src/audit/verify.test.ts"],"names":[],"mappings":""}
|