@inerrata-corporation/errata 2.0.2-dev.334 → 2.0.2-dev.336

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.
@@ -16630,6 +16630,9 @@ init_src2();
16630
16630
  // ../../packages/local-graph/src/problem-package-link.ts
16631
16631
  init_src();
16632
16632
 
16633
+ // ../../packages/local-graph/src/anchor-backfill.ts
16634
+ init_src();
16635
+
16633
16636
  // ../../packages/local-graph/src/percolate.ts
16634
16637
  init_src2();
16635
16638
  var PERCOLATING_LABELS = ["Claim", "Problem", "Solution"];
package/errata.mjs CHANGED
@@ -18597,6 +18597,9 @@ function reinforceSameAnchorProblem(store, relPath, workspaceId2, statement, sou
18597
18597
  }
18598
18598
  return existing.id;
18599
18599
  }
18600
+ function isAutoMinted(n) {
18601
+ return n.label === "Solution" && String(n.description ?? "").startsWith(AUTO_MINT_PREFIX);
18602
+ }
18600
18603
  function priorsForFile(store, relPath) {
18601
18604
  const want = relPath.trim().replace(/^\.?\//, "");
18602
18605
  let file2 = null;
@@ -18623,7 +18626,7 @@ function priorsForFile(store, relPath) {
18623
18626
  } else if (n.attrs["resolvedAs"] == null && n.attrs["mergedInto"] === void 0 && e.attrs?.["anchorProvenance"] !== "legacy") {
18624
18627
  resolvedProblems.push(n);
18625
18628
  }
18626
- } else if (CITABLE_PRIOR_LABELS.has(n.label)) {
18629
+ } else if (CITABLE_PRIOR_LABELS.has(n.label) && !isAutoMinted(n)) {
18627
18630
  related.set(n.id, n);
18628
18631
  }
18629
18632
  }
