@inerrata-corporation/errata 2.0.1-dev.60 → 2.0.2-dev.125

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.
@@ -15194,7 +15194,10 @@ var init_edge_rules = __esm({
15194
15194
  // NOT ruled here — the type pre-exists with broader extractor senses, and a
15195
15195
  // new rule on an old type would reject legitimate live flows (reject-never-flip
15196
15196
  // cuts both ways: only rule types you introduce or senses that are documented).
15197
- CONCERNS: { from: ["Problem", "Solution", "RootCause", "Claim", "Pattern"], to: ["Tool"] },
15197
+ // `Component` joined the target set with OM-agent-anchors: an agent-named
15198
+ // component ("React Router") is the same knowledge→named-unit anchor shape as
15199
+ // a Tool — the knowledge is ABOUT it, not dependent on it.
15200
+ CONCERNS: { from: ["Problem", "Solution", "RootCause", "Claim", "Pattern"], to: ["Tool", "Component"] },
15198
15201
  OPERATES_ON: { from: ["Algorithm"], to: ["DataStructure"] },
15199
15202
  INVOLVES: { from: ["Problem", "Solution"], to: ["DataStructure"] },
15200
15203
  // ── Taxonomy (Track 4 Stream C: MITRE CWE `ChildOf` → `Weakness —IS_A→ Weakness`) ──
@@ -15307,7 +15310,12 @@ var init_wire = __esm({
15307
15310
  * knows which packages are private. The door does NOT trust a `public` claim
15308
15311
  * blindly (it re-confirms on the spine); absent ⇒ unknown ⇒ fail-closed to
15309
15312
  * org-private. Accepted-but-ignored until ORG_MEMBRANE_ENABLED flips. */
15310
- anchorVisibility: external_exports.enum(["public", "private"]).optional()
15313
+ anchorVisibility: external_exports.enum(["public", "private"]).optional(),
15314
+ /** The spine-resolvable anchor id backing a `public` tag (OM-anchor-tag): a
15315
+ * Package purl or `languageCanonicalId`. The door validates THIS on the
15316
+ * public spine (falling back to `canonicalId` when absent — context stubs
15317
+ * are self-anchored). Never trusted without spine confirmation. */
15318
+ anchor: external_exports.string().min(1).max(300).optional()
15311
15319
  });
15312
15320
  RouteContextCountWireSchema = external_exports.object({
15313
15321
  confirmed: external_exports.number().int().min(0),
@@ -16023,6 +16031,13 @@ var SqliteGraphStore = class {
16023
16031
  findByLabel: this.db.prepare(
16024
16032
  "SELECT * FROM nodes WHERE label = ? AND valid_to IS NULL"
16025
16033
  ),
16034
+ // Scalar count twin of findByLabel — same live-row semantics, no row
16035
+ // hydration. Exists because status surfaces (daemon `/` + `/health`) used
16036
+ // findNodesByLabel(...).length, materializing every row's attrs JSON and
16037
+ // embedding blob per request — seconds of synchronous loop-hold per poll.
16038
+ countByLabel: this.db.prepare(
16039
+ "SELECT COUNT(*) AS n FROM nodes WHERE label = ? AND valid_to IS NULL"
16040
+ ),
16026
16041
  // ALL versions of a label — incl frozen/closed (valid_to set). Used by the
16027
16042
  // clean-reindex purge so a true wipe removes history too, not just live rows.
16028
16043
  findByLabelAll: this.db.prepare("SELECT * FROM nodes WHERE label = ?"),
@@ -16276,6 +16291,13 @@ var SqliteGraphStore = class {
16276
16291
  const rows = this.stmts.findByLabel.all(label);
16277
16292
  return rows.map(rowToNode);
16278
16293
  }
16294
+ /** Live-row count for a label — `findNodesByLabel(label).length` without the
16295
+ * per-row hydration (attrs JSON + embedding blob). Status surfaces poll this
16296
+ * per project per request; the materializing form held the daemon's event
16297
+ * loop for seconds at scale. */
16298
+ countNodesByLabel(label) {
16299
+ return Number(this.stmts.countByLabel.get(label).n);
16300
+ }
16279
16301
  findAllVersionsByLabel(label) {
16280
16302
  const rows = this.stmts.findByLabelAll.all(label);
16281
16303
  return rows.map(rowToNode);
package/errata.mjs CHANGED
@@ -938,6 +938,12 @@ function packageCanonicalId(p) {
938
938
  const name2 = eco === "npm" ? p.name.toLowerCase() : p.name;
939
939
  return `pkg:${eco}/${name2}${p.version ? `@${p.version}` : ""}`;
940
940
  }
941
+ function versionlessPurl(purl) {
942
+ if (!purl.startsWith("pkg:")) return null;
943
+ const lastSlash = purl.lastIndexOf("/");
944
+ const lastAt = purl.lastIndexOf("@");
945
+ return lastAt > lastSlash ? purl.slice(0, lastAt) : purl;
946
+ }
941
947
  function parsePackageRef(ref) {
942
948
  let rest2 = ref.trim();
943
949
  if (rest2.startsWith("pkg:")) {
@@ -15363,7 +15369,10 @@ var init_edge_rules = __esm({
15363
15369
  // NOT ruled here — the type pre-exists with broader extractor senses, and a
15364
15370
  // new rule on an old type would reject legitimate live flows (reject-never-flip
15365
15371
  // cuts both ways: only rule types you introduce or senses that are documented).
15366
- CONCERNS: { from: ["Problem", "Solution", "RootCause", "Claim", "Pattern"], to: ["Tool"] },
15372
+ // `Component` joined the target set with OM-agent-anchors: an agent-named
15373
+ // component ("React Router") is the same knowledge→named-unit anchor shape as
15374
+ // a Tool — the knowledge is ABOUT it, not dependent on it.
15375
+ CONCERNS: { from: ["Problem", "Solution", "RootCause", "Claim", "Pattern"], to: ["Tool", "Component"] },
15367
15376
  OPERATES_ON: { from: ["Algorithm"], to: ["DataStructure"] },
15368
15377
  INVOLVES: { from: ["Problem", "Solution"], to: ["DataStructure"] },
15369
15378
  // ── Taxonomy (Track 4 Stream C: MITRE CWE `ChildOf` → `Weakness —IS_A→ Weakness`) ──
@@ -15602,7 +15611,12 @@ var init_wire = __esm({
15602
15611
  * knows which packages are private. The door does NOT trust a `public` claim
15603
15612
  * blindly (it re-confirms on the spine); absent ⇒ unknown ⇒ fail-closed to
15604
15613
  * org-private. Accepted-but-ignored until ORG_MEMBRANE_ENABLED flips. */
15605
- anchorVisibility: external_exports.enum(["public", "private"]).optional()
15614
+ anchorVisibility: external_exports.enum(["public", "private"]).optional(),
15615
+ /** The spine-resolvable anchor id backing a `public` tag (OM-anchor-tag): a
15616
+ * Package purl or `languageCanonicalId`. The door validates THIS on the
15617
+ * public spine (falling back to `canonicalId` when absent — context stubs
15618
+ * are self-anchored). Never trusted without spine confirmation. */
15619
+ anchor: external_exports.string().min(1).max(300).optional()
15606
15620
  });
15607
15621
  RouteContextCountWireSchema = external_exports.object({
15608
15622
  confirmed: external_exports.number().int().min(0),
@@ -15993,6 +16007,7 @@ __export(src_exports, {
15993
16007
  toCloudAttrs: () => toCloudAttrs,
15994
16008
  toolCanonicalId: () => toolCanonicalId,
15995
16009
  validateCastaliaPayload: () => validateCastaliaPayload,
16010
+ versionlessPurl: () => versionlessPurl,
15996
16011
  vetSidecarSummaries: () => vetSidecarSummaries
15997
16012
  });
15998
16013
  var init_src = __esm({
@@ -16662,6 +16677,13 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
16662
16677
  findByLabel: this.db.prepare(
16663
16678
  "SELECT * FROM nodes WHERE label = ? AND valid_to IS NULL"
16664
16679
  ),
16680
+ // Scalar count twin of findByLabel — same live-row semantics, no row
16681
+ // hydration. Exists because status surfaces (daemon `/` + `/health`) used
16682
+ // findNodesByLabel(...).length, materializing every row's attrs JSON and
16683
+ // embedding blob per request — seconds of synchronous loop-hold per poll.
16684
+ countByLabel: this.db.prepare(
16685
+ "SELECT COUNT(*) AS n FROM nodes WHERE label = ? AND valid_to IS NULL"
16686
+ ),
16665
16687
  // ALL versions of a label — incl frozen/closed (valid_to set). Used by the
16666
16688
  // clean-reindex purge so a true wipe removes history too, not just live rows.
16667
16689
  findByLabelAll: this.db.prepare("SELECT * FROM nodes WHERE label = ?"),
@@ -16915,6 +16937,13 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
16915
16937
  const rows = this.stmts.findByLabel.all(label);
16916
16938
  return rows.map(rowToNode);
16917
16939
  }
16940
+ /** Live-row count for a label — `findNodesByLabel(label).length` without the
16941
+ * per-row hydration (attrs JSON + embedding blob). Status surfaces poll this
16942
+ * per project per request; the materializing form held the daemon's event
16943
+ * loop for seconds at scale. */
16944
+ countNodesByLabel(label) {
16945
+ return Number(this.stmts.countByLabel.get(label).n);
16946
+ }
16918
16947
  findAllVersionsByLabel(label) {
16919
16948
  const rows = this.stmts.findByLabelAll.all(label);
16920
16949
  return rows.map(rowToNode);
@@ -18316,6 +18345,55 @@ function mintDomainNode(store, name2, ts) {
18316
18345
  }
18317
18346
  return id;
18318
18347
  }
18348
+ function mintCitedPackageNode(store, ref, ts) {
18349
+ const cleaned = ref.replace(/\s+/g, " ").trim();
18350
+ const slash = /^([a-z0-9-]+)\/(.+)$/i.exec(cleaned);
18351
+ const hasEco = slash != null && !cleaned.startsWith("@");
18352
+ const name2 = (hasEco ? slash[2] : cleaned).trim();
18353
+ const nameLc = name2.toLowerCase();
18354
+ const existing = store.findNodesByLabel("Package").find((n) => String(n.attrs["name"] ?? "").toLowerCase() === nameLc);
18355
+ if (existing) return existing.id;
18356
+ let eco = hasEco ? slash[1].toLowerCase() : "";
18357
+ if (!eco && cleaned.startsWith("@")) eco = "npm";
18358
+ if (!eco) {
18359
+ const counts = /* @__PURE__ */ new Map();
18360
+ for (const p of store.findNodesByLabel("Package")) {
18361
+ const e = String(p.attrs["ecosystem"] ?? "").toLowerCase();
18362
+ if (e) counts.set(e, (counts.get(e) ?? 0) + 1);
18363
+ }
18364
+ eco = [...counts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ?? "npm";
18365
+ }
18366
+ const purlName = eco === "npm" ? nameLc : name2;
18367
+ const purl = `pkg:${eco}/${purlName}`;
18368
+ if (!store.getNode(purl)) {
18369
+ store.mergeNode(
18370
+ buildNode(purl, "Package", name2, ts, {
18371
+ purl,
18372
+ name: name2,
18373
+ ecosystem: eco,
18374
+ resolved: false,
18375
+ // agent-cited, no lockfile resolution
18376
+ source: "convo",
18377
+ provisional: true
18378
+ })
18379
+ );
18380
+ }
18381
+ return purl;
18382
+ }
18383
+ function mintComponentNode(store, name2, ts) {
18384
+ const display = name2.replace(/\s+/g, " ").trim();
18385
+ const slug2 = display.toLowerCase();
18386
+ if (!store.getNode(slug2)) {
18387
+ store.mergeNode(
18388
+ buildNode(slug2, "Component", display, ts, {
18389
+ name: display,
18390
+ source: "convo",
18391
+ provisional: true
18392
+ })
18393
+ );
18394
+ }
18395
+ return slug2;
18396
+ }
18319
18397
  function resolveFileNode(store, path2, workspaceId2) {
18320
18398
  const want = path2.trim().replace(/^\.?\//, "");
18321
18399
  for (const n of store.findNodesByLabel("File")) {
@@ -20766,6 +20844,8 @@ __export(src_exports2, {
20766
20844
  matchSymbolsInText: () => matchSymbolsInText,
20767
20845
  mergeCloudCounts: () => mergeCloudCounts,
20768
20846
  mergeDuplicateProblems: () => mergeDuplicateProblems,
20847
+ mintCitedPackageNode: () => mintCitedPackageNode,
20848
+ mintComponentNode: () => mintComponentNode,
20769
20849
  mintDomainNode: () => mintDomainNode,
20770
20850
  mintPatternNode: () => mintPatternNode,
20771
20851
  openGraphStore: () => openGraphStore,
@@ -21530,7 +21610,12 @@ function toWirePayload(batch, runId) {
21530
21610
  // attrs travel; node-level bookkeeping (embedding, momentum counters,
21531
21611
  // bi-temporal fields) is local-stratum and never crosses.
21532
21612
  attrs: n.attrs ?? {},
21533
- extractionSource: n.extractionSource
21613
+ extractionSource: n.extractionSource,
21614
+ // Org-membrane anchor tag (OM-anchor-tag): the batch builders set these
21615
+ // on wire-bound projections only; the door re-validates the claim on the
21616
+ // public spine, so lifting them is routing input, not a grant.
21617
+ ...n.anchorVisibility ? { anchorVisibility: n.anchorVisibility } : {},
21618
+ ...n.anchor ? { anchor: n.anchor } : {}
21534
21619
  }));
21535
21620
  const edges = batch.edges.filter((e) => !droppedNodeIds.has(e.from) && !droppedNodeIds.has(e.to)).map((e) => {
21536
21621
  const perContext = wirePerContext(e.attrs?.["perContext"]);
@@ -25125,6 +25210,11 @@ function linkBullet(ref) {
25125
25210
  ` \xB7 ${TAG_EXAMPLE.domain()} \u2014 name the ABSTRACT AREA it's about (e.g. (domain: Observability),`,
25126
25211
  " (domain: Community Detection)). An abstract problem with no code anchor NEEDS this or it's",
25127
25212
  " an invisible island: the Domain is the topic other problems in the area cluster on. Title Case.",
25213
+ ` \xB7 ${TAG_EXAMPLE.package()} \u2014 the PUBLIC PACKAGE the problem is about, even when this`,
25214
+ " workspace doesn't depend on it (e.g. (package: chokidar), (package: pypi/requests)) \u2014 a",
25215
+ " public-registry anchor lets the knowledge cross to the collective; internal names stay private.",
25216
+ ` \xB7 ${TAG_EXAMPLE.component()} \u2014 the framework/product-level UNIT it concerns when it's not a`,
25217
+ " package or a language (e.g. (component: React Router), (component: V8 Isolate)).",
25128
25218
  ` \xB7 (aids:[${ref}],\u2026) \u2014 your FIX could also help these other, even unrelated, problems.`,
25129
25219
  " A hypothesis, not a claim \u2014 it's recorded as may-resolve and checked by whoever tries it.",
25130
25220
  ` \xB7 when your fix relates to a PRIOR solution you were primed with (a problem's`,
@@ -25196,6 +25286,12 @@ var init_agent_signals = __esm({
25196
25286
  // DOMAIN — the abstract area a problem is about; the concept layer an
25197
25287
  // anchor-less problem clusters on. Mints/resolves a Domain by name.
25198
25288
  domain: () => `(domain: The Area)`,
25289
+ // PACKAGE/COMPONENT — agent-named public anchors (OM-agent-anchors): the
25290
+ // package a problem is ABOUT (even when not a dependency) and the
25291
+ // framework/product-level unit it concerns. Public spine anchors → the
25292
+ // knowledge can cross to the collective.
25293
+ package: () => `(package: the-package-name)`,
25294
+ component: () => `(component: The Component)`,
25199
25295
  aids: (ref) => `(aids:[${ref}])`
25200
25296
  };
25201
25297
  GLOSS = {
@@ -37339,7 +37435,7 @@ var init_mcp = __esm({
37339
37435
  },
37340
37436
  {
37341
37437
  name: "errata.why",
37342
- description: "Causal/resolution neighborhood along the causal edge families (CAUSED_BY, MANIFESTS_AS, FIXED_BY, SOLVED_BY, \u2026), walked in both directions. For a Problem this surfaces its root causes AND solutions; for a Solution, the problems it resolves. Ranked by accumulated conductance. Pass nodeId or qname. Returns {seedId, nodes:[{id,label,description,hops,edgeType,relevance}]}.",
37438
+ description: "Causal/resolution neighborhood along the causal edge families (CAUSED_BY, MANIFESTS_AS, FIXED_BY, SOLVED_BY, \u2026), walked in both directions. For a Problem this surfaces its root causes AND solutions; for a Solution, the problems it resolves. Merges the machine-wide shared store's triage layer (cause chains from inline `<-` diagnoses land there, keyed by the same content-derived problem id). Ranked by accumulated conductance. Pass nodeId or qname. Returns {seedId, nodes:[{id,label,description,hops,edgeType,relevance}]}.",
37343
37439
  inputSchema: {
37344
37440
  type: "object",
37345
37441
  properties: {
@@ -37354,7 +37450,26 @@ var init_mcp = __esm({
37354
37450
  if (!id) return unresolved(args2);
37355
37451
  const maxHops = Math.max(1, Math.min(8, Number(args2["maxHops"] ?? 4)));
37356
37452
  const limit = Math.max(1, Math.min(100, Number(args2["limit"] ?? 30)));
37357
- return { found: true, ...causalChain(store, { seedId: id, direction: "both", maxHops, limit }) };
37453
+ const local = causalChain(store, { seedId: id, direction: "both", maxHops, limit });
37454
+ try {
37455
+ const path2 = sharedStorePath();
37456
+ if (!existsSync10(path2)) return { found: true, ...local };
37457
+ const shared = openGraphStore({ path: path2 });
37458
+ try {
37459
+ if (!shared.getNode(id)) return { found: true, ...local };
37460
+ const l2 = causalChain(shared, { seedId: id, direction: "both", maxHops, limit });
37461
+ const seen = new Set(local.nodes.map((n) => n.id));
37462
+ const merged = [
37463
+ ...local.nodes,
37464
+ ...l2.nodes.filter((n) => !seen.has(n.id)).map((n) => ({ ...n, store: "shared" }))
37465
+ ].sort((a, b) => (b.relevance ?? 0) - (a.relevance ?? 0)).slice(0, limit);
37466
+ return { found: true, seedId: local.seedId, nodes: merged };
37467
+ } finally {
37468
+ shared.close();
37469
+ }
37470
+ } catch {
37471
+ return { found: true, ...local };
37472
+ }
37358
37473
  }
37359
37474
  },
37360
37475
  {
@@ -49594,6 +49709,8 @@ var ALTERNATIVE_PREFIX = /^\s*alternative:(?:#([a-z][\w-]{0,63}))?\s*/i;
49594
49709
  var INSTANCE_PREFIX = /^\s*instance:\s*/i;
49595
49710
  var PATTERN_RE = /\(\s*pattern:\s*([^()\n]{3,}?)\s*\)/gi;
49596
49711
  var DOMAIN_RE = /\(\s*domain:\s*([^()\n]{3,}?)\s*\)/gi;
49712
+ var PACKAGE_RE = /\(\s*package:\s*([^()\n]{2,}?)\s*\)/gi;
49713
+ var COMPONENT_RE = /\(\s*component:\s*([^()\n]{2,}?)\s*\)/gi;
49597
49714
  var CAUSE_TEXT_MIN = 8;
49598
49715
  var FLAG_RE = /\[([!?])(?:#([a-z][\w-]{0,63})\s+)?\s*([^\]\n]{8,}?)\s*(?:@\s*([^\s\]]+?)(?::(\d+))?\s*)?\]/g;
49599
49716
  var CONSTRAINT_MIN = 8;
@@ -49789,6 +49906,18 @@ function parseInlineTags(text) {
49789
49906
  const raw3 = dm[1].replace(/\s+/g, " ").trim();
49790
49907
  if (raw3.length >= 3) out2.push({ kind: "domain", domainText: raw3, sentence: sfield });
49791
49908
  }
49909
+ PACKAGE_RE.lastIndex = 0;
49910
+ let pk;
49911
+ while ((pk = PACKAGE_RE.exec(sentence)) !== null) {
49912
+ const raw3 = pk[1].replace(/\s+/g, " ").trim();
49913
+ if (raw3.length >= 2) out2.push({ kind: "package", packageText: raw3, sentence: sfield });
49914
+ }
49915
+ COMPONENT_RE.lastIndex = 0;
49916
+ let cm;
49917
+ while ((cm = COMPONENT_RE.exec(sentence)) !== null) {
49918
+ const raw3 = cm[1].replace(/\s+/g, " ").trim();
49919
+ if (raw3.length >= 2) out2.push({ kind: "component", componentText: raw3, sentence: sfield });
49920
+ }
49792
49921
  CONSTRAINT_RE.lastIndex = 0;
49793
49922
  let c;
49794
49923
  while ((c = CONSTRAINT_RE.exec(sentence)) !== null) {
@@ -49823,7 +49952,12 @@ var LABEL_PAIR = {
49823
49952
  // EDGE_RULES-clean by construction: CONCERNS allows exactly these sources.
49824
49953
  "Problem>Tool": "CONCERNS",
49825
49954
  "Solution>Tool": "CONCERNS",
49826
- "RootCause>Tool": "CONCERNS"
49955
+ "RootCause>Tool": "CONCERNS",
49956
+ // Agent-named component anchors (OM-agent-anchors): a Component is a
49957
+ // framework/product-level unit the knowledge is ABOUT — CONCERNS, like Tool.
49958
+ "Problem>Component": "CONCERNS",
49959
+ "Solution>Component": "CONCERNS",
49960
+ "RootCause>Component": "CONCERNS"
49827
49961
  };
49828
49962
  var STACK_GROUNDING_EDGES = ["WRITTEN_IN", "DEPENDS_ON", "OCCURS_IN"];
49829
49963
  var TIEBREAK = [
@@ -49922,7 +50056,7 @@ function harvestInlineTags(store, text, opts) {
49922
50056
  const source = opts.sourceId ? store.getNode(opts.sourceId) : null;
49923
50057
  const mintPriors = opts.mintPriors ?? true;
49924
50058
  const touched = opts.sessionTouchedIds ?? /* @__PURE__ */ new Set();
49925
- const plan = { priorEdges: 0, problems: [], fixes: [], triages: [], attempts: [], unresolvedFixes: [], transfers: [], solutionLinks: [], instances: [], patterns: [], domains: [], refutes: [], corroborations: [] };
50059
+ const plan = { priorEdges: 0, problems: [], fixes: [], triages: [], attempts: [], unresolvedFixes: [], transfers: [], solutionLinks: [], instances: [], patterns: [], domains: [], packages: [], components: [], refutes: [], corroborations: [] };
49926
50060
  const tags = parseInlineTags(text);
49927
50061
  const symptomSeqs = tags.filter((t) => (t.kind === "problem" || t.kind === "todo" || t.kind === "constraint") && t.statement).map((t) => ({ seq: t.seq ?? -1, statement: t.statement, threadId: t.threadId })).sort((a, b) => a.seq - b.seq);
49928
50062
  const bindSymptom = (seq, threadId) => {
@@ -50062,6 +50196,16 @@ function harvestInlineTags(store, text, opts) {
50062
50196
  ...tag.threadId ? { threadId: tag.threadId } : {},
50063
50197
  evidence: b.evidence
50064
50198
  });
50199
+ } else if (tag.kind === "package" || tag.kind === "component") {
50200
+ const b = bindSymptom(tag.seq, tag.threadId);
50201
+ const bound = {
50202
+ ...b.statement ? { boundStatement: b.statement } : {},
50203
+ ...b.problemId ? { problemId: b.problemId } : {},
50204
+ ...tag.threadId ? { threadId: tag.threadId } : {},
50205
+ evidence: b.evidence
50206
+ };
50207
+ if (tag.kind === "package") plan.packages.push({ packageText: tag.packageText, ...bound });
50208
+ else plan.components.push({ componentText: tag.componentText, ...bound });
50065
50209
  } else if (tag.kind === "attempt" || tag.kind === "failure") {
50066
50210
  for (const h of tag.refuteHandles ?? []) {
50067
50211
  const nodeId = resolveHandle(store, h, opts.handleMap);
@@ -50086,6 +50230,17 @@ function harvestInlineTags(store, text, opts) {
50086
50230
  boundStatement: b.statement
50087
50231
  });
50088
50232
  }
50233
+ } else if (tag.kind === "prior") {
50234
+ const targetId = resolveHandle(store, tag.handle, opts.handleMap);
50235
+ const target = targetId ? store.getNode(targetId) : null;
50236
+ const citedLabel = target?.label ?? opts.handleMap[tag.handle]?.label;
50237
+ if (targetId && citedLabel && CORROBORATABLE_LABELS.has(citedLabel)) {
50238
+ const witnessKey = `corrob:${targetId}:lean:${digest({ h: tag.handle })}`.slice(0, 72);
50239
+ if (!plan.corroborations.some((c) => c.witnessKey === witnessKey)) {
50240
+ plan.corroborations.push({ nodeId: targetId, witnessKey });
50241
+ }
50242
+ }
50243
+ if (mintPriors && source && target && mintPriorEdge(store, source, target, tag.sentence, touched, opts.ts)) plan.priorEdges++;
50089
50244
  } else if (mintPriors && source) {
50090
50245
  const targetId = resolveHandle(store, tag.handle, opts.handleMap);
50091
50246
  const target = targetId ? store.getNode(targetId) : null;
@@ -50094,6 +50249,12 @@ function harvestInlineTags(store, text, opts) {
50094
50249
  }
50095
50250
  return plan;
50096
50251
  }
50252
+ var CORROBORATABLE_LABELS = /* @__PURE__ */ new Set(["Problem", "Solution", "RootCause"]);
50253
+ function stampWitnessOrigin(items, origin) {
50254
+ if (!origin) return [...items];
50255
+ const o = digest({ p: origin }).slice(0, 12);
50256
+ return items.map((i2) => ({ ...i2, witnessKey: `${i2.witnessKey}:o:${o}` }));
50257
+ }
50097
50258
 
50098
50259
  // src/rollup.ts
50099
50260
  function readConversation(transcriptPath, includeThinking = true, maxChars = 6e4) {
@@ -50596,7 +50757,9 @@ function generalizeRouteForSync(edge2, level) {
50596
50757
  navFailures: 0
50597
50758
  };
50598
50759
  }
50599
- function buildTriageIngest(shared, daemonVersion, ignorePatterns = [], level = 2) {
50760
+ function buildTriageIngest(shared, daemonVersion, ignorePatterns = [], level = 2, opts = {}) {
50761
+ const lang = opts.primaryLanguage?.trim().toLowerCase();
50762
+ const claim = lang ? { anchorVisibility: "public", anchor: `lang:${lang}` } : {};
50600
50763
  const nodes = [];
50601
50764
  const edges = [];
50602
50765
  const seenIds = /* @__PURE__ */ new Set();
@@ -50609,7 +50772,8 @@ function buildTriageIngest(shared, daemonVersion, ignorePatterns = [], level = 2
50609
50772
  ...n,
50610
50773
  description: generalize(n.description, { level }).text,
50611
50774
  embedding: [],
50612
- attrs: { scope: {} }
50775
+ attrs: { scope: {} },
50776
+ ...claim
50613
50777
  });
50614
50778
  };
50615
50779
  for (const tri of shared.findNodesByLabel("Triage")) {
@@ -50625,7 +50789,8 @@ function buildTriageIngest(shared, daemonVersion, ignorePatterns = [], level = 2
50625
50789
  attrs: {
50626
50790
  ...statement ? { statement: generalize(statement, { level }).text } : {},
50627
50791
  ...tri.attrs["perContextSeen"] ? { perContextSeen: tri.attrs["perContextSeen"] } : {}
50628
- }
50792
+ },
50793
+ ...claim
50629
50794
  });
50630
50795
  }
50631
50796
  for (const tb of shared.inEdges(tri.id, ["TRIAGED_BY"])) {
@@ -51664,7 +51829,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
51664
51829
  }
51665
51830
 
51666
51831
  // src/engine.ts
51667
- var DAEMON_VERSION = true ? "2.0.1-dev.60" : "2.0.0-alpha.0";
51832
+ var DAEMON_VERSION = true ? "2.0.2-dev.125" : "2.0.0-alpha.0";
51668
51833
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
51669
51834
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
51670
51835
  var GIT_OP_MUTE_MS = 4e3;
@@ -52498,6 +52663,20 @@ function createWorkspaceEngine(opts) {
52498
52663
  if (domainId === pid) continue;
52499
52664
  mintCiteEdge(pid, domainId, "PERTAIN_TO", d.evidence === "witnessed" ? 0.4 : 0.3, { domainCite: true, evidence: d.evidence });
52500
52665
  }
52666
+ for (const p of plan.packages) {
52667
+ const pid = bindPid(p);
52668
+ if (!pid) continue;
52669
+ const pkgId = mintCitedPackageNode(store, p.packageText, t);
52670
+ if (pkgId === pid) continue;
52671
+ mintCiteEdge(pid, pkgId, "DEPENDS_ON", p.evidence === "witnessed" ? 0.4 : 0.3, { packageCite: true, evidence: p.evidence });
52672
+ }
52673
+ for (const cpt of plan.components) {
52674
+ const pid = bindPid(cpt);
52675
+ if (!pid) continue;
52676
+ const componentId = mintComponentNode(store, cpt.componentText, t);
52677
+ if (componentId === pid) continue;
52678
+ mintCiteEdge(pid, componentId, "CONCERNS", cpt.evidence === "witnessed" ? 0.4 : 0.3, { componentCite: true, evidence: cpt.evidence });
52679
+ }
52501
52680
  for (const inst of plan.instances) {
52502
52681
  const pid = bindPid(inst);
52503
52682
  if (!pid) continue;
@@ -52539,14 +52718,14 @@ function createWorkspaceEngine(opts) {
52539
52718
  }
52540
52719
  }
52541
52720
  if (plan.refutes.length > 0 && typeof cloud.reportContradictions === "function") {
52542
- void cloud.reportContradictions({ daemonVersion: DAEMON_VERSION, projectId: profile.id, items: plan.refutes }).then((r) => {
52721
+ void cloud.reportContradictions({ daemonVersion: DAEMON_VERSION, projectId: profile.id, items: stampWitnessOrigin(plan.refutes, profile.id) }).then((r) => {
52543
52722
  if (r?.recorded) console.log(`[errata] refute: ${r.recorded} contradiction(s) recorded`);
52544
52723
  }).catch(
52545
52724
  (err2) => console.warn("[errata] refute transport failed (continuing):", err2 instanceof Error ? err2.message : err2)
52546
52725
  );
52547
52726
  }
52548
52727
  if (plan.corroborations.length > 0 && typeof cloud.reportCorroborations === "function") {
52549
- void cloud.reportCorroborations({ daemonVersion: DAEMON_VERSION, projectId: profile.id, items: plan.corroborations }).then((r) => {
52728
+ void cloud.reportCorroborations({ daemonVersion: DAEMON_VERSION, projectId: profile.id, items: stampWitnessOrigin(plan.corroborations, profile.id) }).then((r) => {
52550
52729
  if (r?.recorded) console.log(`[errata] corroborate: ${r.recorded} corroboration(s) recorded`);
52551
52730
  }).catch(
52552
52731
  (err2) => console.warn("[errata] corroboration transport failed (continuing):", err2 instanceof Error ? err2.message : err2)
@@ -53262,7 +53441,12 @@ function buildContextIngest(store, profile, daemonVersion, ignorePatterns = [],
53262
53441
  name: n.attrs["name"],
53263
53442
  ecosystem: n.attrs["ecosystem"],
53264
53443
  resolved: n.attrs["resolved"]
53265
- } : { name: n.attrs["name"] }
53444
+ } : { name: n.attrs["name"] },
53445
+ // OM-anchor-tag: context stubs are self-anchored — the wire id IS the
53446
+ // spine key (purl / languageCanonicalId). The door re-confirms on the
53447
+ // public spine; a private-registry or workspace package never confirms
53448
+ // and fails closed to org, exactly as an untagged one would.
53449
+ anchorVisibility: "public"
53266
53450
  });
53267
53451
  seen.add(n.id);
53268
53452
  }
@@ -53276,6 +53460,10 @@ function buildContextIngest(store, profile, daemonVersion, ignorePatterns = [],
53276
53460
  }
53277
53461
  const base = {
53278
53462
  daemonVersion,
53463
+ // Origin key (= project, the salted `wp_…`) — the door stamps it onto created
53464
+ // nodes as `authoringProject`, arming the evidence channels' cross-origin gate
53465
+ // (EE-corrob-live: without it every node is fail-open to self-corroboration).
53466
+ ...profile.id ? { originProject: profile.id } : {},
53279
53467
  profile: { stack: profile.stack, languages: profile.languages, domains: profile.domains },
53280
53468
  nodes,
53281
53469
  edges
@@ -53355,8 +53543,8 @@ function noveltyAgainst(node2, neighbors, opts = {}) {
53355
53543
  // src/instance-ingest.ts
53356
53544
  var INSTANCE_LABELS = ["Problem", "Solution", "RootCause"];
53357
53545
  var INSTANCE_EDGES = ["CAUSED_BY", "SOLVED_BY"];
53358
- var ANCHOR_EDGES = ["OCCURS_IN", "DEPENDS_ON", "PERTAIN_TO"];
53359
- var ANCHOR_TARGET_LABELS = ["Language", "Package", "Domain"];
53546
+ var ANCHOR_EDGES = ["OCCURS_IN", "DEPENDS_ON", "PERTAIN_TO", "CONCERNS"];
53547
+ var ANCHOR_TARGET_LABELS = ["Language", "Package", "Domain", "Component"];
53360
53548
  function stripCodebaseScope(scope) {
53361
53549
  const s = { ...scope ?? {} };
53362
53550
  delete s["codebase"];
@@ -53372,6 +53560,10 @@ function wireContextId(n) {
53372
53560
  }
53373
53561
  return n.id;
53374
53562
  }
53563
+ function langAnchor(t) {
53564
+ const name2 = String(t.attrs["name"] ?? "").trim() || t.description.trim() || t.id.replace(/^lang:/, "").trim();
53565
+ return name2 ? `lang:${name2.toLowerCase()}` : void 0;
53566
+ }
53375
53567
  function shareableContext(n, wireId) {
53376
53568
  const attrs = n.label === "Package" ? {
53377
53569
  // No `version` attr: the purl encodes it, and the door's temporal
@@ -53381,7 +53573,18 @@ function shareableContext(n, wireId) {
53381
53573
  ecosystem: n.attrs["ecosystem"],
53382
53574
  resolved: n.attrs["resolved"]
53383
53575
  } : n.label === "Domain" ? { name: n.description, canonicalId: n.attrs["canonicalId"] } : { name: n.attrs["name"] };
53384
- return { ...n, id: wireId, embedding: [], attrs };
53576
+ return {
53577
+ ...n,
53578
+ id: wireId,
53579
+ embedding: [],
53580
+ attrs,
53581
+ ...n.label === "Package" ? { anchorVisibility: "public" } : {},
53582
+ ...n.label === "Language" && langAnchor(n) ? { anchorVisibility: "public", anchor: langAnchor(n) } : {},
53583
+ // A Component stub claims itself by slug (OM-agent-anchors) — the door
53584
+ // confirms only against an EXISTING public Component of that slug, so an
53585
+ // org-internal component name never crosses (fails closed to org).
53586
+ ...n.label === "Component" ? { anchorVisibility: "public", anchor: `component:${wireId}` } : {}
53587
+ };
53385
53588
  }
53386
53589
  function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [], opts = {}) {
53387
53590
  const level = opts.level ?? 1;
@@ -53399,6 +53602,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
53399
53602
  });
53400
53603
  const nodes = [];
53401
53604
  const seen = /* @__PURE__ */ new Set();
53605
+ const shippedById = /* @__PURE__ */ new Map();
53402
53606
  const anchorSources = /* @__PURE__ */ new Set();
53403
53607
  const includedByLabel = /* @__PURE__ */ new Map();
53404
53608
  for (const label of INSTANCE_LABELS) {
@@ -53416,7 +53620,9 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
53416
53620
  }
53417
53621
  if (!noveltyAgainst(n, ref, noveltyOpts).ready) continue;
53418
53622
  ref.push(n);
53419
- nodes.push(shareable(n));
53623
+ const wireNode = shareable(n);
53624
+ nodes.push(wireNode);
53625
+ shippedById.set(n.id, wireNode);
53420
53626
  seen.add(n.id);
53421
53627
  anchorSources.add(n.id);
53422
53628
  }
@@ -53438,11 +53644,23 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
53438
53644
  if (e.type === "OCCURS_IN" && t.label !== "Language") continue;
53439
53645
  if (e.type === "DEPENDS_ON" && t.label !== "Package") continue;
53440
53646
  if (e.type === "PERTAIN_TO" && t.label !== "Domain") continue;
53441
- if (t.label === "Package" && opts.includePackages !== true) continue;
53647
+ if (e.type === "CONCERNS" && t.label !== "Component") continue;
53648
+ if ((t.label === "Package" || t.label === "Component") && opts.includePackages !== true) continue;
53442
53649
  if (ignored(t.description) || ignored(String(t.attrs["name"] ?? ""))) continue;
53443
53650
  targets.push({ e, t, wireId: wireContextId(t) });
53444
53651
  }
53445
53652
  if (targets.length === 0) continue;
53653
+ const shipped = shippedById.get(sourceId);
53654
+ if (shipped) {
53655
+ const anchors = (label) => targets.filter((x) => x.t.label === label).map(
53656
+ (x) => label === "Language" ? langAnchor(x.t) : label === "Component" ? `component:${x.wireId}` : x.wireId
53657
+ ).filter((a) => a != null).sort();
53658
+ const anchor = anchors("Package")[0] ?? anchors("Component")[0] ?? anchors("Language")[0];
53659
+ if (anchor) {
53660
+ shipped.anchorVisibility = "public";
53661
+ shipped.anchor = anchor;
53662
+ }
53663
+ }
53446
53664
  const dg = digest(targets.map(({ e, wireId }) => `${e.type}>${wireId}`).sort());
53447
53665
  const sourceNode = store.getNode(sourceId);
53448
53666
  if (sourceNode?.attrs["anchorsContributedDigest"] === dg) continue;
@@ -53456,6 +53674,15 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
53456
53674
  contextNodes.push(shareableContext(t, wireId));
53457
53675
  }
53458
53676
  }
53677
+ const primaryLang = (profile.languages ?? []).map((l) => String(l).trim().toLowerCase()).filter(Boolean)[0];
53678
+ if (primaryLang) {
53679
+ for (const shipped of shippedById.values()) {
53680
+ if (!shipped.anchorVisibility) {
53681
+ shipped.anchorVisibility = "public";
53682
+ shipped.anchor = `lang:${primaryLang}`;
53683
+ }
53684
+ }
53685
+ }
53459
53686
  const project = opts.project;
53460
53687
  if (project) {
53461
53688
  const now = Date.now();
@@ -53533,6 +53760,11 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
53533
53760
  edges.push(...anchorEdges);
53534
53761
  const base = {
53535
53762
  daemonVersion,
53763
+ // Origin key (= project, the salted `wp_…`) — the door stamps it onto created
53764
+ // nodes as `authoringProject`, arming the evidence channels' cross-origin gate
53765
+ // (EE-corrob-live: this is the MAIN semantic drain; without the stamp every
53766
+ // Problem/Solution lands fail-open to self-corroboration).
53767
+ ...profile.id ? { originProject: profile.id } : {},
53536
53768
  profile: { stack: profile.stack, languages: profile.languages, domains: profile.domains },
53537
53769
  // Context nodes FIRST: a chunked drain (cloud-client, 25-node chunks) then
53538
53770
  // co-locates the few Language/Package stubs with the first instance chunk,
@@ -54159,8 +54391,10 @@ async function startMultiDaemon(opts = {}) {
54159
54391
  path: r.root,
54160
54392
  stack: r.entry.stack,
54161
54393
  nodes: r.engine.store.nodeCount(),
54162
- problems: r.engine.store.findNodesByLabel("Problem").length,
54163
- solutions: r.engine.store.findNodesByLabel("Solution").length,
54394
+ // COUNT(*) — the materializing findNodesByLabel(...).length form held
54395
+ // the event loop for seconds per poll once stores grew (HZ-index-hydrate).
54396
+ problems: r.engine.store.countNodesByLabel("Problem"),
54397
+ solutions: r.engine.store.countNodesByLabel("Solution"),
54164
54398
  endpoints: `/ws/${r.id}/`
54165
54399
  })),
54166
54400
  humanView: "run `errata report` \u2014 the dashboard was retired (GRAFT 4e)"
@@ -54216,8 +54450,9 @@ async function startMultiDaemon(opts = {}) {
54216
54450
  name: r.entry.name,
54217
54451
  path: r.root,
54218
54452
  nodes: r.engine.store.nodeCount(),
54219
- problems: r.engine.store.findNodesByLabel("Problem").length,
54220
- solutions: r.engine.store.findNodesByLabel("Solution").length,
54453
+ // COUNT(*) — same hydration hazard as `/` (HZ-index-hydrate).
54454
+ problems: r.engine.store.countNodesByLabel("Problem"),
54455
+ solutions: r.engine.store.countNodesByLabel("Solution"),
54221
54456
  stranded: strandedCount(r)
54222
54457
  }))
54223
54458
  })
@@ -54586,7 +54821,19 @@ async function startMultiDaemon(opts = {}) {
54586
54821
  async syncTriagePublic() {
54587
54822
  if (!loadConfig().consent.sync) return { uploaded: 0, skipped: "consent-off" };
54588
54823
  const ignore = loadClaimIgnorePatterns(globalDir());
54589
- const payload = buildTriageIngest(sharedStore, DAEMON_VERSION, ignore);
54824
+ const langCounts = /* @__PURE__ */ new Map();
54825
+ for (const r of records) {
54826
+ for (const l of r.engine.profile.languages ?? []) {
54827
+ const k = String(l).trim().toLowerCase();
54828
+ if (k) langCounts.set(k, (langCounts.get(k) ?? 0) + 1);
54829
+ }
54830
+ }
54831
+ const primaryLanguage = [...langCounts.entries()].sort(
54832
+ (a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : 1)
54833
+ )[0]?.[0];
54834
+ const payload = buildTriageIngest(sharedStore, DAEMON_VERSION, ignore, 2, {
54835
+ ...primaryLanguage ? { primaryLanguage } : {}
54836
+ });
54590
54837
  if (!payload) return { uploaded: 0 };
54591
54838
  const res = await cloudNow().ingest(payload);
54592
54839
  return { uploaded: res.accepted };
@@ -54773,6 +55020,8 @@ async function startMultiDaemon(opts = {}) {
54773
55020
  }
54774
55021
  };
54775
55022
  app.post("/api/sync", async (c) => {
55023
+ if (boundaryFlushing) return c.json({ skipped: "in-flight" }, 409);
55024
+ boundaryFlushing = true;
54776
55025
  try {
54777
55026
  const principles = await daemon.syncPrinciplesPublic();
54778
55027
  const triage = await daemon.syncTriagePublic();
@@ -54781,6 +55030,8 @@ async function startMultiDaemon(opts = {}) {
54781
55030
  return c.json({ principles, triage, instances, edgeBackfill });
54782
55031
  } catch (err2) {
54783
55032
  return c.json({ error: err2 instanceof Error ? err2.message : String(err2) }, 500);
55033
+ } finally {
55034
+ boundaryFlushing = false;
54784
55035
  }
54785
55036
  });
54786
55037
  app.post("/api/tick", async (c) => {
@@ -57604,8 +57855,12 @@ async function cmdSync(arg) {
57604
57855
  try {
57605
57856
  const res = await fetch(`${lock.webUiUrl}/api/sync`, {
57606
57857
  method: "POST",
57607
- signal: AbortSignal.timeout(3e4)
57858
+ signal: AbortSignal.timeout(15 * 6e4)
57608
57859
  });
57860
+ if (res.status === 409) {
57861
+ console.log("sync already running: the daemon is mid-drain \u2014 it will finish on its own. Nothing new was started.");
57862
+ return;
57863
+ }
57609
57864
  if (!res.ok) {
57610
57865
  const detail = await res.text().catch(() => "");
57611
57866
  console.error(`sync failed: daemon at ${lock.webUiUrl} returned ${res.status}${detail ? ` \u2014 ${detail}` : ""}`);
@@ -57616,7 +57871,7 @@ async function cmdSync(arg) {
57616
57871
  } catch (err2) {
57617
57872
  const timedOut = err2 instanceof Error && err2.name === "TimeoutError";
57618
57873
  console.error(
57619
- timedOut ? `sync failed: the running daemon at ${lock.webUiUrl} didn't respond within 30s \u2014 it may be mid-reindex. Retry shortly.` : `sync failed: could not reach the running daemon at ${lock.webUiUrl} (${err2 instanceof Error ? err2.message : err2})`
57874
+ timedOut ? `sync gave up waiting after 15 min \u2014 the daemon's pass may STILL be running (aborting this request does not cancel it). Check daemon.log before retrying; a retry while it runs answers 409.` : `sync failed: could not reach the running daemon at ${lock.webUiUrl} (${err2 instanceof Error ? err2.message : err2})`
57620
57875
  );
57621
57876
  process.exit(1);
57622
57877
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.1-dev.60",
3
+ "version": "2.0.2-dev.125",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -15049,7 +15049,10 @@ var init_edge_rules = __esm({
15049
15049
  // NOT ruled here — the type pre-exists with broader extractor senses, and a
15050
15050
  // new rule on an old type would reject legitimate live flows (reject-never-flip
15051
15051
  // cuts both ways: only rule types you introduce or senses that are documented).
15052
- CONCERNS: { from: ["Problem", "Solution", "RootCause", "Claim", "Pattern"], to: ["Tool"] },
15052
+ // `Component` joined the target set with OM-agent-anchors: an agent-named
15053
+ // component ("React Router") is the same knowledge→named-unit anchor shape as
15054
+ // a Tool — the knowledge is ABOUT it, not dependent on it.
15055
+ CONCERNS: { from: ["Problem", "Solution", "RootCause", "Claim", "Pattern"], to: ["Tool", "Component"] },
15053
15056
  OPERATES_ON: { from: ["Algorithm"], to: ["DataStructure"] },
15054
15057
  INVOLVES: { from: ["Problem", "Solution"], to: ["DataStructure"] },
15055
15058
  // ── Taxonomy (Track 4 Stream C: MITRE CWE `ChildOf` → `Weakness —IS_A→ Weakness`) ──
@@ -15162,7 +15165,12 @@ var init_wire = __esm({
15162
15165
  * knows which packages are private. The door does NOT trust a `public` claim
15163
15166
  * blindly (it re-confirms on the spine); absent ⇒ unknown ⇒ fail-closed to
15164
15167
  * org-private. Accepted-but-ignored until ORG_MEMBRANE_ENABLED flips. */
15165
- anchorVisibility: external_exports.enum(["public", "private"]).optional()
15168
+ anchorVisibility: external_exports.enum(["public", "private"]).optional(),
15169
+ /** The spine-resolvable anchor id backing a `public` tag (OM-anchor-tag): a
15170
+ * Package purl or `languageCanonicalId`. The door validates THIS on the
15171
+ * public spine (falling back to `canonicalId` when absent — context stubs
15172
+ * are self-anchored). Never trusted without spine confirmation. */
15173
+ anchor: external_exports.string().min(1).max(300).optional()
15166
15174
  });
15167
15175
  RouteContextCountWireSchema = external_exports.object({
15168
15176
  confirmed: external_exports.number().int().min(0),
@@ -24330,6 +24338,13 @@ var SqliteGraphStore = class {
24330
24338
  findByLabel: this.db.prepare(
24331
24339
  "SELECT * FROM nodes WHERE label = ? AND valid_to IS NULL"
24332
24340
  ),
24341
+ // Scalar count twin of findByLabel — same live-row semantics, no row
24342
+ // hydration. Exists because status surfaces (daemon `/` + `/health`) used
24343
+ // findNodesByLabel(...).length, materializing every row's attrs JSON and
24344
+ // embedding blob per request — seconds of synchronous loop-hold per poll.
24345
+ countByLabel: this.db.prepare(
24346
+ "SELECT COUNT(*) AS n FROM nodes WHERE label = ? AND valid_to IS NULL"
24347
+ ),
24333
24348
  // ALL versions of a label — incl frozen/closed (valid_to set). Used by the
24334
24349
  // clean-reindex purge so a true wipe removes history too, not just live rows.
24335
24350
  findByLabelAll: this.db.prepare("SELECT * FROM nodes WHERE label = ?"),
@@ -24583,6 +24598,13 @@ var SqliteGraphStore = class {
24583
24598
  const rows = this.stmts.findByLabel.all(label);
24584
24599
  return rows.map(rowToNode);
24585
24600
  }
24601
+ /** Live-row count for a label — `findNodesByLabel(label).length` without the
24602
+ * per-row hydration (attrs JSON + embedding blob). Status surfaces poll this
24603
+ * per project per request; the materializing form held the daemon's event
24604
+ * loop for seconds at scale. */
24605
+ countNodesByLabel(label) {
24606
+ return Number(this.stmts.countByLabel.get(label).n);
24607
+ }
24586
24608
  findAllVersionsByLabel(label) {
24587
24609
  const rows = this.stmts.findByLabelAll.all(label);
24588
24610
  return rows.map(rowToNode);