@jmtrin/opencode-kevin 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +580 -360
  2. package/dist/migrations/006_v05_glassbox.sql +118 -0
  3. package/dist/migrations/007_v06_pull.sql +145 -0
  4. package/dist/plugin/Archiver.d.ts +42 -0
  5. package/dist/plugin/Archiver.js +99 -0
  6. package/dist/plugin/Archiver.js.map +1 -0
  7. package/dist/plugin/ArtifactWriter.d.ts +50 -0
  8. package/dist/plugin/ArtifactWriter.js +240 -0
  9. package/dist/plugin/ArtifactWriter.js.map +1 -0
  10. package/dist/plugin/ContextInjector.d.ts +87 -0
  11. package/dist/plugin/ContextInjector.js +212 -44
  12. package/dist/plugin/ContextInjector.js.map +1 -1
  13. package/dist/plugin/Curator.d.ts +96 -0
  14. package/dist/plugin/Curator.js +252 -0
  15. package/dist/plugin/Curator.js.map +1 -0
  16. package/dist/plugin/Feedback.d.ts +67 -0
  17. package/dist/plugin/Feedback.js +138 -0
  18. package/dist/plugin/Feedback.js.map +1 -0
  19. package/dist/plugin/InjectionLedger.d.ts +9 -2
  20. package/dist/plugin/InjectionLedger.js +63 -9
  21. package/dist/plugin/InjectionLedger.js.map +1 -1
  22. package/dist/plugin/Materializer.d.ts +59 -0
  23. package/dist/plugin/Materializer.js +237 -0
  24. package/dist/plugin/Materializer.js.map +1 -0
  25. package/dist/plugin/MemoryService.d.ts +38 -0
  26. package/dist/plugin/MemoryService.js +265 -30
  27. package/dist/plugin/MemoryService.js.map +1 -1
  28. package/dist/plugin/Migrate.js +41 -0
  29. package/dist/plugin/Migrate.js.map +1 -1
  30. package/dist/plugin/QualityGate.d.ts +53 -0
  31. package/dist/plugin/QualityGate.js +50 -8
  32. package/dist/plugin/QualityGate.js.map +1 -1
  33. package/dist/plugin/Retrospective.d.ts +1 -0
  34. package/dist/plugin/Retrospective.js +24 -1
  35. package/dist/plugin/Retrospective.js.map +1 -1
  36. package/dist/plugin/capabilities.d.ts +15 -0
  37. package/dist/plugin/capabilities.js +42 -0
  38. package/dist/plugin/capabilities.js.map +1 -0
  39. package/dist/plugin/confidence.d.ts +3 -1
  40. package/dist/plugin/confidence.js +14 -2
  41. package/dist/plugin/confidence.js.map +1 -1
  42. package/dist/plugin/diff.d.ts +8 -0
  43. package/dist/plugin/diff.js +183 -0
  44. package/dist/plugin/diff.js.map +1 -0
  45. package/dist/plugin/index.d.ts +3 -1
  46. package/dist/plugin/index.js +371 -0
  47. package/dist/plugin/index.js.map +1 -1
  48. package/dist/plugin/inferability.d.ts +32 -0
  49. package/dist/plugin/inferability.js +89 -0
  50. package/dist/plugin/inferability.js.map +1 -0
  51. package/dist/plugin/kevin_approve.d.ts +34 -0
  52. package/dist/plugin/kevin_approve.js +50 -0
  53. package/dist/plugin/kevin_approve.js.map +1 -0
  54. package/dist/plugin/kevin_audit.d.ts +95 -0
  55. package/dist/plugin/kevin_audit.js +233 -0
  56. package/dist/plugin/kevin_audit.js.map +1 -0
  57. package/dist/plugin/kevin_propose.d.ts +23 -0
  58. package/dist/plugin/kevin_propose.js +15 -0
  59. package/dist/plugin/kevin_propose.js.map +1 -0
  60. package/dist/plugin/kevin_publish.d.ts +38 -0
  61. package/dist/plugin/kevin_publish.js +19 -0
  62. package/dist/plugin/kevin_publish.js.map +1 -0
  63. package/dist/plugin/kevin_why.js +23 -2
  64. package/dist/plugin/kevin_why.js.map +1 -1
  65. package/dist/plugin/metrics.d.ts +32 -1
  66. package/dist/plugin/metrics.js +86 -2
  67. package/dist/plugin/metrics.js.map +1 -1
  68. package/dist/plugin/replay-types.d.ts +327 -0
  69. package/dist/plugin/replay-types.js +65 -0
  70. package/dist/plugin/replay-types.js.map +1 -0
  71. package/dist/plugin/replay.d.ts +36 -0
  72. package/dist/plugin/replay.js +203 -0
  73. package/dist/plugin/replay.js.map +1 -0
  74. package/migrations/006_v05_glassbox.sql +118 -0
  75. package/migrations/007_v06_pull.sql +145 -0
  76. package/package.json +3 -2
