@inerrata-corporation/errata 2.0.0-dev.30 → 2.0.0-dev.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/errata.mjs CHANGED
@@ -20,16 +20,51 @@ function pagerankEdgeTypes() {
20
20
  (e) => !PAGERANK_EXCLUSIONS.has(e)
21
21
  );
22
22
  }
23
+ function isInferredSource(source) {
24
+ return source === "bko-inferred" || source === "cold-start-seed";
25
+ }
26
+ function normalizeExtractionSource(value) {
27
+ switch (value) {
28
+ case "agent-observed":
29
+ case "daemon-extracted":
30
+ case "bko-inferred":
31
+ case "cold-start-seed":
32
+ case "user-edited":
33
+ return value;
34
+ default:
35
+ return "cold-start-seed";
36
+ }
37
+ }
38
+ function isSemanticLabel(label) {
39
+ return SEMANTIC_NODE_LABELS.includes(label);
40
+ }
23
41
  function isCodeLabel(label) {
24
42
  return CODE_NODE_LABELS.includes(label);
25
43
  }
44
+ function isContextLabel(label) {
45
+ return CONTEXT_NODE_LABELS.includes(label);
46
+ }
47
+ function isValidEdgeType(type) {
48
+ return ALL_EDGE_TYPES.includes(type);
49
+ }
26
50
  function isTestRelPath(relPath) {
27
51
  return TEST_PATH_RE.test(relPath);
28
52
  }
29
53
  function isTestScopeQname(qname) {
30
54
  return TEST_SCOPE_RE.test(qname);
31
55
  }