@@ -18631,8 +18634,8 @@ function priorsForFile(store, relPath) {
18631
18634
  for (const p of [...openProblems, ...constraints, ...resolvedProblems]) {
18632
18635
  for (const e of store.outEdges(p.id, ["SOLVED_BY", "CAUSED_BY", "INSTANCE_OF"])) {
18633
18636
  const n = store.getNode(e.to);
18634
- if (n && CITABLE_PRIOR_LABELS.has(n.label)) related.set(n.id, n);
18635
- if (n && n.label === "Solution" && e.type === "SOLVED_BY") {
18637
+ if (n && CITABLE_PRIOR_LABELS.has(n.label) && !isAutoMinted(n)) related.set(n.id, n);
18638
+ if (n && n.label === "Solution" && e.type === "SOLVED_BY" && !isAutoMinted(n)) {
18636
18639
  const list = solutionsByProblem.get(p.id) ?? [];
18637
18640
  if (!list.some((s) => s.id === n.id)) list.push(n);
18638
18641
  solutionsByProblem.set(p.id, list);
@@ -18864,6 +18867,80 @@ var init_design_problem = __esm({
18864
18867
  function isLegacyAnchor(attrs) {
18865
18868
  return attrs?.["captureTime"] === true && attrs["anchorProvenance"] === void 0;
18866
18869
  }
18870
+ function repairLegacyAnchorsFromStatement(store, ts) {
18871
+ const report = {
18872
+ repaired: [],
18873
+ noPathNamed: 0,
18874
+ pathUnknown: 0,
18875
+ alreadyCorrect: 0
18876
+ };
18877
+ const byPath = /* @__PURE__ */ new Map();
18878
+ for (const f of store.findNodesByLabel("File")) {
18879
+ const path2 = String(f.attrs["relPath"] ?? f.description ?? "");
18880
+ if (path2) byPath.set(path2, { id: f.id, path: path2 });
18881
+ }
18882
+ const resolvePath2 = (named) => {
18883
+ const exact = byPath.get(named);
18884
+ if (exact) return exact;
18885
+ const hits = [...byPath.values()].filter(
18886
+ (f) => f.path.endsWith(`/${named}`) || named.endsWith(`/${f.path}`)
18887
+ );
18888
+ return hits.length === 1 ? hits[0] : null;
18889
+ };
18890
+ for (const p of store.findNodesByLabel("Problem")) {
18891
+ try {
18892
+ const anchors = store.outEdges(p.id, ["ANCHORED_AT"]);
18893
+ const legacy = anchors.filter((e) => e.attrs?.["anchorProvenance"] === "legacy");
18894
+ if (legacy.length === 0) continue;
18895
+ if (anchors.some((e) => e.attrs?.["anchorProvenance"] === "restated")) continue;
18896
+ const named = [...String(p.description ?? "").matchAll(STATEMENT_PATH_RE)].map((m) => m[0]);
18897
+ if (named.length === 0) {
18898
+ report.noPathNamed++;
18899
+ continue;
18900
+ }
18901
+ const guessedPaths = legacy.map((e) => {
18902
+ const f = store.getNode(e.to);
18903
+ return String(f?.attrs["relPath"] ?? f?.description ?? "");
18904
+ });
18905
+ if (named.some((x) => guessedPaths.some((g) => g.endsWith(x) || x.endsWith(g)))) {
18906
+ report.alreadyCorrect++;
18907
+ continue;
18908
+ }
18909
+ const target = named.map(resolvePath2).find((f) => f !== null);
18910
+ if (!target) {
18911
+ report.pathUnknown++;
18912
+ continue;
18913
+ }
18914
+ store.mergeEdge({
18915
+ id: `edge_${digest({ from: p.id, type: "ANCHORED_AT", to: target.id })}`.slice(0, 24),
18916
+ from: p.id,
18917
+ to: target.id,
18918
+ type: "ANCHORED_AT",
18919
+ // Same confidence a capture-time anchor enters at: the source is the
18920
+ // agent's own statement either way, only the moment of reading differs.
18921
+ confidence: 0.4,
18922
+ extractionSource: "agent-observed",
18923
+ createdAt: ts,
18924
+ lastSeenAt: ts,
18925
+ navSuccesses: 0,
18926
+ navFailures: 0,
18927
+ attrs: {
18928
+ anchorProvenance: "restated",
18929
+ restatedFrom: guessedPaths[0] ?? "",
18930
+ restatedAt: ts
18931
+ }
18932
+ });
18933
+ report.repaired.push({
18934
+ problemId: p.id,
18935
+ problem: p.description,
18936
+ guessed: guessedPaths[0] ?? "",
18937
+ restated: target.path
18938
+ });
18939
+ } catch {
18940
+ }
18941
+ }
18942
+ return report;
18943
+ }
18867
18944
  function backfillLegacyAnchors(store, ts) {
18868
18945
  const report = {
18869
18946
  demotedEdges: 0,
@@ -18921,11 +18998,14 @@ function backfillLegacyAnchors(store, ts) {
18921
18998
  }
18922
18999
  return report;
18923
19000
  }
19001
+ var STATEMENT_PATH_RE;
18924
19002
  var init_anchor_backfill = __esm({
18925
19003
  "../../packages/local-graph/src/anchor-backfill.ts"() {
18926
19004
  "use strict";
19005
+ init_src();
18927
19006
  init_justification();
18928
19007
  init_design_problem();
19008
+ STATEMENT_PATH_RE = /(?:[\w.-]+\/)+[\w.-]+\.(?:ts|tsx|js|mjs|cjs|py|go|rs|java|rb|c|cpp|h)/g;
18929
19009
  }
18930
19010
  });
18931
19011
 
@@ -21099,6 +21179,7 @@ __export(src_exports2, {
21099
21179
  recordTriageObservation: () => recordTriageObservation,
21100
21180
  reinforceSameAnchorProblem: () => reinforceSameAnchorProblem,
21101
21181
  relateClaims: () => relateClaims,
21182
+ repairLegacyAnchorsFromStatement: () => repairLegacyAnchorsFromStatement,
21102
21183
  resolveDesignProblemById: () => resolveDesignProblemById,
21103
21184
  resolveDesignProblemByStatement: () => resolveDesignProblemByStatement,
21104
21185
  resolveDesignProblems: () => resolveDesignProblems,
@@ -53035,7 +53116,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
53035
53116
  }
53036
53117
 
53037
53118
  // src/engine.ts
53038
- var DAEMON_VERSION = true ? "2.0.2-dev.334" : "2.0.0-alpha.0";
53119
+ var DAEMON_VERSION = true ? "2.0.2-dev.336" : "2.0.0-alpha.0";
53039
53120
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
53040
53121
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
53041
53122
  var GIT_OP_MUTE_MS = 4e3;
@@ -53479,7 +53560,13 @@ function createWorkspaceEngine(opts) {
53479
53560
  const runNightlyInline = () => {
53480
53561
  try {
53481
53562
  const a = backfillLegacyAnchors(store, Date.now());
53482
- if (a.demotedEdges > 0 || a.suspects.length > 0) {
53563
+ const rep = repairLegacyAnchorsFromStatement(store, Date.now());
53564
+ if (rep.repaired.length > 0) {
53565
+ console.log(
53566
+ `[errata] re-anchored ${rep.repaired.length} legacy-guessed problem(s) onto the file their statement names`
53567
+ );
53568
+ }
53569
+ if (a.demotedEdges > 0 || a.suspects.length > 0 || rep.repaired.length > 0) {
53483
53570
  logAnchorBackfill(a.demotedEdges, a.suspects.length);
53484
53571
  refreshContextNow();
53485
53572
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.2-dev.334",
3
+ "version": "2.0.2-dev.336",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -25310,6 +25310,9 @@ var CITABLE_PRIOR_LABELS = /* @__PURE__ */ new Set([
25310
25310
  "Technique",
25311
25311
  "AntiPattern"
25312
25312
  ]);
25313
+ function isAutoMinted(n) {
25314
+ return n.label === "Solution" && String(n.description ?? "").startsWith(AUTO_MINT_PREFIX);
25315
+ }
25313
25316
  function priorsForFile(store2, relPath) {
25314
25317
  const want = relPath.trim().replace(/^\.?\//, "");
25315
25318
  let file2 = null;
@@ -25336,7 +25339,7 @@ function priorsForFile(store2, relPath) {
25336
25339
  } else if (n.attrs["resolvedAs"] == null && n.attrs["mergedInto"] === void 0 && e.attrs?.["anchorProvenance"] !== "legacy") {
25337
25340
  resolvedProblems.push(n);
25338
25341
  }
25339
- } else if (CITABLE_PRIOR_LABELS.has(n.label)) {
25342
+ } else if (CITABLE_PRIOR_LABELS.has(n.label) && !isAutoMinted(n)) {
25340
25343
  related.set(n.id, n);
25341
25344
  }
25342
25345
  }
@@ -25344,8 +25347,8 @@ function priorsForFile(store2, relPath) {
25344
25347
  for (const p of [...openProblems, ...constraints, ...resolvedProblems]) {
25345
25348
  for (const e of store2.outEdges(p.id, ["SOLVED_BY", "CAUSED_BY", "INSTANCE_OF"])) {
25346
25349
  const n = store2.getNode(e.to);
25347
- if (n && CITABLE_PRIOR_LABELS.has(n.label)) related.set(n.id, n);
25348
- if (n && n.label === "Solution" && e.type === "SOLVED_BY") {
25350
+ if (n && CITABLE_PRIOR_LABELS.has(n.label) && !isAutoMinted(n)) related.set(n.id, n);
25351
+ if (n && n.label === "Solution" && e.type === "SOLVED_BY" && !isAutoMinted(n)) {
25349
25352
  const list = solutionsByProblem.get(p.id) ?? [];
25350
25353
  if (!list.some((s) => s.id === n.id)) list.push(n);
25351
25354
  solutionsByProblem.set(p.id, list);
@@ -25425,9 +25428,85 @@ function resolveDesignProblems(store2, t) {
25425
25428
  }
25426
25429
 
25427
25430
  // ../../packages/local-graph/src/anchor-backfill.ts
25431
+ init_src();
25428
25432
  function isLegacyAnchor(attrs) {
25429
25433
  return attrs?.["captureTime"] === true && attrs["anchorProvenance"] === void 0;
25430
25434
  }
25435
+ var STATEMENT_PATH_RE = /(?:[\w.-]+\/)+[\w.-]+\.(?:ts|tsx|js|mjs|cjs|py|go|rs|java|rb|c|cpp|h)/g;
25436
+ function repairLegacyAnchorsFromStatement(store2, ts) {
25437
+ const report = {
25438
+ repaired: [],
25439
+ noPathNamed: 0,
25440
+ pathUnknown: 0,
25441
+ alreadyCorrect: 0
25442
+ };
25443
+ const byPath = /* @__PURE__ */ new Map();
25444
+ for (const f of store2.findNodesByLabel("File")) {
25445
+ const path = String(f.attrs["relPath"] ?? f.description ?? "");
25446
+ if (path) byPath.set(path, { id: f.id, path });
25447
+ }
25448
+ const resolvePath = (named) => {
25449
+ const exact = byPath.get(named);
25450
+ if (exact) return exact;
25451
+ const hits = [...byPath.values()].filter(
25452
+ (f) => f.path.endsWith(`/${named}`) || named.endsWith(`/${f.path}`)
25453
+ );
25454
+ return hits.length === 1 ? hits[0] : null;
25455
+ };
25456
+ for (const p of store2.findNodesByLabel("Problem")) {
25457
+ try {
25458
+ const anchors = store2.outEdges(p.id, ["ANCHORED_AT"]);
25459
+ const legacy = anchors.filter((e) => e.attrs?.["anchorProvenance"] === "legacy");
25460
+ if (legacy.length === 0) continue;
25461
+ if (anchors.some((e) => e.attrs?.["anchorProvenance"] === "restated")) continue;
25462
+ const named = [...String(p.description ?? "").matchAll(STATEMENT_PATH_RE)].map((m) => m[0]);
25463
+ if (named.length === 0) {
25464
+ report.noPathNamed++;
25465
+ continue;
25466
+ }
25467
+ const guessedPaths = legacy.map((e) => {
25468
+ const f = store2.getNode(e.to);
25469
+ return String(f?.attrs["relPath"] ?? f?.description ?? "");
25470
+ });
25471
+ if (named.some((x) => guessedPaths.some((g) => g.endsWith(x) || x.endsWith(g)))) {
25472
+ report.alreadyCorrect++;
25473
+ continue;
25474
+ }
25475
+ const target = named.map(resolvePath).find((f) => f !== null);
25476
+ if (!target) {
25477
+ report.pathUnknown++;
25478
+ continue;
25479
+ }
25480
+ store2.mergeEdge({
25481
+ id: `edge_${digest({ from: p.id, type: "ANCHORED_AT", to: target.id })}`.slice(0, 24),
25482
+ from: p.id,
25483
+ to: target.id,
25484
+ type: "ANCHORED_AT",
25485
+ // Same confidence a capture-time anchor enters at: the source is the
25486
+ // agent's own statement either way, only the moment of reading differs.
25487
+ confidence: 0.4,
25488
+ extractionSource: "agent-observed",
25489
+ createdAt: ts,
25490
+ lastSeenAt: ts,
25491
+ navSuccesses: 0,
25492
+ navFailures: 0,
25493
+ attrs: {
25494
+ anchorProvenance: "restated",
25495
+ restatedFrom: guessedPaths[0] ?? "",
25496
+ restatedAt: ts
25497
+ }
25498
+ });
25499
+ report.repaired.push({
25500
+ problemId: p.id,
25501
+ problem: p.description,
25502
+ guessed: guessedPaths[0] ?? "",
25503
+ restated: target.path
25504
+ });
25505
+ } catch {
25506
+ }
25507
+ }
25508
+ return report;
25509
+ }
25431
25510
  function backfillLegacyAnchors(store2, ts) {
25432
25511
  const report = {
25433
25512
  demotedEdges: 0,
@@ -26537,6 +26616,7 @@ function runNightly() {
26537
26616
  const a = backfillLegacyAnchors(store, Date.now());
26538
26617
  anchorsDemoted = a.demotedEdges;
26539
26618
  resolutionsSuspect = a.suspects.length;
26619
+ repairLegacyAnchorsFromStatement(store, Date.now());
26540
26620
  } catch {
26541
26621
  }
26542
26622
  const report = runNightlyPipeline(store);