nlm-memory 0.9.2 → 0.10.1
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/README.md +5 -3
- package/dist/cli/nlm.js +67 -1
- package/dist/cli/nlm.js.map +1 -1
- package/dist/core/dataset/build-dataset.d.ts +13 -0
- package/dist/core/dataset/build-dataset.js +31 -2
- package/dist/core/dataset/build-dataset.js.map +1 -1
- package/dist/core/integrity/check-invariants.d.ts +41 -0
- package/dist/core/integrity/check-invariants.js +349 -0
- package/dist/core/integrity/check-invariants.js.map +1 -0
- package/dist/core/scheduler/scan-once.d.ts +4 -1
- package/dist/core/scheduler/scan-once.js +53 -14
- package/dist/core/scheduler/scan-once.js.map +1 -1
- package/dist/core/scheduler/scheduler.js +64 -11
- package/dist/core/scheduler/scheduler.js.map +1 -1
- package/dist/core/storage/live-status.d.ts +5 -3
- package/dist/core/storage/live-status.js +6 -2
- package/dist/core/storage/live-status.js.map +1 -1
- package/dist/core/storage/migrate.d.ts +5 -0
- package/dist/core/storage/migrate.js +24 -8
- package/dist/core/storage/migrate.js.map +1 -1
- package/dist/core/storage/pg-session-store.d.ts +2 -2
- package/dist/core/storage/pg-session-store.js +31 -6
- package/dist/core/storage/pg-session-store.js.map +1 -1
- package/dist/core/storage/sqlite-fact-store.js +7 -15
- package/dist/core/storage/sqlite-fact-store.js.map +1 -1
- package/dist/core/storage/sqlite-session-store.d.ts +14 -2
- package/dist/core/storage/sqlite-session-store.js +61 -24
- package/dist/core/storage/sqlite-session-store.js.map +1 -1
- package/dist/http/app.js +8 -2
- package/dist/http/app.js.map +1 -1
- package/dist/shared/types.d.ts +24 -5
- package/dist/ui/assets/index-CJgVgxlM.js +11 -0
- package/dist/ui/assets/index-D5lKaksH.css +1 -0
- package/dist/ui/index.html +2 -2
- package/migrations/000_initial_schema.sql +174 -0
- package/migrations/001_entity_type_rename.sql +17 -0
- package/migrations/002_adapter_state_extend.sql +12 -0
- package/migrations/003_session_embeddings.sql +11 -0
- package/migrations/004_facts.sql +46 -0
- package/migrations/005_sources.sql +31 -0
- package/migrations/006_providers.sql +33 -0
- package/migrations/007_source_tokens.sql +17 -0
- package/migrations/008_fts_rebuild.sql +9 -0
- package/migrations/009_session_embedding_chunks.sql +46 -0
- package/migrations/010_sources_opencode.sql +30 -0
- package/migrations/011_sources_hermes_agent.sql +30 -0
- package/migrations/012_sources_aider.sql +30 -0
- package/migrations/013_adapter_state_failure_count.sql +12 -0
- package/migrations/014_sources_cursor.sql +30 -0
- package/migrations/015_sources_windsurf.sql +30 -0
- package/migrations/016_sources_codex.sql +30 -0
- package/migrations/017_signals.sql +31 -0
- package/migrations/018_repair_self_supersede.sql +21 -0
- package/migrations/019_split_replaces.sql +117 -0
- package/migrations/020_collapse_duplicate_active_facts.sql +45 -0
- package/migrations/pg/001_initial.sql +214 -0
- package/migrations/pg/018_repair_self_supersede.sql +16 -0
- package/migrations/pg/019_split_replaces.sql +32 -0
- package/migrations/pg/020_collapse_duplicate_active_facts.sql +46 -0
- package/package.json +2 -1
- package/dist/core/recall/useful-scan.d.ts +0 -52
- package/dist/core/recall/useful-scan.js +0 -300
- package/dist/core/recall/useful-scan.js.map +0 -1
- package/dist/hook/pre-compact-hook.d.ts +0 -26
- package/dist/hook/pre-compact-hook.js +0 -94
- package/dist/hook/pre-compact-hook.js.map +0 -1
- package/dist/hook/subagent-start-hook.d.ts +0 -30
- package/dist/hook/subagent-start-hook.js +0 -108
- package/dist/hook/subagent-start-hook.js.map +0 -1
- package/dist/ui/assets/index-BTj60bAH.js +0 -11
- package/dist/ui/assets/index-Baw2qIKc.css +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-invariants — pure integrity check definitions.
|
|
3
|
+
*
|
|
4
|
+
* Each check returns a typed violation describing the problem. A clean
|
|
5
|
+
* database returns an empty violations array. The SQL strings are backend-
|
|
6
|
+
* agnostic where possible; per-backend runners at the bottom execute them.
|
|
7
|
+
*
|
|
8
|
+
* Checks:
|
|
9
|
+
* I1 no self-loop edges in session_edges for any 'kind'
|
|
10
|
+
* I2 status matches incoming edge kind: status='superseded' has an incoming
|
|
11
|
+
* 'supersedes' edge; status='replaced' has an incoming 'replaces' edge
|
|
12
|
+
* I3 supersedence graph is acyclic over the union of 'supersedes' and
|
|
13
|
+
* 'replaces' edges (BFS, depth-capped at 100)
|
|
14
|
+
* I4 every session_edges endpoint exists in sessions
|
|
15
|
+
* I5 at most one active fact per (subject, predicate); every superseded_by
|
|
16
|
+
* references an existing facts.id
|
|
17
|
+
* I6 every non-null adapter_state.session_id references a sessions.id
|
|
18
|
+
*/
|
|
19
|
+
import type Database from "better-sqlite3";
|
|
20
|
+
import type { Pool } from "pg";
|
|
21
|
+
export interface Violation {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
readonly description: string;
|
|
24
|
+
readonly count: number;
|
|
25
|
+
readonly sampleIds: ReadonlyArray<string>;
|
|
26
|
+
}
|
|
27
|
+
export type EdgeLoader = () => ReadonlyArray<{
|
|
28
|
+
from_session: string;
|
|
29
|
+
to_session: string;
|
|
30
|
+
}>;
|
|
31
|
+
export declare function detectCycles(loadEdges: EdgeLoader): Violation | null;
|
|
32
|
+
export declare function runChecksOnSqlite(db: Database.Database): ReadonlyArray<Violation>;
|
|
33
|
+
export declare function runChecksOnPg(pool: Pool): Promise<ReadonlyArray<Violation>>;
|
|
34
|
+
export declare function runCheapChecksOnSqlite(db: Database.Database): ReadonlyArray<Violation>;
|
|
35
|
+
export declare function runCheapChecksOnPg(pool: Pool): Promise<ReadonlyArray<Violation>>;
|
|
36
|
+
export interface FixReport {
|
|
37
|
+
readonly deletedSelfLoops: number;
|
|
38
|
+
readonly restoredToClosed: number;
|
|
39
|
+
}
|
|
40
|
+
export declare function applyFixOnSqlite(db: Database.Database): FixReport;
|
|
41
|
+
export declare function applyFixOnPg(pool: Pool): Promise<FixReport>;
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-invariants — pure integrity check definitions.
|
|
3
|
+
*
|
|
4
|
+
* Each check returns a typed violation describing the problem. A clean
|
|
5
|
+
* database returns an empty violations array. The SQL strings are backend-
|
|
6
|
+
* agnostic where possible; per-backend runners at the bottom execute them.
|
|
7
|
+
*
|
|
8
|
+
* Checks:
|
|
9
|
+
* I1 no self-loop edges in session_edges for any 'kind'
|
|
10
|
+
* I2 status matches incoming edge kind: status='superseded' has an incoming
|
|
11
|
+
* 'supersedes' edge; status='replaced' has an incoming 'replaces' edge
|
|
12
|
+
* I3 supersedence graph is acyclic over the union of 'supersedes' and
|
|
13
|
+
* 'replaces' edges (BFS, depth-capped at 100)
|
|
14
|
+
* I4 every session_edges endpoint exists in sessions
|
|
15
|
+
* I5 at most one active fact per (subject, predicate); every superseded_by
|
|
16
|
+
* references an existing facts.id
|
|
17
|
+
* I6 every non-null adapter_state.session_id references a sessions.id
|
|
18
|
+
*/
|
|
19
|
+
// ─── SQL strings (portable) ──────────────────────────────────────────────────
|
|
20
|
+
const SQL_I1 = `
|
|
21
|
+
SELECT from_session AS bad_id
|
|
22
|
+
FROM session_edges
|
|
23
|
+
WHERE from_session = to_session
|
|
24
|
+
LIMIT 6
|
|
25
|
+
`;
|
|
26
|
+
const SQL_I2_ORPHANED = `
|
|
27
|
+
SELECT s.id AS bad_id
|
|
28
|
+
FROM sessions s
|
|
29
|
+
WHERE s.status = 'superseded'
|
|
30
|
+
AND NOT EXISTS (
|
|
31
|
+
SELECT 1 FROM session_edges e
|
|
32
|
+
WHERE e.to_session = s.id AND e.kind = 'supersedes'
|
|
33
|
+
)
|
|
34
|
+
LIMIT 6
|
|
35
|
+
`;
|
|
36
|
+
const SQL_I2_ORPHANED_REPLACED = `
|
|
37
|
+
SELECT s.id AS bad_id
|
|
38
|
+
FROM sessions s
|
|
39
|
+
WHERE s.status = 'replaced'
|
|
40
|
+
AND NOT EXISTS (
|
|
41
|
+
SELECT 1 FROM session_edges e
|
|
42
|
+
WHERE e.to_session = s.id AND e.kind = 'replaces'
|
|
43
|
+
)
|
|
44
|
+
LIMIT 6
|
|
45
|
+
`;
|
|
46
|
+
const SQL_I4_MISSING_FROM = `
|
|
47
|
+
SELECT e.from_session AS bad_id
|
|
48
|
+
FROM session_edges e
|
|
49
|
+
WHERE NOT EXISTS (SELECT 1 FROM sessions s WHERE s.id = e.from_session)
|
|
50
|
+
LIMIT 6
|
|
51
|
+
`;
|
|
52
|
+
const SQL_I4_MISSING_TO = `
|
|
53
|
+
SELECT e.to_session AS bad_id
|
|
54
|
+
FROM session_edges e
|
|
55
|
+
WHERE NOT EXISTS (SELECT 1 FROM sessions s WHERE s.id = e.to_session)
|
|
56
|
+
LIMIT 6
|
|
57
|
+
`;
|
|
58
|
+
// One row per conflicting (subject, predicate) group — the count is the number
|
|
59
|
+
// of conflicts to resolve, not the number of facts involved. MIN(id) keeps the
|
|
60
|
+
// projection aggregate-only so PostgreSQL's GROUP BY strictness accepts it.
|
|
61
|
+
const SQL_I5_DUPLICATE_FACTS = `
|
|
62
|
+
SELECT MIN(id) AS bad_id
|
|
63
|
+
FROM facts
|
|
64
|
+
WHERE superseded_by IS NULL
|
|
65
|
+
GROUP BY subject, predicate
|
|
66
|
+
HAVING COUNT(*) > 1
|
|
67
|
+
LIMIT 6
|
|
68
|
+
`;
|
|
69
|
+
const SQL_I5_DANGLING_SUPERSEDED_BY = `
|
|
70
|
+
SELECT f.id AS bad_id
|
|
71
|
+
FROM facts f
|
|
72
|
+
WHERE f.superseded_by IS NOT NULL
|
|
73
|
+
AND NOT EXISTS (SELECT 1 FROM facts f2 WHERE f2.id = f.superseded_by)
|
|
74
|
+
LIMIT 6
|
|
75
|
+
`;
|
|
76
|
+
const SQL_I6 = `
|
|
77
|
+
SELECT a.session_id AS bad_id
|
|
78
|
+
FROM adapter_state a
|
|
79
|
+
WHERE a.session_id IS NOT NULL
|
|
80
|
+
AND NOT EXISTS (SELECT 1 FROM sessions s WHERE s.id = a.session_id)
|
|
81
|
+
LIMIT 6
|
|
82
|
+
`;
|
|
83
|
+
const MAX_CYCLE_DEPTH = 100;
|
|
84
|
+
export function detectCycles(loadEdges) {
|
|
85
|
+
const edges = loadEdges();
|
|
86
|
+
const children = new Map();
|
|
87
|
+
for (const { from_session, to_session } of edges) {
|
|
88
|
+
const list = children.get(from_session);
|
|
89
|
+
if (list)
|
|
90
|
+
list.push(to_session);
|
|
91
|
+
else
|
|
92
|
+
children.set(from_session, [to_session]);
|
|
93
|
+
}
|
|
94
|
+
const cycleNodes = [];
|
|
95
|
+
const visited = new Set();
|
|
96
|
+
for (const start of children.keys()) {
|
|
97
|
+
if (visited.has(start))
|
|
98
|
+
continue;
|
|
99
|
+
const queue = [{ node: start, depth: 0 }];
|
|
100
|
+
const inPath = new Set();
|
|
101
|
+
while (queue.length > 0) {
|
|
102
|
+
const item = queue.shift();
|
|
103
|
+
if (item.depth > MAX_CYCLE_DEPTH)
|
|
104
|
+
break;
|
|
105
|
+
if (inPath.has(item.node)) {
|
|
106
|
+
if (cycleNodes.length < 5)
|
|
107
|
+
cycleNodes.push(item.node);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
inPath.add(item.node);
|
|
111
|
+
visited.add(item.node);
|
|
112
|
+
for (const child of children.get(item.node) ?? []) {
|
|
113
|
+
queue.push({ node: child, depth: item.depth + 1 });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (cycleNodes.length === 0)
|
|
118
|
+
return null;
|
|
119
|
+
return {
|
|
120
|
+
id: "I3",
|
|
121
|
+
description: "supersedence graph contains cycles",
|
|
122
|
+
count: cycleNodes.length,
|
|
123
|
+
sampleIds: cycleNodes.slice(0, 5),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
// ─── SQLite runner ────────────────────────────────────────────────────────────
|
|
127
|
+
function sqliteRows(db, sql) {
|
|
128
|
+
return db
|
|
129
|
+
.prepare(sql)
|
|
130
|
+
.all()
|
|
131
|
+
.map((r) => r.bad_id);
|
|
132
|
+
}
|
|
133
|
+
function sqliteCount(db, sql) {
|
|
134
|
+
const countSql = `SELECT count(*) AS n FROM (${sql.replace(/LIMIT \d+/, "")})`;
|
|
135
|
+
return (db.prepare(countSql).get()?.n) ?? 0;
|
|
136
|
+
}
|
|
137
|
+
function buildViolation(id, description, samples, count) {
|
|
138
|
+
return { id, description, count, sampleIds: samples.slice(0, 5) };
|
|
139
|
+
}
|
|
140
|
+
export function runChecksOnSqlite(db) {
|
|
141
|
+
const violations = [];
|
|
142
|
+
// I1
|
|
143
|
+
const i1Samples = sqliteRows(db, SQL_I1);
|
|
144
|
+
if (i1Samples.length > 0) {
|
|
145
|
+
const count = sqliteCount(db, SQL_I1);
|
|
146
|
+
violations.push(buildViolation("I1", "self-loop edges in session_edges", i1Samples, count));
|
|
147
|
+
}
|
|
148
|
+
// I2
|
|
149
|
+
const i2Samples = sqliteRows(db, SQL_I2_ORPHANED);
|
|
150
|
+
if (i2Samples.length > 0) {
|
|
151
|
+
const count = sqliteCount(db, SQL_I2_ORPHANED);
|
|
152
|
+
violations.push(buildViolation("I2", "sessions marked superseded with no incoming supersedes edge", i2Samples, count));
|
|
153
|
+
}
|
|
154
|
+
const i2ReplacedSamples = sqliteRows(db, SQL_I2_ORPHANED_REPLACED);
|
|
155
|
+
if (i2ReplacedSamples.length > 0) {
|
|
156
|
+
const count = sqliteCount(db, SQL_I2_ORPHANED_REPLACED);
|
|
157
|
+
violations.push(buildViolation("I2r", "sessions marked replaced with no incoming replaces edge", i2ReplacedSamples, count));
|
|
158
|
+
}
|
|
159
|
+
// I3
|
|
160
|
+
const i3 = detectCycles(() => db
|
|
161
|
+
.prepare("SELECT from_session, to_session FROM session_edges WHERE kind IN ('supersedes', 'replaces')")
|
|
162
|
+
.all());
|
|
163
|
+
if (i3)
|
|
164
|
+
violations.push(i3);
|
|
165
|
+
// I4
|
|
166
|
+
const i4FromSamples = sqliteRows(db, SQL_I4_MISSING_FROM);
|
|
167
|
+
const i4ToSamples = sqliteRows(db, SQL_I4_MISSING_TO);
|
|
168
|
+
const i4All = [...new Set([...i4FromSamples, ...i4ToSamples])];
|
|
169
|
+
if (i4All.length > 0) {
|
|
170
|
+
const countFrom = sqliteCount(db, SQL_I4_MISSING_FROM);
|
|
171
|
+
const countTo = sqliteCount(db, SQL_I4_MISSING_TO);
|
|
172
|
+
violations.push(buildViolation("I4", "session_edges reference session ids not in sessions table", i4All, countFrom + countTo));
|
|
173
|
+
}
|
|
174
|
+
// I5
|
|
175
|
+
const i5DupSamples = sqliteRows(db, SQL_I5_DUPLICATE_FACTS);
|
|
176
|
+
if (i5DupSamples.length > 0) {
|
|
177
|
+
const count = sqliteCount(db, SQL_I5_DUPLICATE_FACTS);
|
|
178
|
+
violations.push(buildViolation("I5a", "multiple active facts for same (subject, predicate)", i5DupSamples, count));
|
|
179
|
+
}
|
|
180
|
+
const i5DangleSamples = sqliteRows(db, SQL_I5_DANGLING_SUPERSEDED_BY);
|
|
181
|
+
if (i5DangleSamples.length > 0) {
|
|
182
|
+
const count = sqliteCount(db, SQL_I5_DANGLING_SUPERSEDED_BY);
|
|
183
|
+
violations.push(buildViolation("I5b", "facts.superseded_by references non-existent facts.id", i5DangleSamples, count));
|
|
184
|
+
}
|
|
185
|
+
// I6
|
|
186
|
+
const i6Samples = sqliteRows(db, SQL_I6);
|
|
187
|
+
if (i6Samples.length > 0) {
|
|
188
|
+
const count = sqliteCount(db, SQL_I6);
|
|
189
|
+
violations.push(buildViolation("I6", "adapter_state.session_id references non-existent sessions.id", i6Samples, count));
|
|
190
|
+
}
|
|
191
|
+
return violations;
|
|
192
|
+
}
|
|
193
|
+
// ─── PostgreSQL runner ────────────────────────────────────────────────────────
|
|
194
|
+
async function pgRows(pool, sql) {
|
|
195
|
+
const stripped = sql.replace(/LIMIT \d+/, "LIMIT 6");
|
|
196
|
+
const result = await pool.query(stripped);
|
|
197
|
+
return result.rows.map((r) => r.bad_id);
|
|
198
|
+
}
|
|
199
|
+
async function pgCount(pool, sql) {
|
|
200
|
+
const countSql = `SELECT count(*) AS n FROM (${sql.replace(/LIMIT \d+/, "")}) AS sub`;
|
|
201
|
+
const result = await pool.query(countSql);
|
|
202
|
+
return Number.parseInt(result.rows[0]?.n ?? "0", 10);
|
|
203
|
+
}
|
|
204
|
+
export async function runChecksOnPg(pool) {
|
|
205
|
+
const violations = [];
|
|
206
|
+
// I1
|
|
207
|
+
const i1Samples = await pgRows(pool, SQL_I1);
|
|
208
|
+
if (i1Samples.length > 0) {
|
|
209
|
+
const count = await pgCount(pool, SQL_I1);
|
|
210
|
+
violations.push(buildViolation("I1", "self-loop edges in session_edges", i1Samples, count));
|
|
211
|
+
}
|
|
212
|
+
// I2
|
|
213
|
+
const i2Samples = await pgRows(pool, SQL_I2_ORPHANED);
|
|
214
|
+
if (i2Samples.length > 0) {
|
|
215
|
+
const count = await pgCount(pool, SQL_I2_ORPHANED);
|
|
216
|
+
violations.push(buildViolation("I2", "sessions marked superseded with no incoming supersedes edge", i2Samples, count));
|
|
217
|
+
}
|
|
218
|
+
const i2ReplacedSamples = await pgRows(pool, SQL_I2_ORPHANED_REPLACED);
|
|
219
|
+
if (i2ReplacedSamples.length > 0) {
|
|
220
|
+
const count = await pgCount(pool, SQL_I2_ORPHANED_REPLACED);
|
|
221
|
+
violations.push(buildViolation("I2r", "sessions marked replaced with no incoming replaces edge", i2ReplacedSamples, count));
|
|
222
|
+
}
|
|
223
|
+
// I3
|
|
224
|
+
const edgeResult = await pool.query("SELECT from_session, to_session FROM session_edges WHERE kind IN ('supersedes', 'replaces')");
|
|
225
|
+
const i3 = detectCycles(() => edgeResult.rows);
|
|
226
|
+
if (i3)
|
|
227
|
+
violations.push(i3);
|
|
228
|
+
// I4
|
|
229
|
+
const [i4FromSamples, i4ToSamples] = await Promise.all([
|
|
230
|
+
pgRows(pool, SQL_I4_MISSING_FROM),
|
|
231
|
+
pgRows(pool, SQL_I4_MISSING_TO),
|
|
232
|
+
]);
|
|
233
|
+
const i4All = [...new Set([...i4FromSamples, ...i4ToSamples])];
|
|
234
|
+
if (i4All.length > 0) {
|
|
235
|
+
const [countFrom, countTo] = await Promise.all([
|
|
236
|
+
pgCount(pool, SQL_I4_MISSING_FROM),
|
|
237
|
+
pgCount(pool, SQL_I4_MISSING_TO),
|
|
238
|
+
]);
|
|
239
|
+
violations.push(buildViolation("I4", "session_edges reference session ids not in sessions table", i4All, countFrom + countTo));
|
|
240
|
+
}
|
|
241
|
+
// I5
|
|
242
|
+
const [i5DupSamples, i5DangleSamples] = await Promise.all([
|
|
243
|
+
pgRows(pool, SQL_I5_DUPLICATE_FACTS),
|
|
244
|
+
pgRows(pool, SQL_I5_DANGLING_SUPERSEDED_BY),
|
|
245
|
+
]);
|
|
246
|
+
if (i5DupSamples.length > 0) {
|
|
247
|
+
const count = await pgCount(pool, SQL_I5_DUPLICATE_FACTS);
|
|
248
|
+
violations.push(buildViolation("I5a", "multiple active facts for same (subject, predicate)", i5DupSamples, count));
|
|
249
|
+
}
|
|
250
|
+
if (i5DangleSamples.length > 0) {
|
|
251
|
+
const count = await pgCount(pool, SQL_I5_DANGLING_SUPERSEDED_BY);
|
|
252
|
+
violations.push(buildViolation("I5b", "facts.superseded_by references non-existent facts.id", i5DangleSamples, count));
|
|
253
|
+
}
|
|
254
|
+
// I6
|
|
255
|
+
const i6Samples = await pgRows(pool, SQL_I6);
|
|
256
|
+
if (i6Samples.length > 0) {
|
|
257
|
+
const count = await pgCount(pool, SQL_I6);
|
|
258
|
+
violations.push(buildViolation("I6", "adapter_state.session_id references non-existent sessions.id", i6Samples, count));
|
|
259
|
+
}
|
|
260
|
+
return violations;
|
|
261
|
+
}
|
|
262
|
+
// ─── Cheap subset (I1 + I2 + I6) for scheduled watchdog ─────────────────────
|
|
263
|
+
export function runCheapChecksOnSqlite(db) {
|
|
264
|
+
const violations = [];
|
|
265
|
+
const i1Samples = sqliteRows(db, SQL_I1);
|
|
266
|
+
if (i1Samples.length > 0) {
|
|
267
|
+
violations.push(buildViolation("I1", "self-loop edges in session_edges", i1Samples, sqliteCount(db, SQL_I1)));
|
|
268
|
+
}
|
|
269
|
+
const i2Samples = sqliteRows(db, SQL_I2_ORPHANED);
|
|
270
|
+
if (i2Samples.length > 0) {
|
|
271
|
+
violations.push(buildViolation("I2", "sessions marked superseded with no incoming supersedes edge", i2Samples, sqliteCount(db, SQL_I2_ORPHANED)));
|
|
272
|
+
}
|
|
273
|
+
const i2ReplacedSamples = sqliteRows(db, SQL_I2_ORPHANED_REPLACED);
|
|
274
|
+
if (i2ReplacedSamples.length > 0) {
|
|
275
|
+
violations.push(buildViolation("I2r", "sessions marked replaced with no incoming replaces edge", i2ReplacedSamples, sqliteCount(db, SQL_I2_ORPHANED_REPLACED)));
|
|
276
|
+
}
|
|
277
|
+
const i6Samples = sqliteRows(db, SQL_I6);
|
|
278
|
+
if (i6Samples.length > 0) {
|
|
279
|
+
violations.push(buildViolation("I6", "adapter_state.session_id references non-existent sessions.id", i6Samples, sqliteCount(db, SQL_I6)));
|
|
280
|
+
}
|
|
281
|
+
return violations;
|
|
282
|
+
}
|
|
283
|
+
export async function runCheapChecksOnPg(pool) {
|
|
284
|
+
const violations = [];
|
|
285
|
+
const [i1, i2, i2r, i6] = await Promise.all([
|
|
286
|
+
pgRows(pool, SQL_I1),
|
|
287
|
+
pgRows(pool, SQL_I2_ORPHANED),
|
|
288
|
+
pgRows(pool, SQL_I2_ORPHANED_REPLACED),
|
|
289
|
+
pgRows(pool, SQL_I6),
|
|
290
|
+
]);
|
|
291
|
+
if (i1.length > 0) {
|
|
292
|
+
violations.push(buildViolation("I1", "self-loop edges in session_edges", i1, await pgCount(pool, SQL_I1)));
|
|
293
|
+
}
|
|
294
|
+
if (i2.length > 0) {
|
|
295
|
+
violations.push(buildViolation("I2", "sessions marked superseded with no incoming supersedes edge", i2, await pgCount(pool, SQL_I2_ORPHANED)));
|
|
296
|
+
}
|
|
297
|
+
if (i2r.length > 0) {
|
|
298
|
+
violations.push(buildViolation("I2r", "sessions marked replaced with no incoming replaces edge", i2r, await pgCount(pool, SQL_I2_ORPHANED_REPLACED)));
|
|
299
|
+
}
|
|
300
|
+
if (i6.length > 0) {
|
|
301
|
+
violations.push(buildViolation("I6", "adapter_state.session_id references non-existent sessions.id", i6, await pgCount(pool, SQL_I6)));
|
|
302
|
+
}
|
|
303
|
+
return violations;
|
|
304
|
+
}
|
|
305
|
+
export function applyFixOnSqlite(db) {
|
|
306
|
+
const deleteResult = db
|
|
307
|
+
.prepare("DELETE FROM session_edges WHERE from_session = to_session")
|
|
308
|
+
.run();
|
|
309
|
+
const updateSuperseded = db
|
|
310
|
+
.prepare(`
|
|
311
|
+
UPDATE sessions
|
|
312
|
+
SET status = 'closed', updated_at = datetime('now')
|
|
313
|
+
WHERE status = 'superseded'
|
|
314
|
+
AND id NOT IN (SELECT to_session FROM session_edges WHERE kind = 'supersedes')
|
|
315
|
+
`)
|
|
316
|
+
.run();
|
|
317
|
+
const updateReplaced = db
|
|
318
|
+
.prepare(`
|
|
319
|
+
UPDATE sessions
|
|
320
|
+
SET status = 'closed', updated_at = datetime('now')
|
|
321
|
+
WHERE status = 'replaced'
|
|
322
|
+
AND id NOT IN (SELECT to_session FROM session_edges WHERE kind = 'replaces')
|
|
323
|
+
`)
|
|
324
|
+
.run();
|
|
325
|
+
return {
|
|
326
|
+
deletedSelfLoops: deleteResult.changes,
|
|
327
|
+
restoredToClosed: updateSuperseded.changes + updateReplaced.changes,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
export async function applyFixOnPg(pool) {
|
|
331
|
+
const deleteResult = await pool.query("DELETE FROM session_edges WHERE from_session = to_session");
|
|
332
|
+
const updateSuperseded = await pool.query(`
|
|
333
|
+
UPDATE sessions
|
|
334
|
+
SET status = 'closed', updated_at = NOW()
|
|
335
|
+
WHERE status = 'superseded'
|
|
336
|
+
AND id NOT IN (SELECT to_session FROM session_edges WHERE kind = 'supersedes')
|
|
337
|
+
`);
|
|
338
|
+
const updateReplaced = await pool.query(`
|
|
339
|
+
UPDATE sessions
|
|
340
|
+
SET status = 'closed', updated_at = NOW()
|
|
341
|
+
WHERE status = 'replaced'
|
|
342
|
+
AND id NOT IN (SELECT to_session FROM session_edges WHERE kind = 'replaces')
|
|
343
|
+
`);
|
|
344
|
+
return {
|
|
345
|
+
deletedSelfLoops: deleteResult.rowCount ?? 0,
|
|
346
|
+
restoredToClosed: (updateSuperseded.rowCount ?? 0) + (updateReplaced.rowCount ?? 0),
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
//# sourceMappingURL=check-invariants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-invariants.js","sourceRoot":"","sources":["../../../src/core/integrity/check-invariants.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,4 +33,7 @@ export declare function recordClassified(db: Database.Database, adapterName: str
|
|
|
33
33
|
export declare function recordFailed(db: Database.Database, adapterName: string, sourcePath: string): void;
|
|
34
34
|
export declare function getFileSize(sourcePath: string): number | null;
|
|
35
35
|
export declare function scanOncePg(adapter: TranscriptAdapter, idleMinutes: number, pool: Pool, now?: number): Promise<ScanResult[]>;
|
|
36
|
-
export declare function
|
|
36
|
+
export declare function recordClassifiedPg(pool: Pool, adapterName: string, sourcePath: string, sessionId: string): Promise<void>;
|
|
37
|
+
export declare function recordSkippedLowConfidence(db: Database.Database, adapterName: string, sourcePath: string): void;
|
|
38
|
+
export declare function recordSkippedLowConfidencePg(pool: Pool, adapterName: string, sourcePath: string): Promise<void>;
|
|
39
|
+
export declare function recordFailedPg(pool: Pool, adapterName: string, sourcePath: string, fileSize: number | null): Promise<number>;
|
|
@@ -42,7 +42,6 @@ export async function scanOnce(adapter, idleMinutes, db, now = Date.now()) {
|
|
|
42
42
|
if (age < idleMs)
|
|
43
43
|
continue;
|
|
44
44
|
const prior = byPath.get(path);
|
|
45
|
-
let supersedes = null;
|
|
46
45
|
if (prior) {
|
|
47
46
|
const sizeUnchanged = (prior.file_size ?? 0) === st.size;
|
|
48
47
|
if (sizeUnchanged) {
|
|
@@ -54,11 +53,11 @@ export async function scanOnce(adapter, idleMinutes, db, now = Date.now()) {
|
|
|
54
53
|
if (prior.failure_count >= MAX_CLASSIFY_FAILURES) {
|
|
55
54
|
db.prepare("UPDATE adapter_state SET failure_count = 0 WHERE adapter_name = ? AND source_path = ?").run(adapter.name, path);
|
|
56
55
|
}
|
|
57
|
-
supersedes = prior.session_id;
|
|
58
56
|
}
|
|
59
57
|
const chunk = await adapter.parseSession(path);
|
|
60
58
|
if (!chunk)
|
|
61
59
|
continue;
|
|
60
|
+
const supersedes = prior?.session_id && prior.session_id !== chunk.id ? prior.session_id : null;
|
|
62
61
|
out.push({ chunk, supersedes });
|
|
63
62
|
}
|
|
64
63
|
return out;
|
|
@@ -109,9 +108,15 @@ export async function scanOncePg(adapter, idleMinutes, pool, now = Date.now()) {
|
|
|
109
108
|
const idleMs = idleMinutes * 60 * 1000;
|
|
110
109
|
const stateRows = await pool.query(`SELECT source_path, file_size, session_id, COALESCE(failure_count, 0) AS failure_count
|
|
111
110
|
FROM adapter_state WHERE adapter_name = $1`, [adapter.name]);
|
|
111
|
+
// pg returns BIGINT (file_size) as a string; coerce to number so the
|
|
112
|
+
// unchanged-size check compares against statSync's numeric size.
|
|
112
113
|
const stateMap = new Map(stateRows.rows.map((r) => [
|
|
113
114
|
r.source_path,
|
|
114
|
-
{
|
|
115
|
+
{
|
|
116
|
+
fileSize: r.file_size === null ? null : Number(r.file_size),
|
|
117
|
+
sessionId: r.session_id,
|
|
118
|
+
failureCount: r.failure_count,
|
|
119
|
+
},
|
|
115
120
|
]));
|
|
116
121
|
const paths = await adapter.discover();
|
|
117
122
|
const results = [];
|
|
@@ -140,25 +145,59 @@ export async function scanOncePg(adapter, idleMinutes, pool, now = Date.now()) {
|
|
|
140
145
|
const chunk = await adapter.parseSession(sourcePath);
|
|
141
146
|
if (!chunk)
|
|
142
147
|
continue;
|
|
143
|
-
const
|
|
144
|
-
const supersedes = prior?.sessionId !== chunk.id ? (prior?.sessionId ?? null) : null;
|
|
148
|
+
const supersedes = state?.sessionId && state.sessionId !== chunk.id ? state.sessionId : null;
|
|
145
149
|
results.push({ chunk, supersedes });
|
|
146
|
-
await pool.query(`INSERT INTO adapter_state (adapter_name, source_path, last_offset, file_size, session_id, failure_count)
|
|
147
|
-
VALUES ($1, $2, 0, $3, $4, 0)
|
|
148
|
-
ON CONFLICT (adapter_name, source_path) DO UPDATE SET
|
|
149
|
-
file_size = EXCLUDED.file_size,
|
|
150
|
-
session_id = EXCLUDED.session_id,
|
|
151
|
-
failure_count = 0,
|
|
152
|
-
last_processed_at = NOW()`, [adapter.name, sourcePath, getFileSize(sourcePath), chunk.id]);
|
|
153
150
|
}
|
|
154
151
|
return results;
|
|
155
152
|
}
|
|
153
|
+
export async function recordClassifiedPg(pool, adapterName, sourcePath, sessionId) {
|
|
154
|
+
const size = getFileSize(sourcePath);
|
|
155
|
+
if (size === null)
|
|
156
|
+
return;
|
|
157
|
+
await pool.query(`INSERT INTO adapter_state (adapter_name, source_path, last_offset, file_size, session_id, failure_count, last_processed_at)
|
|
158
|
+
VALUES ($1, $2, 0, $3, $4, 0, NOW())
|
|
159
|
+
ON CONFLICT (adapter_name, source_path) DO UPDATE SET
|
|
160
|
+
file_size = EXCLUDED.file_size,
|
|
161
|
+
session_id = EXCLUDED.session_id,
|
|
162
|
+
failure_count = 0,
|
|
163
|
+
last_processed_at = NOW()`, [adapterName, sourcePath, size, sessionId]);
|
|
164
|
+
}
|
|
165
|
+
export function recordSkippedLowConfidence(db, adapterName, sourcePath) {
|
|
166
|
+
let size = 0;
|
|
167
|
+
try {
|
|
168
|
+
size = statSync(sourcePath).size;
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
db.prepare(`INSERT INTO adapter_state
|
|
174
|
+
(adapter_name, source_path, last_offset, file_size, session_id, failure_count, last_processed_at)
|
|
175
|
+
VALUES (?, ?, ?, ?, NULL, 0, datetime('now'))
|
|
176
|
+
ON CONFLICT(adapter_name, source_path) DO UPDATE SET
|
|
177
|
+
last_offset = excluded.last_offset,
|
|
178
|
+
file_size = excluded.file_size,
|
|
179
|
+
failure_count = 0,
|
|
180
|
+
last_processed_at = excluded.last_processed_at`).run(adapterName, sourcePath, size, size);
|
|
181
|
+
}
|
|
182
|
+
export async function recordSkippedLowConfidencePg(pool, adapterName, sourcePath) {
|
|
183
|
+
const size = getFileSize(sourcePath);
|
|
184
|
+
if (size === null)
|
|
185
|
+
return;
|
|
186
|
+
await pool.query(`INSERT INTO adapter_state (adapter_name, source_path, last_offset, file_size, session_id, failure_count, last_processed_at)
|
|
187
|
+
VALUES ($1, $2, 0, $3, NULL, 0, NOW())
|
|
188
|
+
ON CONFLICT (adapter_name, source_path) DO UPDATE SET
|
|
189
|
+
file_size = EXCLUDED.file_size,
|
|
190
|
+
failure_count = 0,
|
|
191
|
+
last_processed_at = NOW()`, [adapterName, sourcePath, size]);
|
|
192
|
+
}
|
|
156
193
|
export async function recordFailedPg(pool, adapterName, sourcePath, fileSize) {
|
|
157
|
-
await pool.query(`INSERT INTO adapter_state (adapter_name, source_path, last_offset, failure_count, file_size)
|
|
194
|
+
const res = await pool.query(`INSERT INTO adapter_state (adapter_name, source_path, last_offset, failure_count, file_size)
|
|
158
195
|
VALUES ($1, $2, 0, 1, $3)
|
|
159
196
|
ON CONFLICT (adapter_name, source_path) DO UPDATE SET
|
|
160
197
|
failure_count = adapter_state.failure_count + 1,
|
|
161
198
|
file_size = $3,
|
|
162
|
-
last_processed_at = NOW()
|
|
199
|
+
last_processed_at = NOW()
|
|
200
|
+
RETURNING failure_count`, [adapterName, sourcePath, fileSize]);
|
|
201
|
+
return res.rows[0]?.failure_count ?? 1;
|
|
163
202
|
}
|
|
164
203
|
//# sourceMappingURL=scan-once.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan-once.js","sourceRoot":"","sources":["../../../src/core/scheduler/scan-once.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAanC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AASvC,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAA0B,EAC1B,WAAmB,EACnB,EAAqB,EACrB,MAAc,IAAI,CAAC,GAAG,EAAE;IAExB,MAAM,MAAM,GAAG,WAAW,GAAG,EAAE,GAAG,IAAI,CAAC;IACvC,MAAM,SAAS,GAAG,EAAE;SACjB,OAAO,CACN,kIAAkI,CACnI;SACA,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,MAAM,MAAM,GAAG,IAAI,GAAG,CAA0B,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAE1F,MAAM,GAAG,GAAiB,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;IAEvC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,EAAE,CAAC;QACP,IAAI,CAAC;YACH,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC;QAC7B,IAAI,GAAG,GAAG,MAAM;YAAE,SAAS;QAE3B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,
|
|
1
|
+
{"version":3,"file":"scan-once.js","sourceRoot":"","sources":["../../../src/core/scheduler/scan-once.ts"],"names":[],"mappings":"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"}
|