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

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 +253 -62
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -15479,15 +15479,18 @@ function summaryRejectionReason(summary, isKnownToken) {
15479
15479
  return null;
15480
15480
  }
15481
15481
  function substituteSymbolSummaries(text, summaryByToken) {
15482
- if (summaryByToken.size === 0) return text;
15482
+ if (summaryByToken.size === 0) return { text, substituted: 0, offered: 0 };
15483
15483
  const present = extractIdentifierTokens(text).filter((t) => summaryByToken.has(t));
15484
15484
  present.sort((a, b) => b.length - a.length);
15485
15485
  let out2 = text;
15486
+ let substituted = 0;
15486
15487
  for (const key of present) {
15487
15488
  const re = new RegExp(`(?<![A-Za-z0-9_$.])${escapeRe2(key)}(?![A-Za-z0-9_$])`, "g");
15489
+ const before = out2;
15488
15490
  out2 = out2.replace(re, summaryByToken.get(key));
15491
+ if (out2 !== before) substituted++;
15489
15492
  }
15490
- return out2;
15493
+ return { text: out2, substituted, offered: summaryByToken.size };
15491
15494
  }
15492
15495
  function vetSidecarSummaries(sidecar) {
15493
15496
  if (!sidecar) return null;
@@ -27844,8 +27847,15 @@ function fileRolePhrase(relPath, level = 1) {
27844
27847
  if (/\.(json|ya?ml|toml|env)$/i.test(relPath)) return "a config file";
27845
27848
  return "a source file";
27846
27849
  }
27850
+ function isSourceFileToken(token) {
27851
+ const basename5 = token.split(/[/\\]/).pop() ?? token;
27852
+ if (CONVENTION_FILENAMES.has(basename5)) return false;
27853
+ const ext = basename5.split(".").pop();
27854
+ return ext !== void 0 && SOURCE_EXTENSIONS.has(ext.toLowerCase());
27855
+ }
27847
27856
  function generalizeFileRefs(text, fileLexicon, level = 1) {
27848
27857
  let out2 = text;
27858
+ let lexiconMisses = 0;
27849
27859
  const files = [];
27850
27860
  const seenFiles = /* @__PURE__ */ new Set();
27851
27861
  for (const m of out2.matchAll(FILE_TOKEN_RE)) {
@@ -27854,6 +27864,7 @@ function generalizeFileRefs(text, fileLexicon, level = 1) {
27854
27864
  seenFiles.add(tok);
27855
27865
  const entry = resolveFileToken(tok, fileLexicon);
27856
27866
  if (entry) files.push([tok, entry]);
27867
+ else if (isSourceFileToken(tok)) lexiconMisses++;
27857
27868
  }
27858
27869
  files.sort((a, b) => b[0].length - a[0].length);
27859
27870
  for (const [tok, entry] of files) {
@@ -27874,10 +27885,10 @@ function generalizeFileRefs(text, fileLexicon, level = 1) {
27874
27885
  const re = new RegExp(`(?<![\\w$/\\\\.-])${escapeRe4(tok)}(?![\\w$/\\\\.-])`, "g");
27875
27886
  out2 = out2.replace(re, fileRolePhrase(entry.relPath, level));
27876
27887
  }
27877
- return out2;
27888
+ return { text: out2, substitutions: files.length + stems.length, lexiconMisses };
27878
27889
  }
27879
27890
  function generalizeSymbols(text, lexicon, level = 1, fileLexicon) {
27880
- let out2 = fileLexicon ? generalizeFileRefs(text, fileLexicon, level) : text;
27891
+ let out2 = fileLexicon ? generalizeFileRefs(text, fileLexicon, level).text : text;
27881
27892
  const present = [];
27882
27893
  const seen = /* @__PURE__ */ new Set();
27883
27894
  for (const m of out2.matchAll(TOKEN_RE3)) {
@@ -27896,7 +27907,7 @@ function generalizeSymbols(text, lexicon, level = 1, fileLexicon) {
27896
27907
  }
27897
27908
  return generalize(out2, { level }).text;
27898
27909
  }
27899
- var SYMBOL_LABELS2, KIND_PHRASE, RE_RESERVED2, escapeRe4, CONVENTION_FILENAMES, CONVENTION_BASENAME_MIN_FILES, CONVENTION_STEMS, FILE_TOKEN_RE, STEM_TOKEN_RE, TOKEN_RE3;
27910
+ var SYMBOL_LABELS2, KIND_PHRASE, RE_RESERVED2, escapeRe4, CONVENTION_FILENAMES, CONVENTION_BASENAME_MIN_FILES, CONVENTION_STEMS, FILE_TOKEN_RE, STEM_TOKEN_RE, SOURCE_EXTENSIONS, TOKEN_RE3;
27900
27911
  var init_generalize_graph = __esm({
27901
27912
  "src/generalize-graph.ts"() {
27902
27913
  "use strict";
@@ -27966,6 +27977,45 @@ var init_generalize_graph = __esm({
27966
27977
  ]);
27967
27978
  FILE_TOKEN_RE = /(?:[A-Za-z0-9_.-]+\/)*[A-Za-z0-9_-][A-Za-z0-9_.-]*\.[A-Za-z0-9]+/g;
27968
27979
  STEM_TOKEN_RE = /[A-Za-z0-9]+(?:[-_][A-Za-z0-9]+)+/g;
27980
+ SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
27981
+ "ts",
27982
+ "tsx",
27983
+ "js",
27984
+ "jsx",
27985
+ "mjs",
27986
+ "cjs",
27987
+ "py",
27988
+ "go",
27989
+ "rs",
27990
+ "java",
27991
+ "kt",
27992
+ "rb",
27993
+ "c",
27994
+ "h",
27995
+ "cc",
27996
+ "cpp",
27997
+ "hpp",
27998
+ "cs",
27999
+ "php",
28000
+ "swift",
28001
+ "scala",
28002
+ "sh",
28003
+ "ps1",
28004
+ "sql",
28005
+ "css",
28006
+ "scss",
28007
+ "html",
28008
+ "vue",
28009
+ "svelte",
28010
+ "md",
28011
+ "json",
28012
+ "yaml",
28013
+ "yml",
28014
+ "toml",
28015
+ "ini",
28016
+ "env",
28017
+ "cypher"
28018
+ ]);
27969
28019
  TOKEN_RE3 = /[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*/g;
27970
28020
  }
27971
28021
  });
@@ -52255,33 +52305,34 @@ function readFrom(path2, fromByte, maxBytes) {
52255
52305
  try {
52256
52306
  fd = openSync(path2, "r");
52257
52307
  } catch {
52258
- return { text: "", nextOffset: fromByte, more: false };
52308
+ return { text: "", nextOffset: fromByte, more: false, ioFailed: true };
52259
52309
  }
52260
52310
  try {
52261
52311
  const size = fstatSync(fd).size;
52262
52312
  const start2 = fromByte > 0 && fromByte <= size ? fromByte : 0;
52263
52313
  const remaining = size - start2;
52264
- if (remaining <= 0) return { text: "", nextOffset: size, more: false };
52314
+ if (remaining <= 0) return { text: "", nextOffset: size, more: false, ioFailed: false };
52265
52315
  let cap = maxBytes && maxBytes > 0 ? maxBytes : remaining;
52266
52316
  for (; ; ) {
52267
52317
  const len = Math.min(cap, remaining);
52268
52318
  const buf = Buffer.allocUnsafe(len);
52269
52319
  readSync(fd, buf, 0, len, start2);
52270
52320
  if (len >= remaining) {
52271
- return { text: buf.toString("utf8"), nextOffset: size, more: false };
52321
+ return { text: buf.toString("utf8"), nextOffset: size, more: false, ioFailed: false };
52272
52322
  }
52273
52323
  const nl = buf.lastIndexOf(10);
52274
52324
  if (nl >= 0) {
52275
52325
  return {
52276
52326
  text: buf.subarray(0, nl + 1).toString("utf8"),
52277
52327
  nextOffset: start2 + nl + 1,
52278
- more: true
52328
+ more: true,
52329
+ ioFailed: false
52279
52330
  };
52280
52331
  }
52281
52332
  cap *= 2;
52282
52333
  }
52283
52334
  } catch {
52284
- return { text: "", nextOffset: fromByte, more: false };
52335
+ return { text: "", nextOffset: fromByte, more: false, ioFailed: true };
52285
52336
  } finally {
52286
52337
  closeSync(fd);
52287
52338
  }
@@ -52299,22 +52350,25 @@ function transcriptSize(path2) {
52299
52350
  }
52300
52351
  }
52301
52352
  function readTail(path2, maxBytes) {
52353
+ return readTailWithLosses(path2, maxBytes).text;
52354
+ }
52355
+ function readTailWithLosses(path2, maxBytes) {
52302
52356
  let fd;
52303
52357
  try {
52304
52358
  fd = openSync(path2, "r");
52305
52359
  } catch {
52306
- return "";
52360
+ return { text: "", bytesUnreachable: 0, ioFailed: true };
52307
52361
  }
52308
52362
  try {
52309
52363
  const size = fstatSync(fd).size;
52310
52364
  const start2 = Math.max(0, size - maxBytes);
52311
52365
  const len = size - start2;
52312
- if (len <= 0) return "";
52366
+ if (len <= 0) return { text: "", bytesUnreachable: 0, ioFailed: false };
52313
52367
  const buf = Buffer.allocUnsafe(len);
52314
52368
  readSync(fd, buf, 0, len, start2);
52315
- return buf.toString("utf8");
52369
+ return { text: buf.toString("utf8"), bytesUnreachable: start2, ioFailed: false };
52316
52370
  } catch {
52317
- return "";
52371
+ return { text: "", bytesUnreachable: 0, ioFailed: true };
52318
52372
  } finally {
52319
52373
  closeSync(fd);
52320
52374
  }
@@ -52374,15 +52428,30 @@ function isUserTurnBoundary(obj) {
52374
52428
  if (blocks.some((b) => b["type"] === "tool_result")) return false;
52375
52429
  return blocks.some((b) => b["type"] === "text");
52376
52430
  }
52377
- function readAssistantTurns(transcriptPath, includeThinking = true, maxBytes = 2e6) {
52378
- return parseAssistantTurns(readTail(transcriptPath, maxBytes), includeThinking);
52431
+ function readAssistantTurnsWithLosses(transcriptPath, includeThinking = true, maxBytes = 2e6) {
52432
+ const tail = readTailWithLosses(transcriptPath, maxBytes);
52433
+ const parsed = parseAssistantTurns(tail.text, includeThinking, false);
52434
+ return {
52435
+ turns: parsed.turns,
52436
+ losses: {
52437
+ parseFailures: parsed.parseFailures,
52438
+ ioFailed: tail.ioFailed,
52439
+ bytesUnreachable: tail.bytesUnreachable
52440
+ }
52441
+ };
52379
52442
  }
52380
52443
  function readAssistantTurnsFrom(transcriptPath, fromByte, includeThinking = true, maxBytes) {
52381
- const { text, nextOffset, more } = readFrom(transcriptPath, fromByte, maxBytes);
52382
- return { turns: parseAssistantTurns(text, includeThinking), nextOffset, more };
52444
+ const { text, nextOffset, more, ioFailed } = readFrom(transcriptPath, fromByte, maxBytes);
52445
+ const parsed = parseAssistantTurns(text, includeThinking, fromByte > 0);
52446
+ return {
52447
+ turns: parsed.turns,
52448
+ nextOffset,
52449
+ more,
52450
+ losses: { parseFailures: parsed.parseFailures, ioFailed, bytesUnreachable: 0 }
52451
+ };
52383
52452
  }
52384
- function parseAssistantTurns(raw2, includeThinking) {
52385
- if (!raw2) return [];
52453
+ function parseAssistantTurns(raw2, includeThinking, skipFirstLineParseFailure = false) {
52454
+ if (!raw2) return { turns: [], parseFailures: 0 };
52386
52455
  const turns = [];
52387
52456
  const lines = raw2.split(/\r?\n/);
52388
52457
  let lastFile;
@@ -52391,6 +52460,7 @@ function parseAssistantTurns(raw2, includeThinking) {
52391
52460
  let editedFile;
52392
52461
  let editedFileTurnSeq = 0;
52393
52462
  let turnSeq = 0;
52463
+ let parseFailures = 0;
52394
52464
  for (let i2 = 0; i2 < lines.length; i2++) {
52395
52465
  const line = lines[i2];
52396
52466
  if (!line) continue;
@@ -52398,6 +52468,7 @@ function parseAssistantTurns(raw2, includeThinking) {
52398
52468
  try {
52399
52469
  obj = JSON.parse(line);
52400
52470
  } catch {
52471
+ if (!(i2 === 0 && skipFirstLineParseFailure)) parseFailures++;
52401
52472
  continue;
52402
52473
  }
52403
52474
  if (isUserTurnBoundary(obj)) {
@@ -52439,7 +52510,7 @@ function parseAssistantTurns(raw2, includeThinking) {
52439
52510
  ...commands.length > 0 ? { commands } : {}
52440
52511
  });
52441
52512
  }
52442
- return turns;
52513
+ return { turns, parseFailures };
52443
52514
  }
52444
52515
  function turnsSince(turns, mark) {
52445
52516
  if (!mark) return turns;
@@ -52524,6 +52595,7 @@ var BUILDS_ON_PREFIX = /^\s*builds-on:(?:#([a-z][\w-]{0,63}))?\s*/i;
52524
52595
  var SUPERSEDES_PREFIX = /^\s*supersedes:(?:#([a-z][\w-]{0,63}))?\s*/i;
52525
52596
  var ALTERNATIVE_PREFIX = /^\s*alternative:(?:#([a-z][\w-]{0,63}))?\s*/i;
52526
52597
  var INSTANCE_PREFIX = /^\s*instance:\s*/i;
52598
+ var BRACKETED_TOKEN_RE = /\[[^\]\n]{1,120}\]/;
52527
52599
  var CONFIRM_PREFIX = /^\s*confirm:\s*/i;
52528
52600
  var REFUTE_PREFIX = /^\s*refute:\s*/i;
52529
52601
  var REFUTE_REASON_MIN = 4;
@@ -52561,18 +52633,44 @@ function deriveFixRationale(sentence, startIdx, endIdx) {
52561
52633
  if (before.length >= FIX_RATIONALE_MIN) return before;
52562
52634
  return fixRationaleAfter(sentence, endIdx);
52563
52635
  }
52636
+ function emptyTagDispositions() {
52637
+ return {
52638
+ oversizeSegments: 0,
52639
+ codeSpanNeutralized: 0,
52640
+ refuteTooShort: 0,
52641
+ causeTooShort: 0,
52642
+ negated: 0,
52643
+ unparseable: 0
52644
+ };
52645
+ }
52646
+ function addTagDispositions(a, b) {
52647
+ a.oversizeSegments += b.oversizeSegments;
52648
+ a.codeSpanNeutralized += b.codeSpanNeutralized;
52649
+ a.refuteTooShort += b.refuteTooShort;
52650
+ a.causeTooShort += b.causeTooShort;
52651
+ a.negated += b.negated;
52652
+ a.unparseable += b.unparseable;
52653
+ }
52564
52654
  function parseInlineTags(text) {
52655
+ return parseInlineTagsWithDispositions(text).tags;
52656
+ }
52657
+ function parseInlineTagsWithDispositions(text) {
52565
52658
  const out2 = [];
52659
+ const dispositions = emptyTagDispositions();
52566
52660
  const deFenced = text.replace(/```[\s\S]*?```/g, " ");
52567
52661
  let seqNo = -1;
52568
52662
  for (const raw2 of deFenced.split(/(?<=[.!?])\s+|\n+/)) {
52569
52663
  seqNo++;
52570
- if (raw2.length > 2e4) continue;
52664
+ if (raw2.length > 2e4) {
52665
+ dispositions.oversizeSegments++;
52666
+ continue;
52667
+ }
52571
52668
  const seqStart = out2.length;
52572
- const sentence = raw2.replace(
52573
- /`[^`]*`/g,
52574
- (m) => /\[[!?]|\((?:fix|cause|constraint|tried|failed|confirm|refute):|\(\[/.test(m) ? " " : m
52575
- );
52669
+ const sentence = raw2.replace(/`[^`]*`/g, (m) => {
52670
+ if (!/\[[!?]|\((?:fix|cause|constraint|tried|failed|confirm|refute):|\(\[/.test(m)) return m;
52671
+ dispositions.codeSpanNeutralized++;
52672
+ return " ";
52673
+ });
52576
52674
  const sfield = sentence.replace(/\s+/g, " ").trim().slice(0, 160);
52577
52675
  const citeMatched = /* @__PURE__ */ new Set();
52578
52676
  CITE_GROUP_RE.lastIndex = 0;
@@ -52622,6 +52720,7 @@ function parseInlineTags(text) {
52622
52720
  if (refuteM) {
52623
52721
  const reason = body2.replace(new RegExp(HANDLE_RE.source, "gi"), " ").replace(/\s+/g, " ").trim();
52624
52722
  if (reason.length >= REFUTE_REASON_MIN) out2.push({ kind: "refute", handle: handle2, statement: reason, sentence: sfield });
52723
+ else dispositions.refuteTooShort++;
52625
52724
  } else {
52626
52725
  out2.push({ kind: "confirm", handle: handle2, sentence: sfield });
52627
52726
  }
@@ -52642,11 +52741,14 @@ function parseInlineTags(text) {
52642
52741
  if (raw3.length >= CAUSE_TEXT_MIN) {
52643
52742
  const causeText = raw3;
52644
52743
  out2.push({ kind: "triage", causeText, sentence: sfield, ...verbThread ? { threadId: verbThread } : {} });
52645
- }
52744
+ } else dispositions.causeTooShort++;
52646
52745
  }
52647
52746
  continue;
52648
52747
  }
52649
- if (!isFix && NEG.test(clauseBefore(sentence, g.index))) continue;
52748
+ if (!isFix && NEG.test(clauseBefore(sentence, g.index))) {
52749
+ dispositions.negated++;
52750
+ continue;
52751
+ }
52650
52752
  let fixRationale;
52651
52753
  if (isFix) {
52652
52754
  const r = deriveFixRationale(sentence, g.index, g.index + g[0].length);
@@ -52672,6 +52774,9 @@ function parseInlineTags(text) {
52672
52774
  const note = content.replace(/\s+/g, " ").trim();
52673
52775
  if (note.length >= FIX_RATIONALE_MIN)
52674
52776
  out2.push({ kind: "fix", fixRationale: note, sentence: sfield, ...verbThread ? { threadId: verbThread } : {} });
52777
+ else dispositions.unparseable++;
52778
+ } else if (!isFix && !emittedHandle && BRACKETED_TOKEN_RE.test(content)) {
52779
+ dispositions.unparseable++;
52675
52780
  }
52676
52781
  }
52677
52782
  for (const pass of [
@@ -52839,7 +52944,7 @@ function parseInlineTags(text) {
52839
52944
  }
52840
52945
  for (let i2 = seqStart; i2 < out2.length; i2++) out2[i2].seq = seqNo;
52841
52946
  }
52842
- return out2;
52947
+ return { tags: out2, dispositions };
52843
52948
  }
52844
52949
  var LABEL_PAIR = {
52845
52950
  "Problem>RootCause": "CAUSED_BY",
@@ -52995,8 +53100,10 @@ function harvestInlineTags(store, text, opts) {
52995
53100
  const source = opts.sourceId ? store.getNode(opts.sourceId) : null;
52996
53101
  const mintPriors = opts.mintPriors ?? true;
52997
53102
  const touched = opts.sessionTouchedIds ?? /* @__PURE__ */ new Set();
52998
- const plan = { priorEdges: 0, corroboratedEdges: 0, exposureShown: 0, exposureEvicted: 0, exposureUnshown: 0, problems: [], fixes: [], triages: [], causalLinks: [], attempts: [], unresolvedFixes: [], transfers: [], solutionLinks: [], instances: [], patterns: [], domains: [], packages: [], components: [], refutes: [], corroborations: [] };
52999
- const tags = parseInlineTags(text);
53103
+ const plan = { priorEdges: 0, corroboratedEdges: 0, exposureShown: 0, exposureEvicted: 0, exposureUnshown: 0, problems: [], fixes: [], triages: [], causalLinks: [], attempts: [], unresolvedFixes: [], unresolvedHandles: [], priorEdgesSuppressed: { flagOff: 0, noSource: 0 }, dispositions: emptyTagDispositions(), transfers: [], solutionLinks: [], instances: [], patterns: [], domains: [], packages: [], components: [], refutes: [], corroborations: [] };
53104
+ const parsed = parseInlineTagsWithDispositions(text);
53105
+ const tags = parsed.tags;
53106
+ plan.dispositions = parsed.dispositions;
53000
53107
  const symptomSeqs = tags.filter((t) => (t.kind === "problem" || t.kind === "todo") && t.statement).map((t) => ({ seq: t.seq ?? -1, statement: t.statement, threadId: t.threadId })).sort((a, b) => a.seq - b.seq);
53001
53108
  const bindSymptom = (seq, threadId) => {
53002
53109
  if (threadId) {
@@ -53018,6 +53125,11 @@ function harvestInlineTags(store, text, opts) {
53018
53125
  if (symptomSeqs.length === 1) return { statement: best.statement, evidence: "witnessed" };
53019
53126
  return { statement: best.statement, evidence: "inferred" };
53020
53127
  };
53128
+ const resolveCited = (kind, handle2) => {
53129
+ const id = resolveHandle(store, handle2, opts.handleMap) ?? null;
53130
+ if (!id) plan.unresolvedHandles.push({ kind, handle: handle2 });
53131
+ return id;
53132
+ };
53021
53133
  for (const tag of tags) {
53022
53134
  if (tag.kind === "problem" || tag.kind === "todo") {
53023
53135
  plan.problems.push({
@@ -53059,7 +53171,7 @@ function harvestInlineTags(store, text, opts) {
53059
53171
  evidence: b.evidence
53060
53172
  };
53061
53173
  if (tag.handle) {
53062
- const causeId = resolveHandle(store, tag.handle, opts.handleMap);
53174
+ const causeId = resolveCited("triage", tag.handle);
53063
53175
  const node2 = causeId ? store.getNode(causeId) : null;
53064
53176
  if (node2) plan.triages.push({ causeId: node2.id, causeDescription: node2.description, ...bound });
53065
53177
  } else if (tag.causeText) {
@@ -53078,7 +53190,7 @@ function harvestInlineTags(store, text, opts) {
53078
53190
  } else if (tag.kind === "transfer") {
53079
53191
  const targetIds = [];
53080
53192
  for (const h of tag.handles ?? []) {
53081
- const id = resolveHandle(store, h, opts.handleMap);
53193
+ const id = resolveCited("transfer", h);
53082
53194
  if (id && !targetIds.includes(id)) targetIds.push(id);
53083
53195
  }
53084
53196
  if (targetIds.length > 0) {
@@ -53092,7 +53204,7 @@ function harvestInlineTags(store, text, opts) {
53092
53204
  } else if (tag.kind === "builds-on" || tag.kind === "supersedes" || tag.kind === "alternative") {
53093
53205
  const targetIds = [];
53094
53206
  for (const h of tag.handles ?? []) {
53095
- const id = resolveHandle(store, h, opts.handleMap);
53207
+ const id = resolveCited(tag.kind, h);
53096
53208
  if (id && !targetIds.includes(id)) targetIds.push(id);
53097
53209
  }
53098
53210
  if (targetIds.length > 0) {
@@ -53108,7 +53220,7 @@ function harvestInlineTags(store, text, opts) {
53108
53220
  } else if (tag.kind === "instance") {
53109
53221
  const targetIds = [];
53110
53222
  for (const h of tag.handles ?? []) {
53111
- const id = resolveHandle(store, h, opts.handleMap);
53223
+ const id = resolveCited("instance", h);
53112
53224
  if (id && !targetIds.includes(id)) targetIds.push(id);
53113
53225
  }
53114
53226
  if (targetIds.length > 0) {
@@ -53130,7 +53242,7 @@ function harvestInlineTags(store, text, opts) {
53130
53242
  evidence: b.evidence
53131
53243
  };
53132
53244
  if (tag.handle) {
53133
- const patternId = resolveHandle(store, tag.handle, opts.handleMap);
53245
+ const patternId = resolveCited("pattern", tag.handle);
53134
53246
  if (patternId) plan.patterns.push({ patternId, ...bound });
53135
53247
  } else if (tag.patternText) {
53136
53248
  plan.patterns.push({ patternText: tag.patternText, ...bound });
@@ -53156,7 +53268,7 @@ function harvestInlineTags(store, text, opts) {
53156
53268
  else plan.components.push({ componentText: tag.componentText, ...bound });
53157
53269
  } else if (tag.kind === "attempt" || tag.kind === "failure") {
53158
53270
  for (const h of tag.refuteHandles ?? []) {
53159
- const nodeId = resolveHandle(store, h, opts.handleMap);
53271
+ const nodeId = resolveCited("refute", h);
53160
53272
  if (nodeId) {
53161
53273
  const witnessKey = `refute:${nodeId}:${digest({ s: tag.statement ?? "" })}`.slice(0, 72);
53162
53274
  if (!plan.refutes.some((r) => r.witnessKey === witnessKey)) {
@@ -53179,7 +53291,7 @@ function harvestInlineTags(store, text, opts) {
53179
53291
  });
53180
53292
  }
53181
53293
  } else if (tag.kind === "confirm" || tag.kind === "refute") {
53182
- const targetId = resolveHandle(store, tag.handle, opts.handleMap);
53294
+ const targetId = resolveCited(tag.kind, tag.handle);
53183
53295
  const target = targetId ? store.getNode(targetId) : null;
53184
53296
  const citedLabel = target?.label ?? opts.handleMap[tag.handle]?.label;
53185
53297
  if (targetId && citedLabel && CORROBORATABLE_LABELS.has(citedLabel)) {
@@ -53200,7 +53312,7 @@ function harvestInlineTags(store, text, opts) {
53200
53312
  }
53201
53313
  }
53202
53314
  } else if (tag.kind === "prior") {
53203
- const targetId = resolveHandle(store, tag.handle, opts.handleMap);
53315
+ const targetId = resolveCited("prior", tag.handle);
53204
53316
  const target = targetId ? store.getNode(targetId) : null;
53205
53317
  const citedLabel = target?.label ?? opts.handleMap[tag.handle]?.label;
53206
53318
  if (targetId && citedLabel && CORROBORATABLE_LABELS.has(citedLabel)) {
@@ -53219,9 +53331,12 @@ function harvestInlineTags(store, text, opts) {
53219
53331
  plan.priorEdges++;
53220
53332
  if (m.corroborated) plan.corroboratedEdges++;
53221
53333
  }
53334
+ } else if (target) {
53335
+ if (!mintPriors) plan.priorEdgesSuppressed.flagOff++;
53336
+ else if (!source) plan.priorEdgesSuppressed.noSource++;
53222
53337
  }
53223
53338
  } else if (mintPriors && source) {
53224
- const targetId = resolveHandle(store, tag.handle, opts.handleMap);
53339
+ const targetId = resolveCited(tag.kind, tag.handle);
53225
53340
  const target = targetId ? store.getNode(targetId) : null;
53226
53341
  if (target) {
53227
53342
  const m = mintPriorEdge(store, source, target, tag.sentence, touched, opts.ts);
@@ -53230,6 +53345,9 @@ function harvestInlineTags(store, text, opts) {
53230
53345
  if (m.corroborated) plan.corroboratedEdges++;
53231
53346
  }
53232
53347
  }
53348
+ } else if (tag.handle) {
53349
+ if (!mintPriors) plan.priorEdgesSuppressed.flagOff++;
53350
+ else if (!source) plan.priorEdgesSuppressed.noSource++;
53233
53351
  }
53234
53352
  }
53235
53353
  return plan;
@@ -55206,16 +55324,19 @@ var WITNESS_MAX_ATTEMPTS = 5;
55206
55324
  function witnessQueuePath(workspaceConfigDir) {
55207
55325
  return join25(workspaceConfigDir, "witness-queue.json");
55208
55326
  }
55209
- function loadWitnessQueue(path2) {
55327
+ function loadWitnessQueueWithLosses(path2) {
55328
+ let raw2;
55210
55329
  try {
55211
- const raw2 = JSON.parse(readFileSync20(path2, "utf8"));
55212
- if (!Array.isArray(raw2)) return [];
55213
- return raw2.filter(
55214
- (w) => !!w && typeof w === "object" && typeof w.nodeId === "string" && typeof w.witnessKey === "string"
55215
- );
55216
- } catch {
55217
- return [];
55330
+ raw2 = JSON.parse(readFileSync20(path2, "utf8"));
55331
+ } catch (err2) {
55332
+ const absent = err2?.code === "ENOENT";
55333
+ return { queue: [], fileUnreadable: !absent, malformedEntries: 0 };
55218
55334
  }
55335
+ if (!Array.isArray(raw2)) return { queue: [], fileUnreadable: true, malformedEntries: 0 };
55336
+ const queue = raw2.filter(
55337
+ (w) => !!w && typeof w === "object" && typeof w.nodeId === "string" && typeof w.witnessKey === "string"
55338
+ );
55339
+ return { queue, fileUnreadable: false, malformedEntries: raw2.length - queue.length };
55219
55340
  }
55220
55341
  function saveWitnessQueue(path2, queue) {
55221
55342
  try {
@@ -55226,10 +55347,21 @@ function saveWitnessQueue(path2, queue) {
55226
55347
  }
55227
55348
  }
55228
55349
  function pruneWitnessQueue(queue, now) {
55229
- const live2 = queue.filter(
55230
- (w) => now - w.ts < WITNESS_TTL_MS && w.attempts < WITNESS_MAX_ATTEMPTS
55231
- );
55232
- return live2.length > WITNESS_QUEUE_CAP ? live2.slice(live2.length - WITNESS_QUEUE_CAP) : live2;
55350
+ return pruneWitnessQueueWithDispositions(queue, now).queue;
55351
+ }
55352
+ function pruneWitnessQueueWithDispositions(queue, now) {
55353
+ const dropped = { expiredTtl: 0, exhaustedAttempts: 0, cappedOverflow: 0 };
55354
+ const live2 = [];
55355
+ for (const w of queue) {
55356
+ if (now - w.ts >= WITNESS_TTL_MS) dropped.expiredTtl++;
55357
+ else if (w.attempts >= WITNESS_MAX_ATTEMPTS) dropped.exhaustedAttempts++;
55358
+ else live2.push(w);
55359
+ }
55360
+ if (live2.length > WITNESS_QUEUE_CAP) {
55361
+ dropped.cappedOverflow = live2.length - WITNESS_QUEUE_CAP;
55362
+ return { queue: live2.slice(live2.length - WITNESS_QUEUE_CAP), dropped };
55363
+ }
55364
+ return { queue: live2, dropped };
55233
55365
  }
55234
55366
  function enqueueWitnesses(queue, fresh, now) {
55235
55367
  const byKey = new Map(queue.map((w) => [`${w.channel}:${w.witnessKey}`, w]));
@@ -55561,7 +55693,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
55561
55693
  }
55562
55694
 
55563
55695
  // src/engine.ts
55564
- var DAEMON_VERSION = true ? "2.0.2-dev.714" : "2.0.0-alpha.0";
55696
+ var DAEMON_VERSION = true ? "2.0.2-dev.723" : "2.0.0-alpha.0";
55565
55697
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
55566
55698
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
55567
55699
  var GIT_OP_MUTE_MS = 4e3;
@@ -55668,10 +55800,19 @@ function createWorkspaceEngine(opts) {
55668
55800
  refreshRepoLocator(opts.workspaceRoot, profile);
55669
55801
  }
55670
55802
  const store = openGraphStore({ path: paths.castalia });
55671
- let witnessQueue = pruneWitnessQueue(
55672
- loadWitnessQueue(witnessQueuePath(paths.configDir)),
55673
- Date.now()
55674
- );
55803
+ const witnessLoad = loadWitnessQueueWithLosses(witnessQueuePath(paths.configDir));
55804
+ const witnessPrune = pruneWitnessQueueWithDispositions(witnessLoad.queue, Date.now());
55805
+ let witnessQueue = witnessPrune.queue;
55806
+ if (witnessLoad.fileUnreadable || witnessLoad.malformedEntries > 0 || witnessPrune.dropped.expiredTtl > 0 || witnessPrune.dropped.exhaustedAttempts > 0 || witnessPrune.dropped.cappedOverflow > 0) {
55807
+ appendPassLedger(paths.configDir, "witness-queue", 0, {
55808
+ loaded: witnessQueue.length,
55809
+ fileUnreadable: witnessLoad.fileUnreadable ? 1 : 0,
55810
+ malformedEntries: witnessLoad.malformedEntries,
55811
+ prunedExpiredTtl: witnessPrune.dropped.expiredTtl,
55812
+ prunedExhaustedAttempts: witnessPrune.dropped.exhaustedAttempts,
55813
+ prunedCappedOverflow: witnessPrune.dropped.cappedOverflow
55814
+ });
55815
+ }
55675
55816
  const log = openEventLog({ path: paths.eventLog });
55676
55817
  const bundled = import.meta.url.endsWith(".mjs");
55677
55818
  const passWorker = bundled && paths.castalia !== ":memory:" ? new PassWorker({
@@ -56302,6 +56443,7 @@ function createWorkspaceEngine(opts) {
56302
56443
  const turnCursorPath = join27(paths.configDir, "turn-cursors.json");
56303
56444
  const lastTurnUuid = loadTurnCursors(turnCursorPath);
56304
56445
  const turnOffset = loadTurnOffsets(turnCursorPath);
56446
+ const readLosses = { parseFailures: 0, ioFailures: 0, bytesUnreachable: 0, sliceGuardHits: 0 };
56305
56447
  const sessionLastProblem = /* @__PURE__ */ new Map();
56306
56448
  const sessionThreads = /* @__PURE__ */ new Map();
56307
56449
  const harvestTexts = async (sessionId, items) => {
@@ -56323,6 +56465,10 @@ function createWorkspaceEngine(opts) {
56323
56465
  let exposureEvicted = 0;
56324
56466
  let exposureUnshown = 0;
56325
56467
  let corroboratedEdges = 0;
56468
+ const dispositions = emptyTagDispositions();
56469
+ let unresolvedHandles = 0;
56470
+ let priorEdgesFlagOff = 0;
56471
+ let priorEdgesNoSource = 0;
56326
56472
  let touchedFileTurns = 0;
56327
56473
  let touchedToolTurns = 0;
56328
56474
  let anchorHintsUpgraded = 0;
@@ -56456,6 +56602,10 @@ function createWorkspaceEngine(opts) {
56456
56602
  });
56457
56603
  priorEdges += plan.priorEdges;
56458
56604
  corroboratedEdges += plan.corroboratedEdges;
56605
+ addTagDispositions(dispositions, plan.dispositions);
56606
+ unresolvedHandles += plan.unresolvedHandles.length;
56607
+ priorEdgesFlagOff += plan.priorEdgesSuppressed.flagOff;
56608
+ priorEdgesNoSource += plan.priorEdgesSuppressed.noSource;
56459
56609
  exposureShown += plan.exposureShown;
56460
56610
  exposureEvicted += plan.exposureEvicted;
56461
56611
  exposureUnshown += plan.exposureUnshown;
@@ -56891,8 +57041,32 @@ function createWorkspaceEngine(opts) {
56891
57041
  // touchedToolTurns 0 with this >0 = the hook and harvest disagree on
56892
57042
  // the session key; 0 with 0 = records never happen.
56893
57043
  toolSessionsTracked: toolRuns.sessions(),
56894
- seqAdvanced: store.currentIngestSeq() - seqAtStart
57044
+ seqAdvanced: store.currentIngestSeq() - seqAtStart,
57045
+ // TEL T1.1/T1.2/T1.3 — the capture path's drops. `tagsCodeSpan` and
57046
+ // `tagsUnparseable` rising means the vocabulary and the writer disagree
57047
+ // (our bug); `tagsRefuteTooShort` means a demotion verdict was lost;
57048
+ // `unresolvedHandles` means an agent cited a prior we could no longer
57049
+ // name. Every one of these used to be a silent `continue`.
57050
+ tagsOversize: dispositions.oversizeSegments,
57051
+ tagsCodeSpan: dispositions.codeSpanNeutralized,
57052
+ tagsRefuteTooShort: dispositions.refuteTooShort,
57053
+ tagsCauseTooShort: dispositions.causeTooShort,
57054
+ tagsNegated: dispositions.negated,
57055
+ tagsUnparseable: dispositions.unparseable,
57056
+ unresolvedHandles,
57057
+ priorEdgesFlagOff,
57058
+ priorEdgesNoSource,
57059
+ // TEL T1.7/T1.8 — transcript-read losses. `harvestBytesUnreachable` is
57060
+ // the only counter here measuring knowledge that can never be recovered.
57061
+ harvestParseFailures: readLosses.parseFailures,
57062
+ harvestIoFailures: readLosses.ioFailures,
57063
+ harvestBytesUnreachable: readLosses.bytesUnreachable,
57064
+ harvestSliceGuardHits: readLosses.sliceGuardHits
56895
57065
  });
57066
+ readLosses.parseFailures = 0;
57067
+ readLosses.ioFailures = 0;
57068
+ readLosses.bytesUnreachable = 0;
57069
+ readLosses.sliceGuardHits = 0;
56896
57070
  }
56897
57071
  };
56898
57072
  const harvestTurns = async (sessionId, transcriptPath) => {
@@ -56901,12 +57075,20 @@ function createWorkspaceEngine(opts) {
56901
57075
  let nextOffset;
56902
57076
  try {
56903
57077
  if (known === void 0) {
56904
- turns = readAssistantTurns(transcriptPath);
57078
+ const first = readAssistantTurnsWithLosses(transcriptPath);
57079
+ turns = first.turns;
56905
57080
  nextOffset = transcriptSize(transcriptPath);
57081
+ readLosses.bytesUnreachable += first.losses.bytesUnreachable;
57082
+ readLosses.parseFailures += first.losses.parseFailures;
57083
+ if (first.losses.ioFailed) readLosses.ioFailures++;
56906
57084
  } else {
56907
- ({ turns, nextOffset } = readAssistantTurnsFrom(transcriptPath, known, true, HARVEST_SLICE_BYTES));
57085
+ const slice = readAssistantTurnsFrom(transcriptPath, known, true, HARVEST_SLICE_BYTES);
57086
+ ({ turns, nextOffset } = slice);
57087
+ readLosses.parseFailures += slice.losses.parseFailures;
57088
+ if (slice.losses.ioFailed) readLosses.ioFailures++;
56908
57089
  }
56909
57090
  } catch {
57091
+ readLosses.ioFailures++;
56910
57092
  return;
56911
57093
  }
56912
57094
  for (let slice = 0; ; slice++) {
@@ -56918,6 +57100,7 @@ function createWorkspaceEngine(opts) {
56918
57100
  }
56919
57101
  saveTurnCursors(turnCursorPath, lastTurnUuid, turnOffset);
56920
57102
  if (slice >= 256) {
57103
+ readLosses.sliceGuardHits++;
56921
57104
  console.warn("[errata] harvest slice guard hit \u2014 backlog resumes next tick");
56922
57105
  break;
56923
57106
  }
@@ -56925,8 +57108,11 @@ function createWorkspaceEngine(opts) {
56925
57108
  try {
56926
57109
  next = readAssistantTurnsFrom(transcriptPath, nextOffset, true, HARVEST_SLICE_BYTES);
56927
57110
  } catch {
57111
+ readLosses.ioFailures++;
56928
57112
  break;
56929
57113
  }
57114
+ readLosses.parseFailures += next.losses.parseFailures;
57115
+ if (next.losses.ioFailed) readLosses.ioFailures++;
56930
57116
  if (next.turns.length === 0 && !next.more) {
56931
57117
  turnOffset.set(sessionId, next.nextOffset);
56932
57118
  saveTurnCursors(turnCursorPath, lastTurnUuid, turnOffset);
@@ -58029,7 +58215,10 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
58029
58215
  const fileLexicon = buildFileLexicon(store);
58030
58216
  const shareable = (n) => {
58031
58217
  const preserved = symbolIndex ? preservedSymbolsFor(n.description, symbolIndex) : [];
58032
- const fileScrubbed = generalizeFileRefs(n.description, fileLexicon, level);
58218
+ const fileRefs = generalizeFileRefs(n.description, fileLexicon, level);
58219
+ const fileScrubbed = fileRefs.text;
58220
+ composition.fileRefsSubstituted += fileRefs.substitutions;
58221
+ composition.fileRefLexiconMisses += fileRefs.lexiconMisses;
58033
58222
  const generalized = generalize(fileScrubbed, { level, project: projectIdentity });
58034
58223
  const shippedText = generalized.text;
58035
58224
  if (generalized.report.classes.length > 0) composition.privacyRewritten++;
@@ -58073,7 +58262,9 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
58073
58262
  privacyRewritten: 0,
58074
58263
  sidecarDropped: 0,
58075
58264
  sidecarDropReasons: {},
58076
- sidecarTruncatedAtCap: 0
58265
+ sidecarTruncatedAtCap: 0,
58266
+ fileRefsSubstituted: 0,
58267
+ fileRefLexiconMisses: 0
58077
58268
  };
58078
58269
  for (const label of INSTANCE_LABELS) {
58079
58270
  const ref = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.2-dev.714",
3
+ "version": "2.0.2-dev.723",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {