@inerrata-corporation/errata 2.0.6-dev.2627 → 2.0.6-dev.2632

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.
@@ -16143,6 +16143,9 @@ CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
16143
16143
  -- incremental reindex can fetch just the changed files' symbols instead of
16144
16144
  -- scanning every versioned node. Partial: only live rows are ever queried.
16145
16145
  CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.relPath')) WHERE valid_to IS NULL;
16146
+ -- Live rows by name, for looking up the few symbols a statement mentions
16147
+ -- instead of hydrating every code symbol per minted problem.
16148
+ CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) WHERE valid_to IS NULL;
16146
16149
  `;
16147
16150
  function encodeEmbedding(emb) {
16148
16151
  if (!emb || emb.length === 0) return null;
@@ -16957,6 +16960,21 @@ var SqliteGraphStore = class {
16957
16960
  /** Live nodes whose attrs.relPath is one of `relPaths`. Uses the nodes_relpath
16958
16961
  * expression index so the incremental reindex fetches only the changed files'
16959
16962
  * symbols instead of scanning every versioned node. */
16963
+ /** Live nodes of `labels` whose description is exactly one of `names`, via
16964
+ * the nodes_live_description index. Chunked under the bound-parameter cap. */
16965
+ liveNodesByDescription(names, labels) {
16966
+ if (names.length === 0 || labels.length === 0) return [];
16967
+ const out = [];
16968
+ const labelPh = labels.map(() => "?").join(",");
16969
+ for (let i = 0; i < names.length; i += 400) {
16970
+ const chunk = names.slice(i, i + 400);
16971
+ const rows = this.db.prepare(
16972
+ `SELECT * FROM nodes WHERE valid_to IS NULL AND description IN (${chunk.map(() => "?").join(",")}) AND label IN (${labelPh})`
16973
+ ).all(...chunk, ...labels);
16974
+ for (const r of rows) out.push(rowToNode(r));
16975
+ }
16976
+ return out;
16977
+ }
16960
16978
  nodesByRelPath(relPaths) {
16961
16979
  if (relPaths.length === 0) return [];
16962
16980
  const placeholders = relPaths.map(() => "?").join(",");
package/errata.mjs CHANGED
@@ -17560,6 +17560,9 @@ CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
17560
17560
  -- incremental reindex can fetch just the changed files' symbols instead of
17561
17561
  -- scanning every versioned node. Partial: only live rows are ever queried.
17562
17562
  CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.relPath')) WHERE valid_to IS NULL;
17563
+ -- Live rows by name, for looking up the few symbols a statement mentions
17564
+ -- instead of hydrating every code symbol per minted problem.
17565
+ CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) WHERE valid_to IS NULL;
17563
17566
  `;
