@inerrata-corporation/errata 2.0.22-dev.4617 → 2.0.22-dev.4629
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/consolidate-worker.mjs +82 -3
- package/errata.mjs +168 -34
- package/generalize-worker.mjs +82 -3
- package/package.json +1 -1
- package/pass-worker.mjs +118 -21
- package/resources/context-plugin/.codex-plugin/plugin.json +1 -1
- package/resources/context-plugin/SHA256SUMS +1 -1
package/consolidate-worker.mjs
CHANGED
|
@@ -17179,6 +17179,12 @@ function changeLogCovers(db, sinceSeq) {
|
|
|
17179
17179
|
const prunedTo = Number(db.prepare("SELECT value FROM store_meta WHERE key = ?").get(PRUNED_TO_KEY)?.["value"] ?? NaN);
|
|
17180
17180
|
return Number.isFinite(prunedTo) && sinceSeq >= prunedTo;
|
|
17181
17181
|
}
|
|
17182
|
+
function readChangedNodeIds(db, sinceSeq, labels) {
|
|
17183
|
+
if (!changeLogCovers(db, sinceSeq)) return null;
|
|
17184
|
+
if (!labels.length) return [];
|
|
17185
|
+
const rows = db.prepare(`SELECT DISTINCT id FROM change_log WHERE change_seq > ? AND kind = 'node' AND label IN (${labels.map(() => "?").join(",")})`).all(sinceSeq, ...labels);
|
|
17186
|
+
return rows.map((r) => r.id);
|
|
17187
|
+
}
|
|
17182
17188
|
function readLineageChangedFiles(db, sinceSeq) {
|
|
17183
17189
|
if (!changeLogCovers(db, sinceSeq)) return null;
|
|
17184
17190
|
const rows = db.prepare(LINEAGE_CHANGED_FILES_SQL).all({ s: sinceSeq });
|
|
@@ -17563,6 +17569,7 @@ var DEMAND_HOT = Math.log1p(10);
|
|
|
17563
17569
|
var DEMAND_WARM = Math.log1p(5);
|
|
17564
17570
|
|
|
17565
17571
|
// ../../packages/local-graph/src/node-select.ts
|
|
17572
|
+
var SELECT_INDEXES = ["nodes_live_local_community", "nodes_live_fold_candidate"];
|
|
17566
17573
|
var EMBEDDING_DIM_SQL = "(CASE WHEN length(embedding_blob) >= 4 THEN length(embedding_blob) / 4 ELSE COALESCE(json_array_length(embedding_json), 0) END)";
|
|
17567
17574
|
var KEY = /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
17568
17575
|
var COLUMNS = /* @__PURE__ */ new Set([
|
|
@@ -17578,6 +17585,10 @@ function path(key) {
|
|
|
17578
17585
|
if (!KEY.test(key)) throw new Error(`selectNodes: bad attr key ${key}`);
|
|
17579
17586
|
return `'$.${key}'`;
|
|
17580
17587
|
}
|
|
17588
|
+
function selectIndex(i) {
|
|
17589
|
+
if (!SELECT_INDEXES.includes(i)) throw new Error(`selectNodes: bad index ${i}`);
|
|
17590
|
+
return i;
|
|
17591
|
+
}
|
|
17581
17592
|
function column(c) {
|
|
17582
17593
|
if (!COLUMNS.has(c)) throw new Error(`selectNodes: bad column ${c}`);
|
|
17583
17594
|
return c;
|
|
@@ -17593,6 +17604,12 @@ function compileNodeWhere(q) {
|
|
|
17593
17604
|
} else if ("idPrefix" in w) {
|
|
17594
17605
|
conds.push("substr(id, 1, ?) = ?");
|
|
17595
17606
|
params.push(w.idPrefix.length, w.idPrefix);
|
|
17607
|
+
} else if ("idIn" in w) {
|
|
17608
|
+
if (w.idIn.length === 0) conds.push("0");
|
|
17609
|
+
else {
|
|
17610
|
+
conds.push(`id IN (${w.idIn.map(() => "?").join(", ")})`);
|
|
17611
|
+
params.push(...w.idIn);
|
|
17612
|
+
}
|
|
17596
17613
|
} else if ("descriptionIn" in w) {
|
|
17597
17614
|
if (w.descriptionIn.length === 0) conds.push("0");
|
|
17598
17615
|
else {
|
|
@@ -17649,7 +17666,7 @@ function compileNodeSelect(q) {
|
|
|
17649
17666
|
}
|
|
17650
17667
|
const orderParams = !q.orderBy && q.labels.length > 1 ? [...q.labels] : [];
|
|
17651
17668
|
const limit = q.limit !== void 0 ? ` LIMIT ${Math.max(0, Math.floor(q.limit))}` : "";
|
|
17652
|
-
const sql = `SELECT id, label, description, created_at, last_updated_at, page_rank, cumulative_hits, extraction_confidence, extraction_source, community, created_at_seq, last_reinforced_at_seq, valid_to, logical_id, version, ${EMBEDDING_DIM_SQL} AS embedding_dim${q.withEmbedding ? ", embedding_blob, embedding_json" : ""}${attrCols} FROM nodes WHERE ${where} ORDER BY ${order}${limit}`;
|
|
17669
|
+
const sql = `SELECT id, label, description, created_at, last_updated_at, page_rank, cumulative_hits, extraction_confidence, extraction_source, community, created_at_seq, last_reinforced_at_seq, valid_to, logical_id, version, ${EMBEDDING_DIM_SQL} AS embedding_dim${q.withEmbedding ? ", embedding_blob, embedding_json" : ""}${attrCols} FROM nodes${q.indexedBy ? ` INDEXED BY ${selectIndex(q.indexedBy)}` : ""} WHERE ${where} ORDER BY ${order}${limit}`;
|
|
17653
17670
|
return { sql, params: [...params, ...orderParams] };
|
|
17654
17671
|
}
|
|
17655
17672
|
function decodeAttr(value, type) {
|
|
@@ -17847,6 +17864,19 @@ var TEMPORAL_INDEX_SQL = `
|
|
|
17847
17864
|
CREATE INDEX IF NOT EXISTS nodes_live ON nodes(label, valid_to);
|
|
17848
17865
|
CREATE INDEX IF NOT EXISTS nodes_live_count ON nodes(valid_to);
|
|
17849
17866
|
CREATE INDEX IF NOT EXISTS nodes_live_recent ON nodes(label, last_updated_at DESC) WHERE valid_to IS NULL;
|
|
17867
|
+
-- "Anything created since the watermark?" guards (the fold, regression and
|
|
17868
|
+
-- canonical-bind sweeps run one per session boundary). Without it the planner
|
|
17869
|
+
-- walks nodes_live and reads every live row of the label to test created_at:
|
|
17870
|
+
-- 56 MB per guard on a 1.1 GB store, to learn there was nothing to do. valid_to
|
|
17871
|
+
-- is a key column so the planner prefers this over nodes_live (one more term).
|
|
17872
|
+
CREATE INDEX IF NOT EXISTS nodes_live_created ON nodes(label, valid_to, created_at) WHERE valid_to IS NULL;
|
|
17873
|
+
-- Community members (the skills pull reads them twice per session boundary):
|
|
17874
|
+
-- ~15% of semantic nodes carry a localCommunity, and without this every live
|
|
17875
|
+
-- semantic row was read to find them (168 MB \u2192 18 MB per read).
|
|
17876
|
+
CREATE INDEX IF NOT EXISTS nodes_live_local_community ON nodes(label, valid_to, json_extract(attrs_json, '$.localCommunity')) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.localCommunity') IS NOT NULL;
|
|
17877
|
+
-- Problems parked for the fold judge (read every settle boundary): ~1 in 5 open
|
|
17878
|
+
-- Problems; without it every live Problem was read to find them (56 MB).
|
|
17879
|
+
CREATE INDEX IF NOT EXISTS nodes_live_fold_candidate ON nodes(label, valid_to) WHERE valid_to IS NULL AND json_type(attrs_json, '$.foldCandidate') IS NOT NULL;
|
|
17850
17880
|
CREATE INDEX IF NOT EXISTS nodes_session_evidence ON nodes(id) WHERE ${SESSION_EVIDENCE_PREDICATE};
|
|
17851
17881
|
CREATE INDEX IF NOT EXISTS edges_session_evidence ON edges(id) WHERE ${SESSION_EVIDENCE_PREDICATE};
|
|
17852
17882
|
-- Covering + partial index for labelFingerprint over the instance labels: the
|
|
@@ -17861,6 +17891,14 @@ CREATE INDEX IF NOT EXISTS nodes_instance_fingerprint_v2 ON nodes(label, last_up
|
|
|
17861
17891
|
CREATE INDEX IF NOT EXISTS nodes_live_page_rank ON nodes(valid_to, page_rank);
|
|
17862
17892
|
CREATE INDEX IF NOT EXISTS nodes_logical ON nodes(logical_id, version);
|
|
17863
17893
|
CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
|
|
17894
|
+
-- Newest live edges first, so a "recent N matching edges" read stops early instead
|
|
17895
|
+
-- of matching and sorting every live edge (the hourly liveness check: 163 MB \u2192
|
|
17896
|
+
-- 69 MB). Named by recentEdgeAttrCoverage; the planner keeps edges_live otherwise.
|
|
17897
|
+
CREATE INDEX IF NOT EXISTS edges_live_created ON edges(created_at) WHERE valid_to IS NULL;
|
|
17898
|
+
-- Live prior-tag edges by recency: the liveness corroboration check reads the
|
|
17899
|
+
-- newest 100 of ~300, and walking all live edges newest-first to find them read
|
|
17900
|
+
-- 69 MB. Its predicate is the one recentEdgeAttrCoverage uses for that marker.
|
|
17901
|
+
CREATE INDEX IF NOT EXISTS edges_live_prior_tag ON edges(created_at) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1;
|
|
17864
17902
|
-- Expression index on the per-node relPath (stored in attrs_json) so the
|
|
17865
17903
|
-- incremental reindex can fetch just the changed files' symbols instead of
|
|
17866
17904
|
-- scanning every versioned node. Partial: only live rows are ever queried.
|
|
@@ -17951,6 +17989,7 @@ function rowToEdge(r) {
|
|
|
17951
17989
|
}
|
|
17952
17990
|
var FINGERPRINT_INDEXED_LABELS = ["Problem", "Vulnerability", "Solution", "RootCause"];
|
|
17953
17991
|
var NODE_LABELS_CHUNK = 256;
|
|
17992
|
+
var PRIOR_TAG_MARKER = '"priorTag":true';
|
|
17954
17993
|
var SqliteGraphStore = class {
|
|
17955
17994
|
db;
|
|
17956
17995
|
// Typed edge lookups build their SQL from the number of types asked for, and
|
|
@@ -18557,6 +18596,27 @@ var SqliteGraphStore = class {
|
|
|
18557
18596
|
cloud: r.cloud === 1
|
|
18558
18597
|
}));
|
|
18559
18598
|
}
|
|
18599
|
+
findNodeStampsByLabelAttrs(label, attrKeys) {
|
|
18600
|
+
for (const k of attrKeys) if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) throw new Error(`findNodeStampsByLabelAttrs: bad attr key ${k}`);
|
|
18601
|
+
const keys = [...new Set(attrKeys)];
|
|
18602
|
+
const rows = this.db.prepare(
|
|
18603
|
+
`SELECT id, created_at, created_at_seq,
|
|
18604
|
+
${keys.map((k, i) => `json_type(attrs_json, '$.${k}') IS NOT NULL AS h${i}`).join(", ")}${keys.length ? "," : ""}
|
|
18605
|
+
COALESCE(json_extract(attrs_json, '$.source') = 'cloud', 0) AS cloud
|
|
18606
|
+
FROM nodes WHERE label = ? AND valid_to IS NULL`
|
|
18607
|
+
).all(label);
|
|
18608
|
+
const out = new Map(keys.map((k) => [k, []]));
|
|
18609
|
+
for (const r of rows) {
|
|
18610
|
+
keys.forEach((k, i) => out.get(k).push({
|
|
18611
|
+
id: r.id,
|
|
18612
|
+
createdAt: r.created_at,
|
|
18613
|
+
...r.created_at_seq != null ? { createdAtSeq: r.created_at_seq } : {},
|
|
18614
|
+
has: r[`h${i}`] === 1,
|
|
18615
|
+
cloud: r.cloud === 1
|
|
18616
|
+
}));
|
|
18617
|
+
}
|
|
18618
|
+
return out;
|
|
18619
|
+
}
|
|
18560
18620
|
findNodeAttrsByLabel(label) {
|
|
18561
18621
|
const rows = this.stmts.attrsByLabel.all(label);
|
|
18562
18622
|
return rows.map((r) => ({
|
|
@@ -18798,6 +18858,9 @@ var SqliteGraphStore = class {
|
|
|
18798
18858
|
lineageChangedFiles(sinceSeq) {
|
|
18799
18859
|
return readLineageChangedFiles(this.db, sinceSeq);
|
|
18800
18860
|
}
|
|
18861
|
+
changedNodeIds(sinceSeq, labels) {
|
|
18862
|
+
return readChangedNodeIds(this.db, sinceSeq, labels);
|
|
18863
|
+
}
|
|
18801
18864
|
pruneChangeLog() {
|
|
18802
18865
|
return pruneChangeLog(this.db);
|
|
18803
18866
|
}
|
|
@@ -18988,11 +19051,26 @@ var SqliteGraphStore = class {
|
|
|
18988
19051
|
).get(...edgeTypes, label, cloudOnly ? 1 : 0);
|
|
18989
19052
|
return { count: Number(r.count), total: Number(r.total) };
|
|
18990
19053
|
}
|
|
19054
|
+
liveEdgeTargets(edgeTypes) {
|
|
19055
|
+
if (edgeTypes.length === 0) return [];
|
|
19056
|
+
const rows = this.db.prepare(`SELECT DISTINCT to_id FROM edges INDEXED BY edges_type WHERE type IN (${edgeTypes.map(() => "?").join(",")}) AND valid_to IS NULL`).all(...edgeTypes);
|
|
19057
|
+
return rows.map((r) => r.to_id);
|
|
19058
|
+
}
|
|
18991
19059
|
recentEdgeAttrCoverage(marker, attr, limit) {
|
|
19060
|
+
if (marker === PRIOR_TAG_MARKER) {
|
|
19061
|
+
const r2 = this.db.prepare(
|
|
19062
|
+
`SELECT COUNT(*) AS total,
|
|
19063
|
+
COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
|
|
19064
|
+
FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_prior_tag
|
|
19065
|
+
WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1
|
|
19066
|
+
ORDER BY created_at DESC LIMIT ?)`
|
|
19067
|
+
).get(attr, limit);
|
|
19068
|
+
return { count: Number(r2.count), total: Number(r2.total) };
|
|
19069
|
+
}
|
|
18992
19070
|
const r = this.db.prepare(
|
|
18993
19071
|
`SELECT COUNT(*) AS total,
|
|
18994
19072
|
COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
|
|
18995
|
-
FROM (SELECT attrs_json FROM edges
|
|
19073
|
+
FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_created
|
|
18996
19074
|
WHERE valid_to IS NULL AND attrs_json LIKE ?
|
|
18997
19075
|
ORDER BY created_at DESC LIMIT ?)`
|
|
18998
19076
|
).get(attr, `%${marker}%`, limit);
|
|
@@ -19140,8 +19218,9 @@ var SqliteGraphStore = class {
|
|
|
19140
19218
|
* so it must be a plain identifier. */
|
|
19141
19219
|
nodesAsOfWhereTrue(t, attr) {
|
|
19142
19220
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attr)) throw new Error(`nodesAsOfWhereTrue: bad attr ${JSON.stringify(attr)}`);
|
|
19221
|
+
const indexed = attr === "revisit" ? " INDEXED BY nodes_revisit_true" : "";
|
|
19143
19222
|
const rows = this.db.prepare(
|
|
19144
|
-
`SELECT * FROM nodes WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)
|
|
19223
|
+
`SELECT * FROM nodes${indexed} WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)
|
|
19145
19224
|
AND json_type(attrs_json, '$.${attr}') = 'true'
|
|
19146
19225
|
ORDER BY rowid`
|
|
19147
19226
|
).all({ t });
|
package/errata.mjs
CHANGED
|
@@ -19243,6 +19243,12 @@ function changeLogCovers(db, sinceSeq) {
|
|
|
19243
19243
|
const prunedTo = Number(db.prepare("SELECT value FROM store_meta WHERE key = ?").get(PRUNED_TO_KEY)?.["value"] ?? NaN);
|
|
19244
19244
|
return Number.isFinite(prunedTo) && sinceSeq >= prunedTo;
|
|
19245
19245
|
}
|
|
19246
|
+
function readChangedNodeIds(db, sinceSeq, labels) {
|
|
19247
|
+
if (!changeLogCovers(db, sinceSeq)) return null;
|
|
19248
|
+
if (!labels.length) return [];
|
|
19249
|
+
const rows = db.prepare(`SELECT DISTINCT id FROM change_log WHERE change_seq > ? AND kind = 'node' AND label IN (${labels.map(() => "?").join(",")})`).all(sinceSeq, ...labels);
|
|
19250
|
+
return rows.map((r) => r.id);
|
|
19251
|
+
}
|
|
19246
19252
|
function readLineageChangedFiles(db, sinceSeq) {
|
|
19247
19253
|
if (!changeLogCovers(db, sinceSeq)) return null;
|
|
19248
19254
|
const rows = db.prepare(LINEAGE_CHANGED_FILES_SQL).all({ s: sinceSeq });
|
|
@@ -20376,6 +20382,10 @@ function path(key) {
|
|
|
20376
20382
|
if (!KEY.test(key)) throw new Error(`selectNodes: bad attr key ${key}`);
|
|
20377
20383
|
return `'$.${key}'`;
|
|
20378
20384
|
}
|
|
20385
|
+
function selectIndex(i2) {
|
|
20386
|
+
if (!SELECT_INDEXES.includes(i2)) throw new Error(`selectNodes: bad index ${i2}`);
|
|
20387
|
+
return i2;
|
|
20388
|
+
}
|
|
20379
20389
|
function column(c) {
|
|
20380
20390
|
if (!COLUMNS.has(c)) throw new Error(`selectNodes: bad column ${c}`);
|
|
20381
20391
|
return c;
|
|
@@ -20391,6 +20401,12 @@ function compileNodeWhere(q) {
|
|
|
20391
20401
|
} else if ("idPrefix" in w) {
|
|
20392
20402
|
conds.push("substr(id, 1, ?) = ?");
|
|
20393
20403
|
params.push(w.idPrefix.length, w.idPrefix);
|
|
20404
|
+
} else if ("idIn" in w) {
|
|
20405
|
+
if (w.idIn.length === 0) conds.push("0");
|
|
20406
|
+
else {
|
|
20407
|
+
conds.push(`id IN (${w.idIn.map(() => "?").join(", ")})`);
|
|
20408
|
+
params.push(...w.idIn);
|
|
20409
|
+
}
|
|
20394
20410
|
} else if ("descriptionIn" in w) {
|
|
20395
20411
|
if (w.descriptionIn.length === 0) conds.push("0");
|
|
20396
20412
|
else {
|
|
@@ -20447,7 +20463,7 @@ function compileNodeSelect(q) {
|
|
|
20447
20463
|
}
|
|
20448
20464
|
const orderParams = !q.orderBy && q.labels.length > 1 ? [...q.labels] : [];
|
|
20449
20465
|
const limit = q.limit !== void 0 ? ` LIMIT ${Math.max(0, Math.floor(q.limit))}` : "";
|
|
20450
|
-
const sql = `SELECT id, label, description, created_at, last_updated_at, page_rank, cumulative_hits, extraction_confidence, extraction_source, community, created_at_seq, last_reinforced_at_seq, valid_to, logical_id, version, ${EMBEDDING_DIM_SQL} AS embedding_dim${q.withEmbedding ? ", embedding_blob, embedding_json" : ""}${attrCols} FROM nodes WHERE ${where} ORDER BY ${order}${limit}`;
|
|
20466
|
+
const sql = `SELECT id, label, description, created_at, last_updated_at, page_rank, cumulative_hits, extraction_confidence, extraction_source, community, created_at_seq, last_reinforced_at_seq, valid_to, logical_id, version, ${EMBEDDING_DIM_SQL} AS embedding_dim${q.withEmbedding ? ", embedding_blob, embedding_json" : ""}${attrCols} FROM nodes${q.indexedBy ? ` INDEXED BY ${selectIndex(q.indexedBy)}` : ""} WHERE ${where} ORDER BY ${order}${limit}`;
|
|
20451
20467
|
return { sql, params: [...params, ...orderParams] };
|
|
20452
20468
|
}
|
|
20453
20469
|
function decodeAttr(value, type) {
|
|
@@ -20495,10 +20511,11 @@ function decodeSelectedRow(r, attrs, decodeVector) {
|
|
|
20495
20511
|
attrs: out2
|
|
20496
20512
|
};
|
|
20497
20513
|
}
|
|
20498
|
-
var EMBEDDING_DIM_SQL, KEY, COLUMNS;
|
|
20514
|
+
var SELECT_INDEXES, EMBEDDING_DIM_SQL, KEY, COLUMNS;
|
|
20499
20515
|
var init_node_select = __esm({
|
|
20500
20516
|
"../../packages/local-graph/src/node-select.ts"() {
|
|
20501
20517
|
"use strict";
|
|
20518
|
+
SELECT_INDEXES = ["nodes_live_local_community", "nodes_live_fold_candidate"];
|
|
20502
20519
|
EMBEDDING_DIM_SQL = "(CASE WHEN length(embedding_blob) >= 4 THEN length(embedding_blob) / 4 ELSE COALESCE(json_array_length(embedding_json), 0) END)";
|
|
20503
20520
|
KEY = /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
20504
20521
|
COLUMNS = /* @__PURE__ */ new Set([
|
|
@@ -20611,7 +20628,7 @@ function rowToEdge(r) {
|
|
|
20611
20628
|
function openGraphStore(opts) {
|
|
20612
20629
|
return new SqliteGraphStore(opts);
|
|
20613
20630
|
}
|
|
20614
|
-
var PAGE_RANK_SCALE_KEY, TEXT_SEARCH_COLUMNS, LOCAL_RULE_OVERRIDES, SCHEMA_VERSION, SESSION_REPAIR_KEY, SESSION_EVIDENCE_PREDICATE, SCHEMA_SQL, TEMPORAL_INDEX_SQL, FINGERPRINT_INDEXED_LABELS, NODE_LABELS_CHUNK, SqliteGraphStore;
|
|
20631
|
+
var PAGE_RANK_SCALE_KEY, TEXT_SEARCH_COLUMNS, LOCAL_RULE_OVERRIDES, SCHEMA_VERSION, SESSION_REPAIR_KEY, SESSION_EVIDENCE_PREDICATE, SCHEMA_SQL, TEMPORAL_INDEX_SQL, FINGERPRINT_INDEXED_LABELS, NODE_LABELS_CHUNK, PRIOR_TAG_MARKER, SqliteGraphStore;
|
|
20615
20632
|
var init_store = __esm({
|
|
20616
20633
|
"../../packages/local-graph/src/store.ts"() {
|
|
20617
20634
|
"use strict";
|
|
@@ -20756,6 +20773,19 @@ CREATE UNIQUE INDEX IF NOT EXISTS edges_triple ON edges(from_id, type, to_id);
|
|
|
20756
20773
|
CREATE INDEX IF NOT EXISTS nodes_live ON nodes(label, valid_to);
|
|
20757
20774
|
CREATE INDEX IF NOT EXISTS nodes_live_count ON nodes(valid_to);
|
|
20758
20775
|
CREATE INDEX IF NOT EXISTS nodes_live_recent ON nodes(label, last_updated_at DESC) WHERE valid_to IS NULL;
|
|
20776
|
+
-- "Anything created since the watermark?" guards (the fold, regression and
|
|
20777
|
+
-- canonical-bind sweeps run one per session boundary). Without it the planner
|
|
20778
|
+
-- walks nodes_live and reads every live row of the label to test created_at:
|
|
20779
|
+
-- 56 MB per guard on a 1.1 GB store, to learn there was nothing to do. valid_to
|
|
20780
|
+
-- is a key column so the planner prefers this over nodes_live (one more term).
|
|
20781
|
+
CREATE INDEX IF NOT EXISTS nodes_live_created ON nodes(label, valid_to, created_at) WHERE valid_to IS NULL;
|
|
20782
|
+
-- Community members (the skills pull reads them twice per session boundary):
|
|
20783
|
+
-- ~15% of semantic nodes carry a localCommunity, and without this every live
|
|
20784
|
+
-- semantic row was read to find them (168 MB \u2192 18 MB per read).
|
|
20785
|
+
CREATE INDEX IF NOT EXISTS nodes_live_local_community ON nodes(label, valid_to, json_extract(attrs_json, '$.localCommunity')) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.localCommunity') IS NOT NULL;
|
|
20786
|
+
-- Problems parked for the fold judge (read every settle boundary): ~1 in 5 open
|
|
20787
|
+
-- Problems; without it every live Problem was read to find them (56 MB).
|
|
20788
|
+
CREATE INDEX IF NOT EXISTS nodes_live_fold_candidate ON nodes(label, valid_to) WHERE valid_to IS NULL AND json_type(attrs_json, '$.foldCandidate') IS NOT NULL;
|
|
20759
20789
|
CREATE INDEX IF NOT EXISTS nodes_session_evidence ON nodes(id) WHERE ${SESSION_EVIDENCE_PREDICATE};
|
|
20760
20790
|
CREATE INDEX IF NOT EXISTS edges_session_evidence ON edges(id) WHERE ${SESSION_EVIDENCE_PREDICATE};
|
|
20761
20791
|
-- Covering + partial index for labelFingerprint over the instance labels: the
|
|
@@ -20770,6 +20800,14 @@ CREATE INDEX IF NOT EXISTS nodes_instance_fingerprint_v2 ON nodes(label, last_up
|
|
|
20770
20800
|
CREATE INDEX IF NOT EXISTS nodes_live_page_rank ON nodes(valid_to, page_rank);
|
|
20771
20801
|
CREATE INDEX IF NOT EXISTS nodes_logical ON nodes(logical_id, version);
|
|
20772
20802
|
CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
|
|
20803
|
+
-- Newest live edges first, so a "recent N matching edges" read stops early instead
|
|
20804
|
+
-- of matching and sorting every live edge (the hourly liveness check: 163 MB \u2192
|
|
20805
|
+
-- 69 MB). Named by recentEdgeAttrCoverage; the planner keeps edges_live otherwise.
|
|
20806
|
+
CREATE INDEX IF NOT EXISTS edges_live_created ON edges(created_at) WHERE valid_to IS NULL;
|
|
20807
|
+
-- Live prior-tag edges by recency: the liveness corroboration check reads the
|
|
20808
|
+
-- newest 100 of ~300, and walking all live edges newest-first to find them read
|
|
20809
|
+
-- 69 MB. Its predicate is the one recentEdgeAttrCoverage uses for that marker.
|
|
20810
|
+
CREATE INDEX IF NOT EXISTS edges_live_prior_tag ON edges(created_at) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1;
|
|
20773
20811
|
-- Expression index on the per-node relPath (stored in attrs_json) so the
|
|
20774
20812
|
-- incremental reindex can fetch just the changed files' symbols instead of
|
|
20775
20813
|
-- scanning every versioned node. Partial: only live rows are ever queried.
|
|
@@ -20803,6 +20841,7 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
|
|
|
20803
20841
|
`;
|
|
20804
20842
|
FINGERPRINT_INDEXED_LABELS = ["Problem", "Vulnerability", "Solution", "RootCause"];
|
|
20805
20843
|
NODE_LABELS_CHUNK = 256;
|
|
20844
|
+
PRIOR_TAG_MARKER = '"priorTag":true';
|
|
20806
20845
|
SqliteGraphStore = class {
|
|
20807
20846
|
db;
|
|
20808
20847
|
// Typed edge lookups build their SQL from the number of types asked for, and
|
|
@@ -21409,6 +21448,27 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
|
|
|
21409
21448
|
cloud: r.cloud === 1
|
|
21410
21449
|
}));
|
|
21411
21450
|
}
|
|
21451
|
+
findNodeStampsByLabelAttrs(label, attrKeys) {
|
|
21452
|
+
for (const k of attrKeys) if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) throw new Error(`findNodeStampsByLabelAttrs: bad attr key ${k}`);
|
|
21453
|
+
const keys = [...new Set(attrKeys)];
|
|
21454
|
+
const rows = this.db.prepare(
|
|
21455
|
+
`SELECT id, created_at, created_at_seq,
|
|
21456
|
+
${keys.map((k, i2) => `json_type(attrs_json, '$.${k}') IS NOT NULL AS h${i2}`).join(", ")}${keys.length ? "," : ""}
|
|
21457
|
+
COALESCE(json_extract(attrs_json, '$.source') = 'cloud', 0) AS cloud
|
|
21458
|
+
FROM nodes WHERE label = ? AND valid_to IS NULL`
|
|
21459
|
+
).all(label);
|
|
21460
|
+
const out2 = new Map(keys.map((k) => [k, []]));
|
|
21461
|
+
for (const r of rows) {
|
|
21462
|
+
keys.forEach((k, i2) => out2.get(k).push({
|
|
21463
|
+
id: r.id,
|
|
21464
|
+
createdAt: r.created_at,
|
|
21465
|
+
...r.created_at_seq != null ? { createdAtSeq: r.created_at_seq } : {},
|
|
21466
|
+
has: r[`h${i2}`] === 1,
|
|
21467
|
+
cloud: r.cloud === 1
|
|
21468
|
+
}));
|
|
21469
|
+
}
|
|
21470
|
+
return out2;
|
|
21471
|
+
}
|
|
21412
21472
|
findNodeAttrsByLabel(label) {
|
|
21413
21473
|
const rows = this.stmts.attrsByLabel.all(label);
|
|
21414
21474
|
return rows.map((r) => ({
|
|
@@ -21650,6 +21710,9 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
|
|
|
21650
21710
|
lineageChangedFiles(sinceSeq) {
|
|
21651
21711
|
return readLineageChangedFiles(this.db, sinceSeq);
|
|
21652
21712
|
}
|
|
21713
|
+
changedNodeIds(sinceSeq, labels) {
|
|
21714
|
+
return readChangedNodeIds(this.db, sinceSeq, labels);
|
|
21715
|
+
}
|
|
21653
21716
|
pruneChangeLog() {
|
|
21654
21717
|
return pruneChangeLog(this.db);
|
|
21655
21718
|
}
|
|
@@ -21840,11 +21903,26 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
|
|
|
21840
21903
|
).get(...edgeTypes, label, cloudOnly ? 1 : 0);
|
|
21841
21904
|
return { count: Number(r.count), total: Number(r.total) };
|
|
21842
21905
|
}
|
|
21906
|
+
liveEdgeTargets(edgeTypes) {
|
|
21907
|
+
if (edgeTypes.length === 0) return [];
|
|
21908
|
+
const rows = this.db.prepare(`SELECT DISTINCT to_id FROM edges INDEXED BY edges_type WHERE type IN (${edgeTypes.map(() => "?").join(",")}) AND valid_to IS NULL`).all(...edgeTypes);
|
|
21909
|
+
return rows.map((r) => r.to_id);
|
|
21910
|
+
}
|
|
21843
21911
|
recentEdgeAttrCoverage(marker, attr, limit) {
|
|
21912
|
+
if (marker === PRIOR_TAG_MARKER) {
|
|
21913
|
+
const r2 = this.db.prepare(
|
|
21914
|
+
`SELECT COUNT(*) AS total,
|
|
21915
|
+
COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
|
|
21916
|
+
FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_prior_tag
|
|
21917
|
+
WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1
|
|
21918
|
+
ORDER BY created_at DESC LIMIT ?)`
|
|
21919
|
+
).get(attr, limit);
|
|
21920
|
+
return { count: Number(r2.count), total: Number(r2.total) };
|
|
21921
|
+
}
|
|
21844
21922
|
const r = this.db.prepare(
|
|
21845
21923
|
`SELECT COUNT(*) AS total,
|
|
21846
21924
|
COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
|
|
21847
|
-
FROM (SELECT attrs_json FROM edges
|
|
21925
|
+
FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_created
|
|
21848
21926
|
WHERE valid_to IS NULL AND attrs_json LIKE ?
|
|
21849
21927
|
ORDER BY created_at DESC LIMIT ?)`
|
|
21850
21928
|
).get(attr, `%${marker}%`, limit);
|
|
@@ -21992,8 +22070,9 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
|
|
|
21992
22070
|
* so it must be a plain identifier. */
|
|
21993
22071
|
nodesAsOfWhereTrue(t, attr) {
|
|
21994
22072
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attr)) throw new Error(`nodesAsOfWhereTrue: bad attr ${JSON.stringify(attr)}`);
|
|
22073
|
+
const indexed = attr === "revisit" ? " INDEXED BY nodes_revisit_true" : "";
|
|
21995
22074
|
const rows = this.db.prepare(
|
|
21996
|
-
`SELECT * FROM nodes WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)
|
|
22075
|
+
`SELECT * FROM nodes${indexed} WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)
|
|
21997
22076
|
AND json_type(attrs_json, '$.${attr}') = 'true'
|
|
21998
22077
|
ORDER BY rowid`
|
|
21999
22078
|
).all({ t });
|
|
@@ -22373,19 +22452,16 @@ function conditionOf(node2) {
|
|
|
22373
22452
|
}
|
|
22374
22453
|
function clearAnsweredRevisits(store, ts) {
|
|
22375
22454
|
const report = { cleared: 0, standing: 0 };
|
|
22376
|
-
|
|
22377
|
-
|
|
22378
|
-
|
|
22379
|
-
|
|
22380
|
-
|
|
22381
|
-
|
|
22382
|
-
|
|
22383
|
-
report.standing++;
|
|
22384
|
-
continue;
|
|
22385
|
-
}
|
|
22386
|
-
clearRevisit(store, node2.id, ts);
|
|
22387
|
-
report.cleared++;
|
|
22455
|
+
const semantic = new Set(SEMANTIC_NODE_LABELS);
|
|
22456
|
+
for (const node2 of store.nodesAsOfWhereTrue(ts, "revisit")) {
|
|
22457
|
+
if (!semantic.has(node2.label) || node2.validTo != null) continue;
|
|
22458
|
+
const condition = conditionOf(node2);
|
|
22459
|
+
if (condition === void 0 || !isRevisitAnswered(store, node2, condition)) {
|
|
22460
|
+
report.standing++;
|
|
22461
|
+
continue;
|
|
22388
22462
|
}
|
|
22463
|
+
clearRevisit(store, node2.id, ts);
|
|
22464
|
+
report.cleared++;
|
|
22389
22465
|
}
|
|
22390
22466
|
return report;
|
|
22391
22467
|
}
|
|
@@ -26253,7 +26329,10 @@ function communityMembers(store) {
|
|
|
26253
26329
|
return store.selectNodes({
|
|
26254
26330
|
labels: JOINT_COMMUNITY_LABELS,
|
|
26255
26331
|
attrs: ["localCommunity", "cloudNodeId", "source"],
|
|
26256
|
-
where: [{ attr: "localCommunity", notNullish: true }]
|
|
26332
|
+
where: [{ attr: "localCommunity", notNullish: true }],
|
|
26333
|
+
// ~15% of semantic nodes are members; the ordered select otherwise walks
|
|
26334
|
+
// nodes_live and reads every live semantic row (168 MB on a 1.1 GB store).
|
|
26335
|
+
indexedBy: "nodes_live_local_community"
|
|
26257
26336
|
});
|
|
26258
26337
|
}
|
|
26259
26338
|
function communitySeeds(store, opts = {}) {
|
|
@@ -26451,7 +26530,10 @@ async function resolveFoldCandidates(store, opts) {
|
|
|
26451
26530
|
{ attr: "resolvedAt", nullish: true },
|
|
26452
26531
|
{ attr: "mergedInto", absent: true },
|
|
26453
26532
|
{ attr: "foldCandidate", present: true }
|
|
26454
|
-
]
|
|
26533
|
+
],
|
|
26534
|
+
// Only parked Problems are in it; the rowid-ordered select otherwise walks
|
|
26535
|
+
// nodes_live and reads every live Problem (56 MB per settle boundary).
|
|
26536
|
+
indexedBy: "nodes_live_fold_candidate"
|
|
26455
26537
|
});
|
|
26456
26538
|
const markOf = (n) => n.attrs["foldCandidate"];
|
|
26457
26539
|
report.pending = pool.length;
|
|
@@ -26783,7 +26865,14 @@ var init_principle_sync = __esm({
|
|
|
26783
26865
|
});
|
|
26784
26866
|
|
|
26785
26867
|
// ../../packages/local-graph/src/mechanism-liveness.ts
|
|
26786
|
-
function evaluateFed(store, d) {
|
|
26868
|
+
function evaluateFed(store, d, stamps) {
|
|
26869
|
+
const incomingRows = d.fedIncoming && store.liveEdgeTargets ? stamps?.(d.fedIncoming.label, "source") : void 0;
|
|
26870
|
+
if (d.fedIncoming && incomingRows) {
|
|
26871
|
+
const targets = new Set(store.liveEdgeTargets(d.fedIncoming.edgeTypes));
|
|
26872
|
+
const rows = d.fedIncoming.cloudOnly ? incomingRows.filter((r) => r.cloud) : incomingRows;
|
|
26873
|
+
const count2 = rows.filter((r) => targets.has(r.id)).length;
|
|
26874
|
+
return { count: count2, total: rows.length, fraction: rows.length === 0 ? 0 : count2 / rows.length };
|
|
26875
|
+
}
|
|
26787
26876
|
if (d.fedIncoming) {
|
|
26788
26877
|
const { count: count2, total } = store.incomingEdgeCoverage?.(
|
|
26789
26878
|
d.fedIncoming.label,
|
|
@@ -26803,7 +26892,7 @@ function evaluateFed(store, d) {
|
|
|
26803
26892
|
if (!d.fed) return { count: 0, total: 0, fraction: 0 };
|
|
26804
26893
|
const column2 = COLUMN_INPUTS[d.fed.attr];
|
|
26805
26894
|
const fed = d.fed;
|
|
26806
|
-
const all = fed.labels.flatMap((label) => store.findNodeStampsByLabel ? store.findNodeStampsByLabel(label, fed.attr) : store.findNodeAttrsByLabel(label));
|
|
26895
|
+
const all = fed.labels.flatMap((label) => stamps?.(label, fed.attr) ?? (store.findNodeStampsByLabel ? store.findNodeStampsByLabel(label, fed.attr) : store.findNodeAttrsByLabel(label)));
|
|
26807
26896
|
const isCloudMirror = (n) => n.cloud ?? n.attrs?.["source"] === "cloud";
|
|
26808
26897
|
const nodes = fed.localOnly ? all.filter((n) => !isCloudMirror(n)) : all;
|
|
26809
26898
|
const has = (n) => column2 ? column2(n) : n.has ?? n.attrs?.[fed.attr] !== void 0;
|
|
@@ -26826,8 +26915,16 @@ function evaluateMechanisms(store, invocations = /* @__PURE__ */ new Map(), mech
|
|
|
26826
26915
|
if (!counts.has(label)) counts.set(label, store.countNodesByLabel(label));
|
|
26827
26916
|
return counts.get(label);
|
|
26828
26917
|
};
|
|
26918
|
+
const wanted = /* @__PURE__ */ new Map();
|
|
26919
|
+
for (const d of mechanisms) for (const l of d.fed?.labels ?? []) wanted.set(l, (wanted.get(l) ?? /* @__PURE__ */ new Set()).add(d.fed.attr));
|
|
26920
|
+
for (const d of mechanisms) if (d.fedIncoming) wanted.set(d.fedIncoming.label, (wanted.get(d.fedIncoming.label) ?? /* @__PURE__ */ new Set()).add("source"));
|
|
26921
|
+
const byLabel = /* @__PURE__ */ new Map();
|
|
26922
|
+
const stamps = store.findNodeStampsByLabelAttrs ? (label, attr) => {
|
|
26923
|
+
if (!byLabel.has(label)) byLabel.set(label, store.findNodeStampsByLabelAttrs(label, [...wanted.get(label) ?? [attr]]));
|
|
26924
|
+
return byLabel.get(label).get(attr);
|
|
26925
|
+
} : void 0;
|
|
26829
26926
|
return mechanisms.map((d) => {
|
|
26830
|
-
const fed = evaluateFed(store, d);
|
|
26927
|
+
const fed = evaluateFed(store, d, stamps);
|
|
26831
26928
|
const inv = invocations.get(d.pass);
|
|
26832
26929
|
const effectCount = d.effectIsLevel ? Math.max(
|
|
26833
26930
|
0,
|
|
@@ -34598,7 +34695,10 @@ function embedCodeNodes(store, opts = {}) {
|
|
|
34598
34695
|
return embedNodesByLabels(store, CODE_LABELS, opts);
|
|
34599
34696
|
}
|
|
34600
34697
|
function embedSemanticNodes(store, opts = {}) {
|
|
34601
|
-
return embedNodesByLabels(store, SEMANTIC_LABELS,
|
|
34698
|
+
return embedNodesByLabels(store, SEMANTIC_LABELS, {
|
|
34699
|
+
incrementalKey: `embed-scan:semantic:${opts.mode === "hash" ? "hash" : "model"}`,
|
|
34700
|
+
...opts
|
|
34701
|
+
});
|
|
34602
34702
|
}
|
|
34603
34703
|
async function ensureNodeEmbedded(store, nodeId, opts = {}) {
|
|
34604
34704
|
const node2 = store.getNode(nodeId);
|
|
@@ -34671,14 +34771,32 @@ async function embedNodesByLabels(store, labels, opts = {}) {
|
|
|
34671
34771
|
};
|
|
34672
34772
|
const hashOnly = opts.mode === "hash";
|
|
34673
34773
|
const candidates = [];
|
|
34674
|
-
|
|
34675
|
-
|
|
34676
|
-
|
|
34677
|
-
|
|
34678
|
-
|
|
34774
|
+
const watermarkKey = opts.incrementalKey;
|
|
34775
|
+
const seqBefore = watermarkKey ? store.changeSeq?.() : void 0;
|
|
34776
|
+
let held = null;
|
|
34777
|
+
try {
|
|
34778
|
+
held = watermarkKey ? JSON.parse(store.getMeta?.(watermarkKey) ?? "null") : null;
|
|
34779
|
+
} catch {
|
|
34780
|
+
held = null;
|
|
34781
|
+
}
|
|
34782
|
+
const changedIds = !opts.force && held && seqBefore !== void 0 ? store.changedNodeIds?.(held.seq, labels) ?? null : null;
|
|
34783
|
+
const scan2 = function* () {
|
|
34784
|
+
if (changedIds === null) {
|
|
34785
|
+
for (const label of labels) yield* store.selectNodes({ labels: [label], attrs: EMBED_SCAN_ATTRS });
|
|
34786
|
+
return;
|
|
34787
|
+
}
|
|
34788
|
+
for (let i2 = 0; i2 < changedIds.length; i2 += ID_CHUNK) {
|
|
34789
|
+
yield* store.selectNodes({ labels, attrs: EMBED_SCAN_ATTRS, where: [{ idIn: changedIds.slice(i2, i2 + ID_CHUNK) }] });
|
|
34790
|
+
}
|
|
34791
|
+
};
|
|
34792
|
+
const complete = (version3) => {
|
|
34793
|
+
if (watermarkKey && seqBefore !== void 0 && report.failed === 0) store.setMeta?.(watermarkKey, JSON.stringify({ seq: seqBefore, version: version3 }));
|
|
34794
|
+
};
|
|
34795
|
+
{
|
|
34796
|
+
for (const node2 of scan2()) {
|
|
34679
34797
|
report.scanned++;
|
|
34680
34798
|
if (!eligibleForEmbedding(store, node2)) {
|
|
34681
|
-
clearWithdrawnVector(store, node2.id);
|
|
34799
|
+
if (node2.embeddingDim > 0 || node2.attrs["embeddingVersion"] !== void 0) clearWithdrawnVector(store, node2.id);
|
|
34682
34800
|
continue;
|
|
34683
34801
|
}
|
|
34684
34802
|
const existingVersion = node2.attrs["embeddingVersion"] ?? null;
|
|
@@ -34693,10 +34811,18 @@ async function embedNodesByLabels(store, labels, opts = {}) {
|
|
|
34693
34811
|
}
|
|
34694
34812
|
}
|
|
34695
34813
|
if (candidates.length === 0) {
|
|
34814
|
+
complete(held?.version ?? (hashOnly ? EMBEDDING_VERSION : null));
|
|
34696
34815
|
report.durationMs = Date.now() - started2;
|
|
34697
34816
|
return report;
|
|
34698
34817
|
}
|
|
34699
34818
|
const currentVersion = hashOnly ? EMBEDDING_VERSION : (await embedBatchWithModelOrHash(["probe"]))[0]?.version ?? "unknown";
|
|
34819
|
+
if (changedIds !== null && held?.version && held.version !== currentVersion) {
|
|
34820
|
+
const { incrementalKey: _incremental, ...fullOpts } = opts;
|
|
34821
|
+
return embedNodesByLabels(store, labels, fullOpts).then((full) => {
|
|
34822
|
+
if (full.failed === 0 && watermarkKey && seqBefore !== void 0) store.setMeta?.(watermarkKey, JSON.stringify({ seq: seqBefore, version: currentVersion }));
|
|
34823
|
+
return full;
|
|
34824
|
+
});
|
|
34825
|
+
}
|
|
34700
34826
|
const todo = [];
|
|
34701
34827
|
for (const { node: node2, existingVersion } of candidates) {
|
|
34702
34828
|
if (!opts.force && existingVersion === currentVersion && node2.embeddingDim > 0) {
|
|
@@ -34732,6 +34858,7 @@ async function embedNodesByLabels(store, labels, opts = {}) {
|
|
|
34732
34858
|
});
|
|
34733
34859
|
if (opts.progress) opts.progress(report.embedded, todo.length);
|
|
34734
34860
|
}
|
|
34861
|
+
complete(currentVersion);
|
|
34735
34862
|
report.durationMs = Date.now() - started2;
|
|
34736
34863
|
return report;
|
|
34737
34864
|
}
|
|
@@ -34752,7 +34879,7 @@ function findDocstring(store, nodeId) {
|
|
|
34752
34879
|
}
|
|
34753
34880
|
return null;
|
|
34754
34881
|
}
|
|
34755
|
-
var CODE_LABELS, SEMANTIC_LABELS, BATCH_SIZE, EMBED_SCAN_ATTRS;
|
|
34882
|
+
var CODE_LABELS, SEMANTIC_LABELS, BATCH_SIZE, ID_CHUNK, EMBED_SCAN_ATTRS;
|
|
34756
34883
|
var init_embed_code = __esm({
|
|
34757
34884
|
"../../packages/generalizer/src/embed-code.ts"() {
|
|
34758
34885
|
"use strict";
|
|
@@ -34761,6 +34888,7 @@ var init_embed_code = __esm({
|
|
|
34761
34888
|
CODE_LABELS = ["Function", "Method", "Class", "Const"];
|
|
34762
34889
|
SEMANTIC_LABELS = ["Problem", "RootCause", "Solution", "Pattern", "Claim"];
|
|
34763
34890
|
BATCH_SIZE = 32;
|
|
34891
|
+
ID_CHUNK = 500;
|
|
34764
34892
|
EMBED_SCAN_ATTRS = [
|
|
34765
34893
|
"cloudNodeId",
|
|
34766
34894
|
"source",
|
|
@@ -86568,6 +86696,8 @@ function createLivenessWatch(deps) {
|
|
|
86568
86696
|
// src/workspace-maintenance.ts
|
|
86569
86697
|
init_src8();
|
|
86570
86698
|
init_src5();
|
|
86699
|
+
var WM_CALIBRATION_AT_KEY = "wm-calibration-at";
|
|
86700
|
+
var WM_CALIBRATION_INTERVAL_MS = 30 * 6e4;
|
|
86571
86701
|
function runWorkspaceMaintenance(store, workspaceId2) {
|
|
86572
86702
|
const seqBefore = store.currentIngestSeq();
|
|
86573
86703
|
const report = runSemanticMaintenance(store);
|
|
@@ -86578,9 +86708,13 @@ function runWorkspaceMaintenance(store, workspaceId2) {
|
|
|
86578
86708
|
}
|
|
86579
86709
|
let calibration = null;
|
|
86580
86710
|
const calibrationStarted = Date.now();
|
|
86581
|
-
|
|
86582
|
-
|
|
86583
|
-
|
|
86711
|
+
const lastCalibration = Number(store.getMeta?.(WM_CALIBRATION_AT_KEY) ?? 0);
|
|
86712
|
+
if (!(calibrationStarted - lastCalibration < WM_CALIBRATION_INTERVAL_MS)) {
|
|
86713
|
+
try {
|
|
86714
|
+
calibration = wmCalibrationCells(store);
|
|
86715
|
+
store.setMeta?.(WM_CALIBRATION_AT_KEY, String(calibrationStarted));
|
|
86716
|
+
} catch {
|
|
86717
|
+
}
|
|
86584
86718
|
}
|
|
86585
86719
|
return {
|
|
86586
86720
|
report,
|
|
@@ -86711,7 +86845,7 @@ function createWatchBreaker(deps) {
|
|
|
86711
86845
|
}
|
|
86712
86846
|
|
|
86713
86847
|
// src/engine.ts
|
|
86714
|
-
var DAEMON_VERSION = true ? "2.0.22-dev.
|
|
86848
|
+
var DAEMON_VERSION = true ? "2.0.22-dev.4629" : "2.0.0-alpha.0";
|
|
86715
86849
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
86716
86850
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
86717
86851
|
var GIT_OP_MUTE_MS = 4e3;
|
package/generalize-worker.mjs
CHANGED
|
@@ -15753,6 +15753,12 @@ function changeLogCovers(db, sinceSeq) {
|
|
|
15753
15753
|
const prunedTo = Number(db.prepare("SELECT value FROM store_meta WHERE key = ?").get(PRUNED_TO_KEY)?.["value"] ?? NaN);
|
|
15754
15754
|
return Number.isFinite(prunedTo) && sinceSeq >= prunedTo;
|
|
15755
15755
|
}
|
|
15756
|
+
function readChangedNodeIds(db, sinceSeq, labels) {
|
|
15757
|
+
if (!changeLogCovers(db, sinceSeq)) return null;
|
|
15758
|
+
if (!labels.length) return [];
|
|
15759
|
+
const rows = db.prepare(`SELECT DISTINCT id FROM change_log WHERE change_seq > ? AND kind = 'node' AND label IN (${labels.map(() => "?").join(",")})`).all(sinceSeq, ...labels);
|
|
15760
|
+
return rows.map((r) => r.id);
|
|
15761
|
+
}
|
|
15756
15762
|
function readLineageChangedFiles(db, sinceSeq) {
|
|
15757
15763
|
if (!changeLogCovers(db, sinceSeq)) return null;
|
|
15758
15764
|
const rows = db.prepare(LINEAGE_CHANGED_FILES_SQL).all({ s: sinceSeq });
|
|
@@ -15960,6 +15966,7 @@ var DEMAND_HOT = Math.log1p(10);
|
|
|
15960
15966
|
var DEMAND_WARM = Math.log1p(5);
|
|
15961
15967
|
|
|
15962
15968
|
// ../../packages/local-graph/src/node-select.ts
|
|
15969
|
+
var SELECT_INDEXES = ["nodes_live_local_community", "nodes_live_fold_candidate"];
|
|
15963
15970
|
var EMBEDDING_DIM_SQL = "(CASE WHEN length(embedding_blob) >= 4 THEN length(embedding_blob) / 4 ELSE COALESCE(json_array_length(embedding_json), 0) END)";
|
|
15964
15971
|
var KEY = /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
15965
15972
|
var COLUMNS = /* @__PURE__ */ new Set([
|
|
@@ -15975,6 +15982,10 @@ function path(key) {
|
|
|
15975
15982
|
if (!KEY.test(key)) throw new Error(`selectNodes: bad attr key ${key}`);
|
|
15976
15983
|
return `'$.${key}'`;
|
|
15977
15984
|
}
|
|
15985
|
+
function selectIndex(i) {
|
|
15986
|
+
if (!SELECT_INDEXES.includes(i)) throw new Error(`selectNodes: bad index ${i}`);
|
|
15987
|
+
return i;
|
|
15988
|
+
}
|
|
15978
15989
|
function column(c) {
|
|
15979
15990
|
if (!COLUMNS.has(c)) throw new Error(`selectNodes: bad column ${c}`);
|
|
15980
15991
|
return c;
|
|
@@ -15990,6 +16001,12 @@ function compileNodeWhere(q) {
|
|
|
15990
16001
|
} else if ("idPrefix" in w) {
|
|
15991
16002
|
conds.push("substr(id, 1, ?) = ?");
|
|
15992
16003
|
params.push(w.idPrefix.length, w.idPrefix);
|
|
16004
|
+
} else if ("idIn" in w) {
|
|
16005
|
+
if (w.idIn.length === 0) conds.push("0");
|
|
16006
|
+
else {
|
|
16007
|
+
conds.push(`id IN (${w.idIn.map(() => "?").join(", ")})`);
|
|
16008
|
+
params.push(...w.idIn);
|
|
16009
|
+
}
|
|
15993
16010
|
} else if ("descriptionIn" in w) {
|
|
15994
16011
|
if (w.descriptionIn.length === 0) conds.push("0");
|
|
15995
16012
|
else {
|
|
@@ -16046,7 +16063,7 @@ function compileNodeSelect(q) {
|
|
|
16046
16063
|
}
|
|
16047
16064
|
const orderParams = !q.orderBy && q.labels.length > 1 ? [...q.labels] : [];
|
|
16048
16065
|
const limit = q.limit !== void 0 ? ` LIMIT ${Math.max(0, Math.floor(q.limit))}` : "";
|
|
16049
|
-
const sql = `SELECT id, label, description, created_at, last_updated_at, page_rank, cumulative_hits, extraction_confidence, extraction_source, community, created_at_seq, last_reinforced_at_seq, valid_to, logical_id, version, ${EMBEDDING_DIM_SQL} AS embedding_dim${q.withEmbedding ? ", embedding_blob, embedding_json" : ""}${attrCols} FROM nodes WHERE ${where} ORDER BY ${order}${limit}`;
|
|
16066
|
+
const sql = `SELECT id, label, description, created_at, last_updated_at, page_rank, cumulative_hits, extraction_confidence, extraction_source, community, created_at_seq, last_reinforced_at_seq, valid_to, logical_id, version, ${EMBEDDING_DIM_SQL} AS embedding_dim${q.withEmbedding ? ", embedding_blob, embedding_json" : ""}${attrCols} FROM nodes${q.indexedBy ? ` INDEXED BY ${selectIndex(q.indexedBy)}` : ""} WHERE ${where} ORDER BY ${order}${limit}`;
|
|
16050
16067
|
return { sql, params: [...params, ...orderParams] };
|
|
16051
16068
|
}
|
|
16052
16069
|
function decodeAttr(value, type) {
|
|
@@ -16244,6 +16261,19 @@ var TEMPORAL_INDEX_SQL = `
|
|
|
16244
16261
|
CREATE INDEX IF NOT EXISTS nodes_live ON nodes(label, valid_to);
|
|
16245
16262
|
CREATE INDEX IF NOT EXISTS nodes_live_count ON nodes(valid_to);
|
|
16246
16263
|
CREATE INDEX IF NOT EXISTS nodes_live_recent ON nodes(label, last_updated_at DESC) WHERE valid_to IS NULL;
|
|
16264
|
+
-- "Anything created since the watermark?" guards (the fold, regression and
|
|
16265
|
+
-- canonical-bind sweeps run one per session boundary). Without it the planner
|
|
16266
|
+
-- walks nodes_live and reads every live row of the label to test created_at:
|
|
16267
|
+
-- 56 MB per guard on a 1.1 GB store, to learn there was nothing to do. valid_to
|
|
16268
|
+
-- is a key column so the planner prefers this over nodes_live (one more term).
|
|
16269
|
+
CREATE INDEX IF NOT EXISTS nodes_live_created ON nodes(label, valid_to, created_at) WHERE valid_to IS NULL;
|
|
16270
|
+
-- Community members (the skills pull reads them twice per session boundary):
|
|
16271
|
+
-- ~15% of semantic nodes carry a localCommunity, and without this every live
|
|
16272
|
+
-- semantic row was read to find them (168 MB \u2192 18 MB per read).
|
|
16273
|
+
CREATE INDEX IF NOT EXISTS nodes_live_local_community ON nodes(label, valid_to, json_extract(attrs_json, '$.localCommunity')) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.localCommunity') IS NOT NULL;
|
|
16274
|
+
-- Problems parked for the fold judge (read every settle boundary): ~1 in 5 open
|
|
16275
|
+
-- Problems; without it every live Problem was read to find them (56 MB).
|
|
16276
|
+
CREATE INDEX IF NOT EXISTS nodes_live_fold_candidate ON nodes(label, valid_to) WHERE valid_to IS NULL AND json_type(attrs_json, '$.foldCandidate') IS NOT NULL;
|
|
16247
16277
|
CREATE INDEX IF NOT EXISTS nodes_session_evidence ON nodes(id) WHERE ${SESSION_EVIDENCE_PREDICATE};
|
|
16248
16278
|
CREATE INDEX IF NOT EXISTS edges_session_evidence ON edges(id) WHERE ${SESSION_EVIDENCE_PREDICATE};
|
|
16249
16279
|
-- Covering + partial index for labelFingerprint over the instance labels: the
|
|
@@ -16258,6 +16288,14 @@ CREATE INDEX IF NOT EXISTS nodes_instance_fingerprint_v2 ON nodes(label, last_up
|
|
|
16258
16288
|
CREATE INDEX IF NOT EXISTS nodes_live_page_rank ON nodes(valid_to, page_rank);
|
|
16259
16289
|
CREATE INDEX IF NOT EXISTS nodes_logical ON nodes(logical_id, version);
|
|
16260
16290
|
CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
|
|
16291
|
+
-- Newest live edges first, so a "recent N matching edges" read stops early instead
|
|
16292
|
+
-- of matching and sorting every live edge (the hourly liveness check: 163 MB \u2192
|
|
16293
|
+
-- 69 MB). Named by recentEdgeAttrCoverage; the planner keeps edges_live otherwise.
|
|
16294
|
+
CREATE INDEX IF NOT EXISTS edges_live_created ON edges(created_at) WHERE valid_to IS NULL;
|
|
16295
|
+
-- Live prior-tag edges by recency: the liveness corroboration check reads the
|
|
16296
|
+
-- newest 100 of ~300, and walking all live edges newest-first to find them read
|
|
16297
|
+
-- 69 MB. Its predicate is the one recentEdgeAttrCoverage uses for that marker.
|
|
16298
|
+
CREATE INDEX IF NOT EXISTS edges_live_prior_tag ON edges(created_at) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1;
|
|
16261
16299
|
-- Expression index on the per-node relPath (stored in attrs_json) so the
|
|
16262
16300
|
-- incremental reindex can fetch just the changed files' symbols instead of
|
|
16263
16301
|
-- scanning every versioned node. Partial: only live rows are ever queried.
|
|
@@ -16348,6 +16386,7 @@ function rowToEdge(r) {
|
|
|
16348
16386
|
}
|
|
16349
16387
|
var FINGERPRINT_INDEXED_LABELS = ["Problem", "Vulnerability", "Solution", "RootCause"];
|
|
16350
16388
|
var NODE_LABELS_CHUNK = 256;
|
|
16389
|
+
var PRIOR_TAG_MARKER = '"priorTag":true';
|
|
16351
16390
|
var SqliteGraphStore = class {
|
|
16352
16391
|
db;
|
|
16353
16392
|
// Typed edge lookups build their SQL from the number of types asked for, and
|
|
@@ -16954,6 +16993,27 @@ var SqliteGraphStore = class {
|
|
|
16954
16993
|
cloud: r.cloud === 1
|
|
16955
16994
|
}));
|
|
16956
16995
|
}
|
|
16996
|
+
findNodeStampsByLabelAttrs(label, attrKeys) {
|
|
16997
|
+
for (const k of attrKeys) if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) throw new Error(`findNodeStampsByLabelAttrs: bad attr key ${k}`);
|
|
16998
|
+
const keys = [...new Set(attrKeys)];
|
|
16999
|
+
const rows = this.db.prepare(
|
|
17000
|
+
`SELECT id, created_at, created_at_seq,
|
|
17001
|
+
${keys.map((k, i) => `json_type(attrs_json, '$.${k}') IS NOT NULL AS h${i}`).join(", ")}${keys.length ? "," : ""}
|
|
17002
|
+
COALESCE(json_extract(attrs_json, '$.source') = 'cloud', 0) AS cloud
|
|
17003
|
+
FROM nodes WHERE label = ? AND valid_to IS NULL`
|
|
17004
|
+
).all(label);
|
|
17005
|
+
const out = new Map(keys.map((k) => [k, []]));
|
|
17006
|
+
for (const r of rows) {
|
|
17007
|
+
keys.forEach((k, i) => out.get(k).push({
|
|
17008
|
+
id: r.id,
|
|
17009
|
+
createdAt: r.created_at,
|
|
17010
|
+
...r.created_at_seq != null ? { createdAtSeq: r.created_at_seq } : {},
|
|
17011
|
+
has: r[`h${i}`] === 1,
|
|
17012
|
+
cloud: r.cloud === 1
|
|
17013
|
+
}));
|
|
17014
|
+
}
|
|
17015
|
+
return out;
|
|
17016
|
+
}
|
|
16957
17017
|
findNodeAttrsByLabel(label) {
|
|
16958
17018
|
const rows = this.stmts.attrsByLabel.all(label);
|
|
16959
17019
|
return rows.map((r) => ({
|
|
@@ -17195,6 +17255,9 @@ var SqliteGraphStore = class {
|
|
|
17195
17255
|
lineageChangedFiles(sinceSeq) {
|
|
17196
17256
|
return readLineageChangedFiles(this.db, sinceSeq);
|
|
17197
17257
|
}
|
|
17258
|
+
changedNodeIds(sinceSeq, labels) {
|
|
17259
|
+
return readChangedNodeIds(this.db, sinceSeq, labels);
|
|
17260
|
+
}
|
|
17198
17261
|
pruneChangeLog() {
|
|
17199
17262
|
return pruneChangeLog(this.db);
|
|
17200
17263
|
}
|
|
@@ -17385,11 +17448,26 @@ var SqliteGraphStore = class {
|
|
|
17385
17448
|
).get(...edgeTypes, label, cloudOnly ? 1 : 0);
|
|
17386
17449
|
return { count: Number(r.count), total: Number(r.total) };
|
|
17387
17450
|
}
|
|
17451
|
+
liveEdgeTargets(edgeTypes) {
|
|
17452
|
+
if (edgeTypes.length === 0) return [];
|
|
17453
|
+
const rows = this.db.prepare(`SELECT DISTINCT to_id FROM edges INDEXED BY edges_type WHERE type IN (${edgeTypes.map(() => "?").join(",")}) AND valid_to IS NULL`).all(...edgeTypes);
|
|
17454
|
+
return rows.map((r) => r.to_id);
|
|
17455
|
+
}
|
|
17388
17456
|
recentEdgeAttrCoverage(marker, attr, limit) {
|
|
17457
|
+
if (marker === PRIOR_TAG_MARKER) {
|
|
17458
|
+
const r2 = this.db.prepare(
|
|
17459
|
+
`SELECT COUNT(*) AS total,
|
|
17460
|
+
COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
|
|
17461
|
+
FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_prior_tag
|
|
17462
|
+
WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1
|
|
17463
|
+
ORDER BY created_at DESC LIMIT ?)`
|
|
17464
|
+
).get(attr, limit);
|
|
17465
|
+
return { count: Number(r2.count), total: Number(r2.total) };
|
|
17466
|
+
}
|
|
17389
17467
|
const r = this.db.prepare(
|
|
17390
17468
|
`SELECT COUNT(*) AS total,
|
|
17391
17469
|
COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
|
|
17392
|
-
FROM (SELECT attrs_json FROM edges
|
|
17470
|
+
FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_created
|
|
17393
17471
|
WHERE valid_to IS NULL AND attrs_json LIKE ?
|
|
17394
17472
|
ORDER BY created_at DESC LIMIT ?)`
|
|
17395
17473
|
).get(attr, `%${marker}%`, limit);
|
|
@@ -17537,8 +17615,9 @@ var SqliteGraphStore = class {
|
|
|
17537
17615
|
* so it must be a plain identifier. */
|
|
17538
17616
|
nodesAsOfWhereTrue(t, attr) {
|
|
17539
17617
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attr)) throw new Error(`nodesAsOfWhereTrue: bad attr ${JSON.stringify(attr)}`);
|
|
17618
|
+
const indexed = attr === "revisit" ? " INDEXED BY nodes_revisit_true" : "";
|
|
17540
17619
|
const rows = this.db.prepare(
|
|
17541
|
-
`SELECT * FROM nodes WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)
|
|
17620
|
+
`SELECT * FROM nodes${indexed} WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)
|
|
17542
17621
|
AND json_type(attrs_json, '$.${attr}') = 'true'
|
|
17543
17622
|
ORDER BY rowid`
|
|
17544
17623
|
).all({ t });
|
package/package.json
CHANGED
package/pass-worker.mjs
CHANGED
|
@@ -26185,6 +26185,12 @@ function changeLogCovers(db, sinceSeq) {
|
|
|
26185
26185
|
const prunedTo = Number(db.prepare("SELECT value FROM store_meta WHERE key = ?").get(PRUNED_TO_KEY)?.["value"] ?? NaN);
|
|
26186
26186
|
return Number.isFinite(prunedTo) && sinceSeq >= prunedTo;
|
|
26187
26187
|
}
|
|
26188
|
+
function readChangedNodeIds(db, sinceSeq, labels) {
|
|
26189
|
+
if (!changeLogCovers(db, sinceSeq)) return null;
|
|
26190
|
+
if (!labels.length) return [];
|
|
26191
|
+
const rows = db.prepare(`SELECT DISTINCT id FROM change_log WHERE change_seq > ? AND kind = 'node' AND label IN (${labels.map(() => "?").join(",")})`).all(sinceSeq, ...labels);
|
|
26192
|
+
return rows.map((r) => r.id);
|
|
26193
|
+
}
|
|
26188
26194
|
function readLineageChangedFiles(db, sinceSeq) {
|
|
26189
26195
|
if (!changeLogCovers(db, sinceSeq)) return null;
|
|
26190
26196
|
const rows = db.prepare(LINEAGE_CHANGED_FILES_SQL).all({ s: sinceSeq });
|
|
@@ -26828,6 +26834,7 @@ function pagerankLocal(input) {
|
|
|
26828
26834
|
}
|
|
26829
26835
|
|
|
26830
26836
|
// ../../packages/local-graph/src/node-select.ts
|
|
26837
|
+
var SELECT_INDEXES = ["nodes_live_local_community", "nodes_live_fold_candidate"];
|
|
26831
26838
|
var EMBEDDING_DIM_SQL = "(CASE WHEN length(embedding_blob) >= 4 THEN length(embedding_blob) / 4 ELSE COALESCE(json_array_length(embedding_json), 0) END)";
|
|
26832
26839
|
var KEY = /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
26833
26840
|
var COLUMNS = /* @__PURE__ */ new Set([
|
|
@@ -26843,6 +26850,10 @@ function path(key) {
|
|
|
26843
26850
|
if (!KEY.test(key)) throw new Error(`selectNodes: bad attr key ${key}`);
|
|
26844
26851
|
return `'$.${key}'`;
|
|
26845
26852
|
}
|
|
26853
|
+
function selectIndex(i2) {
|
|
26854
|
+
if (!SELECT_INDEXES.includes(i2)) throw new Error(`selectNodes: bad index ${i2}`);
|
|
26855
|
+
return i2;
|
|
26856
|
+
}
|
|
26846
26857
|
function column(c) {
|
|
26847
26858
|
if (!COLUMNS.has(c)) throw new Error(`selectNodes: bad column ${c}`);
|
|
26848
26859
|
return c;
|
|
@@ -26858,6 +26869,12 @@ function compileNodeWhere(q) {
|
|
|
26858
26869
|
} else if ("idPrefix" in w) {
|
|
26859
26870
|
conds.push("substr(id, 1, ?) = ?");
|
|
26860
26871
|
params.push(w.idPrefix.length, w.idPrefix);
|
|
26872
|
+
} else if ("idIn" in w) {
|
|
26873
|
+
if (w.idIn.length === 0) conds.push("0");
|
|
26874
|
+
else {
|
|
26875
|
+
conds.push(`id IN (${w.idIn.map(() => "?").join(", ")})`);
|
|
26876
|
+
params.push(...w.idIn);
|
|
26877
|
+
}
|
|
26861
26878
|
} else if ("descriptionIn" in w) {
|
|
26862
26879
|
if (w.descriptionIn.length === 0) conds.push("0");
|
|
26863
26880
|
else {
|
|
@@ -26914,7 +26931,7 @@ function compileNodeSelect(q) {
|
|
|
26914
26931
|
}
|
|
26915
26932
|
const orderParams = !q.orderBy && q.labels.length > 1 ? [...q.labels] : [];
|
|
26916
26933
|
const limit = q.limit !== void 0 ? ` LIMIT ${Math.max(0, Math.floor(q.limit))}` : "";
|
|
26917
|
-
const sql = `SELECT id, label, description, created_at, last_updated_at, page_rank, cumulative_hits, extraction_confidence, extraction_source, community, created_at_seq, last_reinforced_at_seq, valid_to, logical_id, version, ${EMBEDDING_DIM_SQL} AS embedding_dim${q.withEmbedding ? ", embedding_blob, embedding_json" : ""}${attrCols} FROM nodes WHERE ${where} ORDER BY ${order}${limit}`;
|
|
26934
|
+
const sql = `SELECT id, label, description, created_at, last_updated_at, page_rank, cumulative_hits, extraction_confidence, extraction_source, community, created_at_seq, last_reinforced_at_seq, valid_to, logical_id, version, ${EMBEDDING_DIM_SQL} AS embedding_dim${q.withEmbedding ? ", embedding_blob, embedding_json" : ""}${attrCols} FROM nodes${q.indexedBy ? ` INDEXED BY ${selectIndex(q.indexedBy)}` : ""} WHERE ${where} ORDER BY ${order}${limit}`;
|
|
26918
26935
|
return { sql, params: [...params, ...orderParams] };
|
|
26919
26936
|
}
|
|
26920
26937
|
function decodeAttr(value, type) {
|
|
@@ -27112,6 +27129,19 @@ var TEMPORAL_INDEX_SQL = `
|
|
|
27112
27129
|
CREATE INDEX IF NOT EXISTS nodes_live ON nodes(label, valid_to);
|
|
27113
27130
|
CREATE INDEX IF NOT EXISTS nodes_live_count ON nodes(valid_to);
|
|
27114
27131
|
CREATE INDEX IF NOT EXISTS nodes_live_recent ON nodes(label, last_updated_at DESC) WHERE valid_to IS NULL;
|
|
27132
|
+
-- "Anything created since the watermark?" guards (the fold, regression and
|
|
27133
|
+
-- canonical-bind sweeps run one per session boundary). Without it the planner
|
|
27134
|
+
-- walks nodes_live and reads every live row of the label to test created_at:
|
|
27135
|
+
-- 56 MB per guard on a 1.1 GB store, to learn there was nothing to do. valid_to
|
|
27136
|
+
-- is a key column so the planner prefers this over nodes_live (one more term).
|
|
27137
|
+
CREATE INDEX IF NOT EXISTS nodes_live_created ON nodes(label, valid_to, created_at) WHERE valid_to IS NULL;
|
|
27138
|
+
-- Community members (the skills pull reads them twice per session boundary):
|
|
27139
|
+
-- ~15% of semantic nodes carry a localCommunity, and without this every live
|
|
27140
|
+
-- semantic row was read to find them (168 MB \u2192 18 MB per read).
|
|
27141
|
+
CREATE INDEX IF NOT EXISTS nodes_live_local_community ON nodes(label, valid_to, json_extract(attrs_json, '$.localCommunity')) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.localCommunity') IS NOT NULL;
|
|
27142
|
+
-- Problems parked for the fold judge (read every settle boundary): ~1 in 5 open
|
|
27143
|
+
-- Problems; without it every live Problem was read to find them (56 MB).
|
|
27144
|
+
CREATE INDEX IF NOT EXISTS nodes_live_fold_candidate ON nodes(label, valid_to) WHERE valid_to IS NULL AND json_type(attrs_json, '$.foldCandidate') IS NOT NULL;
|
|
27115
27145
|
CREATE INDEX IF NOT EXISTS nodes_session_evidence ON nodes(id) WHERE ${SESSION_EVIDENCE_PREDICATE};
|
|
27116
27146
|
CREATE INDEX IF NOT EXISTS edges_session_evidence ON edges(id) WHERE ${SESSION_EVIDENCE_PREDICATE};
|
|
27117
27147
|
-- Covering + partial index for labelFingerprint over the instance labels: the
|
|
@@ -27126,6 +27156,14 @@ CREATE INDEX IF NOT EXISTS nodes_instance_fingerprint_v2 ON nodes(label, last_up
|
|
|
27126
27156
|
CREATE INDEX IF NOT EXISTS nodes_live_page_rank ON nodes(valid_to, page_rank);
|
|
27127
27157
|
CREATE INDEX IF NOT EXISTS nodes_logical ON nodes(logical_id, version);
|
|
27128
27158
|
CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
|
|
27159
|
+
-- Newest live edges first, so a "recent N matching edges" read stops early instead
|
|
27160
|
+
-- of matching and sorting every live edge (the hourly liveness check: 163 MB \u2192
|
|
27161
|
+
-- 69 MB). Named by recentEdgeAttrCoverage; the planner keeps edges_live otherwise.
|
|
27162
|
+
CREATE INDEX IF NOT EXISTS edges_live_created ON edges(created_at) WHERE valid_to IS NULL;
|
|
27163
|
+
-- Live prior-tag edges by recency: the liveness corroboration check reads the
|
|
27164
|
+
-- newest 100 of ~300, and walking all live edges newest-first to find them read
|
|
27165
|
+
-- 69 MB. Its predicate is the one recentEdgeAttrCoverage uses for that marker.
|
|
27166
|
+
CREATE INDEX IF NOT EXISTS edges_live_prior_tag ON edges(created_at) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1;
|
|
27129
27167
|
-- Expression index on the per-node relPath (stored in attrs_json) so the
|
|
27130
27168
|
-- incremental reindex can fetch just the changed files' symbols instead of
|
|
27131
27169
|
-- scanning every versioned node. Partial: only live rows are ever queried.
|
|
@@ -27216,6 +27254,7 @@ function rowToEdge(r) {
|
|
|
27216
27254
|
}
|
|
27217
27255
|
var FINGERPRINT_INDEXED_LABELS = ["Problem", "Vulnerability", "Solution", "RootCause"];
|
|
27218
27256
|
var NODE_LABELS_CHUNK = 256;
|
|
27257
|
+
var PRIOR_TAG_MARKER = '"priorTag":true';
|
|
27219
27258
|
var SqliteGraphStore = class {
|
|
27220
27259
|
db;
|
|
27221
27260
|
// Typed edge lookups build their SQL from the number of types asked for, and
|
|
@@ -27822,6 +27861,27 @@ var SqliteGraphStore = class {
|
|
|
27822
27861
|
cloud: r.cloud === 1
|
|
27823
27862
|
}));
|
|
27824
27863
|
}
|
|
27864
|
+
findNodeStampsByLabelAttrs(label, attrKeys) {
|
|
27865
|
+
for (const k of attrKeys) if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) throw new Error(`findNodeStampsByLabelAttrs: bad attr key ${k}`);
|
|
27866
|
+
const keys = [...new Set(attrKeys)];
|
|
27867
|
+
const rows = this.db.prepare(
|
|
27868
|
+
`SELECT id, created_at, created_at_seq,
|
|
27869
|
+
${keys.map((k, i2) => `json_type(attrs_json, '$.${k}') IS NOT NULL AS h${i2}`).join(", ")}${keys.length ? "," : ""}
|
|
27870
|
+
COALESCE(json_extract(attrs_json, '$.source') = 'cloud', 0) AS cloud
|
|
27871
|
+
FROM nodes WHERE label = ? AND valid_to IS NULL`
|
|
27872
|
+
).all(label);
|
|
27873
|
+
const out2 = new Map(keys.map((k) => [k, []]));
|
|
27874
|
+
for (const r of rows) {
|
|
27875
|
+
keys.forEach((k, i2) => out2.get(k).push({
|
|
27876
|
+
id: r.id,
|
|
27877
|
+
createdAt: r.created_at,
|
|
27878
|
+
...r.created_at_seq != null ? { createdAtSeq: r.created_at_seq } : {},
|
|
27879
|
+
has: r[`h${i2}`] === 1,
|
|
27880
|
+
cloud: r.cloud === 1
|
|
27881
|
+
}));
|
|
27882
|
+
}
|
|
27883
|
+
return out2;
|
|
27884
|
+
}
|
|
27825
27885
|
findNodeAttrsByLabel(label) {
|
|
27826
27886
|
const rows = this.stmts.attrsByLabel.all(label);
|
|
27827
27887
|
return rows.map((r) => ({
|
|
@@ -28063,6 +28123,9 @@ var SqliteGraphStore = class {
|
|
|
28063
28123
|
lineageChangedFiles(sinceSeq) {
|
|
28064
28124
|
return readLineageChangedFiles(this.db, sinceSeq);
|
|
28065
28125
|
}
|
|
28126
|
+
changedNodeIds(sinceSeq, labels) {
|
|
28127
|
+
return readChangedNodeIds(this.db, sinceSeq, labels);
|
|
28128
|
+
}
|
|
28066
28129
|
pruneChangeLog() {
|
|
28067
28130
|
return pruneChangeLog(this.db);
|
|
28068
28131
|
}
|
|
@@ -28253,11 +28316,26 @@ var SqliteGraphStore = class {
|
|
|
28253
28316
|
).get(...edgeTypes, label, cloudOnly ? 1 : 0);
|
|
28254
28317
|
return { count: Number(r.count), total: Number(r.total) };
|
|
28255
28318
|
}
|
|
28319
|
+
liveEdgeTargets(edgeTypes) {
|
|
28320
|
+
if (edgeTypes.length === 0) return [];
|
|
28321
|
+
const rows = this.db.prepare(`SELECT DISTINCT to_id FROM edges INDEXED BY edges_type WHERE type IN (${edgeTypes.map(() => "?").join(",")}) AND valid_to IS NULL`).all(...edgeTypes);
|
|
28322
|
+
return rows.map((r) => r.to_id);
|
|
28323
|
+
}
|
|
28256
28324
|
recentEdgeAttrCoverage(marker, attr, limit) {
|
|
28325
|
+
if (marker === PRIOR_TAG_MARKER) {
|
|
28326
|
+
const r2 = this.db.prepare(
|
|
28327
|
+
`SELECT COUNT(*) AS total,
|
|
28328
|
+
COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
|
|
28329
|
+
FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_prior_tag
|
|
28330
|
+
WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1
|
|
28331
|
+
ORDER BY created_at DESC LIMIT ?)`
|
|
28332
|
+
).get(attr, limit);
|
|
28333
|
+
return { count: Number(r2.count), total: Number(r2.total) };
|
|
28334
|
+
}
|
|
28257
28335
|
const r = this.db.prepare(
|
|
28258
28336
|
`SELECT COUNT(*) AS total,
|
|
28259
28337
|
COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
|
|
28260
|
-
FROM (SELECT attrs_json FROM edges
|
|
28338
|
+
FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_created
|
|
28261
28339
|
WHERE valid_to IS NULL AND attrs_json LIKE ?
|
|
28262
28340
|
ORDER BY created_at DESC LIMIT ?)`
|
|
28263
28341
|
).get(attr, `%${marker}%`, limit);
|
|
@@ -28405,8 +28483,9 @@ var SqliteGraphStore = class {
|
|
|
28405
28483
|
* so it must be a plain identifier. */
|
|
28406
28484
|
nodesAsOfWhereTrue(t, attr) {
|
|
28407
28485
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attr)) throw new Error(`nodesAsOfWhereTrue: bad attr ${JSON.stringify(attr)}`);
|
|
28486
|
+
const indexed = attr === "revisit" ? " INDEXED BY nodes_revisit_true" : "";
|
|
28408
28487
|
const rows = this.db.prepare(
|
|
28409
|
-
`SELECT * FROM nodes WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)
|
|
28488
|
+
`SELECT * FROM nodes${indexed} WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)
|
|
28410
28489
|
AND json_type(attrs_json, '$.${attr}') = 'true'
|
|
28411
28490
|
ORDER BY rowid`
|
|
28412
28491
|
).all({ t });
|
|
@@ -28492,19 +28571,16 @@ function conditionOf(node) {
|
|
|
28492
28571
|
}
|
|
28493
28572
|
function clearAnsweredRevisits(store2, ts) {
|
|
28494
28573
|
const report = { cleared: 0, standing: 0 };
|
|
28495
|
-
|
|
28496
|
-
|
|
28497
|
-
|
|
28498
|
-
|
|
28499
|
-
|
|
28500
|
-
|
|
28501
|
-
|
|
28502
|
-
report.standing++;
|
|
28503
|
-
continue;
|
|
28504
|
-
}
|
|
28505
|
-
clearRevisit(store2, node.id, ts);
|
|
28506
|
-
report.cleared++;
|
|
28574
|
+
const semantic = new Set(SEMANTIC_NODE_LABELS);
|
|
28575
|
+
for (const node of store2.nodesAsOfWhereTrue(ts, "revisit")) {
|
|
28576
|
+
if (!semantic.has(node.label) || node.validTo != null) continue;
|
|
28577
|
+
const condition = conditionOf(node);
|
|
28578
|
+
if (condition === void 0 || !isRevisitAnswered(store2, node, condition)) {
|
|
28579
|
+
report.standing++;
|
|
28580
|
+
continue;
|
|
28507
28581
|
}
|
|
28582
|
+
clearRevisit(store2, node.id, ts);
|
|
28583
|
+
report.cleared++;
|
|
28508
28584
|
}
|
|
28509
28585
|
return report;
|
|
28510
28586
|
}
|
|
@@ -30107,7 +30183,14 @@ var MECHANISMS = [
|
|
|
30107
30183
|
var COLUMN_INPUTS = {
|
|
30108
30184
|
__createdAtSeq: (n) => n.createdAtSeq !== void 0 && n.createdAtSeq !== null
|
|
30109
30185
|
};
|
|
30110
|
-
function evaluateFed(store2, d) {
|
|
30186
|
+
function evaluateFed(store2, d, stamps) {
|
|
30187
|
+
const incomingRows = d.fedIncoming && store2.liveEdgeTargets ? stamps?.(d.fedIncoming.label, "source") : void 0;
|
|
30188
|
+
if (d.fedIncoming && incomingRows) {
|
|
30189
|
+
const targets = new Set(store2.liveEdgeTargets(d.fedIncoming.edgeTypes));
|
|
30190
|
+
const rows = d.fedIncoming.cloudOnly ? incomingRows.filter((r) => r.cloud) : incomingRows;
|
|
30191
|
+
const count2 = rows.filter((r) => targets.has(r.id)).length;
|
|
30192
|
+
return { count: count2, total: rows.length, fraction: rows.length === 0 ? 0 : count2 / rows.length };
|
|
30193
|
+
}
|
|
30111
30194
|
if (d.fedIncoming) {
|
|
30112
30195
|
const { count: count2, total } = store2.incomingEdgeCoverage?.(
|
|
30113
30196
|
d.fedIncoming.label,
|
|
@@ -30127,7 +30210,7 @@ function evaluateFed(store2, d) {
|
|
|
30127
30210
|
if (!d.fed) return { count: 0, total: 0, fraction: 0 };
|
|
30128
30211
|
const column2 = COLUMN_INPUTS[d.fed.attr];
|
|
30129
30212
|
const fed = d.fed;
|
|
30130
|
-
const all = fed.labels.flatMap((label) => store2.findNodeStampsByLabel ? store2.findNodeStampsByLabel(label, fed.attr) : store2.findNodeAttrsByLabel(label));
|
|
30213
|
+
const all = fed.labels.flatMap((label) => stamps?.(label, fed.attr) ?? (store2.findNodeStampsByLabel ? store2.findNodeStampsByLabel(label, fed.attr) : store2.findNodeAttrsByLabel(label)));
|
|
30131
30214
|
const isCloudMirror = (n) => n.cloud ?? n.attrs?.["source"] === "cloud";
|
|
30132
30215
|
const nodes = fed.localOnly ? all.filter((n) => !isCloudMirror(n)) : all;
|
|
30133
30216
|
const has = (n) => column2 ? column2(n) : n.has ?? n.attrs?.[fed.attr] !== void 0;
|
|
@@ -30150,8 +30233,16 @@ function evaluateMechanisms(store2, invocations = /* @__PURE__ */ new Map(), mec
|
|
|
30150
30233
|
if (!counts.has(label)) counts.set(label, store2.countNodesByLabel(label));
|
|
30151
30234
|
return counts.get(label);
|
|
30152
30235
|
};
|
|
30236
|
+
const wanted = /* @__PURE__ */ new Map();
|
|
30237
|
+
for (const d of mechanisms) for (const l of d.fed?.labels ?? []) wanted.set(l, (wanted.get(l) ?? /* @__PURE__ */ new Set()).add(d.fed.attr));
|
|
30238
|
+
for (const d of mechanisms) if (d.fedIncoming) wanted.set(d.fedIncoming.label, (wanted.get(d.fedIncoming.label) ?? /* @__PURE__ */ new Set()).add("source"));
|
|
30239
|
+
const byLabel = /* @__PURE__ */ new Map();
|
|
30240
|
+
const stamps = store2.findNodeStampsByLabelAttrs ? (label, attr) => {
|
|
30241
|
+
if (!byLabel.has(label)) byLabel.set(label, store2.findNodeStampsByLabelAttrs(label, [...wanted.get(label) ?? [attr]]));
|
|
30242
|
+
return byLabel.get(label).get(attr);
|
|
30243
|
+
} : void 0;
|
|
30153
30244
|
return mechanisms.map((d) => {
|
|
30154
|
-
const fed = evaluateFed(store2, d);
|
|
30245
|
+
const fed = evaluateFed(store2, d, stamps);
|
|
30155
30246
|
const inv = invocations.get(d.pass);
|
|
30156
30247
|
const effectCount = d.effectIsLevel ? Math.max(
|
|
30157
30248
|
0,
|
|
@@ -31204,6 +31295,8 @@ async function reconcileStaleFiles(store2, rootPath, workspaceId) {
|
|
|
31204
31295
|
}
|
|
31205
31296
|
|
|
31206
31297
|
// src/workspace-maintenance.ts
|
|
31298
|
+
var WM_CALIBRATION_AT_KEY = "wm-calibration-at";
|
|
31299
|
+
var WM_CALIBRATION_INTERVAL_MS = 30 * 6e4;
|
|
31207
31300
|
function runWorkspaceMaintenance(store2, workspaceId) {
|
|
31208
31301
|
const seqBefore = store2.currentIngestSeq();
|
|
31209
31302
|
const report = runSemanticMaintenance(store2);
|
|
@@ -31214,9 +31307,13 @@ function runWorkspaceMaintenance(store2, workspaceId) {
|
|
|
31214
31307
|
}
|
|
31215
31308
|
let calibration = null;
|
|
31216
31309
|
const calibrationStarted = Date.now();
|
|
31217
|
-
|
|
31218
|
-
|
|
31219
|
-
|
|
31310
|
+
const lastCalibration = Number(store2.getMeta?.(WM_CALIBRATION_AT_KEY) ?? 0);
|
|
31311
|
+
if (!(calibrationStarted - lastCalibration < WM_CALIBRATION_INTERVAL_MS)) {
|
|
31312
|
+
try {
|
|
31313
|
+
calibration = wmCalibrationCells(store2);
|
|
31314
|
+
store2.setMeta?.(WM_CALIBRATION_AT_KEY, String(calibrationStarted));
|
|
31315
|
+
} catch {
|
|
31316
|
+
}
|
|
31220
31317
|
}
|
|
31221
31318
|
return {
|
|
31222
31319
|
report,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
6116713b2c7fa083cb68622899bbfe5c62167d3c1b8d6d62ec2c81e4cc391baa .codex-plugin/plugin.json
|
|
2
2
|
a7bebae9fb01c838d6c75fc784129e28be571233fa66ff5ee8039b574f35ccf7 assets/icon.png
|
|
3
3
|
fc38b64e4df1e0b72c35764bef6c4c05430d97c9009ad0ecc8a9e75b4deab232 configure-local.mjs
|
|
4
4
|
73dc6028b3b070257c7c31f252d11e55a9e096f4aed0f187f10cb21716e1e6d7 dist/client.js
|