@inerrata-corporation/errata 2.0.2-dev.704 → 2.0.2-dev.714

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 +141 -12
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -15447,6 +15447,15 @@ function extractIdentifierTokens(text) {
15447
15447
  }
15448
15448
  return out2;
15449
15449
  }
15450
+ function sidecarDropBucket(reason) {
15451
+ if (reason === null) return null;
15452
+ if (reason === "empty summary") return "empty";
15453
+ if (reason === "summary too long") return "too_long";
15454
+ if (reason === "contains a path shape") return "path_shape";
15455
+ if (reason === "contains a quoted literal") return "quoted_literal";
15456
+ if (reason.startsWith("contains verbatim identifier")) return "verbatim_identifier";
15457
+ return "other";
15458
+ }
15450
15459
  function summaryRejectionReason(summary, isKnownToken) {
15451
15460
  if (!summary.trim()) return "empty summary";
15452
15461
  if (summary.length > MAX_SYMBOL_SUMMARY_CHARS) return "summary too long";
@@ -16062,6 +16071,7 @@ __export(src_exports, {
16062
16071
  retrievalTokens: () => retrievalTokens,
16063
16072
  sha256: () => sha256,
16064
16073
  sha256Short: () => sha256Short,
16074
+ sidecarDropBucket: () => sidecarDropBucket,
16065
16075
  splitPnpmKey: () => splitPnpmKey,
16066
16076
  substituteSymbolSummaries: () => substituteSymbolSummaries,
16067
16077
  summarizeIngestResult: () => summarizeIngestResult,
@@ -22299,6 +22309,25 @@ var init_mechanism_liveness = __esm({
22299
22309
  },
22300
22310
  effectCounter: "shown"
22301
22311
  },
22312
+ {
22313
+ id: "contribution-ship",
22314
+ what: "carries local knowledge across the membrane to the cloud, and records the door's verdict",
22315
+ pass: "ship",
22316
+ // FED = nodes that have actually crossed. `contributedAtSeq` is stamped
22317
+ // only after the door accepts, so a fed reading is proof the whole chain
22318
+ // (build → generalize → drain → accept) ran, not merely that a timer fired.
22319
+ // The instance lane sat DEAD for 13 days behind a 422 nobody surfaced —
22320
+ // this row is the instrument that would have caught it on day one.
22321
+ fed: {
22322
+ labels: ["Problem", "Solution", "RootCause"],
22323
+ attr: "contributedAtSeq",
22324
+ minFraction: 0.01
22325
+ },
22326
+ effectCounter: "accepted",
22327
+ // Rising = knowledge piling up locally that never crossed. A backlog that
22328
+ // climbs while `accepted` stays flat is the shape of a silently-closed door.
22329
+ backlogCounter: "candidates"
22330
+ },
22302
22331
  {
22303
22332
  id: "orphan-reap",
22304
22333
  what: "closes File nodes whose path the indexer no longer covers",
@@ -55532,7 +55561,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
55532
55561
  }
55533
55562
 
55534
55563
  // src/engine.ts
55535
- var DAEMON_VERSION = true ? "2.0.2-dev.704" : "2.0.0-alpha.0";
55564
+ var DAEMON_VERSION = true ? "2.0.2-dev.714" : "2.0.0-alpha.0";
55536
55565
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
55537
55566
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
55538
55567
  var GIT_OP_MUTE_MS = 4e3;
@@ -57915,6 +57944,21 @@ function stripCodebaseScope(scope) {
57915
57944
  delete s["codebase"];
57916
57945
  return s;
57917
57946
  }
57947
+ function compositionCounters(c) {
57948
+ const { sidecarDropReasons, ...scalars } = c;
57949
+ const buckets = [
57950
+ "empty",
57951
+ "too_long",
57952
+ "path_shape",
57953
+ "quoted_literal",
57954
+ "verbatim_identifier",
57955
+ "other"
57956
+ ];
57957
+ return {
57958
+ ...scalars,
57959
+ ...Object.fromEntries(buckets.map((b) => [`sidecarDrop_${b}`, sidecarDropReasons[b] ?? 0]))
57960
+ };
57961
+ }
57918
57962
  function contributedWireId(n) {
57919
57963
  const cloudId = n.attrs["cloudNodeId"];
57920
57964
  return isMembraneSaltedId(cloudId) ? cloudId : n.id;
@@ -57986,7 +58030,9 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
57986
58030
  const shareable = (n) => {
57987
58031
  const preserved = symbolIndex ? preservedSymbolsFor(n.description, symbolIndex) : [];
57988
58032
  const fileScrubbed = generalizeFileRefs(n.description, fileLexicon, level);
57989
- const shippedText = generalize(fileScrubbed, { level, project: projectIdentity }).text;
58033
+ const generalized = generalize(fileScrubbed, { level, project: projectIdentity });
58034
+ const shippedText = generalized.text;
58035
+ if (generalized.report.classes.length > 0) composition.privacyRewritten++;
57990
58036
  const internalSyms = internalSymbolsFor(shippedText, (t) => ownLexicon.has(t), symbolIndex);
57991
58037
  const internalFiles = internalFilesFor(shippedText, fileLexicon);
57992
58038
  const internal = [.../* @__PURE__ */ new Set([...internalFiles, ...internalSyms])].slice(
@@ -58013,26 +58059,60 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
58013
58059
  const anchorSources = /* @__PURE__ */ new Set();
58014
58060
  const semanticEndpoints = /* @__PURE__ */ new Map();
58015
58061
  const includedByLabel = /* @__PURE__ */ new Map();
58062
+ const composition = {
58063
+ candidates: 0,
58064
+ shipped: 0,
58065
+ cloudSourced: 0,
58066
+ falsePositive: 0,
58067
+ ignored: 0,
58068
+ watermarked: 0,
58069
+ autoMint: 0,
58070
+ notNovel: 0,
58071
+ unshippable: 0,
58072
+ heldOrphans: 0,
58073
+ privacyRewritten: 0,
58074
+ sidecarDropped: 0,
58075
+ sidecarDropReasons: {},
58076
+ sidecarTruncatedAtCap: 0
58077
+ };
58016
58078
  for (const label of INSTANCE_LABELS) {
58017
58079
  const ref = [];
58018
58080
  includedByLabel.set(label, ref);
58019
58081
  const population = label === "RootCause" && opts.sharedStore ? [...store.findNodesByLabel(label), ...opts.sharedStore.findNodesByLabel(label)] : store.findNodesByLabel(label);
58020
58082
  for (const n of population) {
58021
58083
  if (seen.has(n.id)) continue;
58022
- if (n.attrs["source"] === "cloud") continue;
58023
- if (label === "Problem" && n.attrs["resolvedAs"] === PROBLEM_RESOLUTION.FALSE_POSITIVE) continue;
58024
- if (ignored(n.description)) continue;
58084
+ composition.candidates++;
58085
+ if (n.attrs["source"] === "cloud") {
58086
+ composition.cloudSourced++;
58087
+ continue;
58088
+ }
58089
+ if (label === "Problem" && n.attrs["resolvedAs"] === PROBLEM_RESOLUTION.FALSE_POSITIVE) {
58090
+ composition.falsePositive++;
58091
+ continue;
58092
+ }
58093
+ if (ignored(n.description)) {
58094
+ composition.ignored++;
58095
+ continue;
58096
+ }
58025
58097
  const contributedAtSeq = n.attrs["contributedAtSeq"];
58026
58098
  if (typeof contributedAtSeq === "number" && (n.lastReinforcedAtSeq ?? 0) <= contributedAtSeq) {
58099
+ composition.watermarked++;
58027
58100
  anchorSources.add(n.id);
58028
58101
  semanticEndpoints.set(n.id, contributedWireId(n));
58029
58102
  continue;
58030
58103
  }
58031
- if (label === "Solution" && n.description.startsWith(AUTO_MINT_PREFIX)) continue;
58032
- if (!noveltyAgainst(n, ref, noveltyOpts).ready) continue;
58104
+ if (label === "Solution" && n.description.startsWith(AUTO_MINT_PREFIX)) {
58105
+ composition.autoMint++;
58106
+ continue;
58107
+ }
58108
+ if (!noveltyAgainst(n, ref, noveltyOpts).ready) {
58109
+ composition.notNovel++;
58110
+ continue;
58111
+ }
58033
58112
  const reject = unshippableReason(n.id, n.label);
58034
58113
  if (reject) {
58035
58114
  console.warn(`[errata] skipping unshippable node ${n.id} (${n.label}): ${reject}`);
58115
+ composition.unshippable++;
58036
58116
  continue;
58037
58117
  }
58038
58118
  ref.push(n);
@@ -58169,7 +58249,10 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
58169
58249
  edges.push({ ...e, from: wireFrom, to: wireTo, attrs: {} });
58170
58250
  }
58171
58251
  }
58172
- if (nodes.length === 0 && anchorEdges.length === 0 && edges.length === 0) return null;
58252
+ if (nodes.length === 0 && anchorEdges.length === 0 && edges.length === 0) {
58253
+ opts.onComposition?.(composition);
58254
+ return null;
58255
+ }
58173
58256
  let symbolSummaries;
58174
58257
  if (opts.lexicon && opts.lexicon.size > 0 && nodes.length > 0) {
58175
58258
  const lexicon = opts.lexicon;
@@ -58183,8 +58266,16 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
58183
58266
  const entry = lexicon.get(tok);
58184
58267
  if (!entry?.summary) continue;
58185
58268
  const scrubbed = generalize(entry.summary, { level, project: projectIdentity }).text.trim();
58186
- if (!scrubbed || summaryRejectionReason(scrubbed, isKnown) !== null) continue;
58187
- if (count >= MAX_SIDECAR_SYMBOLS) break outer;
58269
+ const dropBucket = !scrubbed ? "empty" : sidecarDropBucket(summaryRejectionReason(scrubbed, isKnown));
58270
+ if (dropBucket !== null) {
58271
+ composition.sidecarDropped++;
58272
+ composition.sidecarDropReasons[dropBucket] = (composition.sidecarDropReasons[dropBucket] ?? 0) + 1;
58273
+ continue;
58274
+ }
58275
+ if (count >= MAX_SIDECAR_SYMBOLS) {
58276
+ composition.sidecarTruncatedAtCap = 1;
58277
+ break outer;
58278
+ }
58188
58279
  sidecar[tok] = { kind: entry.kind, summary: scrubbed };
58189
58280
  count++;
58190
58281
  }
@@ -58214,7 +58305,12 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
58214
58305
  `[errata] held ${heldOrphans.size} causal-orphan node(s) \u2014 no shippable binding edge this drain (VS-orphan-gate)`
58215
58306
  );
58216
58307
  }
58217
- if (shippableNodes.length === 0 && shippableEdges.length === 0) return null;
58308
+ composition.heldOrphans = heldOrphans.size;
58309
+ composition.shipped = shippableNodes.length;
58310
+ if (shippableNodes.length === 0 && shippableEdges.length === 0) {
58311
+ opts.onComposition?.(composition);
58312
+ return null;
58313
+ }
58218
58314
  const base = {
58219
58315
  daemonVersion,
58220
58316
  // Origin key (= project, the salted `wp_…`) — the door stamps it onto created
@@ -58232,7 +58328,8 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
58232
58328
  // payloadDigest — byte-identical to the pre-sidecar batch (backward compat).
58233
58329
  ...symbolSummaries ? { symbolSummaries } : {}
58234
58330
  };
58235
- return { ...base, payloadDigest: digest(base), anchorDigests, semanticEdgeDigests };
58331
+ opts.onComposition?.(composition);
58332
+ return { ...base, payloadDigest: digest(base), anchorDigests, semanticEdgeDigests, composition };
58236
58333
  }
58237
58334
 
58238
58335
  // src/backfill-edges.ts
@@ -59581,15 +59678,28 @@ async function startMultiDaemon(opts = {}) {
59581
59678
  } catch {
59582
59679
  }
59583
59680
  }
59681
+ let composition = null;
59584
59682
  const instances = buildInstanceIngest(store, r.engine.profile, DAEMON_VERSION, ignore, {
59585
59683
  includePackages: cfg2.consent.contributePackages,
59586
59684
  workspaceRoot: r.root,
59587
59685
  sharedStore,
59686
+ onComposition: (c) => {
59687
+ composition = c;
59688
+ },
59588
59689
  ...lexicon ? { lexicon } : {},
59589
59690
  ...project ? { project } : {}
59590
59691
  });
59692
+ if (!instances && composition) {
59693
+ appendPassLedger(r.engine.paths.configDir, "ship", 0, {
59694
+ ...compositionCounters(composition),
59695
+ accepted: 0,
59696
+ rejected: 0,
59697
+ blocked: 0
59698
+ });
59699
+ }
59591
59700
  if (instances) {
59592
59701
  if (project) instances.projectId = project.projectId;
59702
+ const shipStartedAt = Date.now();
59593
59703
  await lane("instances", projectName, async () => {
59594
59704
  const blocked = /* @__PURE__ */ new Set();
59595
59705
  const res = await client.ingest(instances, {
@@ -59608,6 +59718,16 @@ async function startMultiDaemon(opts = {}) {
59608
59718
  const cloudIdByLocal = new Map(
59609
59719
  res.result.nodes.filter((rn) => rn.nodeId).map((rn) => [rn.canonicalId, rn.nodeId])
59610
59720
  );
59721
+ const rejected = /* @__PURE__ */ new Map();
59722
+ for (const rn of res.result.nodes) {
59723
+ if (rn.decision === "rejected") rejected.set(rn.canonicalId, rn.reason ?? "no reason given");
59724
+ }
59725
+ if (rejected.size > 0) {
59726
+ const sample = [...rejected.entries()].slice(0, 3).map(([id, why]) => `${store.getNode(id)?.description.slice(0, 60) ?? id}: ${why}`);
59727
+ console.warn(
59728
+ `[sync\u2192cloud] [${projectName}] instances: ${rejected.size} node(s) REJECTED by the door \u2014 left pending for the next flush: ` + sample.join(" | ")
59729
+ );
59730
+ }
59611
59731
  const owningStore = (id) => {
59612
59732
  const w = store.getNode(id);
59613
59733
  if (w) return { s: store, n: w };
@@ -59619,6 +59739,7 @@ async function startMultiDaemon(opts = {}) {
59619
59739
  const owner = owningStore(n.id);
59620
59740
  if (!owner || !["Problem", "Solution", "RootCause"].includes(owner.n.label)) continue;
59621
59741
  if (blocked.has(n.id)) continue;
59742
+ if (rejected.has(n.id)) continue;
59622
59743
  const cloudNodeId = cloudIdByLocal.get(n.id);
59623
59744
  owner.s.updateNode(n.id, {
59624
59745
  attrs: {
@@ -59631,6 +59752,7 @@ async function startMultiDaemon(opts = {}) {
59631
59752
  for (const [localId, dg] of Object.entries(instances.anchorDigests)) {
59632
59753
  const owner = owningStore(localId);
59633
59754
  if (!owner) continue;
59755
+ if (rejected.has(localId) || blocked.has(localId)) continue;
59634
59756
  owner.s.updateNode(localId, {
59635
59757
  attrs: { ...owner.n.attrs, anchorsContributedDigest: dg }
59636
59758
  });
@@ -59638,10 +59760,17 @@ async function startMultiDaemon(opts = {}) {
59638
59760
  for (const [localId, dg] of Object.entries(instances.semanticEdgeDigests)) {
59639
59761
  const owner = owningStore(localId);
59640
59762
  if (!owner) continue;
59763
+ if (rejected.has(localId) || blocked.has(localId)) continue;
59641
59764
  owner.s.updateNode(localId, {
59642
59765
  attrs: { ...owner.n.attrs, semanticEdgesContributedDigest: dg }
59643
59766
  });
59644
59767
  }
59768
+ appendPassLedger(r.engine.paths.configDir, "ship", Date.now() - shipStartedAt, {
59769
+ ...compositionCounters(instances.composition),
59770
+ accepted: res.accepted,
59771
+ rejected: rejected.size,
59772
+ blocked: blocked.size
59773
+ });
59645
59774
  return res.accepted;
59646
59775
  });
59647
59776
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.2-dev.704",
3
+ "version": "2.0.2-dev.714",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {