@inerrata-corporation/errata 2.0.21 → 2.0.22

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.
@@ -594,6 +594,13 @@ function aliasRegex(alias) {
594
594
  const body = escapeRe(alias).replace(/\\?\s+/g, "\\s+");
595
595
  return new RegExp(`(?<![\\w-])${body}(?![\\w-])`, "i");
596
596
  }
597
+ function withoutEntityMentions(text, entityId) {
598
+ let out = text;
599
+ for (const { entity, re } of COMPILED) {
600
+ if (entity.id === entityId) out = out.replace(new RegExp(re.source, "gi"), " ");
601
+ }
602
+ return out;
603
+ }
597
604
  function prefilterEntities(text) {
598
605
  const seen = /* @__PURE__ */ new Set();
599
606
  const hits = [];
@@ -770,13 +777,19 @@ var init_concept_bag = __esm({
770
777
 
771
778
  // ../../packages/shared/src/nlp/claim-id.ts
772
779
  function claimStructure(text, scope) {
773
- const entities = prefilterEntities(text).map((e) => e.id).sort();
780
+ const extracted = prefilterEntities(text);
781
+ const entities = extracted.map((e) => e.id).sort();
774
782
  const predicate = normalizePredicate(text);
775
783
  const stance = detectStance(text);
776
784
  const base = { entities, predicate, stance, scope: scope ?? {} };
777
- if (predicate === "") base.raw = conceptBag(text);
785
+ if (predicate === "" || entities.length === 0 || predicateIsTheEntity(text, extracted[0].id, entities.length)) {
786
+ base.raw = conceptBag(text);
787
+ }
778
788
  return base;
779
789
  }
790
+ function predicateIsTheEntity(text, entityId, entityCount) {
791
+ return entityCount === 1 && normalizePredicate(withoutEntityMentions(text, entityId)) === "";
792
+ }
780
793
  function canonicalClaimId(text, scope) {
781
794
  const s = claimStructure(text, scope);
782
795
  return digest(
@@ -15242,6 +15255,36 @@ var init_history_evidence = __esm({
15242
15255
  });
15243
15256
 
15244
15257
  // ../../packages/shared/src/history-dependencies.ts
15258
+ function historyDependencyIdentity(raw) {
15259
+ const compact = compactDependencyIdentity(raw);
15260
+ if (compact !== void 0) return compact;
15261
+ const parsed = HistoryDependencyContextSchema.safeParse(raw);
15262
+ if (!parsed.success || !parsed.data.complete || parsed.data.conflict) return null;
15263
+ if (parsed.data.dependencies.some((d) => !exactHistoryDependencyVersion(d))) return null;
15264
+ return digest(parsed.data.dependencies.map((d) => [d.packageId, d.manifestId, d.side, d.declaredRange, d.resolvedVersion]).sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b))));
15265
+ }
15266
+ function exactHistoryDependencyVersion(d) {
15267
+ return d.resolvedVersion ?? (/^\d+\.\d+\.\d+(?:-[\w.-]+)?$/.test(d.declaredRange ?? "") ? d.declaredRange : null);
15268
+ }
15269
+ function compactDependencyIdentity(raw) {
15270
+ if (!raw || typeof raw !== "object" || raw.compact !== true) return void 0;
15271
+ const identity = raw.identity;
15272
+ return typeof identity === "string" ? identity : null;
15273
+ }
15274
+ function compactHistoryQuality(quality) {
15275
+ const out = { ...quality };
15276
+ const context = quality["dependencyContext"];
15277
+ if (context !== void 0 && compactDependencyIdentity(context) === void 0) {
15278
+ const compact = { schemaVersion: "history-deps-1", compact: true, identity: historyDependencyIdentity(context) };
15279
+ out["dependencyContext"] = compact;
15280
+ }
15281
+ const evidence = quality["reconciliationEvidence"];
15282
+ if (evidence && typeof evidence === "object" && !Array.isArray(evidence)) {
15283
+ const build = evidence["build"];
15284
+ out["reconciliationEvidence"] = build === void 0 ? {} : { build };
15285
+ }
15286
+ return out;
15287
+ }
15245
15288
  var version2, HistoryDependencySchema, HistoryDependencyContextSchema;
15246
15289
  var init_history_dependencies = __esm({
15247
15290
  "../../packages/shared/src/history-dependencies.ts"() {
@@ -15726,10 +15769,12 @@ var init_history_quality = __esm({
15726
15769
  });
15727
15770
 
15728
15771
  // ../../packages/shared/src/history-read.ts
15772
+ var CLOUD_ATTR_DUPLICATE_KEYS;
15729
15773
  var init_history_read = __esm({
15730
15774
  "../../packages/shared/src/history-read.ts"() {
15731
15775
  "use strict";
15732
15776
  init_history_dependencies();
15777
+ CLOUD_ATTR_DUPLICATE_KEYS = ["attrsJson", "embedding"];
15733
15778
  }
15734
15779
  });
15735
15780
 
@@ -16396,7 +16441,275 @@ function installEditPlaceholderRetirement(db) {
16396
16441
  });
16397
16442
  }
16398
16443
 
16444
+ // ../../packages/local-graph/src/cloud-attr-compaction.ts
16445
+ init_src2();
16446
+ var CLOUD_ATTR_COMPACTION_KEY = "cloud-attr-compaction-1";
16447
+ var DUPES = CLOUD_ATTR_DUPLICATE_KEYS.map((k) => `'${k}'`).join(",");
16448
+ function compacted(row) {
16449
+ const packed = `json_extract(${row}.attrs_json, '$.attrsJson')`;
16450
+ const nested = `CASE WHEN json_type(${row}.attrs_json, '$.attrsJson') = 'text' AND json_valid(${packed})
16451
+ AND json_type(${packed}) = 'object' THEN ${packed} ELSE '{}' END`;
16452
+ const value = `CASE WHEN type IN ('array','object') THEN json(value) WHEN type IN ('true','false') THEN json(type) ELSE value END`;
16453
+ return `(SELECT json_group_object(key, ${value}) FROM (
16454
+ SELECT key, value, type, min(pri) FROM (
16455
+ SELECT key, value, type, 0 AS pri FROM json_each(${row}.attrs_json)
16456
+ UNION ALL
16457
+ SELECT key, value, type, 1 AS pri FROM json_each(${nested})
16458
+ ) WHERE key NOT IN (${DUPES}) GROUP BY key))`;
16459
+ }
16460
+ function dirty(row) {
16461
+ const has = CLOUD_ATTR_DUPLICATE_KEYS.map((k) => `json_type(${row}.attrs_json, '$.${k}') IS NOT NULL`).join(" OR ");
16462
+ return `json_extract(${row}.attrs_json, '$.source') = 'cloud' AND (${has})`;
16463
+ }
16464
+ function installCloudAttrCompaction(db) {
16465
+ if (db.prepare("SELECT value FROM store_meta WHERE key = ?").get(CLOUD_ATTR_COMPACTION_KEY)) return;
16466
+ db.transaction(() => {
16467
+ for (const operation of ["INSERT", "UPDATE"]) {
16468
+ db.exec(`CREATE TRIGGER IF NOT EXISTS cloud_attr_compact_${operation.toLowerCase()}
16469
+ AFTER ${operation} ON nodes WHEN ${dirty("NEW")}
16470
+ BEGIN UPDATE nodes SET attrs_json = ${compacted("nodes")} WHERE id = NEW.id; END;`);
16471
+ }
16472
+ db.exec(`UPDATE nodes SET attrs_json = ${compacted("nodes")} WHERE ${dirty("nodes")}`);
16473
+ db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(CLOUD_ATTR_COMPACTION_KEY, "installed");
16474
+ });
16475
+ }
16476
+
16477
+ // ../../packages/local-graph/src/history-attr-slim.ts
16478
+ init_src();
16479
+ var HISTORY_ATTR_SLIM_KEY = "history-attr-slim-1";
16480
+ var SLIM_BATCH = 500;
16481
+ function installHistoryAttrSlim(db) {
16482
+ if (db.prepare("SELECT value FROM store_meta WHERE key = ?").get(HISTORY_ATTR_SLIM_KEY)) return;
16483
+ const select = db.prepare(`SELECT rowid AS rid, json_extract(attrs_json, '$.historyQuality') AS q FROM nodes
16484
+ WHERE rowid > ? AND (json_type(attrs_json, '$.historyQuality.dependencyContext.dependencies') IS NOT NULL
16485
+ OR json_type(attrs_json, '$.historyQuality.reconciliationEvidence') = 'object')
16486
+ ORDER BY rowid LIMIT ${SLIM_BATCH}`);
16487
+ const write = db.prepare(`UPDATE nodes SET attrs_json = json_set(attrs_json, '$.historyQuality', json(?)) WHERE rowid = ?`);
16488
+ let after = 0;
16489
+ for (; ; ) {
16490
+ const rows = select.all(after);
16491
+ if (rows.length === 0) break;
16492
+ db.transaction(() => {
16493
+ for (const { rid, q } of rows) {
16494
+ if (!q) continue;
16495
+ let quality;
16496
+ try {
16497
+ quality = JSON.parse(q);
16498
+ } catch {
16499
+ continue;
16500
+ }
16501
+ if (!quality || typeof quality !== "object" || Array.isArray(quality)) continue;
16502
+ const slim = JSON.stringify(compactHistoryQuality(quality));
16503
+ if (slim !== q) write.run(slim, rid);
16504
+ }
16505
+ });
16506
+ after = rows[rows.length - 1].rid;
16507
+ }
16508
+ db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(HISTORY_ATTR_SLIM_KEY, "done");
16509
+ }
16510
+
16511
+ // ../../packages/math/src/constants.ts
16512
+ var NEMORI_DEDUP_COSINE = 0.88;
16513
+
16514
+ // ../../packages/math/src/triage.ts
16515
+ var TRIAGE_GLOBAL_BUCKET = "*";
16516
+ function triageContextBuckets(ctx) {
16517
+ const out = [];
16518
+ for (const s of ctx.stack ?? []) {
16519
+ const t = s.trim().toLowerCase();
16520
+ if (t) out.push(`stack:${t}`);
16521
+ }
16522
+ const domains = Array.isArray(ctx.domain) ? ctx.domain : typeof ctx.domain === "string" ? [ctx.domain] : [];
16523
+ for (const d of domains) {
16524
+ const t = d.trim().toLowerCase();
16525
+ if (t) out.push(`domain:${t}`);
16526
+ }
16527
+ return out;
16528
+ }
16529
+
16530
+ // ../../packages/math/src/relevance.ts
16531
+ function pageRankScale(ranks) {
16532
+ const positive = [...ranks].filter((r) => Number.isFinite(r) && r > 0).sort((a, b) => a - b);
16533
+ return positive.length ? Math.max(1e-9, positive[Math.floor((positive.length - 1) * 0.95)]) : 1;
16534
+ }
16535
+
16536
+ // ../../packages/math/src/leiden.ts
16537
+ function buildGraph(nodeIds, adj) {
16538
+ const nbr = /* @__PURE__ */ new Map();
16539
+ const deg = /* @__PURE__ */ new Map();
16540
+ const present = new Set(nodeIds);
16541
+ for (const id of nodeIds) {
16542
+ nbr.set(id, /* @__PURE__ */ new Map());
16543
+ deg.set(id, 0);
16544
+ }
16545
+ let m2 = 0;
16546
+ for (const id of nodeIds) {
16547
+ for (const { to, weight } of adj.get(id) ?? []) {
16548
+ if (!present.has(to)) continue;
16549
+ const row = nbr.get(id);
16550
+ row.set(to, (row.get(to) ?? 0) + weight);
16551
+ deg.set(id, (deg.get(id) ?? 0) + weight);
16552
+ m2 += weight;
16553
+ }
16554
+ }
16555
+ return { nbr, deg, m2 };
16556
+ }
16557
+ function localMoving(nodeIds, g) {
16558
+ const community = new Map(nodeIds.map((n) => [n, n]));
16559
+ const comTot = new Map(nodeIds.map((n) => [n, g.deg.get(n) ?? 0]));
16560
+ const order = [...nodeIds].sort();
16561
+ const m2 = g.m2 > 0 ? g.m2 : 1;
16562
+ let improved = true;
16563
+ let iter = 0;
16564
+ while (improved && iter < 100) {
16565
+ improved = false;
16566
+ iter++;
16567
+ for (const node of order) {
16568
+ const ci = community.get(node);
16569
+ const ki = g.deg.get(node) ?? 0;
16570
+ comTot.set(ci, (comTot.get(ci) ?? 0) - ki);
16571
+ const wToComm = /* @__PURE__ */ new Map();
16572
+ for (const [nb, w] of g.nbr.get(node) ?? []) {
16573
+ if (nb === node) continue;
16574
+ const c = community.get(nb);
16575
+ wToComm.set(c, (wToComm.get(c) ?? 0) + w);
16576
+ }
16577
+ let bestC = ci;
16578
+ let bestGain = (wToComm.get(ci) ?? 0) - (comTot.get(ci) ?? 0) * ki / m2;
16579
+ for (const [c, kiIn] of [...wToComm.entries()].sort(
16580
+ (a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0
16581
+ )) {
16582
+ const gain = kiIn - (comTot.get(c) ?? 0) * ki / m2;
16583
+ if (gain > bestGain) {
16584
+ bestGain = gain;
16585
+ bestC = c;
16586
+ }
16587
+ }
16588
+ community.set(node, bestC);
16589
+ comTot.set(bestC, (comTot.get(bestC) ?? 0) + ki);
16590
+ if (bestC !== ci) improved = true;
16591
+ }
16592
+ }
16593
+ return community;
16594
+ }
16595
+ function refineConnectivity(community, g) {
16596
+ const members = /* @__PURE__ */ new Map();
16597
+ for (const [id, c] of community) {
16598
+ const l = members.get(c) ?? [];
16599
+ l.push(id);
16600
+ members.set(c, l);
16601
+ }
16602
+ const refined = /* @__PURE__ */ new Map();
16603
+ for (const [, group] of members) {
16604
+ const inGroup = new Set(group);
16605
+ const seen = /* @__PURE__ */ new Set();
16606
+ for (const start of [...group].sort()) {
16607
+ if (seen.has(start)) continue;
16608
+ const comp = [];
16609
+ const stack = [start];
16610
+ seen.add(start);
16611
+ while (stack.length) {
16612
+ const cur = stack.pop();
16613
+ comp.push(cur);
16614
+ for (const [nb] of g.nbr.get(cur) ?? []) {
16615
+ if (inGroup.has(nb) && !seen.has(nb)) {
16616
+ seen.add(nb);
16617
+ stack.push(nb);
16618
+ }
16619
+ }
16620
+ }
16621
+ const anchor = [...comp].sort()[0];
16622
+ for (const id of comp) refined.set(id, anchor);
16623
+ }
16624
+ }
16625
+ return refined;
16626
+ }
16627
+ function normalize(assignment) {
16628
+ const groups = /* @__PURE__ */ new Map();
16629
+ for (const [id, c] of assignment) {
16630
+ const l = groups.get(c) ?? [];
16631
+ l.push(id);
16632
+ groups.set(c, l);
16633
+ }
16634
+ const community = /* @__PURE__ */ new Map();
16635
+ for (const grp of groups.values()) {
16636
+ const anchor = [...grp].sort()[0];
16637
+ const cid = `community_${anchor}`;
16638
+ for (const m of grp) community.set(m, cid);
16639
+ }
16640
+ return { community, count: groups.size, iterations: 1 };
16641
+ }
16642
+ function causalComponents(nodeIds, pairs) {
16643
+ const parent = new Map(nodeIds.map((n) => [n, n]));
16644
+ const find = (x) => {
16645
+ let r = x;
16646
+ while (parent.get(r) !== r) r = parent.get(r);
16647
+ let c = x;
16648
+ while (parent.get(c) !== r) {
16649
+ const next = parent.get(c);
16650
+ parent.set(c, r);
16651
+ c = next;
16652
+ }
16653
+ return r;
16654
+ };
16655
+ for (const [a, b] of pairs) {
16656
+ const ra = find(a);
16657
+ const rb = find(b);
16658
+ if (ra !== rb) parent.set(ra < rb ? rb : ra, ra < rb ? ra : rb);
16659
+ }
16660
+ return find;
16661
+ }
16662
+ function detectCommunitiesLeiden(input, opts = {}) {
16663
+ const idSet = new Set(input.nodeIds);
16664
+ const protect = [...opts.protect ?? []].filter(
16665
+ ([a, b]) => a !== b && idSet.has(a) && idSet.has(b)
16666
+ );
16667
+ if (protect.length === 0) {
16668
+ const g = buildGraph(input.nodeIds, input.adj);
16669
+ return normalize(refineConnectivity(localMoving(input.nodeIds, g), g));
16670
+ }
16671
+ const rep = causalComponents(input.nodeIds, protect);
16672
+ const superIds = [...new Set(input.nodeIds.map(rep))];
16673
+ const superAdj = /* @__PURE__ */ new Map();
16674
+ const acc = /* @__PURE__ */ new Map();
16675
+ for (const id of input.nodeIds) {
16676
+ const ra = rep(id);
16677
+ for (const { to, weight } of input.adj.get(id) ?? []) {
16678
+ if (!idSet.has(to)) continue;
16679
+ const rb = rep(to);
16680
+ if (ra === rb) continue;
16681
+ const row = acc.get(ra) ?? /* @__PURE__ */ new Map();
16682
+ row.set(rb, (row.get(rb) ?? 0) + weight);
16683
+ acc.set(ra, row);
16684
+ }
16685
+ }
16686
+ for (const [a, row] of acc) superAdj.set(a, [...row].map(([to, weight]) => ({ to, weight })));
16687
+ const sg = buildGraph(superIds, superAdj);
16688
+ const superComm = refineConnectivity(localMoving(superIds, sg), sg);
16689
+ const assignment = /* @__PURE__ */ new Map();
16690
+ for (const id of input.nodeIds) assignment.set(id, superComm.get(rep(id)) ?? rep(id));
16691
+ return normalize(assignment);
16692
+ }
16693
+
16694
+ // ../../packages/math/src/void-demand.ts
16695
+ var DEMAND_HOT = Math.log1p(10);
16696
+ var DEMAND_WARM = Math.log1p(5);
16697
+
16399
16698
  // ../../packages/local-graph/src/store.ts
16699
+ var PAGE_RANK_SCALE_KEY = "pageRankScale.p95.v1";
16700
+ var TEXT_SEARCH_COLUMNS = `id, label, description, page_rank,
16701
+ json_object('test', json(CASE WHEN json_type(attrs_json, '$.test') = 'true' THEN 'true' ELSE 'false' END),
16702
+ 'relPath', json_extract(attrs_json, '$.relPath'),
16703
+ 'resolutionSuspect', json(CASE WHEN json_type(attrs_json, '$.resolutionSuspect') = 'true' THEN 'true' ELSE 'false' END),
16704
+ 'resolvedAt', json_extract(attrs_json, '$.resolvedAt'),
16705
+ 'refutedAt', json_extract(attrs_json, '$.refutedAt'),
16706
+ 'refuteReasons', json_extract(attrs_json, '$.refuteReasons'),
16707
+ 'reopenedFrom', json_extract(attrs_json, '$.reopenedFrom'),
16708
+ 'resolvedAs', json_extract(attrs_json, '$.resolvedAs')) AS search_attrs`;
16709
+ function textSearchNode(row) {
16710
+ const attrs = JSON.parse(row.search_attrs);
16711
+ return { id: row.id, label: row.label, description: row.description, pageRank: row.page_rank, attrs };
16712
+ }
16400
16713
  var LOCAL_RULE_OVERRIDES = {
16401
16714
  ANCHORED_AT: {
16402
16715
  from: EDGE_RULES["ANCHORED_AT"]?.from,
@@ -16540,6 +16853,9 @@ CREATE INDEX IF NOT EXISTS edges_session_evidence ON edges(id) WHERE ${SESSION_E
16540
16853
  DROP INDEX IF EXISTS nodes_live_fingerprint;
16541
16854
  DROP INDEX IF EXISTS nodes_instance_fingerprint;
16542
16855
  CREATE INDEX IF NOT EXISTS nodes_instance_fingerprint_v2 ON nodes(label, last_updated_at, last_reinforced_at_seq, created_at_seq) WHERE valid_to IS NULL AND label IN ('Problem','Vulnerability','Solution','RootCause');
16856
+ -- Calibrate rank from a covering scalar index; the global page-rank index
16857
+ -- requires a table lookup per node to exclude frozen versions.
16858
+ CREATE INDEX IF NOT EXISTS nodes_live_page_rank ON nodes(valid_to, page_rank);
16543
16859
  CREATE INDEX IF NOT EXISTS nodes_logical ON nodes(logical_id, version);
16544
16860
  CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
16545
16861
  -- Expression index on the per-node relPath (stored in attrs_json) so the
@@ -16552,6 +16868,16 @@ CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) W
16552
16868
  -- Problems by the file their anchor hint names: the harvest upgrades hints for
16553
16869
  -- every edited file of every turn, and a scan parses every Problem's attrs.
16554
16870
  CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_json, '$.anchorHint.path')) WHERE valid_to IS NULL;
16871
+ -- Problems by the command / checker / file that opened them. The generalizer
16872
+ -- looked these up per shell or tool EVENT by hydrating every Problem: ~12s of
16873
+ -- every minute of daemon main-thread time on a 3.4k-Problem store (2026-10-05).
16874
+ CREATE INDEX IF NOT EXISTS nodes_command_signature ON nodes(json_extract(attrs_json, '$.commandSignature')) WHERE valid_to IS NULL;
16875
+ CREATE INDEX IF NOT EXISTS nodes_diag_command ON nodes(json_extract(attrs_json, '$.diagCommand')) WHERE valid_to IS NULL;
16876
+ CREATE INDEX IF NOT EXISTS nodes_lsp_rel_path ON nodes(json_extract(attrs_json, '$.lspRelPath')) WHERE valid_to IS NULL;
16877
+ -- Local nodes by the cloud twin their upload receipt recorded. Every burst /
16878
+ -- search fusion folds the Network copy of the caller's own knowledge back onto
16879
+ -- the local node; unindexed, the reverse lookup was a ~300ms attrs scan per call.
16880
+ CREATE INDEX IF NOT EXISTS nodes_cloud_node_id ON nodes(json_extract(attrs_json, '$.cloudNodeId')) WHERE valid_to IS NULL;
16555
16881
  -- Nodes still waiting on a root-cause ask. The MCP server checks this on EVERY
16556
16882
  -- tool response (the enrichment piggyback), so it must not parse every
16557
16883
  -- Solution's and Problem's attrs per call. Not partial: the Problem pull reads
@@ -16638,6 +16964,7 @@ var SqliteGraphStore = class {
16638
16964
  * ALL upserts incl. code reindex) — this counter is the knowledge-arrival axis
16639
16965
  * Δseq is measured over, so code reindex churn must NOT advance it. */
16640
16966
  ingestSeq = 0;
16967
+ initialPageRankScale;
16641
16968
  constructor(opts) {
16642
16969
  this.db = openDatabase(opts.path);
16643
16970
  this.db.exec(SCHEMA_SQL);
@@ -16654,6 +16981,8 @@ var SqliteGraphStore = class {
16654
16981
  this.db.exec(TEMPORAL_INDEX_SQL);
16655
16982
  installHistoryCacheFloor(this.db);
16656
16983
  installEditPlaceholderRetirement(this.db);
16984
+ installCloudAttrCompaction(this.db);
16985
+ installHistoryAttrSlim(this.db);
16657
16986
  if (!this.db.prepare("SELECT value FROM store_meta WHERE key = ?").get(SESSION_REPAIR_KEY)) {
16658
16987
  this.db.transaction(() => {
16659
16988
  this.repairSessionAliases();
@@ -16705,6 +17034,12 @@ var SqliteGraphStore = class {
16705
17034
  setPageRank: this.db.prepare("UPDATE nodes SET page_rank = :v WHERE id = :id"),
16706
17035
  setLandmark: this.db.prepare("UPDATE nodes SET is_landmark = :v WHERE id = :id"),
16707
17036
  setCommunity: this.db.prepare("UPDATE nodes SET community = :v WHERE id = :id"),
17037
+ setLocalCommunity: this.db.prepare(`
17038
+ UPDATE nodes SET
17039
+ attrs_json = CASE WHEN :v IS NULL THEN json_remove(attrs_json, '$.localCommunity')
17040
+ ELSE json_set(attrs_json, '$.localCommunity', :v) END,
17041
+ community = CASE WHEN :col = 1 THEN :v ELSE community END
17042
+ WHERE id = :id`),
16708
17043
  updateNode: this.db.prepare(`
16709
17044
  UPDATE nodes SET
16710
17045
  description = COALESCE(:description, description),
@@ -17025,6 +17360,36 @@ var SqliteGraphStore = class {
17025
17360
  setLandmark(id, isLandmark) {
17026
17361
  this.stmts.setLandmark.run({ id, v: isLandmark ? 1 : 0 });
17027
17362
  }
17363
+ setLocalCommunity(id, community, column) {
17364
+ this.stmts.setLocalCommunity.run({ id, v: community, col: column ? 1 : 0 });
17365
+ }
17366
+ fieldStmts = /* @__PURE__ */ new Map();
17367
+ findNodeFieldsByLabel(label, attrKeys) {
17368
+ for (const k of attrKeys) if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) throw new Error(`findNodeFieldsByLabel: bad attr key ${k}`);
17369
+ const cacheKey = attrKeys.join(",");
17370
+ let stmt = this.fieldStmts.get(cacheKey);
17371
+ if (!stmt) {
17372
+ const cols = attrKeys.map((k, i) => `, json_extract(attrs_json, '$.${k}') AS a${i}`).join("");
17373
+ stmt = this.db.prepare(
17374
+ `SELECT id, description, community, extraction_confidence${cols} FROM nodes WHERE label = ? AND valid_to IS NULL`
17375
+ );
17376
+ this.fieldStmts.set(cacheKey, stmt);
17377
+ }
17378
+ return stmt.all(label).map((r) => {
17379
+ const attrs = {};
17380
+ attrKeys.forEach((k, i) => {
17381
+ const v = r[`a${i}`];
17382
+ if (v !== null && v !== void 0) attrs[k] = v;
17383
+ });
17384
+ return {
17385
+ id: r["id"],
17386
+ description: r["description"] ?? "",
17387
+ community: r["community"] ?? null,
17388
+ extractionConfidence: r["extraction_confidence"],
17389
+ attrs
17390
+ };
17391
+ });
17392
+ }
17028
17393
  setCommunity(id, community) {
17029
17394
  this.stmts.setCommunity.run({ id, v: community });
17030
17395
  }
@@ -17151,6 +17516,19 @@ var SqliteGraphStore = class {
17151
17516
  * read attrs and never the vector. `findNodesByLabel` decodes every embedding
17152
17517
  * blob; the liveness watch's coverage pass spent 3.4s of a 4.3s main-thread
17153
17518
  * hold doing exactly that on a 227k-node store (2026-09-24). */
17519
+ findNodeStampsByLabel(label, attrKey) {
17520
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attrKey)) throw new Error(`findNodeStampsByLabel: bad attr key ${attrKey}`);
17521
+ const rows = this.db.prepare(
17522
+ `SELECT id, created_at, created_at_seq, json_type(attrs_json, '$.${attrKey}') IS NOT NULL AS has
17523
+ FROM nodes WHERE label = ? AND valid_to IS NULL`
17524
+ ).all(label);
17525
+ return rows.map((r) => ({
17526
+ id: r.id,
17527
+ createdAt: r.created_at,
17528
+ ...r.created_at_seq != null ? { createdAtSeq: r.created_at_seq } : {},
17529
+ has: r.has === 1
17530
+ }));
17531
+ }
17154
17532
  findNodeAttrsByLabel(label) {
17155
17533
  const rows = this.stmts.attrsByLabel.all(label);
17156
17534
  return rows.map((r) => ({
@@ -17257,6 +17635,34 @@ var SqliteGraphStore = class {
17257
17635
  ).all(...terms.map((t) => `%${t}%`), Math.max(1, limit));
17258
17636
  return rows.map((r) => ({ node: rowToNode(r), matched: Number(r.matched) }));
17259
17637
  }
17638
+ searchTextCandidates(terms) {
17639
+ if (terms.length === 0) return [];
17640
+ const rows = this.db.prepare(`WITH matches AS MATERIALIZED (
17641
+ SELECT n.id, COUNT(*) AS matched FROM nodes n INDEXED BY nodes_live_description, json_each(:terms) t
17642
+ WHERE n.valid_to IS NULL AND n.description LIKE '%' || t.value || '%'
17643
+ GROUP BY n.id
17644
+ ) SELECT ${TEXT_SEARCH_COLUMNS}, matches.matched FROM nodes
17645
+ JOIN matches USING (id) ORDER BY page_rank DESC, last_updated_at DESC`).all({ terms: JSON.stringify(terms) });
17646
+ return rows.map((row) => ({ node: textSearchNode(row), matched: row.matched }));
17647
+ }
17648
+ getTextSearchNode(id) {
17649
+ const row = this.db.prepare(`SELECT ${TEXT_SEARCH_COLUMNS} FROM nodes WHERE id = ? AND valid_to IS NULL`).get(id);
17650
+ return row ? textSearchNode(row) : null;
17651
+ }
17652
+ readPageRankScale() {
17653
+ const rows = this.db.prepare("SELECT page_rank FROM nodes WHERE valid_to IS NULL AND page_rank > 0").all();
17654
+ return pageRankScale(rows.map((row) => row.page_rank));
17655
+ }
17656
+ pageRankScale() {
17657
+ const value = Number(this.getMeta(PAGE_RANK_SCALE_KEY));
17658
+ if (Number.isFinite(value) && value > 0) return value;
17659
+ return this.initialPageRankScale ??= this.readPageRankScale();
17660
+ }
17661
+ refreshPageRankScale() {
17662
+ const scale = this.readPageRankScale();
17663
+ this.setMeta(PAGE_RANK_SCALE_KEY, String(scale));
17664
+ return scale;
17665
+ }
17260
17666
  typedEdgeStmt(sql) {
17261
17667
  let stmt = this.typedEdgeStmts.get(sql);
17262
17668
  if (!stmt) {
@@ -17491,6 +17897,19 @@ var SqliteGraphStore = class {
17491
17897
  ).get(attr, `%${marker}%`, limit);
17492
17898
  return { count: Number(r.count), total: Number(r.total) };
17493
17899
  }
17900
+ liveNodeIdsByCloudNodeId(cloudIds) {
17901
+ const out = /* @__PURE__ */ new Map();
17902
+ const CHUNK = 900;
17903
+ for (let i = 0; i < cloudIds.length; i += CHUNK) {
17904
+ const slice = cloudIds.slice(i, i + CHUNK);
17905
+ if (slice.length === 0) continue;
17906
+ const rows = this.db.prepare(
17907
+ `SELECT id, json_extract(attrs_json, '$.cloudNodeId') AS cloud FROM nodes INDEXED BY nodes_cloud_node_id WHERE json_extract(attrs_json, '$.cloudNodeId') IN (${slice.map(() => "?").join(",")}) AND valid_to IS NULL ORDER BY id`
17908
+ ).all(...slice);
17909
+ for (const r of rows) out.set(r.cloud, [...out.get(r.cloud) ?? [], r.id]);
17910
+ }
17911
+ return out;
17912
+ }
17494
17913
  liveNodeIds(ids) {
17495
17914
  const live = /* @__PURE__ */ new Set();
17496
17915
  const CHUNK = 900;
@@ -17552,7 +17971,10 @@ var SqliteGraphStore = class {
17552
17971
  if (relPaths.length === 0) return [];
17553
17972
  const placeholders = relPaths.map(() => "?").join(",");
17554
17973
  const rows = this.db.prepare(
17555
- `SELECT * FROM nodes WHERE valid_to IS NULL AND json_extract(attrs_json, '$.relPath') IN (${placeholders})`
17974
+ // INDEXED BY: unforced, the planner took nodes_live_page_rank and
17975
+ // json-parsed every live row — 11–25s per reindexed file pair on the
17976
+ // live store vs 7ms here (2026-10-08).
17977
+ `SELECT * FROM nodes INDEXED BY nodes_relpath WHERE valid_to IS NULL AND json_extract(attrs_json, '$.relPath') IN (${placeholders})`
17556
17978
  ).all(...relPaths);
17557
17979
  return rows.map(rowToNode);
17558
17980
  }
@@ -17802,183 +18224,6 @@ function percolate(l1, l2, opts) {
17802
18224
  init_src();
17803
18225
  init_src2();
17804
18226
 
17805
- // ../../packages/math/src/constants.ts
17806
- var NEMORI_DEDUP_COSINE = 0.88;
17807
-
17808
- // ../../packages/math/src/triage.ts
17809
- var TRIAGE_GLOBAL_BUCKET = "*";
17810
- function triageContextBuckets(ctx) {
17811
- const out = [];
17812
- for (const s of ctx.stack ?? []) {
17813
- const t = s.trim().toLowerCase();
17814
- if (t) out.push(`stack:${t}`);
17815
- }
17816
- const domains = Array.isArray(ctx.domain) ? ctx.domain : typeof ctx.domain === "string" ? [ctx.domain] : [];
17817
- for (const d of domains) {
17818
- const t = d.trim().toLowerCase();
17819
- if (t) out.push(`domain:${t}`);
17820
- }
17821
- return out;
17822
- }
17823
-
17824
- // ../../packages/math/src/leiden.ts
17825
- function buildGraph(nodeIds, adj) {
17826
- const nbr = /* @__PURE__ */ new Map();
17827
- const deg = /* @__PURE__ */ new Map();
17828
- const present = new Set(nodeIds);
17829
- for (const id of nodeIds) {
17830
- nbr.set(id, /* @__PURE__ */ new Map());
17831
- deg.set(id, 0);
17832
- }
17833
- let m2 = 0;
17834
- for (const id of nodeIds) {
17835
- for (const { to, weight } of adj.get(id) ?? []) {
17836
- if (!present.has(to)) continue;
17837
- const row = nbr.get(id);
17838
- row.set(to, (row.get(to) ?? 0) + weight);
17839
- deg.set(id, (deg.get(id) ?? 0) + weight);
17840
- m2 += weight;
17841
- }
17842
- }
17843
- return { nbr, deg, m2 };
17844
- }
17845
- function localMoving(nodeIds, g) {
17846
- const community = new Map(nodeIds.map((n) => [n, n]));
17847
- const comTot = new Map(nodeIds.map((n) => [n, g.deg.get(n) ?? 0]));
17848
- const order = [...nodeIds].sort();
17849
- const m2 = g.m2 > 0 ? g.m2 : 1;
17850
- let improved = true;
17851
- let iter = 0;
17852
- while (improved && iter < 100) {
17853
- improved = false;
17854
- iter++;
17855
- for (const node of order) {
17856
- const ci = community.get(node);
17857
- const ki = g.deg.get(node) ?? 0;
17858
- comTot.set(ci, (comTot.get(ci) ?? 0) - ki);
17859
- const wToComm = /* @__PURE__ */ new Map();
17860
- for (const [nb, w] of g.nbr.get(node) ?? []) {
17861
- if (nb === node) continue;
17862
- const c = community.get(nb);
17863
- wToComm.set(c, (wToComm.get(c) ?? 0) + w);
17864
- }
17865
- let bestC = ci;
17866
- let bestGain = (wToComm.get(ci) ?? 0) - (comTot.get(ci) ?? 0) * ki / m2;
17867
- for (const [c, kiIn] of [...wToComm.entries()].sort(
17868
- (a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0
17869
- )) {
17870
- const gain = kiIn - (comTot.get(c) ?? 0) * ki / m2;
17871
- if (gain > bestGain) {
17872
- bestGain = gain;
17873
- bestC = c;
17874
- }
17875
- }
17876
- community.set(node, bestC);
17877
- comTot.set(bestC, (comTot.get(bestC) ?? 0) + ki);
17878
- if (bestC !== ci) improved = true;
17879
- }
17880
- }
17881
- return community;
17882
- }
17883
- function refineConnectivity(community, g) {
17884
- const members = /* @__PURE__ */ new Map();
17885
- for (const [id, c] of community) {
17886
- const l = members.get(c) ?? [];
17887
- l.push(id);
17888
- members.set(c, l);
17889
- }
17890
- const refined = /* @__PURE__ */ new Map();
17891
- for (const [, group] of members) {
17892
- const inGroup = new Set(group);
17893
- const seen = /* @__PURE__ */ new Set();
17894
- for (const start of [...group].sort()) {
17895
- if (seen.has(start)) continue;
17896
- const comp = [];
17897
- const stack = [start];
17898
- seen.add(start);
17899
- while (stack.length) {
17900
- const cur = stack.pop();
17901
- comp.push(cur);
17902
- for (const [nb] of g.nbr.get(cur) ?? []) {
17903
- if (inGroup.has(nb) && !seen.has(nb)) {
17904
- seen.add(nb);
17905
- stack.push(nb);
17906
- }
17907
- }
17908
- }
17909
- const anchor = [...comp].sort()[0];
17910
- for (const id of comp) refined.set(id, anchor);
17911
- }
17912
- }
17913
- return refined;
17914
- }
17915
- function normalize(assignment) {
17916
- const groups = /* @__PURE__ */ new Map();
17917
- for (const [id, c] of assignment) {
17918
- const l = groups.get(c) ?? [];
17919
- l.push(id);
17920
- groups.set(c, l);
17921
- }
17922
- const community = /* @__PURE__ */ new Map();
17923
- for (const grp of groups.values()) {
17924
- const anchor = [...grp].sort()[0];
17925
- const cid = `community_${anchor}`;
17926
- for (const m of grp) community.set(m, cid);
17927
- }
17928
- return { community, count: groups.size, iterations: 1 };
17929
- }
17930
- function causalComponents(nodeIds, pairs) {
17931
- const parent = new Map(nodeIds.map((n) => [n, n]));
17932
- const find = (x) => {
17933
- let r = x;
17934
- while (parent.get(r) !== r) r = parent.get(r);
17935
- let c = x;
17936
- while (parent.get(c) !== r) {
17937
- const next = parent.get(c);
17938
- parent.set(c, r);
17939
- c = next;
17940
- }
17941
- return r;
17942
- };
17943
- for (const [a, b] of pairs) {
17944
- const ra = find(a);
17945
- const rb = find(b);
17946
- if (ra !== rb) parent.set(ra < rb ? rb : ra, ra < rb ? ra : rb);
17947
- }
17948
- return find;
17949
- }
17950
- function detectCommunitiesLeiden(input, opts = {}) {
17951
- const idSet = new Set(input.nodeIds);
17952
- const protect = [...opts.protect ?? []].filter(
17953
- ([a, b]) => a !== b && idSet.has(a) && idSet.has(b)
17954
- );
17955
- if (protect.length === 0) {
17956
- const g = buildGraph(input.nodeIds, input.adj);
17957
- return normalize(refineConnectivity(localMoving(input.nodeIds, g), g));
17958
- }
17959
- const rep = causalComponents(input.nodeIds, protect);
17960
- const superIds = [...new Set(input.nodeIds.map(rep))];
17961
- const superAdj = /* @__PURE__ */ new Map();
17962
- const acc = /* @__PURE__ */ new Map();
17963
- for (const id of input.nodeIds) {
17964
- const ra = rep(id);
17965
- for (const { to, weight } of input.adj.get(id) ?? []) {
17966
- if (!idSet.has(to)) continue;
17967
- const rb = rep(to);
17968
- if (ra === rb) continue;
17969
- const row = acc.get(ra) ?? /* @__PURE__ */ new Map();
17970
- row.set(rb, (row.get(rb) ?? 0) + weight);
17971
- acc.set(ra, row);
17972
- }
17973
- }
17974
- for (const [a, row] of acc) superAdj.set(a, [...row].map(([to, weight]) => ({ to, weight })));
17975
- const sg = buildGraph(superIds, superAdj);
17976
- const superComm = refineConnectivity(localMoving(superIds, sg), sg);
17977
- const assignment = /* @__PURE__ */ new Map();
17978
- for (const id of input.nodeIds) assignment.set(id, superComm.get(rep(id)) ?? rep(id));
17979
- return normalize(assignment);
17980
- }
17981
-
17982
18227
  // ../../packages/local-graph/src/triage.ts
17983
18228
  init_src();
17984
18229
  init_src();
@@ -19368,7 +19613,7 @@ var DOC_COMMENT_KINDS = /* @__PURE__ */ new Set(["docstring", "explanation"]);
19368
19613
  var MAX_DOC_CHARS = 600;
19369
19614
  function buildDocIndex(store) {
19370
19615
  const byName = /* @__PURE__ */ new Map();
19371
- for (const c of store.findNodesByLabel("Comment")) {
19616
+ for (const c of store.findNodeFieldsByLabel("Comment", ["attachedTo", "kind", "text"])) {
19372
19617
  const name = c.attrs["attachedTo"];
19373
19618
  const kind = c.attrs["kind"];
19374
19619
  if (typeof name !== "string" || !name) continue;
@@ -19384,7 +19629,7 @@ function buildSymbolLexicon(store) {
19384
19629
  const docs = buildDocIndex(store);
19385
19630
  const candidates = [];
19386
19631
  for (const [label, kind] of SYMBOL_LABELS) {
19387
- for (const n of store.findNodesByLabel(label)) {
19632
+ for (const n of store.findNodeFieldsByLabel(label, ["qname"])) {
19388
19633
  const qname = String(n.attrs["qname"] ?? "");
19389
19634
  const doc = (n.description ? docs.get(n.description) : void 0) ?? (qname ? docs.get(qname) : void 0);
19390
19635
  for (const name of [n.description, qname]) {
@@ -19490,7 +19735,7 @@ function buildFileLexicon(store) {
19490
19735
  const basenameCount = /* @__PURE__ */ new Map();
19491
19736
  const stemRelPaths = /* @__PURE__ */ new Map();
19492
19737
  const entries = [];
19493
- for (const n of store.findNodesByLabel("File")) {
19738
+ for (const n of store.findNodeFieldsByLabel("File", ["relPath"])) {
19494
19739
  const relPath = typeof n.attrs["relPath"] === "string" && n.attrs["relPath"].length > 0 ? n.attrs["relPath"] : n.description;
19495
19740
  if (!relPath) continue;
19496
19741
  const basename = relPath.split("/").pop();
@@ -19812,9 +20057,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
19812
20057
  collapsedEdges: 0
19813
20058
  };
19814
20059
  const sharedCauses = /* @__PURE__ */ new Map();
19815
- const causalQueue = store.findNodesByLabel("Problem").filter(
19816
- (n) => n.attrs["source"] !== "cloud" && n.attrs["resolvedAs"] !== PROBLEM_RESOLUTION.FALSE_POSITIVE && !ignored(n.description)
19817
- ).map((n) => n.id);
20060
+ const causalQueue = store.findNodeFieldsByLabel("Problem", ["source", "resolvedAs"]).filter((r) => r.attrs["source"] !== "cloud" && r.attrs["resolvedAs"] !== PROBLEM_RESOLUTION.FALSE_POSITIVE).map((r) => r.id).filter((id) => ignorePatterns.length === 0 || !ignored(store.getNode(id)?.description ?? ""));
19818
20061
  const causalSeen = new Set(causalQueue);
19819
20062
  for (let i = 0; i < causalQueue.length; i++) {
19820
20063
  const id = causalQueue[i];
@@ -19830,7 +20073,20 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
19830
20073
  for (const label of INSTANCE_LABELS) {
19831
20074
  const ref = [];
19832
20075
  includedByLabel.set(label, ref);
19833
- const population = label === "RootCause" && opts.sharedStore ? [...store.findNodesByLabel(label), ...sharedCauses.values()] : store.findNodesByLabel(label);
20076
+ const local = [];
20077
+ for (const row of store.findNodeFieldsByLabel(label, ["source", "privateFinding"])) {
20078
+ if (row.attrs["source"] !== "cloud") {
20079
+ const n = store.getNode(row.id);
20080
+ if (n) local.push(n);
20081
+ continue;
20082
+ }
20083
+ if (seen.has(row.id) || walked.has(row.id)) continue;
20084
+ walked.add(row.id);
20085
+ composition.candidates++;
20086
+ if ((row.attrs["privateFinding"] || label === "Vulnerability") && !opts.project) composition.privateTargetMissing++;
20087
+ else composition.cloudSourced++;
20088
+ }
20089
+ const population = label === "RootCause" && opts.sharedStore ? [...local, ...sharedCauses.values()] : local;
19834
20090
  for (const n of population) {
19835
20091
  if (seen.has(n.id)) continue;
19836
20092
  if (walked.has(n.id)) continue;