@jmtrin/opencode-kevin 1.2.0 → 1.3.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 (141) hide show
  1. package/dist/plugin/index.d.ts +4 -3
  2. package/dist/plugin/index.js +122 -113
  3. package/dist/plugin/native.d.ts +2 -2
  4. package/dist/plugin/native.js +2 -2
  5. package/package.json +56 -68
  6. package/LICENSE +0 -21
  7. package/README.md +0 -605
  8. package/dist/migrations/001_initial.sql +0 -92
  9. package/dist/migrations/002_indexes.sql +0 -14
  10. package/dist/migrations/003_v02_signal.sql +0 -58
  11. package/dist/migrations/004_v03_knowledge.sql +0 -138
  12. package/dist/migrations/005_v04_signal.sql +0 -57
  13. package/dist/migrations/006_v05_glassbox.sql +0 -118
  14. package/dist/migrations/007_v06_pull.sql +0 -145
  15. package/dist/migrations/008_v07_truth.sql +0 -124
  16. package/dist/migrations/009_v08_team.sql +0 -100
  17. package/dist/migrations/010_v09_native.sql +0 -78
  18. package/dist/migrations/011_v10_proven.sql +0 -69
  19. package/dist/migrations/012_v11_drift.sql +0 -24
  20. package/dist/plugin/Archiver.d.ts +0 -42
  21. package/dist/plugin/Archiver.js +0 -83
  22. package/dist/plugin/ArtifactWriter.d.ts +0 -93
  23. package/dist/plugin/ArtifactWriter.js +0 -291
  24. package/dist/plugin/CausalChain.d.ts +0 -22
  25. package/dist/plugin/CausalChain.js +0 -197
  26. package/dist/plugin/ChatBridge.d.ts +0 -41
  27. package/dist/plugin/ChatBridge.js +0 -103
  28. package/dist/plugin/ConflictDetector.d.ts +0 -35
  29. package/dist/plugin/ConflictDetector.js +0 -260
  30. package/dist/plugin/ContextInjector.d.ts +0 -222
  31. package/dist/plugin/ContextInjector.js +0 -533
  32. package/dist/plugin/ConventionMiner.d.ts +0 -35
  33. package/dist/plugin/ConventionMiner.js +0 -242
  34. package/dist/plugin/Curator.d.ts +0 -116
  35. package/dist/plugin/Curator.js +0 -324
  36. package/dist/plugin/DashboardHtml.d.ts +0 -5
  37. package/dist/plugin/DashboardHtml.js +0 -180
  38. package/dist/plugin/Feedback.d.ts +0 -67
  39. package/dist/plugin/Feedback.js +0 -120
  40. package/dist/plugin/HookLiveness.d.ts +0 -88
  41. package/dist/plugin/HookLiveness.js +0 -322
  42. package/dist/plugin/InjectionLedger.d.ts +0 -98
  43. package/dist/plugin/InjectionLedger.js +0 -295
  44. package/dist/plugin/LessonFixer.d.ts +0 -44
  45. package/dist/plugin/LessonFixer.js +0 -45
  46. package/dist/plugin/Materializer.d.ts +0 -83
  47. package/dist/plugin/Materializer.js +0 -181
  48. package/dist/plugin/MemoryService.d.ts +0 -360
  49. package/dist/plugin/MemoryService.js +0 -1242
  50. package/dist/plugin/Migrate.d.ts +0 -17
  51. package/dist/plugin/Migrate.js +0 -271
  52. package/dist/plugin/PatternMiner.d.ts +0 -49
  53. package/dist/plugin/PatternMiner.js +0 -132
  54. package/dist/plugin/QualityGate.d.ts +0 -124
  55. package/dist/plugin/QualityGate.js +0 -119
  56. package/dist/plugin/Reflector.d.ts +0 -91
  57. package/dist/plugin/Reflector.js +0 -307
  58. package/dist/plugin/RepoIdentity.d.ts +0 -124
  59. package/dist/plugin/RepoIdentity.js +0 -300
  60. package/dist/plugin/RepoTruth.d.ts +0 -80
  61. package/dist/plugin/RepoTruth.js +0 -599
  62. package/dist/plugin/Retrospective.d.ts +0 -17
  63. package/dist/plugin/Retrospective.js +0 -216
  64. package/dist/plugin/SharedLayer.d.ts +0 -159
  65. package/dist/plugin/SharedLayer.js +0 -462
  66. package/dist/plugin/Store.d.ts +0 -29
  67. package/dist/plugin/Store.js +0 -50
  68. package/dist/plugin/ToolCallObserver.d.ts +0 -32
  69. package/dist/plugin/ToolCallObserver.js +0 -201
  70. package/dist/plugin/TuiActions.d.ts +0 -43
  71. package/dist/plugin/TuiActions.js +0 -181
  72. package/dist/plugin/TuiSnapshots.d.ts +0 -24
  73. package/dist/plugin/TuiSnapshots.js +0 -158
  74. package/dist/plugin/columns.d.ts +0 -11
  75. package/dist/plugin/columns.js +0 -54
  76. package/dist/plugin/confidence.d.ts +0 -8
  77. package/dist/plugin/confidence.js +0 -34
  78. package/dist/plugin/contract.d.ts +0 -54
  79. package/dist/plugin/contract.js +0 -386
  80. package/dist/plugin/diff.d.ts +0 -8
  81. package/dist/plugin/diff.js +0 -182
  82. package/dist/plugin/escape.d.ts +0 -39
  83. package/dist/plugin/escape.js +0 -60
  84. package/dist/plugin/fingerprint.d.ts +0 -27
  85. package/dist/plugin/fingerprint.js +0 -73
  86. package/dist/plugin/inferability.d.ts +0 -32
  87. package/dist/plugin/inferability.js +0 -88
  88. package/dist/plugin/kevin_approve.d.ts +0 -34
  89. package/dist/plugin/kevin_approve.js +0 -52
  90. package/dist/plugin/kevin_audit.d.ts +0 -229
  91. package/dist/plugin/kevin_audit.js +0 -631
  92. package/dist/plugin/kevin_bench.d.ts +0 -10
  93. package/dist/plugin/kevin_bench.js +0 -82
  94. package/dist/plugin/kevin_conflicts.d.ts +0 -9
  95. package/dist/plugin/kevin_conflicts.js +0 -50
  96. package/dist/plugin/kevin_contract.d.ts +0 -8
  97. package/dist/plugin/kevin_contract.js +0 -59
  98. package/dist/plugin/kevin_doctor.d.ts +0 -62
  99. package/dist/plugin/kevin_doctor.js +0 -196
  100. package/dist/plugin/kevin_facts.d.ts +0 -42
  101. package/dist/plugin/kevin_facts.js +0 -36
  102. package/dist/plugin/kevin_forget.d.ts +0 -33
  103. package/dist/plugin/kevin_forget.js +0 -260
  104. package/dist/plugin/kevin_native.d.ts +0 -29
  105. package/dist/plugin/kevin_native.js +0 -79
  106. package/dist/plugin/kevin_propose.d.ts +0 -23
  107. package/dist/plugin/kevin_propose.js +0 -14
  108. package/dist/plugin/kevin_publish.d.ts +0 -38
  109. package/dist/plugin/kevin_publish.js +0 -18
  110. package/dist/plugin/kevin_why.d.ts +0 -23
  111. package/dist/plugin/kevin_why.js +0 -111
  112. package/dist/plugin/memory-format.d.ts +0 -20
  113. package/dist/plugin/memory-format.js +0 -59
  114. package/dist/plugin/metrics.d.ts +0 -97
  115. package/dist/plugin/metrics.js +0 -288
  116. package/dist/plugin/okf-export.d.ts +0 -3
  117. package/dist/plugin/okf-export.js +0 -134
  118. package/dist/plugin/okf-import.d.ts +0 -76
  119. package/dist/plugin/okf-import.js +0 -271
  120. package/dist/plugin/okf.d.ts +0 -107
  121. package/dist/plugin/okf.js +0 -303
  122. package/dist/plugin/perf.d.ts +0 -35
  123. package/dist/plugin/perf.js +0 -174
  124. package/dist/plugin/query-tokenizer.d.ts +0 -13
  125. package/dist/plugin/query-tokenizer.js +0 -133
  126. package/dist/plugin/redact.d.ts +0 -2
  127. package/dist/plugin/redact.js +0 -18
  128. package/dist/plugin/replay-types.d.ts +0 -69
  129. package/dist/plugin/replay-types.js +0 -156
  130. package/dist/plugin/replay.d.ts +0 -36
  131. package/dist/plugin/replay.js +0 -202
  132. package/dist/plugin/sqlite-adapter.d.ts +0 -12
  133. package/dist/plugin/sqlite-adapter.js +0 -81
  134. package/dist/plugin/time-ms.d.ts +0 -1
  135. package/dist/plugin/time-ms.js +0 -16
  136. package/dist/plugin/tui-types.d.ts +0 -59
  137. package/dist/plugin/tui-types.js +0 -4
  138. package/dist/plugin/tui.d.ts +0 -18
  139. package/dist/plugin/tui.js +0 -198
  140. package/dist/plugin/uuid.d.ts +0 -1
  141. package/dist/plugin/uuid.js +0 -50
