@inerrata-corporation/errata 2.0.0-dev.22 → 2.0.0-dev.24

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.
Files changed (3) hide show
  1. package/consolidate-worker.mjs +11565 -10638
  2. package/errata.mjs +207 -65
  3. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -790,6 +790,12 @@ function identityId(input) {
790
790
  );
791
791
  }
792
792
  }
793
+ function genericCanonicalId(prefix, content) {
794
+ return `${prefix}_${digest(content)}`.slice(0, 56);
795
+ }
796
+ function languageCanonicalId(name2) {
797
+ return genericCanonicalId("Language", { name: name2.trim().toLowerCase() });
798
+ }
793
799
  var DESIGN_PROBLEM_PREFIX, DESIGN_PROBLEM_ID_LENGTH, DIAGNOSTIC_PROBLEM_PREFIX, DIAGNOSTIC_HASH_LENGTH, TRIAGE_PREFIX, TRIAGE_ID_LENGTH;
794
800
  var init_identity = __esm({
795
801
  "../../packages/shared/src/identity.ts"() {
@@ -20117,14 +20123,22 @@ var init_client = __esm({
20117
20123
  return { ...summarizeIngestResult(result), result };
20118
20124
  }
20119
20125
  const merged = { runId, nodes: [], edges: [] };
20126
+ let pendingEdges = [...batch.edges];
20120
20127
  for (const nodeChunk of chunkArray(batch.nodes, INGEST_NODE_CHUNK)) {
20121
- const r = await this.ingestWire(toWirePayload({ ...batch, nodes: nodeChunk, edges: [] }, runId));
20128
+ const ids = new Set(nodeChunk.map((n) => n.id));
20129
+ const inChunk = pendingEdges.filter((e) => ids.has(e.from) && ids.has(e.to)).slice(0, MAX_EDGES_PER_PAYLOAD);
20130
+ if (inChunk.length > 0) {
20131
+ const shipped = new Set(inChunk);
20132
+ pendingEdges = pendingEdges.filter((e) => !shipped.has(e));
20133
+ }
20134
+ const r = await this.ingestWire(toWirePayload({ ...batch, nodes: nodeChunk, edges: inChunk }, runId));
20122
20135
  merged.nodes.push(...r.nodes);
20136
+ merged.edges.push(...r.edges);
20123
20137
  if (r.patternReconciliation) {
20124
20138
  merged.patternReconciliation = { ...merged.patternReconciliation, ...r.patternReconciliation };
20125
20139
  }
20126
20140
  }
20127
- for (const edgeChunk of chunkArray(batch.edges, MAX_EDGES_PER_PAYLOAD)) {
20141
+ for (const edgeChunk of chunkArray(pendingEdges, MAX_EDGES_PER_PAYLOAD)) {
20128
20142
  const r = await this.ingestWire(toWirePayload({ ...batch, nodes: [], edges: edgeChunk }, runId));
20129
20143
  merged.edges.push(...r.edges);
20130
20144
  }
@@ -24968,7 +24982,7 @@ var init_motifs = __esm({
24968
24982
 
24969
24983
  // ../../packages/generalizer/src/nightly.ts
24970
24984
  function runNightlyPipeline(store) {
24971
- const started = Date.now();
24985
+ const started2 = Date.now();
24972
24986
  const allowedTypes = new Set(pagerankEdgeTypes());
24973
24987
  const nodeIds = [];
24974
24988
  const meta3 = /* @__PURE__ */ new Map();
@@ -25049,9 +25063,9 @@ function runNightlyPipeline(store) {
25049
25063
  store.transaction(() => {
25050
25064
  for (const [id, c] of comm.community) store.updateNode(id, { community: c });
25051
25065
  });
25052
- const motifs = promoteMotifs(store, started);
25053
- const designResolved = resolveDesignProblems(store, started);
25054
- const cry = crystallize(store, { ts: started });
25066
+ const motifs = promoteMotifs(store, started2);
25067
+ const designResolved = resolveDesignProblems(store, started2);
25068
+ const cry = crystallize(store, { ts: started2 });
25055
25069
  return {
25056
25070
  scoredNodes: scored,
25057
25071
  iterations: result.iterations,
@@ -25067,7 +25081,7 @@ function runNightlyPipeline(store) {
25067
25081
  designResolved,
25068
25082
  claimsEvaluated: cry.evaluated,
25069
25083
  claimsDerived: cry.derived.length,
25070
- durationMs: Date.now() - started
25084
+ durationMs: Date.now() - started2
25071
25085
  };
25072
25086
  }
25073
25087
  function codeAnchorProjection(store, semanticIds, opts = {}) {
@@ -25110,7 +25124,7 @@ function embedSemanticNodes(store, opts = {}) {
25110
25124
  return embedNodesByLabels(store, SEMANTIC_LABELS, opts);
25111
25125
  }
25112
25126
  async function embedNodesByLabels(store, labels, opts = {}) {
25113
- const started = Date.now();
25127
+ const started2 = Date.now();
25114
25128
  const report = {
25115
25129
  scanned: 0,
25116
25130
  embedded: 0,
@@ -25164,7 +25178,7 @@ async function embedNodesByLabels(store, labels, opts = {}) {
25164
25178
  });
25165
25179
  if (opts.progress) opts.progress(report.embedded, todo.length);
25166
25180
  }
25167
- report.durationMs = Date.now() - started;
25181
+ report.durationMs = Date.now() - started2;
25168
25182
  return report;
25169
25183
  }
25170
25184
  function buildText(store, node2) {
@@ -25884,16 +25898,16 @@ async function incrementalReindex(store, rootPath, workspaceId2, changedAbsPaths
25884
25898
  };
25885
25899
  }
25886
25900
  async function runIndexer(store, opts) {
25887
- const started = Date.now();
25901
+ const started2 = Date.now();
25888
25902
  indexNow = opts.now ?? Date.now();
25889
25903
  const ignores = /* @__PURE__ */ new Set([...DEFAULT_IGNORES, ...opts.ignoreDirs ?? []]);
25890
25904
  const maxBytes = opts.maxFileBytes ?? 1024 * 1024;
25891
- let perfLast = started;
25905
+ let perfLast = started2;
25892
25906
  const perfFile = process.env["ERRATA_PERF"];
25893
25907
  const perf = (label) => {
25894
25908
  if (!perfFile) return;
25895
25909
  const now = Date.now();
25896
- const line = `[perf] ${label}: ${now - perfLast}ms (total ${now - started}ms)
25910
+ const line = `[perf] ${label}: ${now - perfLast}ms (total ${now - started2}ms)
25897
25911
  `;
25898
25912
  perfLast = now;
25899
25913
  try {
@@ -26368,7 +26382,7 @@ async function runIndexer(store, opts) {
26368
26382
  }
26369
26383
  }
26370
26384
  perf("flush cross-file edges");
26371
- report.durationMs = Date.now() - started;
26385
+ report.durationMs = Date.now() - started2;
26372
26386
  indexNow = null;
26373
26387
  return report;
26374
26388
  }
@@ -41077,7 +41091,7 @@ function maybeFlushDigests() {
41077
41091
  }
41078
41092
 
41079
41093
  // src/engine.ts
41080
- var DAEMON_VERSION = true ? "2.0.0-dev.22" : "2.0.0-alpha.0";
41094
+ var DAEMON_VERSION = true ? "2.0.0-dev.24" : "2.0.0-alpha.0";
41081
41095
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
41082
41096
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
41083
41097
  var GIT_OP_MUTE_MS = 4e3;
@@ -42367,6 +42381,10 @@ function buildContextIngest(store, profile, daemonVersion, ignorePatterns = [],
42367
42381
  if (ignored(n.description) || ignored(String(n.attrs["name"] ?? ""))) continue;
42368
42382
  nodes.push({
42369
42383
  ...n,
42384
+ // Language wire id = the shared `languageCanonicalId` (warming-spine
42385
+ // parity, EE-cloud-anchors) — the local `lang:<name>` id is internal.
42386
+ // Package ids are already the purl (= the cross-stratum canonicalId).
42387
+ id: label === "Language" ? languageCanonicalId(String(n.attrs["name"] ?? "").trim() || n.description) : n.id,
42370
42388
  embedding: [],
42371
42389
  attrs: label === "Package" ? {
42372
42390
  purl: n.attrs["purl"],
@@ -42596,11 +42614,34 @@ function noveltyAgainst(node2, neighbors, opts = {}) {
42596
42614
  // src/instance-ingest.ts
42597
42615
  var INSTANCE_LABELS = ["Problem", "Solution", "RootCause"];
42598
42616
  var INSTANCE_EDGES = ["CAUSED_BY", "SOLVED_BY"];
42617
+ var ANCHOR_EDGES = ["OCCURS_IN", "DEPENDS_ON"];
42618
+ var ANCHOR_TARGET_LABELS = ["Language", "Package"];
42599
42619
  function stripCodebaseScope(scope) {
42600
42620
  const s = { ...scope ?? {} };
42601
42621
  delete s["codebase"];
42602
42622
  return s;
42603
42623
  }
42624
+ function wireContextId(n) {
42625
+ if (n.label === "Language" && n.attrs["source"] !== "cloud") {
42626
+ const name2 = String(n.attrs["name"] ?? "").trim() || n.description.trim() || n.id.replace(/^lang:/, "");
42627
+ return languageCanonicalId(name2);
42628
+ }
42629
+ return n.id;
42630
+ }
42631
+ function shareableContext(n, wireId) {
42632
+ return {
42633
+ ...n,
42634
+ id: wireId,
42635
+ embedding: [],
42636
+ attrs: n.label === "Package" ? {
42637
+ purl: n.attrs["purl"],
42638
+ name: n.attrs["name"],
42639
+ version: n.attrs["version"],
42640
+ ecosystem: n.attrs["ecosystem"],
42641
+ resolved: n.attrs["resolved"]
42642
+ } : { name: n.attrs["name"] }
42643
+ };
42644
+ }
42604
42645
  function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [], opts = {}) {
42605
42646
  const level = opts.level ?? 1;
42606
42647
  const noveltyOpts = opts.dedupCosine != null ? { dedupCosine: opts.dedupCosine } : {};
@@ -42617,6 +42658,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
42617
42658
  });
42618
42659
  const nodes = [];
42619
42660
  const seen = /* @__PURE__ */ new Set();
42661
+ const anchorSources = /* @__PURE__ */ new Set();
42620
42662
  const includedByLabel = /* @__PURE__ */ new Map();
42621
42663
  for (const label of INSTANCE_LABELS) {
42622
42664
  const ref = [];
@@ -42624,14 +42666,18 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
42624
42666
  for (const n of store.findNodesByLabel(label)) {
42625
42667
  if (seen.has(n.id)) continue;
42626
42668
  if (n.attrs["source"] === "cloud") continue;
42627
- const contributedAtSeq = n.attrs["contributedAtSeq"];
42628
- if (typeof contributedAtSeq === "number" && (n.lastReinforcedAtSeq ?? 0) <= contributedAtSeq) continue;
42629
42669
  if (label === "Problem" && n.attrs["resolvedAs"] === PROBLEM_RESOLUTION.FALSE_POSITIVE) continue;
42630
42670
  if (ignored(n.description)) continue;
42671
+ const contributedAtSeq = n.attrs["contributedAtSeq"];
42672
+ if (typeof contributedAtSeq === "number" && (n.lastReinforcedAtSeq ?? 0) <= contributedAtSeq) {
42673
+ anchorSources.add(n.id);
42674
+ continue;
42675
+ }
42631
42676
  if (!noveltyAgainst(n, ref, noveltyOpts).ready) continue;
42632
42677
  ref.push(n);
42633
42678
  nodes.push(shareable(n));
42634
42679
  seen.add(n.id);
42680
+ anchorSources.add(n.id);
42635
42681
  }
42636
42682
  }
42637
42683
  for (const n of nodes) {
@@ -42639,20 +42685,50 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
42639
42685
  throw new Error(`buildInstanceIngest: refusing to ship non-instance ${n.id} (${n.label}) \u2014 C7 invariant`);
42640
42686
  }
42641
42687
  }
42642
- if (nodes.length === 0) return null;
42688
+ const anchorEdges = [];
42689
+ const contextNodes = [];
42690
+ const contextSeen = /* @__PURE__ */ new Set();
42691
+ const anchorDigests = {};
42692
+ for (const sourceId of anchorSources) {
42693
+ const targets = [];
42694
+ for (const e of store.outEdges(sourceId, [...ANCHOR_EDGES])) {
42695
+ const t = store.getNode(e.to);
42696
+ if (!t || !ANCHOR_TARGET_LABELS.includes(t.label)) continue;
42697
+ if (e.type === "OCCURS_IN" && t.label !== "Language") continue;
42698
+ if (e.type === "DEPENDS_ON" && t.label !== "Package") continue;
42699
+ if (t.label === "Package" && opts.includePackages !== true) continue;
42700
+ if (ignored(t.description) || ignored(String(t.attrs["name"] ?? ""))) continue;
42701
+ targets.push({ e, t, wireId: wireContextId(t) });
42702
+ }
42703
+ if (targets.length === 0) continue;
42704
+ const dg = digest(targets.map(({ e, wireId }) => `${e.type}>${wireId}`).sort());
42705
+ if (store.getNode(sourceId)?.attrs["anchorsContributedDigest"] === dg) continue;
42706
+ anchorDigests[sourceId] = dg;
42707
+ for (const { e, t, wireId } of targets) {
42708
+ anchorEdges.push({ ...e, to: wireId, attrs: {} });
42709
+ if (t.attrs["source"] === "cloud" || contextSeen.has(wireId)) continue;
42710
+ contextSeen.add(wireId);
42711
+ contextNodes.push(shareableContext(t, wireId));
42712
+ }
42713
+ }
42714
+ if (nodes.length === 0 && anchorEdges.length === 0) return null;
42643
42715
  const edges = [];
42644
42716
  for (const id of seen) {
42645
42717
  for (const e of store.outEdges(id, [...INSTANCE_EDGES])) {
42646
42718
  if (seen.has(e.to)) edges.push({ ...e, attrs: {} });
42647
42719
  }
42648
42720
  }
42721
+ edges.push(...anchorEdges);
42649
42722
  const base = {
42650
42723
  daemonVersion,
42651
42724
  profile: { stack: profile.stack, languages: profile.languages, domains: profile.domains },
42652
- nodes,
42725
+ // Context nodes FIRST: a chunked drain (cloud-client, 25-node chunks) then
42726
+ // co-locates the few Language/Package stubs with the first instance chunk,
42727
+ // maximizing in-payload endpoint resolution.
42728
+ nodes: [...contextNodes, ...nodes],
42653
42729
  edges
42654
42730
  };
42655
- return { ...base, payloadDigest: digest(base) };
42731
+ return { ...base, payloadDigest: digest(base), anchorDigests };
42656
42732
  }
42657
42733
 
42658
42734
  // src/multi.ts
@@ -42727,6 +42803,32 @@ var ConsolidateWorker = class {
42727
42803
  }
42728
42804
  };
42729
42805
 
42806
+ // src/loop-lag.ts
42807
+ var HEARTBEAT_MS = 500;
42808
+ var currentPass = "idle";
42809
+ var started = false;
42810
+ function markPass(name2) {
42811
+ const prev = currentPass;
42812
+ currentPass = name2;
42813
+ return () => {
42814
+ currentPass = prev;
42815
+ };
42816
+ }
42817
+ function startLoopLagMonitor(thresholdMs = 1e3) {
42818
+ if (started) return;
42819
+ started = true;
42820
+ let last = Date.now();
42821
+ const timer = setInterval(() => {
42822
+ const now = Date.now();
42823
+ const lag = now - last - HEARTBEAT_MS;
42824
+ if (lag > thresholdMs) {
42825
+ console.warn(`[loop-lag] event loop held ~${(lag / 1e3).toFixed(1)}s during "${currentPass}"`);
42826
+ }
42827
+ last = now;
42828
+ }, HEARTBEAT_MS);
42829
+ timer.unref();
42830
+ }
42831
+
42730
42832
  // src/multi.ts
42731
42833
  init_paths();
42732
42834
 
@@ -42813,6 +42915,7 @@ async function startMultiDaemon(opts = {}) {
42813
42915
  const sharedStore = openGraphStore({ path: sharedDbPath });
42814
42916
  const bundledRun = import.meta.url.endsWith(".mjs");
42815
42917
  const consolidateWorker = bundledRun && sharedDbPath !== ":memory:" ? new ConsolidateWorker() : null;
42918
+ startLoopLagMonitor();
42816
42919
  let baseUrl = "";
42817
42920
  const records = [];
42818
42921
  const boundaryListeners = [];
@@ -42937,12 +43040,43 @@ async function startMultiDaemon(opts = {}) {
42937
43040
  );
42938
43041
  const STRANDED_TTL_MS = 6e4;
42939
43042
  const strandedCache = /* @__PURE__ */ new Map();
43043
+ const strandedRefreshing = /* @__PURE__ */ new Set();
42940
43044
  const strandedCount = (r) => {
42941
43045
  const hit = strandedCache.get(r.id);
42942
43046
  if (hit && Date.now() - hit.at < STRANDED_TTL_MS) return hit.count;
42943
- const count = findStrandedSymbols(r.engine.store).length;
42944
- strandedCache.set(r.id, { at: Date.now(), count });
42945
- return count;
43047
+ if (!strandedRefreshing.has(r.id)) {
43048
+ strandedRefreshing.add(r.id);
43049
+ const finish = (count) => {
43050
+ strandedCache.set(r.id, { at: Date.now(), count });
43051
+ strandedRefreshing.delete(r.id);
43052
+ };
43053
+ if (consolidateWorker && r.engine.paths.castalia !== ":memory:") {
43054
+ consolidateWorker.run({ kind: "strandedCount", sharedDbPath, castaliaPath: r.engine.paths.castalia }).then((n) => finish(Number(n))).catch(() => {
43055
+ setImmediate(() => {
43056
+ const done = markPass(`stranded-scan:${r.entry.name}`);
43057
+ try {
43058
+ finish(findStrandedSymbols(r.engine.store).length);
43059
+ } catch {
43060
+ strandedRefreshing.delete(r.id);
43061
+ } finally {
43062
+ done();
43063
+ }
43064
+ });
43065
+ });
43066
+ } else {
43067
+ setImmediate(() => {
43068
+ const done = markPass(`stranded-scan:${r.entry.name}`);
43069
+ try {
43070
+ finish(findStrandedSymbols(r.engine.store).length);
43071
+ } catch {
43072
+ strandedRefreshing.delete(r.id);
43073
+ } finally {
43074
+ done();
43075
+ }
43076
+ });
43077
+ }
43078
+ }
43079
+ return hit?.count ?? -1;
42946
43080
  };
42947
43081
  app.get(
42948
43082
  "/health",
@@ -42971,13 +43105,18 @@ async function startMultiDaemon(opts = {}) {
42971
43105
  const owner = ownerOf(records, pathInBody(body2));
42972
43106
  if (!owner) return c.json({ error: "no-matching-project" }, 404);
42973
43107
  const sub = c.req.path;
42974
- return owner.webApp.fetch(
42975
- new Request(`http://local${sub}`, {
42976
- method: "POST",
42977
- headers: { "content-type": "application/json" },
42978
- body: raw2
42979
- })
42980
- );
43108
+ const done = markPass(`${sub}:${owner.entry.name}`);
43109
+ try {
43110
+ return await owner.webApp.fetch(
43111
+ new Request(`http://local${sub}`, {
43112
+ method: "POST",
43113
+ headers: { "content-type": "application/json" },
43114
+ body: raw2
43115
+ })
43116
+ );
43117
+ } finally {
43118
+ done();
43119
+ }
42981
43120
  };
42982
43121
  app.post(
42983
43122
  "/api/hook",
@@ -42995,10 +43134,11 @@ async function startMultiDaemon(opts = {}) {
42995
43134
  return typeof loc === "string" ? fileUriToFsPath(loc) : void 0;
42996
43135
  })
42997
43136
  );
42998
- app.post("/api/turn", (c) => forward(c, (b) => b["cwd"]));
42999
- app.post("/api/message", (c) => forward(c, (b) => b["cwd"]));
43000
- app.post("/api/session-end", (c) => forward(c, (b) => b["cwd"]));
43001
- app.post("/api/context-inject", (c) => forward(c, (b) => b["cwd"]));
43137
+ const cwdOf = (b) => typeof b["cwd"] === "string" ? b["cwd"] : void 0;
43138
+ app.post("/api/turn", (c) => forward(c, cwdOf));
43139
+ app.post("/api/message", (c) => forward(c, cwdOf));
43140
+ app.post("/api/session-end", (c) => forward(c, cwdOf));
43141
+ app.post("/api/context-inject", (c) => forward(c, cwdOf));
43002
43142
  for (const r of records) app.route(`/ws/${r.id}`, r.webApp);
43003
43143
  const reindexAll = async (rOpts) => {
43004
43144
  const out2 = /* @__PURE__ */ new Map();
@@ -43013,6 +43153,7 @@ async function startMultiDaemon(opts = {}) {
43013
43153
  out2.set(r.id, r.engine.store.nodeCount());
43014
43154
  continue;
43015
43155
  }
43156
+ const done = markPass(`reindex:${r.entry.name}`);
43016
43157
  try {
43017
43158
  const idx = await r.engine.reindex({ skipEmbed: rOpts?.skipEmbed ?? true, quiet: true });
43018
43159
  out2.set(r.id, idx.nodes);
@@ -43021,6 +43162,8 @@ async function startMultiDaemon(opts = {}) {
43021
43162
  } catch (err2) {
43022
43163
  console.warn(`[errata] index failed for ${r.entry.name}: ${err2 instanceof Error ? err2.message : err2}`);
43023
43164
  out2.set(r.id, r.engine.store.nodeCount());
43165
+ } finally {
43166
+ done();
43024
43167
  }
43025
43168
  }
43026
43169
  if (toIndex.length > 0) {
@@ -43057,6 +43200,7 @@ async function startMultiDaemon(opts = {}) {
43057
43200
  const out2 = /* @__PURE__ */ new Map();
43058
43201
  for (const r of records) {
43059
43202
  await new Promise((resolve5) => setImmediate(resolve5));
43203
+ const done = markPass(`package-index:${r.entry.name}`);
43060
43204
  try {
43061
43205
  out2.set(
43062
43206
  r.id,
@@ -43070,6 +43214,8 @@ async function startMultiDaemon(opts = {}) {
43070
43214
  );
43071
43215
  } catch (err2) {
43072
43216
  console.warn(`[errata] package index failed for ${r.entry.name}: ${err2 instanceof Error ? err2.message : err2}`);
43217
+ } finally {
43218
+ done();
43073
43219
  }
43074
43220
  }
43075
43221
  return out2;
@@ -43084,10 +43230,13 @@ async function startMultiDaemon(opts = {}) {
43084
43230
  async tickAll() {
43085
43231
  const out2 = /* @__PURE__ */ new Map();
43086
43232
  for (const r of records) {
43233
+ const done = markPass(`tick:${r.entry.name}`);
43087
43234
  try {
43088
43235
  out2.set(r.id, await r.engine.tick());
43089
43236
  } catch (err2) {
43090
43237
  console.warn(`[errata] tick failed for ${r.entry.name}: ${err2 instanceof Error ? err2.message : err2}`);
43238
+ } finally {
43239
+ done();
43091
43240
  }
43092
43241
  }
43093
43242
  return out2;
@@ -43095,10 +43244,13 @@ async function startMultiDaemon(opts = {}) {
43095
43244
  async nightlyAll() {
43096
43245
  const out2 = /* @__PURE__ */ new Map();
43097
43246
  for (const r of records) {
43247
+ const done = markPass(`nightly:${r.entry.name}`);
43098
43248
  try {
43099
43249
  out2.set(r.id, await r.engine.nightly());
43100
43250
  } catch (err2) {
43101
43251
  console.warn(`[errata] nightly failed for ${r.entry.name}: ${err2 instanceof Error ? err2.message : err2}`);
43252
+ } finally {
43253
+ done();
43102
43254
  }
43103
43255
  }
43104
43256
  return out2;
@@ -43129,12 +43281,15 @@ async function startMultiDaemon(opts = {}) {
43129
43281
  }
43130
43282
  }
43131
43283
  for (const r of inlineRecords) {
43284
+ const done = markPass(`percolate-inline:${r.entry.name}`);
43132
43285
  try {
43133
43286
  out2.set(r.id, percolate(r.engine.store, sharedStore, { workspaceId: r.engine.profile.id, ts }));
43134
43287
  } catch (err2) {
43135
43288
  console.warn(
43136
43289
  `[errata] percolate failed for ${r.entry.name}: ${err2 instanceof Error ? err2.message : err2}`
43137
43290
  );
43291
+ } finally {
43292
+ done();
43138
43293
  }
43139
43294
  }
43140
43295
  return out2;
@@ -43234,7 +43389,16 @@ async function startMultiDaemon(opts = {}) {
43234
43389
  let uploaded = 0;
43235
43390
  for (const r of records) {
43236
43391
  const store = r.engine.store;
43237
- const instances = buildInstanceIngest(store, r.engine.profile, DAEMON_VERSION, ignore);
43392
+ const context = buildContextIngest(store, r.engine.profile, DAEMON_VERSION, ignore, {
43393
+ includePackages: cfg2.consent.contributePackages
43394
+ });
43395
+ if (context) {
43396
+ const res = await client.ingest(context);
43397
+ uploaded += res.accepted;
43398
+ }
43399
+ const instances = buildInstanceIngest(store, r.engine.profile, DAEMON_VERSION, ignore, {
43400
+ includePackages: cfg2.consent.contributePackages
43401
+ });
43238
43402
  if (instances) {
43239
43403
  const res = await client.ingest(instances);
43240
43404
  uploaded += res.accepted;
@@ -43244,7 +43408,7 @@ async function startMultiDaemon(opts = {}) {
43244
43408
  );
43245
43409
  for (const n of instances.nodes) {
43246
43410
  const local = store.getNode(n.id);
43247
- if (!local) continue;
43411
+ if (!local || !["Problem", "Solution", "RootCause"].includes(local.label)) continue;
43248
43412
  const cloudNodeId = cloudIdByLocal.get(n.id);
43249
43413
  store.updateNode(n.id, {
43250
43414
  attrs: {
@@ -43254,13 +43418,13 @@ async function startMultiDaemon(opts = {}) {
43254
43418
  }
43255
43419
  });
43256
43420
  }
43257
- }
43258
- const context = buildContextIngest(store, r.engine.profile, DAEMON_VERSION, ignore, {
43259
- includePackages: cfg2.consent.contributePackages
43260
- });
43261
- if (context) {
43262
- const res = await client.ingest(context);
43263
- uploaded += res.accepted;
43421
+ for (const [localId, dg] of Object.entries(instances.anchorDigests)) {
43422
+ const local = store.getNode(localId);
43423
+ if (!local) continue;
43424
+ store.updateNode(localId, {
43425
+ attrs: { ...local.attrs, anchorsContributedDigest: dg }
43426
+ });
43427
+ }
43264
43428
  }
43265
43429
  }
43266
43430
  return { uploaded };
@@ -43462,28 +43626,6 @@ async function loginOAuthLoopback(opts) {
43462
43626
  // src/update.ts
43463
43627
  import { spawn as spawn2 } from "node:child_process";
43464
43628
  var PACKAGE_NAME = "@inerrata-corporation/errata";
43465
- function parse3(v) {
43466
- const m = /^(\d+)\.(\d+)\.(\d+)(?:-dev\.(\d+))?/.exec(v.trim());
43467
- if (!m) return null;
43468
- return {
43469
- base: [Number(m[1]), Number(m[2]), Number(m[3])],
43470
- pre: m[4] === void 0 ? null : Number(m[4])
43471
- };
43472
- }
43473
- function compareVersions(a, b) {
43474
- const pa = parse3(a);
43475
- const pb = parse3(b);
43476
- if (!pa || !pb) return 0;
43477
- const [aMaj, aMin, aPatch] = pa.base;
43478
- const [bMaj, bMin, bPatch] = pb.base;
43479
- if (aMaj !== bMaj) return aMaj - bMaj;
43480
- if (aMin !== bMin) return aMin - bMin;
43481
- if (aPatch !== bPatch) return aPatch - bPatch;
43482
- if (pa.pre === pb.pre) return 0;
43483
- if (pa.pre === null) return 1;
43484
- if (pb.pre === null) return -1;
43485
- return pa.pre - pb.pre;
43486
- }
43487
43629
  async function latestPublished(channel, timeoutMs = 4e3) {
43488
43630
  const ctrl = new AbortController();
43489
43631
  const timer = setTimeout(() => ctrl.abort(), timeoutMs);
@@ -43506,7 +43648,7 @@ async function checkForUpdate(channel) {
43506
43648
  return {
43507
43649
  current: DAEMON_VERSION,
43508
43650
  latest,
43509
- updateAvailable: latest !== null && compareVersions(latest, DAEMON_VERSION) > 0
43651
+ updateAvailable: latest !== null && latest !== DAEMON_VERSION
43510
43652
  };
43511
43653
  }
43512
43654
  function runNpmInstall(channel) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.0-dev.22",
3
+ "version": "2.0.0-dev.24",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {