@inerrata-corporation/errata 2.0.22-dev.4624 → 2.0.22-dev.4630

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.
@@ -17895,10 +17895,18 @@ CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
17895
17895
  -- of matching and sorting every live edge (the hourly liveness check: 163 MB \u2192
17896
17896
  -- 69 MB). Named by recentEdgeAttrCoverage; the planner keeps edges_live otherwise.
17897
17897
  CREATE INDEX IF NOT EXISTS edges_live_created ON edges(created_at) WHERE valid_to IS NULL;
17898
+ -- Live prior-tag edges by recency: the liveness corroboration check reads the
17899
+ -- newest 100 of ~300, and walking all live edges newest-first to find them read
17900
+ -- 69 MB. Its predicate is the one recentEdgeAttrCoverage uses for that marker.
17901
+ CREATE INDEX IF NOT EXISTS edges_live_prior_tag ON edges(created_at) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1;
17898
17902
  -- Expression index on the per-node relPath (stored in attrs_json) so the
17899
17903
  -- incremental reindex can fetch just the changed files' symbols instead of
17900
17904
  -- scanning every versioned node. Partial: only live rows are ever queried.
17901
17905
  CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.relPath')) WHERE valid_to IS NULL;
17906
+ -- Closed rows by relPath, for reviveReobserved (every incremental reindex): the
17907
+ -- live-only index above cannot serve it, so it scanned the whole table (~275 MB
17908
+ -- of a 1.1 GB store per reindex, 2026-10-20).
17909
+ CREATE INDEX IF NOT EXISTS nodes_closed_relpath ON nodes(json_extract(attrs_json, '$.relPath'), last_updated_at) WHERE valid_to IS NOT NULL;
17902
17910
  -- Live rows by name, for looking up the few symbols a statement mentions
17903
17911
  -- instead of hydrating every code symbol per minted problem.
17904
17912
  CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) WHERE valid_to IS NULL;
@@ -17985,6 +17993,7 @@ function rowToEdge(r) {
17985
17993
  }
17986
17994
  var FINGERPRINT_INDEXED_LABELS = ["Problem", "Vulnerability", "Solution", "RootCause"];
17987
17995
  var NODE_LABELS_CHUNK = 256;
17996
+ var PRIOR_TAG_MARKER = '"priorTag":true';
17988
17997
  var SqliteGraphStore = class {
17989
17998
  db;
17990
17999
  // Typed edge lookups build their SQL from the number of types asked for, and
@@ -19046,7 +19055,22 @@ var SqliteGraphStore = class {
19046
19055
  ).get(...edgeTypes, label, cloudOnly ? 1 : 0);
19047
19056
  return { count: Number(r.count), total: Number(r.total) };
19048
19057
  }