32
- var SEMANTIC_NODE_LABELS, CONTEXT_NODE_LABELS, CODE_NODE_LABELS, ALL_NODE_LABELS, STRUCTURAL_EDGES, CAUSAL_EDGES, RESOLUTION_EDGES, CONCEPTUAL_EDGES, EVIDENCE_EDGES, CODE_EDGES, BRIDGE_EDGES, IDENTITY_EDGES, JUSTIFICATION_EDGES, BELIEF_EDGES, ABSTRACTION_EDGES, DECOMPOSITION_EDGES, TAXONOMY_EDGES, TRIAGE_EDGES, GIT_EDGES, ALL_EDGE_TYPES, PAGERANK_EXCLUSIONS, EDGE_WEIGHT, CAUSAL_PROTECT_EDGES, VALIDATION_SOURCES, ABSTRACTION_LEVEL, PROBLEM_RESOLUTION, DRIFT_KIND, TEST_PATH_RE, TEST_SCOPE_RE;
56
+ function toCloudAttrs(attrs) {
57
+ const rest2 = { ...attrs };
58
+ delete rest2["confidence"];
59
+ const scope = rest2["scope"];
60
+ if (scope && typeof scope === "object" && !Array.isArray(scope)) {
61
+ const scopeCopy = { ...scope };
62
+ delete scopeCopy["codebase"];
63
+ rest2["scope"] = scopeCopy;
64
+ }
65
+ return rest2;
66
+ }
67
+ var SEMANTIC_NODE_LABELS, CONTEXT_NODE_LABELS, CODE_NODE_LABELS, ALL_NODE_LABELS, STRUCTURAL_EDGES, CAUSAL_EDGES, RESOLUTION_EDGES, CONCEPTUAL_EDGES, EVIDENCE_EDGES, CODE_EDGES, BRIDGE_EDGES, IDENTITY_EDGES, JUSTIFICATION_EDGES, BELIEF_EDGES, ABSTRACTION_EDGES, DECOMPOSITION_EDGES, TRANSFER_EDGES, TAXONOMY_EDGES, TRIAGE_EDGES, GIT_EDGES, ALL_EDGE_TYPES, PAGERANK_EXCLUSIONS, EDGE_WEIGHT, CAUSAL_PROTECT_EDGES, VALIDATION_SOURCES, TRUTH_KIND, ABSTRACTION_LEVEL, PROBLEM_RESOLUTION, DRIFT_KIND, TEST_PATH_RE, TEST_SCOPE_RE;
33
68
  var init_castalia = __esm({
34
69
  "../../packages/shared/src/castalia.ts"() {
35
70
  "use strict";
@@ -179,6 +214,7 @@ var init_castalia = __esm({
179
214
  BELIEF_EDGES = ["CORROBORATES"];
180
215
  ABSTRACTION_EDGES = ["GENERALIZES", "DERIVED_FROM"];
181
216
  DECOMPOSITION_EDGES = ["SPLIT_INTO"];
217
+ TRANSFER_EDGES = ["MAY_RESOLVE"];
182
218
  TAXONOMY_EDGES = ["IS_A"];
183
219
  TRIAGE_EDGES = ["TRIAGED_BY", "CONFIRMS", "INDICATES", "ROUTES_TO"];
184
220
  GIT_EDGES = ["POINTS_AT", "PARENT", "AUTHORED_BY"];
@@ -193,6 +229,7 @@ var init_castalia = __esm({
193
229
  ...IDENTITY_EDGES,
194
230
  ...JUSTIFICATION_EDGES,
195
231
  ...BELIEF_EDGES,
232
+ ...TRANSFER_EDGES,
196
233
  ...ABSTRACTION_EDGES,
197
234
  ...DECOMPOSITION_EDGES,
198
235
  ...TAXONOMY_EDGES,
@@ -319,6 +356,10 @@ var init_castalia = __esm({
319
356
  INDICATES: 0.4,
320
357
  ROUTES_TO: 1,
321
358
  TRIAGED_BY: 0,
359
+ // Transfer — a witnessed could-aid hypothesis (Solution → Problem). Discounted like
360
+ // INDICATES: real signal, but a candidate must not form a hub; promotion mints the
361
+ // full-weight SOLVED_BY/MITIGATES instead of upgrading this edge.
362
+ MAY_RESOLVE: 0.3,
322
363
  // Git — topology/authorship, weightless (not domain signal-flow)
323
364
  POINTS_AT: 0,
324
365
  PARENT: 0,
@@ -331,6 +372,11 @@ var init_castalia = __esm({
331
372
  "agent-observed",
332
373
  "machine-derived"
333
374
  ];
375
+ TRUTH_KIND = {
376
+ OBJECTIVE: "objective",
377
+ CONTEXTUAL: "contextual",
378
+ TASTE: "taste"
379
+ };
334
380
  ABSTRACTION_LEVEL = { CONCRETE: 1, PRINCIPLE: 2 };
335
381
  PROBLEM_RESOLUTION = {
336
382
  FIXED: "fixed",
@@ -478,6 +524,9 @@ function canonicalizeError(raw2) {
478
524
  const sig = { ...canonical, digest: digest(canonical) };
479
525
  return sig;
480
526
  }
527
+ function errorSignatureEqual(a, b) {
528
+ return a.digest === b.digest;
529
+ }
481
530
  function problemIdFromError(sig) {
482
531
  return `prob_${sha256(sig.digest).slice(0, 16)}`;
483
532
  }
@@ -498,6 +547,9 @@ function resolveCanonical(label) {
498
547
  function resolveCanonicalId(label) {
499
548
  return resolveCanonical(label)?.id;
500
549
  }
550
+ function allEntities() {
551
+ return REGISTRY;
552
+ }
501
553
  function aliasesLongestFirst() {
502
554
  const out2 = [];
503
555
  for (const e of REGISTRY) for (const a of e.aliases) out2.push({ alias: a.toLowerCase(), entity: e });
@@ -796,6 +848,26 @@ function genericCanonicalId(prefix, content) {
796
848
  function languageCanonicalId(name2) {
797
849
  return genericCanonicalId("Language", { name: name2.trim().toLowerCase() });
798
850
  }
851
+ function packageCanonicalId(p) {
852
+ const eco = p.ecosystem.toLowerCase();
853
+ const name2 = eco === "npm" ? p.name.toLowerCase() : p.name;
854
+ return `pkg:${eco}/${name2}${p.version ? `@${p.version}` : ""}`;
855
+ }
856
+ function parsePackageRef(ref) {
857
+ let rest2 = ref.trim();
858
+ if (rest2.startsWith("pkg:")) {
859
+ rest2 = rest2.slice(4);
860
+ const slash = rest2.indexOf("/");
861
+ if (slash !== -1) rest2 = rest2.slice(slash + 1);
862
+ const q = rest2.search(/[?#]/);
863
+ if (q !== -1) rest2 = rest2.slice(0, q);
864
+ }
865
+ const at = rest2.lastIndexOf("@");
866
+ const name2 = at > 0 ? rest2.slice(0, at) : rest2;
867
+ const version2 = at > 0 ? rest2.slice(at + 1) || null : null;
868
+ const slug2 = (version2 ? `${name2}@${version2}` : name2).toLowerCase();
869
+ return { name: name2, version: version2, slug: slug2 };
870
+ }
799
871
  var DESIGN_PROBLEM_PREFIX, DESIGN_PROBLEM_ID_LENGTH, DIAGNOSTIC_PROBLEM_PREFIX, DIAGNOSTIC_HASH_LENGTH, TRIAGE_PREFIX, TRIAGE_ID_LENGTH;
800
872
  var init_identity = __esm({
801
873
  "../../packages/shared/src/identity.ts"() {
@@ -15128,13 +15200,113 @@ var init_zod = __esm({
15128
15200
  });
15129
15201
 
15130
15202
  // ../../packages/shared/src/edge-rules.ts
15203
+ function isValidEdge(from, type, to) {
15204
+ const rule = EDGE_RULES[type];
15205
+ if (!rule) return { ok: true };
15206
+ if (from && rule.from && !rule.from.includes(from)) {
15207
+ return {
15208
+ ok: false,
15209
+ reason: `${type} cannot originate from ${from} (allowed: ${rule.from.join(", ")})`
15210
+ };
15211
+ }
15212
+ if (to && rule.to && !rule.to.includes(to)) {
15213
+ return {
15214
+ ok: false,
15215
+ reason: `${type} cannot target ${to} (allowed: ${rule.to.join(", ")})`
15216
+ };
15217
+ }
15218
+ return { ok: true };
15219
+ }
15220
+ var EDGE_RULES;
15131
15221
  var init_edge_rules = __esm({
15132
15222
  "../../packages/shared/src/edge-rules.ts"() {
15133
15223
  "use strict";
15224
+ EDGE_RULES = {
15225
+ // ── Security spine (v1 taxonomy.ts SECURITY_FORWARD_ONLY commentary) ──
15226
+ TARGETS: { from: ["Exploit"], to: ["Vulnerability"] },
15227
+ ENABLES: { from: ["AntiPattern"], to: ["Vulnerability"] },
15228
+ MITIGATES: { from: ["Solution"], to: ["Vulnerability"] },
15229
+ PRESENTS: { from: ["Solution"], to: ["Problem", "Vulnerability"] },
15230
+ // SOLVED_BY sources: Vulnerability (v1 comment) + Problem/RootCause
15231
+ // (upstream design-problem.ts + triage.ts mint both).
15232
+ SOLVED_BY: { from: ["Vulnerability", "Problem", "RootCause"], to: ["Solution"] },
15233
+ FIXED_BY: { to: ["Solution"] },
15234
+ // ── Triage family (upstream castalia.ts: Problem —TRIAGED_BY→ Triage —{INDICATES|CONFIRMS}→ cause) ──
15235
+ // Two-edge differential model (T3-rename): INDICATES = provisional candidate,
15236
+ // CONFIRMS = promoted router (a discriminator exists). Same endpoint matrix.
15237
+ // ROUTES_TO is the deprecated pre-split alias, kept readable during migration.
15238
+ TRIAGED_BY: { from: ["Problem"], to: ["Triage"] },
15239
+ CONFIRMS: { from: ["Triage"], to: ["RootCause", "Problem"] },
15240
+ INDICATES: { from: ["Triage"], to: ["RootCause", "Problem"] },
15241
+ ROUTES_TO: { from: ["Triage"], to: ["RootCause", "Problem"] },
15242
+ // ── Context grounding (v1 taxonomy.ts comments) ──
15243
+ WRITTEN_IN: { from: ["Component", "Package"], to: ["Language"] },
15244
+ OCCURS_IN: { to: ["Language"] },
15245
+ OCCURS_ON: { to: ["OperatingSystem"] },
15246
+ RUNS_ON: { to: ["OperatingSystem"] },
15247
+ OPERATES_ON: { from: ["Algorithm"], to: ["DataStructure"] },
15248
+ INVOLVES: { from: ["Problem", "Solution"], to: ["DataStructure"] },
15249
+ // ── Taxonomy (Track 4 Stream C: MITRE CWE `ChildOf` → `Weakness —IS_A→ Weakness`) ──
15250
+ IS_A: { from: ["Weakness"], to: ["Weakness"] },
15251
+ // ── Conceptual (v1 taxonomy.ts: instance → motif/pattern reference) ──
15252
+ INSTANCE_OF: { to: ["Pattern", "Weakness", "Technique"] },
15253
+ IMPLEMENTS: { from: ["Solution", "Language", "Component"], to: ["Pattern", "Technique"] },
15254
+ MATCHES: { to: ["Pattern"] },
15255
+ // ── Artifact evidence (v1 taxonomy.ts artifact rows) ──
15256
+ PRODUCED: { from: ["Report"], to: ["Artifact"] },
15257
+ MANIFESTED_IN: { from: ["Problem"], to: ["Artifact"] },
15258
+ REVEALED_BY: { from: ["RootCause"], to: ["Artifact"] },
15259
+ // ── Belief / abstraction gradients (upstream castalia.ts) ──
15260
+ CORROBORATES: { from: ["Claim"], to: ["Claim"] },
15261
+ GENERALIZES: { from: ["Claim"] },
15262
+ DERIVED_FROM: { from: ["Claim"] },
15263
+ // ── Decomposition (castalia.ts: a Problem fans out into independent root
15264
+ // problems; §5.1 also attaches SPLIT_INTO to Claim when one conflates two).
15265
+ // `to` left unconstrained — the replacement set's labels vary by case. ──
15266
+ SPLIT_INTO: { from: ["Problem", "Claim"] }
15267
+ };
15134
15268
  }
15135
15269
  });
15136
15270
 
15137
15271
  // ../../packages/shared/src/wire.ts
15272
+ function provenanceBand(source) {
15273
+ switch (source) {
15274
+ case "agent-observed":
15275
+ case "user-edited":
15276
+ return "validated";
15277
+ case "daemon-extracted":
15278
+ case "bko-inferred":
15279
+ return "derived";
15280
+ case "cold-start-seed":
15281
+ return "seed";
15282
+ // Unknown/absent provenance is treated as the weakest band — a node with no
15283
+ // recorded source must never be mistaken for validated knowledge.
15284
+ default:
15285
+ return "seed";
15286
+ }
15287
+ }
15288
+ function isSeedProvenance(source) {
15289
+ return provenanceBand(source) === "seed";
15290
+ }
15291
+ function validateCastaliaPayload(p) {
15292
+ const errors = [];
15293
+ const labelByCid = /* @__PURE__ */ new Map();
15294
+ for (const n of p.nodes) {
15295
+ if (labelByCid.has(n.canonicalId)) errors.push(`duplicate node canonicalId '${n.canonicalId}'`);
15296
+ labelByCid.set(n.canonicalId, n.label);
15297
+ }
15298
+ for (const e of p.edges) {
15299
+ if (e.fromCanonicalId === e.toCanonicalId) {
15300
+ errors.push(`self-loop edge ${e.type} on '${e.fromCanonicalId}'`);
15301
+ continue;
15302
+ }
15303
+ const verdict = isValidEdge(labelByCid.get(e.fromCanonicalId), e.type, labelByCid.get(e.toCanonicalId));
15304
+ if (!verdict.ok) {
15305
+ errors.push(`edge ${e.fromCanonicalId} -${e.type}\u2192 ${e.toCanonicalId}: ${verdict.reason}`);
15306
+ }
15307
+ }
15308
+ return { ok: errors.length === 0, errors };
15309
+ }
15138
15310
  function summarizeIngestResult(r) {
15139
15311
  const all = [...r.nodes, ...r.edges];
15140
15312
  const rejectedItems = all.filter((x) => x.decision === "rejected");
@@ -15145,7 +15317,7 @@ function summarizeIngestResult(r) {
15145
15317
  ...r.patternReconciliation ? { patternReconciliation: r.patternReconciliation } : {}
15146
15318
  };
15147
15319
  }
15148
- var CLOUD_NODE_LABELS, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, MAX_EDGES_PER_PAYLOAD, CastaliaIngestNodeSchema, RouteContextCountWireSchema, CastaliaIngestEdgeSchema, CastaliaIngestPayloadSchema;
15320
+ var CLOUD_NODE_LABELS, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, MAX_NODES_PER_PAYLOAD, MAX_EDGES_PER_PAYLOAD, CastaliaIngestNodeSchema, RouteContextCountWireSchema, CastaliaIngestEdgeSchema, CastaliaIngestPayloadSchema;
15149
15321
  var init_wire = __esm({
15150
15322
  "../../packages/shared/src/wire.ts"() {
15151
15323
  "use strict";
@@ -15167,6 +15339,7 @@ var init_wire = __esm({
15167
15339
  "cold-start-seed",
15168
15340
  "user-edited"
15169
15341
  ];
15342
+ MAX_NODES_PER_PAYLOAD = 200;
15170
15343
  MAX_EDGES_PER_PAYLOAD = 500;
15171
15344
  CastaliaIngestNodeSchema = external_exports.object({
15172
15345
  /** Deterministic content id from identity.ts — the cross-stratum merge key. */
@@ -15211,6 +15384,9 @@ var init_wire = __esm({
15211
15384
  });
15212
15385
 
15213
15386
  // ../../packages/shared/src/nlp/canonicalize.ts
15387
+ function canonicalize(value) {
15388
+ return value.normalize("NFC").trim().toLowerCase().replace(/\s+/g, " ");
15389
+ }
15214
15390
  var init_canonicalize = __esm({
15215
15391
  "../../packages/shared/src/nlp/canonicalize.ts"() {
15216
15392
  "use strict";
@@ -15236,6 +15412,91 @@ var init_triage_canon = __esm({
15236
15412
  });
15237
15413
 
15238
15414
  // ../../packages/shared/src/index.ts
15415
+ var src_exports = {};
15416
+ __export(src_exports, {
15417
+ ABSTRACTION_EDGES: () => ABSTRACTION_EDGES,
15418
+ ABSTRACTION_LEVEL: () => ABSTRACTION_LEVEL,
15419
+ ALL_EDGE_TYPES: () => ALL_EDGE_TYPES,
15420
+ ALL_NODE_LABELS: () => ALL_NODE_LABELS,
15421
+ BELIEF_EDGES: () => BELIEF_EDGES,
15422
+ BRIDGE_EDGES: () => BRIDGE_EDGES,
15423
+ CAUSAL_EDGES: () => CAUSAL_EDGES,
15424
+ CAUSAL_PROTECT_EDGES: () => CAUSAL_PROTECT_EDGES,
15425
+ CLOUD_EDGE_TYPES: () => CLOUD_EDGE_TYPES,
15426
+ CLOUD_NODE_LABELS: () => CLOUD_NODE_LABELS,
15427
+ CODE_EDGES: () => CODE_EDGES,
15428
+ CODE_NODE_LABELS: () => CODE_NODE_LABELS,
15429
+ CONCEPTUAL_EDGES: () => CONCEPTUAL_EDGES,
15430
+ CONTEXT_NODE_LABELS: () => CONTEXT_NODE_LABELS,
15431
+ CastaliaIngestEdgeSchema: () => CastaliaIngestEdgeSchema,
15432
+ CastaliaIngestNodeSchema: () => CastaliaIngestNodeSchema,
15433
+ CastaliaIngestPayloadSchema: () => CastaliaIngestPayloadSchema,
15434
+ DECOMPOSITION_EDGES: () => DECOMPOSITION_EDGES,
15435
+ DRIFT_KIND: () => DRIFT_KIND,
15436
+ EDGE_RULES: () => EDGE_RULES,
15437
+ EDGE_WEIGHT: () => EDGE_WEIGHT,
15438
+ EVIDENCE_EDGES: () => EVIDENCE_EDGES,
15439
+ GIT_EDGES: () => GIT_EDGES,
15440
+ IDENTITY_EDGES: () => IDENTITY_EDGES,
15441
+ INGEST_EXTRACTION_SOURCES: () => INGEST_EXTRACTION_SOURCES,
15442
+ INGEST_SOURCES: () => INGEST_SOURCES,
15443
+ JUSTIFICATION_EDGES: () => JUSTIFICATION_EDGES,
15444
+ MAX_EDGES_PER_PAYLOAD: () => MAX_EDGES_PER_PAYLOAD,
15445
+ MAX_NODES_PER_PAYLOAD: () => MAX_NODES_PER_PAYLOAD,
15446
+ PAGERANK_EXCLUSIONS: () => PAGERANK_EXCLUSIONS,
15447
+ PROBLEM_RESOLUTION: () => PROBLEM_RESOLUTION,
15448
+ RESOLUTION_EDGES: () => RESOLUTION_EDGES,
15449
+ RouteContextCountWireSchema: () => RouteContextCountWireSchema,
15450
+ SEMANTIC_NODE_LABELS: () => SEMANTIC_NODE_LABELS,
15451
+ STRUCTURAL_EDGES: () => STRUCTURAL_EDGES,
15452
+ TAXONOMY_EDGES: () => TAXONOMY_EDGES,
15453
+ TRANSFER_EDGES: () => TRANSFER_EDGES,
15454
+ TRIAGE_EDGES: () => TRIAGE_EDGES,
15455
+ TRUTH_KIND: () => TRUTH_KIND,
15456
+ VALIDATION_SOURCES: () => VALIDATION_SOURCES,
15457
+ aliasesLongestFirst: () => aliasesLongestFirst,
15458
+ allEntities: () => allEntities,
15459
+ canonicalClaimId: () => canonicalClaimId,
15460
+ canonicalJSON: () => canonicalJSON,
15461
+ canonicalize: () => canonicalize,
15462
+ canonicalizeContext: () => canonicalizeContext,
15463
+ canonicalizeError: () => canonicalizeError,
15464
+ canonicalizeToken: () => canonicalizeToken,
15465
+ claimStructure: () => claimStructure,
15466
+ conceptBag: () => conceptBag,
15467
+ conceptTokens: () => conceptTokens,
15468
+ detectStance: () => detectStance,
15469
+ digest: () => digest,
15470
+ errorSignatureEqual: () => errorSignatureEqual,
15471
+ genericCanonicalId: () => genericCanonicalId,
15472
+ identityId: () => identityId,
15473
+ isCausalProtected: () => isCausalProtected,
15474
+ isCodeLabel: () => isCodeLabel,
15475
+ isContextLabel: () => isContextLabel,
15476
+ isInferredSource: () => isInferredSource,
15477
+ isSeedProvenance: () => isSeedProvenance,
15478
+ isSemanticLabel: () => isSemanticLabel,
15479
+ isTestRelPath: () => isTestRelPath,
15480
+ isTestScopeQname: () => isTestScopeQname,
15481
+ isValidEdge: () => isValidEdge,
15482
+ isValidEdgeType: () => isValidEdgeType,
15483
+ languageCanonicalId: () => languageCanonicalId,
15484
+ normalizeExtractionSource: () => normalizeExtractionSource,
15485
+ normalizePredicate: () => normalizePredicate,
15486
+ packageCanonicalId: () => packageCanonicalId,
15487
+ pagerankEdgeTypes: () => pagerankEdgeTypes,
15488
+ parsePackageRef: () => parsePackageRef,
15489
+ prefilterEntities: () => prefilterEntities,
15490
+ problemIdFromError: () => problemIdFromError,
15491
+ provenanceBand: () => provenanceBand,
15492
+ resolveCanonical: () => resolveCanonical,
15493
+ resolveCanonicalId: () => resolveCanonicalId,
15494
+ sha256: () => sha256,
15495
+ sha256Short: () => sha256Short,
15496
+ summarizeIngestResult: () => summarizeIngestResult,
15497
+ toCloudAttrs: () => toCloudAttrs,
15498
+ validateCastaliaPayload: () => validateCastaliaPayload
15499
+ });
15239
15500
  var init_src = __esm({
15240
15501
  "../../packages/shared/src/index.ts"() {
15241
15502
  "use strict";
@@ -17312,6 +17573,16 @@ function ingestDesignProblem(store, flag, opts) {
17312
17573
  const linkedPackages = linkProblemToPackages(store, problemId, linkText, opts.ts).linked;
17313
17574
  return { problemId, created, corroborated, rootCauseId, solutionId, anchored, linkedPackages };
17314
17575
  }
17576
+ function mintPatternNode(store, name2, ts) {
17577
+ const display = name2.replace(/\s+/g, " ").trim();
17578
+ const id = `pat_${digest({ pattern: display.toLowerCase() })}`.slice(0, 56);
17579
+ if (!store.getNode(id)) {
17580
+ store.mergeNode(
17581
+ buildNode(id, "Pattern", display, ts, { source: "convo", provisional: true })
17582
+ );
17583
+ }
17584
+ return id;
17585
+ }
17315
17586
  function resolveFileNode(store, path2, workspaceId2) {
17316
17587
  const want = path2.trim().replace(/^\.?\//, "");
17317
17588
  for (const n of store.findNodesByLabel("File")) {
@@ -17513,12 +17784,14 @@ function resolveDesignProblems(store, t) {
17513
17784
  if (!p.id.startsWith("dprob_")) continue;
17514
17785
  if (p.attrs["resolvedAt"]) continue;
17515
17786
  let symName = "";
17787
+ let symRelPath;
17516
17788
  let edited = false;
17517
17789
  for (const e of store.outEdges(p.id, ["ANCHORED_AT"])) {
17518
17790
  const sym = store.getNode(e.to);
17519
17791
  if (sym && sym.lastUpdatedAt > p.createdAt) {
17520
17792
  edited = true;
17521
17793
  symName = sym.description;
17794
+ symRelPath = sym.attrs["relPath"] ?? void 0;
17522
17795
  break;
17523
17796
  }
17524
17797
  }
@@ -17528,7 +17801,11 @@ function resolveDesignProblems(store, t) {
17528
17801
  store.mergeNode(
17529
17802
  buildNode(solId, "Solution", `addressed by an edit to ${symName}`, t, {
17530
17803
  source: "convo",
17531
- provisional: false
17804
+ provisional: false,
17805
+ // AC-resolution-attrs: the resolving symbol/file as STRUCTURED data, not
17806
+ // just prose — the F2 join key downstream backfills and the viz read.
17807
+ resolvedSymbols: [symName],
17808
+ ...symRelPath ? { resolvedRelPath: symRelPath } : {}
17532
17809
  })
17533
17810
  );
17534
17811
  mergeEdge(store, p.id, solId, "SOLVED_BY", t);
@@ -19503,8 +19780,8 @@ var init_principle_sync = __esm({
19503
19780
  });
19504
19781
 
19505
19782
  // ../../packages/local-graph/src/index.ts
19506
- var src_exports = {};
19507
- __export(src_exports, {
19783
+ var src_exports2 = {};
19784
+ __export(src_exports2, {
19508
19785
  CAUSAL_FAMILY: () => CAUSAL_FAMILY,
19509
19786
  CITABLE_PRIOR_LABELS: () => CITABLE_PRIOR_LABELS,
19510
19787
  CODE_REACH_EDGES: () => CODE_REACH_EDGES,
@@ -19558,6 +19835,7 @@ __export(src_exports, {
19558
19835
  matchPackagesInText: () => matchPackagesInText,
19559
19836
  mergeCloudCounts: () => mergeCloudCounts,
19560
19837
  mergeDuplicateProblems: () => mergeDuplicateProblems,
19838
+ mintPatternNode: () => mintPatternNode,
19561
19839
  openGraphStore: () => openGraphStore,
19562
19840
  parseAbstractionFences: () => parseAbstractionFences,
19563
19841
  parseSemver: () => parseSemver,
@@ -23176,6 +23454,18 @@ function triageBullet(ref) {
23176
23454
  " you? bind by its handle/id directly: (cause:#the-shown-handle \u2026) / (fix:#dprob_\u2026 \u2026)."
23177
23455
  ].join("\n");
23178
23456
  }
23457
+ function linkBullet(ref) {
23458
+ return [
23459
+ " \u2022 a problem you flagged resembles prior knowledge \u2014 LINK it to the canonical priors, not just one:",
23460
+ ` \xB7 (instance:[${ref}],[another-prior],\u2026) \u2014 the priors this problem is an instance of.`,
23461
+ " Aim for ~3 DIFFERENT relevant priors; one link is weak, three triangulate it.",
23462
+ ` \xB7 ${TAG_EXAMPLE.pattern()} \u2014 name the general shape it instantiates (e.g. (pattern: unbounded`,
23463
+ " queue growth under backpressure)) \u2014 this works with NO code anchor, and two agents naming",
23464
+ " the same pattern converge on one node. Cite a shown Pattern by handle: (pattern:[handle]).",
23465
+ ` \xB7 (aids:[${ref}],\u2026) \u2014 your FIX could also help these other, even unrelated, problems.`,
23466
+ " A hypothesis, not a claim \u2014 it's recorded as may-resolve and checked by whoever tries it."
23467
+ ].join("\n");
23468
+ }
23179
23469
  function attemptBullet() {
23180
23470
  return [
23181
23471
  " \u2022 you're attempting an approach to a flagged problem, or an attempt didn't pan out:",
@@ -23186,15 +23476,15 @@ function attemptBullet() {
23186
23476
  ].join("\n");
23187
23477
  }
23188
23478
  function buildAgentInstruction(opts = {}) {
23189
- const signals = opts.signals ?? ["prior", "problem", "fix", "constraint", "triage", "attempt"];
23479
+ const signals = opts.signals ?? ["prior", "problem", "fix", "constraint", "triage", "attempt", "link"];
23190
23480
  const ref = opts.referent ?? "its-handle";
23191
- const token = (s) => s === "problem" ? TAG_EXAMPLE.problem() : s === "constraint" ? TAG_EXAMPLE.constraint() : s === "attempt" ? TAG_EXAMPLE.tried() : TAG_EXAMPLE[s](ref);
23481
+ const token = (s) => s === "problem" ? TAG_EXAMPLE.problem() : s === "constraint" ? TAG_EXAMPLE.constraint() : s === "attempt" ? TAG_EXAMPLE.tried() : s === "link" ? TAG_EXAMPLE.pattern() : TAG_EXAMPLE[s](ref);
23192
23482
  const head2 = `We tag the priors we show you with a short handle like [${opts.handleExample ?? "chokidar-glob"}]. This is a capture protocol, not optional notes: what you DON'T tag is silently lost \u2014 the tag is the ONLY thing recorded. Whenever one of these is true, wrap it inline in your prose (no fences, no extra calls). Tag every one you state; we filter downstream, so don't self-censor or batch:`;
23193
23483
  const tail = "Mid-turn text (between tool calls) can be dropped by the harness \u2014 if a tag above appeared only mid-turn, RESTATE it in your final message of the turn; the final message always survives.";
23194
23484
  return [
23195
23485
  head2,
23196
23486
  ...signals.map(
23197
- (s) => s === "triage" ? triageBullet(ref) : s === "attempt" ? attemptBullet() : ` \u2022 ${GLOSS[s]} \u2192 ${token(s)}`
23487
+ (s) => s === "triage" ? triageBullet(ref) : s === "attempt" ? attemptBullet() : s === "link" ? linkBullet(ref) : ` \u2022 ${GLOSS[s]} \u2192 ${token(s)}`
23198
23488
  ),
23199
23489
  tail
23200
23490
  ].join("\n");
@@ -23230,7 +23520,13 @@ var init_agent_signals = __esm({
23230
23520
  // ATTEMPT arc — what's being tried and what didn't work. A failed attempt is a
23231
23521
  // witnessed NEGATIVE result: it saves the next agent the same dead end.
23232
23522
  tried: () => `(tried: the approach you're attempting)`,
23233
- failed: () => `(failed: what didn't work and the dead end it rules out)`
23523
+ failed: () => `(failed: what didn't work and the dead end it rules out)`,
23524
+ // LINK verbs (AC epic) — bind the problem in scope to CANONICAL priors and
23525
+ // abstractions. Multi-target by design: single links are weak; ~3 links to 3
23526
+ // DIFFERENT relevant priors is the target shape (see linkBullet).
23527
+ instance: (ref) => `(instance:[${ref}],[another],[a-third])`,
23528
+ pattern: () => `(pattern: name the general shape)`,
23529
+ aids: (ref) => `(aids:[${ref}])`
23234
23530
  };
23235
23531
  GLOSS = {
23236
23532
  prior: "a prior we showed you helped \u2014 or this work sits in a primed language/package",
@@ -23238,7 +23534,8 @@ var init_agent_signals = __esm({
23238
23534
  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)",
23239
23535
  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)",
23240
23536
  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",
23241
- attempt: "you're attempting an approach, or an attempt didn't pan out \u2014 (tried: \u2026) / (failed: \u2026); a failed attempt rules out a path for the next agent"
23537
+ attempt: "you're attempting an approach, or an attempt didn't pan out \u2014 (tried: \u2026) / (failed: \u2026); a failed attempt rules out a path for the next agent",
23538
+ link: "the problem you flagged is an instance of priors/abstractions you can name \u2014 (instance:[h1],[h2],\u2026) / (pattern: \u2026) / (aids:[h]); rendered whole via linkBullet"
23242
23539
  };
23243
23540
  }
23244
23541
  });
@@ -23534,8 +23831,8 @@ var init_recheck = __esm({
23534
23831
  });
23535
23832
 
23536
23833
  // ../../packages/canonical/src/index.ts
23537
- var src_exports2 = {};
23538
- __export(src_exports2, {
23834
+ var src_exports3 = {};
23835
+ __export(src_exports3, {
23539
23836
  detectViolations: () => detectViolations,
23540
23837
  hashIdentifier: () => hashIdentifier,
23541
23838
  recheck: () => recheck,
@@ -24325,6 +24622,47 @@ function mergeProblemsByEmbedding(store, opts) {
24325
24622
  });
24326
24623
  return report;
24327
24624
  }
24625
+ function bindCanonicalNeighbors(store, opts) {
24626
+ const k = opts.k ?? 3;
24627
+ const live = (n) => n.attrs["mergedInto"] === void 0;
24628
+ const problems = store.findNodesByLabel("Problem").filter((p) => p.embedding.length > 0 && live(p));
24629
+ const patterns = store.findNodesByLabel("Pattern").filter((p) => p.embedding.length > 0);
24630
+ const candidates = [...problems, ...patterns];
24631
+ let bound = 0;
24632
+ for (const p of problems) {
24633
+ const existing = new Set(
24634
+ store.outEdges(p.id, ["MATCHES", "INSTANCE_OF"]).map((e) => e.to)
24635
+ );
24636
+ if (existing.size >= k) continue;
24637
+ const ranked = candidates.filter(
24638
+ (c) => c.id !== p.id && !existing.has(c.id) && c.embedding.length === p.embedding.length && (c.attrs["embeddingVersion"] ?? "") === (p.attrs["embeddingVersion"] ?? "")
24639
+ ).map((c) => ({ c, s: cosine(p.embedding, c.embedding) })).filter((x) => x.s >= CANONICAL_BIND_MIN && x.s < NEMORI_DEDUP_COSINE).sort((a, b) => b.s - a.s);
24640
+ const picked = [];
24641
+ for (const cand of ranked) {
24642
+ if (picked.length + existing.size >= k) break;
24643
+ if (picked.some((q) => cosine(q.c.embedding, cand.c.embedding) >= NEMORI_DEDUP_COSINE)) continue;
24644
+ picked.push(cand);
24645
+ }
24646
+ for (const { c, s } of picked) {
24647
+ const type = c.label === "Pattern" ? "INSTANCE_OF" : "MATCHES";
24648
+ store.mergeEdge({
24649
+ id: `edge_${digest({ from: p.id, type, to: c.id, k: "canonBind" })}`.slice(0, 24),
24650
+ from: p.id,
24651
+ to: c.id,
24652
+ type,
24653
+ confidence: 0.3,
24654
+ extractionSource: "daemon-extracted",
24655
+ createdAt: opts.ts,
24656
+ lastSeenAt: opts.ts,
24657
+ navSuccesses: 0,
24658
+ navFailures: 0,
24659
+ attrs: { provisional: true, machineProposed: true, cosine: Math.round(s * 100) / 100 }
24660
+ });
24661
+ bound++;
24662
+ }
24663
+ }
24664
+ return { bound, scanned: problems.length };
24665
+ }
24328
24666
  async function ingestErrorSignature(opts, sig, commandSig) {
24329
24667
  const candidateId = identityId({ kind: "RuntimeProblem", error: sig });
24330
24668
  const now = Date.now();
@@ -25043,7 +25381,7 @@ function reconcileDiagnostics(store, workspaceId2, relPath, diags, t, command) {
25043
25381
  }
25044
25382
  return { opened, resolved };
25045
25383
  }
25046
- var GENERALIZER_CURSOR, GENERALIZER_KINDS, GENERALIZER_BATCH, ANCHOR_LABELS, DIAG_SEVERITY_ERROR;
25384
+ var GENERALIZER_CURSOR, GENERALIZER_KINDS, GENERALIZER_BATCH, CANONICAL_BIND_MIN, ANCHOR_LABELS, DIAG_SEVERITY_ERROR;
25047
25385
  var init_generalizer = __esm({
25048
25386
  "../../packages/generalizer/src/generalizer.ts"() {
25049
25387
  "use strict";
@@ -25063,6 +25401,7 @@ var init_generalizer = __esm({
25063
25401
  "harness.error"
25064
25402
  ];
25065
25403
  GENERALIZER_BATCH = 500;
25404
+ CANONICAL_BIND_MIN = 0.78;
25066
25405
  ANCHOR_LABELS = ["Function", "Method", "Class"];
25067
25406
  DIAG_SEVERITY_ERROR = 1;
25068
25407
  }
@@ -25439,6 +25778,21 @@ function scoreCandidate(candidate, ctx = {}, weights) {
25439
25778
  weights
25440
25779
  );
25441
25780
  }
25781
+ function rankByRelevance(store, seedId, candidateIds, opts = {}) {
25782
+ const seed = store.getNode(seedId);
25783
+ const ctx = {
25784
+ ...seed && seed.embedding.length > 0 ? { seedEmbedding: seed.embedding, seedEmbeddingVersion: seed.attrs["embeddingVersion"] } : {},
25785
+ ...opts.hops !== void 0 ? { hops: opts.hops } : {}
25786
+ };
25787
+ const nodes = candidateIds.map((id) => store.getNode(id)).filter((n) => n != null);
25788
+ const maxPr = Math.max(1e-9, ...nodes.map((n) => n.pageRank));
25789
+ const weights = { centralityScale: maxPr, ...opts.weights };
25790
+ const now = store.currentIngestSeq();
25791
+ return nodes.map((node2) => {
25792
+ const r = scoreCandidate(node2, { ...ctx, decay: nodeFreshness(node2, now) }, weights);
25793
+ return { id: node2.id, score: r.score, components: r.components, node: node2 };
25794
+ }).sort((a, b) => b.score - a.score);
25795
+ }
25442
25796
  function localBurst(store, seedId, opts = {}) {
25443
25797
  const maxHops = opts.maxHops ?? 2;
25444
25798
  const limit = opts.limit ?? 20;
@@ -25483,6 +25837,36 @@ var init_relevance_rank = __esm({
25483
25837
  });
25484
25838
 
25485
25839
  // ../../packages/generalizer/src/index.ts
25840
+ var src_exports4 = {};
25841
+ __export(src_exports4, {
25842
+ anchorByLine: () => anchorByLine,
25843
+ anchorCandidates: () => anchorCandidates,
25844
+ anchorProblemToCode: () => anchorProblemToCode,
25845
+ annotateResolution: () => annotateResolution,
25846
+ attributeRootCause: () => attributeRootCause,
25847
+ bindCanonicalNeighbors: () => bindCanonicalNeighbors,
25848
+ closeProblem: () => closeProblem,
25849
+ codeAnchorProjection: () => codeAnchorProjection,
25850
+ commandSignature: () => commandSignature,
25851
+ embedCodeNodes: () => embedCodeNodes,
25852
+ embedSemanticNodes: () => embedSemanticNodes,
25853
+ evaluateForReview: () => evaluateForReview,
25854
+ extractDiagnostics: () => extractDiagnostics,
25855
+ extractErrorSignature: () => extractErrorSignature,
25856
+ ingestErrorSignature: () => ingestErrorSignature,
25857
+ localBurst: () => localBurst,
25858
+ mergeProblemsByEmbedding: () => mergeProblemsByEmbedding,
25859
+ nemoriDecide: () => nemoriDecide,
25860
+ promoteMotifs: () => promoteMotifs,
25861
+ rankByRelevance: () => rankByRelevance,
25862
+ rankOpenProblemNeighbors: () => rankOpenProblemNeighbors,
25863
+ reconcileDiagnostics: () => reconcileDiagnostics,
25864
+ resolveProblem: () => resolveProblem,
25865
+ runGeneralizer: () => runGeneralizer,
25866
+ runNightlyPipeline: () => runNightlyPipeline,
25867
+ scoreCandidate: () => scoreCandidate,
25868
+ selectAnchorFrame: () => selectAnchorFrame
25869
+ });
25486
25870
  var init_src10 = __esm({
25487
25871
  "../../packages/generalizer/src/index.ts"() {
25488
25872
  "use strict";
@@ -25857,7 +26241,7 @@ async function incrementalReindex(store, rootPath, workspaceId2, changedAbsPaths
25857
26241
  continuations: []
25858
26242
  };
25859
26243
  }
25860
- const { defaultProviders: defaultProviders2 } = await Promise.resolve().then(() => (init_src11(), src_exports3));
26244
+ const { defaultProviders: defaultProviders2 } = await Promise.resolve().then(() => (init_src11(), src_exports5));
25861
26245
  const providers = defaultProviders2();
25862
26246
  for (const p of providers) if (p.preload) await p.preload();
25863
26247
  const before = /* @__PURE__ */ new Map();
@@ -26207,8 +26591,8 @@ async function runIndexer(store, opts) {
26207
26591
  if (reExports.length > 0) reExportsByFile.set(f.relPath, reExports);
26208
26592
  report.filesParsed++;
26209
26593
  report.byLanguage[f.provider.id] = (report.byLanguage[f.provider.id] ?? 0) + 1;
26210
- if (report.filesParsed % 250 === 0) {
26211
- perf(`parse @ ${report.filesParsed}/${files.length}`);
26594
+ if (report.filesParsed % 250 === 0) perf(`parse @ ${report.filesParsed}/${files.length}`);
26595
+ if (report.filesParsed % 25 === 0) {
26212
26596
  await new Promise((r) => setImmediate(r));
26213
26597
  }
26214
26598
  }
@@ -26370,7 +26754,12 @@ async function runIndexer(store, opts) {
26370
26754
  const pendingEdges = [];
26371
26755
  perf("index-build (exports/imports/workspace-pkgs/re-export-fixpoint)");
26372
26756
  const providerByRel = new Map(files.map((x) => [x.relPath, x.provider]));
26757
+ let emittedFiles = 0;
26373
26758
  for (const [relPath, symbols] of symbolsByFile) {
26759
+ if (emittedFiles > 0 && emittedFiles % 50 === 0) {
26760
+ await new Promise((r) => setImmediate(r));
26761
+ }
26762
+ emittedFiles++;
26374
26763
  store.transaction(() => {
26375
26764
  const fileId = fileNodeId(opts.workspaceId, relPath);
26376
26765
  const langProvider = providerByRel.get(relPath);
@@ -26565,6 +26954,7 @@ async function runIndexer(store, opts) {
26565
26954
  if (pendingEdges.length > 0) {
26566
26955
  const EDGE_BATCH = 5e3;
26567
26956
  for (let ei = 0; ei < pendingEdges.length; ei += EDGE_BATCH) {
26957
+ if (ei > 0) await new Promise((r) => setImmediate(r));
26568
26958
  const slice = pendingEdges.slice(ei, ei + EDGE_BATCH);
26569
26959
  store.transaction(() => {
26570
26960
  for (const e of slice) {
@@ -34000,8 +34390,8 @@ var init_csharp_treesitter = __esm({
34000
34390
  });
34001
34391
 
34002
34392
  // ../../packages/indexer/src/index.ts
34003
- var src_exports3 = {};
34004
- __export(src_exports3, {
34393
+ var src_exports5 = {};
34394
+ __export(src_exports5, {
34005
34395
  DRIFT_FORK_RATIO: () => DRIFT_FORK_RATIO,
34006
34396
  TreeSitterCSharpProvider: () => TreeSitterCSharpProvider,
34007
34397
  TreeSitterCppProvider: () => TreeSitterCppProvider,
@@ -39742,6 +40132,10 @@ var FIX_PREFIX = /^\s*fix:(?:#([a-z][\w-]{0,63}))?\s*/i;
39742
40132
  var CONSTRAINT_RE = /\(\s*constraint:\s*([^()\n]{8,}?)\s*\)/gi;
39743
40133
  var CAUSE_PREFIX = /^\s*cause:(?:#([a-z][\w-]{0,63}))?\s*/i;
39744
40134
  var ATTEMPT_RE = /\(\s*(tried|failed):(?:#([a-z][\w-]{0,63}))?\s*((?:[^()\n]|\([^()\n]*\)){8,}?)\s*\)/gi;
40135
+ var AIDS_PREFIX = /^\s*aids:(?:#([a-z][\w-]{0,63}))?\s*/i;
40136
+ var INSTANCE_PREFIX = /^\s*instance:\s*/i;
40137
+ var PATTERN_RE = /\(\s*pattern:\s*([^()\n]{3,}?)\s*\)/gi;
40138
+ var PATTERN_TEXT_MAX = 120;
39745
40139
  var CAUSE_TEXT_MIN = 8;
39746
40140
  var CAUSE_TEXT_MAX = 200;
39747
40141
  var FLAG_RE = /\[([!?])(?:#([a-z][\w-]{0,63})\s+)?\s*([^\]\n]{8,}?)\s*(?:@\s*([^\s\]]+?)(?::(\d+))?\s*)?\]/g;
@@ -39777,10 +40171,32 @@ function parseInlineTags(text) {
39777
40171
  let g;
39778
40172
  while ((g = CITE_GROUP_RE.exec(sentence)) !== null) {
39779
40173
  let content = g[1];
40174
+ if (/^\s*pattern:/i.test(content)) continue;
39780
40175
  const fixM = FIX_PREFIX.exec(content);
39781
40176
  const causeM = fixM ? null : CAUSE_PREFIX.exec(content);
40177
+ const aidsM = fixM || causeM ? null : AIDS_PREFIX.exec(content);
40178
+ const instM = fixM || causeM || aidsM ? null : INSTANCE_PREFIX.exec(content);
39782
40179
  const isFix = fixM !== null;
39783
40180
  const isCause = causeM !== null;
40181
+ if (aidsM || instM) {
40182
+ const body2 = content.replace(aidsM ? AIDS_PREFIX : INSTANCE_PREFIX, "");
40183
+ const handles = [];
40184
+ HANDLE_RE.lastIndex = 0;
40185
+ let hh;
40186
+ while ((hh = HANDLE_RE.exec(body2)) !== null) {
40187
+ const handle2 = hh[1] ?? hh[2];
40188
+ if (handle2 && !handles.includes(handle2)) handles.push(handle2);
40189
+ }
40190
+ if (handles.length > 0) {
40191
+ out2.push({
40192
+ kind: aidsM ? "transfer" : "instance",
40193
+ handles,
40194
+ sentence: sfield,
40195
+ ...aidsM?.[1] ? { threadId: aidsM[1] } : {}
40196
+ });
40197
+ }
40198
+ continue;
40199
+ }
39784
40200
  const verbThread = fixM?.[1] ?? causeM?.[1] ?? void 0;
39785
40201
  if (isFix) content = content.replace(FIX_PREFIX, "");
39786
40202
  else if (isCause) content = content.replace(CAUSE_PREFIX, "");
@@ -39866,6 +40282,23 @@ function parseInlineTags(text) {
39866
40282
  });
39867
40283
  }
39868
40284
  }
40285
+ PATTERN_RE.lastIndex = 0;
40286
+ let pm;
40287
+ while ((pm = PATTERN_RE.exec(sentence)) !== null) {
40288
+ const body2 = pm[1].trim();
40289
+ HANDLE_RE.lastIndex = 0;
40290
+ const ph = HANDLE_RE.exec(body2);
40291
+ const handle2 = ph ? ph[1] ?? ph[2] : void 0;
40292
+ if (handle2) {
40293
+ out2.push({ kind: "pattern", handle: handle2, sentence: sfield });
40294
+ } else {
40295
+ const raw3 = body2.replace(/\s+/g, " ").trim();
40296
+ if (raw3.length >= 3) {
40297
+ const patternText = raw3.length > PATTERN_TEXT_MAX ? `${raw3.slice(0, PATTERN_TEXT_MAX - 1).trimEnd()}\u2026` : raw3;
40298
+ out2.push({ kind: "pattern", patternText, sentence: sfield });
40299
+ }
40300
+ }
40301
+ }
39869
40302
  CONSTRAINT_RE.lastIndex = 0;
39870
40303
  let c;
39871
40304
  while ((c = CONSTRAINT_RE.exec(sentence)) !== null) {
@@ -39986,7 +40419,7 @@ function harvestInlineTags(store, text, opts) {
39986
40419
  const source = opts.sourceId ? store.getNode(opts.sourceId) : null;
39987
40420
  const mintPriors = opts.mintPriors ?? true;
39988
40421
  const touched = opts.sessionTouchedIds ?? /* @__PURE__ */ new Set();
39989
- const plan = { priorEdges: 0, problems: [], fixes: [], triages: [], attempts: [], unresolvedFixes: [] };
40422
+ const plan = { priorEdges: 0, problems: [], fixes: [], triages: [], attempts: [], unresolvedFixes: [], transfers: [], instances: [], patterns: [] };
39990
40423
  const tags = parseInlineTags(text);
39991
40424
  const symptomSeqs = tags.filter((t) => (t.kind === "problem" || t.kind === "todo" || t.kind === "constraint") && t.statement).map((t) => ({ seq: t.seq ?? -1, statement: t.statement, threadId: t.threadId })).sort((a, b) => a.seq - b.seq);
39992
40425
  const bindSymptom = (seq, threadId) => {
@@ -40052,6 +40485,50 @@ function harvestInlineTags(store, text, opts) {
40052
40485
  const causeId = `dcause_${digest({ statement: tag.causeText })}`.slice(0, 56);
40053
40486
  plan.triages.push({ causeId, causeDescription: tag.causeText, ...bound });
40054
40487
  }
40488
+ } else if (tag.kind === "transfer") {
40489
+ const targetIds = [];
40490
+ for (const h of tag.handles ?? []) {
40491
+ const id = resolveHandle(store, h, opts.handleMap);
40492
+ if (id && !targetIds.includes(id)) targetIds.push(id);
40493
+ }
40494
+ if (targetIds.length > 0) {
40495
+ const b = bindSymptom(tag.seq, tag.threadId);
40496
+ plan.transfers.push({
40497
+ targetIds,
40498
+ ...tag.threadId ? { threadId: tag.threadId } : {},
40499
+ ...b.statement ? { boundStatement: b.statement } : {}
40500
+ });
40501
+ }
40502
+ } else if (tag.kind === "instance") {
40503
+ const targetIds = [];
40504
+ for (const h of tag.handles ?? []) {
40505
+ const id = resolveHandle(store, h, opts.handleMap);
40506
+ if (id && !targetIds.includes(id)) targetIds.push(id);
40507
+ }
40508
+ if (targetIds.length > 0) {
40509
+ const b = bindSymptom(tag.seq, tag.threadId);
40510
+ plan.instances.push({
40511
+ targetIds,
40512
+ ...b.statement ? { boundStatement: b.statement } : {},
40513
+ ...b.problemId ? { problemId: b.problemId } : {},
40514
+ ...tag.threadId ? { threadId: tag.threadId } : {},
40515
+ evidence: b.evidence
40516
+ });
40517
+ }
40518
+ } else if (tag.kind === "pattern") {
40519
+ const b = bindSymptom(tag.seq, tag.threadId);
40520
+ const bound = {
40521
+ ...b.statement ? { boundStatement: b.statement } : {},
40522
+ ...b.problemId ? { problemId: b.problemId } : {},
40523
+ ...tag.threadId ? { threadId: tag.threadId } : {},
40524
+ evidence: b.evidence
40525
+ };
40526
+ if (tag.handle) {
40527
+ const patternId = resolveHandle(store, tag.handle, opts.handleMap);
40528
+ if (patternId) plan.patterns.push({ patternId, ...bound });
40529
+ } else if (tag.patternText) {
40530
+ plan.patterns.push({ patternText: tag.patternText, ...bound });
40531
+ }
40055
40532
  } else if (tag.kind === "attempt" || tag.kind === "failure") {
40056
40533
  const b = bindSymptom(tag.seq, tag.threadId);
40057
40534
  const outcome = tag.kind === "attempt" ? "tried" : "failed";
@@ -40284,6 +40761,12 @@ var PassWorker = class {
40284
40761
  snapshot(opts) {
40285
40762
  return this.call("snapshot", opts);
40286
40763
  }
40764
+ /** Run an fs/git incremental reindex on the worker — `incrementalReindex`
40765
+ * embeds a full-workspace `runIndexer` (cross-file re-resolution), which held
40766
+ * the main loop ~30s+ per saved file when run inline (HZ-reindex-offload). */
40767
+ reindex(opts) {
40768
+ return this.call("reindex", opts);
40769
+ }
40287
40770
  call(kind, payload) {
40288
40771
  if (this.stopped) return Promise.reject(new Error("pass worker stopped"));
40289
40772
  this.ensureWorker();
@@ -41363,7 +41846,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
41363
41846
  }
41364
41847
 
41365
41848
  // src/engine.ts
41366
- var DAEMON_VERSION = true ? "2.0.0-dev.30" : "2.0.0-alpha.0";
41849
+ var DAEMON_VERSION = true ? "2.0.0-dev.32" : "2.0.0-alpha.0";
41367
41850
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
41368
41851
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
41369
41852
  var GIT_OP_MUTE_MS = 4e3;
@@ -41485,6 +41968,36 @@ function createWorkspaceEngine(opts) {
41485
41968
  watcher.on("add", onFs("fs.add"));
41486
41969
  watcher.on("change", onFs("fs.change"));
41487
41970
  watcher.on("unlink", onFs("fs.unlink"));
41971
+ const auditIdentity = (t, e) => {
41972
+ appendIdentityAudit(identityAuditPath, e, JSON.stringify({ t, ...e }) + "\n");
41973
+ };
41974
+ const runReindexPass = async (passName, changed, t, declaredRenames) => {
41975
+ if (passWorker) {
41976
+ try {
41977
+ const { identityEvaluations, ...r } = await passWorker.reindex({
41978
+ changedAbsPaths: changed,
41979
+ t,
41980
+ ...declaredRenames !== void 0 ? { declaredRenames } : {}
41981
+ });
41982
+ for (const e of identityEvaluations) auditIdentity(t, e);
41983
+ return r;
41984
+ } catch (err2) {
41985
+ console.warn(
41986
+ "[errata] reindex worker unavailable, running inline:",
41987
+ err2 instanceof Error ? err2.message : err2
41988
+ );
41989
+ }
41990
+ }
41991
+ const done = markPass(passName);
41992
+ try {
41993
+ return await incrementalReindex(store, opts.workspaceRoot, profile.id, changed, t, {
41994
+ onIdentityEvaluate: (e) => auditIdentity(t, e),
41995
+ ...declaredRenames !== void 0 ? { declaredRenames } : {}
41996
+ });
41997
+ } finally {
41998
+ done();
41999
+ }
42000
+ };
41488
42001
  const dirty = /* @__PURE__ */ new Set();
41489
42002
  let gitOpMuteUntil = 0;
41490
42003
  const scheduleFlush = () => {
@@ -41496,13 +42009,12 @@ function createWorkspaceEngine(opts) {
41496
42009
  const t = Date.now();
41497
42010
  const relChanged = changed.map((p) => relative6(opts.workspaceRoot, p).split(sep4).join("/"));
41498
42011
  const causal = causalBuffer.correlate(relChanged, t) ?? void 0;
41499
- const doneReindex = markPass(`fs-reindex:${profile.name} (${changed.length} files)`);
41500
- void incrementalReindex(store, opts.workspaceRoot, profile.id, changed, t, {
41501
- onIdentityEvaluate: (e) => {
41502
- appendIdentityAudit(identityAuditPath, e, JSON.stringify({ t, ...e }) + "\n");
41503
- },
41504
- declaredRenames: causal?.declaredRenames
41505
- }).finally(doneReindex).then((r) => {
42012
+ void runReindexPass(
42013
+ `fs-reindex:${profile.name} (${changed.length} files)`,
42014
+ changed,
42015
+ t,
42016
+ causal?.declaredRenames
42017
+ ).then((r) => {
41506
42018
  if (r.filesReindexed > 0) {
41507
42019
  console.log(
41508
42020
  `[errata] incremental reindex: ${r.filesReindexed} file(s), +${r.nodesEmitted} nodes / +${r.edgesEmitted} edges`
@@ -41560,9 +42072,13 @@ function createWorkspaceEngine(opts) {
41560
42072
  let episodeId2;
41561
42073
  if (srcPaths.length > 0) {
41562
42074
  const abs = srcPaths.map((p) => join19(opts.workspaceRoot, p));
41563
- const doneReindex = markPass(`git-reindex:${profile.name} (${abs.length} files)`);
41564
42075
  try {
41565
- const r = await incrementalReindex(store, opts.workspaceRoot, profile.id, abs, t, { declaredRenames });
42076
+ const r = await runReindexPass(
42077
+ `git-reindex:${profile.name} (${abs.length} files)`,
42078
+ abs,
42079
+ t,
42080
+ declaredRenames
42081
+ );
41566
42082
  if (r.filesReindexed > 0) {
41567
42083
  const epId = recordEpisode(store, profile.id, t, r.delta, void 0);
41568
42084
  if (epId) {
@@ -41573,8 +42089,6 @@ function createWorkspaceEngine(opts) {
41573
42089
  }
41574
42090
  } catch (err2) {
41575
42091
  console.warn("[errata] git reindex failed:", err2);
41576
- } finally {
41577
- doneReindex();
41578
42092
  }
41579
42093
  }
41580
42094
  recordGitCommit(store, {
@@ -41845,6 +42359,7 @@ function createWorkspaceEngine(opts) {
41845
42359
  let abstracted = 0;
41846
42360
  let triaged = 0;
41847
42361
  let priorEdges = 0;
42362
+ let linked = 0;
41848
42363
  const t = Date.now();
41849
42364
  let processedTurns = 0;
41850
42365
  const elicit = isEdgeElicitationEnabled();
@@ -42075,6 +42590,65 @@ function createWorkspaceEngine(opts) {
42075
42590
  console.warn("[errata] attempt journal failed:", err2);
42076
42591
  }
42077
42592
  }
42593
+ const bindPid = (tag) => {
42594
+ const pid = tag.problemId ?? (tag.threadId ? threads.get(tag.threadId) : void 0) ?? (tag.boundStatement ? designProblemId(tag.boundStatement) : void 0) ?? inScopeProblemId ?? sessionLastProblem.get(sessionId);
42595
+ return pid && store.getNode(pid) ? pid : void 0;
42596
+ };
42597
+ const mintCiteEdge = (from, to, type, confidence, extraAttrs) => {
42598
+ store.mergeEdge({
42599
+ id: `edge_${digest({ from, type, to })}`.slice(0, 24),
42600
+ from,
42601
+ to,
42602
+ type,
42603
+ confidence,
42604
+ extractionSource: "agent-observed",
42605
+ createdAt: t,
42606
+ lastSeenAt: t,
42607
+ navSuccesses: 0,
42608
+ navFailures: 0,
42609
+ attrs: { provisional: true, session: sessionId, ...extraAttrs }
42610
+ });
42611
+ linked++;
42612
+ };
42613
+ for (const pt of plan.patterns) {
42614
+ const pid = bindPid(pt);
42615
+ if (!pid) continue;
42616
+ let patternId = pt.patternId;
42617
+ if (patternId) {
42618
+ const node2 = store.getNode(patternId);
42619
+ if (!node2 || node2.label !== "Pattern") continue;
42620
+ } else if (pt.patternText) {
42621
+ patternId = mintPatternNode(store, pt.patternText, t);
42622
+ }
42623
+ if (!patternId || patternId === pid) continue;
42624
+ mintCiteEdge(pid, patternId, "INSTANCE_OF", pt.evidence === "witnessed" ? 0.4 : 0.3, { patternCite: true, evidence: pt.evidence });
42625
+ }
42626
+ for (const inst of plan.instances) {
42627
+ const pid = bindPid(inst);
42628
+ if (!pid) continue;
42629
+ for (const targetId of inst.targetIds) {
42630
+ if (targetId === pid) continue;
42631
+ const target = store.getNode(targetId);
42632
+ if (!target) continue;
42633
+ const fallback = typePriorEdge("Problem", target.label);
42634
+ const type = target.label === "Pattern" ? "INSTANCE_OF" : target.label === "Problem" ? "MATCHES" : fallback === "SUPERSEDES" ? "RELATES_TO" : fallback;
42635
+ mintCiteEdge(pid, targetId, type, inst.evidence === "witnessed" ? 0.4 : 0.3, { instanceCite: true, evidence: inst.evidence });
42636
+ }
42637
+ }
42638
+ for (const tf of plan.transfers) {
42639
+ const pid = bindPid(tf);
42640
+ const solId = pid ? solutionForProblem(store, pid) : void 0;
42641
+ if (!solId) {
42642
+ console.warn("[errata] aids tag dropped: no solution in scope to hypothesize from \u2014 state it beside its (fix:\u2026)");
42643
+ continue;
42644
+ }
42645
+ for (const targetId of tf.targetIds) {
42646
+ if (targetId === solId) continue;
42647
+ const target = store.getNode(targetId);
42648
+ if (!target || target.label !== "Problem") continue;
42649
+ mintCiteEdge(solId, targetId, "MAY_RESOLVE", 0.3, { transfer: true, hypothesis: true });
42650
+ }
42651
+ }
42078
42652
  } catch (err2) {
42079
42653
  console.warn("[errata] inline-tag harvest failed:", err2);
42080
42654
  }
@@ -42083,6 +42657,10 @@ function createWorkspaceEngine(opts) {
42083
42657
  console.log(`[errata] edge-elicitation: +${priorEdges} soft prior-tag edge(s)`);
42084
42658
  contextDirty = true;
42085
42659
  }
42660
+ if (linked > 0) {
42661
+ console.log(`[errata] canonical-bind: +${linked} abstraction link(s) (pattern/instance/aids)`);
42662
+ contextDirty = true;
42663
+ }
42086
42664
  if (minted > 0 || resolved > 0) {
42087
42665
  console.log(
42088
42666
  `[errata] design: +${minted} flagged, ${resolved} resolved from the conversation`
@@ -42309,6 +42887,10 @@ function createWorkspaceEngine(opts) {
42309
42887
  if (e.merged > 0) {
42310
42888
  console.log(`[errata] dedup: merged ${e.merged} paraphrased problem(s) by embedding across ${e.clusters} cluster(s)`);
42311
42889
  }
42890
+ const cb = bindCanonicalNeighbors(store, { ts: Date.now() });
42891
+ if (cb.bound > 0) {
42892
+ console.log(`[errata] canonical-bind: +${cb.bound} machine-proposed link(s) across ${cb.scanned} problem(s)`);
42893
+ }
42312
42894
  refreshContextNow();
42313
42895
  }
42314
42896
  return { embedded: sem.embedded };
@@ -42345,6 +42927,10 @@ function createWorkspaceEngine(opts) {
42345
42927
  console.log(`[errata] dedup: merged ${e.merged} paraphrased problem(s) by embedding across ${e.clusters} cluster(s)`);
42346
42928
  refreshContextNow();
42347
42929
  }
42930
+ const cb = bindCanonicalNeighbors(store, { ts: Date.now() });
42931
+ if (cb.bound > 0) {
42932
+ console.log(`[errata] canonical-bind: +${cb.bound} machine-proposed link(s) across ${cb.scanned} problem(s)`);
42933
+ }
42348
42934
  } catch (err2) {
42349
42935
  console.warn("[errata] embedding problem dedup failed:", err2);
42350
42936
  }
@@ -44135,6 +44721,8 @@ async function main() {
44135
44721
  return cmdDash(rest);
44136
44722
  case "notify-test":
44137
44723
  return cmdNotifyTest();
44724
+ case "backfill-anchors":
44725
+ return cmdBackfillAnchors();
44138
44726
  case "help":
44139
44727
  case "--help":
44140
44728
  case "-h":
@@ -44172,6 +44760,9 @@ Commands:
44172
44760
  --no-embed skips the code-node embedding pass
44173
44761
  (~minutes on first run; incremental after).
44174
44762
  review Print the pending review queue
44763
+ backfill-anchors Retro-anchor resolved problems whose fix location lives only
44764
+ in prose ("addressed by an edit to \u2026") + run the canonical
44765
+ binder over the embedded backlog. Idempotent.
44175
44766
  locate <path> Print the File node + immediate symbols for a path
44176
44767
  neighbors <id> Walk the graph from a node (BFS depth 2)
44177
44768
  Flags: --depth N (1..5)
@@ -44720,7 +45311,7 @@ async function cmdLocate(relPath) {
44720
45311
  process.exit(2);
44721
45312
  }
44722
45313
  await ensureProfile();
44723
- const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports));
45314
+ const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
44724
45315
  const { workspacePaths: workspacePaths2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
44725
45316
  const paths = workspacePaths2(ROOT);
44726
45317
  const store = openGraphStore2({ path: paths.castalia });
@@ -44772,7 +45363,7 @@ async function cmdNeighbors(args2) {
44772
45363
  const depthIdx = args2.indexOf("--depth");
44773
45364
  const depth = depthIdx >= 0 && args2[depthIdx + 1] ? Math.max(1, Math.min(5, Number(args2[depthIdx + 1]))) : 2;
44774
45365
  await ensureProfile();
44775
- const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports));
45366
+ const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
44776
45367
  const { workspacePaths: workspacePaths2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
44777
45368
  const paths = workspacePaths2(ROOT);
44778
45369
  const store = openGraphStore2({ path: paths.castalia });
@@ -44820,7 +45411,7 @@ async function cmdNeighbors(args2) {
44820
45411
  }
44821
45412
  async function cmdTodos() {
44822
45413
  await ensureProfile();
44823
- const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports));
45414
+ const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
44824
45415
  const { workspacePaths: workspacePaths2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
44825
45416
  const paths = workspacePaths2(ROOT);
44826
45417
  const store = openGraphStore2({ path: paths.castalia });
@@ -44856,9 +45447,86 @@ async function cmdTodos() {
44856
45447
  store.close();
44857
45448
  }
44858
45449
  }
45450
+ async function cmdBackfillAnchors() {
45451
+ const profile = loadProfile(ROOT);
45452
+ await ensureProfile();
45453
+ const { anchorSolutionToDiff: anchorSolutionToDiff2, anchorProblemToDiff: anchorProblemToDiff2, deriveContextFromAnchors: deriveContextFromAnchors2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
45454
+ const { bindCanonicalNeighbors: bindCanonicalNeighbors2 } = await Promise.resolve().then(() => (init_src10(), src_exports4));
45455
+ const { digest: digest2 } = await Promise.resolve().then(() => (init_src(), src_exports));
45456
+ await withStore(async (store) => {
45457
+ const ts = Date.now();
45458
+ const wsId = profile.id;
45459
+ const PROSE = /^addressed by an edit to (.+)$/;
45460
+ let anchored = 0;
45461
+ let skipped = 0;
45462
+ for (const sol of store.findNodesByLabel("Solution")) {
45463
+ const m = PROSE.exec(sol.description.trim());
45464
+ if (!m) continue;
45465
+ if (store.outEdges(sol.id, ["ANCHORED_AT"]).length > 0) {
45466
+ skipped++;
45467
+ continue;
45468
+ }
45469
+ const target = m[1].trim();
45470
+ const problemIds = store.inEdges(sol.id, ["SOLVED_BY"]).map((e) => e.from).filter((id) => store.getNode(id)?.label === "Problem");
45471
+ const isPath = target.includes("/") || target.includes("\\");
45472
+ if (isPath) {
45473
+ anchorSolutionToDiff2(store, sol.id, [target], wsId, ts);
45474
+ for (const pid of problemIds) {
45475
+ anchorProblemToDiff2(store, pid, [target], wsId, ts);
45476
+ deriveContextFromAnchors2(store, pid, ts);
45477
+ }
45478
+ } else {
45479
+ const bare = target.includes(".") ? target.slice(target.lastIndexOf(".") + 1) : target;
45480
+ let sym = null;
45481
+ outer: for (const label of ["Function", "Method", "Class"]) {
45482
+ for (const n of store.findNodesByLabel(label)) {
45483
+ if (n.attrs["workspaceId"] && n.attrs["workspaceId"] !== wsId) continue;
45484
+ const qname = String(n.attrs["qname"] ?? "");
45485
+ if (qname === target || n.description === target) {
45486
+ sym = n;
45487
+ break outer;
45488
+ }
45489
+ if (!sym && (qname.endsWith(`.${bare}`) || n.description === bare)) sym = n;
45490
+ }
45491
+ }
45492
+ if (!sym) continue;
45493
+ for (const from of [sol.id, ...problemIds]) {
45494
+ store.mergeEdge({
45495
+ id: `edge_${digest2({ from, type: "ANCHORED_AT", to: sym.id })}`.slice(0, 24),
45496
+ from,
45497
+ to: sym.id,
45498
+ type: "ANCHORED_AT",
45499
+ confidence: 0.6,
45500
+ extractionSource: "daemon-extracted",
45501
+ createdAt: ts,
45502
+ lastSeenAt: ts,
45503
+ navSuccesses: 0,
45504
+ navFailures: 0,
45505
+ attrs: { provisional: true, backfill: true }
45506
+ });
45507
+ }
45508
+ for (const pid of problemIds) deriveContextFromAnchors2(store, pid, ts);
45509
+ }
45510
+ if (store.outEdges(sol.id, ["ANCHORED_AT"]).length > 0) {
45511
+ anchored++;
45512
+ store.updateNode(sol.id, {
45513
+ attrs: {
45514
+ ...sol.attrs,
45515
+ ...isPath ? { resolvedRelPath: target } : { resolvedSymbols: [target] }
45516
+ },
45517
+ lastUpdatedAt: ts
45518
+ });
45519
+ }
45520
+ }
45521
+ const cb = bindCanonicalNeighbors2(store, { ts });
45522
+ console.log(
45523
+ `backfill: anchored ${anchored} resolution(s) from prose (${skipped} already anchored); canonical-bind: +${cb.bound} machine link(s) across ${cb.scanned} embedded problem(s)`
45524
+ );
45525
+ });
45526
+ }
44859
45527
  async function withStore(fn) {
44860
45528
  await ensureProfile();
44861
- const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports));
45529
+ const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
44862
45530
  const { workspacePaths: workspacePaths2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
44863
45531
  const paths = workspacePaths2(ROOT);
44864
45532
  const store = openGraphStore2({ path: paths.castalia });
@@ -45233,7 +45901,7 @@ async function gatherRepo(store, ws) {
45233
45901
  }
45234
45902
  async function gatherReportData(generatedAt) {
45235
45903
  const { existsSync: existsSync20 } = await import("node:fs");
45236
- const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports));
45904
+ const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
45237
45905
  const cfg = loadConfig();
45238
45906
  const outbound = cfg.consent.sync ? "auto" : "off";
45239
45907
  const repos = [];
@@ -45964,7 +46632,7 @@ async function cmdFeedback(args2) {
45964
46632
  console.error('usage: errata feedback [up|down] "<message>"');
45965
46633
  process.exit(2);
45966
46634
  }
45967
- const { scrub: scrub2 } = await Promise.resolve().then(() => (init_src7(), src_exports2));
46635
+ const { scrub: scrub2 } = await Promise.resolve().then(() => (init_src7(), src_exports3));
45968
46636
  const scrubbed = scrub2(message).text;
45969
46637
  const c = authedCloudClient(cfg);
45970
46638
  try {