@inerrata-corporation/errata 2.0.0-dev.83 → 2.0.0-dev.85

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 +137 -21
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -17773,6 +17773,59 @@ function linkProblemToPackages(store, problemId, text, ts, index) {
17773
17773
  }
17774
17774
  return { linked };
17775
17775
  }
17776
+ function buildLanguageIndex(store) {
17777
+ const idx = /* @__PURE__ */ new Map();
17778
+ for (const n of store.findNodesByLabel("Language")) {
17779
+ const name2 = String(n.attrs["name"] ?? n.description ?? "").trim().toLowerCase();
17780
+ if (name2) idx.set(name2, n);
17781
+ }
17782
+ return idx;
17783
+ }
17784
+ function matchLanguagesInText(text, index) {
17785
+ const hay = text.toLowerCase();
17786
+ const out2 = [];
17787
+ for (const [key, node2] of index) {
17788
+ if (key.length < LANGUAGE_MIN_LEN) continue;
17789
+ if (!hay.includes(key)) continue;
17790
+ const bounded = new RegExp(`(?<![\\w@/.\\-])${escapeRe3(key)}(?![\\w])`);
17791
+ if (bounded.test(hay)) out2.push(node2);
17792
+ }
17793
+ return out2;
17794
+ }
17795
+ function linkProblemToLanguages(store, problemId, text, ts, index) {
17796
+ const p = store.getNode(problemId);
17797
+ if (!p || p.label !== "Problem") return [];
17798
+ const idx = index ?? buildLanguageIndex(store);
17799
+ if (idx.size === 0) return [];
17800
+ const already = new Set(store.outEdges(problemId, ["OCCURS_IN"]).map((e) => e.to));
17801
+ const linked = [];
17802
+ for (const node2 of matchLanguagesInText(text, idx)) {
17803
+ if (already.has(node2.id)) continue;
17804
+ store.mergeEdge({
17805
+ id: `edge_${digest({ from: problemId, type: "OCCURS_IN", to: node2.id })}`.slice(0, 24),
17806
+ from: problemId,
17807
+ to: node2.id,
17808
+ type: "OCCURS_IN",
17809
+ confidence: 0.3,
17810
+ // below the structural walk's 0.4 — a mention, not an anchor walk
17811
+ extractionSource: "daemon-extracted",
17812
+ createdAt: ts,
17813
+ lastSeenAt: ts,
17814
+ navSuccesses: 0,
17815
+ navFailures: 0,
17816
+ attrs: { provisional: true, mention: true }
17817
+ });
17818
+ already.add(node2.id);
17819
+ linked.push(node2.id);
17820
+ }
17821
+ return linked;
17822
+ }
17823
+ function deriveContextFromStatement(store, problemId, text, ts, pkgIndex) {
17824
+ return {
17825
+ packages: linkProblemToPackages(store, problemId, text, ts, pkgIndex).linked,
17826
+ languages: linkProblemToLanguages(store, problemId, text, ts)
17827
+ };
17828
+ }
17776
17829
  function problemText(store, p) {
17777
17830
  const parts2 = [p.description];
17778
17831
  for (const e of store.outEdges(p.id, ["CAUSED_BY"])) {
@@ -17894,7 +17947,7 @@ function backfillProblemContext(store, ts) {
17894
17947
  }
17895
17948
  return report;
17896
17949
  }
17897
- var NAME_SEPARATOR, MIN_NAME_LEN;
17950
+ var NAME_SEPARATOR, MIN_NAME_LEN, LANGUAGE_MIN_LEN;
17898
17951
  var init_problem_package_link = __esm({
17899
17952
  "../../packages/local-graph/src/problem-package-link.ts"() {
17900
17953
  "use strict";
@@ -17902,6 +17955,7 @@ var init_problem_package_link = __esm({
17902
17955
  init_justification();
17903
17956
  NAME_SEPARATOR = /[@/\-._]/;
17904
17957
  MIN_NAME_LEN = 3;
17958
+ LANGUAGE_MIN_LEN = 4;
17905
17959
  }
17906
17960
  });
17907
17961
 
@@ -18191,7 +18245,7 @@ function solutionForProblem(store, problemId) {
18191
18245
  const e = store.outEdges(problemId, ["SOLVED_BY"])[0];
18192
18246
  return e ? e.to : null;
18193
18247
  }
18194
- function anchorProblemToWorkingFile(store, problemId, relPath, workspaceId2, ts) {
18248
+ function anchorProblemToWorkingFile(store, problemId, relPath, workspaceId2, ts, provenance = "edited") {
18195
18249
  const p = store.getNode(problemId);
18196
18250
  if (!p || p.label !== "Problem") return false;
18197
18251
  if (!ANCHORABLE_CODE.test(relPath)) return false;
@@ -18204,14 +18258,23 @@ function anchorProblemToWorkingFile(store, problemId, relPath, workspaceId2, ts)
18204
18258
  from: problemId,
18205
18259
  to: file2.id,
18206
18260
  type: "ANCHORED_AT",
18207
- confidence: 0.3,
18208
- // soft: in-focus file is a heuristic, below F2's resolve-diff anchor (0.4)
18261
+ // witnessed = the agent's own declaration, F2-grade; edited = soft heuristic.
18262
+ confidence: provenance === "witnessed" ? 0.4 : 0.3,
18209
18263
  extractionSource: "agent-observed",
18210
18264
  createdAt: ts,
18211
18265
  lastSeenAt: ts,
18212
18266
  navSuccesses: 0,
18213
18267
  navFailures: 0,
18214
- attrs: { provisional: true, captureTime: true }
18268
+ attrs: { provisional: true, captureTime: true, anchorProvenance: provenance }
18269
+ });
18270
+ return true;
18271
+ }
18272
+ function recordAnchorHint(store, problemId, relPath, provenance, ts) {
18273
+ const p = store.getNode(problemId);
18274
+ if (!p || p.label !== "Problem") return false;
18275
+ if (p.attrs["anchorHint"]) return false;
18276
+ store.updateNode(problemId, {
18277
+ attrs: { ...p.attrs, anchorHint: { path: relPath, provenance, ts } }
18215
18278
  });
18216
18279
  return true;
18217
18280
  }
@@ -20300,6 +20363,7 @@ __export(src_exports2, {
20300
20363
  applyPulledPrinciples: () => applyPulledPrinciples,
20301
20364
  backfillProblemContext: () => backfillProblemContext,
20302
20365
  backfillProblemPackageLinks: () => backfillProblemPackageLinks,
20366
+ buildLanguageIndex: () => buildLanguageIndex,
20303
20367
  buildPackageIndex: () => buildPackageIndex,
20304
20368
  buildPrincipleSync: () => buildPrincipleSync,
20305
20369
  causalChain: () => causalChain,
@@ -20312,6 +20376,7 @@ __export(src_exports2, {
20312
20376
  creditAssignment: () => creditAssignment,
20313
20377
  crystallize: () => crystallize,
20314
20378
  deriveContextFromAnchors: () => deriveContextFromAnchors,
20379
+ deriveContextFromStatement: () => deriveContextFromStatement,
20315
20380
  designProblemId: () => designProblemId,
20316
20381
  detectLocalCommunities: () => detectLocalCommunities,
20317
20382
  edgeConductance: () => edgeConductance,
@@ -20327,8 +20392,10 @@ __export(src_exports2, {
20327
20392
  induceTriage: () => induceTriage,
20328
20393
  ingestDesignProblem: () => ingestDesignProblem,
20329
20394
  isPlaceholderStatement: () => isPlaceholderStatement,
20395
+ linkProblemToLanguages: () => linkProblemToLanguages,
20330
20396
  linkProblemToPackages: () => linkProblemToPackages,
20331
20397
  listNeedsRevisit: () => listNeedsRevisit,
20398
+ matchLanguagesInText: () => matchLanguagesInText,
20332
20399
  matchPackagesInText: () => matchPackagesInText,
20333
20400
  mergeCloudCounts: () => mergeCloudCounts,
20334
20401
  mergeDuplicateProblems: () => mergeDuplicateProblems,
@@ -20342,6 +20409,7 @@ __export(src_exports2, {
20342
20409
  priorsForFile: () => priorsForFile,
20343
20410
  propagateFactChange: () => propagateFactChange,
20344
20411
  propagateVersionChange: () => propagateVersionChange,
20412
+ recordAnchorHint: () => recordAnchorHint,
20345
20413
  recordClaim: () => recordClaim,
20346
20414
  recordMisreadPrior: () => recordMisreadPrior,
20347
20415
  recordTriageObservation: () => recordTriageObservation,
@@ -24568,7 +24636,7 @@ var init_agent_signals = __esm({
24568
24636
  };
24569
24637
  GLOSS = {
24570
24638
  prior: "a prior we showed you helped \u2014 or this work sits in a primed language/package",
24571
- problem: "you hit a real problem \u2014 incidental, or the one you're fixing",
24639
+ problem: "you hit a real problem \u2014 incidental, or the one you're fixing. About specific code? NAME the file in the tag: [!what's wrong @ src/file.ts:42] \u2014 we anchor to what you name, or to a file you edited this turn, never to one you merely read; a design/topic problem is fine with no @",
24572
24640
  fix: "your edit fixes a problem \u2014 cite the one we showed you, or just say how you fixed one you found yourself: (fix: what you changed)",
24573
24641
  constraint: "you made a design decision because requirements conflict or something's constrained \u2014 tag the tension, ESPECIALLY when your fix makes it 'only look' contradictory (a clean solution still hides a real trap the next agent needs)",
24574
24642
  triage: "you diagnosed a bug \u2014 SPLIT the symptom (what breaks \u2192 [!\u2026]) from the cause (the mechanism you'd change \u2192 (cause:\u2026)); if the line says WHY it breaks, it's a cause, not a problem",
@@ -37995,6 +38063,9 @@ function buildWebUi(deps) {
37995
38063
  stack: deps.profile.stack,
37996
38064
  nodes: deps.store.nodeCount(),
37997
38065
  edges: deps.store.edgeCount(),
38066
+ // Ontology-gate refusals since daemon start (local EDGE_RULES at
38067
+ // mergeEdge, #1153) — a misbehaving extractor shows here, never silently.
38068
+ rejectedEdges: deps.store.rejectedEdgeCount,
37998
38069
  pendingReview: pendingCount(deps.paths),
37999
38070
  daemonVersion: deps.daemonVersion,
38000
38071
  endpoints: [
@@ -38026,6 +38097,7 @@ function buildWebUi(deps) {
38026
38097
  workspace: deps.profile.id,
38027
38098
  nodes: deps.store.nodeCount(),
38028
38099
  edges: deps.store.edgeCount(),
38100
+ rejectedEdges: deps.store.rejectedEdgeCount,
38029
38101
  pendingReview: pendingCount(deps.paths),
38030
38102
  daemonVersion: deps.daemonVersion
38031
38103
  })
@@ -41398,12 +41470,27 @@ function parseDesignResolutions(text) {
41398
41470
  return out2;
41399
41471
  }
41400
41472
  var FILE_TOOLS = /* @__PURE__ */ new Set(["Read", "Edit", "Write", "MultiEdit", "NotebookEdit"]);
41473
+ var WRITE_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
41474
+ function isUserTurnBoundary(obj) {
41475
+ if (obj.type !== "user") return false;
41476
+ const content = obj.message?.content;
41477
+ if (typeof content === "string") return content.trim().length > 0;
41478
+ if (!Array.isArray(content)) return false;
41479
+ const blocks = content;
41480
+ if (blocks.some((b) => b["type"] === "tool_result")) return false;
41481
+ return blocks.some((b) => b["type"] === "text");
41482
+ }
41401
41483
  function readAssistantTurns(transcriptPath, includeThinking = true, maxBytes = 2e6) {
41402
41484
  const raw2 = readTail(transcriptPath, maxBytes);
41403
41485
  if (!raw2) return [];
41404
41486
  const turns = [];
41405
41487
  const lines = raw2.split(/\r?\n/);
41406
41488
  let lastFile;
41489
+ let lastFileIsWrite = false;
41490
+ let lastFileTurnSeq = 0;
41491
+ let editedFile;
41492
+ let editedFileTurnSeq = 0;
41493
+ let turnSeq = 0;
41407
41494
  for (let i2 = 0; i2 < lines.length; i2++) {
41408
41495
  const line = lines[i2];
41409
41496
  if (!line) continue;
@@ -41413,6 +41500,10 @@ function readAssistantTurns(transcriptPath, includeThinking = true, maxBytes = 2
41413
41500
  } catch {
41414
41501
  continue;
41415
41502
  }
41503
+ if (isUserTurnBoundary(obj)) {
41504
+ turnSeq++;
41505
+ continue;
41506
+ }
41416
41507
  if (obj.type !== "assistant" || !Array.isArray(obj.message?.content)) continue;
41417
41508
  const parts2 = [];
41418
41509
  for (const b of obj.message.content) {
@@ -41422,13 +41513,24 @@ function readAssistantTurns(transcriptPath, includeThinking = true, maxBytes = 2
41422
41513
  else if (b["type"] === "tool_use" && typeof b["name"] === "string" && FILE_TOOLS.has(b["name"])) {
41423
41514
  const input = b["input"];
41424
41515
  const fp = input && typeof input === "object" ? input["file_path"] : void 0;
41425
- if (typeof fp === "string" && fp) lastFile = fp;
41516
+ if (typeof fp === "string" && fp) {
41517
+ lastFile = fp;
41518
+ lastFileIsWrite = WRITE_TOOLS.has(b["name"]);
41519
+ lastFileTurnSeq = turnSeq;
41520
+ if (lastFileIsWrite) {
41521
+ editedFile = fp;
41522
+ editedFileTurnSeq = turnSeq;
41523
+ }
41524
+ }
41426
41525
  }
41427
41526
  }
41527
+ const provenance = lastFile ? lastFileTurnSeq === turnSeq ? lastFileIsWrite ? "edited" : "read" : "carried" : void 0;
41428
41528
  turns.push({
41429
41529
  uuid: String(obj.uuid ?? i2),
41430
41530
  text: parts2.join("\n\n"),
41431
- ...lastFile ? { workingFile: lastFile } : {}
41531
+ ...lastFile ? { workingFile: lastFile } : {},
41532
+ ...provenance ? { workingFileProvenance: provenance } : {},
41533
+ ...editedFile && editedFileTurnSeq === turnSeq ? { editedFile } : {}
41432
41534
  });
41433
41535
  }
41434
41536
  return turns;
@@ -43529,7 +43631,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
43529
43631
  }
43530
43632
 
43531
43633
  // src/engine.ts
43532
- var DAEMON_VERSION = true ? "2.0.0-dev.83" : "2.0.0-alpha.0";
43634
+ var DAEMON_VERSION = true ? "2.0.0-dev.85" : "2.0.0-alpha.0";
43533
43635
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
43534
43636
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
43535
43637
  var GIT_OP_MUTE_MS = 4e3;
@@ -44074,6 +44176,7 @@ function createWorkspaceEngine(opts) {
44074
44176
  for (const turn of items) {
44075
44177
  if (processedTurns++ > 0) await yieldToLoop();
44076
44178
  const turnFile = turn.workingFile ? toRel(turn.workingFile) : void 0;
44179
+ const editedTurnFile = turn.editedFile ? toRel(turn.editedFile) : void 0;
44077
44180
  if (opts.sharedStore) {
44078
44181
  try {
44079
44182
  abstracted += harvestAbstractionFences(opts.sharedStore, turn.text, t).applied;
@@ -44099,12 +44202,19 @@ function createWorkspaceEngine(opts) {
44099
44202
  });
44100
44203
  if (r.created || r.corroborated) minted++;
44101
44204
  sessionLastProblem.set(sessionId, designProblemId(flag.problem));
44102
- const fencedAnchor = turnFile ?? workingFiles.get(sessionId);
44103
- if ((r.created || r.corroborated) && fencedAnchor) {
44205
+ if (r.created || r.corroborated) {
44104
44206
  try {
44105
- if (anchorProblemToWorkingFile(store, r.problemId, fencedAnchor, profile.id, t)) {
44106
- deriveContextFromAnchors(store, r.problemId, t);
44207
+ if (editedTurnFile) {
44208
+ if (anchorProblemToWorkingFile(store, r.problemId, editedTurnFile, profile.id, t, "edited")) {
44209
+ deriveContextFromAnchors(store, r.problemId, t);
44210
+ }
44211
+ } else if (!flag.anchor) {
44212
+ const hintPath = turnFile ?? workingFiles.get(sessionId);
44213
+ if (hintPath) {
44214
+ recordAnchorHint(store, r.problemId, hintPath, turn.workingFileProvenance === "read" ? "read" : "carried", t);
44215
+ }
44107
44216
  }
44217
+ deriveContextFromStatement(store, r.problemId, flag.problem, t);
44108
44218
  } catch {
44109
44219
  }
44110
44220
  }
@@ -44163,10 +44273,13 @@ function createWorkspaceEngine(opts) {
44163
44273
  const threads = sessionThreads.get(sessionId) ?? /* @__PURE__ */ new Map();
44164
44274
  sessionThreads.set(sessionId, threads);
44165
44275
  for (const p of plan.problems) {
44166
- const anchorPath = p.location?.path ?? turnFile ?? wf;
44167
- if (anchorPath) {
44276
+ const anchorPath = p.location?.path ?? editedTurnFile;
44277
+ const anchorProvenance = p.location?.path ? "witnessed" : "edited";
44278
+ const hintPath = anchorPath ? void 0 : turnFile ?? wf;
44279
+ const dedupPath = anchorPath ?? hintPath;
44280
+ if (dedupPath) {
44168
44281
  try {
44169
- const dupId = reinforceSameAnchorProblem(store, anchorPath, profile.id, p.statement, sessionId, t);
44282
+ const dupId = reinforceSameAnchorProblem(store, dedupPath, profile.id, p.statement, sessionId, t);
44170
44283
  if (dupId) {
44171
44284
  minted++;
44172
44285
  sessionLastProblem.set(sessionId, dupId);
@@ -44187,13 +44300,16 @@ function createWorkspaceEngine(opts) {
44187
44300
  sessionLastProblem.set(sessionId, designProblemId(p.statement));
44188
44301
  inScopeProblemId = designProblemId(p.statement);
44189
44302
  if (p.threadId) threads.set(p.threadId, designProblemId(p.statement));
44190
- if (anchorPath) {
44191
- try {
44192
- if (anchorProblemToWorkingFile(store, r.problemId, anchorPath, profile.id, t)) {
44303
+ try {
44304
+ if (anchorPath) {
44305
+ if (anchorProblemToWorkingFile(store, r.problemId, anchorPath, profile.id, t, anchorProvenance)) {
44193
44306
  deriveContextFromAnchors(store, r.problemId, t);
44194
44307
  }
44195
- } catch {
44308
+ } else if (hintPath) {
44309
+ recordAnchorHint(store, r.problemId, hintPath, turn.workingFileProvenance === "read" ? "read" : "carried", t);
44196
44310
  }
44311
+ deriveContextFromStatement(store, r.problemId, p.statement, t);
44312
+ } catch {
44197
44313
  }
44198
44314
  }
44199
44315
  }
@@ -44214,7 +44330,7 @@ function createWorkspaceEngine(opts) {
44214
44330
  }
44215
44331
  if (resolveDesignProblemById(store, pid, fx.fixNote, t)) {
44216
44332
  resolved++;
44217
- const fxAnchor = turnFile ?? wf;
44333
+ const fxAnchor = editedTurnFile ?? turnFile ?? wf;
44218
44334
  if (fxAnchor) {
44219
44335
  try {
44220
44336
  anchorProblemToDiff(store, pid, [fxAnchor], profile.id, t);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.0-dev.83",
3
+ "version": "2.0.0-dev.85",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {