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

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
@@ -17660,13 +17660,46 @@ function addDependency(store, opts) {
17660
17660
  store.mergeEdge(edge2);
17661
17661
  return edge2;
17662
17662
  }
17663
- function markRevisit(store, node2, reason, ts) {
17663
+ function markRevisit(store, node2, reason, ts, answeredWhen) {
17664
17664
  const fresh = store.getNode(node2.id) ?? node2;
17665
17665
  store.updateNode(node2.id, {
17666
- attrs: { ...fresh.attrs, revisit: true, revisitReason: reason, revisitSinceTs: ts },
17666
+ attrs: {
17667
+ ...fresh.attrs,
17668
+ revisit: true,
17669
+ revisitReason: reason,
17670
+ revisitSinceTs: ts,
17671
+ ...answeredWhen ? { revisitAnsweredWhen: answeredWhen } : {}
17672
+ },
17667
17673
  lastUpdatedAt: ts
17668
17674
  });
17669
17675
  }
17676
+ function conditionOf(node2) {
17677
+ const explicit = node2.attrs["revisitAnsweredWhen"];
17678
+ if (explicit === "parentProblemOpen") return explicit;
17679
+ if (String(node2.attrs["revisitReason"] ?? "").startsWith(LEGACY_AUTO_CLOSE_ASK)) {
17680
+ return "parentProblemOpen";
17681
+ }
17682
+ return void 0;
17683
+ }
17684
+ function clearAnsweredRevisits(store, ts) {
17685
+ const report = { cleared: 0, standing: 0 };
17686
+ for (const node2 of store.findNodesByLabel("Solution")) {
17687
+ if (node2.attrs["revisit"] !== true) continue;
17688
+ if (conditionOf(node2) !== "parentProblemOpen") {
17689
+ report.standing++;
17690
+ continue;
17691
+ }
17692
+ const parents = store.inEdges(node2.id, ["SOLVED_BY"]).map((e) => store.getNode(e.from)).filter((n) => n !== null);
17693
+ const answered = parents.every((p) => p.attrs["resolvedAt"] == null);
17694
+ if (!answered) {
17695
+ report.standing++;
17696
+ continue;
17697
+ }
17698
+ clearRevisit(store, node2.id, ts);
17699
+ report.cleared++;
17700
+ }
17701
+ return report;
17702
+ }
17670
17703
  function clearRevisit(store, nodeId, ts) {
17671
17704
  const n = store.getNode(nodeId);
17672
17705
  if (!n) return;
@@ -17739,10 +17772,12 @@ function propagateFactChange(store, opts) {
17739
17772
  cascade(store, seeds, visited, flagged, opts.ts);
17740
17773
  return flagged;
17741
17774
  }
17775
+ var LEGACY_AUTO_CLOSE_ASK;
17742
17776
  var init_justification = __esm({
17743
17777
  "../../packages/local-graph/src/justification.ts"() {
17744
17778
  "use strict";
17745
17779
  init_src();
17780
+ LEGACY_AUTO_CLOSE_ASK = "auto-closed off a pre-provenance anchor";
17746
17781
  }
17747
17782
  });
17748
17783
 
@@ -19260,11 +19295,12 @@ function markFixCandidates(store, t) {
19260
19295
  let symName = "";
19261
19296
  let symRelPath;
19262
19297
  let edited = false;
19298
+ const since = Math.max(p.createdAt, Number(p.attrs["fixCandidateClearedAt"] ?? 0));
19263
19299
  for (const e of store.outEdges(p.id, ["ANCHORED_AT"])) {
19264
19300
  if (e.attrs?.["mention"] === true) continue;
19265
19301
  if (e.attrs?.["anchorProvenance"] === "legacy") continue;
19266
19302
  const sym = store.getNode(e.to);
19267
- if (sym && sym.lastUpdatedAt > p.createdAt) {
19303
+ if (sym && sym.lastUpdatedAt > since) {
19268
19304
  edited = true;
19269
19305
  symName = sym.description;
19270
19306
  symRelPath = sym.attrs["relPath"] ?? void 0;
@@ -19285,7 +19321,12 @@ function markFixCandidates(store, t) {
19285
19321
  // asking about. Deliberately NOT `resolvedAt` — this is a question.
19286
19322
  fixCandidateAt: t,
19287
19323
  fixCandidateSymbol: symName,
19288
- ...symRelPath ? { fixCandidateFile: symRelPath } : {}
19324
+ ...symRelPath ? { fixCandidateFile: symRelPath } : {},
19325
+ // Snapshot the render-ledger counter so "shown since THIS ask" is
19326
+ // measurable. `shownCount` is the node's LIFETIME count across every
19327
+ // band, so comparing it raw would retire a fresh ask on a
19328
+ // frequently-surfaced problem before anyone had seen the question once.
19329
+ fixCandidateShownBase: Number(p.attrs["shownCount"] ?? 0)
19289
19330
  },
19290
19331
  lastUpdatedAt: t
19291
19332
  });
@@ -19293,6 +19334,34 @@ function markFixCandidates(store, t) {
19293
19334
  }
19294
19335
  return resolved;
19295
19336
  }
19337
+ function clearSettledFixCandidates(store, t) {
19338
+ const report = { answered: 0, ignored: 0, standing: 0 };
19339
+ for (const p of store.findNodesByLabel("Problem")) {
19340
+ if (p.attrs["fixCandidateAt"] === void 0) continue;
19341
+ const answered = p.attrs["resolvedAt"] != null || store.outEdges(p.id, ["SOLVED_BY"]).some((e) => {
19342
+ const s = store.getNode(e.to);
19343
+ return s !== null && !String(s.description ?? "").startsWith(AUTO_MINT_PREFIX);
19344
+ });
19345
+ const base = Number(
19346
+ p.attrs["fixCandidateShownBase"] ?? p.attrs["shownCount"] ?? 0
19347
+ );
19348
+ const shownSinceAsk = Number(p.attrs["shownCount"] ?? 0) - base;
19349
+ const ignored = shownSinceAsk >= FIX_CANDIDATE_ASK_LIMIT;
19350
+ if (!answered && !ignored) {
19351
+ report.standing++;
19352
+ continue;
19353
+ }
19354
+ const attrs = { ...p.attrs };
19355
+ delete attrs["fixCandidateAt"];
19356
+ delete attrs["fixCandidateSymbol"];
19357
+ delete attrs["fixCandidateFile"];
19358
+ attrs["fixCandidateClearedAt"] = t;
19359
+ store.updateNode(p.id, { attrs, lastUpdatedAt: t });
19360
+ if (answered) report.answered++;
19361
+ else report.ignored++;
19362
+ }
19363
+ return report;
19364
+ }
19296
19365
  function recordRenderLedger(store, ledger, seq, ts) {
19297
19366
  const bump = (ids, field) => {
19298
19367
  let n = 0;
@@ -19318,7 +19387,7 @@ function recordRenderLedger(store, ledger, seq, ts) {
19318
19387
  });
19319
19388
  return { shown, evicted };
19320
19389
  }
19321
- var DESIGN_PROMOTE_AT, STATEMENT_ALIAS_CAP, PATTERN_DEDUP_COSINE, PATTERN_ALIAS_CAP, DEDUP_STOPWORDS, SAME_ANCHOR_DEDUP_JACCARD, CITABLE_PRIOR_LABELS, MAX_ANCHOR_FILES, AUTO_MINT_PREFIX;
19390
+ var DESIGN_PROMOTE_AT, STATEMENT_ALIAS_CAP, PATTERN_DEDUP_COSINE, PATTERN_ALIAS_CAP, DEDUP_STOPWORDS, SAME_ANCHOR_DEDUP_JACCARD, CITABLE_PRIOR_LABELS, MAX_ANCHOR_FILES, AUTO_MINT_PREFIX, FIX_CANDIDATE_ASK_LIMIT;
19322
19391
  var init_design_problem = __esm({
19323
19392
  "../../packages/local-graph/src/design-problem.ts"() {
19324
19393
  "use strict";
@@ -19365,6 +19434,7 @@ var init_design_problem = __esm({
19365
19434
  ]);
19366
19435
  MAX_ANCHOR_FILES = 5;
19367
19436
  AUTO_MINT_PREFIX = "addressed by an edit to ";
19437
+ FIX_CANDIDATE_ASK_LIMIT = 5;
19368
19438
  }
19369
19439
  });
19370
19440
 
@@ -19560,7 +19630,11 @@ function backfillLegacyAnchors(store, ts) {
19560
19630
  store,
19561
19631
  sol,
19562
19632
  `auto-closed off a pre-provenance anchor (guessed ${guessedAnchor}) \u2014 confirm the problem is really fixed, or reopen it`,
19563
- ts
19633
+ ts,
19634
+ // "or reopen it" is half the ask, and the nightly reopen takes that
19635
+ // branch — so record what would answer this, or the flag can never be
19636
+ // lowered and the band fills with settled questions.
19637
+ "parentProblemOpen"
19564
19638
  );
19565
19639
  store.updateNode(p.id, {
19566
19640
  attrs: { ...p.attrs, resolutionSuspect: true },
@@ -21684,6 +21758,7 @@ __export(src_exports2, {
21684
21758
  CITABLE_PRIOR_LABELS: () => CITABLE_PRIOR_LABELS,
21685
21759
  CODE_REACH_EDGES: () => CODE_REACH_EDGES,
21686
21760
  CREDIT_FAMILY: () => CREDIT_FAMILY,
21761
+ FIX_CANDIDATE_ASK_LIMIT: () => FIX_CANDIDATE_ASK_LIMIT,
21687
21762
  JOINT_COMMUNITY_EDGES: () => JOINT_COMMUNITY_EDGES,
21688
21763
  JOINT_COMMUNITY_LABELS: () => JOINT_COMMUNITY_LABELS,
21689
21764
  MAX_ANCHOR_FILES: () => MAX_ANCHOR_FILES,
@@ -21711,7 +21786,9 @@ __export(src_exports2, {
21711
21786
  canonicalizePatternText: () => canonicalizePatternText,
21712
21787
  causalChain: () => causalChain,
21713
21788
  claimId: () => claimId,
21789
+ clearAnsweredRevisits: () => clearAnsweredRevisits,
21714
21790
  clearRevisit: () => clearRevisit,
21791
+ clearSettledFixCandidates: () => clearSettledFixCandidates,
21715
21792
  communityInductionRequests: () => communityInductionRequests,
21716
21793
  communitySeeds: () => communitySeeds,
21717
21794
  compareSemver: () => compareSemver,
@@ -28434,6 +28511,8 @@ function runNightlyPipeline(store) {
28434
28511
  });
28435
28512
  const motifs = promoteMotifs(store, started2);
28436
28513
  reopenAutoClosedProblems(store, started2);
28514
+ const revisits = clearAnsweredRevisits(store, started2);
28515
+ const fixCandidates = clearSettledFixCandidates(store, started2);
28437
28516
  const designResolved = markFixCandidates(store, started2);
28438
28517
  const cry = crystallize(store, { ts: started2 });
28439
28518
  return {
@@ -28449,6 +28528,8 @@ function runNightlyPipeline(store) {
28449
28528
  // skills are cloud-induced now (see above)
28450
28529
  skillsRefreshed: 0,
28451
28530
  designResolved,
28531
+ revisitsCleared: revisits.cleared,
28532
+ fixCandidatesSettled: fixCandidates.answered + fixCandidates.ignored,
28452
28533
  claimsEvaluated: cry.evaluated,
28453
28534
  claimsDerived: cry.derived.length,
28454
28535
  durationMs: Date.now() - started2
@@ -53704,7 +53785,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
53704
53785
  }
53705
53786
 
53706
53787
  // src/engine.ts
53707
- var DAEMON_VERSION = true ? "2.0.2-dev.483" : "2.0.0-alpha.0";
53788
+ var DAEMON_VERSION = true ? "2.0.2-dev.500" : "2.0.0-alpha.0";
53708
53789
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
53709
53790
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
53710
53791
  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.483",
3
+ "version": "2.0.2-dev.500",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -25007,13 +25007,56 @@ function addDependency(store2, opts) {
25007
25007
  store2.mergeEdge(edge);
25008
25008
  return edge;
25009
25009
  }
25010
- function markRevisit(store2, node, reason, ts) {
25010
+ function markRevisit(store2, node, reason, ts, answeredWhen) {
25011
25011
  const fresh = store2.getNode(node.id) ?? node;
25012
25012
  store2.updateNode(node.id, {
25013
- attrs: { ...fresh.attrs, revisit: true, revisitReason: reason, revisitSinceTs: ts },
25013
+ attrs: {
25014
+ ...fresh.attrs,
25015
+ revisit: true,
25016
+ revisitReason: reason,
25017
+ revisitSinceTs: ts,
25018
+ ...answeredWhen ? { revisitAnsweredWhen: answeredWhen } : {}
25019
+ },
25014
25020
  lastUpdatedAt: ts
25015
25021
  });
25016
25022
  }
25023
+ var LEGACY_AUTO_CLOSE_ASK = "auto-closed off a pre-provenance anchor";
25024
+ function conditionOf(node) {
25025
+ const explicit = node.attrs["revisitAnsweredWhen"];
25026
+ if (explicit === "parentProblemOpen") return explicit;
25027
+ if (String(node.attrs["revisitReason"] ?? "").startsWith(LEGACY_AUTO_CLOSE_ASK)) {
25028
+ return "parentProblemOpen";
25029
+ }
25030
+ return void 0;
25031
+ }
25032
+ function clearAnsweredRevisits(store2, ts) {
25033
+ const report = { cleared: 0, standing: 0 };
25034
+ for (const node of store2.findNodesByLabel("Solution")) {
25035
+ if (node.attrs["revisit"] !== true) continue;
25036
+ if (conditionOf(node) !== "parentProblemOpen") {
25037
+ report.standing++;
25038
+ continue;
25039
+ }
25040
+ const parents = store2.inEdges(node.id, ["SOLVED_BY"]).map((e) => store2.getNode(e.from)).filter((n) => n !== null);
25041
+ const answered = parents.every((p) => p.attrs["resolvedAt"] == null);
25042
+ if (!answered) {
25043
+ report.standing++;
25044
+ continue;
25045
+ }
25046
+ clearRevisit(store2, node.id, ts);
25047
+ report.cleared++;
25048
+ }
25049
+ return report;
25050
+ }
25051
+ function clearRevisit(store2, nodeId, ts) {
25052
+ const n = store2.getNode(nodeId);
25053
+ if (!n) return;
25054
+ const attrs = { ...n.attrs };
25055
+ delete attrs["revisit"];
25056
+ delete attrs["revisitReason"];
25057
+ delete attrs["revisitSinceTs"];
25058
+ store2.updateNode(nodeId, { attrs, lastUpdatedAt: ts });
25059
+ }
25017
25060
  function listNeedsRevisit(store2, asOf) {
25018
25061
  return store2.nodesAsOf(asOf).filter((n) => n.attrs["revisit"] === true).map((n) => ({
25019
25062
  id: n.id,
@@ -25536,11 +25579,12 @@ function markFixCandidates(store2, t) {
25536
25579
  let symName = "";
25537
25580
  let symRelPath;
25538
25581
  let edited = false;
25582
+ const since = Math.max(p.createdAt, Number(p.attrs["fixCandidateClearedAt"] ?? 0));
25539
25583
  for (const e of store2.outEdges(p.id, ["ANCHORED_AT"])) {
25540
25584
  if (e.attrs?.["mention"] === true) continue;
25541
25585
  if (e.attrs?.["anchorProvenance"] === "legacy") continue;
25542
25586
  const sym = store2.getNode(e.to);
25543
- if (sym && sym.lastUpdatedAt > p.createdAt) {
25587
+ if (sym && sym.lastUpdatedAt > since) {
25544
25588
  edited = true;
25545
25589
  symName = sym.description;
25546
25590
  symRelPath = sym.attrs["relPath"] ?? void 0;
@@ -25561,7 +25605,12 @@ function markFixCandidates(store2, t) {
25561
25605
  // asking about. Deliberately NOT `resolvedAt` — this is a question.
25562
25606
  fixCandidateAt: t,
25563
25607
  fixCandidateSymbol: symName,
25564
- ...symRelPath ? { fixCandidateFile: symRelPath } : {}
25608
+ ...symRelPath ? { fixCandidateFile: symRelPath } : {},
25609
+ // Snapshot the render-ledger counter so "shown since THIS ask" is
25610
+ // measurable. `shownCount` is the node's LIFETIME count across every
25611
+ // band, so comparing it raw would retire a fresh ask on a
25612
+ // frequently-surfaced problem before anyone had seen the question once.
25613
+ fixCandidateShownBase: Number(p.attrs["shownCount"] ?? 0)
25565
25614
  },
25566
25615
  lastUpdatedAt: t
25567
25616
  });
@@ -25569,6 +25618,35 @@ function markFixCandidates(store2, t) {
25569
25618
  }
25570
25619
  return resolved;
25571
25620
  }
25621
+ var FIX_CANDIDATE_ASK_LIMIT = 5;
25622
+ function clearSettledFixCandidates(store2, t) {
25623
+ const report = { answered: 0, ignored: 0, standing: 0 };
25624
+ for (const p of store2.findNodesByLabel("Problem")) {
25625
+ if (p.attrs["fixCandidateAt"] === void 0) continue;
25626
+ const answered = p.attrs["resolvedAt"] != null || store2.outEdges(p.id, ["SOLVED_BY"]).some((e) => {
25627
+ const s = store2.getNode(e.to);
25628
+ return s !== null && !String(s.description ?? "").startsWith(AUTO_MINT_PREFIX);
25629
+ });
25630
+ const base = Number(
25631
+ p.attrs["fixCandidateShownBase"] ?? p.attrs["shownCount"] ?? 0
25632
+ );
25633
+ const shownSinceAsk = Number(p.attrs["shownCount"] ?? 0) - base;
25634
+ const ignored = shownSinceAsk >= FIX_CANDIDATE_ASK_LIMIT;
25635
+ if (!answered && !ignored) {
25636
+ report.standing++;
25637
+ continue;
25638
+ }
25639
+ const attrs = { ...p.attrs };
25640
+ delete attrs["fixCandidateAt"];
25641
+ delete attrs["fixCandidateSymbol"];
25642
+ delete attrs["fixCandidateFile"];
25643
+ attrs["fixCandidateClearedAt"] = t;
25644
+ store2.updateNode(p.id, { attrs, lastUpdatedAt: t });
25645
+ if (answered) report.answered++;
25646
+ else report.ignored++;
25647
+ }
25648
+ return report;
25649
+ }
25572
25650
 
25573
25651
  // ../../packages/local-graph/src/intent.ts
25574
25652
  init_src();
@@ -25716,7 +25794,11 @@ function backfillLegacyAnchors(store2, ts) {
25716
25794
  store2,
25717
25795
  sol,
25718
25796
  `auto-closed off a pre-provenance anchor (guessed ${guessedAnchor}) \u2014 confirm the problem is really fixed, or reopen it`,
25719
- ts
25797
+ ts,
25798
+ // "or reopen it" is half the ask, and the nightly reopen takes that
25799
+ // branch — so record what would answer this, or the flag can never be
25800
+ // lowered and the band fills with settled questions.
25801
+ "parentProblemOpen"
25720
25802
  );
25721
25803
  store2.updateNode(p.id, {
25722
25804
  attrs: { ...p.attrs, resolutionSuspect: true },
@@ -26299,6 +26381,8 @@ function runNightlyPipeline(store2) {
26299
26381
  });
26300
26382
  const motifs = promoteMotifs(store2, started);
26301
26383
  reopenAutoClosedProblems(store2, started);
26384
+ const revisits = clearAnsweredRevisits(store2, started);
26385
+ const fixCandidates = clearSettledFixCandidates(store2, started);
26302
26386
  const designResolved = markFixCandidates(store2, started);
26303
26387
  const cry = crystallize(store2, { ts: started });
26304
26388
  return {
@@ -26314,6 +26398,8 @@ function runNightlyPipeline(store2) {
26314
26398
  // skills are cloud-induced now (see above)
26315
26399
  skillsRefreshed: 0,
26316
26400
  designResolved,
26401
+ revisitsCleared: revisits.cleared,
26402
+ fixCandidatesSettled: fixCandidates.answered + fixCandidates.ignored,
26317
26403
  claimsEvaluated: cry.evaluated,
26318
26404
  claimsDerived: cry.derived.length,
26319
26405
  durationMs: Date.now() - started