17564
17567
  SqliteGraphStore = class {
17565
17568
  db;
@@ -18317,6 +18320,21 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
18317
18320
  /** Live nodes whose attrs.relPath is one of `relPaths`. Uses the nodes_relpath
18318
18321
  * expression index so the incremental reindex fetches only the changed files'
18319
18322
  * symbols instead of scanning every versioned node. */
18323
+ /** Live nodes of `labels` whose description is exactly one of `names`, via
18324
+ * the nodes_live_description index. Chunked under the bound-parameter cap. */
18325
+ liveNodesByDescription(names, labels) {
18326
+ if (names.length === 0 || labels.length === 0) return [];
18327
+ const out2 = [];
18328
+ const labelPh = labels.map(() => "?").join(",");
18329
+ for (let i2 = 0; i2 < names.length; i2 += 400) {
18330
+ const chunk = names.slice(i2, i2 + 400);
18331
+ const rows = this.db.prepare(
18332
+ `SELECT * FROM nodes WHERE valid_to IS NULL AND description IN (${chunk.map(() => "?").join(",")}) AND label IN (${labelPh})`
18333
+ ).all(...chunk, ...labels);
18334
+ for (const r of rows) out2.push(rowToNode(r));
18335
+ }
18336
+ return out2;
18337
+ }
18320
18338
  nodesByRelPath(relPaths) {
18321
18339
  if (relPaths.length === 0) return [];
18322
18340
  const placeholders = relPaths.map(() => "?").join(",");
@@ -19303,6 +19321,33 @@ function buildSymbolIndex(store) {
19303
19321
  }
19304
19322
  return idx;
19305
19323
  }
19324
+ function symbolCandidatesInText(text) {
19325
+ const out2 = /* @__PURE__ */ new Set();
19326
+ for (const run3 of text.match(/[\w$.]+/g) ?? []) {
19327
+ const segs = run3.split(".");
19328
+ for (let i2 = 0; i2 < segs.length; i2++) {
19329
+ if (!segs[i2]) continue;
19330
+ let name2 = "";
19331
+ for (let j = i2; j < segs.length && segs[j]; j++) {
19332
+ name2 = j === i2 ? segs[j] : `${name2}.${segs[j]}`;
19333
+ if (isShapedSymbol(name2)) out2.add(name2);
19334
+ }
19335
+ }
19336
+ }
19337
+ return [...out2];
19338
+ }
19339
+ function symbolIndexForText(store, text) {
19340
+ const counts = /* @__PURE__ */ new Map();
19341
+ for (const n of store.liveNodesByDescription(symbolCandidatesInText(text), SYMBOL_LABELS)) {
19342
+ const name2 = n.description.trim();
19343
+ const list = counts.get(name2);
19344
+ if (list) list.push(n);
19345
+ else counts.set(name2, [n]);
19346
+ }
19347
+ const idx = /* @__PURE__ */ new Map();
19348
+ for (const [name2, nodes] of counts) if (nodes.length === 1) idx.set(name2, nodes[0]);
19349
+ return idx;
19350
+ }
19306
19351
  function matchSymbolsInText(text, index) {
19307
19352
  const out2 = [];
19308
19353
  for (const [name2, node2] of index) {
@@ -19315,19 +19360,9 @@ function matchSymbolsInText(text, index) {
19315
19360
  function linkProblemToSymbols(store, problemId, text, ts, index) {
19316
19361
  const p = store.getNode(problemId);
19317
19362
  if (!p || p.label !== "Problem") return [];
19318
- const idx = index ?? buildSymbolIndex(store);
19363
+ const idx = index ?? symbolIndexForText(store, text);
19319
19364
  if (idx.size === 0) return [];
19320
- let fileByPath = null;
19321
- const fileFor2 = (relPath) => {
19322
- if (!fileByPath) {
19323
- fileByPath = /* @__PURE__ */ new Map();
19324
- for (const f of store.findNodesByLabel("File")) {
19325
- const rp = String(f.attrs["relPath"] ?? f.description ?? "");
19326
- if (rp) fileByPath.set(rp, f);
19327
- }
19328
- }
19329
- return fileByPath.get(relPath) ?? null;
19330
- };
19365
+ const fileFor2 = (relPath) => store.nodesByRelPath([relPath]).find((f) => f.label === "File") ?? null;
19331
19366
  const already = new Set(store.outEdges(problemId, ["ANCHORED_AT"]).map((e) => e.to));
19332
19367
  const linked = [];
19333
19368
  for (const sym of matchSymbolsInText(text, idx)) {
@@ -24052,6 +24087,8 @@ __export(src_exports2, {
24052
24087
  stampObservedOs: () => stampObservedOs,
24053
24088
  statementIdentityKey: () => statementIdentityKey,
24054
24089
  staticConductance: () => staticConductance,
24090
+ symbolCandidatesInText: () => symbolCandidatesInText,
24091
+ symbolIndexForText: () => symbolIndexForText,
24055
24092
  toolNodeId: () => toolNodeId,
24056
24093
  toolPriorsFor: () => toolPriorsFor,
24057
24094
  triageOf: () => triageOf,
@@ -78478,7 +78515,7 @@ function createWatchBreaker(deps) {
78478
78515
  }
78479
78516
 
78480
78517
  // src/engine.ts
78481
- var DAEMON_VERSION = true ? "2.0.6-dev.2627" : "2.0.0-alpha.0";
78518
+ var DAEMON_VERSION = true ? "2.0.6-dev.2632" : "2.0.0-alpha.0";
78482
78519
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
78483
78520
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
78484
78521
  var GIT_OP_MUTE_MS = 4e3;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.6-dev.2627",
3
+ "version": "2.0.6-dev.2632",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -24525,6 +24525,9 @@ CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
24525
24525
  -- incremental reindex can fetch just the changed files' symbols instead of
24526
24526
  -- scanning every versioned node. Partial: only live rows are ever queried.
24527
24527
  CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.relPath')) WHERE valid_to IS NULL;
24528
+ -- Live rows by name, for looking up the few symbols a statement mentions
24529
+ -- instead of hydrating every code symbol per minted problem.
24530
+ CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) WHERE valid_to IS NULL;
24528
24531
  `;
24529
24532
  function encodeEmbedding(emb) {
24530
24533
  if (!emb || emb.length === 0) return null;
@@ -25339,6 +25342,21 @@ var SqliteGraphStore = class {
25339
25342
  /** Live nodes whose attrs.relPath is one of `relPaths`. Uses the nodes_relpath
25340
25343
  * expression index so the incremental reindex fetches only the changed files'
25341
25344
  * symbols instead of scanning every versioned node. */
25345
+ /** Live nodes of `labels` whose description is exactly one of `names`, via
25346
+ * the nodes_live_description index. Chunked under the bound-parameter cap. */
25347
+ liveNodesByDescription(names, labels) {
25348
+ if (names.length === 0 || labels.length === 0) return [];
25349
+ const out2 = [];
25350
+ const labelPh = labels.map(() => "?").join(",");
25351
+ for (let i2 = 0; i2 < names.length; i2 += 400) {
25352
+ const chunk = names.slice(i2, i2 + 400);
25353
+ const rows = this.db.prepare(
25354
+ `SELECT * FROM nodes WHERE valid_to IS NULL AND description IN (${chunk.map(() => "?").join(",")}) AND label IN (${labelPh})`
25355
+ ).all(...chunk, ...labels);
25356
+ for (const r of rows) out2.push(rowToNode(r));
25357
+ }
25358
+ return out2;
25359
+ }
25342
25360
  nodesByRelPath(relPaths) {
25343
25361
  if (relPaths.length === 0) return [];
25344
25362
  const placeholders = relPaths.map(() => "?").join(",");