@inerrata-corporation/errata 2.0.2-dev.1255 → 2.0.2-dev.1274

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 (3) hide show
  1. package/errata.mjs +545 -23
  2. package/package.json +1 -1
  3. package/pass-worker.mjs +16 -1
package/errata.mjs CHANGED
@@ -18962,11 +18962,16 @@ function foldDuplicateProblem(store, dup, survivor, ts) {
18962
18962
  if (!surv) return;
18963
18963
  const sources = new Set(surv.attrs["sources"] ?? []);
18964
18964
  for (const s of dup.attrs["sources"] ?? []) sources.add(s);
18965
+ const dupSeq = dup.attrs["createdAtSeq"] ?? store.currentIngestSeq();
18966
+ const exposure = priorExposure(store, survivor.id, dupSeq);
18967
+ const expField = `reinforce${exposure[0].toUpperCase()}${exposure.slice(1)}Count`;
18965
18968
  store.updateNode(survivor.id, {
18966
18969
  attrs: {
18967
18970
  ...surv.attrs,
18968
18971
  sources: [...sources],
18969
- corroborations: corroborations(surv) + corroborations(dup) + 1
18972
+ corroborations: corroborations(surv) + corroborations(dup) + 1,
18973
+ [expField]: (surv.attrs[expField] ?? 0) + 1,
18974
+ lastReinforceExposure: exposure
18970
18975
  },
18971
18976
  cumulativeHits: (surv.cumulativeHits ?? 0) + (dup.cumulativeHits ?? 0),
18972
18977
  lastUpdatedAt: ts
@@ -19400,22 +19405,61 @@ function tokenJaccard(a, b) {
19400
19405
  return inter / (sa.size + sb.size - inter);
19401
19406
  }
19402
19407
  function reinforceSameAnchorProblem(store, relPath, workspaceId2, statement, source, ts, kind = "problem") {
19408
+ return foldSameAnchorProblem(store, relPath, workspaceId2, statement, source, ts, kind).foldedId;
19409
+ }
19410
+ function foldSameAnchorProblem(store, relPath, workspaceId2, statement, source, ts, kind = "problem") {
19411
+ const report = { ...EMPTY_FOLD_REPORT };
19403
19412
  const stmt = statement.trim();
19404
- if (!isAnchorableCodePath(relPath)) return null;
19413
+ if (!isAnchorableCodePath(relPath)) {
19414
+ report.noFile = true;
19415
+ return report;
19416
+ }
19405
19417
  const file2 = resolveFileNode(store, relPath, workspaceId2);
19406
- if (!file2) return null;
19418
+ if (!file2) {
19419
+ report.noFile = true;
19420
+ return report;
19421
+ }
19407
19422
  const selfId = identityId({ kind: "DesignProblem", statement: stmt });
19423
+ let stmtVec = null;
19408
19424
  let best = null;
19425
+ let bestScout = null;
19409
19426
  for (const e of store.inEdges(file2.id, ["ANCHORED_AT"])) {
19410
19427
  const cand = store.getNode(e.from);
19411
19428
  if (!cand || cand.label !== "Problem" || cand.attrs["resolvedAt"]) continue;
19412
19429
  if (cand.id === selfId) continue;
19413
19430
  const candKind = cand.attrs["kind"] === "constraint" ? "constraint" : "problem";
19414
- if (candKind !== (kind === "constraint" ? "constraint" : "problem")) continue;
19431
+ if (candKind !== (kind === "constraint" ? "constraint" : "problem")) {
19432
+ report.kindVetoed++;
19433
+ continue;
19434
+ }
19435
+ report.candidates++;
19415
19436
  const score2 = tokenJaccard(stmt, cand.description);
19437
+ if (score2 > report.bestJaccard) report.bestJaccard = score2;
19416
19438
  if (score2 >= SAME_ANCHOR_DEDUP_JACCARD && (!best || score2 > best.score)) best = { node: cand, score: score2 };
19439
+ if (!best) {
19440
+ stmtVec ??= embed(stmt);
19441
+ const hc = cosine(stmtVec, embed(cand.description));
19442
+ if (hc > report.bestHashCos) report.bestHashCos = hc;
19443
+ if ((hc >= SAME_ANCHOR_SCOUT_MIN_COSINE || score2 >= SAME_ANCHOR_NOMINATE_JACCARD) && (!bestScout || hc > bestScout.hashCos)) {
19444
+ bestScout = { node: cand, hashCos: hc, jaccard: score2 };
19445
+ }
19446
+ }
19417
19447
  }
19418
- if (!best) return null;
19448
+ if (!best && bestScout && bestScout.hashCos >= SAME_ANCHOR_SCOUT_AUTO_COSINE) {
19449
+ best = { node: bestScout.node, score: bestScout.jaccard };
19450
+ report.foldedBy = "scout";
19451
+ }
19452
+ if (!best) {
19453
+ if (bestScout) {
19454
+ report.nominate = {
19455
+ targetId: bestScout.node.id,
19456
+ jaccard: bestScout.jaccard,
19457
+ hashCos: bestScout.hashCos
19458
+ };
19459
+ }
19460
+ return report;
19461
+ }
19462
+ report.foldedBy ??= "jaccard";
19419
19463
  const existing = best.node;
19420
19464
  const sources = existing.attrs["sources"] ?? [];
19421
19465
  if (!sources.includes(source)) {
@@ -19437,7 +19481,8 @@ function reinforceSameAnchorProblem(store, relPath, workspaceId2, statement, sou
19437
19481
  lastUpdatedAt: ts
19438
19482
  });
19439
19483
  }
19440
- return existing.id;
19484
+ report.foldedId = existing.id;
19485
+ return report;
19441
19486
  }
19442
19487
  function findResolvedAnchorMatch(store, relPath, workspaceId2, statement, kind = "problem") {
19443
19488
  const stmt = statement.trim();
@@ -19911,7 +19956,7 @@ function priorExposure(store, nodeId, atSeq) {
19911
19956
  if ((n.attrs["evictedCount"] ?? 0) > 0) return "evicted";
19912
19957
  return "unshown";
19913
19958
  }
19914
- var DESIGN_PROMOTE_AT, STATEMENT_ALIAS_CAP, RECURRENCE_DEBOUNCE_MS, PATTERN_DEDUP_COSINE, PATTERN_ALIAS_CAP, DEDUP_STOPWORDS, SAME_ANCHOR_DEDUP_JACCARD, REOPEN_MIN_SOURCES, RECURRENCE_SOURCES_CAP, CITABLE_PRIOR_LABELS, MAX_ANCHOR_FILES, AUTO_MINT_PREFIX, FIX_CANDIDATE_ASK_LIMIT;
19959
+ var DESIGN_PROMOTE_AT, STATEMENT_ALIAS_CAP, RECURRENCE_DEBOUNCE_MS, PATTERN_DEDUP_COSINE, PATTERN_ALIAS_CAP, DEDUP_STOPWORDS, SAME_ANCHOR_DEDUP_JACCARD, EMPTY_FOLD_REPORT, SAME_ANCHOR_SCOUT_AUTO_COSINE, SAME_ANCHOR_SCOUT_MIN_COSINE, SAME_ANCHOR_NOMINATE_JACCARD, REOPEN_MIN_SOURCES, RECURRENCE_SOURCES_CAP, CITABLE_PRIOR_LABELS, MAX_ANCHOR_FILES, AUTO_MINT_PREFIX, FIX_CANDIDATE_ASK_LIMIT;
19915
19960
  var init_design_problem = __esm({
19916
19961
  "../../packages/local-graph/src/design-problem.ts"() {
19917
19962
  "use strict";
@@ -19951,6 +19996,19 @@ var init_design_problem = __esm({
19951
19996
  "where"
19952
19997
  ]);
19953
19998
  SAME_ANCHOR_DEDUP_JACCARD = 0.6;
19999
+ EMPTY_FOLD_REPORT = {
20000
+ foldedId: null,
20001
+ foldedBy: null,
20002
+ noFile: false,
20003
+ candidates: 0,
20004
+ kindVetoed: 0,
20005
+ bestJaccard: 0,
20006
+ bestHashCos: 0,
20007
+ nominate: null
20008
+ };
20009
+ SAME_ANCHOR_SCOUT_AUTO_COSINE = 0.85;
20010
+ SAME_ANCHOR_SCOUT_MIN_COSINE = 0.5;
20011
+ SAME_ANCHOR_NOMINATE_JACCARD = 0.3;
19954
20012
  REOPEN_MIN_SOURCES = 2;
19955
20013
  RECURRENCE_SOURCES_CAP = 8;
19956
20014
  CITABLE_PRIOR_LABELS = /* @__PURE__ */ new Set([
@@ -22195,6 +22253,160 @@ var init_community2 = __esm({
22195
22253
  }
22196
22254
  });
22197
22255
 
22256
+ // ../../packages/local-graph/src/fold-candidates.ts
22257
+ function markFoldCandidate(store, problemId, targetId, info2) {
22258
+ if (problemId === targetId) return false;
22259
+ const n = store.getNode(problemId);
22260
+ if (!openProblem(n)) return false;
22261
+ if (n.attrs["foldCandidate"] !== void 0) return false;
22262
+ const rejected = n.attrs["foldRejected"] ?? [];
22263
+ if (rejected.includes(targetId)) return false;
22264
+ if (!openProblem(store.getNode(targetId))) return false;
22265
+ const mark = {
22266
+ targetId,
22267
+ ...info2.hashCos !== void 0 ? { hashCos: info2.hashCos } : {},
22268
+ ...info2.jaccard !== void 0 ? { jaccard: info2.jaccard } : {},
22269
+ source: info2.source,
22270
+ ts: info2.ts,
22271
+ markedAtSeq: store.currentIngestSeq()
22272
+ };
22273
+ store.updateNode(problemId, { attrs: { ...n.attrs, foldCandidate: mark }, lastUpdatedAt: info2.ts });
22274
+ return true;
22275
+ }
22276
+ function findWorkspaceFoldCandidate(store, workspaceId2, statement, kind, opts) {
22277
+ const stmtVec = embed(statement);
22278
+ const wantConstraint = kind === "constraint";
22279
+ const open2 = store.findNodesByLabel("Problem").filter(
22280
+ (p) => p.attrs["resolvedAt"] == null && p.attrs["mergedInto"] === void 0 && p.id !== opts?.excludeId && (p.attrs["workspaceId"] === void 0 || p.attrs["workspaceId"] === workspaceId2) && isConstraintProblem(p) === wantConstraint
22281
+ ).sort((a, b) => (b.lastUpdatedAt ?? b.createdAt) - (a.lastUpdatedAt ?? a.createdAt)).slice(0, opts?.scanCap ?? WORKSPACE_SCAN_CAP);
22282
+ let best = null;
22283
+ for (const p of open2) {
22284
+ const c = cosine(stmtVec, embed(p.description));
22285
+ if (c >= FOLD_SCOUT_MIN_COSINE && (!best || c > best.hashCos)) best = { targetId: p.id, hashCos: c };
22286
+ }
22287
+ return best;
22288
+ }
22289
+ function followMerges(store, id) {
22290
+ let cur = store.getNode(id);
22291
+ for (let hop = 0; hop < 3 && cur && cur.attrs["mergedInto"] !== void 0; hop++) {
22292
+ cur = store.getNode(String(cur.attrs["mergedInto"]));
22293
+ }
22294
+ return cur ?? null;
22295
+ }
22296
+ function clearCandidate(store, node2, ts, rejectTargetId) {
22297
+ const attrs = { ...node2.attrs };
22298
+ delete attrs["foldCandidate"];
22299
+ if (rejectTargetId) {
22300
+ const rejected = attrs["foldRejected"] ?? [];
22301
+ if (!rejected.includes(rejectTargetId)) {
22302
+ attrs["foldRejected"] = [...rejected, rejectTargetId].slice(-FOLD_REJECTED_CAP);
22303
+ }
22304
+ }
22305
+ store.updateNode(node2.id, { attrs, lastUpdatedAt: ts });
22306
+ }
22307
+ async function resolveFoldCandidates(store, opts) {
22308
+ const report = {
22309
+ examined: 0,
22310
+ folded: 0,
22311
+ foldedEmbedding: 0,
22312
+ foldedJudge: 0,
22313
+ rejected: 0,
22314
+ standing: 0,
22315
+ judgeErrors: 0,
22316
+ retargeted: 0
22317
+ };
22318
+ const limit = opts.limit ?? 8;
22319
+ const marked = store.findNodesByLabel("Problem").filter((p) => openProblem(p) && p.attrs["foldCandidate"] !== void 0).sort((a, b) => {
22320
+ const ma = a.attrs["foldCandidate"].ts ?? 0;
22321
+ const mb = b.attrs["foldCandidate"].ts ?? 0;
22322
+ return ma - mb;
22323
+ }).slice(0, limit);
22324
+ for (const node2 of marked) {
22325
+ const fresh = store.getNode(node2.id);
22326
+ if (!openProblem(fresh)) continue;
22327
+ report.examined++;
22328
+ const mark = fresh.attrs["foldCandidate"];
22329
+ let target = followMerges(store, mark.targetId);
22330
+ if (target && target.id !== mark.targetId) report.retargeted++;
22331
+ if (!openProblem(target)) {
22332
+ clearCandidate(store, fresh, opts.ts);
22333
+ report.rejected++;
22334
+ continue;
22335
+ }
22336
+ if (isConstraintProblem(fresh) !== isConstraintProblem(target)) {
22337
+ clearCandidate(store, fresh, opts.ts, target.id);
22338
+ report.rejected++;
22339
+ continue;
22340
+ }
22341
+ let cos = null;
22342
+ if (fresh.embedding.length > 0 && fresh.embedding.length === target.embedding.length && (fresh.attrs["embeddingVersion"] ?? "") === (target.attrs["embeddingVersion"] ?? "")) {
22343
+ cos = cosine(fresh.embedding, target.embedding);
22344
+ }
22345
+ if (cos !== null && cos >= FOLD_EMBED_AUTO_COSINE) {
22346
+ foldPair(store, fresh, target, opts.ts);
22347
+ report.folded++;
22348
+ report.foldedEmbedding++;
22349
+ continue;
22350
+ }
22351
+ if (cos !== null && cos < FOLD_JUDGE_MIN_COSINE) {
22352
+ clearCandidate(store, fresh, opts.ts, target.id);
22353
+ report.rejected++;
22354
+ continue;
22355
+ }
22356
+ if (!opts.judge) {
22357
+ report.standing++;
22358
+ continue;
22359
+ }
22360
+ let verdict = null;
22361
+ try {
22362
+ verdict = await opts.judge(fresh.description, target.description);
22363
+ } catch {
22364
+ verdict = null;
22365
+ }
22366
+ if (verdict === "same") {
22367
+ foldPair(store, fresh, target, opts.ts);
22368
+ report.folded++;
22369
+ report.foldedJudge++;
22370
+ } else if (verdict === "distinct") {
22371
+ clearCandidate(store, fresh, opts.ts, target.id);
22372
+ report.rejected++;
22373
+ } else {
22374
+ report.judgeErrors++;
22375
+ report.standing++;
22376
+ }
22377
+ }
22378
+ return report;
22379
+ }
22380
+ function foldPair(store, a, b, ts) {
22381
+ const corro = (n) => Number(n.attrs["corroborations"] ?? 0);
22382
+ const survivor = corro(a) !== corro(b) ? corro(a) > corro(b) ? a : b : a.createdAt <= b.createdAt ? a : b;
22383
+ const dup = survivor === a ? b : a;
22384
+ for (const n of [a, b]) {
22385
+ if (n.attrs["foldCandidate"] !== void 0) clearCandidate(store, n, ts);
22386
+ }
22387
+ const freshSurvivor = store.getNode(survivor.id);
22388
+ const freshDup = store.getNode(dup.id);
22389
+ if (!freshSurvivor || !freshDup) return;
22390
+ foldDuplicateProblem(store, freshDup, freshSurvivor, ts);
22391
+ }
22392
+ var FOLD_SCOUT_AUTO_COSINE, FOLD_SCOUT_MIN_COSINE, FOLD_SCOUT_MIN_JACCARD, FOLD_EMBED_AUTO_COSINE, FOLD_JUDGE_MIN_COSINE, FOLD_REJECTED_CAP, WORKSPACE_SCAN_CAP, openProblem;
22393
+ var init_fold_candidates = __esm({
22394
+ "../../packages/local-graph/src/fold-candidates.ts"() {
22395
+ "use strict";
22396
+ init_src3();
22397
+ init_design_problem();
22398
+ init_problem_dedup();
22399
+ FOLD_SCOUT_AUTO_COSINE = 0.85;
22400
+ FOLD_SCOUT_MIN_COSINE = 0.5;
22401
+ FOLD_SCOUT_MIN_JACCARD = 0.3;
22402
+ FOLD_EMBED_AUTO_COSINE = 0.88;
22403
+ FOLD_JUDGE_MIN_COSINE = 0.5;
22404
+ FOLD_REJECTED_CAP = 8;
22405
+ WORKSPACE_SCAN_CAP = 400;
22406
+ openProblem = (n) => !!n && n.label === "Problem" && n.attrs["resolvedAt"] == null && n.attrs["mergedInto"] === void 0;
22407
+ }
22408
+ });
22409
+
22198
22410
  // ../../packages/local-graph/src/tools.ts
22199
22411
  function toolNodeId(name2) {
22200
22412
  return `tool:${name2}`;
@@ -22649,6 +22861,32 @@ var init_mechanism_liveness = __esm({
22649
22861
  backlogCounter: "anchorHintsStanding",
22650
22862
  note: "drains as hinted files change; contentChangedAt is forward-only so the backlog moves with real edits"
22651
22863
  },
22864
+ {
22865
+ id: "fold-candidate-resolve",
22866
+ what: "resolves parked paraphrase-fold nominations (embedding-certain bands auto, ambiguous band via the equivalence judge)",
22867
+ // The settle boundary's fold-judge pass is the sole consumer of
22868
+ // attrs.foldCandidate; producers are the file/workspace scouts (capture)
22869
+ // and the settle near-miss band (mergeProblemsByEmbedding).
22870
+ pass: "fold-judge",
22871
+ // Conditional mark, rare by design (a nomination is a near-miss event) —
22872
+ // the bar is "the field is written at all", the revisit-sweep precedent.
22873
+ fed: { labels: ["Problem"], attr: "foldCandidate", minFraction: 0 },
22874
+ effectCounter: "folded",
22875
+ // Standing nominations ARE the judge-less backlog — without the gauge a
22876
+ // deployment with no judge configured reads as "nothing to fold".
22877
+ backlogCounter: "standing",
22878
+ note: "standing > 0 with folded 0 = the judge lane is unconfigured (ERRATA_FOLD_JUDGE / azure env), not an empty queue"
22879
+ },
22880
+ {
22881
+ id: "cite-anchor-accrual",
22882
+ what: "accrues cite-context anchor evidence on anchorless cited priors; two distinct sessions promote a cite-confirmed ANCHORED_AT",
22883
+ pass: "capture",
22884
+ // Conditional attr: only anchorless semantic priors cited from a known
22885
+ // working file carry hints — "written at all" is the honest floor.
22886
+ fed: { labels: ["Problem"], attr: "citeAnchorHints", minFraction: 0 },
22887
+ effectCounter: "citeAnchorsPromoted",
22888
+ note: "the supply-side fix for corroboration 0-for-8: promoted anchors are what the overlap gate intersects on the NEXT citation"
22889
+ },
22652
22890
  {
22653
22891
  id: "wm-reinforce-exposure",
22654
22892
  what: "labels each paraphrase re-derivation with the prior's exposure (shown/evicted/unshown)",
@@ -22769,6 +23007,12 @@ __export(src_exports2, {
22769
23007
  CREDIT_FAMILY: () => CREDIT_FAMILY,
22770
23008
  DEFAULT_MIN_COVERAGE: () => DEFAULT_MIN_COVERAGE,
22771
23009
  FIX_CANDIDATE_ASK_LIMIT: () => FIX_CANDIDATE_ASK_LIMIT,
23010
+ FOLD_EMBED_AUTO_COSINE: () => FOLD_EMBED_AUTO_COSINE,
23011
+ FOLD_JUDGE_MIN_COSINE: () => FOLD_JUDGE_MIN_COSINE,
23012
+ FOLD_REJECTED_CAP: () => FOLD_REJECTED_CAP,
23013
+ FOLD_SCOUT_AUTO_COSINE: () => FOLD_SCOUT_AUTO_COSINE,
23014
+ FOLD_SCOUT_MIN_COSINE: () => FOLD_SCOUT_MIN_COSINE,
23015
+ FOLD_SCOUT_MIN_JACCARD: () => FOLD_SCOUT_MIN_JACCARD,
22772
23016
  JOINT_COMMUNITY_EDGES: () => JOINT_COMMUNITY_EDGES,
22773
23017
  JOINT_COMMUNITY_LABELS: () => JOINT_COMMUNITY_LABELS,
22774
23018
  MAX_ANCHOR_FILES: () => MAX_ANCHOR_FILES,
@@ -22781,10 +23025,14 @@ __export(src_exports2, {
22781
23025
  RECURRENCE_DEBOUNCE_MS: () => RECURRENCE_DEBOUNCE_MS,
22782
23026
  REOPEN_MIN_SOURCES: () => REOPEN_MIN_SOURCES,
22783
23027
  SAME_ANCHOR_DEDUP_JACCARD: () => SAME_ANCHOR_DEDUP_JACCARD,
23028
+ SAME_ANCHOR_NOMINATE_JACCARD: () => SAME_ANCHOR_NOMINATE_JACCARD,
23029
+ SAME_ANCHOR_SCOUT_AUTO_COSINE: () => SAME_ANCHOR_SCOUT_AUTO_COSINE,
23030
+ SAME_ANCHOR_SCOUT_MIN_COSINE: () => SAME_ANCHOR_SCOUT_MIN_COSINE,
22784
23031
  STALL_MIN_RUNS: () => STALL_MIN_RUNS,
22785
23032
  STALL_MIN_SPAN_MS: () => STALL_MIN_SPAN_MS,
22786
23033
  SqliteGraphStore: () => SqliteGraphStore,
22787
23034
  WM_CALIBRATION_LABELS: () => WM_CALIBRATION_LABELS,
23035
+ WORKSPACE_SCAN_CAP: () => WORKSPACE_SCAN_CAP,
22788
23036
  addDependency: () => addDependency,
22789
23037
  aggregateClaimConfidence: () => aggregateClaimConfidence,
22790
23038
  anchorProblemToDiff: () => anchorProblemToDiff,
@@ -22825,8 +23073,10 @@ __export(src_exports2, {
22825
23073
  findPath: () => findPath,
22826
23074
  findResolvedAnchorMatch: () => findResolvedAnchorMatch,
22827
23075
  findReusableSolution: () => findReusableSolution,
23076
+ findWorkspaceFoldCandidate: () => findWorkspaceFoldCandidate,
22828
23077
  flattenCloudCounts: () => flattenCloudCounts,
22829
23078
  foldDuplicateProblem: () => foldDuplicateProblem,
23079
+ foldSameAnchorProblem: () => foldSameAnchorProblem,
22830
23080
  formatMechanismStatus: () => formatMechanismStatus,
22831
23081
  getClaim: () => getClaim,
22832
23082
  harvestAbstractionFences: () => harvestAbstractionFences,
@@ -22846,6 +23096,7 @@ __export(src_exports2, {
22846
23096
  localEdgeViolation: () => localEdgeViolation,
22847
23097
  markDiscriminatorAsked: () => markDiscriminatorAsked,
22848
23098
  markFixCandidates: () => markFixCandidates,
23099
+ markFoldCandidate: () => markFoldCandidate,
22849
23100
  markResolvedRecurrence: () => markResolvedRecurrence,
22850
23101
  markRevisit: () => markRevisit,
22851
23102
  matchLanguagesInText: () => matchLanguagesInText,
@@ -22887,6 +23138,7 @@ __export(src_exports2, {
22887
23138
  repairLegacyAnchorsFromStatement: () => repairLegacyAnchorsFromStatement,
22888
23139
  resolveDesignProblemById: () => resolveDesignProblemById,
22889
23140
  resolveDesignProblemByStatement: () => resolveDesignProblemByStatement,
23141
+ resolveFoldCandidates: () => resolveFoldCandidates,
22890
23142
  resolveOsNode: () => resolveOsNode,
22891
23143
  retractDesignProblemById: () => retractDesignProblemById,
22892
23144
  retractDesignProblemByStatement: () => retractDesignProblemByStatement,
@@ -22925,6 +23177,7 @@ var init_src5 = __esm({
22925
23177
  init_community2();
22926
23178
  init_triage2();
22927
23179
  init_problem_dedup();
23180
+ init_fold_candidates();
22928
23181
  init_problem_package_link();
22929
23182
  init_tools();
22930
23183
  init_principle_sync();
@@ -24079,7 +24332,7 @@ function provenanceHeaders(provenance) {
24079
24332
  ...provenance.agentModel ? { "x-inerrata-agent-model": provenance.agentModel } : {}
24080
24333
  };
24081
24334
  }
24082
- var asWireCount, INGEST_NODE_CHUNK, CloudClient, CloudError;
24335
+ var asWireCount, INGEST_NODE_CHUNK, E6B_PUBLIC_CONTEXT_SENTINEL, CloudClient, CloudError;
24083
24336
  var init_client = __esm({
24084
24337
  "../../packages/cloud-client/src/client.ts"() {
24085
24338
  "use strict";
@@ -24087,6 +24340,7 @@ var init_client = __esm({
24087
24340
  init_src();
24088
24341
  asWireCount = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0 ? Math.floor(n) : null;
24089
24342
  INGEST_NODE_CHUNK = 8;
24343
+ E6B_PUBLIC_CONTEXT_SENTINEL = "00000000-0000-4e6b-8000-000000000e6b";
24090
24344
  CloudClient = class {
24091
24345
  baseUrl;
24092
24346
  apiKey;
@@ -24478,7 +24732,19 @@ var init_client = __esm({
24478
24732
  if (q.seed?.length) qs.set("seed", q.seed.join(","));
24479
24733
  if (q.q) qs.set("q", q.q);
24480
24734
  if (q.channel) qs.set("channel", q.channel);
24481
- const res = await this.json("GET", `/v2/search?${qs.toString()}`);
24735
+ const publicCtx = process.env["ERRATA_PRIMING_PUBLIC_CONTEXT"];
24736
+ const usePublicCtx = Boolean(publicCtx && publicCtx !== "0" && q.channel === "priming");
24737
+ const UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
24738
+ const res = await this.json(
24739
+ "GET",
24740
+ `/v2/search?${qs.toString()}`,
24741
+ void 0,
24742
+ usePublicCtx ? {
24743
+ extraHeaders: {
24744
+ "X-Inerrata-Project-Id": UUID_RE2.test(publicCtx) ? publicCtx : E6B_PUBLIC_CONTEXT_SENTINEL
24745
+ }
24746
+ } : void 0
24747
+ );
24482
24748
  const { nodes, edges } = this.toCastalia(res);
24483
24749
  return {
24484
24750
  nodes,
@@ -24642,7 +24908,8 @@ var init_client = __esm({
24642
24908
  const headers = {
24643
24909
  "content-type": "application/json",
24644
24910
  accept: "application/json",
24645
- ...provenanceHeaders(this.provenance)
24911
+ ...provenanceHeaders(this.provenance),
24912
+ ...opts?.extraHeaders ?? {}
24646
24913
  };
24647
24914
  if (!opts?.skipAuth) {
24648
24915
  const token = opts?.bearerToken ?? await this.authToken();
@@ -29565,7 +29832,8 @@ function rankOpenProblemNeighbors(store, embedding, limit = 5) {
29565
29832
  }
29566
29833
  function mergeProblemsByEmbedding(store, opts) {
29567
29834
  const minCosine = opts.minCosine ?? NEMORI_DEDUP_COSINE;
29568
- const report = { clusters: 0, merged: 0 };
29835
+ const NEAR_MISS_FLOOR = 0.72;
29836
+ const report = { clusters: 0, merged: 0, nearMissMarked: 0 };
29569
29837
  const open2 = store.findNodesByLabel("Problem").filter(
29570
29838
  (p) => p.attrs["resolvedAt"] == null && p.attrs["mergedInto"] === void 0 && p.embedding.length > 0
29571
29839
  );
@@ -29580,9 +29848,15 @@ function mergeProblemsByEmbedding(store, opts) {
29580
29848
  if (b.embedding.length !== a.embedding.length) continue;
29581
29849
  if ((a.attrs["embeddingVersion"] ?? "") !== (b.attrs["embeddingVersion"] ?? "")) continue;
29582
29850
  if (isConstraintProblem(a) !== isConstraintProblem(b)) continue;
29583
- if (cosine(a.embedding, b.embedding) >= minCosine) {
29851
+ const cos = cosine(a.embedding, b.embedding);
29852
+ if (cos >= minCosine) {
29584
29853
  cluster.push(b);
29585
29854
  consumed.add(b.id);
29855
+ } else if (cos >= NEAR_MISS_FLOOR) {
29856
+ const [younger, elder] = a.createdAt >= b.createdAt ? [a, b] : [b, a];
29857
+ if (markFoldCandidate(store, younger.id, elder.id, { hashCos: cos, source: "settle-nearmiss", ts: opts.ts })) {
29858
+ report.nearMissMarked = (report.nearMissMarked ?? 0) + 1;
29859
+ }
29586
29860
  }
29587
29861
  }
29588
29862
  if (cluster.length < 2) continue;
@@ -53242,6 +53516,91 @@ function openEventLog(opts) {
53242
53516
  return new EventLog(opts);
53243
53517
  }
53244
53518
 
53519
+ // src/llm-provider.ts
53520
+ function chatProvider() {
53521
+ return (process.env["EXTRACTION_PROVIDER"] ?? "azure").toLowerCase() === "anthropic" ? "anthropic" : "azure";
53522
+ }
53523
+ function deploymentFor(model) {
53524
+ const key = `MODEL_${model.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_OPENAI`;
53525
+ return process.env[key] ?? process.env["AZURE_OPENAI_DEPLOYMENT"];
53526
+ }
53527
+ function isChatConfigured(model) {
53528
+ if (chatProvider() === "azure") {
53529
+ return Boolean(
53530
+ process.env["AZURE_OPENAI_API_KEY"] && process.env["AZURE_OPENAI_ENDPOINT"] && deploymentFor(model)
53531
+ );
53532
+ }
53533
+ return Boolean(process.env["ANTHROPIC_API_KEY"]);
53534
+ }
53535
+ async function chat(req) {
53536
+ const provider = chatProvider();
53537
+ try {
53538
+ if (provider === "azure") {
53539
+ const endpoint = (process.env["AZURE_OPENAI_ENDPOINT"] ?? "").replace(/\/+$/, "");
53540
+ const version2 = process.env["AZURE_OPENAI_API_VERSION"] ?? "2024-10-21";
53541
+ const deployment = deploymentFor(req.model);
53542
+ if (!endpoint || !deployment) {
53543
+ console.warn("[errata] llm: azure selected but endpoint/deployment missing \u2014 skipping");
53544
+ return null;
53545
+ }
53546
+ const resp2 = await fetch(
53547
+ `${endpoint}/openai/deployments/${deployment}/chat/completions?api-version=${version2}`,
53548
+ {
53549
+ method: "POST",
53550
+ headers: {
53551
+ "api-key": process.env["AZURE_OPENAI_API_KEY"] ?? "",
53552
+ "content-type": "application/json"
53553
+ },
53554
+ body: JSON.stringify({
53555
+ messages: [
53556
+ ...req.system ? [{ role: "system", content: req.system }] : [],
53557
+ { role: "user", content: req.user }
53558
+ ],
53559
+ // `max_completion_tokens`: the newer deployments reject `max_tokens`.
53560
+ max_completion_tokens: req.maxTokens
53561
+ })
53562
+ }
53563
+ );
53564
+ if (!resp2.ok) {
53565
+ console.warn(
53566
+ `[errata] llm: azure ${resp2.status} \u2014 ${(await resp2.text().catch(() => "")).slice(0, 200)}`
53567
+ );
53568
+ return null;
53569
+ }
53570
+ const json3 = await resp2.json();
53571
+ return json3.choices?.[0]?.message?.content ?? null;
53572
+ }
53573
+ const resp = await fetch("https://api.anthropic.com/v1/messages", {
53574
+ method: "POST",
53575
+ headers: {
53576
+ "x-api-key": process.env["ANTHROPIC_API_KEY"] ?? "",
53577
+ "anthropic-version": "2023-06-01",
53578
+ "content-type": "application/json"
53579
+ },
53580
+ body: JSON.stringify({
53581
+ model: req.model,
53582
+ max_tokens: req.maxTokens,
53583
+ ...req.system ? { system: req.system } : {},
53584
+ messages: [{ role: "user", content: req.user }]
53585
+ })
53586
+ });
53587
+ if (!resp.ok) {
53588
+ console.warn(
53589
+ `[errata] llm: anthropic ${resp.status} \u2014 ${(await resp.text().catch(() => "")).slice(0, 200)}`
53590
+ );
53591
+ return null;
53592
+ }
53593
+ const json2 = await resp.json();
53594
+ return json2.content?.find((c) => c.type === "text")?.text ?? null;
53595
+ } catch (err2) {
53596
+ console.warn(
53597
+ `[errata] llm: ${provider} transport failed \u2014`,
53598
+ err2 instanceof Error ? err2.message : err2
53599
+ );
53600
+ return null;
53601
+ }
53602
+ }
53603
+
53245
53604
  // src/engine.ts
53246
53605
  init_src11();
53247
53606
  init_src6();
@@ -54464,7 +54823,52 @@ function readPrimingHandles(path2) {
54464
54823
  function resolveHandle(store, handle2, handleMap) {
54465
54824
  return handleMap[handle2]?.id ?? (store.getNode(handle2) ? handle2 : void 0);
54466
54825
  }
54467
- function mintPriorEdge(store, source, target, sentence, touched, ts) {
54826
+ var CITE_ANCHOR_LABELS = /* @__PURE__ */ new Set(["Problem", "Solution", "RootCause", "Pattern", "Claim", "Technique", "AntiPattern"]);
54827
+ var CITE_ANCHOR_PROMOTE_SESSIONS = 2;
54828
+ var CITE_ANCHOR_MAX_FILES = 4;
54829
+ var CITE_ANCHOR_MAX_SESSIONS = 6;
54830
+ function accrueCiteAnchor(store, targetId, touched, sessionId, ts) {
54831
+ let fileId;
54832
+ for (const tid of touched) {
54833
+ if (store.getNode(tid)?.label === "File") {
54834
+ fileId = tid;
54835
+ break;
54836
+ }
54837
+ }
54838
+ if (!fileId) return { accrued: false, promoted: false };
54839
+ const node2 = store.getNode(targetId);
54840
+ if (!node2) return { accrued: false, promoted: false };
54841
+ const hints = { ...node2.attrs["citeAnchorHints"] ?? {} };
54842
+ const entry = hints[fileId] ?? [];
54843
+ if (entry.includes(sessionId)) return { accrued: false, promoted: false };
54844
+ if (hints[fileId] === void 0 && Object.keys(hints).length >= CITE_ANCHOR_MAX_FILES) {
54845
+ return { accrued: false, promoted: false };
54846
+ }
54847
+ const grown = [...entry, sessionId].slice(-CITE_ANCHOR_MAX_SESSIONS);
54848
+ let promoted = false;
54849
+ if (grown.length >= CITE_ANCHOR_PROMOTE_SESSIONS) {
54850
+ store.mergeEdge({
54851
+ id: `edge_${digest({ from: targetId, type: "ANCHORED_AT", to: fileId })}`.slice(0, 24),
54852
+ from: targetId,
54853
+ to: fileId,
54854
+ type: "ANCHORED_AT",
54855
+ confidence: 0.3,
54856
+ extractionSource: "agent-observed",
54857
+ createdAt: ts,
54858
+ lastSeenAt: ts,
54859
+ navSuccesses: 0,
54860
+ navFailures: 0,
54861
+ attrs: { provisional: true, captureTime: true, anchorProvenance: "cite-confirmed", citeSessions: grown }
54862
+ });
54863
+ delete hints[fileId];
54864
+ promoted = true;
54865
+ } else {
54866
+ hints[fileId] = grown;
54867
+ }
54868
+ store.updateNode(targetId, { attrs: { ...node2.attrs, citeAnchorHints: hints }, lastUpdatedAt: ts });
54869
+ return { accrued: true, promoted };
54870
+ }
54871
+ function mintPriorEdge(store, source, target, sentence, touched, ts, sessionId) {
54468
54872
  if (target.id === source.id) return false;
54469
54873
  const type = typePriorEdge(source.label, target.label, sentence);
54470
54874
  const anchorIds = new Set(
@@ -54508,13 +54912,24 @@ function mintPriorEdge(store, source, target, sentence, touched, ts) {
54508
54912
  } catch {
54509
54913
  }
54510
54914
  }
54511
- return { corroborated };
54915
+ let citeAnchorAccrued = false;
54916
+ let citeAnchorPromoted = false;
54917
+ if (!corroborated && sessionId && CITE_ANCHOR_LABELS.has(target.label)) {
54918
+ try {
54919
+ const acc = accrueCiteAnchor(store, target.id, touched, sessionId, ts);
54920
+ citeAnchorAccrued = acc.accrued;
54921
+ citeAnchorPromoted = acc.promoted;
54922
+ } catch (err2) {
54923
+ console.warn("[errata] cite-anchor accrual failed (citation kept):", err2 instanceof Error ? err2.message : err2);
54924
+ }
54925
+ }
54926
+ return { corroborated, citeAnchorAccrued, citeAnchorPromoted };
54512
54927
  }
54513
54928
  function harvestInlineTags(store, text, opts) {
54514
54929
  const source = opts.sourceId ? store.getNode(opts.sourceId) : null;
54515
54930
  const mintPriors = opts.mintPriors ?? true;
54516
54931
  const touched = opts.sessionTouchedIds ?? /* @__PURE__ */ new Set();
54517
- 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: [] };
54932
+ const plan = { priorEdges: 0, corroboratedEdges: 0, citeAnchorsAccrued: 0, citeAnchorsPromoted: 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: [] };
54518
54933
  const parsed = parseInlineTagsWithDispositions(text);
54519
54934
  const tags = parsed.tags;
54520
54935
  plan.dispositions = parsed.dispositions;
@@ -54742,10 +55157,12 @@ function harvestInlineTags(store, text, opts) {
54742
55157
  }
54743
55158
  }
54744
55159
  if (mintPriors && source && target) {
54745
- const m = mintPriorEdge(store, source, target, tag.sentence, touched, opts.ts);
55160
+ const m = mintPriorEdge(store, source, target, tag.sentence, touched, opts.ts, opts.sessionId);
54746
55161
  if (m) {
54747
55162
  plan.priorEdges++;
54748
55163
  if (m.corroborated) plan.corroboratedEdges++;
55164
+ if (m.citeAnchorAccrued) plan.citeAnchorsAccrued++;
55165
+ if (m.citeAnchorPromoted) plan.citeAnchorsPromoted++;
54749
55166
  }
54750
55167
  } else if (target) {
54751
55168
  if (!mintPriors) plan.priorEdgesSuppressed.flagOff++;
@@ -54755,10 +55172,12 @@ function harvestInlineTags(store, text, opts) {
54755
55172
  const targetId = resolveCited(tag.kind, tag.handle);
54756
55173
  const target = targetId ? store.getNode(targetId) : null;
54757
55174
  if (target) {
54758
- const m = mintPriorEdge(store, source, target, tag.sentence, touched, opts.ts);
55175
+ const m = mintPriorEdge(store, source, target, tag.sentence, touched, opts.ts, opts.sessionId);
54759
55176
  if (m) {
54760
55177
  plan.priorEdges++;
54761
55178
  if (m.corroborated) plan.corroboratedEdges++;
55179
+ if (m.citeAnchorAccrued) plan.citeAnchorsAccrued++;
55180
+ if (m.citeAnchorPromoted) plan.citeAnchorsPromoted++;
54762
55181
  }
54763
55182
  }
54764
55183
  } else if (tag.handle) {
@@ -57309,7 +57728,7 @@ function createWatchBreaker(deps) {
57309
57728
  }
57310
57729
 
57311
57730
  // src/engine.ts
57312
- var DAEMON_VERSION = true ? "2.0.2-dev.1255" : "2.0.0-alpha.0";
57731
+ var DAEMON_VERSION = true ? "2.0.2-dev.1274" : "2.0.0-alpha.0";
57313
57732
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
57314
57733
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
57315
57734
  var GIT_OP_MUTE_MS = 4e3;
@@ -58155,6 +58574,17 @@ function createWorkspaceEngine(opts) {
58155
58574
  let touchedFileTurns = 0;
58156
58575
  let touchedToolTurns = 0;
58157
58576
  let anchorHintsUpgraded = 0;
58577
+ let foldAttempts = 0;
58578
+ let foldNoFile = 0;
58579
+ let foldNoCandidates = 0;
58580
+ let foldKindVeto = 0;
58581
+ let foldJaccardHit = 0;
58582
+ let foldScoutHit = 0;
58583
+ let foldNearMiss30 = 0;
58584
+ let foldNearMiss45 = 0;
58585
+ let foldCandidatesMarked = 0;
58586
+ let citeAnchorsAccrued = 0;
58587
+ let citeAnchorsPromoted = 0;
58158
58588
  let linked = 0;
58159
58589
  const t = Date.now();
58160
58590
  let processedTurns = 0;
@@ -58298,10 +58728,16 @@ function createWorkspaceEngine(opts) {
58298
58728
  handleMap,
58299
58729
  ts: t,
58300
58730
  mintPriors: elicit,
58731
+ // WM-fold phase 3: cite-time anchor accrual keys on the session — two
58732
+ // DISTINCT sessions co-citing a prior from the same file promote a
58733
+ // real anchor; one session, or none, accrues silently.
58734
+ sessionId,
58301
58735
  ...touched.size > 0 ? { sessionTouchedIds: touched } : {}
58302
58736
  });
58303
58737
  priorEdges += plan.priorEdges;
58304
58738
  corroboratedEdges += plan.corroboratedEdges;
58739
+ citeAnchorsAccrued += plan.citeAnchorsAccrued;
58740
+ citeAnchorsPromoted += plan.citeAnchorsPromoted;
58305
58741
  const refuteResult = applyLocalRefutations(store, plan.refutes, t);
58306
58742
  refutesStamped += refuteResult.stamped;
58307
58743
  for (const c of plan.corroborations) {
@@ -58347,21 +58783,43 @@ function createWorkspaceEngine(opts) {
58347
58783
  const anchorProvenance = p.location?.path ? "witnessed" : "edited";
58348
58784
  const hintPath = anchorPath ? void 0 : turnFile ?? wf;
58349
58785
  const dedupPath = anchorPath ?? hintPath;
58786
+ let pendingNomination = null;
58350
58787
  if (dedupPath) {
58351
58788
  try {
58352
- const dupId = reinforceSameAnchorProblem(store, dedupPath, profile.id, p.statement, sessionId, t, p.kind);
58353
- if (dupId) {
58789
+ foldAttempts++;
58790
+ const fold = foldSameAnchorProblem(store, dedupPath, profile.id, p.statement, sessionId, t, p.kind);
58791
+ if (fold.noFile) foldNoFile++;
58792
+ else if (fold.candidates === 0) foldNoCandidates++;
58793
+ foldKindVeto += fold.kindVetoed;
58794
+ if (!fold.foldedId) {
58795
+ if (fold.bestJaccard >= 0.45) foldNearMiss45++;
58796
+ else if (fold.bestJaccard >= 0.3) foldNearMiss30++;
58797
+ if (fold.nominate) {
58798
+ pendingNomination = { ...fold.nominate, source: "file-scout" };
58799
+ }
58800
+ }
58801
+ if (fold.foldedId) {
58802
+ if (fold.foldedBy === "scout") foldScoutHit++;
58803
+ else foldJaccardHit++;
58354
58804
  minted++;
58355
58805
  if (p.kind !== "constraint") {
58356
- sessionLastProblem.set(sessionId, dupId);
58357
- inScopeProblemId = dupId;
58806
+ sessionLastProblem.set(sessionId, fold.foldedId);
58807
+ inScopeProblemId = fold.foldedId;
58358
58808
  }
58359
- if (p.threadId) threads.set(p.threadId, dupId);
58809
+ if (p.threadId) threads.set(p.threadId, fold.foldedId);
58360
58810
  continue;
58361
58811
  }
58362
58812
  } catch {
58363
58813
  }
58364
58814
  }
58815
+ if (!pendingNomination) {
58816
+ try {
58817
+ const ws = findWorkspaceFoldCandidate(store, profile.id, p.statement, p.kind);
58818
+ if (ws) pendingNomination = { ...ws, source: "workspace-scout" };
58819
+ } catch (err2) {
58820
+ console.warn("[errata] workspace fold scout failed (mint unaffected):", err2 instanceof Error ? err2.message : err2);
58821
+ }
58822
+ }
58365
58823
  const r = ingestDesignProblem(store, { problem: p.statement, kind: p.kind }, {
58366
58824
  workspaceId: profile.id,
58367
58825
  source: sessionId,
@@ -58399,6 +58857,19 @@ function createWorkspaceEngine(opts) {
58399
58857
  );
58400
58858
  }
58401
58859
  }
58860
+ if (r.created && pendingNomination) {
58861
+ try {
58862
+ const marked = markFoldCandidate(store, r.problemId, pendingNomination.targetId, {
58863
+ ...pendingNomination.hashCos !== void 0 ? { hashCos: pendingNomination.hashCos } : {},
58864
+ ...pendingNomination.jaccard !== void 0 ? { jaccard: pendingNomination.jaccard } : {},
58865
+ source: pendingNomination.source,
58866
+ ts: t
58867
+ });
58868
+ if (marked) foldCandidatesMarked++;
58869
+ } catch (err2) {
58870
+ console.warn("[errata] fold nomination failed (mint unaffected):", err2 instanceof Error ? err2.message : err2);
58871
+ }
58872
+ }
58402
58873
  if (r.created || r.corroborated) {
58403
58874
  minted++;
58404
58875
  if (p.kind !== "constraint") {
@@ -58820,6 +59291,20 @@ function createWorkspaceEngine(opts) {
58820
59291
  exposureOutcomes: exposureShown + exposureEvicted + exposureUnshown,
58821
59292
  // AC-hint-upgrade (harvest seam): edited-this-turn hint promotions.
58822
59293
  anchorHintsUpgraded,
59294
+ // WM-fold funnel (phase 0) — which gate of the same-anchor fold
59295
+ // conjunction eats the mass, and the near-miss bands under the bars.
59296
+ foldAttempts,
59297
+ foldNoFile,
59298
+ foldNoCandidates,
59299
+ foldKindVeto,
59300
+ foldJaccardHit,
59301
+ foldScoutHit,
59302
+ foldNearMiss30,
59303
+ foldNearMiss45,
59304
+ foldCandidatesMarked,
59305
+ // WM-fold phase 3 — cite-time anchor accrual on cited priors.
59306
+ citeAnchorsAccrued,
59307
+ citeAnchorsPromoted,
58823
59308
  touchedFileTurns,
58824
59309
  touchedToolTurns,
58825
59310
  // Seam diagnostic: sessions holding tool-run records at harvest time.
@@ -58992,6 +59477,22 @@ function createWorkspaceEngine(opts) {
58992
59477
  });
58993
59478
  };
58994
59479
  const designRollup = opts.designRollup ?? (process.env["ERRATA_ROLLUP"] === "1" ? haikuDesignRollup(process.env["ANTHROPIC_API_KEY"] ?? null) : void 0);
59480
+ const foldJudgeModel = process.env["ERRATA_FOLD_JUDGE_MODEL"] ?? "gpt-5-mini";
59481
+ const foldJudge = process.env["ERRATA_FOLD_JUDGE"] === "1" && isChatConfigured(foldJudgeModel) ? async (a, b) => {
59482
+ const out2 = await chat({
59483
+ model: foldJudgeModel,
59484
+ system: "You judge whether two independently-written one-line problem reports from the same codebase describe the SAME underlying problem. Reworded restatements of one problem are SAME; related-but-different defects, or a defect vs a design constraint, are DISTINCT. Answer with exactly one word: SAME or DISTINCT.",
59485
+ user: `A: ${a}
59486
+ B: ${b}`,
59487
+ maxTokens: 8
59488
+ });
59489
+ if (!out2) return null;
59490
+ const same = /\bSAME\b/i.test(out2);
59491
+ const distinct = /\bDISTINCT\b/i.test(out2);
59492
+ if (same && !distinct) return "same";
59493
+ if (distinct && !same) return "distinct";
59494
+ return null;
59495
+ } : void 0;
58995
59496
  const onSessionEnd = (e) => {
58996
59497
  if (!designRollup) return;
58997
59498
  setImmediate(() => {
@@ -59283,6 +59784,27 @@ function createWorkspaceEngine(opts) {
59283
59784
  console.warn(`[errata] REGRESSION: bound ${rg.bound} open problem(s) to resolved predecessors${rg.full ? " (first full sweep)" : ""}`);
59284
59785
  refreshContextNow();
59285
59786
  }
59787
+ const fjStart = Date.now();
59788
+ const fj = await resolveFoldCandidates(store, {
59789
+ ts: fjStart,
59790
+ ...foldJudge ? { judge: foldJudge } : {}
59791
+ });
59792
+ if (fj.examined > 0) {
59793
+ appendPassLedger(paths.configDir, "fold-judge", Date.now() - fjStart, {
59794
+ examined: fj.examined,
59795
+ folded: fj.folded,
59796
+ foldedEmbedding: fj.foldedEmbedding,
59797
+ foldedJudge: fj.foldedJudge,
59798
+ rejected: fj.rejected,
59799
+ standing: fj.standing,
59800
+ judgeErrors: fj.judgeErrors,
59801
+ retargeted: fj.retargeted
59802
+ });
59803
+ if (fj.folded > 0) {
59804
+ console.log(`[errata] fold-judge: folded ${fj.folded} paraphrase pair(s) (${fj.foldedEmbedding} by embedding, ${fj.foldedJudge} by judge), ${fj.standing} standing`);
59805
+ refreshContextNow();
59806
+ }
59807
+ }
59286
59808
  return { embedded: sem.embedded };
59287
59809
  } catch (err2) {
59288
59810
  console.warn("[errata] settled embed failed:", err2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.2-dev.1255",
3
+ "version": "2.0.2-dev.1274",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -25734,11 +25734,16 @@ function foldDuplicateProblem(store2, dup, survivor, ts) {
25734
25734
  if (!surv) return;
25735
25735
  const sources = new Set(surv.attrs["sources"] ?? []);
25736
25736
  for (const s of dup.attrs["sources"] ?? []) sources.add(s);
25737
+ const dupSeq = dup.attrs["createdAtSeq"] ?? store2.currentIngestSeq();
25738
+ const exposure = priorExposure(store2, survivor.id, dupSeq);
25739
+ const expField = `reinforce${exposure[0].toUpperCase()}${exposure.slice(1)}Count`;
25737
25740
  store2.updateNode(survivor.id, {
25738
25741
  attrs: {
25739
25742
  ...surv.attrs,
25740
25743
  sources: [...sources],
25741
- corroborations: corroborations(surv) + corroborations(dup) + 1
25744
+ corroborations: corroborations(surv) + corroborations(dup) + 1,
25745
+ [expField]: (surv.attrs[expField] ?? 0) + 1,
25746
+ lastReinforceExposure: exposure
25742
25747
  },
25743
25748
  cumulativeHits: (surv.cumulativeHits ?? 0) + (dup.cumulativeHits ?? 0),
25744
25749
  lastUpdatedAt: ts
@@ -25954,6 +25959,16 @@ function clearSettledFixCandidates(store2, t) {
25954
25959
  }
25955
25960
  return report;
25956
25961
  }
25962
+ function priorExposure(store2, nodeId, atSeq) {
25963
+ const n = store2.getNode(nodeId);
25964
+ if (!n || !n.attrs) return "unshown";
25965
+ const shownSeq = n.attrs["lastShownAtSeq"];
25966
+ if (shownSeq !== void 0 && shownSeq <= atSeq) return "shown";
25967
+ const evictedSeq = n.attrs["lastEvictedAtSeq"];
25968
+ if (evictedSeq !== void 0 && evictedSeq <= atSeq) return "evicted";
25969
+ if ((n.attrs["evictedCount"] ?? 0) > 0) return "evicted";
25970
+ return "unshown";
25971
+ }
25957
25972
 
25958
25973
  // ../../packages/local-graph/src/intent.ts
25959
25974
  init_src();