@@ -1,322 +0,0 @@
1
- import { HOOK_NAMES } from "./Migrate.js";
2
- const DEFAULT_THRESHOLD = 3;
3
- /**
4
- * v0.9.0 (K9-010 / plan §5.3, D9-09) — parse the TEXT setting
5
- * `dead_hook_report_threshold` into the [1, 1000] clamp. NaN and empty
6
- * fall back to 3 (never 0: a zero threshold would report every hook dead
7
- * before a single session completes a checkpoint).
8
- */
9
- export function parseThreshold(text) {
10
- if (text === null || text === undefined || text === "")
11
- return DEFAULT_THRESHOLD;
12
- const n = Number.parseInt(text, 10);
13
- // NaN → default; 0 is not a valid threshold (K9-010 AC: 'abc'/''/'0'
14
- // all clamp to the default of three — never zero).
15
- if (Number.isNaN(n) || n === 0)
16
- return DEFAULT_THRESHOLD;
17
- return Math.min(1000, Math.max(1, n));
18
- }
19
- /**
20
- * v0.9.0 (K9-009/K9-010 / plan §5.3) — wraps the plugin's hooks with a
21
- * success-path recorder, dedups per-session checkpoints, and reports each
22
- * hook's liveness state. Persistence is machine-scoped: the hook_liveness
23
- * table carries no project_id or repo_id (D9-08).
24
- */
25
- export class HookLiveness {
26
- store;
27
- options;
28
- // v1.1.0 (K11-015) — debug counter for excess arity; never logged on hot path
29
- excessArityCount = 0;
30
- counters;
31
- seenSessions;
32
- suppressedSessions = new Set();
33
- threshold;
34
- pluginVersion;
35
- constructor(store, options) {
36
- this.store = store;
37
- this.options = options;
38
- this.threshold = parseThreshold(options.thresholdText);
39
- this.pluginVersion = options.pluginVersion;
40
- this.counters = new Map();
41
- this.seenSessions = new Map();
42
- for (const hook of HOOK_NAMES) {
43
- this.counters.set(hook, {
44
- fireCount: 0,
45
- errorCount: 0,
46
- expectedCount: 0,
47
- firstSeenAt: null,
48
- lastSeenAt: null,
49
- deadSince: null,
50
- });
51
- this.seenSessions.set(hook, new Set());
52
- }
53
- this.loadFromDb();
54
- }
55
- /**
56
- * Returns a new object with the same keys; function values are replaced
57
- * by delegating wrappers, non-function values (the tool map) pass by
58
- * reference. When liveness is disabled, returns the argument unchanged —
59
- * the same object, not a copy.
60
- */
61
- wrap(hooks) {
62
- if (!this.options.enabled)
63
- return hooks;
64
- const out = {};
65
- for (const [key, value] of Object.entries(hooks)) {
66
- if (typeof value === "function") {
67
- out[key] = this.makeWrapper(key, value);
68
- }
69
- else {
70
- out[key] = value;
71
- }
72
- }
73
- return out;
74
- }
75
- /**
76
- * v0.9.0 (K9-010 / plan §5.3) — a checkpoint: the session reached a
77
- * model turn (tool.execute.after fired), so the system prompt was
78
- * assembled and `experimental.chat.system.transform` MUST have been
79
- * offered. Deduped per session: 20 tool calls in one session count
80
- * exactly one expectation.
81
- */
82
- expect(hook, sessionID) {
83
- const seen = this.seenSessions.get(hook);
84
- if (!seen || seen.has(sessionID))
85
- return;
86
- seen.add(sessionID);
87
- const counters = this.counters.get(hook);
88
- if (!counters)
89
- return;
90
- counters.expectedCount += 1;
91
- // The dead flag is materialized here (not only in report()) so that
92
- // flush() persists dead_since even when no report() was ever called:
93
- // kevin_doctor's PURE-SQL blocks read dead_since from the table.
94
- if (counters.fireCount === 0 &&
95
- counters.expectedCount >= this.threshold &&
96
- counters.deadSince === null) {
97
- counters.deadSince = counters.lastSeenAt ?? new Date().toISOString();
98
- }
99
- // v0.9.0 (K9-011 / plan §5.3) — when the injection hook is dead, the
100
- // checkpointed session was suppressed: the host stopped offering the
101
- // transform, so no injection could happen. Counted once per session
102
- // (same dedup as expected_count) and persisted by flush(). This is
103
- // the counter that turns "zero injections" from an ambiguous number
104
- // into a diagnosis.
105
- if (hook === "experimental.chat.system.transform" &&
106
- counters.deadSince !== null &&
107
- !this.suppressedSessions.has(sessionID)) {
108
- this.suppressedSessions.add(sessionID);
109
- }
110
- }
111
- /**
112
- * Per-hook liveness verdicts in canonical HOOK_NAMES order.
113
- * A hook that fired once is live forever; dead requires both zero fires
114
- * and `expectedCount >= threshold`; everything else is unknown — and
115
- * unknown is never rounded to healthy (D9-09).
116
- */
117
- report() {
118
- const out = [];
119
- for (const hook of HOOK_NAMES) {
120
- const c = this.counters.get(hook);
121
- if (!c)
122
- continue;
123
- let state;
124
- if (c.fireCount > 0) {
125
- state = "live";
126
- }
127
- else if (c.expectedCount >= this.threshold) {
128
- // dead_since is set ONCE and never cleared: it documents the
129
- // historical death even if the hook later recovers.
130
- if (c.deadSince === null) {
131
- c.deadSince = c.lastSeenAt ?? new Date().toISOString();
132
- }
133
- state = "dead";
134
- }
135
- else {
136
- state = "unknown";
137
- }
138
- out.push({
139
- hook,
140
- experimental: hook.startsWith("experimental."),
141
- state,
142
- firstSeenAt: c.firstSeenAt,
143
- lastSeenAt: c.lastSeenAt,
144
- fireCount: c.fireCount,
145
- expectedCount: c.expectedCount,
146
- deadSince: c.deadSince,
147
- });
148
- }
149
- return out;
150
- }
151
- /** Persists every counter row. Called on the metrics.flush() cadence. */
152
- flush() {
153
- const store = this.store;
154
- store.transaction(() => {
155
- // Created lazily on first flush, mirroring Metrics.flush(): the
156
- // migration guarantees the table in production, but unit tests
157
- // against pre-010 DBs must not explode at dispose.
158
- store.exec(`CREATE TABLE IF NOT EXISTS hook_liveness (
159
- hook TEXT PRIMARY KEY,
160
- experimental INTEGER NOT NULL DEFAULT 0,
161
- fire_count INTEGER NOT NULL DEFAULT 0,
162
- error_count INTEGER NOT NULL DEFAULT 0,
163
- expected_count INTEGER NOT NULL DEFAULT 0,
164
- first_seen_at TEXT,
165
- last_seen_at TEXT,
166
- dead_since TEXT,
167
- plugin_version TEXT
168
- )`);
169
- const upsert = store.prepare(`INSERT INTO hook_liveness (hook, experimental, fire_count, error_count,
170
- expected_count, first_seen_at, last_seen_at, dead_since, plugin_version)
171
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
172
- ON CONFLICT(hook) DO UPDATE SET
173
- experimental = excluded.experimental,
174
- fire_count = excluded.fire_count,
175
- error_count = excluded.error_count,
176
- expected_count = excluded.expected_count,
177
- first_seen_at = excluded.first_seen_at,
178
- last_seen_at = excluded.last_seen_at,
179
- dead_since = excluded.dead_since,
180
- plugin_version = excluded.plugin_version`);
181
- for (const [hook, c] of this.counters) {
182
- upsert.run(hook, hook.startsWith("experimental.") ? 1 : 0, c.fireCount, c.errorCount, c.expectedCount, c.firstSeenAt, c.lastSeenAt, c.deadSince, this.pluginVersion);
183
- }
184
- // v0.9.0 (K9-011 / plan §5.3) — the four v0.9.0 counters are
185
- // re-derived here, on the metrics cadence, exactly like the 009
186
- // post-apply hook re-derives hooks_dead_total: SUM(fire_count),
187
- // SUM(error_count), COUNT(dead_since) and the per-session
188
- // suppression count. No Metrics dependency, no writes in the hot
189
- // path — flush() is the single persistence point.
190
- let fireSum = 0;
191
- let errorSum = 0;
192
- let deadCount = 0;
193
- for (const c of this.counters.values()) {
194
- fireSum += c.fireCount;
195
- errorSum += c.errorCount;
196
- if (c.deadSince !== null)
197
- deadCount += 1;
198
- }
199
- store.exec(`CREATE TABLE IF NOT EXISTS kevin_metrics (
200
- key TEXT PRIMARY KEY,
201
- value INTEGER NOT NULL DEFAULT 0,
202
- updated_at TEXT NOT NULL DEFAULT (datetime('now'))
203
- )`);
204
- const derive = store.prepare(`INSERT INTO kevin_metrics (key, value, updated_at)
205
- VALUES (?, ?, datetime('now'))
206
- ON CONFLICT(key) DO UPDATE SET
207
- value = excluded.value,
208
- updated_at = datetime('now')`);
209
- derive.run("hook_fires_total", fireSum);
210
- derive.run("hook_errors_total", errorSum);
211
- derive.run("hooks_dead_total", deadCount);
212
- derive.run("injections_suppressed_dead_hook", this.suppressedSessions.size);
213
- });
214
- }
215
- makeWrapper(key, delegate) {
216
- const record = () => {
217
- // v1.0.0 (K10-013) — dispose is recorded inside its own delegate
218
- // (via recordDispose()) rather than here: the wrapper's post-return
219
- // record would land after the store is closed and could never be
220
- // persisted — the event being detected is the process ending.
221
- if (key === "dispose")
222
- return;
223
- if (HOOK_NAMES.includes(key)) {
224
- this.recordSuccess(key);
225
- }
226
- };
227
- const recordError = (e) => {
228
- if (HOOK_NAMES.includes(key)) {
229
- this.recordError(key);
230
- }
231
- throw e;
232
- };
233
- // v1.1.0 (K11-015) — arity guard: maximum supported arity is 2 (plan §5.5).
234
- // Excess args are sliced and counted via excessArityCount; never logged.
235
- return async (...args) => {
236
- let callArgs = args;
237
- if (args.length > 2) {
238
- this.excessArityCount++;
239
- callArgs = args.slice(0, 2);
240
- }
241
- try {
242
- const result = await delegate(...callArgs);
243
- record();
244
- return result;
245
- }
246
- catch (e) {
247
- return recordError(e);
248
- }
249
- };
250
- }
251
- /**
252
- * v1.0.0 (K10-013 / plan §5.3) — records the `dispose` fire and
253
- * flushes immediately, from inside the dispose delegate: this is the
254
- * last write of the process, and nothing after it can persist.
255
- */
256
- recordDispose() {
257
- this.recordSuccess("dispose");
258
- this.flush();
259
- }
260
- recordSuccess(hook) {
261
- const c = this.counters.get(hook);
262
- if (!c)
263
- return;
264
- c.fireCount += 1;
265
- const now = new Date().toISOString();
266
- if (c.firstSeenAt === null)
267
- c.firstSeenAt = now;
268
- c.lastSeenAt = now;
269
- }
270
- recordError(hook) {
271
- const c = this.counters.get(hook);
272
- if (!c)
273
- return;
274
- c.errorCount += 1;
275
- }
276
- loadFromDb() {
277
- let rows = [];
278
- try {
279
- rows = this.store
280
- .prepare("SELECT hook, fire_count, error_count, expected_count, first_seen_at, last_seen_at, dead_since FROM hook_liveness")
281
- .all();
282
- }
283
- catch {
284
- // Graceful: pre-010 DBs have no hook_liveness table; the seeded
285
- // zeros remain until the first flush creates rows.
286
- rows = [];
287
- }
288
- for (const row of rows) {
289
- if (!HOOK_NAMES.includes(row.hook))
290
- continue;
291
- const c = this.counters.get(row.hook);
292
- if (!c)
293
- continue;
294
- c.fireCount = row.fire_count;
295
- c.errorCount = row.error_count;
296
- c.expectedCount = row.expected_count;
297
- c.firstSeenAt = row.first_seen_at;
298
- c.lastSeenAt = row.last_seen_at;
299
- c.deadSince = row.dead_since;
300
- }
301
- }
302
- }
303
- export function reduceVerdict(reports) {
304
- if (reports.length === 0) {
305
- return { verdict: "unknown", reason: "no hook reports yet" };
306
- }
307
- const dead = reports.filter((r) => r.state === "dead");
308
- if (dead.length > 0) {
309
- return {
310
- verdict: "degraded",
311
- reason: `${dead.map((r) => r.hook).join(", ")} dead since ${dead[0].deadSince ?? "unknown"}; ${dead.length} affected hook(s)`,
312
- };
313
- }
314
- if (reports.every((r) => r.state === "live")) {
315
- return { verdict: "healthy", reason: "all hooks live" };
316
- }
317
- const pending = reports.filter((r) => r.state === "unknown").length;
318
- return {
319
- verdict: "unknown",
320
- reason: `${pending} hook(s) without checkpoint`,
321
- };
322
- }
@@ -1,98 +0,0 @@
1
- import type { Store } from "./Store.js";
2
- import type { Metrics } from "./metrics.js";
3
- /**
4
- * v0.4.0 InjectionLedger (K4-006/K4-007, plan §5.2, D4-04).
5
- *
6
- * The measurement half of the closed feedback loop: every lesson injected
7
- * into a prompt is recorded in `kevin_injections`, and at `session.idle` the
8
- * ledger settles each unmeasured row — if the same fingerprint failed again
9
- * after the injection, the lesson is `ineffective`; otherwise `effective`.
10
- * `precision_rate = effective / total` is the honest, measured value of the
11
- * injection system (replacing Kevin_Token_Impact-style estimates).
12
- *
13
- * Schema (migration 005_v04_signal.sql):
14
- * kevin_injections(id PK, memory_id, fingerprint, session_id, hook,
15
- * tokens, injected_at, outcome)
16
- *
17
- * BUG-015 — a ledger row is only meaningful when its fingerprint can be
18
- * matched against failing tool_calls (`COALESCE(error_fingerprint,
19
- * fingerprint)`). Memories WITHOUT a fingerprint (agent-saved notes) can
20
- * never match, so they are NOT recorded: settle() would otherwise mark
21
- * them `effective` forever and inflate `precision_rate`. The caller
22
- * (ContextInjector.recordInjections) skips them.
23
- */
24
- export type InjectionHook = "pre_prompt" | "compacting";
25
- export type InjectionOutcome = "unmeasured" | "effective" | "ineffective" | "inconclusive";
26
- export interface InjectionRecordInput {
27
- memoryId: string;
28
- fingerprint: string;
29
- sessionId: string;
30
- hook: InjectionHook;
31
- tokens: number;
32
- /**
33
- * v0.8.0 (K8-024 / plan §5.7) — the memory's layer, passed by the
34
- * caller (the injector already knows it — no lookup on the hot path).
35
- * Drives the `injections_from_shared` counter.
36
- */
37
- layer?: string | null;
38
- }
39
- interface InjectionRow {
40
- id: string;
41
- memory_id: string;
42
- fingerprint: string;
43
- session_id: string;
44
- hook: InjectionHook;
45
- tokens: number;
46
- injected_at: string;
47
- outcome: InjectionOutcome;
48
- }
49
- export declare class InjectionLedger {
50
- private readonly store;
51
- private readonly metrics;
52
- constructor(store: Store, metrics?: Metrics | null);
53
- /**
54
- * Records one injected memory. Idempotent at the row level (UUID PK);
55
- * duplicates are expected only via the caller's per-session seen-set.
56
- */
57
- record(input: InjectionRecordInput): void;
58
- /**
59
- * Settles every unmeasured injection of the session: a fingerprint that
60
- * failed again (as a failing tool_call) after the injection is
61
- * `ineffective`, otherwise `effective`. Idempotent — only
62
- * `outcome = 'unmeasured'` rows are flipped, and the recurrence charge
63
- * is `MAX(recurrence_count, n)` where n = all failing calls of the
64
- * fingerprint after `injected_at` (a later idle re-computes n and
65
- * catches up — plan §5.1 rule 4: 3 recurrences → stale).
66
- *
67
- * An ineffective injection also bumps the target memory's
68
- * `recurrence_count` (negative evidence, plan §5.3) and stamps
69
- * `last_injected_at` (monotonically — an older row can never
70
- * regress a newer injection's timestamp; the column means "most
71
- * recent injection").
72
- */
73
- settle(sessionId: string): void;
74
- /**
75
- * Per-fingerprint failing tool-call counts for the session. Feeds
76
- * QualityGate.canInject and the HITL suggestion block.
77
- */
78
- recurrencesFor(sessionId: string): Map<string, number>;
79
- /**
80
- * v0.4.0 (K4-017) — recurrence counts for the QualityGate at
81
- * injection time: only failing calls that happened AFTER the
82
- * fingerprint was already injected this session count. The failure
83
- * that *created* a lesson is not a recurrence — it precedes any
84
- * injection (plan §5.1 rule 4, same `ts >= injected_at` semantics
85
- * `settle` uses).
86
- */
87
- postInjectionRecurrencesFor(sessionId: string): Map<string, number>;
88
- /** Number of rows for the session not yet settled (drives tests and settle). */
89
- unsettledForSession(sessionId: string): number;
90
- /** Latest ledger rows for a session, newest first (used by tests/tools). */
91
- rowsForSession(sessionId: string): InjectionRow[];
92
- /**
93
- * v0.5.0 (K5-005 / plan §8.4) — one grouped rollup over the whole
94
- * ledger, zero-filled for every outcome. Consumed by `kevin_audit`.
95
- */
96
- outcomeCounts(): Record<InjectionOutcome, number>;
97
- }
98
- export {};