@@ -0,0 +1,252 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ import { MARKER_BEGIN, MARKER_END, } from "./ArtifactWriter.js";
4
+ import { computeConfidence } from "./confidence.js";
5
+ import { uuidv7 } from "./uuid.js";
6
+ const MAX_CANDIDATE_LINES = 20;
7
+ const MAX_CANDIDATE_CHARS = 4000;
8
+ const CONFIDENCE_FLOOR = 0.6;
9
+ const MAX_SENTENCE_CHARS = 160;
10
+ export function firstSentence(content) {
11
+ const match = content.match(/^[\s\S]*?(?=[.!?](?:\s|$)|\r?\n|$)/);
12
+ const sentence = (match ? match[0] : content).trim();
13
+ return sentence.slice(0, MAX_SENTENCE_CHARS);
14
+ }
15
+ function evidenceString(row) {
16
+ const parts = [];
17
+ if (row.evidence_count >= 2) {
18
+ const last = row.last_verified_at
19
+ ? `, last ${row.last_verified_at.slice(0, 10)}`
20
+ : "";
21
+ parts.push(`verified ${row.evidence_count}×${last}`);
22
+ }
23
+ if (row.feedback_positive >= 1) {
24
+ parts.push(`feedback ${row.feedback_positive}×`);
25
+ }
26
+ return parts.join(", ");
27
+ }
28
+ export class Curator {
29
+ store;
30
+ memoryService;
31
+ projectId;
32
+ metrics;
33
+ constructor(store, memoryService, projectId, metrics) {
34
+ this.store = store;
35
+ this.memoryService = memoryService;
36
+ this.projectId = projectId;
37
+ this.metrics = metrics ?? null;
38
+ }
39
+ /**
40
+ * Plan §5.4 selection predicate — all clauses must hold, evaluated
41
+ * verbatim. The confidence floor cannot be expressed in SQL (it is the
42
+ * two-sided formula of `computeConfidence`), so the cheap clauses run
43
+ * in SQL and confidence is computed and filtered per row in JS.
44
+ *
45
+ * The floor is `confidence >= 0.6` where the feedback arm of D6-09 also
46
+ * clears it: `computeConfidence` credits one positive human verdict at
47
+ * 0.05 (K5-010), so a row with `feedback_positive = 1` and no causal
48
+ * evidence scores 0.55 — yet D6-09's warrant is "either the world
49
+ * verified it twice, or a human verified it once". The disjunction
50
+ * (K6-012 acceptance) is the floor's complement for the feedback arm.
51
+ *
52
+ * Ordered by `confidence DESC, updated_at DESC`, capped at 20 lines and
53
+ * 4000 characters of content, whichever binds first. The char budget
54
+ * counts the raw content length: rendered lines are truncated to 160
55
+ * chars, so a rendered-line budget could never bind before the line cap.
56
+ */
57
+ candidates(limit) {
58
+ const rows = this.store
59
+ .prepare(`SELECT id, content, evidence_count, recurrence_count,
60
+ feedback_positive, feedback_negative,
61
+ last_verified_at, updated_at
62
+ FROM memories
63
+ WHERE status = 'active'
64
+ AND ignored = 0
65
+ AND curated = 0
66
+ AND (inferable IS NULL OR inferable != 1)
67
+ AND (evidence_count >= 2 OR feedback_positive >= 1)`)
68
+ .all();
69
+ const scored = rows
70
+ .map((row) => ({
71
+ row,
72
+ confidence: computeConfidence(row.evidence_count ?? 0, row.recurrence_count ?? 0, row.feedback_positive ?? 0, row.feedback_negative ?? 0),
73
+ }))
74
+ .filter((s) => s.confidence >= CONFIDENCE_FLOOR || s.row.feedback_positive >= 1)
75
+ .sort((a, b) => b.confidence - a.confidence ||
76
+ b.row.updated_at.localeCompare(a.row.updated_at));
77
+ const maxLines = limit ?? MAX_CANDIDATE_LINES;
78
+ const result = [];
79
+ let totalChars = 0;
80
+ for (const s of scored) {
81
+ if (result.length >= maxLines)
82
+ break;
83
+ if (totalChars + s.row.content.length > MAX_CANDIDATE_CHARS)
84
+ break;
85
+ const evidence = evidenceString(s.row);
86
+ result.push({
87
+ memoryId: s.row.id,
88
+ line: `- ${firstSentence(s.row.content)} (${evidence})`,
89
+ confidence: s.confidence,
90
+ evidence,
91
+ });
92
+ totalChars += s.row.content.length;
93
+ }
94
+ return result;
95
+ }
96
+ /**
97
+ * Renders the block sorted by memory id (D6-10): confidence orders
98
+ * selection, id orders output. Adding one candidate to a set of ten
99
+ * must change exactly one line of the rendered block.
100
+ */
101
+ renderBlock(candidates) {
102
+ const sorted = [...candidates].sort((a, b) => a.memoryId.localeCompare(b.memoryId));
103
+ return `${sorted.map((c) => c.line).join("\n")}\n`;
104
+ }
105
+ /**
106
+ * Plan §5.4 — strict dry run (D5-08): plan only, never write. Returns a
107
+ * pending proposal per call, or [] when no candidate clears the floor.
108
+ *
109
+ * The proposal is a whole-block proposal: the persisted `proposed_text`
110
+ * is the merged block (current block in the file + new candidate lines),
111
+ * so approving it replaces the file block with exactly what was reviewed.
112
+ * The current block is learned from `plan().before` — the Curator has no
113
+ * fs capability, the writer reads (D6-01). Both plan calls are
114
+ * deterministic, so a second propose() with unchanged inputs reproduces
115
+ * the persisted diff byte-identically.
116
+ *
117
+ * A new proposal supersedes prior pending (or rejected) rows for the
118
+ * same (project_id, kind, target_path) triple — §5.5's regeneration
119
+ * arrow. Rows are never deleted (the audit trail is append-only).
120
+ *
121
+ * The schema's `memory_id` column is singular while a whole-block
122
+ * proposal carries several ids; the contributing ids are stored joined
123
+ * by "," (uuidv7 ids contain no comma) and split on read.
124
+ */
125
+ propose(kind, writer) {
126
+ const targetPath = this.targetPathFor(kind);
127
+ const candidates = this.candidates();
128
+ if (candidates.length === 0)
129
+ return [];
130
+ const newBlock = this.renderBlock(candidates);
131
+ const currentBlock = extractBlock(writer.plan(targetPath, newBlock).before);
132
+ // Merge: keep the current block verbatim and append only lines that
133
+ // are not already in it. Without the dedup, a block the user (or an
134
+ // approval) already pasted would be proposed doubled.
135
+ const currentLines = currentBlock === "" ? [] : currentBlock.split(/\r?\n/);
136
+ const newLines = newBlock
137
+ .split("\n")
138
+ .filter((l) => l !== "" && !currentLines.includes(l));
139
+ const mergedBlock = currentBlock === ""
140
+ ? newBlock
141
+ : newLines.length === 0
142
+ ? currentBlock
143
+ : `${currentBlock}${currentBlock.endsWith("\n") ? "" : "\n"}${newLines.join("\n")}\n`;
144
+ const plan = writer.plan(targetPath, mergedBlock);
145
+ const prior = this.store
146
+ .prepare(`SELECT id FROM curation_proposals
147
+ WHERE project_id = ? AND kind = ? AND target_path = ?
148
+ AND status IN ('pending', 'rejected')`)
149
+ .all(this.projectId, kind, targetPath);
150
+ for (const row of prior) {
151
+ this.transition(row.id, "supersede");
152
+ }
153
+ const memoryIds = candidates.map((c) => c.memoryId);
154
+ const id = uuidv7();
155
+ this.store
156
+ .prepare(`INSERT INTO curation_proposals
157
+ (id, project_id, memory_id, kind, target_path,
158
+ proposed_text, diff, status)
159
+ VALUES (?, ?, ?, ?, ?, ?, ?, 'pending')`)
160
+ .run(id, this.projectId, memoryIds.join(","), kind, targetPath, mergedBlock, plan.diff);
161
+ this.metrics?.incr("proposals_created", 1);
162
+ const row = this.store
163
+ .prepare("SELECT created_at FROM curation_proposals WHERE id = ?")
164
+ .get(id);
165
+ return [
166
+ {
167
+ id,
168
+ kind,
169
+ targetPath,
170
+ memoryIds,
171
+ proposedText: mergedBlock,
172
+ diff: plan.diff,
173
+ status: "pending",
174
+ createdAt: row.created_at,
175
+ },
176
+ ];
177
+ }
178
+ /**
179
+ * Plan §5.5 state machine, as explicit transitions with an exhaustive
180
+ * switch — an unknown transition or an illegal source state throws
181
+ * rather than silently no-oping. `decided_at` stamps approve/reject/
182
+ * supersede, `applied_at` stamps apply.
183
+ */
184
+ transition(proposalId, transition) {
185
+ const row = this.store
186
+ .prepare("SELECT status FROM curation_proposals WHERE id = ?")
187
+ .get(proposalId);
188
+ if (!row) {
189
+ throw new Error(`proposal not found: ${proposalId}`);
190
+ }
191
+ const status = row.status;
192
+ let next = null;
193
+ switch (transition) {
194
+ case "approve":
195
+ if (status === "pending")
196
+ next = "approved";
197
+ break;
198
+ case "reject":
199
+ if (status === "pending")
200
+ next = "rejected";
201
+ break;
202
+ case "apply":
203
+ if (status === "approved")
204
+ next = "applied";
205
+ break;
206
+ case "supersede":
207
+ if (status === "pending" || status === "rejected") {
208
+ next = "superseded";
209
+ }
210
+ break;
211
+ default:
212
+ throw new Error(`unknown transition: ${transition}`);
213
+ }
214
+ if (next === null) {
215
+ throw new Error(`illegal transition: ${status} -> ${transition}`);
216
+ }
217
+ if (next === "applied") {
218
+ this.store
219
+ .prepare("UPDATE curation_proposals SET status = 'applied', applied_at = datetime('now') WHERE id = ?")
220
+ .run(proposalId);
221
+ }
222
+ else {
223
+ this.store
224
+ .prepare("UPDATE curation_proposals SET status = ?, decided_at = datetime('now') WHERE id = ?")
225
+ .run(next, proposalId);
226
+ }
227
+ return next;
228
+ }
229
+ /** Plan §5.6 target paths. agents_md is a setting; skill/reference live under ~/.opencode-kevin. */
230
+ targetPathFor(kind) {
231
+ switch (kind) {
232
+ case "agents_md":
233
+ return this.memoryService.getSetting("agents_md_path", "AGENTS.md");
234
+ case "skill":
235
+ return join(homedir(), ".opencode-kevin", "skills", "project-knowledge.md");
236
+ case "reference":
237
+ return join(homedir(), ".opencode-kevin", "refs", "project-knowledge.md");
238
+ }
239
+ }
240
+ }
241
+ /** The block content currently between the markers, "" when absent or malformed. */
242
+ function extractBlock(before) {
243
+ const begin = before.indexOf(MARKER_BEGIN);
244
+ const end = before.indexOf(MARKER_END);
245
+ if (begin === -1 || end === -1 || end < begin)
246
+ return "";
247
+ return before
248
+ .slice(begin + MARKER_BEGIN.length, end)
249
+ .replace(/^\r?\n/, "")
250
+ .replace(/\r?\n$/, "");
251
+ }
252
+ //# sourceMappingURL=Curator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Curator.js","sourceRoot":"","sources":["../../plugin/Curator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import type { Store } from "./Store.js";
2
+ import type { Metrics } from "./metrics.js";
3
+ /**
4
+ * v0.5.0 Feedback (K5-009 / plan §5.3, D5-02).
5
+ *
6
+ * The human-judgement half of the glassbox: the agent can report whether a
7
+ * memory was useful, wrong, outdated, or should be ignored. Verdicts are
8
+ * stored in `memory_feedback` (migration 006_v05_glassbox.sql) and folded
9
+ * into the memory's `feedback_positive` / `feedback_negative` counters —
10
+ * kept SEPARATE from `evidence_count` / `recurrence_count` by design: human
11
+ * judgement is evidence about the memory, causal counters are evidence
12
+ * about the world (the confidence-poisoning defect closed in v0.4.0).
13
+ *
14
+ * D5-07 — the `ignore` verdict is a hard lifecycle action, not a soft
15
+ * signal: the memory is stamped `ignored = 1`, which excludes it from
16
+ * retrieval (K5-008) and from the quality gate (K5-007).
17
+ *
18
+ * Schema:
19
+ * memory_feedback(id PK, memory_id, verdict, session_id, note, created_at)
20
+ * memories(feedback_positive, feedback_negative, ignored)
21
+ */
22
+ export type FeedbackVerdict = "useful" | "wrong" | "outdated" | "ignore";
23
+ export interface FeedbackRecordInput {
24
+ memoryId: string;
25
+ verdict: FeedbackVerdict;
26
+ sessionId?: string | null;
27
+ note?: string | null;
28
+ }
29
+ export interface FeedbackRow {
30
+ id: string;
31
+ memoryId: string;
32
+ verdict: FeedbackVerdict;
33
+ sessionId: string | null;
34
+ note: string | null;
35
+ createdAt: string;
36
+ }
37
+ export interface FeedbackCounts {
38
+ positive: number;
39
+ negative: number;
40
+ }
41
+ export declare class Feedback {
42
+ private readonly store;
43
+ private readonly metrics;
44
+ private readonly now;
45
+ constructor(store: Store, metrics?: Metrics | null, now?: () => Date);
46
+ /**
47
+ * Records one human verdict and folds it into the memory's counters.
48
+ * Counters are RECOMPUTED from the table (never incremented) so rows
49
+ * deleted in tests or by hand cannot drift them.
50
+ *
51
+ * The `ignore` verdict also stamps `memories.ignored = 1` (D5-07).
52
+ * Returns the feedback row id.
53
+ */
54
+ record(input: FeedbackRecordInput): string;
55
+ /** Human-judgement counters for one memory (from the row, not the table). */
56
+ countsFor(memoryId: string): FeedbackCounts;
57
+ /**
58
+ * Raw verdict history, newest first. Used by `kevin_feedback` (K5-011)
59
+ * and by the audit tool (K5-016).
60
+ */
61
+ list(memoryId?: string, limit?: number): FeedbackRow[];
62
+ /**
63
+ * Recompute a memory's positive/negative counters straight from the
64
+ * verdict table. Kept private — `record` is the only mutation path.
65
+ */
66
+ private recomputeCounters;
67
+ }
@@ -0,0 +1,138 @@
1
+ import { uuidv7 } from "./uuid.js";
2
+ const POSITIVE_VERDICTS = ["useful"];
3
+ const NEGATIVE_VERDICTS = [
4
+ "wrong",
5
+ "outdated",
6
+ "ignore",
7
+ ];
8
+ // v0.5.0 — pre-006 DBs lack `memory_feedback`; record() fails loudly with a
9
+ // descriptive error instead of a bare "no such table" (the tool layer turns
10
+ // it into a graceful message).
11
+ // v0.6.0 (K6-001a) — positive-only caching: a successful probe is cached,
12
+ // a failed probe is NOT. A Store migrated in place heals on the next call.
13
+ const feedbackTableCache = new WeakMap();
14
+ function hasFeedbackTable(store) {
15
+ const cached = feedbackTableCache.get(store);
16
+ if (cached === true)
17
+ return true;
18
+ try {
19
+ store.prepare("SELECT COUNT(*) FROM memory_feedback").get();
20
+ feedbackTableCache.set(store, true);
21
+ return true;
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ }
27
+ export class Feedback {
28
+ store;
29
+ metrics;
30
+ now;
31
+ constructor(store, metrics, now = () => new Date()) {
32
+ this.store = store;
33
+ this.metrics = metrics ?? null;
34
+ this.now = now;
35
+ }
36
+ /**
37
+ * Records one human verdict and folds it into the memory's counters.
38
+ * Counters are RECOMPUTED from the table (never incremented) so rows
39
+ * deleted in tests or by hand cannot drift them.
40
+ *
41
+ * The `ignore` verdict also stamps `memories.ignored = 1` (D5-07).
42
+ * Returns the feedback row id.
43
+ */
44
+ record(input) {
45
+ if (!hasFeedbackTable(this.store)) {
46
+ throw new Error("kevin_feedback requires migration 006_v05_glassbox.sql (missing table memory_feedback)");
47
+ }
48
+ const id = uuidv7();
49
+ this.store
50
+ .prepare(`INSERT INTO memory_feedback
51
+ (id, memory_id, verdict, session_id, note)
52
+ VALUES (?, ?, ?, ?, ?)`)
53
+ .run(id, input.memoryId, input.verdict, input.sessionId ?? null, input.note ?? null);
54
+ this.recomputeCounters(input.memoryId);
55
+ if (input.verdict === "ignore") {
56
+ this.store
57
+ .prepare("UPDATE memories SET ignored = 1 WHERE id = ?")
58
+ .run(input.memoryId);
59
+ }
60
+ // v0.5.0 (K5-023 / plan §5.3, D5-06) — lifecycle action of a
61
+ // negative verdict. `wrong` is an opinion and deserves a second
62
+ // opinion: it demotes only at feedback_negative >= 2. `outdated`
63
+ // is a self-verifying claim about the world and acts at once.
64
+ // `useful` confirms the memory and refreshes its verification.
65
+ if (input.verdict === "outdated") {
66
+ this.store
67
+ .prepare("UPDATE memories SET status = 'stale' WHERE id = ?")
68
+ .run(input.memoryId);
69
+ }
70
+ else if (input.verdict === "wrong") {
71
+ const counts = this.countsFor(input.memoryId);
72
+ if (counts.negative >= 2) {
73
+ this.store
74
+ .prepare("UPDATE memories SET status = 'stale' WHERE id = ?")
75
+ .run(input.memoryId);
76
+ }
77
+ }
78
+ else if (input.verdict === "useful") {
79
+ this.store
80
+ .prepare("UPDATE memories SET last_verified_at = datetime('now') WHERE id = ?")
81
+ .run(input.memoryId);
82
+ }
83
+ if (POSITIVE_VERDICTS.includes(input.verdict)) {
84
+ this.metrics?.incr("feedback_positive_total", 1);
85
+ }
86
+ else if (NEGATIVE_VERDICTS.includes(input.verdict)) {
87
+ this.metrics?.incr("feedback_negative_total", 1);
88
+ }
89
+ return id;
90
+ }
91
+ /** Human-judgement counters for one memory (from the row, not the table). */
92
+ countsFor(memoryId) {
93
+ const row = this.store
94
+ .prepare("SELECT feedback_positive, feedback_negative FROM memories WHERE id = ?")
95
+ .get(memoryId);
96
+ if (!row)
97
+ return { positive: 0, negative: 0 };
98
+ return { positive: row.feedback_positive, negative: row.feedback_negative };
99
+ }
100
+ /**
101
+ * Raw verdict history, newest first. Used by `kevin_feedback` (K5-011)
102
+ * and by the audit tool (K5-016).
103
+ */
104
+ list(memoryId, limit = 50) {
105
+ const rows = this.store
106
+ .prepare(`SELECT id, memory_id, verdict, session_id, note, created_at
107
+ FROM memory_feedback
108
+ ${memoryId ? "WHERE memory_id = ?" : ""}
109
+ ORDER BY created_at DESC, rowid DESC
110
+ LIMIT ?`)
111
+ .all(...(memoryId ? [memoryId, limit] : [limit]));
112
+ return rows.map((r) => ({
113
+ id: r.id,
114
+ memoryId: r.memory_id,
115
+ verdict: r.verdict,
116
+ sessionId: r.session_id,
117
+ note: r.note,
118
+ createdAt: r.created_at,
119
+ }));
120
+ }
121
+ /**
122
+ * Recompute a memory's positive/negative counters straight from the
123
+ * verdict table. Kept private — `record` is the only mutation path.
124
+ */
125
+ recomputeCounters(memoryId) {
126
+ this.store
127
+ .prepare(`UPDATE memories SET
128
+ feedback_positive = (
129
+ SELECT COUNT(*) FROM memory_feedback
130
+ WHERE memory_id = ? AND verdict = 'useful'),
131
+ feedback_negative = (
132
+ SELECT COUNT(*) FROM memory_feedback
133
+ WHERE memory_id = ? AND verdict IN ('wrong','outdated','ignore'))
134
+ WHERE id = ?`)
135
+ .run(memoryId, memoryId, memoryId);
136
+ }
137
+ }
138
+ //# sourceMappingURL=Feedback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Feedback.js","sourceRoot":"","sources":["../../plugin/Feedback.ts"],"names":[],"mappings":"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"}
@@ -22,7 +22,7 @@ import type { Metrics } from "./metrics.js";
22
22
  * (ContextInjector.recordInjections) skips them.
23
23
  */
24
24
  export type InjectionHook = "pre_prompt" | "compacting";
25
- export type InjectionOutcome = "unmeasured" | "effective" | "ineffective";
25
+ export type InjectionOutcome = "unmeasured" | "effective" | "ineffective" | "inconclusive";
26
26
  export interface InjectionRecordInput {
27
27
  memoryId: string;
28
28
  fingerprint: string;
@@ -60,7 +60,9 @@ export declare class InjectionLedger {
60
60
  *
61
61
  * An ineffective injection also bumps the target memory's
62
62
  * `recurrence_count` (negative evidence, plan §5.3) and stamps
63
- * `last_injected_at`.
63
+ * `last_injected_at` (monotonically — an older row can never
64
+ * regress a newer injection's timestamp; the column means "most
65
+ * recent injection").
64
66
  */
65
67
  settle(sessionId: string): void;
66
68
  /**
@@ -81,5 +83,10 @@ export declare class InjectionLedger {
81
83
  unsettledForSession(sessionId: string): number;
82
84
  /** Latest ledger rows for a session, newest first (used by tests/tools). */
83
85
  rowsForSession(sessionId: string): InjectionRow[];
86
+ /**
87
+ * v0.5.0 (K5-005 / plan §8.4) — one grouped rollup over the whole
88
+ * ledger, zero-filled for every outcome. Consumed by `kevin_audit`.
89
+ */
90
+ outcomeCounts(): Record<InjectionOutcome, number>;
84
91
  }
85
92
  export {};
@@ -29,13 +29,16 @@ export class InjectionLedger {
29
29
  *
30
30
  * An ineffective injection also bumps the target memory's
31
31
  * `recurrence_count` (negative evidence, plan §5.3) and stamps
32
- * `last_injected_at`.
32
+ * `last_injected_at` (monotonically — an older row can never
33
+ * regress a newer injection's timestamp; the column means "most
34
+ * recent injection").
33
35
  */
34
36
  settle(sessionId) {
35
37
  const injections = this.store
36
38
  .prepare(`SELECT id, memory_id, fingerprint, injected_at, outcome
37
39
  FROM kevin_injections
38
- WHERE session_id = ?`)
40
+ WHERE session_id = ?
41
+ ORDER BY injected_at ASC, id ASC`)
39
42
  .all(sessionId);
40
43
  for (const inj of injections) {
41
44
  // Same identity dimension CausalChain uses: the failing call's
@@ -67,6 +70,11 @@ export class InjectionLedger {
67
70
  LIMIT 1`)
68
71
  .get(sessionId, inj.fingerprint, inj.injected_at, originCallId, originCallId);
69
72
  const n = countRow.n;
73
+ // v0.5.0 (K5-005 / plan §5.1, D5-01) — three-way settlement:
74
+ // recurrences >= 1 → ineffective (existing side effects unchanged)
75
+ // else fixes >= 1 → effective (a linked fix was OBSERVED)
76
+ // else → inconclusive (new majority bucket; excluded
77
+ // from the precision denominator)
70
78
  if (n >= 1) {
71
79
  if (inj.outcome === "unmeasured") {
72
80
  this.store
@@ -78,9 +86,12 @@ export class InjectionLedger {
78
86
  this.store
79
87
  .prepare(`UPDATE memories
80
88
  SET recurrence_count = MAX(recurrence_count, ?),
81
- last_injected_at = ?
89
+ last_injected_at = CASE
90
+ WHEN last_injected_at IS NULL
91
+ OR ? > last_injected_at
92
+ THEN ? ELSE last_injected_at END
82
93
  WHERE fingerprint = ? AND id = ?`)
83
- .run(countRow.n, inj.injected_at, inj.fingerprint, inj.memory_id);
94
+ .run(countRow.n, inj.injected_at, inj.injected_at, inj.fingerprint, inj.memory_id);
84
95
  // v0.4.0 (K4-025 / plan §5.1 rule 4, D4-06) — recurrence
85
96
  // expels: a fingerprint at `recurrence_count >= 3` is
86
97
  // demoted to `status='stale'` and never injected again
@@ -92,11 +103,35 @@ export class InjectionLedger {
92
103
  .run(inj.memory_id);
93
104
  }
94
105
  else if (inj.outcome === "unmeasured") {
95
- this.store
96
- .prepare(`UPDATE kevin_injections SET outcome = 'effective'
97
- WHERE id = ?`)
98
- .run(inj.id);
99
- this.metrics?.incr("injections_effective", 1);
106
+ // Mirror of the recurrence predicate with the success flag
107
+ // inverted and the fingerprint matched on
108
+ // `fix_for_fingerprint` (populated by CausalChain.onSuccess,
109
+ // indexed by idx_tool_calls_fix_fp since migration 004). The
110
+ // `ts >= injected_at` bound and `session_id = ?` filter are
111
+ // kept; there is no `origin_call_id` exemption for fixes —
112
+ // a fix is not the creating call.
113
+ const fixRow = this.store
114
+ .prepare(`SELECT COUNT(*) AS m FROM tool_calls
115
+ WHERE session_id = ?
116
+ AND success = 1
117
+ AND fix_for_fingerprint = ?
118
+ AND ts >= ?
119
+ LIMIT 1`)
120
+ .get(sessionId, inj.fingerprint, inj.injected_at);
121
+ if (fixRow.m >= 1) {
122
+ this.store
123
+ .prepare(`UPDATE kevin_injections SET outcome = 'effective'
124
+ WHERE id = ?`)
125
+ .run(inj.id);
126
+ this.metrics?.incr("injections_effective", 1);
127
+ }
128
+ else {
129
+ this.store
130
+ .prepare(`UPDATE kevin_injections SET outcome = 'inconclusive'
131
+ WHERE id = ?`)
132
+ .run(inj.id);
133
+ this.metrics?.incr("injections_inconclusive", 1);
134
+ }
100
135
  }
101
136
  }
102
137
  }
@@ -165,6 +200,25 @@ export class InjectionLedger {
165
200
  ORDER BY injected_at ASC, id ASC`)
166
201
  .all(sessionId);
167
202
  }
203
+ /**
204
+ * v0.5.0 (K5-005 / plan §8.4) — one grouped rollup over the whole
205
+ * ledger, zero-filled for every outcome. Consumed by `kevin_audit`.
206
+ */
207
+ outcomeCounts() {
208
+ const rows = this.store
209
+ .prepare("SELECT outcome, COUNT(*) AS n FROM kevin_injections GROUP BY outcome")
210
+ .all();
211
+ const out = {
212
+ unmeasured: 0,
213
+ effective: 0,
214
+ ineffective: 0,
215
+ inconclusive: 0,
216
+ };
217
+ for (const r of rows) {
218
+ out[r.outcome] = r.n;
219
+ }
220
+ return out;
221
+ }
168
222
  }
169
223
  /**
170
224
  * BUG-003 — read `origin_call_id` (the failing tool_call that CREATED the
@@ -1 +1 @@
1
- {"version":3,"file":"InjectionLedger.js","sourceRoot":"","sources":["../../plugin/InjectionLedger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"InjectionLedger.js","sourceRoot":"","sources":["../../plugin/InjectionLedger.ts"],"names":[],"mappings":"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"}