@inerrata-corporation/errata 2.0.22-dev.4641 → 2.0.22-dev.4652
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 +163 -14
- package/errata.mjs +164 -15
- package/generalize-worker.mjs +118 -6
- package/package.json +1 -1
- package/pass-worker.mjs +61 -5
- package/resources/context-plugin/.codex-plugin/plugin.json +1 -1
- package/resources/context-plugin/SHA256SUMS +1 -1
package/consolidate-worker.mjs
CHANGED
|
@@ -17596,8 +17596,10 @@ function column(c) {
|
|
|
17596
17596
|
function compileNodeWhere(q) {
|
|
17597
17597
|
if (q.labels.length === 0) throw new Error("selectNodes: no labels");
|
|
17598
17598
|
const params = [...q.labels];
|
|
17599
|
-
const
|
|
17600
|
-
|
|
17599
|
+
const byId = (q.where ?? []).some((w) => "idIn" in w);
|
|
17600
|
+
const unindexed = byId ? "+" : "";
|
|
17601
|
+
const conds = [`${unindexed}label IN (${q.labels.map(() => "?").join(", ")})`];
|
|
17602
|
+
if (!q.includeClosed) conds.push(`${unindexed}valid_to IS NULL`);
|
|
17601
17603
|
for (const w of q.where ?? []) {
|
|
17602
17604
|
if ("embedding" in w) {
|
|
17603
17605
|
conds.push(`${EMBEDDING_DIM_SQL} ${w.embedding === "present" ? ">" : "="} 0`);
|
|
@@ -17649,6 +17651,14 @@ function compileNodeWhere(q) {
|
|
|
17649
17651
|
function attrValueSql(p) {
|
|
17650
17652
|
return `CASE json_type(attrs_json, ${p}) WHEN 'integer' THEN CAST(json_extract(attrs_json, ${p}) AS REAL) ELSE json_extract(attrs_json, ${p}) END`;
|
|
17651
17653
|
}
|
|
17654
|
+
function nodeSelectFrom(q) {
|
|
17655
|
+
if (q.indexedBy) return `nodes INDEXED BY ${selectIndex(q.indexedBy)}`;
|
|
17656
|
+
const where = q.where ?? [];
|
|
17657
|
+
if (!q.includeClosed && where.some((w) => "descriptionIn" in w && w.descriptionIn.length > 0) && !where.some((w) => "idIn" in w)) {
|
|
17658
|
+
return "nodes INDEXED BY nodes_live_description";
|
|
17659
|
+
}
|
|
17660
|
+
return "nodes";
|
|
17661
|
+
}
|
|
17652
17662
|
function compileNodeSelect(q) {
|
|
17653
17663
|
const { where, params } = compileNodeWhere(q);
|
|
17654
17664
|
const attrs = q.attrs ?? [];
|
|
@@ -17666,7 +17676,7 @@ function compileNodeSelect(q) {
|
|
|
17666
17676
|
}
|
|
17667
17677
|
const orderParams = !q.orderBy && q.labels.length > 1 ? [...q.labels] : [];
|
|
17668
17678
|
const limit = q.limit !== void 0 ? ` LIMIT ${Math.max(0, Math.floor(q.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
|
|
17679
|
+
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 ${nodeSelectFrom(q)} WHERE ${where} ORDER BY ${order}${limit}`;
|
|
17670
17680
|
return { sql, params: [...params, ...orderParams] };
|
|
17671
17681
|
}
|
|
17672
17682
|
function decodeAttr(value, type) {
|
|
@@ -17903,6 +17913,18 @@ CREATE INDEX IF NOT EXISTS edges_live_prior_tag ON edges(created_at) WHERE valid
|
|
|
17903
17913
|
-- incremental reindex can fetch just the changed files' symbols instead of
|
|
17904
17914
|
-- scanning every versioned node. Partial: only live rows are ever queried.
|
|
17905
17915
|
CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.relPath')) WHERE valid_to IS NULL;
|
|
17916
|
+
-- Symbols by qname and doc comments by the symbol they attach to: the drain's
|
|
17917
|
+
-- symbol lexicon resolves the names in the text it ships one at a time, instead
|
|
17918
|
+
-- of reading every Function/Method/Class/Interface/Const and Comment row on each
|
|
17919
|
+
-- live push (~300 MB of a 1.1 GB store per push, 2026-10-20).
|
|
17920
|
+
CREATE INDEX IF NOT EXISTS nodes_live_qname ON nodes(json_extract(attrs_json, '$.qname')) WHERE valid_to IS NULL;
|
|
17921
|
+
CREATE INDEX IF NOT EXISTS nodes_live_attached_to ON nodes(json_extract(attrs_json, '$.attachedTo')) WHERE valid_to IS NULL AND label = 'Comment';
|
|
17922
|
+
-- The attrs the cloud drain gates every instance row on, so it reads them from
|
|
17923
|
+
-- the index alone: pulled cloud rows are most of these labels (7,105 of 7,708
|
|
17924
|
+
-- Solutions on the live store) at ~10 KB of attrs each, and five full scans for
|
|
17925
|
+
-- two attrs read ~220 MB per push to find the few local rows that can ship.
|
|
17926
|
+
-- created_at leads so the index order is findNodeFieldsByLabel's.
|
|
17927
|
+
CREATE INDEX IF NOT EXISTS nodes_live_instance_gate ON nodes(label, created_at, json_extract(attrs_json, '$.source'), json_extract(attrs_json, '$.privateFinding'), json_extract(attrs_json, '$.resolvedAs'), id) WHERE valid_to IS NULL AND label IN ('Problem', 'Vulnerability', 'Solution', 'RootCause');
|
|
17906
17928
|
-- Closed rows by relPath, for reviveReobserved (every incremental reindex): the
|
|
17907
17929
|
-- live-only index above cannot serve it, so it scanned the whole table (~275 MB
|
|
17908
17930
|
-- of a 1.1 GB store per reindex, 2026-10-20).
|
|
@@ -18269,6 +18291,36 @@ var SqliteGraphStore = class {
|
|
|
18269
18291
|
}
|
|
18270
18292
|
return out;
|
|
18271
18293
|
}
|
|
18294
|
+
firstLiveByNameOrQname(labels, name) {
|
|
18295
|
+
if (labels.length === 0) return null;
|
|
18296
|
+
const inLabels = labels.map(() => "?").join(",");
|
|
18297
|
+
const probe = (index, match) => this.db.prepare(
|
|
18298
|
+
`SELECT rowid AS rid, created_at AS at, label, description, json_extract(attrs_json, '$.qname') AS qname FROM nodes INDEXED BY ${index}
|
|
18299
|
+
WHERE ${match} = ? AND label IN (${inLabels}) AND valid_to IS NULL`
|
|
18300
|
+
).all(name, ...labels);
|
|
18301
|
+
const rank = (r) => [labels.indexOf(r.label), r.at, r.rid];
|
|
18302
|
+
const before = (a, b) => a[0] < b[0] || a[0] === b[0] && (a[1] < b[1] || a[1] === b[1] && a[2] < b[2]);
|
|
18303
|
+
let best;
|
|
18304
|
+
for (const r of [...probe("nodes_live_description", "description"), ...probe("nodes_live_qname", "json_extract(attrs_json, '$.qname')")]) {
|
|
18305
|
+
if (!best || before(rank(r), rank(best))) best = r;
|
|
18306
|
+
}
|
|
18307
|
+
return best ? { label: best.label, description: best.description, qname: typeof best.qname === "string" ? best.qname : null } : null;
|
|
18308
|
+
}
|
|
18309
|
+
instanceGateRows(label) {
|
|
18310
|
+
return this.db.prepare(
|
|
18311
|
+
`SELECT id, json_extract(attrs_json, '$.source') AS source, json_extract(attrs_json, '$.privateFinding') AS privateFinding,
|
|
18312
|
+
json_extract(attrs_json, '$.resolvedAs') AS resolvedAs
|
|
18313
|
+
FROM nodes INDEXED BY nodes_live_instance_gate
|
|
18314
|
+
WHERE label IN ('Problem', 'Vulnerability', 'Solution', 'RootCause') AND label = ? AND valid_to IS NULL
|
|
18315
|
+
ORDER BY label, created_at, rowid`
|
|
18316
|
+
).all(label);
|
|
18317
|
+
}
|
|
18318
|
+
liveCommentsAttachedTo(name) {
|
|
18319
|
+
return this.db.prepare(
|
|
18320
|
+
`SELECT json_extract(attrs_json, '$.kind') AS kind, json_extract(attrs_json, '$.text') AS text, description FROM nodes INDEXED BY nodes_live_attached_to
|
|
18321
|
+
WHERE label = 'Comment' AND valid_to IS NULL AND json_extract(attrs_json, '$.attachedTo') = ? ORDER BY created_at, rowid`
|
|
18322
|
+
).all(name);
|
|
18323
|
+
}
|
|
18272
18324
|
strandedEdges() {
|
|
18273
18325
|
return countStrandedEdges(this.db);
|
|
18274
18326
|
}
|
|
@@ -18447,7 +18499,11 @@ var SqliteGraphStore = class {
|
|
|
18447
18499
|
if (!stmt2) {
|
|
18448
18500
|
const cols = attrKeys.map((k, i) => `, ${attrValueSql(`'$.${k}'`)} AS a${i}, json_type(attrs_json, '$.${k}') AS t${i}`).join("");
|
|
18449
18501
|
stmt2 = this.db.prepare(
|
|
18450
|
-
|
|
18502
|
+
// Ordered, not left to the planner: readers take "first row wins" (the
|
|
18503
|
+
// symbol lexicon's name winner and doc pick), and the order otherwise
|
|
18504
|
+
// followed whichever partial index the planner chose. nodes_live_created
|
|
18505
|
+
// serves this order without a sort.
|
|
18506
|
+
`SELECT id, description, community, extraction_confidence${cols} FROM nodes WHERE label = ? AND valid_to IS NULL ORDER BY created_at, rowid`
|
|
18451
18507
|
);
|
|
18452
18508
|
this.fieldStmts.set(cacheKey, stmt2);
|
|
18453
18509
|
}
|
|
@@ -18473,7 +18529,7 @@ var SqliteGraphStore = class {
|
|
|
18473
18529
|
}
|
|
18474
18530
|
countNodes(q) {
|
|
18475
18531
|
const { where, params } = compileNodeWhere(q);
|
|
18476
|
-
return Number(this.db.prepare(`SELECT COUNT(*) AS n FROM
|
|
18532
|
+
return Number(this.db.prepare(`SELECT COUNT(*) AS n FROM ${nodeSelectFrom(q)} WHERE ${where}`).get(...params).n);
|
|
18477
18533
|
}
|
|
18478
18534
|
setCommunity(id, community) {
|
|
18479
18535
|
this.stmts.setCommunity.run({ id, v: community });
|
|
@@ -20893,6 +20949,62 @@ function buildSymbolLexicon(store) {
|
|
|
20893
20949
|
}
|
|
20894
20950
|
return lex;
|
|
20895
20951
|
}
|
|
20952
|
+
function lazySymbolLexicon(store) {
|
|
20953
|
+
if (!store.firstLiveByNameOrQname || !store.liveCommentsAttachedTo) return null;
|
|
20954
|
+
const labels = SYMBOL_LABELS.map(([label]) => label);
|
|
20955
|
+
const kindOf = new Map(SYMBOL_LABELS.map(([label, kind]) => [label, kind]));
|
|
20956
|
+
const members = /* @__PURE__ */ new Map();
|
|
20957
|
+
const docs = /* @__PURE__ */ new Map();
|
|
20958
|
+
const entries = /* @__PURE__ */ new Map();
|
|
20959
|
+
const member = (name) => {
|
|
20960
|
+
if (!members.has(name)) {
|
|
20961
|
+
const hit = isDistinctiveIdentifier(name) ? store.firstLiveByNameOrQname(labels, name) : null;
|
|
20962
|
+
members.set(name, hit ? { kind: kindOf.get(hit.label), description: hit.description, qname: hit.qname } : null);
|
|
20963
|
+
}
|
|
20964
|
+
return members.get(name);
|
|
20965
|
+
};
|
|
20966
|
+
const docFor = (name) => {
|
|
20967
|
+
if (!docs.has(name)) {
|
|
20968
|
+
let found;
|
|
20969
|
+
for (const c of store.liveCommentsAttachedTo(name)) {
|
|
20970
|
+
if (typeof c.kind !== "string" || !DOC_COMMENT_KINDS.has(c.kind)) continue;
|
|
20971
|
+
const text = typeof c.text === "string" ? c.text : c.description;
|
|
20972
|
+
if (!text?.trim()) continue;
|
|
20973
|
+
found = text.trim().slice(0, MAX_DOC_CHARS);
|
|
20974
|
+
break;
|
|
20975
|
+
}
|
|
20976
|
+
docs.set(name, found);
|
|
20977
|
+
}
|
|
20978
|
+
return docs.get(name);
|
|
20979
|
+
};
|
|
20980
|
+
const isKnown = (tok) => member(tok) !== null;
|
|
20981
|
+
let anySymbol;
|
|
20982
|
+
return {
|
|
20983
|
+
has: isKnown,
|
|
20984
|
+
get(name) {
|
|
20985
|
+
if (!entries.has(name)) {
|
|
20986
|
+
const m = member(name);
|
|
20987
|
+
let entry = null;
|
|
20988
|
+
if (m) {
|
|
20989
|
+
entry = { kind: m.kind };
|
|
20990
|
+
const doc = (m.description ? docFor(m.description) : void 0) ?? (m.qname ? docFor(m.qname) : void 0);
|
|
20991
|
+
for (const phrase of summaryCandidates(name, m.kind, doc)) {
|
|
20992
|
+
if (summaryRejectionReason(phrase, isKnown) === null) {
|
|
20993
|
+
entry.summary = phrase;
|
|
20994
|
+
break;
|
|
20995
|
+
}
|
|
20996
|
+
}
|
|
20997
|
+
}
|
|
20998
|
+
entries.set(name, entry);
|
|
20999
|
+
}
|
|
21000
|
+
return entries.get(name) ?? void 0;
|
|
21001
|
+
},
|
|
21002
|
+
get size() {
|
|
21003
|
+
anySymbol ??= labels.some((label) => store.countNodesByLabel(label) > 0);
|
|
21004
|
+
return anySymbol ? 1 : 0;
|
|
21005
|
+
}
|
|
21006
|
+
};
|
|
21007
|
+
}
|
|
20896
21008
|
var LEXICON_SYMBOL_LABELS = ["Function", "Method", "Class", "Interface", "Const", "Comment"];
|
|
20897
21009
|
function codeGraphKey(store) {
|
|
20898
21010
|
const files = store.labelFingerprint?.(["File"]);
|
|
@@ -20904,7 +21016,7 @@ function lexiconsFor(store) {
|
|
|
20904
21016
|
const key = codeGraphKey(store);
|
|
20905
21017
|
const hit = key !== null ? lexiconCache.get(store) : void 0;
|
|
20906
21018
|
if (hit && hit.key === key) return hit;
|
|
20907
|
-
const built = { symbols: buildSymbolLexicon(store), files: buildFileLexicon(store) };
|
|
21019
|
+
const built = { symbols: lazySymbolLexicon(store) ?? buildSymbolLexicon(store), files: buildFileLexicon(store) };
|
|
20908
21020
|
if (key !== null) lexiconCache.set(store, { key, ...built });
|
|
20909
21021
|
return built;
|
|
20910
21022
|
}
|
|
@@ -21143,6 +21255,38 @@ function stripCodebaseScope(scope) {
|
|
|
21143
21255
|
delete s["codebase"];
|
|
21144
21256
|
return s;
|
|
21145
21257
|
}
|
|
21258
|
+
function instanceGateRows(store, label) {
|
|
21259
|
+
return store.instanceGateRows?.(label) ?? store.findNodeFieldsByLabel(label, ["source", "privateFinding", "resolvedAs"]).map((r) => ({
|
|
21260
|
+
id: r.id,
|
|
21261
|
+
source: r.attrs["source"],
|
|
21262
|
+
privateFinding: r.attrs["privateFinding"],
|
|
21263
|
+
resolvedAs: r.attrs["resolvedAs"]
|
|
21264
|
+
}));
|
|
21265
|
+
}
|
|
21266
|
+
var GATE_VIEW_ATTRS = [
|
|
21267
|
+
"privateFinding",
|
|
21268
|
+
"source",
|
|
21269
|
+
"sources",
|
|
21270
|
+
"resolvedAs",
|
|
21271
|
+
"instanceReceipts",
|
|
21272
|
+
"cloudWithdrawn",
|
|
21273
|
+
"withdrawnAtCorrectionSeq",
|
|
21274
|
+
"contributedAtSeq",
|
|
21275
|
+
"cloudNodeId"
|
|
21276
|
+
];
|
|
21277
|
+
var GATE_VIEW_CHUNK = 500;
|
|
21278
|
+
var gateView = /* @__PURE__ */ new WeakSet();
|
|
21279
|
+
function gateViews(store, label, ids) {
|
|
21280
|
+
const byId = /* @__PURE__ */ new Map();
|
|
21281
|
+
for (let i = 0; i < ids.length; i += GATE_VIEW_CHUNK) {
|
|
21282
|
+
for (const r of store.selectNodes({ labels: [label], attrs: GATE_VIEW_ATTRS, where: [{ idIn: ids.slice(i, i + GATE_VIEW_CHUNK) }] })) {
|
|
21283
|
+
const view = { ...r, embedding: [] };
|
|
21284
|
+
gateView.add(view);
|
|
21285
|
+
byId.set(r.id, view);
|
|
21286
|
+
}
|
|
21287
|
+
}
|
|
21288
|
+
return ids.flatMap((id) => byId.get(id) ?? []);
|
|
21289
|
+
}
|
|
21146
21290
|
function contributedWireId(n, destinationKey) {
|
|
21147
21291
|
const cloudId = instanceReceipt(n, destinationKey)["cloudNodeId"];
|
|
21148
21292
|
return typeof cloudId === "string" && cloudId ? cloudId : n.id;
|
|
@@ -21301,7 +21445,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
21301
21445
|
edgesHeldDropped: 0
|
|
21302
21446
|
};
|
|
21303
21447
|
const sharedCauses = /* @__PURE__ */ new Map();
|
|
21304
|
-
const causalQueue = store
|
|
21448
|
+
const causalQueue = instanceGateRows(store, "Problem").filter((r) => r.source !== "cloud" && r.resolvedAs !== PROBLEM_RESOLUTION.FALSE_POSITIVE).map((r) => r.id).filter((id) => ignorePatterns.length === 0 || !ignored(store.getNode(id)?.description ?? ""));
|
|
21305
21449
|
const causalSeen = new Set(causalQueue);
|
|
21306
21450
|
for (let i = 0; i < causalQueue.length; i++) {
|
|
21307
21451
|
const id = causalQueue[i];
|
|
@@ -21317,21 +21461,21 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
21317
21461
|
for (const label of INSTANCE_LABELS) {
|
|
21318
21462
|
const ref = [];
|
|
21319
21463
|
includedByLabel.set(label, ref);
|
|
21320
|
-
const
|
|
21321
|
-
for (const row of store
|
|
21322
|
-
if (row.
|
|
21323
|
-
|
|
21324
|
-
if (n) local.push(n);
|
|
21464
|
+
const localIds = [];
|
|
21465
|
+
for (const row of instanceGateRows(store, label)) {
|
|
21466
|
+
if (row.source !== "cloud") {
|
|
21467
|
+
localIds.push(row.id);
|
|
21325
21468
|
continue;
|
|
21326
21469
|
}
|
|
21327
21470
|
if (seen.has(row.id) || walked.has(row.id)) continue;
|
|
21328
21471
|
walked.add(row.id);
|
|
21329
21472
|
composition.candidates++;
|
|
21330
|
-
if ((row.
|
|
21473
|
+
if ((row.privateFinding || label === "Vulnerability") && !opts.project) composition.privateTargetMissing++;
|
|
21331
21474
|
else composition.cloudSourced++;
|
|
21332
21475
|
}
|
|
21476
|
+
const local = gateViews(store, label, localIds);
|
|
21333
21477
|
const population = label === "RootCause" && opts.sharedStore ? [...local, ...sharedCauses.values()] : local;
|
|
21334
|
-
for (
|
|
21478
|
+
for (let n of population) {
|
|
21335
21479
|
if (seen.has(n.id)) continue;
|
|
21336
21480
|
if (walked.has(n.id)) continue;
|
|
21337
21481
|
walked.add(n.id);
|
|
@@ -21367,6 +21511,11 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
21367
21511
|
semanticEndpoints.set(n.id, contributedWireId(n, opts.destinationKey));
|
|
21368
21512
|
continue;
|
|
21369
21513
|
}
|
|
21514
|
+
if (gateView.has(n)) {
|
|
21515
|
+
const full = store.getNode(n.id);
|
|
21516
|
+
if (!full) continue;
|
|
21517
|
+
n = full;
|
|
21518
|
+
}
|
|
21370
21519
|
if (isEditPlaceholderSolution(n)) {
|
|
21371
21520
|
composition.autoMint++;
|
|
21372
21521
|
continue;
|
package/errata.mjs
CHANGED
|
@@ -20393,8 +20393,10 @@ function column(c) {
|
|
|
20393
20393
|
function compileNodeWhere(q) {
|
|
20394
20394
|
if (q.labels.length === 0) throw new Error("selectNodes: no labels");
|
|
20395
20395
|
const params = [...q.labels];
|
|
20396
|
-
const
|
|
20397
|
-
|
|
20396
|
+
const byId = (q.where ?? []).some((w) => "idIn" in w);
|
|
20397
|
+
const unindexed = byId ? "+" : "";
|
|
20398
|
+
const conds = [`${unindexed}label IN (${q.labels.map(() => "?").join(", ")})`];
|
|
20399
|
+
if (!q.includeClosed) conds.push(`${unindexed}valid_to IS NULL`);
|
|
20398
20400
|
for (const w of q.where ?? []) {
|
|
20399
20401
|
if ("embedding" in w) {
|
|
20400
20402
|
conds.push(`${EMBEDDING_DIM_SQL} ${w.embedding === "present" ? ">" : "="} 0`);
|
|
@@ -20446,6 +20448,14 @@ function compileNodeWhere(q) {
|
|
|
20446
20448
|
function attrValueSql(p) {
|
|
20447
20449
|
return `CASE json_type(attrs_json, ${p}) WHEN 'integer' THEN CAST(json_extract(attrs_json, ${p}) AS REAL) ELSE json_extract(attrs_json, ${p}) END`;
|
|
20448
20450
|
}
|
|
20451
|
+
function nodeSelectFrom(q) {
|
|
20452
|
+
if (q.indexedBy) return `nodes INDEXED BY ${selectIndex(q.indexedBy)}`;
|
|
20453
|
+
const where = q.where ?? [];
|
|
20454
|
+
if (!q.includeClosed && where.some((w) => "descriptionIn" in w && w.descriptionIn.length > 0) && !where.some((w) => "idIn" in w)) {
|
|
20455
|
+
return "nodes INDEXED BY nodes_live_description";
|
|
20456
|
+
}
|
|
20457
|
+
return "nodes";
|
|
20458
|
+
}
|
|
20449
20459
|
function compileNodeSelect(q) {
|
|
20450
20460
|
const { where, params } = compileNodeWhere(q);
|
|
20451
20461
|
const attrs = q.attrs ?? [];
|
|
@@ -20463,7 +20473,7 @@ function compileNodeSelect(q) {
|
|
|
20463
20473
|
}
|
|
20464
20474
|
const orderParams = !q.orderBy && q.labels.length > 1 ? [...q.labels] : [];
|
|
20465
20475
|
const limit = q.limit !== void 0 ? ` LIMIT ${Math.max(0, Math.floor(q.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
|
|
20476
|
+
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 ${nodeSelectFrom(q)} WHERE ${where} ORDER BY ${order}${limit}`;
|
|
20467
20477
|
return { sql, params: [...params, ...orderParams] };
|
|
20468
20478
|
}
|
|
20469
20479
|
function decodeAttr(value, type) {
|
|
@@ -20812,6 +20822,18 @@ CREATE INDEX IF NOT EXISTS edges_live_prior_tag ON edges(created_at) WHERE valid
|
|
|
20812
20822
|
-- incremental reindex can fetch just the changed files' symbols instead of
|
|
20813
20823
|
-- scanning every versioned node. Partial: only live rows are ever queried.
|
|
20814
20824
|
CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.relPath')) WHERE valid_to IS NULL;
|
|
20825
|
+
-- Symbols by qname and doc comments by the symbol they attach to: the drain's
|
|
20826
|
+
-- symbol lexicon resolves the names in the text it ships one at a time, instead
|
|
20827
|
+
-- of reading every Function/Method/Class/Interface/Const and Comment row on each
|
|
20828
|
+
-- live push (~300 MB of a 1.1 GB store per push, 2026-10-20).
|
|
20829
|
+
CREATE INDEX IF NOT EXISTS nodes_live_qname ON nodes(json_extract(attrs_json, '$.qname')) WHERE valid_to IS NULL;
|
|
20830
|
+
CREATE INDEX IF NOT EXISTS nodes_live_attached_to ON nodes(json_extract(attrs_json, '$.attachedTo')) WHERE valid_to IS NULL AND label = 'Comment';
|
|
20831
|
+
-- The attrs the cloud drain gates every instance row on, so it reads them from
|
|
20832
|
+
-- the index alone: pulled cloud rows are most of these labels (7,105 of 7,708
|
|
20833
|
+
-- Solutions on the live store) at ~10 KB of attrs each, and five full scans for
|
|
20834
|
+
-- two attrs read ~220 MB per push to find the few local rows that can ship.
|
|
20835
|
+
-- created_at leads so the index order is findNodeFieldsByLabel's.
|
|
20836
|
+
CREATE INDEX IF NOT EXISTS nodes_live_instance_gate ON nodes(label, created_at, json_extract(attrs_json, '$.source'), json_extract(attrs_json, '$.privateFinding'), json_extract(attrs_json, '$.resolvedAs'), id) WHERE valid_to IS NULL AND label IN ('Problem', 'Vulnerability', 'Solution', 'RootCause');
|
|
20815
20837
|
-- Closed rows by relPath, for reviveReobserved (every incremental reindex): the
|
|
20816
20838
|
-- live-only index above cannot serve it, so it scanned the whole table (~275 MB
|
|
20817
20839
|
-- of a 1.1 GB store per reindex, 2026-10-20).
|
|
@@ -21121,6 +21143,36 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
|
|
|
21121
21143
|
}
|
|
21122
21144
|
return out2;
|
|
21123
21145
|
}
|
|
21146
|
+
firstLiveByNameOrQname(labels, name2) {
|
|
21147
|
+
if (labels.length === 0) return null;
|
|
21148
|
+
const inLabels = labels.map(() => "?").join(",");
|
|
21149
|
+
const probe = (index, match2) => this.db.prepare(
|
|
21150
|
+
`SELECT rowid AS rid, created_at AS at, label, description, json_extract(attrs_json, '$.qname') AS qname FROM nodes INDEXED BY ${index}
|
|
21151
|
+
WHERE ${match2} = ? AND label IN (${inLabels}) AND valid_to IS NULL`
|
|
21152
|
+
).all(name2, ...labels);
|
|
21153
|
+
const rank = (r) => [labels.indexOf(r.label), r.at, r.rid];
|
|
21154
|
+
const before = (a, b) => a[0] < b[0] || a[0] === b[0] && (a[1] < b[1] || a[1] === b[1] && a[2] < b[2]);
|
|
21155
|
+
let best;
|
|
21156
|
+
for (const r of [...probe("nodes_live_description", "description"), ...probe("nodes_live_qname", "json_extract(attrs_json, '$.qname')")]) {
|
|
21157
|
+
if (!best || before(rank(r), rank(best))) best = r;
|
|
21158
|
+
}
|
|
21159
|
+
return best ? { label: best.label, description: best.description, qname: typeof best.qname === "string" ? best.qname : null } : null;
|
|
21160
|
+
}
|
|
21161
|
+
instanceGateRows(label) {
|
|
21162
|
+
return this.db.prepare(
|
|
21163
|
+
`SELECT id, json_extract(attrs_json, '$.source') AS source, json_extract(attrs_json, '$.privateFinding') AS privateFinding,
|
|
21164
|
+
json_extract(attrs_json, '$.resolvedAs') AS resolvedAs
|
|
21165
|
+
FROM nodes INDEXED BY nodes_live_instance_gate
|
|
21166
|
+
WHERE label IN ('Problem', 'Vulnerability', 'Solution', 'RootCause') AND label = ? AND valid_to IS NULL
|
|
21167
|
+
ORDER BY label, created_at, rowid`
|
|
21168
|
+
).all(label);
|
|
21169
|
+
}
|
|
21170
|
+
liveCommentsAttachedTo(name2) {
|
|
21171
|
+
return this.db.prepare(
|
|
21172
|
+
`SELECT json_extract(attrs_json, '$.kind') AS kind, json_extract(attrs_json, '$.text') AS text, description FROM nodes INDEXED BY nodes_live_attached_to
|
|
21173
|
+
WHERE label = 'Comment' AND valid_to IS NULL AND json_extract(attrs_json, '$.attachedTo') = ? ORDER BY created_at, rowid`
|
|
21174
|
+
).all(name2);
|
|
21175
|
+
}
|
|
21124
21176
|
strandedEdges() {
|
|
21125
21177
|
return countStrandedEdges(this.db);
|
|
21126
21178
|
}
|
|
@@ -21299,7 +21351,11 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
|
|
|
21299
21351
|
if (!stmt2) {
|
|
21300
21352
|
const cols = attrKeys.map((k, i2) => `, ${attrValueSql(`'$.${k}'`)} AS a${i2}, json_type(attrs_json, '$.${k}') AS t${i2}`).join("");
|
|
21301
21353
|
stmt2 = this.db.prepare(
|
|
21302
|
-
|
|
21354
|
+
// Ordered, not left to the planner: readers take "first row wins" (the
|
|
21355
|
+
// symbol lexicon's name winner and doc pick), and the order otherwise
|
|
21356
|
+
// followed whichever partial index the planner chose. nodes_live_created
|
|
21357
|
+
// serves this order without a sort.
|
|
21358
|
+
`SELECT id, description, community, extraction_confidence${cols} FROM nodes WHERE label = ? AND valid_to IS NULL ORDER BY created_at, rowid`
|
|
21303
21359
|
);
|
|
21304
21360
|
this.fieldStmts.set(cacheKey2, stmt2);
|
|
21305
21361
|
}
|
|
@@ -21325,7 +21381,7 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
|
|
|
21325
21381
|
}
|
|
21326
21382
|
countNodes(q) {
|
|
21327
21383
|
const { where, params } = compileNodeWhere(q);
|
|
21328
|
-
return Number(this.db.prepare(`SELECT COUNT(*) AS n FROM
|
|
21384
|
+
return Number(this.db.prepare(`SELECT COUNT(*) AS n FROM ${nodeSelectFrom(q)} WHERE ${where}`).get(...params).n);
|
|
21329
21385
|
}
|
|
21330
21386
|
setCommunity(id, community) {
|
|
21331
21387
|
this.stmts.setCommunity.run({ id, v: community });
|
|
@@ -37302,6 +37358,62 @@ function buildSymbolLexicon(store) {
|
|
|
37302
37358
|
}
|
|
37303
37359
|
return lex;
|
|
37304
37360
|
}
|
|
37361
|
+
function lazySymbolLexicon(store) {
|
|
37362
|
+
if (!store.firstLiveByNameOrQname || !store.liveCommentsAttachedTo) return null;
|
|
37363
|
+
const labels = SYMBOL_LABELS2.map(([label]) => label);
|
|
37364
|
+
const kindOf = new Map(SYMBOL_LABELS2.map(([label, kind]) => [label, kind]));
|
|
37365
|
+
const members = /* @__PURE__ */ new Map();
|
|
37366
|
+
const docs = /* @__PURE__ */ new Map();
|
|
37367
|
+
const entries = /* @__PURE__ */ new Map();
|
|
37368
|
+
const member = (name2) => {
|
|
37369
|
+
if (!members.has(name2)) {
|
|
37370
|
+
const hit = isDistinctiveIdentifier(name2) ? store.firstLiveByNameOrQname(labels, name2) : null;
|
|
37371
|
+
members.set(name2, hit ? { kind: kindOf.get(hit.label), description: hit.description, qname: hit.qname } : null);
|
|
37372
|
+
}
|
|
37373
|
+
return members.get(name2);
|
|
37374
|
+
};
|
|
37375
|
+
const docFor = (name2) => {
|
|
37376
|
+
if (!docs.has(name2)) {
|
|
37377
|
+
let found;
|
|
37378
|
+
for (const c of store.liveCommentsAttachedTo(name2)) {
|
|
37379
|
+
if (typeof c.kind !== "string" || !DOC_COMMENT_KINDS.has(c.kind)) continue;
|
|
37380
|
+
const text = typeof c.text === "string" ? c.text : c.description;
|
|
37381
|
+
if (!text?.trim()) continue;
|
|
37382
|
+
found = text.trim().slice(0, MAX_DOC_CHARS);
|
|
37383
|
+
break;
|
|
37384
|
+
}
|
|
37385
|
+
docs.set(name2, found);
|
|
37386
|
+
}
|
|
37387
|
+
return docs.get(name2);
|
|
37388
|
+
};
|
|
37389
|
+
const isKnown = (tok) => member(tok) !== null;
|
|
37390
|
+
let anySymbol;
|
|
37391
|
+
return {
|
|
37392
|
+
has: isKnown,
|
|
37393
|
+
get(name2) {
|
|
37394
|
+
if (!entries.has(name2)) {
|
|
37395
|
+
const m = member(name2);
|
|
37396
|
+
let entry = null;
|
|
37397
|
+
if (m) {
|
|
37398
|
+
entry = { kind: m.kind };
|
|
37399
|
+
const doc = (m.description ? docFor(m.description) : void 0) ?? (m.qname ? docFor(m.qname) : void 0);
|
|
37400
|
+
for (const phrase2 of summaryCandidates(name2, m.kind, doc)) {
|
|
37401
|
+
if (summaryRejectionReason(phrase2, isKnown) === null) {
|
|
37402
|
+
entry.summary = phrase2;
|
|
37403
|
+
break;
|
|
37404
|
+
}
|
|
37405
|
+
}
|
|
37406
|
+
}
|
|
37407
|
+
entries.set(name2, entry);
|
|
37408
|
+
}
|
|
37409
|
+
return entries.get(name2) ?? void 0;
|
|
37410
|
+
},
|
|
37411
|
+
get size() {
|
|
37412
|
+
anySymbol ??= labels.some((label) => store.countNodesByLabel(label) > 0);
|
|
37413
|
+
return anySymbol ? 1 : 0;
|
|
37414
|
+
}
|
|
37415
|
+
};
|
|
37416
|
+
}
|
|
37305
37417
|
function codeGraphKey(store) {
|
|
37306
37418
|
const files = store.labelFingerprint?.(["File"]);
|
|
37307
37419
|
if (files === void 0) return null;
|
|
@@ -37311,7 +37423,7 @@ function lexiconsFor(store) {
|
|
|
37311
37423
|
const key = codeGraphKey(store);
|
|
37312
37424
|
const hit = key !== null ? lexiconCache.get(store) : void 0;
|
|
37313
37425
|
if (hit && hit.key === key) return hit;
|
|
37314
|
-
const built = { symbols: buildSymbolLexicon(store), files: buildFileLexicon(store) };
|
|
37426
|
+
const built = { symbols: lazySymbolLexicon(store) ?? buildSymbolLexicon(store), files: buildFileLexicon(store) };
|
|
37315
37427
|
if (key !== null) lexiconCache.set(store, { key, ...built });
|
|
37316
37428
|
return built;
|
|
37317
37429
|
}
|
|
@@ -86894,7 +87006,7 @@ function createWatchBreaker(deps) {
|
|
|
86894
87006
|
}
|
|
86895
87007
|
|
|
86896
87008
|
// src/engine.ts
|
|
86897
|
-
var DAEMON_VERSION = true ? "2.0.22-dev.
|
|
87009
|
+
var DAEMON_VERSION = true ? "2.0.22-dev.4652" : "2.0.0-alpha.0";
|
|
86898
87010
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
86899
87011
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
86900
87012
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -90732,6 +90844,38 @@ function compositionCounters(c) {
|
|
|
90732
90844
|
...Object.fromEntries(buckets.map((b) => [`sidecarDrop_${b}`, sidecarDropReasons[b] ?? 0]))
|
|
90733
90845
|
};
|
|
90734
90846
|
}
|
|
90847
|
+
function instanceGateRows(store, label) {
|
|
90848
|
+
return store.instanceGateRows?.(label) ?? store.findNodeFieldsByLabel(label, ["source", "privateFinding", "resolvedAs"]).map((r) => ({
|
|
90849
|
+
id: r.id,
|
|
90850
|
+
source: r.attrs["source"],
|
|
90851
|
+
privateFinding: r.attrs["privateFinding"],
|
|
90852
|
+
resolvedAs: r.attrs["resolvedAs"]
|
|
90853
|
+
}));
|
|
90854
|
+
}
|
|
90855
|
+
var GATE_VIEW_ATTRS = [
|
|
90856
|
+
"privateFinding",
|
|
90857
|
+
"source",
|
|
90858
|
+
"sources",
|
|
90859
|
+
"resolvedAs",
|
|
90860
|
+
"instanceReceipts",
|
|
90861
|
+
"cloudWithdrawn",
|
|
90862
|
+
"withdrawnAtCorrectionSeq",
|
|
90863
|
+
"contributedAtSeq",
|
|
90864
|
+
"cloudNodeId"
|
|
90865
|
+
];
|
|
90866
|
+
var GATE_VIEW_CHUNK = 500;
|
|
90867
|
+
var gateView = /* @__PURE__ */ new WeakSet();
|
|
90868
|
+
function gateViews(store, label, ids) {
|
|
90869
|
+
const byId = /* @__PURE__ */ new Map();
|
|
90870
|
+
for (let i2 = 0; i2 < ids.length; i2 += GATE_VIEW_CHUNK) {
|
|
90871
|
+
for (const r of store.selectNodes({ labels: [label], attrs: GATE_VIEW_ATTRS, where: [{ idIn: ids.slice(i2, i2 + GATE_VIEW_CHUNK) }] })) {
|
|
90872
|
+
const view = { ...r, embedding: [] };
|
|
90873
|
+
gateView.add(view);
|
|
90874
|
+
byId.set(r.id, view);
|
|
90875
|
+
}
|
|
90876
|
+
}
|
|
90877
|
+
return ids.flatMap((id) => byId.get(id) ?? []);
|
|
90878
|
+
}
|
|
90735
90879
|
function contributedWireId(n, destinationKey) {
|
|
90736
90880
|
const cloudId = instanceReceipt(n, destinationKey)["cloudNodeId"];
|
|
90737
90881
|
return typeof cloudId === "string" && cloudId ? cloudId : n.id;
|
|
@@ -90890,7 +91034,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
90890
91034
|
edgesHeldDropped: 0
|
|
90891
91035
|
};
|
|
90892
91036
|
const sharedCauses = /* @__PURE__ */ new Map();
|
|
90893
|
-
const causalQueue = store
|
|
91037
|
+
const causalQueue = instanceGateRows(store, "Problem").filter((r) => r.source !== "cloud" && r.resolvedAs !== PROBLEM_RESOLUTION.FALSE_POSITIVE).map((r) => r.id).filter((id) => ignorePatterns.length === 0 || !ignored(store.getNode(id)?.description ?? ""));
|
|
90894
91038
|
const causalSeen = new Set(causalQueue);
|
|
90895
91039
|
for (let i2 = 0; i2 < causalQueue.length; i2++) {
|
|
90896
91040
|
const id = causalQueue[i2];
|
|
@@ -90906,21 +91050,21 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
90906
91050
|
for (const label of INSTANCE_LABELS) {
|
|
90907
91051
|
const ref = [];
|
|
90908
91052
|
includedByLabel.set(label, ref);
|
|
90909
|
-
const
|
|
90910
|
-
for (const row of store
|
|
90911
|
-
if (row.
|
|
90912
|
-
|
|
90913
|
-
if (n) local.push(n);
|
|
91053
|
+
const localIds = [];
|
|
91054
|
+
for (const row of instanceGateRows(store, label)) {
|
|
91055
|
+
if (row.source !== "cloud") {
|
|
91056
|
+
localIds.push(row.id);
|
|
90914
91057
|
continue;
|
|
90915
91058
|
}
|
|
90916
91059
|
if (seen.has(row.id) || walked.has(row.id)) continue;
|
|
90917
91060
|
walked.add(row.id);
|
|
90918
91061
|
composition.candidates++;
|
|
90919
|
-
if ((row.
|
|
91062
|
+
if ((row.privateFinding || label === "Vulnerability") && !opts.project) composition.privateTargetMissing++;
|
|
90920
91063
|
else composition.cloudSourced++;
|
|
90921
91064
|
}
|
|
91065
|
+
const local = gateViews(store, label, localIds);
|
|
90922
91066
|
const population = label === "RootCause" && opts.sharedStore ? [...local, ...sharedCauses.values()] : local;
|
|
90923
|
-
for (
|
|
91067
|
+
for (let n of population) {
|
|
90924
91068
|
if (seen.has(n.id)) continue;
|
|
90925
91069
|
if (walked.has(n.id)) continue;
|
|
90926
91070
|
walked.add(n.id);
|
|
@@ -90956,6 +91100,11 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
90956
91100
|
semanticEndpoints.set(n.id, contributedWireId(n, opts.destinationKey));
|
|
90957
91101
|
continue;
|
|
90958
91102
|
}
|
|
91103
|
+
if (gateView.has(n)) {
|
|
91104
|
+
const full = store.getNode(n.id);
|
|
91105
|
+
if (!full) continue;
|
|
91106
|
+
n = full;
|
|
91107
|
+
}
|
|
90959
91108
|
if (isEditPlaceholderSolution(n)) {
|
|
90960
91109
|
composition.autoMint++;
|
|
90961
91110
|
continue;
|
package/generalize-worker.mjs
CHANGED
|
@@ -15993,8 +15993,10 @@ function column(c) {
|
|
|
15993
15993
|
function compileNodeWhere(q) {
|
|
15994
15994
|
if (q.labels.length === 0) throw new Error("selectNodes: no labels");
|
|
15995
15995
|
const params = [...q.labels];
|
|
15996
|
-
const
|
|
15997
|
-
|
|
15996
|
+
const byId = (q.where ?? []).some((w) => "idIn" in w);
|
|
15997
|
+
const unindexed = byId ? "+" : "";
|
|
15998
|
+
const conds = [`${unindexed}label IN (${q.labels.map(() => "?").join(", ")})`];
|
|
15999
|
+
if (!q.includeClosed) conds.push(`${unindexed}valid_to IS NULL`);
|
|
15998
16000
|
for (const w of q.where ?? []) {
|
|
15999
16001
|
if ("embedding" in w) {
|
|
16000
16002
|
conds.push(`${EMBEDDING_DIM_SQL} ${w.embedding === "present" ? ">" : "="} 0`);
|
|
@@ -16046,6 +16048,14 @@ function compileNodeWhere(q) {
|
|
|
16046
16048
|
function attrValueSql(p) {
|
|
16047
16049
|
return `CASE json_type(attrs_json, ${p}) WHEN 'integer' THEN CAST(json_extract(attrs_json, ${p}) AS REAL) ELSE json_extract(attrs_json, ${p}) END`;
|
|
16048
16050
|
}
|
|
16051
|
+
function nodeSelectFrom(q) {
|
|
16052
|
+
if (q.indexedBy) return `nodes INDEXED BY ${selectIndex(q.indexedBy)}`;
|
|
16053
|
+
const where = q.where ?? [];
|
|
16054
|
+
if (!q.includeClosed && where.some((w) => "descriptionIn" in w && w.descriptionIn.length > 0) && !where.some((w) => "idIn" in w)) {
|
|
16055
|
+
return "nodes INDEXED BY nodes_live_description";
|
|
16056
|
+
}
|
|
16057
|
+
return "nodes";
|
|
16058
|
+
}
|
|
16049
16059
|
function compileNodeSelect(q) {
|
|
16050
16060
|
const { where, params } = compileNodeWhere(q);
|
|
16051
16061
|
const attrs = q.attrs ?? [];
|
|
@@ -16063,7 +16073,7 @@ function compileNodeSelect(q) {
|
|
|
16063
16073
|
}
|
|
16064
16074
|
const orderParams = !q.orderBy && q.labels.length > 1 ? [...q.labels] : [];
|
|
16065
16075
|
const limit = q.limit !== void 0 ? ` LIMIT ${Math.max(0, Math.floor(q.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
|
|
16076
|
+
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 ${nodeSelectFrom(q)} WHERE ${where} ORDER BY ${order}${limit}`;
|
|
16067
16077
|
return { sql, params: [...params, ...orderParams] };
|
|
16068
16078
|
}
|
|
16069
16079
|
function decodeAttr(value, type) {
|
|
@@ -16300,6 +16310,18 @@ CREATE INDEX IF NOT EXISTS edges_live_prior_tag ON edges(created_at) WHERE valid
|
|
|
16300
16310
|
-- incremental reindex can fetch just the changed files' symbols instead of
|
|
16301
16311
|
-- scanning every versioned node. Partial: only live rows are ever queried.
|
|
16302
16312
|
CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.relPath')) WHERE valid_to IS NULL;
|
|
16313
|
+
-- Symbols by qname and doc comments by the symbol they attach to: the drain's
|
|
16314
|
+
-- symbol lexicon resolves the names in the text it ships one at a time, instead
|
|
16315
|
+
-- of reading every Function/Method/Class/Interface/Const and Comment row on each
|
|
16316
|
+
-- live push (~300 MB of a 1.1 GB store per push, 2026-10-20).
|
|
16317
|
+
CREATE INDEX IF NOT EXISTS nodes_live_qname ON nodes(json_extract(attrs_json, '$.qname')) WHERE valid_to IS NULL;
|
|
16318
|
+
CREATE INDEX IF NOT EXISTS nodes_live_attached_to ON nodes(json_extract(attrs_json, '$.attachedTo')) WHERE valid_to IS NULL AND label = 'Comment';
|
|
16319
|
+
-- The attrs the cloud drain gates every instance row on, so it reads them from
|
|
16320
|
+
-- the index alone: pulled cloud rows are most of these labels (7,105 of 7,708
|
|
16321
|
+
-- Solutions on the live store) at ~10 KB of attrs each, and five full scans for
|
|
16322
|
+
-- two attrs read ~220 MB per push to find the few local rows that can ship.
|
|
16323
|
+
-- created_at leads so the index order is findNodeFieldsByLabel's.
|
|
16324
|
+
CREATE INDEX IF NOT EXISTS nodes_live_instance_gate ON nodes(label, created_at, json_extract(attrs_json, '$.source'), json_extract(attrs_json, '$.privateFinding'), json_extract(attrs_json, '$.resolvedAs'), id) WHERE valid_to IS NULL AND label IN ('Problem', 'Vulnerability', 'Solution', 'RootCause');
|
|
16303
16325
|
-- Closed rows by relPath, for reviveReobserved (every incremental reindex): the
|
|
16304
16326
|
-- live-only index above cannot serve it, so it scanned the whole table (~275 MB
|
|
16305
16327
|
-- of a 1.1 GB store per reindex, 2026-10-20).
|
|
@@ -16666,6 +16688,36 @@ var SqliteGraphStore = class {
|
|
|
16666
16688
|
}
|
|
16667
16689
|
return out;
|
|
16668
16690
|
}
|
|
16691
|
+
firstLiveByNameOrQname(labels, name) {
|
|
16692
|
+
if (labels.length === 0) return null;
|
|
16693
|
+
const inLabels = labels.map(() => "?").join(",");
|
|
16694
|
+
const probe = (index, match) => this.db.prepare(
|
|
16695
|
+
`SELECT rowid AS rid, created_at AS at, label, description, json_extract(attrs_json, '$.qname') AS qname FROM nodes INDEXED BY ${index}
|
|
16696
|
+
WHERE ${match} = ? AND label IN (${inLabels}) AND valid_to IS NULL`
|
|
16697
|
+
).all(name, ...labels);
|
|
16698
|
+
const rank = (r) => [labels.indexOf(r.label), r.at, r.rid];
|
|
16699
|
+
const before = (a, b) => a[0] < b[0] || a[0] === b[0] && (a[1] < b[1] || a[1] === b[1] && a[2] < b[2]);
|
|
16700
|
+
let best;
|
|
16701
|
+
for (const r of [...probe("nodes_live_description", "description"), ...probe("nodes_live_qname", "json_extract(attrs_json, '$.qname')")]) {
|
|
16702
|
+
if (!best || before(rank(r), rank(best))) best = r;
|
|
16703
|
+
}
|
|
16704
|
+
return best ? { label: best.label, description: best.description, qname: typeof best.qname === "string" ? best.qname : null } : null;
|
|
16705
|
+
}
|
|
16706
|
+
instanceGateRows(label) {
|
|
16707
|
+
return this.db.prepare(
|
|
16708
|
+
`SELECT id, json_extract(attrs_json, '$.source') AS source, json_extract(attrs_json, '$.privateFinding') AS privateFinding,
|
|
16709
|
+
json_extract(attrs_json, '$.resolvedAs') AS resolvedAs
|
|
16710
|
+
FROM nodes INDEXED BY nodes_live_instance_gate
|
|
16711
|
+
WHERE label IN ('Problem', 'Vulnerability', 'Solution', 'RootCause') AND label = ? AND valid_to IS NULL
|
|
16712
|
+
ORDER BY label, created_at, rowid`
|
|
16713
|
+
).all(label);
|
|
16714
|
+
}
|
|
16715
|
+
liveCommentsAttachedTo(name) {
|
|
16716
|
+
return this.db.prepare(
|
|
16717
|
+
`SELECT json_extract(attrs_json, '$.kind') AS kind, json_extract(attrs_json, '$.text') AS text, description FROM nodes INDEXED BY nodes_live_attached_to
|
|
16718
|
+
WHERE label = 'Comment' AND valid_to IS NULL AND json_extract(attrs_json, '$.attachedTo') = ? ORDER BY created_at, rowid`
|
|
16719
|
+
).all(name);
|
|
16720
|
+
}
|
|
16669
16721
|
strandedEdges() {
|
|
16670
16722
|
return countStrandedEdges(this.db);
|
|
16671
16723
|
}
|
|
@@ -16844,7 +16896,11 @@ var SqliteGraphStore = class {
|
|
|
16844
16896
|
if (!stmt2) {
|
|
16845
16897
|
const cols = attrKeys.map((k, i) => `, ${attrValueSql(`'$.${k}'`)} AS a${i}, json_type(attrs_json, '$.${k}') AS t${i}`).join("");
|
|
16846
16898
|
stmt2 = this.db.prepare(
|
|
16847
|
-
|
|
16899
|
+
// Ordered, not left to the planner: readers take "first row wins" (the
|
|
16900
|
+
// symbol lexicon's name winner and doc pick), and the order otherwise
|
|
16901
|
+
// followed whichever partial index the planner chose. nodes_live_created
|
|
16902
|
+
// serves this order without a sort.
|
|
16903
|
+
`SELECT id, description, community, extraction_confidence${cols} FROM nodes WHERE label = ? AND valid_to IS NULL ORDER BY created_at, rowid`
|
|
16848
16904
|
);
|
|
16849
16905
|
this.fieldStmts.set(cacheKey, stmt2);
|
|
16850
16906
|
}
|
|
@@ -16870,7 +16926,7 @@ var SqliteGraphStore = class {
|
|
|
16870
16926
|
}
|
|
16871
16927
|
countNodes(q) {
|
|
16872
16928
|
const { where, params } = compileNodeWhere(q);
|
|
16873
|
-
return Number(this.db.prepare(`SELECT COUNT(*) AS n FROM
|
|
16929
|
+
return Number(this.db.prepare(`SELECT COUNT(*) AS n FROM ${nodeSelectFrom(q)} WHERE ${where}`).get(...params).n);
|
|
16874
16930
|
}
|
|
16875
16931
|
setCommunity(id, community) {
|
|
16876
16932
|
this.stmts.setCommunity.run({ id, v: community });
|
|
@@ -18350,6 +18406,62 @@ function buildSymbolLexicon(store) {
|
|
|
18350
18406
|
}
|
|
18351
18407
|
return lex;
|
|
18352
18408
|
}
|
|
18409
|
+
function lazySymbolLexicon(store) {
|
|
18410
|
+
if (!store.firstLiveByNameOrQname || !store.liveCommentsAttachedTo) return null;
|
|
18411
|
+
const labels = SYMBOL_LABELS.map(([label]) => label);
|
|
18412
|
+
const kindOf = new Map(SYMBOL_LABELS.map(([label, kind]) => [label, kind]));
|
|
18413
|
+
const members = /* @__PURE__ */ new Map();
|
|
18414
|
+
const docs = /* @__PURE__ */ new Map();
|
|
18415
|
+
const entries = /* @__PURE__ */ new Map();
|
|
18416
|
+
const member = (name) => {
|
|
18417
|
+
if (!members.has(name)) {
|
|
18418
|
+
const hit = isDistinctiveIdentifier(name) ? store.firstLiveByNameOrQname(labels, name) : null;
|
|
18419
|
+
members.set(name, hit ? { kind: kindOf.get(hit.label), description: hit.description, qname: hit.qname } : null);
|
|
18420
|
+
}
|
|
18421
|
+
return members.get(name);
|
|
18422
|
+
};
|
|
18423
|
+
const docFor = (name) => {
|
|
18424
|
+
if (!docs.has(name)) {
|
|
18425
|
+
let found;
|
|
18426
|
+
for (const c of store.liveCommentsAttachedTo(name)) {
|
|
18427
|
+
if (typeof c.kind !== "string" || !DOC_COMMENT_KINDS.has(c.kind)) continue;
|
|
18428
|
+
const text = typeof c.text === "string" ? c.text : c.description;
|
|
18429
|
+
if (!text?.trim()) continue;
|
|
18430
|
+
found = text.trim().slice(0, MAX_DOC_CHARS);
|
|
18431
|
+
break;
|
|
18432
|
+
}
|
|
18433
|
+
docs.set(name, found);
|
|
18434
|
+
}
|
|
18435
|
+
return docs.get(name);
|
|
18436
|
+
};
|
|
18437
|
+
const isKnown = (tok) => member(tok) !== null;
|
|
18438
|
+
let anySymbol;
|
|
18439
|
+
return {
|
|
18440
|
+
has: isKnown,
|
|
18441
|
+
get(name) {
|
|
18442
|
+
if (!entries.has(name)) {
|
|
18443
|
+
const m = member(name);
|
|
18444
|
+
let entry = null;
|
|
18445
|
+
if (m) {
|
|
18446
|
+
entry = { kind: m.kind };
|
|
18447
|
+
const doc = (m.description ? docFor(m.description) : void 0) ?? (m.qname ? docFor(m.qname) : void 0);
|
|
18448
|
+
for (const phrase of summaryCandidates(name, m.kind, doc)) {
|
|
18449
|
+
if (summaryRejectionReason(phrase, isKnown) === null) {
|
|
18450
|
+
entry.summary = phrase;
|
|
18451
|
+
break;
|
|
18452
|
+
}
|
|
18453
|
+
}
|
|
18454
|
+
}
|
|
18455
|
+
entries.set(name, entry);
|
|
18456
|
+
}
|
|
18457
|
+
return entries.get(name) ?? void 0;
|
|
18458
|
+
},
|
|
18459
|
+
get size() {
|
|
18460
|
+
anySymbol ??= labels.some((label) => store.countNodesByLabel(label) > 0);
|
|
18461
|
+
return anySymbol ? 1 : 0;
|
|
18462
|
+
}
|
|
18463
|
+
};
|
|
18464
|
+
}
|
|
18353
18465
|
var LEXICON_SYMBOL_LABELS = ["Function", "Method", "Class", "Interface", "Const", "Comment"];
|
|
18354
18466
|
function codeGraphKey(store) {
|
|
18355
18467
|
const files = store.labelFingerprint?.(["File"]);
|
|
@@ -18361,7 +18473,7 @@ function lexiconsFor(store) {
|
|
|
18361
18473
|
const key = codeGraphKey(store);
|
|
18362
18474
|
const hit = key !== null ? lexiconCache.get(store) : void 0;
|
|
18363
18475
|
if (hit && hit.key === key) return hit;
|
|
18364
|
-
const built = { symbols: buildSymbolLexicon(store), files: buildFileLexicon(store) };
|
|
18476
|
+
const built = { symbols: lazySymbolLexicon(store) ?? buildSymbolLexicon(store), files: buildFileLexicon(store) };
|
|
18365
18477
|
if (key !== null) lexiconCache.set(store, { key, ...built });
|
|
18366
18478
|
return built;
|
|
18367
18479
|
}
|
package/package.json
CHANGED
package/pass-worker.mjs
CHANGED
|
@@ -26871,8 +26871,10 @@ function column(c) {
|
|
|
26871
26871
|
function compileNodeWhere(q) {
|
|
26872
26872
|
if (q.labels.length === 0) throw new Error("selectNodes: no labels");
|
|
26873
26873
|
const params = [...q.labels];
|
|
26874
|
-
const
|
|
26875
|
-
|
|
26874
|
+
const byId = (q.where ?? []).some((w) => "idIn" in w);
|
|
26875
|
+
const unindexed = byId ? "+" : "";
|
|
26876
|
+
const conds = [`${unindexed}label IN (${q.labels.map(() => "?").join(", ")})`];
|
|
26877
|
+
if (!q.includeClosed) conds.push(`${unindexed}valid_to IS NULL`);
|
|
26876
26878
|
for (const w of q.where ?? []) {
|
|
26877
26879
|
if ("embedding" in w) {
|
|
26878
26880
|
conds.push(`${EMBEDDING_DIM_SQL} ${w.embedding === "present" ? ">" : "="} 0`);
|
|
@@ -26924,6 +26926,14 @@ function compileNodeWhere(q) {
|
|
|
26924
26926
|
function attrValueSql(p) {
|
|
26925
26927
|
return `CASE json_type(attrs_json, ${p}) WHEN 'integer' THEN CAST(json_extract(attrs_json, ${p}) AS REAL) ELSE json_extract(attrs_json, ${p}) END`;
|
|
26926
26928
|
}
|
|
26929
|
+
function nodeSelectFrom(q) {
|
|
26930
|
+
if (q.indexedBy) return `nodes INDEXED BY ${selectIndex(q.indexedBy)}`;
|
|
26931
|
+
const where = q.where ?? [];
|
|
26932
|
+
if (!q.includeClosed && where.some((w) => "descriptionIn" in w && w.descriptionIn.length > 0) && !where.some((w) => "idIn" in w)) {
|
|
26933
|
+
return "nodes INDEXED BY nodes_live_description";
|
|
26934
|
+
}
|
|
26935
|
+
return "nodes";
|
|
26936
|
+
}
|
|
26927
26937
|
function compileNodeSelect(q) {
|
|
26928
26938
|
const { where, params } = compileNodeWhere(q);
|
|
26929
26939
|
const attrs = q.attrs ?? [];
|
|
@@ -26941,7 +26951,7 @@ function compileNodeSelect(q) {
|
|
|
26941
26951
|
}
|
|
26942
26952
|
const orderParams = !q.orderBy && q.labels.length > 1 ? [...q.labels] : [];
|
|
26943
26953
|
const limit = q.limit !== void 0 ? ` LIMIT ${Math.max(0, Math.floor(q.limit))}` : "";
|
|
26944
|
-
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
|
|
26954
|
+
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 ${nodeSelectFrom(q)} WHERE ${where} ORDER BY ${order}${limit}`;
|
|
26945
26955
|
return { sql, params: [...params, ...orderParams] };
|
|
26946
26956
|
}
|
|
26947
26957
|
function decodeAttr(value, type) {
|
|
@@ -27178,6 +27188,18 @@ CREATE INDEX IF NOT EXISTS edges_live_prior_tag ON edges(created_at) WHERE valid
|
|
|
27178
27188
|
-- incremental reindex can fetch just the changed files' symbols instead of
|
|
27179
27189
|
-- scanning every versioned node. Partial: only live rows are ever queried.
|
|
27180
27190
|
CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.relPath')) WHERE valid_to IS NULL;
|
|
27191
|
+
-- Symbols by qname and doc comments by the symbol they attach to: the drain's
|
|
27192
|
+
-- symbol lexicon resolves the names in the text it ships one at a time, instead
|
|
27193
|
+
-- of reading every Function/Method/Class/Interface/Const and Comment row on each
|
|
27194
|
+
-- live push (~300 MB of a 1.1 GB store per push, 2026-10-20).
|
|
27195
|
+
CREATE INDEX IF NOT EXISTS nodes_live_qname ON nodes(json_extract(attrs_json, '$.qname')) WHERE valid_to IS NULL;
|
|
27196
|
+
CREATE INDEX IF NOT EXISTS nodes_live_attached_to ON nodes(json_extract(attrs_json, '$.attachedTo')) WHERE valid_to IS NULL AND label = 'Comment';
|
|
27197
|
+
-- The attrs the cloud drain gates every instance row on, so it reads them from
|
|
27198
|
+
-- the index alone: pulled cloud rows are most of these labels (7,105 of 7,708
|
|
27199
|
+
-- Solutions on the live store) at ~10 KB of attrs each, and five full scans for
|
|
27200
|
+
-- two attrs read ~220 MB per push to find the few local rows that can ship.
|
|
27201
|
+
-- created_at leads so the index order is findNodeFieldsByLabel's.
|
|
27202
|
+
CREATE INDEX IF NOT EXISTS nodes_live_instance_gate ON nodes(label, created_at, json_extract(attrs_json, '$.source'), json_extract(attrs_json, '$.privateFinding'), json_extract(attrs_json, '$.resolvedAs'), id) WHERE valid_to IS NULL AND label IN ('Problem', 'Vulnerability', 'Solution', 'RootCause');
|
|
27181
27203
|
-- Closed rows by relPath, for reviveReobserved (every incremental reindex): the
|
|
27182
27204
|
-- live-only index above cannot serve it, so it scanned the whole table (~275 MB
|
|
27183
27205
|
-- of a 1.1 GB store per reindex, 2026-10-20).
|
|
@@ -27544,6 +27566,36 @@ var SqliteGraphStore = class {
|
|
|
27544
27566
|
}
|
|
27545
27567
|
return out2;
|
|
27546
27568
|
}
|
|
27569
|
+
firstLiveByNameOrQname(labels, name2) {
|
|
27570
|
+
if (labels.length === 0) return null;
|
|
27571
|
+
const inLabels = labels.map(() => "?").join(",");
|
|
27572
|
+
const probe = (index, match) => this.db.prepare(
|
|
27573
|
+
`SELECT rowid AS rid, created_at AS at, label, description, json_extract(attrs_json, '$.qname') AS qname FROM nodes INDEXED BY ${index}
|
|
27574
|
+
WHERE ${match} = ? AND label IN (${inLabels}) AND valid_to IS NULL`
|
|
27575
|
+
).all(name2, ...labels);
|
|
27576
|
+
const rank = (r) => [labels.indexOf(r.label), r.at, r.rid];
|
|
27577
|
+
const before = (a, b) => a[0] < b[0] || a[0] === b[0] && (a[1] < b[1] || a[1] === b[1] && a[2] < b[2]);
|
|
27578
|
+
let best;
|
|
27579
|
+
for (const r of [...probe("nodes_live_description", "description"), ...probe("nodes_live_qname", "json_extract(attrs_json, '$.qname')")]) {
|
|
27580
|
+
if (!best || before(rank(r), rank(best))) best = r;
|
|
27581
|
+
}
|
|
27582
|
+
return best ? { label: best.label, description: best.description, qname: typeof best.qname === "string" ? best.qname : null } : null;
|
|
27583
|
+
}
|
|
27584
|
+
instanceGateRows(label) {
|
|
27585
|
+
return this.db.prepare(
|
|
27586
|
+
`SELECT id, json_extract(attrs_json, '$.source') AS source, json_extract(attrs_json, '$.privateFinding') AS privateFinding,
|
|
27587
|
+
json_extract(attrs_json, '$.resolvedAs') AS resolvedAs
|
|
27588
|
+
FROM nodes INDEXED BY nodes_live_instance_gate
|
|
27589
|
+
WHERE label IN ('Problem', 'Vulnerability', 'Solution', 'RootCause') AND label = ? AND valid_to IS NULL
|
|
27590
|
+
ORDER BY label, created_at, rowid`
|
|
27591
|
+
).all(label);
|
|
27592
|
+
}
|
|
27593
|
+
liveCommentsAttachedTo(name2) {
|
|
27594
|
+
return this.db.prepare(
|
|
27595
|
+
`SELECT json_extract(attrs_json, '$.kind') AS kind, json_extract(attrs_json, '$.text') AS text, description FROM nodes INDEXED BY nodes_live_attached_to
|
|
27596
|
+
WHERE label = 'Comment' AND valid_to IS NULL AND json_extract(attrs_json, '$.attachedTo') = ? ORDER BY created_at, rowid`
|
|
27597
|
+
).all(name2);
|
|
27598
|
+
}
|
|
27547
27599
|
strandedEdges() {
|
|
27548
27600
|
return countStrandedEdges(this.db);
|
|
27549
27601
|
}
|
|
@@ -27722,7 +27774,11 @@ var SqliteGraphStore = class {
|
|
|
27722
27774
|
if (!stmt2) {
|
|
27723
27775
|
const cols = attrKeys.map((k, i2) => `, ${attrValueSql(`'$.${k}'`)} AS a${i2}, json_type(attrs_json, '$.${k}') AS t${i2}`).join("");
|
|
27724
27776
|
stmt2 = this.db.prepare(
|
|
27725
|
-
|
|
27777
|
+
// Ordered, not left to the planner: readers take "first row wins" (the
|
|
27778
|
+
// symbol lexicon's name winner and doc pick), and the order otherwise
|
|
27779
|
+
// followed whichever partial index the planner chose. nodes_live_created
|
|
27780
|
+
// serves this order without a sort.
|
|
27781
|
+
`SELECT id, description, community, extraction_confidence${cols} FROM nodes WHERE label = ? AND valid_to IS NULL ORDER BY created_at, rowid`
|
|
27726
27782
|
);
|
|
27727
27783
|
this.fieldStmts.set(cacheKey, stmt2);
|
|
27728
27784
|
}
|
|
@@ -27748,7 +27804,7 @@ var SqliteGraphStore = class {
|
|
|
27748
27804
|
}
|
|
27749
27805
|
countNodes(q) {
|
|
27750
27806
|
const { where, params } = compileNodeWhere(q);
|
|
27751
|
-
return Number(this.db.prepare(`SELECT COUNT(*) AS n FROM
|
|
27807
|
+
return Number(this.db.prepare(`SELECT COUNT(*) AS n FROM ${nodeSelectFrom(q)} WHERE ${where}`).get(...params).n);
|
|
27752
27808
|
}
|
|
27753
27809
|
setCommunity(id, community) {
|
|
27754
27810
|
this.stmts.setCommunity.run({ id, v: community });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
ba1065832fc364902b70117e8568ae7f0d76cd3af48ed4d0929f03d9d3d55c7f .codex-plugin/plugin.json
|
|
2
2
|
a7bebae9fb01c838d6c75fc784129e28be571233fa66ff5ee8039b574f35ccf7 assets/icon.png
|
|
3
3
|
fc38b64e4df1e0b72c35764bef6c4c05430d97c9009ad0ecc8a9e75b4deab232 configure-local.mjs
|
|
4
4
|
73dc6028b3b070257c7c31f252d11e55a9e096f4aed0f187f10cb21716e1e6d7 dist/client.js
|