19058
+ liveEdgeTargets(edgeTypes) {
19059
+ if (edgeTypes.length === 0) return [];
19060
+ const rows = this.db.prepare(`SELECT DISTINCT to_id FROM edges INDEXED BY edges_type WHERE type IN (${edgeTypes.map(() => "?").join(",")}) AND valid_to IS NULL`).all(...edgeTypes);
19061
+ return rows.map((r) => r.to_id);
19062
+ }
19049
19063
  recentEdgeAttrCoverage(marker, attr, limit) {
19064
+ if (marker === PRIOR_TAG_MARKER) {
19065
+ const r2 = this.db.prepare(
19066
+ `SELECT COUNT(*) AS total,
19067
+ COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
19068
+ FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_prior_tag
19069
+ WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1
19070
+ ORDER BY created_at DESC LIMIT ?)`
19071
+ ).get(attr, limit);
19072
+ return { count: Number(r2.count), total: Number(r2.total) };
19073
+ }
19050
19074
  const r = this.db.prepare(
19051
19075
  `SELECT COUNT(*) AS total,
19052
19076
  COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
package/errata.mjs CHANGED
@@ -20628,7 +20628,7 @@ function rowToEdge(r) {
20628
20628
  function openGraphStore(opts) {
20629
20629
  return new SqliteGraphStore(opts);
20630
20630
  }
20631
- var PAGE_RANK_SCALE_KEY, TEXT_SEARCH_COLUMNS, LOCAL_RULE_OVERRIDES, SCHEMA_VERSION, SESSION_REPAIR_KEY, SESSION_EVIDENCE_PREDICATE, SCHEMA_SQL, TEMPORAL_INDEX_SQL, FINGERPRINT_INDEXED_LABELS, NODE_LABELS_CHUNK, SqliteGraphStore;
20631
+ var PAGE_RANK_SCALE_KEY, TEXT_SEARCH_COLUMNS, LOCAL_RULE_OVERRIDES, SCHEMA_VERSION, SESSION_REPAIR_KEY, SESSION_EVIDENCE_PREDICATE, SCHEMA_SQL, TEMPORAL_INDEX_SQL, FINGERPRINT_INDEXED_LABELS, NODE_LABELS_CHUNK, PRIOR_TAG_MARKER, SqliteGraphStore;
20632
20632
  var init_store = __esm({
20633
20633
  "../../packages/local-graph/src/store.ts"() {
20634
20634
  "use strict";
@@ -20804,10 +20804,18 @@ CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
20804
20804
  -- of matching and sorting every live edge (the hourly liveness check: 163 MB \u2192
20805
20805
  -- 69 MB). Named by recentEdgeAttrCoverage; the planner keeps edges_live otherwise.
20806
20806
  CREATE INDEX IF NOT EXISTS edges_live_created ON edges(created_at) WHERE valid_to IS NULL;
20807
+ -- Live prior-tag edges by recency: the liveness corroboration check reads the
20808
+ -- newest 100 of ~300, and walking all live edges newest-first to find them read
20809
+ -- 69 MB. Its predicate is the one recentEdgeAttrCoverage uses for that marker.
20810
+ CREATE INDEX IF NOT EXISTS edges_live_prior_tag ON edges(created_at) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1;
20807
20811
  -- Expression index on the per-node relPath (stored in attrs_json) so the
20808
20812
  -- incremental reindex can fetch just the changed files' symbols instead of
20809
20813
  -- scanning every versioned node. Partial: only live rows are ever queried.
20810
20814
  CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.relPath')) WHERE valid_to IS NULL;
20815
+ -- Closed rows by relPath, for reviveReobserved (every incremental reindex): the
20816
+ -- live-only index above cannot serve it, so it scanned the whole table (~275 MB
20817
+ -- of a 1.1 GB store per reindex, 2026-10-20).
20818
+ CREATE INDEX IF NOT EXISTS nodes_closed_relpath ON nodes(json_extract(attrs_json, '$.relPath'), last_updated_at) WHERE valid_to IS NOT NULL;
20811
20819
  -- Live rows by name, for looking up the few symbols a statement mentions
20812
20820
  -- instead of hydrating every code symbol per minted problem.
20813
20821
  CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) WHERE valid_to IS NULL;
@@ -20837,6 +20845,7 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
20837
20845
  `;
20838
20846
  FINGERPRINT_INDEXED_LABELS = ["Problem", "Vulnerability", "Solution", "RootCause"];
20839
20847
  NODE_LABELS_CHUNK = 256;
20848
+ PRIOR_TAG_MARKER = '"priorTag":true';
20840
20849
  SqliteGraphStore = class {
20841
20850
  db;
20842
20851
  // Typed edge lookups build their SQL from the number of types asked for, and
@@ -21898,7 +21907,22 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
21898
21907
  ).get(...edgeTypes, label, cloudOnly ? 1 : 0);
21899
21908
  return { count: Number(r.count), total: Number(r.total) };
21900
21909
  }
21910
+ liveEdgeTargets(edgeTypes) {
21911
+ if (edgeTypes.length === 0) return [];
21912
+ const rows = this.db.prepare(`SELECT DISTINCT to_id FROM edges INDEXED BY edges_type WHERE type IN (${edgeTypes.map(() => "?").join(",")}) AND valid_to IS NULL`).all(...edgeTypes);
21913
+ return rows.map((r) => r.to_id);
21914
+ }
21901
21915
  recentEdgeAttrCoverage(marker, attr, limit) {
21916
+ if (marker === PRIOR_TAG_MARKER) {
21917
+ const r2 = this.db.prepare(
21918
+ `SELECT COUNT(*) AS total,
21919
+ COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
21920
+ FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_prior_tag
21921
+ WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1
21922
+ ORDER BY created_at DESC LIMIT ?)`
21923
+ ).get(attr, limit);
21924
+ return { count: Number(r2.count), total: Number(r2.total) };
21925
+ }
21902
21926
  const r = this.db.prepare(
21903
21927
  `SELECT COUNT(*) AS total,
21904
21928
  COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
@@ -26846,6 +26870,13 @@ var init_principle_sync = __esm({
26846
26870
 
26847
26871
  // ../../packages/local-graph/src/mechanism-liveness.ts
26848
26872
  function evaluateFed(store, d, stamps) {
26873
+ const incomingRows = d.fedIncoming && store.liveEdgeTargets ? stamps?.(d.fedIncoming.label, "source") : void 0;
26874
+ if (d.fedIncoming && incomingRows) {
26875
+ const targets = new Set(store.liveEdgeTargets(d.fedIncoming.edgeTypes));
26876
+ const rows = d.fedIncoming.cloudOnly ? incomingRows.filter((r) => r.cloud) : incomingRows;
26877
+ const count2 = rows.filter((r) => targets.has(r.id)).length;
26878
+ return { count: count2, total: rows.length, fraction: rows.length === 0 ? 0 : count2 / rows.length };
26879
+ }
26849
26880
  if (d.fedIncoming) {
26850
26881
  const { count: count2, total } = store.incomingEdgeCoverage?.(
26851
26882
  d.fedIncoming.label,
@@ -26890,6 +26921,7 @@ function evaluateMechanisms(store, invocations = /* @__PURE__ */ new Map(), mech
26890
26921
  };
26891
26922
  const wanted = /* @__PURE__ */ new Map();
26892
26923
  for (const d of mechanisms) for (const l of d.fed?.labels ?? []) wanted.set(l, (wanted.get(l) ?? /* @__PURE__ */ new Set()).add(d.fed.attr));
26924
+ for (const d of mechanisms) if (d.fedIncoming) wanted.set(d.fedIncoming.label, (wanted.get(d.fedIncoming.label) ?? /* @__PURE__ */ new Set()).add("source"));
26893
26925
  const byLabel = /* @__PURE__ */ new Map();
26894
26926
  const stamps = store.findNodeStampsByLabelAttrs ? (label, attr) => {
26895
26927
  if (!byLabel.has(label)) byLabel.set(label, store.findNodeStampsByLabelAttrs(label, [...wanted.get(label) ?? [attr]]));
@@ -39066,7 +39098,13 @@ async function runIndexer(store, opts) {
39066
39098
  }
39067
39099
  }
39068
39100
  perf(`parse (${report.filesParsed} parsed, ${report.filesSkipped} skipped)`);
39069
- const exportsByFile = /* @__PURE__ */ new Map();
39101
+ const pendingExports = /* @__PURE__ */ new Set();
39102
+ const exportsByFile = new class extends Map {
39103
+ get(relPath) {
39104
+ if (pendingExports.delete(relPath)) super.set(relPath, graphExportMap(store, opts.workspaceId, relPath));
39105
+ return super.get(relPath);
39106
+ }
39107
+ }();
39070
39108
  const importsByFile = /* @__PURE__ */ new Map();
39071
39109
  for (const [relPath, symbols] of symbolsByFile) {
39072
39110
  const localExports = /* @__PURE__ */ new Map();
@@ -39090,7 +39128,8 @@ async function runIndexer(store, opts) {
39090
39128
  if (scope !== void 0) {
39091
39129
  for (const f of files) {
39092
39130
  if (inScope(f.relPath) || exportsByFile.has(f.relPath)) continue;
39093
- exportsByFile.set(f.relPath, graphExportMap(store, opts.workspaceId, f.relPath));
39131
+ exportsByFile.set(f.relPath, /* @__PURE__ */ new Map());
39132
+ pendingExports.add(f.relPath);
39094
39133
  }
39095
39134
  }
39096
39135
  const workspacePackages = /* @__PURE__ */ new Map();
@@ -86817,7 +86856,7 @@ function createWatchBreaker(deps) {
86817
86856
  }
86818
86857
 
86819
86858
  // src/engine.ts
86820
- var DAEMON_VERSION = true ? "2.0.22-dev.4624" : "2.0.0-alpha.0";
86859
+ var DAEMON_VERSION = true ? "2.0.22-dev.4630" : "2.0.0-alpha.0";
86821
86860
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
86822
86861
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
86823
86862
  var GIT_OP_MUTE_MS = 4e3;
@@ -16292,10 +16292,18 @@ CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
16292
16292
  -- of matching and sorting every live edge (the hourly liveness check: 163 MB \u2192
16293
16293
  -- 69 MB). Named by recentEdgeAttrCoverage; the planner keeps edges_live otherwise.
16294
16294
  CREATE INDEX IF NOT EXISTS edges_live_created ON edges(created_at) WHERE valid_to IS NULL;
16295
+ -- Live prior-tag edges by recency: the liveness corroboration check reads the
16296
+ -- newest 100 of ~300, and walking all live edges newest-first to find them read
16297
+ -- 69 MB. Its predicate is the one recentEdgeAttrCoverage uses for that marker.
16298
+ CREATE INDEX IF NOT EXISTS edges_live_prior_tag ON edges(created_at) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1;
16295
16299
  -- Expression index on the per-node relPath (stored in attrs_json) so the
16296
16300
  -- incremental reindex can fetch just the changed files' symbols instead of
16297
16301
  -- scanning every versioned node. Partial: only live rows are ever queried.
16298
16302
  CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.relPath')) WHERE valid_to IS NULL;
16303
+ -- Closed rows by relPath, for reviveReobserved (every incremental reindex): the
16304
+ -- live-only index above cannot serve it, so it scanned the whole table (~275 MB
16305
+ -- of a 1.1 GB store per reindex, 2026-10-20).
16306
+ CREATE INDEX IF NOT EXISTS nodes_closed_relpath ON nodes(json_extract(attrs_json, '$.relPath'), last_updated_at) WHERE valid_to IS NOT NULL;
16299
16307
  -- Live rows by name, for looking up the few symbols a statement mentions
16300
16308
  -- instead of hydrating every code symbol per minted problem.
16301
16309
  CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) WHERE valid_to IS NULL;
@@ -16382,6 +16390,7 @@ function rowToEdge(r) {
16382
16390
  }
16383
16391
  var FINGERPRINT_INDEXED_LABELS = ["Problem", "Vulnerability", "Solution", "RootCause"];
16384
16392
  var NODE_LABELS_CHUNK = 256;
16393
+ var PRIOR_TAG_MARKER = '"priorTag":true';
16385
16394
  var SqliteGraphStore = class {
16386
16395
  db;
16387
16396
  // Typed edge lookups build their SQL from the number of types asked for, and
@@ -17443,7 +17452,22 @@ var SqliteGraphStore = class {
17443
17452
  ).get(...edgeTypes, label, cloudOnly ? 1 : 0);
17444
17453
  return { count: Number(r.count), total: Number(r.total) };
17445
17454
  }
17455
+ liveEdgeTargets(edgeTypes) {
17456
+ if (edgeTypes.length === 0) return [];
17457
+ const rows = this.db.prepare(`SELECT DISTINCT to_id FROM edges INDEXED BY edges_type WHERE type IN (${edgeTypes.map(() => "?").join(",")}) AND valid_to IS NULL`).all(...edgeTypes);
17458
+ return rows.map((r) => r.to_id);
17459
+ }
17446
17460
  recentEdgeAttrCoverage(marker, attr, limit) {
17461
+ if (marker === PRIOR_TAG_MARKER) {
17462
+ const r2 = this.db.prepare(
17463
+ `SELECT COUNT(*) AS total,
17464
+ COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
17465
+ FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_prior_tag
17466
+ WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1
17467
+ ORDER BY created_at DESC LIMIT ?)`
17468
+ ).get(attr, limit);
17469
+ return { count: Number(r2.count), total: Number(r2.total) };
17470
+ }
17447
17471
  const r = this.db.prepare(
17448
17472
  `SELECT COUNT(*) AS total,
17449
17473
  COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.22-dev.4624",
3
+ "version": "2.0.22-dev.4630",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -17905,7 +17905,13 @@ async function runIndexer(store2, opts) {
17905
17905
  }
17906
17906
  }
17907
17907
  perf(`parse (${report.filesParsed} parsed, ${report.filesSkipped} skipped)`);
17908
- const exportsByFile = /* @__PURE__ */ new Map();
17908
+ const pendingExports = /* @__PURE__ */ new Set();
17909
+ const exportsByFile = new class extends Map {
17910
+ get(relPath) {
17911
+ if (pendingExports.delete(relPath)) super.set(relPath, graphExportMap(store2, opts.workspaceId, relPath));
17912
+ return super.get(relPath);
17913
+ }
17914
+ }();
17909
17915
  const importsByFile = /* @__PURE__ */ new Map();
17910
17916
  for (const [relPath, symbols] of symbolsByFile) {
17911
17917
  const localExports = /* @__PURE__ */ new Map();
@@ -17929,7 +17935,8 @@ async function runIndexer(store2, opts) {
17929
17935
  if (scope !== void 0) {
17930
17936
  for (const f of files) {
17931
17937
  if (inScope(f.relPath) || exportsByFile.has(f.relPath)) continue;
17932
- exportsByFile.set(f.relPath, graphExportMap(store2, opts.workspaceId, f.relPath));
17938
+ exportsByFile.set(f.relPath, /* @__PURE__ */ new Map());
17939
+ pendingExports.add(f.relPath);
17933
17940
  }
17934
17941
  }
17935
17942
  const workspacePackages = /* @__PURE__ */ new Map();
@@ -27160,10 +27167,18 @@ CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
27160
27167
  -- of matching and sorting every live edge (the hourly liveness check: 163 MB \u2192
27161
27168
  -- 69 MB). Named by recentEdgeAttrCoverage; the planner keeps edges_live otherwise.
27162
27169
  CREATE INDEX IF NOT EXISTS edges_live_created ON edges(created_at) WHERE valid_to IS NULL;
27170
+ -- Live prior-tag edges by recency: the liveness corroboration check reads the
27171
+ -- newest 100 of ~300, and walking all live edges newest-first to find them read
27172
+ -- 69 MB. Its predicate is the one recentEdgeAttrCoverage uses for that marker.
27173
+ CREATE INDEX IF NOT EXISTS edges_live_prior_tag ON edges(created_at) WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1;
27163
27174
  -- Expression index on the per-node relPath (stored in attrs_json) so the
27164
27175
  -- incremental reindex can fetch just the changed files' symbols instead of
27165
27176
  -- scanning every versioned node. Partial: only live rows are ever queried.
27166
27177
  CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.relPath')) WHERE valid_to IS NULL;
27178
+ -- Closed rows by relPath, for reviveReobserved (every incremental reindex): the
27179
+ -- live-only index above cannot serve it, so it scanned the whole table (~275 MB
27180
+ -- of a 1.1 GB store per reindex, 2026-10-20).
27181
+ CREATE INDEX IF NOT EXISTS nodes_closed_relpath ON nodes(json_extract(attrs_json, '$.relPath'), last_updated_at) WHERE valid_to IS NOT NULL;
27167
27182
  -- Live rows by name, for looking up the few symbols a statement mentions
27168
27183
  -- instead of hydrating every code symbol per minted problem.
27169
27184
  CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) WHERE valid_to IS NULL;
@@ -27250,6 +27265,7 @@ function rowToEdge(r) {
27250
27265
  }
27251
27266
  var FINGERPRINT_INDEXED_LABELS = ["Problem", "Vulnerability", "Solution", "RootCause"];
27252
27267
  var NODE_LABELS_CHUNK = 256;
27268
+ var PRIOR_TAG_MARKER = '"priorTag":true';
27253
27269
  var SqliteGraphStore = class {
27254
27270
  db;
27255
27271
  // Typed edge lookups build their SQL from the number of types asked for, and
@@ -28311,7 +28327,22 @@ var SqliteGraphStore = class {
28311
28327
  ).get(...edgeTypes, label, cloudOnly ? 1 : 0);
28312
28328
  return { count: Number(r.count), total: Number(r.total) };
28313
28329
  }
28330
+ liveEdgeTargets(edgeTypes) {
28331
+ if (edgeTypes.length === 0) return [];
28332
+ const rows = this.db.prepare(`SELECT DISTINCT to_id FROM edges INDEXED BY edges_type WHERE type IN (${edgeTypes.map(() => "?").join(",")}) AND valid_to IS NULL`).all(...edgeTypes);
28333
+ return rows.map((r) => r.to_id);
28334
+ }
28314
28335
  recentEdgeAttrCoverage(marker, attr, limit) {
28336
+ if (marker === PRIOR_TAG_MARKER) {
28337
+ const r2 = this.db.prepare(
28338
+ `SELECT COUNT(*) AS total,
28339
+ COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
28340
+ FROM (SELECT attrs_json FROM edges INDEXED BY edges_live_prior_tag
28341
+ WHERE valid_to IS NULL AND json_extract(attrs_json, '$.priorTag') = 1
28342
+ ORDER BY created_at DESC LIMIT ?)`
28343
+ ).get(attr, limit);
28344
+ return { count: Number(r2.count), total: Number(r2.total) };
28345
+ }
28315
28346
  const r = this.db.prepare(
28316
28347
  `SELECT COUNT(*) AS total,
28317
28348
  COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
@@ -30164,6 +30195,13 @@ var COLUMN_INPUTS = {
30164
30195
  __createdAtSeq: (n) => n.createdAtSeq !== void 0 && n.createdAtSeq !== null
30165
30196
  };
30166
30197
  function evaluateFed(store2, d, stamps) {
30198
+ const incomingRows = d.fedIncoming && store2.liveEdgeTargets ? stamps?.(d.fedIncoming.label, "source") : void 0;
30199
+ if (d.fedIncoming && incomingRows) {
30200
+ const targets = new Set(store2.liveEdgeTargets(d.fedIncoming.edgeTypes));
30201
+ const rows = d.fedIncoming.cloudOnly ? incomingRows.filter((r) => r.cloud) : incomingRows;
30202
+ const count2 = rows.filter((r) => targets.has(r.id)).length;
30203
+ return { count: count2, total: rows.length, fraction: rows.length === 0 ? 0 : count2 / rows.length };
30204
+ }
30167
30205
  if (d.fedIncoming) {
30168
30206
  const { count: count2, total } = store2.incomingEdgeCoverage?.(
30169
30207
  d.fedIncoming.label,
@@ -30208,6 +30246,7 @@ function evaluateMechanisms(store2, invocations = /* @__PURE__ */ new Map(), mec
30208
30246
  };
30209
30247
  const wanted = /* @__PURE__ */ new Map();
30210
30248
  for (const d of mechanisms) for (const l of d.fed?.labels ?? []) wanted.set(l, (wanted.get(l) ?? /* @__PURE__ */ new Set()).add(d.fed.attr));
30249
+ for (const d of mechanisms) if (d.fedIncoming) wanted.set(d.fedIncoming.label, (wanted.get(d.fedIncoming.label) ?? /* @__PURE__ */ new Set()).add("source"));
30211
30250
  const byLabel = /* @__PURE__ */ new Map();
30212
30251
  const stamps = store2.findNodeStampsByLabelAttrs ? (label, attr) => {
30213
30252
  if (!byLabel.has(label)) byLabel.set(label, store2.findNodeStampsByLabelAttrs(label, [...wanted.get(label) ?? [attr]]));
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "errata-context",
3
- "version": "2.0.22-dev.4624",
3
+ "version": "2.0.22-dev.4630",
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
- 2f2ed72ed3ac78912e2f6d5afbfd43bb55b67b91e397c9c559d045d0b93f1bde .codex-plugin/plugin.json
1
+ c1fadeab6f8e468c4a68d145040bb552c2a78a8506e06fa9fc87e3f8fd6eef10 .codex-plugin/plugin.json
2
2
  a7bebae9fb01c838d6c75fc784129e28be571233fa66ff5ee8039b574f35ccf7 assets/icon.png
3
3
  fc38b64e4df1e0b72c35764bef6c4c05430d97c9009ad0ecc8a9e75b4deab232 configure-local.mjs
4
4
  73dc6028b3b070257c7c31f252d11e55a9e096f4aed0f187f10cb21716e1e6d7 dist/client.js