@inerrata-corporation/errata 2.0.0-dev.98 → 2.0.1-dev.101

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 (2) hide show
  1. package/errata.mjs +66 -36
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -21851,8 +21851,14 @@ var init_client = __esm({
21851
21851
  * the per-decision response into flush accounting.
21852
21852
  *
21853
21853
  * The v1 door caps a payload at `MAX_NODES_PER_PAYLOAD` / `MAX_EDGES_PER_PAYLOAD`
21854
- * (413 over). A batch above the cap is split and drained across calls under ONE
21855
- * runId: every NODE chunk first (edges empty), then EDGE chunks (nodes empty).
21854
+ * (413 over). A batch above the cap is split and drained across calls, every
21855
+ * NODE chunk first (edges empty), then EDGE chunks (nodes empty). Each chunk
21856
+ * gets its OWN runId: the door's durable idempotency claim is keyed on
21857
+ * (agent, org, runId) with the payload digest, so reusing one runId across
21858
+ * different chunk payloads 409s "runId was already used with a different
21859
+ * payload" on the second chunk — exactly how the first real >25-node drain
21860
+ * died (2026-07-22). The runId never grouped anything server-side; it exists
21861
+ * for duplicate-POST protection, which is per-request by nature.
21856
21862
  * Recognition resolves an edge's endpoints against nodes already ingested this
21857
21863
  * drain (endpoint-label validation is deferred to the service when an endpoint
21858
21864
  * isn't in-payload), so the split never orphans an edge. Sub-results concat into
@@ -21872,7 +21878,7 @@ var init_client = __esm({
21872
21878
  const shipped = new Set(inChunk);
21873
21879
  pendingEdges = pendingEdges.filter((e) => !shipped.has(e));
21874
21880
  }
21875
- const r = await this.ingestWire(toWirePayload({ ...batch, nodes: nodeChunk, edges: inChunk }, runId));
21881
+ const r = await this.ingestWire(toWirePayload({ ...batch, nodes: nodeChunk, edges: inChunk }, randomUUID()));
21876
21882
  merged.nodes.push(...r.nodes);
21877
21883
  merged.edges.push(...r.edges);
21878
21884
  if (r.patternReconciliation) {
@@ -21880,7 +21886,7 @@ var init_client = __esm({
21880
21886
  }
21881
21887
  }
21882
21888
  for (const edgeChunk of chunkArray(pendingEdges, MAX_EDGES_PER_PAYLOAD)) {
21883
- const r = await this.ingestWire(toWirePayload({ ...batch, nodes: [], edges: edgeChunk }, runId));
21889
+ const r = await this.ingestWire(toWirePayload({ ...batch, nodes: [], edges: edgeChunk }, randomUUID()));
21884
21890
  merged.edges.push(...r.edges);
21885
21891
  }
21886
21892
  return { ...summarizeIngestResult(merged), result: merged };
@@ -51649,7 +51655,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
51649
51655
  }
51650
51656
 
51651
51657
  // src/engine.ts
51652
- var DAEMON_VERSION = true ? "2.0.0-dev.98" : "2.0.0-alpha.0";
51658
+ var DAEMON_VERSION = true ? "2.0.1-dev.101" : "2.0.0-alpha.0";
51653
51659
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
51654
51660
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
51655
51661
  var GIT_OP_MUTE_MS = 4e3;
@@ -53238,10 +53244,13 @@ function buildContextIngest(store, profile, daemonVersion, ignorePatterns = [],
53238
53244
  // Package ids are already the purl (= the cross-stratum canonicalId).
53239
53245
  id: label === "Language" ? languageCanonicalId(String(n.attrs["name"] ?? "").trim() || n.description) : n.id,
53240
53246
  embedding: [],
53247
+ // No `version` attr on the wire: the purl already encodes the resolved
53248
+ // version, and the door's temporal guard rejects ANY `attrs.version` as
53249
+ // bi-temporal bookkeeping (ingest-temporal-guard.ts) — shipping it 422s
53250
+ // the whole batch. `resolved` still travels (range-vs-lockfile signal).
53241
53251
  attrs: label === "Package" ? {
53242
53252
  purl: n.attrs["purl"],
53243
53253
  name: n.attrs["name"],
53244
- version: n.attrs["version"],
53245
53254
  ecosystem: n.attrs["ecosystem"],
53246
53255
  resolved: n.attrs["resolved"]
53247
53256
  } : { name: n.attrs["name"] }
@@ -53356,9 +53365,10 @@ function wireContextId(n) {
53356
53365
  }
53357
53366
  function shareableContext(n, wireId) {
53358
53367
  const attrs = n.label === "Package" ? {
53368
+ // No `version` attr: the purl encodes it, and the door's temporal
53369
+ // guard 422s any `attrs.version` (mirrors buildContextIngest).
53359
53370
  purl: n.attrs["purl"],
53360
53371
  name: n.attrs["name"],
53361
- version: n.attrs["version"],
53362
53372
  ecosystem: n.attrs["ecosystem"],
53363
53373
  resolved: n.attrs["resolved"]
53364
53374
  } : n.label === "Domain" ? { name: n.description, canonicalId: n.attrs["canonicalId"] } : { name: n.attrs["name"] };
@@ -54533,14 +54543,27 @@ async function startMultiDaemon(opts = {}) {
54533
54543
  const ignore = loadClaimIgnorePatterns(globalDir());
54534
54544
  const client = cloudNow();
54535
54545
  let uploaded = 0;
54546
+ const errors = [];
54547
+ const lane = async (name2, projectName, run3) => {
54548
+ try {
54549
+ await run3();
54550
+ } catch (err2) {
54551
+ const msg = `[${projectName}] ${name2}: ${err2 instanceof Error ? err2.message : String(err2)}`;
54552
+ errors.push(msg);
54553
+ console.error(`[sync\u2192cloud] ${msg}`);
54554
+ }
54555
+ };
54536
54556
  for (const r of records) {
54537
54557
  const store = r.engine.store;
54558
+ const projectName = r.engine.profile.name ?? r.engine.profile.id;
54538
54559
  const context = buildContextIngest(store, r.engine.profile, DAEMON_VERSION, ignore, {
54539
54560
  includePackages: cfg2.consent.contributePackages
54540
54561
  });
54541
54562
  if (context) {
54542
- const res = await client.ingest(context);
54543
- uploaded += res.accepted;
54563
+ await lane("context", projectName, async () => {
54564
+ const res = await client.ingest(context);
54565
+ uploaded += res.accepted;
54566
+ });
54544
54567
  }
54545
54568
  let lexicon;
54546
54569
  try {
@@ -54563,34 +54586,36 @@ async function startMultiDaemon(opts = {}) {
54563
54586
  });
54564
54587
  if (instances) {
54565
54588
  if (project) instances.projectId = project.projectId;
54566
- const res = await client.ingest(instances);
54567
- uploaded += res.accepted;
54568
- const seq = store.currentIngestSeq();
54569
- const cloudIdByLocal = new Map(
54570
- res.result.nodes.filter((rn) => rn.nodeId).map((rn) => [rn.canonicalId, rn.nodeId])
54571
- );
54572
- for (const n of instances.nodes) {
54573
- const local = store.getNode(n.id);
54574
- if (!local || !["Problem", "Solution", "RootCause"].includes(local.label)) continue;
54575
- const cloudNodeId = cloudIdByLocal.get(n.id);
54576
- store.updateNode(n.id, {
54577
- attrs: {
54578
- ...local.attrs,
54579
- contributedAtSeq: seq,
54580
- ...cloudNodeId && cloudNodeId !== n.id ? { cloudNodeId } : {}
54581
- }
54582
- });
54583
- }
54584
- for (const [localId, dg] of Object.entries(instances.anchorDigests)) {
54585
- const local = store.getNode(localId);
54586
- if (!local) continue;
54587
- store.updateNode(localId, {
54588
- attrs: { ...local.attrs, anchorsContributedDigest: dg }
54589
- });
54590
- }
54589
+ await lane("instances", projectName, async () => {
54590
+ const res = await client.ingest(instances);
54591
+ uploaded += res.accepted;
54592
+ const seq = store.currentIngestSeq();
54593
+ const cloudIdByLocal = new Map(
54594
+ res.result.nodes.filter((rn) => rn.nodeId).map((rn) => [rn.canonicalId, rn.nodeId])
54595
+ );
54596
+ for (const n of instances.nodes) {
54597
+ const local = store.getNode(n.id);
54598
+ if (!local || !["Problem", "Solution", "RootCause"].includes(local.label)) continue;
54599
+ const cloudNodeId = cloudIdByLocal.get(n.id);
54600
+ store.updateNode(n.id, {
54601
+ attrs: {
54602
+ ...local.attrs,
54603
+ contributedAtSeq: seq,
54604
+ ...cloudNodeId && cloudNodeId !== n.id ? { cloudNodeId } : {}
54605
+ }
54606
+ });
54607
+ }
54608
+ for (const [localId, dg] of Object.entries(instances.anchorDigests)) {
54609
+ const local = store.getNode(localId);
54610
+ if (!local) continue;
54611
+ store.updateNode(localId, {
54612
+ attrs: { ...local.attrs, anchorsContributedDigest: dg }
54613
+ });
54614
+ }
54615
+ });
54591
54616
  }
54592
54617
  }
54593
- return { uploaded };
54618
+ return { uploaded, ...errors.length > 0 ? { errors } : {} };
54594
54619
  },
54595
54620
  async pullTriagePublic() {
54596
54621
  if (!loadConfig().consent.sync) return { merged: 0, skipped: "consent-off" };
@@ -54640,7 +54665,12 @@ async function startMultiDaemon(opts = {}) {
54640
54665
  }
54641
54666
  const inst = await daemon.syncInstancesPublic();
54642
54667
  const skills = await daemon.syncSkillsAll();
54643
- return { uploaded: inst.uploaded, written: skills.written, pruned: skills.pruned };
54668
+ return {
54669
+ uploaded: inst.uploaded,
54670
+ written: skills.written,
54671
+ pruned: skills.pruned,
54672
+ ...inst.errors ? { errors: inst.errors } : {}
54673
+ };
54644
54674
  } finally {
54645
54675
  boundaryFlushing = false;
54646
54676
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.0-dev.98",
3
+ "version": "2.0.1-dev.101",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {