@inerrata-corporation/errata 2.0.2-dev.500 → 2.0.2-dev.506

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.
package/errata.mjs CHANGED
@@ -19300,7 +19300,8 @@ function markFixCandidates(store, t) {
19300
19300
  if (e.attrs?.["mention"] === true) continue;
19301
19301
  if (e.attrs?.["anchorProvenance"] === "legacy") continue;
19302
19302
  const sym = store.getNode(e.to);
19303
- if (sym && sym.lastUpdatedAt > since) {
19303
+ const changedAt = sym?.label === "File" ? Number(sym.attrs["contentChangedAt"] ?? 0) : sym?.lastUpdatedAt ?? 0;
19304
+ if (sym && changedAt > since) {
19304
19305
  edited = true;
19305
19306
  symName = sym.description;
19306
19307
  symRelPath = sym.attrs["relPath"] ?? void 0;
@@ -19335,9 +19336,11 @@ function markFixCandidates(store, t) {
19335
19336
  return resolved;
19336
19337
  }
19337
19338
  function clearSettledFixCandidates(store, t) {
19338
- const report = { answered: 0, ignored: 0, standing: 0 };
19339
+ const report = { answered: 0, ignored: 0, unsubstantiated: 0, standing: 0 };
19339
19340
  for (const p of store.findNodesByLabel("Problem")) {
19340
19341
  if (p.attrs["fixCandidateAt"] === void 0) continue;
19342
+ const fileAnchors = store.outEdges(p.id, ["ANCHORED_AT"]).filter((e) => e.attrs?.["mention"] !== true && e.attrs?.["anchorProvenance"] !== "legacy").map((e) => store.getNode(e.to)).filter((n) => n !== null && n.label === "File");
19343
+ const unsubstantiated = fileAnchors.length > 0 && fileAnchors.every((f) => f.attrs["contentChangedAt"] === void 0);
19341
19344
  const answered = p.attrs["resolvedAt"] != null || store.outEdges(p.id, ["SOLVED_BY"]).some((e) => {
19342
19345
  const s = store.getNode(e.to);
19343
19346
  return s !== null && !String(s.description ?? "").startsWith(AUTO_MINT_PREFIX);
@@ -19347,7 +19350,7 @@ function clearSettledFixCandidates(store, t) {
19347
19350
  );
19348
19351
  const shownSinceAsk = Number(p.attrs["shownCount"] ?? 0) - base;
19349
19352
  const ignored = shownSinceAsk >= FIX_CANDIDATE_ASK_LIMIT;
19350
- if (!answered && !ignored) {
19353
+ if (!answered && !ignored && !unsubstantiated) {
19351
19354
  report.standing++;
19352
19355
  continue;
19353
19356
  }
@@ -19358,7 +19361,8 @@ function clearSettledFixCandidates(store, t) {
19358
19361
  attrs["fixCandidateClearedAt"] = t;
19359
19362
  store.updateNode(p.id, { attrs, lastUpdatedAt: t });
19360
19363
  if (answered) report.answered++;
19361
- else report.ignored++;
19364
+ else if (ignored) report.ignored++;
19365
+ else report.unsubstantiated++;
19362
19366
  }
19363
19367
  return report;
19364
19368
  }
@@ -19458,10 +19462,12 @@ function parseIntentFences(text) {
19458
19462
  }
19459
19463
  function searchByIntent(store, intent, opts) {
19460
19464
  const limit = opts?.limit ?? 5;
19461
- const minCoverage = opts?.minCoverage ?? 0.25;
19465
+ const minCoverage = opts?.minCoverage ?? DEFAULT_MIN_COVERAGE;
19462
19466
  const want = new Set(retrievalTokens(intent));
19463
19467
  if (want.size < MIN_INTENT_TOKENS) return [];
19464
- const hits = [];
19468
+ const candidates = [];
19469
+ const df = /* @__PURE__ */ new Map();
19470
+ let corpus = 0;
19465
19471
  for (const label of RECALLABLE) {
19466
19472
  for (const node2 of store.findNodesByLabel(label)) {
19467
19473
  if (node2.attrs["mergedInto"] !== void 0) continue;
@@ -19470,19 +19476,30 @@ function searchByIntent(store, intent, opts) {
19470
19476
  }
19471
19477
  const bag = retrievalTokens(node2.description ?? "");
19472
19478
  if (bag.length === 0) continue;
19479
+ corpus++;
19473
19480
  const matched = bag.filter((t) => want.has(t));
19474
- if (matched.length === 0) continue;
19475
- const coverage = matched.length / want.size;
19476
- if (coverage < minCoverage) continue;
19477
- hits.push({ node: node2, coverage, matched });
19481
+ for (const t of matched) df.set(t, (df.get(t) ?? 0) + 1);
19482
+ if (matched.length > 0) candidates.push({ node: node2, matched });
19478
19483
  }
19479
19484
  }
19485
+ const idf = (t) => Math.log(1 + corpus / (1 + (df.get(t) ?? 0)));
19486
+ let denom = 0;
19487
+ for (const t of want) if ((df.get(t) ?? 0) > 0) denom += idf(t);
19488
+ if (denom === 0) return [];
19489
+ const hits = [];
19490
+ for (const { node: node2, matched } of candidates) {
19491
+ let num2 = 0;
19492
+ for (const t of matched) num2 += idf(t);
19493
+ const coverage = num2 / denom;
19494
+ if (coverage < minCoverage) continue;
19495
+ hits.push({ node: node2, coverage, matched });
19496
+ }
19480
19497
  hits.sort(
19481
19498
  (a, b) => b.coverage - a.coverage || (a.node.description?.length ?? 0) - (b.node.description?.length ?? 0)
19482
19499
  );
19483
19500
  return hits.slice(0, limit);
19484
19501
  }
19485
- var RECALLABLE, MIN_INTENT_TOKENS;
19502
+ var RECALLABLE, MIN_INTENT_TOKENS, DEFAULT_MIN_COVERAGE;
19486
19503
  var init_intent = __esm({
19487
19504
  "../../packages/local-graph/src/intent.ts"() {
19488
19505
  "use strict";
@@ -19490,6 +19507,7 @@ var init_intent = __esm({
19490
19507
  init_design_problem();
19491
19508
  RECALLABLE = ["Problem", "Solution", "RootCause", "Pattern"];
19492
19509
  MIN_INTENT_TOKENS = 2;
19510
+ DEFAULT_MIN_COVERAGE = 0.2;
19493
19511
  }
19494
19512
  });
19495
19513
 
@@ -21758,6 +21776,7 @@ __export(src_exports2, {
21758
21776
  CITABLE_PRIOR_LABELS: () => CITABLE_PRIOR_LABELS,
21759
21777
  CODE_REACH_EDGES: () => CODE_REACH_EDGES,
21760
21778
  CREDIT_FAMILY: () => CREDIT_FAMILY,
21779
+ DEFAULT_MIN_COVERAGE: () => DEFAULT_MIN_COVERAGE,
21761
21780
  FIX_CANDIDATE_ASK_LIMIT: () => FIX_CANDIDATE_ASK_LIMIT,
21762
21781
  JOINT_COMMUNITY_EDGES: () => JOINT_COMMUNITY_EDGES,
21763
21782
  JOINT_COMMUNITY_LABELS: () => JOINT_COMMUNITY_LABELS,
@@ -28529,7 +28548,7 @@ function runNightlyPipeline(store) {
28529
28548
  skillsRefreshed: 0,
28530
28549
  designResolved,
28531
28550
  revisitsCleared: revisits.cleared,
28532
- fixCandidatesSettled: fixCandidates.answered + fixCandidates.ignored,
28551
+ fixCandidatesSettled: fixCandidates.answered + fixCandidates.ignored + fixCandidates.unsubstantiated,
28533
28552
  claimsEvaluated: cry.evaluated,
28534
28553
  claimsDerived: cry.derived.length,
28535
28554
  durationMs: Date.now() - started2
@@ -29725,7 +29744,15 @@ async function incrementalReindex(store, rootPath, workspaceId2, changedAbsPaths
29725
29744
  const h = fileHashes.get(rel);
29726
29745
  if (!h) continue;
29727
29746
  const fnode = store.getNode(fileNodeId(workspaceId2, rel));
29728
- if (fnode) store.updateNode(fnode.id, { attrs: { ...fnode.attrs, contentHash: h } });
29747
+ if (!fnode) continue;
29748
+ const contentMoved = fnode.attrs["contentHash"] !== h;
29749
+ store.updateNode(fnode.id, {
29750
+ attrs: {
29751
+ ...fnode.attrs,
29752
+ contentHash: h,
29753
+ ...contentMoved ? { contentChangedAt: t } : {}
29754
+ }
29755
+ });
29729
29756
  }
29730
29757
  return {
29731
29758
  filesReindexed: changedRelPaths.size,
@@ -53785,7 +53812,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
53785
53812
  }
53786
53813
 
53787
53814
  // src/engine.ts
53788
- var DAEMON_VERSION = true ? "2.0.2-dev.500" : "2.0.0-alpha.0";
53815
+ var DAEMON_VERSION = true ? "2.0.2-dev.506" : "2.0.0-alpha.0";
53789
53816
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
53790
53817
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
53791
53818
  var GIT_OP_MUTE_MS = 4e3;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.2-dev.500",
3
+ "version": "2.0.2-dev.506",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -16139,7 +16139,15 @@ async function incrementalReindex(store2, rootPath, workspaceId, changedAbsPaths
16139
16139
  const h = fileHashes.get(rel);
16140
16140
  if (!h) continue;
16141
16141
  const fnode = store2.getNode(fileNodeId(workspaceId, rel));
16142
- if (fnode) store2.updateNode(fnode.id, { attrs: { ...fnode.attrs, contentHash: h } });
16142
+ if (!fnode) continue;
16143
+ const contentMoved = fnode.attrs["contentHash"] !== h;
16144
+ store2.updateNode(fnode.id, {
16145
+ attrs: {
16146
+ ...fnode.attrs,
16147
+ contentHash: h,
16148
+ ...contentMoved ? { contentChangedAt: t } : {}
16149
+ }
16150
+ });
16143
16151
  }
16144
16152
  return {
16145
16153
  filesReindexed: changedRelPaths.size,
@@ -25584,7 +25592,8 @@ function markFixCandidates(store2, t) {
25584
25592
  if (e.attrs?.["mention"] === true) continue;
25585
25593
  if (e.attrs?.["anchorProvenance"] === "legacy") continue;
25586
25594
  const sym = store2.getNode(e.to);
25587
- if (sym && sym.lastUpdatedAt > since) {
25595
+ const changedAt = sym?.label === "File" ? Number(sym.attrs["contentChangedAt"] ?? 0) : sym?.lastUpdatedAt ?? 0;
25596
+ if (sym && changedAt > since) {
25588
25597
  edited = true;
25589
25598
  symName = sym.description;
25590
25599
  symRelPath = sym.attrs["relPath"] ?? void 0;
@@ -25620,9 +25629,11 @@ function markFixCandidates(store2, t) {
25620
25629
  }
25621
25630
  var FIX_CANDIDATE_ASK_LIMIT = 5;
25622
25631
  function clearSettledFixCandidates(store2, t) {
25623
- const report = { answered: 0, ignored: 0, standing: 0 };
25632
+ const report = { answered: 0, ignored: 0, unsubstantiated: 0, standing: 0 };
25624
25633
  for (const p of store2.findNodesByLabel("Problem")) {
25625
25634
  if (p.attrs["fixCandidateAt"] === void 0) continue;
25635
+ const fileAnchors = store2.outEdges(p.id, ["ANCHORED_AT"]).filter((e) => e.attrs?.["mention"] !== true && e.attrs?.["anchorProvenance"] !== "legacy").map((e) => store2.getNode(e.to)).filter((n) => n !== null && n.label === "File");
25636
+ const unsubstantiated = fileAnchors.length > 0 && fileAnchors.every((f) => f.attrs["contentChangedAt"] === void 0);
25626
25637
  const answered = p.attrs["resolvedAt"] != null || store2.outEdges(p.id, ["SOLVED_BY"]).some((e) => {
25627
25638
  const s = store2.getNode(e.to);
25628
25639
  return s !== null && !String(s.description ?? "").startsWith(AUTO_MINT_PREFIX);
@@ -25632,7 +25643,7 @@ function clearSettledFixCandidates(store2, t) {
25632
25643
  );
25633
25644
  const shownSinceAsk = Number(p.attrs["shownCount"] ?? 0) - base;
25634
25645
  const ignored = shownSinceAsk >= FIX_CANDIDATE_ASK_LIMIT;
25635
- if (!answered && !ignored) {
25646
+ if (!answered && !ignored && !unsubstantiated) {
25636
25647
  report.standing++;
25637
25648
  continue;
25638
25649
  }
@@ -25643,7 +25654,8 @@ function clearSettledFixCandidates(store2, t) {
25643
25654
  attrs["fixCandidateClearedAt"] = t;
25644
25655
  store2.updateNode(p.id, { attrs, lastUpdatedAt: t });
25645
25656
  if (answered) report.answered++;
25646
- else report.ignored++;
25657
+ else if (ignored) report.ignored++;
25658
+ else report.unsubstantiated++;
25647
25659
  }
25648
25660
  return report;
25649
25661
  }
@@ -26399,7 +26411,7 @@ function runNightlyPipeline(store2) {
26399
26411
  skillsRefreshed: 0,
26400
26412
  designResolved,
26401
26413
  revisitsCleared: revisits.cleared,
26402
- fixCandidatesSettled: fixCandidates.answered + fixCandidates.ignored,
26414
+ fixCandidatesSettled: fixCandidates.answered + fixCandidates.ignored + fixCandidates.unsubstantiated,
26403
26415
  claimsEvaluated: cry.evaluated,
26404
26416
  claimsDerived: cry.derived.length,
26405
26417
  durationMs: Date.now() - started