@inerrata-corporation/errata 2.0.22-dev.4652 → 2.0.22-dev.4657

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.
@@ -17126,6 +17126,7 @@ var EXPOSURE_SCOPE = "exposure";
17126
17126
  // ../../packages/local-graph/src/change-feed.ts
17127
17127
  var CHANGE_FEED_KEY = "change-feed";
17128
17128
  var ANY_CHANGE = "*";
17129
+ var nodeScope = (label) => `node:${label}`;
17129
17130
  var CHANGE_LOG_KEEP = 25e4;
17130
17131
  var PRUNED_TO_KEY = "change-log-pruned-to";
17131
17132
  function installChangeFeed(db) {
@@ -18040,6 +18041,7 @@ var SqliteGraphStore = class {
18040
18041
  initialPageRankScale;
18041
18042
  constructor(opts) {
18042
18043
  this.db = openDatabase(opts.path);
18044
+ this.db.exec("PRAGMA cache_size = -32768");
18043
18045
  this.db.exec(SCHEMA_SQL);
18044
18046
  const versionRow = this.db.prepare("SELECT version FROM schema_version LIMIT 1").get();
18045
18047
  if (!versionRow) {
@@ -18104,6 +18106,7 @@ var SqliteGraphStore = class {
18104
18106
  attrs_json = excluded.attrs_json
18105
18107
  `),
18106
18108
  getNode: this.db.prepare("SELECT * FROM nodes WHERE id = ?"),
18109
+ labelOf: this.db.prepare("SELECT label FROM nodes WHERE id = ?"),
18107
18110
  // Single-column fast paths for the nightly pass — writing 100k pageRank
18108
18111
  // values through the 18-column COALESCE updateNode took ~30s; these are ~10x
18109
18112
  // cheaper (one bound column, no COALESCE evaluation per row).
@@ -18603,11 +18606,13 @@ var SqliteGraphStore = class {
18603
18606
  }
18604
18607
  }
18605
18608
  edgeRuleViolation(edge) {
18606
- return localEdgeViolation(
18607
- this.getNode(edge.from)?.label,
18608
- edge.type,
18609
- this.getNode(edge.to)?.label
18610
- );
18609
+ return localEdgeViolation(this.labelOf(edge.from), edge.type, this.labelOf(edge.to));
18610
+ }
18611
+ /** An endpoint's label, any version, as `getNode(id)?.label` reads it. Every
18612
+ * edge write checks both endpoints, and hydrating them (attrs + vector) to
18613
+ * read one leading column was most of an incremental reindex's reads. */
18614
+ labelOf(id) {
18615
+ return this.stmts.labelOf.get(id)?.label;
18611
18616
  }
18612
18617
  updateEdge(id, patch) {
18613
18618
  this.stmts.updateEdge.run({
@@ -18651,7 +18656,21 @@ var SqliteGraphStore = class {
18651
18656
  * per project per request; the materializing form held the daemon's event
18652
18657
  * loop for seconds at scale. */
18653
18658
  countNodesByLabel(label) {
18654
- return Number(this.stmts.countByLabel.get(label).n);
18659
+ return this.countAt(`label:${label}`, [nodeScope(label)], () => Number(this.stmts.countByLabel.get(label).n));
18660
+ }
18661
+ /** Counts asked for on every status poll (/health, `errata status`, the
18662
+ * dashboards): a live-node COUNT(*) reads the whole liveness index, ~3 MB per
18663
+ * call on a 1.1 GB store, to recount a set that moves only on a write. Each is
18664
+ * kept with the change-feed reading of the rows it counts — triggers bump it on
18665
+ * every write from any connection, so a hit is exact, not a TTL guess. */
18666
+ counts = /* @__PURE__ */ new Map();
18667
+ countAt(key, scopes, count) {
18668
+ const seq = readChangeSeq(this.db, scopes);
18669
+ const hit = this.counts.get(key);
18670
+ if (hit && hit.seq === seq) return hit.n;
18671
+ const n = count();
18672
+ this.counts.set(key, { seq, n });
18673
+ return n;
18655
18674
  }
18656
18675
  /** Live rows for a label with attrs and creation stamps only — for scans that
18657
18676
  * read attrs and never the vector. `findNodesByLabel` decodes every embedding
@@ -18918,7 +18937,7 @@ var SqliteGraphStore = class {
18918
18937
  return out;
18919
18938
  }
18920
18939
  nodeCount() {
18921
- return Number(this.stmts.nodeCount.get().n);
18940
+ return this.countAt("nodes", [ANY_CHANGE], () => Number(this.stmts.nodeCount.get().n));
18922
18941
  }
18923
18942
  mutationCount() {
18924
18943
  return this.mutations;
@@ -18962,7 +18981,7 @@ var SqliteGraphStore = class {
18962
18981
  return this.ingestSeq;
18963
18982
  }
18964
18983
  edgeCount() {
18965
- return Number(this.stmts.edgeCount.get().n);
18984
+ return this.countAt("edges", [ANY_CHANGE], () => Number(this.stmts.edgeCount.get().n));
18966
18985
  }
18967
18986
  // Lightweight whole-graph scans — select only the columns the caller needs so a
18968
18987
  // 100k-node pass skips the per-row attrs JSON.parse + embedding decode rowToNode
package/errata.mjs CHANGED
@@ -20892,6 +20892,7 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
20892
20892
  initialPageRankScale;
20893
20893
  constructor(opts) {
20894
20894
  this.db = openDatabase(opts.path);
20895
+ this.db.exec("PRAGMA cache_size = -32768");
20895
20896
  this.db.exec(SCHEMA_SQL);
20896
20897
  const versionRow = this.db.prepare("SELECT version FROM schema_version LIMIT 1").get();
20897
20898
  if (!versionRow) {
@@ -20956,6 +20957,7 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
20956
20957
  attrs_json = excluded.attrs_json
20957
20958
  `),
20958
20959
  getNode: this.db.prepare("SELECT * FROM nodes WHERE id = ?"),
20960
+ labelOf: this.db.prepare("SELECT label FROM nodes WHERE id = ?"),
20959
20961
  // Single-column fast paths for the nightly pass — writing 100k pageRank
20960
20962
  // values through the 18-column COALESCE updateNode took ~30s; these are ~10x
20961
20963
  // cheaper (one bound column, no COALESCE evaluation per row).
@@ -21455,11 +21457,13 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
21455
21457
  }
21456
21458
  }
21457
21459
  edgeRuleViolation(edge2) {
21458
- return localEdgeViolation(
21459
- this.getNode(edge2.from)?.label,
21460
- edge2.type,
21461
- this.getNode(edge2.to)?.label
21462
- );
21460
+ return localEdgeViolation(this.labelOf(edge2.from), edge2.type, this.labelOf(edge2.to));
21461
+ }
21462
+ /** An endpoint's label, any version, as `getNode(id)?.label` reads it. Every
21463
+ * edge write checks both endpoints, and hydrating them (attrs + vector) to
21464
+ * read one leading column was most of an incremental reindex's reads. */
21465
+ labelOf(id) {
21466
+ return this.stmts.labelOf.get(id)?.label;
21463
21467
  }
21464
21468
  updateEdge(id, patch) {
21465
21469
  this.stmts.updateEdge.run({
@@ -21503,7 +21507,21 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
21503
21507
  * per project per request; the materializing form held the daemon's event
21504
21508
  * loop for seconds at scale. */
21505
21509
  countNodesByLabel(label) {
21506
- return Number(this.stmts.countByLabel.get(label).n);
21510
+ return this.countAt(`label:${label}`, [nodeScope(label)], () => Number(this.stmts.countByLabel.get(label).n));
21511
+ }
21512
+ /** Counts asked for on every status poll (/health, `errata status`, the
21513
+ * dashboards): a live-node COUNT(*) reads the whole liveness index, ~3 MB per
21514
+ * call on a 1.1 GB store, to recount a set that moves only on a write. Each is
21515
+ * kept with the change-feed reading of the rows it counts — triggers bump it on
21516
+ * every write from any connection, so a hit is exact, not a TTL guess. */
21517
+ counts = /* @__PURE__ */ new Map();
21518
+ countAt(key, scopes, count) {
21519
+ const seq = readChangeSeq(this.db, scopes);
21520
+ const hit = this.counts.get(key);
21521
+ if (hit && hit.seq === seq) return hit.n;
21522
+ const n = count();
21523
+ this.counts.set(key, { seq, n });
21524
+ return n;
21507
21525
  }
21508
21526
  /** Live rows for a label with attrs and creation stamps only — for scans that
21509
21527
  * read attrs and never the vector. `findNodesByLabel` decodes every embedding
@@ -21770,7 +21788,7 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
21770
21788
  return out2;
21771
21789
  }
21772
21790
  nodeCount() {
21773
- return Number(this.stmts.nodeCount.get().n);
21791
+ return this.countAt("nodes", [ANY_CHANGE], () => Number(this.stmts.nodeCount.get().n));
21774
21792
  }
21775
21793
  mutationCount() {
21776
21794
  return this.mutations;
@@ -21814,7 +21832,7 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
21814
21832
  return this.ingestSeq;
21815
21833
  }
21816
21834
  edgeCount() {
21817
- return Number(this.stmts.edgeCount.get().n);
21835
+ return this.countAt("edges", [ANY_CHANGE], () => Number(this.stmts.edgeCount.get().n));
21818
21836
  }
21819
21837
  // Lightweight whole-graph scans — select only the columns the caller needs so a
21820
21838
  // 100k-node pass skips the per-row attrs JSON.parse + embedding decode rowToNode
@@ -39603,9 +39621,10 @@ async function runIndexer(store, opts) {
39603
39621
  if (ei > 0) await new Promise((r) => setImmediate(r));
39604
39622
  const slice = pendingEdges.slice(ei, ei + EDGE_BATCH);
39605
39623
  store.transaction(() => {
39624
+ const present = store.nodeLabels([...new Set(slice.flatMap((e) => [e.from, e.to]))]);
39606
39625
  for (const e of slice) {
39607
39626
  if (e.from === e.to) continue;
39608
- if (!store.getNode(e.from) || !store.getNode(e.to)) continue;
39627
+ if (!present.has(e.from) || !present.has(e.to)) continue;
39609
39628
  upsertEdge(
39610
39629
  store,
39611
39630
  e.from,
@@ -87006,7 +87025,7 @@ function createWatchBreaker(deps) {
87006
87025
  }
87007
87026
 
87008
87027
  // src/engine.ts
87009
- var DAEMON_VERSION = true ? "2.0.22-dev.4652" : "2.0.0-alpha.0";
87028
+ var DAEMON_VERSION = true ? "2.0.22-dev.4657" : "2.0.0-alpha.0";
87010
87029
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
87011
87030
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
87012
87031
  var GIT_OP_MUTE_MS = 4e3;
@@ -15700,6 +15700,7 @@ var EXPOSURE_SCOPE = "exposure";
15700
15700
  // ../../packages/local-graph/src/change-feed.ts
15701
15701
  var CHANGE_FEED_KEY = "change-feed";
15702
15702
  var ANY_CHANGE = "*";
15703
+ var nodeScope = (label) => `node:${label}`;
15703
15704
  var CHANGE_LOG_KEEP = 25e4;
15704
15705
  var PRUNED_TO_KEY = "change-log-pruned-to";
15705
15706
  function installChangeFeed(db) {
@@ -16437,6 +16438,7 @@ var SqliteGraphStore = class {
16437
16438
  initialPageRankScale;
16438
16439
  constructor(opts) {
16439
16440
  this.db = openDatabase(opts.path);
16441
+ this.db.exec("PRAGMA cache_size = -32768");
16440
16442
  this.db.exec(SCHEMA_SQL);
16441
16443
  const versionRow = this.db.prepare("SELECT version FROM schema_version LIMIT 1").get();
16442
16444
  if (!versionRow) {
@@ -16501,6 +16503,7 @@ var SqliteGraphStore = class {
16501
16503
  attrs_json = excluded.attrs_json
16502
16504
  `),
16503
16505
  getNode: this.db.prepare("SELECT * FROM nodes WHERE id = ?"),
16506
+ labelOf: this.db.prepare("SELECT label FROM nodes WHERE id = ?"),
16504
16507
  // Single-column fast paths for the nightly pass — writing 100k pageRank
16505
16508
  // values through the 18-column COALESCE updateNode took ~30s; these are ~10x
16506
16509
  // cheaper (one bound column, no COALESCE evaluation per row).
@@ -17000,11 +17003,13 @@ var SqliteGraphStore = class {
17000
17003
  }
17001
17004
  }
17002
17005
  edgeRuleViolation(edge) {
17003
- return localEdgeViolation(
17004
- this.getNode(edge.from)?.label,
17005
- edge.type,
17006
- this.getNode(edge.to)?.label
17007
- );
17006
+ return localEdgeViolation(this.labelOf(edge.from), edge.type, this.labelOf(edge.to));
17007
+ }
17008
+ /** An endpoint's label, any version, as `getNode(id)?.label` reads it. Every
17009
+ * edge write checks both endpoints, and hydrating them (attrs + vector) to
17010
+ * read one leading column was most of an incremental reindex's reads. */
17011
+ labelOf(id) {
17012
+ return this.stmts.labelOf.get(id)?.label;
17008
17013
  }
17009
17014
  updateEdge(id, patch) {
17010
17015
  this.stmts.updateEdge.run({
@@ -17048,7 +17053,21 @@ var SqliteGraphStore = class {
17048
17053
  * per project per request; the materializing form held the daemon's event
17049
17054
  * loop for seconds at scale. */
17050
17055
  countNodesByLabel(label) {
17051
- return Number(this.stmts.countByLabel.get(label).n);
17056
+ return this.countAt(`label:${label}`, [nodeScope(label)], () => Number(this.stmts.countByLabel.get(label).n));
17057
+ }
17058
+ /** Counts asked for on every status poll (/health, `errata status`, the
17059
+ * dashboards): a live-node COUNT(*) reads the whole liveness index, ~3 MB per
17060
+ * call on a 1.1 GB store, to recount a set that moves only on a write. Each is
17061
+ * kept with the change-feed reading of the rows it counts — triggers bump it on
17062
+ * every write from any connection, so a hit is exact, not a TTL guess. */
17063
+ counts = /* @__PURE__ */ new Map();
17064
+ countAt(key, scopes, count) {
17065
+ const seq = readChangeSeq(this.db, scopes);
17066
+ const hit = this.counts.get(key);
17067
+ if (hit && hit.seq === seq) return hit.n;
17068
+ const n = count();
17069
+ this.counts.set(key, { seq, n });
17070
+ return n;
17052
17071
  }
17053
17072
  /** Live rows for a label with attrs and creation stamps only — for scans that
17054
17073
  * read attrs and never the vector. `findNodesByLabel` decodes every embedding
@@ -17315,7 +17334,7 @@ var SqliteGraphStore = class {
17315
17334
  return out;
17316
17335
  }
17317
17336
  nodeCount() {
17318
- return Number(this.stmts.nodeCount.get().n);
17337
+ return this.countAt("nodes", [ANY_CHANGE], () => Number(this.stmts.nodeCount.get().n));
17319
17338
  }
17320
17339
  mutationCount() {
17321
17340
  return this.mutations;
@@ -17359,7 +17378,7 @@ var SqliteGraphStore = class {
17359
17378
  return this.ingestSeq;
17360
17379
  }
17361
17380
  edgeCount() {
17362
- return Number(this.stmts.edgeCount.get().n);
17381
+ return this.countAt("edges", [ANY_CHANGE], () => Number(this.stmts.edgeCount.get().n));
17363
17382
  }
17364
17383
  // Lightweight whole-graph scans — select only the columns the caller needs so a
17365
17384
  // 100k-node pass skips the per-row attrs JSON.parse + embedding decode rowToNode
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.22-dev.4652",
3
+ "version": "2.0.22-dev.4657",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -18280,9 +18280,10 @@ async function runIndexer(store2, opts) {
18280
18280
  if (ei > 0) await new Promise((r) => setImmediate(r));
18281
18281
  const slice = pendingEdges.slice(ei, ei + EDGE_BATCH);
18282
18282
  store2.transaction(() => {
18283
+ const present = store2.nodeLabels([...new Set(slice.flatMap((e) => [e.from, e.to]))]);
18283
18284
  for (const e of slice) {
18284
18285
  if (e.from === e.to) continue;
18285
- if (!store2.getNode(e.from) || !store2.getNode(e.to)) continue;
18286
+ if (!present.has(e.from) || !present.has(e.to)) continue;
18286
18287
  upsertEdge(
18287
18288
  store2,
18288
18289
  e.from,
@@ -26142,6 +26143,7 @@ var EXPOSURE_SCOPE = "exposure";
26142
26143
  // ../../packages/local-graph/src/change-feed.ts
26143
26144
  var CHANGE_FEED_KEY = "change-feed";
26144
26145
  var ANY_CHANGE = "*";
26146
+ var nodeScope = (label) => `node:${label}`;
26145
26147
  var CHANGE_LOG_KEEP = 25e4;
26146
26148
  var PRUNED_TO_KEY = "change-log-pruned-to";
26147
26149
  function installChangeFeed(db) {
@@ -27315,6 +27317,7 @@ var SqliteGraphStore = class {
27315
27317
  initialPageRankScale;
27316
27318
  constructor(opts) {
27317
27319
  this.db = openDatabase(opts.path);
27320
+ this.db.exec("PRAGMA cache_size = -32768");
27318
27321
  this.db.exec(SCHEMA_SQL);
27319
27322
  const versionRow = this.db.prepare("SELECT version FROM schema_version LIMIT 1").get();
27320
27323
  if (!versionRow) {
@@ -27379,6 +27382,7 @@ var SqliteGraphStore = class {
27379
27382
  attrs_json = excluded.attrs_json
27380
27383
  `),
27381
27384
  getNode: this.db.prepare("SELECT * FROM nodes WHERE id = ?"),
27385
+ labelOf: this.db.prepare("SELECT label FROM nodes WHERE id = ?"),
27382
27386
  // Single-column fast paths for the nightly pass — writing 100k pageRank
27383
27387
  // values through the 18-column COALESCE updateNode took ~30s; these are ~10x
27384
27388
  // cheaper (one bound column, no COALESCE evaluation per row).
@@ -27878,11 +27882,13 @@ var SqliteGraphStore = class {
27878
27882
  }
27879
27883
  }
27880
27884
  edgeRuleViolation(edge) {
27881
- return localEdgeViolation(
27882
- this.getNode(edge.from)?.label,
27883
- edge.type,
27884
- this.getNode(edge.to)?.label
27885
- );
27885
+ return localEdgeViolation(this.labelOf(edge.from), edge.type, this.labelOf(edge.to));
27886
+ }
27887
+ /** An endpoint's label, any version, as `getNode(id)?.label` reads it. Every
27888
+ * edge write checks both endpoints, and hydrating them (attrs + vector) to
27889
+ * read one leading column was most of an incremental reindex's reads. */
27890
+ labelOf(id) {
27891
+ return this.stmts.labelOf.get(id)?.label;
27886
27892
  }
27887
27893
  updateEdge(id, patch) {
27888
27894
  this.stmts.updateEdge.run({
@@ -27926,7 +27932,21 @@ var SqliteGraphStore = class {
27926
27932
  * per project per request; the materializing form held the daemon's event
27927
27933
  * loop for seconds at scale. */
27928
27934
  countNodesByLabel(label) {
27929
- return Number(this.stmts.countByLabel.get(label).n);
27935
+ return this.countAt(`label:${label}`, [nodeScope(label)], () => Number(this.stmts.countByLabel.get(label).n));
27936
+ }
27937
+ /** Counts asked for on every status poll (/health, `errata status`, the
27938
+ * dashboards): a live-node COUNT(*) reads the whole liveness index, ~3 MB per
27939
+ * call on a 1.1 GB store, to recount a set that moves only on a write. Each is
27940
+ * kept with the change-feed reading of the rows it counts — triggers bump it on
27941
+ * every write from any connection, so a hit is exact, not a TTL guess. */
27942
+ counts = /* @__PURE__ */ new Map();
27943
+ countAt(key, scopes, count) {
27944
+ const seq = readChangeSeq(this.db, scopes);
27945
+ const hit = this.counts.get(key);
27946
+ if (hit && hit.seq === seq) return hit.n;
27947
+ const n = count();
27948
+ this.counts.set(key, { seq, n });
27949
+ return n;
27930
27950
  }
27931
27951
  /** Live rows for a label with attrs and creation stamps only — for scans that
27932
27952
  * read attrs and never the vector. `findNodesByLabel` decodes every embedding
@@ -28193,7 +28213,7 @@ var SqliteGraphStore = class {
28193
28213
  return out2;
28194
28214
  }
28195
28215
  nodeCount() {
28196
- return Number(this.stmts.nodeCount.get().n);
28216
+ return this.countAt("nodes", [ANY_CHANGE], () => Number(this.stmts.nodeCount.get().n));
28197
28217
  }
28198
28218
  mutationCount() {
28199
28219
  return this.mutations;
@@ -28237,7 +28257,7 @@ var SqliteGraphStore = class {
28237
28257
  return this.ingestSeq;
28238
28258
  }
28239
28259
  edgeCount() {
28240
- return Number(this.stmts.edgeCount.get().n);
28260
+ return this.countAt("edges", [ANY_CHANGE], () => Number(this.stmts.edgeCount.get().n));
28241
28261
  }
28242
28262
  // Lightweight whole-graph scans — select only the columns the caller needs so a
28243
28263
  // 100k-node pass skips the per-row attrs JSON.parse + embedding decode rowToNode
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "errata-context",
3
- "version": "2.0.22-dev.4652",
3
+ "version": "2.0.22-dev.4657",
4
4
  "description": "A minimal 3D view of loaded Errata priors and recent graph bursts.",
5
5
  "author": {
6
6
  "name": "inErrata"
@@ -1,4 +1,4 @@
1
- ba1065832fc364902b70117e8568ae7f0d76cd3af48ed4d0929f03d9d3d55c7f .codex-plugin/plugin.json
1
+ e7f2b11ac106aa4f1ad1c492a48adfed53759ae7c7d5cba5f087ff791f67f48d .codex-plugin/plugin.json
2
2
  a7bebae9fb01c838d6c75fc784129e28be571233fa66ff5ee8039b574f35ccf7 assets/icon.png
3
3
  fc38b64e4df1e0b72c35764bef6c4c05430d97c9009ad0ecc8a9e75b4deab232 configure-local.mjs
4
4
  73dc6028b3b070257c7c31f252d11e55a9e096f4aed0f187f10cb21716e1e6d7 dist/client.js