@inerrata-corporation/errata 2.0.6-dev.2621 → 2.0.6-dev.2627
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 +34 -1
- package/errata.mjs +49 -14
- package/package.json +1 -1
- package/pass-worker.mjs +35 -2
package/consolidate-worker.mjs
CHANGED
|
@@ -16400,8 +16400,16 @@ var SqliteGraphStore = class {
|
|
|
16400
16400
|
closeEdge: this.db.prepare(
|
|
16401
16401
|
"UPDATE edges SET valid_to = :t WHERE id = :id AND valid_to IS NULL"
|
|
16402
16402
|
),
|
|
16403
|
+
// Same rows as `COALESCE(logical_id, id) = ?`, split so each branch can use
|
|
16404
|
+
// an index (nodes_logical, then the id primary key). The COALESCE form made
|
|
16405
|
+
// SQLite SCAN nodes: 0.4-0.9s per call on a 227k-node store, once per new
|
|
16406
|
+
// diagnostic via attributeRootCause (2026-09-24).
|
|
16403
16407
|
nodeHistory: this.db.prepare(
|
|
16404
|
-
|
|
16408
|
+
`SELECT * FROM (
|
|
16409
|
+
SELECT * FROM nodes WHERE logical_id = ?1
|
|
16410
|
+
UNION ALL
|
|
16411
|
+
SELECT * FROM nodes WHERE id = ?1 AND logical_id IS NULL
|
|
16412
|
+
) ORDER BY version ASC`
|
|
16405
16413
|
),
|
|
16406
16414
|
nodesAsOf: this.db.prepare(
|
|
16407
16415
|
"SELECT * FROM nodes WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)"
|
|
@@ -16729,6 +16737,18 @@ var SqliteGraphStore = class {
|
|
|
16729
16737
|
).all(params);
|
|
16730
16738
|
return rows.map(rowToEdge);
|
|
16731
16739
|
}
|
|
16740
|
+
/** Live in-degree per target over `types`, in one grouped query — the counts
|
|
16741
|
+
* `inEdges(id, types).length` gives, for every node at once. A per-node
|
|
16742
|
+
* inEdges loop over ~48k code nodes held a PreToolUse hook 12.6s when the
|
|
16743
|
+
* hotspots vfile materialized (2026-09-24). */
|
|
16744
|
+
inDegreeByType(types) {
|
|
16745
|
+
if (types.length === 0) return /* @__PURE__ */ new Map();
|
|
16746
|
+
const placeholders = types.map(() => "?").join(",");
|
|
16747
|
+
const rows = this.db.prepare(
|
|
16748
|
+
`SELECT to_id, COUNT(*) AS n FROM edges WHERE type IN (${placeholders}) AND valid_to IS NULL GROUP BY to_id`
|
|
16749
|
+
).all(...types);
|
|
16750
|
+
return new Map(rows.map((r) => [r.to_id, Number(r.n)]));
|
|
16751
|
+
}
|
|
16732
16752
|
neighbors(nodeId, types) {
|
|
16733
16753
|
const out = [];
|
|
16734
16754
|
const edges = this.outEdges(nodeId, types);
|
|
@@ -16991,6 +17011,19 @@ var SqliteGraphStore = class {
|
|
|
16991
17011
|
const rows = this.stmts.nodesAsOf.all({ t });
|
|
16992
17012
|
return rows.map(rowToNode);
|
|
16993
17013
|
}
|
|
17014
|
+
/** `nodesAsOf(t).filter((n) => n.attrs[attr] === true)` with the attr test in
|
|
17015
|
+
* SQL, so only the flagged rows are hydrated. The filter-after form hydrated
|
|
17016
|
+
* the whole graph for a handful of revisit flags: 6.7s per context render on
|
|
17017
|
+
* a 227k-node store (2026-09-24). `attr` is interpolated into a JSON path,
|
|
17018
|
+
* so it must be a plain identifier. */
|
|
17019
|
+
nodesAsOfWhereTrue(t, attr) {
|
|
17020
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attr)) throw new Error(`nodesAsOfWhereTrue: bad attr ${JSON.stringify(attr)}`);
|
|
17021
|
+
const rows = this.db.prepare(
|
|
17022
|
+
`SELECT * FROM nodes WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)
|
|
17023
|
+
AND json_type(attrs_json, '$.${attr}') = 'true'`
|
|
17024
|
+
).all({ t });
|
|
17025
|
+
return rows.map(rowToNode);
|
|
17026
|
+
}
|
|
16994
17027
|
edgesAsOf(t) {
|
|
16995
17028
|
const rows = this.stmts.edgesAsOf.all({ t });
|
|
16996
17029
|
return rows.map(rowToEdge);
|
package/errata.mjs
CHANGED
|
@@ -17760,8 +17760,16 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
|
|
|
17760
17760
|
closeEdge: this.db.prepare(
|
|
17761
17761
|
"UPDATE edges SET valid_to = :t WHERE id = :id AND valid_to IS NULL"
|
|
17762
17762
|
),
|
|
17763
|
+
// Same rows as `COALESCE(logical_id, id) = ?`, split so each branch can use
|
|
17764
|
+
// an index (nodes_logical, then the id primary key). The COALESCE form made
|
|
17765
|
+
// SQLite SCAN nodes: 0.4-0.9s per call on a 227k-node store, once per new
|
|
17766
|
+
// diagnostic via attributeRootCause (2026-09-24).
|
|
17763
17767
|
nodeHistory: this.db.prepare(
|
|
17764
|
-
|
|
17768
|
+
`SELECT * FROM (
|
|
17769
|
+
SELECT * FROM nodes WHERE logical_id = ?1
|
|
17770
|
+
UNION ALL
|
|
17771
|
+
SELECT * FROM nodes WHERE id = ?1 AND logical_id IS NULL
|
|
17772
|
+
) ORDER BY version ASC`
|
|
17765
17773
|
),
|
|
17766
17774
|
nodesAsOf: this.db.prepare(
|
|
17767
17775
|
"SELECT * FROM nodes WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)"
|
|
@@ -18089,6 +18097,18 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
|
|
|
18089
18097
|
).all(params);
|
|
18090
18098
|
return rows.map(rowToEdge);
|
|
18091
18099
|
}
|
|
18100
|
+
/** Live in-degree per target over `types`, in one grouped query — the counts
|
|
18101
|
+
* `inEdges(id, types).length` gives, for every node at once. A per-node
|
|
18102
|
+
* inEdges loop over ~48k code nodes held a PreToolUse hook 12.6s when the
|
|
18103
|
+
* hotspots vfile materialized (2026-09-24). */
|
|
18104
|
+
inDegreeByType(types) {
|
|
18105
|
+
if (types.length === 0) return /* @__PURE__ */ new Map();
|
|
18106
|
+
const placeholders = types.map(() => "?").join(",");
|
|
18107
|
+
const rows = this.db.prepare(
|
|
18108
|
+
`SELECT to_id, COUNT(*) AS n FROM edges WHERE type IN (${placeholders}) AND valid_to IS NULL GROUP BY to_id`
|
|
18109
|
+
).all(...types);
|
|
18110
|
+
return new Map(rows.map((r) => [r.to_id, Number(r.n)]));
|
|
18111
|
+
}
|
|
18092
18112
|
neighbors(nodeId, types) {
|
|
18093
18113
|
const out2 = [];
|
|
18094
18114
|
const edges = this.outEdges(nodeId, types);
|
|
@@ -18351,6 +18371,19 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
|
|
|
18351
18371
|
const rows = this.stmts.nodesAsOf.all({ t });
|
|
18352
18372
|
return rows.map(rowToNode);
|
|
18353
18373
|
}
|
|
18374
|
+
/** `nodesAsOf(t).filter((n) => n.attrs[attr] === true)` with the attr test in
|
|
18375
|
+
* SQL, so only the flagged rows are hydrated. The filter-after form hydrated
|
|
18376
|
+
* the whole graph for a handful of revisit flags: 6.7s per context render on
|
|
18377
|
+
* a 227k-node store (2026-09-24). `attr` is interpolated into a JSON path,
|
|
18378
|
+
* so it must be a plain identifier. */
|
|
18379
|
+
nodesAsOfWhereTrue(t, attr) {
|
|
18380
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attr)) throw new Error(`nodesAsOfWhereTrue: bad attr ${JSON.stringify(attr)}`);
|
|
18381
|
+
const rows = this.db.prepare(
|
|
18382
|
+
`SELECT * FROM nodes WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)
|
|
18383
|
+
AND json_type(attrs_json, '$.${attr}') = 'true'`
|
|
18384
|
+
).all({ t });
|
|
18385
|
+
return rows.map(rowToNode);
|
|
18386
|
+
}
|
|
18354
18387
|
edgesAsOf(t) {
|
|
18355
18388
|
const rows = this.stmts.edgesAsOf.all({ t });
|
|
18356
18389
|
return rows.map(rowToEdge);
|
|
@@ -18757,7 +18790,7 @@ function clearRevisit(store, nodeId, ts) {
|
|
|
18757
18790
|
store.updateNode(nodeId, { attrs, lastUpdatedAt: ts });
|
|
18758
18791
|
}
|
|
18759
18792
|
function listNeedsRevisit(store, asOf) {
|
|
18760
|
-
return store.
|
|
18793
|
+
return store.nodesAsOfWhereTrue(asOf, "revisit").map((n) => ({
|
|
18761
18794
|
id: n.id,
|
|
18762
18795
|
label: n.label,
|
|
18763
18796
|
description: n.description,
|
|
@@ -31739,16 +31772,17 @@ function diagnosticKey(relPath, d) {
|
|
|
31739
31772
|
function anchorByLine(store, workspaceId2, relPath, line) {
|
|
31740
31773
|
let best = null;
|
|
31741
31774
|
let bestRow = -1;
|
|
31742
|
-
|
|
31743
|
-
|
|
31744
|
-
|
|
31745
|
-
|
|
31746
|
-
|
|
31747
|
-
|
|
31748
|
-
|
|
31749
|
-
|
|
31750
|
-
|
|
31751
|
-
|
|
31775
|
+
const labelRank = { Function: 0, Method: 1, Class: 2 };
|
|
31776
|
+
for (const n of store.nodesByRelPath([relPath])) {
|
|
31777
|
+
const rank = labelRank[n.label];
|
|
31778
|
+
if (rank === void 0) continue;
|
|
31779
|
+
if (n.attrs["workspaceId"] !== workspaceId2) continue;
|
|
31780
|
+
if (n.attrs["relPath"] !== relPath) continue;
|
|
31781
|
+
const row = n.attrs["startRow"];
|
|
31782
|
+
if (typeof row !== "number" || row > line) continue;
|
|
31783
|
+
if (row > bestRow || row === bestRow && best !== null && rank < labelRank[best.label]) {
|
|
31784
|
+
bestRow = row;
|
|
31785
|
+
best = n;
|
|
31752
31786
|
}
|
|
31753
31787
|
}
|
|
31754
31788
|
return best ? best.logicalId ?? best.id : null;
|
|
@@ -42800,7 +42834,8 @@ var init_mcp = __esm({
|
|
|
42800
42834
|
items: dead.slice(0, limit)
|
|
42801
42835
|
};
|
|
42802
42836
|
}
|
|
42803
|
-
const
|
|
42837
|
+
const fanIn = store.inDegreeByType([...CODE_REACH_EDGES]);
|
|
42838
|
+
const ranked = codeNodes.map((n) => ({ id: n.id, label: n.label, name: n.description, fanIn: fanIn.get(n.id) ?? 0 })).sort((a, b) => b.fanIn - a.fanIn).slice(0, limit);
|
|
42804
42839
|
return { kind: "fan-in", items: ranked };
|
|
42805
42840
|
}
|
|
42806
42841
|
},
|
|
@@ -78443,7 +78478,7 @@ function createWatchBreaker(deps) {
|
|
|
78443
78478
|
}
|
|
78444
78479
|
|
|
78445
78480
|
// src/engine.ts
|
|
78446
|
-
var DAEMON_VERSION = true ? "2.0.6-dev.
|
|
78481
|
+
var DAEMON_VERSION = true ? "2.0.6-dev.2627" : "2.0.0-alpha.0";
|
|
78447
78482
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
78448
78483
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
78449
78484
|
var GIT_OP_MUTE_MS = 4e3;
|
package/package.json
CHANGED
package/pass-worker.mjs
CHANGED
|
@@ -24782,8 +24782,16 @@ var SqliteGraphStore = class {
|
|
|
24782
24782
|
closeEdge: this.db.prepare(
|
|
24783
24783
|
"UPDATE edges SET valid_to = :t WHERE id = :id AND valid_to IS NULL"
|
|
24784
24784
|
),
|
|
24785
|
+
// Same rows as `COALESCE(logical_id, id) = ?`, split so each branch can use
|
|
24786
|
+
// an index (nodes_logical, then the id primary key). The COALESCE form made
|
|
24787
|
+
// SQLite SCAN nodes: 0.4-0.9s per call on a 227k-node store, once per new
|
|
24788
|
+
// diagnostic via attributeRootCause (2026-09-24).
|
|
24785
24789
|
nodeHistory: this.db.prepare(
|
|
24786
|
-
|
|
24790
|
+
`SELECT * FROM (
|
|
24791
|
+
SELECT * FROM nodes WHERE logical_id = ?1
|
|
24792
|
+
UNION ALL
|
|
24793
|
+
SELECT * FROM nodes WHERE id = ?1 AND logical_id IS NULL
|
|
24794
|
+
) ORDER BY version ASC`
|
|
24787
24795
|
),
|
|
24788
24796
|
nodesAsOf: this.db.prepare(
|
|
24789
24797
|
"SELECT * FROM nodes WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)"
|
|
@@ -25111,6 +25119,18 @@ var SqliteGraphStore = class {
|
|
|
25111
25119
|
).all(params);
|
|
25112
25120
|
return rows.map(rowToEdge);
|
|
25113
25121
|
}
|
|
25122
|
+
/** Live in-degree per target over `types`, in one grouped query — the counts
|
|
25123
|
+
* `inEdges(id, types).length` gives, for every node at once. A per-node
|
|
25124
|
+
* inEdges loop over ~48k code nodes held a PreToolUse hook 12.6s when the
|
|
25125
|
+
* hotspots vfile materialized (2026-09-24). */
|
|
25126
|
+
inDegreeByType(types) {
|
|
25127
|
+
if (types.length === 0) return /* @__PURE__ */ new Map();
|
|
25128
|
+
const placeholders = types.map(() => "?").join(",");
|
|
25129
|
+
const rows = this.db.prepare(
|
|
25130
|
+
`SELECT to_id, COUNT(*) AS n FROM edges WHERE type IN (${placeholders}) AND valid_to IS NULL GROUP BY to_id`
|
|
25131
|
+
).all(...types);
|
|
25132
|
+
return new Map(rows.map((r) => [r.to_id, Number(r.n)]));
|
|
25133
|
+
}
|
|
25114
25134
|
neighbors(nodeId, types) {
|
|
25115
25135
|
const out2 = [];
|
|
25116
25136
|
const edges = this.outEdges(nodeId, types);
|
|
@@ -25373,6 +25393,19 @@ var SqliteGraphStore = class {
|
|
|
25373
25393
|
const rows = this.stmts.nodesAsOf.all({ t });
|
|
25374
25394
|
return rows.map(rowToNode);
|
|
25375
25395
|
}
|
|
25396
|
+
/** `nodesAsOf(t).filter((n) => n.attrs[attr] === true)` with the attr test in
|
|
25397
|
+
* SQL, so only the flagged rows are hydrated. The filter-after form hydrated
|
|
25398
|
+
* the whole graph for a handful of revisit flags: 6.7s per context render on
|
|
25399
|
+
* a 227k-node store (2026-09-24). `attr` is interpolated into a JSON path,
|
|
25400
|
+
* so it must be a plain identifier. */
|
|
25401
|
+
nodesAsOfWhereTrue(t, attr) {
|
|
25402
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attr)) throw new Error(`nodesAsOfWhereTrue: bad attr ${JSON.stringify(attr)}`);
|
|
25403
|
+
const rows = this.db.prepare(
|
|
25404
|
+
`SELECT * FROM nodes WHERE valid_from <= :t AND (valid_to IS NULL OR valid_to > :t)
|
|
25405
|
+
AND json_type(attrs_json, '$.${attr}') = 'true'`
|
|
25406
|
+
).all({ t });
|
|
25407
|
+
return rows.map(rowToNode);
|
|
25408
|
+
}
|
|
25376
25409
|
edgesAsOf(t) {
|
|
25377
25410
|
const rows = this.stmts.edgesAsOf.all({ t });
|
|
25378
25411
|
return rows.map(rowToEdge);
|
|
@@ -25488,7 +25521,7 @@ function clearRevisit(store2, nodeId, ts) {
|
|
|
25488
25521
|
store2.updateNode(nodeId, { attrs, lastUpdatedAt: ts });
|
|
25489
25522
|
}
|
|
25490
25523
|
function listNeedsRevisit(store2, asOf) {
|
|
25491
|
-
return store2.
|
|
25524
|
+
return store2.nodesAsOfWhereTrue(asOf, "revisit").map((n) => ({
|
|
25492
25525
|
id: n.id,
|
|
25493
25526
|
label: n.label,
|
|
25494
25527
|
description: n.description,
|