@inerrata-corporation/errata 2.0.0-dev.40 → 2.0.0-dev.42
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 +89 -19
- package/package.json +1 -1
- package/pass-worker.mjs +14 -3
package/errata.mjs
CHANGED
|
@@ -18445,7 +18445,7 @@ var init_triage = __esm({
|
|
|
18445
18445
|
// ../../packages/math/src/relevance.ts
|
|
18446
18446
|
function scoreRelevance(input, weights) {
|
|
18447
18447
|
const w = { ...DEFAULT_RELEVANCE_WEIGHTS, ...weights };
|
|
18448
|
-
const semantic = input.semantic
|
|
18448
|
+
const semantic = input.semantic != null ? clamp01((input.semantic - w.semanticFloor) / (1 - w.semanticFloor)) : input.semanticUnknown ? clamp01(w.semanticNeutral) : 1;
|
|
18449
18449
|
const specificity = 1 + w.specificityWeight * clamp01(input.specificity ?? 0);
|
|
18450
18450
|
const centrality = 1 + w.centralityWeight * Math.tanh((input.centrality ?? 0) / w.centralityScale);
|
|
18451
18451
|
const quality = 1 + w.qualityWeight * Math.tanh((input.quality ?? 0) / w.qualityScale);
|
|
@@ -18462,6 +18462,7 @@ var init_relevance = __esm({
|
|
|
18462
18462
|
"use strict";
|
|
18463
18463
|
DEFAULT_RELEVANCE_WEIGHTS = {
|
|
18464
18464
|
semanticFloor: 0.5,
|
|
18465
|
+
semanticNeutral: 0.4,
|
|
18465
18466
|
centralityWeight: 0.5,
|
|
18466
18467
|
centralityScale: 1,
|
|
18467
18468
|
qualityWeight: 0.4,
|
|
@@ -20054,11 +20055,15 @@ function buildSnapshot(opts) {
|
|
|
20054
20055
|
languages: opts.profile.languages.map((name2) => ({ name: name2, node: matchNode(langNodes, name2) })),
|
|
20055
20056
|
packages: opts.profile.stack.map((name2) => ({ name: name2, node: matchNode(pkgNodes, pkgBase(name2)) }))
|
|
20056
20057
|
};
|
|
20058
|
+
const causalNudge = recent.length >= 2 && recent.every(
|
|
20059
|
+
(r) => opts.store.outEdges(r.node.id, ["CAUSED_BY"]).length === 0 && opts.store.inEdges(r.node.id, ["CAUSED_BY"]).length === 0
|
|
20060
|
+
);
|
|
20057
20061
|
return {
|
|
20058
20062
|
profile: opts.profile,
|
|
20059
20063
|
profileContext,
|
|
20060
20064
|
recentProblems: recent,
|
|
20061
20065
|
recentResolved,
|
|
20066
|
+
...causalNudge ? { causalNudge } : {},
|
|
20062
20067
|
motifs,
|
|
20063
20068
|
reviewCount: opts.reviewCount,
|
|
20064
20069
|
reviewUiUrl: opts.reviewUiUrl,
|
|
@@ -20205,6 +20210,11 @@ function renderSnapshot(s) {
|
|
|
20205
20210
|
const surprise = (r.node.cumulativeSurprise ?? 0).toFixed(2);
|
|
20206
20211
|
lines.push(` - observed ${hits}\xD7 \xB7 cumulativeSurprise ${surprise}`);
|
|
20207
20212
|
}
|
|
20213
|
+
if (s.causalNudge) {
|
|
20214
|
+
lines.push(
|
|
20215
|
+
"_None of these problems are causally linked yet \u2014 if one caused another (or your report says so in prose), bind them with `(cause:#slug \u2026)` / `(cause:[handle])`. Trace can only follow edges you declare._"
|
|
20216
|
+
);
|
|
20217
|
+
}
|
|
20208
20218
|
}
|
|
20209
20219
|
if (s.recentResolved.length > 0) {
|
|
20210
20220
|
lines.push("_Recently resolved \u2014 solved here; jumping-off points, not live defects:_");
|
|
@@ -20358,12 +20368,17 @@ _${dropped} lower-priority item${dropped === 1 ? "" : "s"} omitted to fit the pa
|
|
|
20358
20368
|
}
|
|
20359
20369
|
return { body: body2, snapshot, dropped };
|
|
20360
20370
|
}
|
|
20361
|
-
var SEARCH_IMPERATIVE_HEADER, SEARCH_IMPERATIVE_BODY, EVICTION_ORDER, DEFAULT_AGENT_CONTEXT_BUDGET;
|
|
20371
|
+
var RECALL_FIRST_HEADER, RECALL_FIRST_BODY, RECALL_FIRST_BLOCK, SEARCH_IMPERATIVE_HEADER, SEARCH_IMPERATIVE_BODY, EVICTION_ORDER, DEFAULT_AGENT_CONTEXT_BUDGET;
|
|
20362
20372
|
var init_render = __esm({
|
|
20363
20373
|
"../../packages/context-writer/src/render.ts"() {
|
|
20364
20374
|
"use strict";
|
|
20365
20375
|
init_src4();
|
|
20366
20376
|
init_src2();
|
|
20377
|
+
RECALL_FIRST_HEADER = "## errata \u2014 recall before you work";
|
|
20378
|
+
RECALL_FIRST_BODY = "Before investigating any bug or error, your FIRST tool call must be `mcp__errata__errata_search` with a few words describing the problem. This machine's knowledge graph records previously solved problems \u2014 the answer may already be recorded. Read what it returns before touching any files.";
|
|
20379
|
+
RECALL_FIRST_BLOCK = `${RECALL_FIRST_HEADER}
|
|
20380
|
+
|
|
20381
|
+
${RECALL_FIRST_BODY}`;
|
|
20367
20382
|
SEARCH_IMPERATIVE_HEADER = "### \u{1F50E} PRIORS ARE SEEDS \u2014 a sample, not the whole graph";
|
|
20368
20383
|
SEARCH_IMPERATIVE_BODY = "Everything below is a budgeted, top-of-head slice of a much larger graph. Any prior id below is a live burst seed: `errata.burst` it (or read `.errata/g/burst/<id>`) to pull its wider neighborhood \u2014 causes, fixes, siblings. When a prior is adjacent-but-not-quite, or none fit, that gap is exactly when to search deeper before solving cold: a stuck search is itself a signal that routes help to you.";
|
|
20369
20384
|
EVICTION_ORDER = [
|
|
@@ -21361,7 +21376,7 @@ function loadConfig() {
|
|
|
21361
21376
|
saveConfig(cfg);
|
|
21362
21377
|
return cfg;
|
|
21363
21378
|
}
|
|
21364
|
-
const raw2 = readFileSync3(p, "utf8");
|
|
21379
|
+
const raw2 = readFileSync3(p, "utf8").replace(/^\uFEFF/, "");
|
|
21365
21380
|
const parsed = JSON.parse(raw2);
|
|
21366
21381
|
const base = defaultConfig();
|
|
21367
21382
|
return {
|
|
@@ -24583,6 +24598,18 @@ import { mkdirSync as mkdirSync4, existsSync as existsSync6 } from "node:fs";
|
|
|
24583
24598
|
import { homedir as homedir2 } from "node:os";
|
|
24584
24599
|
import { dirname as dirname3, join as join4 } from "node:path";
|
|
24585
24600
|
import { createRequire } from "node:module";
|
|
24601
|
+
function semanticFloorFor(version2) {
|
|
24602
|
+
if (version2 === EMBEDDING_VERSION) return 0.25;
|
|
24603
|
+
return 0.5;
|
|
24604
|
+
}
|
|
24605
|
+
function noteHashFallback() {
|
|
24606
|
+
if (warnedHashFallback) return;
|
|
24607
|
+
if (process.env["ERRATA_EMBED_HASH_ONLY"] === "1") return;
|
|
24608
|
+
warnedHashFallback = true;
|
|
24609
|
+
console.warn(
|
|
24610
|
+
`[errata] embedding model unavailable (${lastError?.message ?? "unknown"}) \u2014 falling back to ${EMBEDDING_VERSION} hash vectors; semantic ranking runs at reduced fidelity`
|
|
24611
|
+
);
|
|
24612
|
+
}
|
|
24586
24613
|
function getCacheDir() {
|
|
24587
24614
|
return process.env["ERRATA_MODEL_CACHE"] ?? join4(homedir2(), ".errata", "models");
|
|
24588
24615
|
}
|
|
@@ -24673,6 +24700,7 @@ async function embedBatchWithModelOrHash(texts) {
|
|
|
24673
24700
|
}
|
|
24674
24701
|
} catch {
|
|
24675
24702
|
}
|
|
24703
|
+
noteHashFallback();
|
|
24676
24704
|
return texts.map((t) => {
|
|
24677
24705
|
const v = embed(t);
|
|
24678
24706
|
return { vector: v, version: EMBEDDING_VERSION, dim: v.length };
|
|
@@ -24687,11 +24715,12 @@ async function embedTextWithModelOrHash(text) {
|
|
|
24687
24715
|
const v = await embedTextWithModel(text);
|
|
24688
24716
|
return { vector: v, version: MODEL_EMBEDDING_VERSION, dim: v.length };
|
|
24689
24717
|
} catch {
|
|
24718
|
+
noteHashFallback();
|
|
24690
24719
|
const v = embed(text);
|
|
24691
24720
|
return { vector: v, version: EMBEDDING_VERSION, dim: v.length };
|
|
24692
24721
|
}
|
|
24693
24722
|
}
|
|
24694
|
-
var MODEL_NAME, MODEL_EMBEDDING_DIM, MODEL_EMBEDDING_VERSION, pipelinePromise, lastError;
|
|
24723
|
+
var MODEL_NAME, MODEL_EMBEDDING_DIM, MODEL_EMBEDDING_VERSION, pipelinePromise, lastError, warnedHashFallback;
|
|
24695
24724
|
var init_model = __esm({
|
|
24696
24725
|
"../../packages/embedding/src/model.ts"() {
|
|
24697
24726
|
"use strict";
|
|
@@ -24701,6 +24730,7 @@ var init_model = __esm({
|
|
|
24701
24730
|
MODEL_EMBEDDING_VERSION = "minilm-l6-v2";
|
|
24702
24731
|
pipelinePromise = null;
|
|
24703
24732
|
lastError = null;
|
|
24733
|
+
warnedHashFallback = false;
|
|
24704
24734
|
}
|
|
24705
24735
|
});
|
|
24706
24736
|
|
|
@@ -25860,11 +25890,11 @@ var init_generalizer = __esm({
|
|
|
25860
25890
|
function layerOf(kind) {
|
|
25861
25891
|
return kind === "Technique" ? "technique" : kind === "AntiPattern" ? "antipattern" : "pattern";
|
|
25862
25892
|
}
|
|
25863
|
-
function motifTitle(members, layer) {
|
|
25893
|
+
function motifTitle(members, layer, instanceCount) {
|
|
25864
25894
|
const top = [...members].sort(
|
|
25865
25895
|
(a, b) => b.extractionConfidence - a.extractionConfidence
|
|
25866
25896
|
)[0];
|
|
25867
|
-
return `${layer}: ${top?.description ?? "recurring problem cluster"}`;
|
|
25897
|
+
return `${layer} \xD7${instanceCount} (exemplar): ${top?.description ?? "recurring problem cluster"}`;
|
|
25868
25898
|
}
|
|
25869
25899
|
function classifyMotif(store, instances, promoted) {
|
|
25870
25900
|
if (!promoted || instances.length === 0) return "Pattern";
|
|
@@ -25910,7 +25940,9 @@ function promoteMotifs(store, t) {
|
|
|
25910
25940
|
const motif = {
|
|
25911
25941
|
id: motifId,
|
|
25912
25942
|
label: kind,
|
|
25913
|
-
|
|
25943
|
+
// Refresh the deterministic title every run (exemplar/count/kind drift),
|
|
25944
|
+
// but never clobber a distilled one — a distillation pass owns it then.
|
|
25945
|
+
description: existing?.attrs["titleDistilled"] === true ? existing.description : motifTitle(members, layerOf(kind), instanceCount),
|
|
25914
25946
|
extractionConfidence: d.motifConfidence,
|
|
25915
25947
|
extractionSource: "bko-inferred",
|
|
25916
25948
|
embedding: existing?.embedding ?? [],
|
|
@@ -26121,8 +26153,8 @@ async function embedNodesByLabels(store, labels, opts = {}) {
|
|
|
26121
26153
|
durationMs: 0,
|
|
26122
26154
|
versionsSeen: {}
|
|
26123
26155
|
};
|
|
26124
|
-
const
|
|
26125
|
-
const currentVersion = probe[0]?.version ?? "unknown";
|
|
26156
|
+
const hashOnly = opts.mode === "hash";
|
|
26157
|
+
const currentVersion = hashOnly ? EMBEDDING_VERSION : (await embedBatchWithModelOrHash(["probe"]))[0]?.version ?? "unknown";
|
|
26126
26158
|
const todo = [];
|
|
26127
26159
|
for (const label of labels) {
|
|
26128
26160
|
for (const node2 of store.findNodesByLabel(label)) {
|
|
@@ -26131,6 +26163,10 @@ async function embedNodesByLabels(store, labels, opts = {}) {
|
|
|
26131
26163
|
if (existingVersion) {
|
|
26132
26164
|
report.versionsSeen[existingVersion] = (report.versionsSeen[existingVersion] ?? 0) + 1;
|
|
26133
26165
|
}
|
|
26166
|
+
if (hashOnly && node2.embedding.length > 0) {
|
|
26167
|
+
report.skippedFresh++;
|
|
26168
|
+
continue;
|
|
26169
|
+
}
|
|
26134
26170
|
if (!opts.force && existingVersion === currentVersion && node2.embedding.length > 0) {
|
|
26135
26171
|
report.skippedFresh++;
|
|
26136
26172
|
continue;
|
|
@@ -26144,7 +26180,10 @@ async function embedNodesByLabels(store, labels, opts = {}) {
|
|
|
26144
26180
|
const batch = todo.slice(i2, i2 + BATCH_SIZE);
|
|
26145
26181
|
let results;
|
|
26146
26182
|
try {
|
|
26147
|
-
results =
|
|
26183
|
+
results = hashOnly ? batch.map((b) => {
|
|
26184
|
+
const v = embed(b.text);
|
|
26185
|
+
return { vector: v, version: EMBEDDING_VERSION, dim: v.length };
|
|
26186
|
+
}) : await embedBatchWithModelOrHash(batch.map((b) => b.text));
|
|
26148
26187
|
} catch {
|
|
26149
26188
|
report.failed += batch.length;
|
|
26150
26189
|
continue;
|
|
@@ -26210,12 +26249,15 @@ function nodeFreshness(node2, currentIngestSeq) {
|
|
|
26210
26249
|
}
|
|
26211
26250
|
function scoreCandidate(candidate, ctx = {}, weights) {
|
|
26212
26251
|
const sameVersion = !ctx.seedEmbeddingVersion || !candidate.attrs["embeddingVersion"] || candidate.attrs["embeddingVersion"] === ctx.seedEmbeddingVersion;
|
|
26213
|
-
const
|
|
26252
|
+
const comparable = ctx.seedEmbedding != null && candidate.embedding.length === ctx.seedEmbedding.length && sameVersion;
|
|
26253
|
+
const semantic = comparable ? cosine(ctx.seedEmbedding, candidate.embedding) : void 0;
|
|
26254
|
+
const semanticUnknown = ctx.seedEmbedding != null && !comparable;
|
|
26214
26255
|
const quality = typeof candidate.attrs["effectivenessScore"] === "number" ? candidate.attrs["effectivenessScore"] : void 0;
|
|
26215
26256
|
const trustTier = candidate.attrs["trustTier"];
|
|
26216
26257
|
return scoreRelevance(
|
|
26217
26258
|
{
|
|
26218
26259
|
...semantic !== void 0 ? { semantic } : {},
|
|
26260
|
+
...semanticUnknown ? { semanticUnknown } : {},
|
|
26219
26261
|
centrality: candidate.pageRank,
|
|
26220
26262
|
...quality !== void 0 ? { quality } : {},
|
|
26221
26263
|
...ctx.specificity !== void 0 ? { specificity: ctx.specificity } : {},
|
|
@@ -26235,7 +26277,11 @@ function rankByRelevance(store, seedId, candidateIds, opts = {}) {
|
|
|
26235
26277
|
};
|
|
26236
26278
|
const nodes = candidateIds.map((id) => store.getNode(id)).filter((n) => n != null);
|
|
26237
26279
|
const maxPr = Math.max(1e-9, ...nodes.map((n) => n.pageRank));
|
|
26238
|
-
const weights = {
|
|
26280
|
+
const weights = {
|
|
26281
|
+
centralityScale: maxPr,
|
|
26282
|
+
...ctx.seedEmbedding ? { semanticFloor: semanticFloorFor(ctx.seedEmbeddingVersion) } : {},
|
|
26283
|
+
...opts.weights
|
|
26284
|
+
};
|
|
26239
26285
|
const now = store.currentIngestSeq();
|
|
26240
26286
|
return nodes.map((node2) => {
|
|
26241
26287
|
const r = scoreCandidate(node2, { ...ctx, decay: nodeFreshness(node2, now) }, weights);
|
|
@@ -26270,7 +26316,11 @@ function localBurst(store, seedId, opts = {}) {
|
|
|
26270
26316
|
const gated = seed.embedding.length > 0;
|
|
26271
26317
|
const nodes = [...hopOf.entries()].map(([id, hops]) => ({ node: store.getNode(id), hops })).filter((x) => x.node != null);
|
|
26272
26318
|
const maxPr = Math.max(1e-9, ...nodes.map((x) => x.node.pageRank));
|
|
26273
|
-
const weights = {
|
|
26319
|
+
const weights = {
|
|
26320
|
+
centralityScale: maxPr,
|
|
26321
|
+
...gated ? { semanticFloor: semanticFloorFor(ctxSeed.seedEmbeddingVersion) } : {},
|
|
26322
|
+
...opts.weights
|
|
26323
|
+
};
|
|
26274
26324
|
const now = store.currentIngestSeq();
|
|
26275
26325
|
return nodes.map(({ node: node2, hops }) => {
|
|
26276
26326
|
const r = scoreCandidate(node2, { ...ctxSeed, hops, decay: nodeFreshness(node2, now) }, weights);
|
|
@@ -36972,7 +37022,7 @@ function resolvePath(rawPath) {
|
|
|
36972
37022
|
const rest2 = segs.slice(1);
|
|
36973
37023
|
if (verb === "index" || verb === "README" || verb === "help") return { kind: "index" };
|
|
36974
37024
|
if (verb === "search") {
|
|
36975
|
-
const query = rest2.join(" ").trim();
|
|
37025
|
+
const query = rest2.join(" ").replace(/[-_]+/g, " ").trim();
|
|
36976
37026
|
if (!query) return null;
|
|
36977
37027
|
return { kind: "tool", tool: "errata.search", args: { query } };
|
|
36978
37028
|
}
|
|
@@ -42504,7 +42554,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
42504
42554
|
}
|
|
42505
42555
|
|
|
42506
42556
|
// src/engine.ts
|
|
42507
|
-
var DAEMON_VERSION = true ? "2.0.0-dev.
|
|
42557
|
+
var DAEMON_VERSION = true ? "2.0.0-dev.42" : "2.0.0-alpha.0";
|
|
42508
42558
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
42509
42559
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
42510
42560
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -43532,6 +43582,16 @@ function createWorkspaceEngine(opts) {
|
|
|
43532
43582
|
telemetry.count("problems_resolved", gen.problemsResolved);
|
|
43533
43583
|
telemetry.count("reviews_triggered", gen.reviewsTriggered);
|
|
43534
43584
|
telemetry.count("signals_credited", report.signalsCredited);
|
|
43585
|
+
if (gen.problemsWritten > 0) {
|
|
43586
|
+
try {
|
|
43587
|
+
const inline = await embedSemanticNodes(store, { mode: "hash" });
|
|
43588
|
+
if (inline.embedded > 0) {
|
|
43589
|
+
console.log(`[errata] inline-embedded ${inline.embedded} fresh semantic node(s) (hash)`);
|
|
43590
|
+
}
|
|
43591
|
+
} catch (err2) {
|
|
43592
|
+
console.warn("[errata] inline semantic embed failed:", err2 instanceof Error ? err2.message : err2);
|
|
43593
|
+
}
|
|
43594
|
+
}
|
|
43535
43595
|
const graphChanged = gen.problemsWritten + gen.problemsResolved + gen.problemsReinforced + gen.reviewsTriggered + report.signalsCredited > 0;
|
|
43536
43596
|
if (!opts.skipContextWriter && (graphChanged || contextDirty)) {
|
|
43537
43597
|
refreshContextNow();
|
|
@@ -47033,6 +47093,7 @@ async function installClaudeHooks(port) {
|
|
|
47033
47093
|
}
|
|
47034
47094
|
}
|
|
47035
47095
|
const matcher = "Read|Edit|Write|Grep|Glob|NotebookEdit|Bash";
|
|
47096
|
+
const postMatcher = `${matcher}|ToolSearch|mcp__errata__.*`;
|
|
47036
47097
|
const preCmd = `${hookCurlCommand(port)} ${ERRATA_TAG}`;
|
|
47037
47098
|
const postCmd = `${hookRelayCommand(port, "/api/hook")} ${ERRATA_TAG}`;
|
|
47038
47099
|
settings.hooks ??= {};
|
|
@@ -47041,13 +47102,13 @@ async function installClaudeHooks(port) {
|
|
|
47041
47102
|
if (list[i2].hooks.some((h) => h.command.includes(ERRATA_TAG))) list.splice(i2, 1);
|
|
47042
47103
|
}
|
|
47043
47104
|
};
|
|
47044
|
-
for (const [event, command] of [
|
|
47045
|
-
["PreToolUse", preCmd],
|
|
47046
|
-
["PostToolUse", postCmd]
|
|
47105
|
+
for (const [event, command, eventMatcher] of [
|
|
47106
|
+
["PreToolUse", preCmd, matcher],
|
|
47107
|
+
["PostToolUse", postCmd, postMatcher]
|
|
47047
47108
|
]) {
|
|
47048
47109
|
const list = settings.hooks[event] ??= [];
|
|
47049
47110
|
dropErrata(list);
|
|
47050
|
-
list.push({ matcher, hooks: [{ type: "command", command }] });
|
|
47111
|
+
list.push({ matcher: eventMatcher, hooks: [{ type: "command", command }] });
|
|
47051
47112
|
}
|
|
47052
47113
|
const turnCmd = `${hookCurlCommand(port, "/api/turn")} ${ERRATA_TAG}`;
|
|
47053
47114
|
for (const event of ["Stop", "SubagentStop"]) {
|
|
@@ -47074,6 +47135,15 @@ async function installClaudeHooks(port) {
|
|
|
47074
47135
|
writeFileSync16(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
47075
47136
|
console.log(`installed Claude Code hooks \u2192 ${file2}`);
|
|
47076
47137
|
await installClaudeMcpConfig();
|
|
47138
|
+
const claudeMd = join24(ROOT, "CLAUDE.md");
|
|
47139
|
+
const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
|
|
47140
|
+
if (recall.kind === "collision") {
|
|
47141
|
+
console.warn(
|
|
47142
|
+
` \u26A0\uFE0F CLAUDE.md errata block was hand-edited \u2014 leaving it alone (expected ${recall.expectedHash}, found ${recall.actualHash})`
|
|
47143
|
+
);
|
|
47144
|
+
} else {
|
|
47145
|
+
console.log(`installed recall-first block \u2192 ${claudeMd}`);
|
|
47146
|
+
}
|
|
47077
47147
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
47078
47148
|
}
|
|
47079
47149
|
async function installClaudeMcpConfig() {
|
package/package.json
CHANGED
package/pass-worker.mjs
CHANGED
|
@@ -25393,11 +25393,11 @@ var MEMBER_LABELS = ["Problem", "RootCause", "Solution"];
|
|
|
25393
25393
|
function layerOf(kind) {
|
|
25394
25394
|
return kind === "Technique" ? "technique" : kind === "AntiPattern" ? "antipattern" : "pattern";
|
|
25395
25395
|
}
|
|
25396
|
-
function motifTitle(members, layer) {
|
|
25396
|
+
function motifTitle(members, layer, instanceCount) {
|
|
25397
25397
|
const top = [...members].sort(
|
|
25398
25398
|
(a, b) => b.extractionConfidence - a.extractionConfidence
|
|
25399
25399
|
)[0];
|
|
25400
|
-
return `${layer}: ${top?.description ?? "recurring problem cluster"}`;
|
|
25400
|
+
return `${layer} \xD7${instanceCount} (exemplar): ${top?.description ?? "recurring problem cluster"}`;
|
|
25401
25401
|
}
|
|
25402
25402
|
function classifyMotif(store2, instances, promoted) {
|
|
25403
25403
|
if (!promoted || instances.length === 0) return "Pattern";
|
|
@@ -25443,7 +25443,9 @@ function promoteMotifs(store2, t) {
|
|
|
25443
25443
|
const motif = {
|
|
25444
25444
|
id: motifId,
|
|
25445
25445
|
label: kind,
|
|
25446
|
-
|
|
25446
|
+
// Refresh the deterministic title every run (exemplar/count/kind drift),
|
|
25447
|
+
// but never clobber a distilled one — a distillation pass owns it then.
|
|
25448
|
+
description: existing?.attrs["titleDistilled"] === true ? existing.description : motifTitle(members, layerOf(kind), instanceCount),
|
|
25447
25449
|
extractionConfidence: d.motifConfidence,
|
|
25448
25450
|
extractionSource: "bko-inferred",
|
|
25449
25451
|
embedding: existing?.embedding ?? [],
|
|
@@ -25681,11 +25683,15 @@ function buildSnapshot(opts) {
|
|
|
25681
25683
|
languages: opts.profile.languages.map((name2) => ({ name: name2, node: matchNode(langNodes, name2) })),
|
|
25682
25684
|
packages: opts.profile.stack.map((name2) => ({ name: name2, node: matchNode(pkgNodes, pkgBase(name2)) }))
|
|
25683
25685
|
};
|
|
25686
|
+
const causalNudge = recent.length >= 2 && recent.every(
|
|
25687
|
+
(r) => opts.store.outEdges(r.node.id, ["CAUSED_BY"]).length === 0 && opts.store.inEdges(r.node.id, ["CAUSED_BY"]).length === 0
|
|
25688
|
+
);
|
|
25684
25689
|
return {
|
|
25685
25690
|
profile: opts.profile,
|
|
25686
25691
|
profileContext,
|
|
25687
25692
|
recentProblems: recent,
|
|
25688
25693
|
recentResolved,
|
|
25694
|
+
...causalNudge ? { causalNudge } : {},
|
|
25689
25695
|
motifs,
|
|
25690
25696
|
reviewCount: opts.reviewCount,
|
|
25691
25697
|
reviewUiUrl: opts.reviewUiUrl,
|
|
@@ -25754,6 +25760,11 @@ function fileOf(store2, nodeId) {
|
|
|
25754
25760
|
}
|
|
25755
25761
|
return null;
|
|
25756
25762
|
}
|
|
25763
|
+
var RECALL_FIRST_HEADER = "## errata \u2014 recall before you work";
|
|
25764
|
+
var RECALL_FIRST_BODY = "Before investigating any bug or error, your FIRST tool call must be `mcp__errata__errata_search` with a few words describing the problem. This machine's knowledge graph records previously solved problems \u2014 the answer may already be recorded. Read what it returns before touching any files.";
|
|
25765
|
+
var RECALL_FIRST_BLOCK = `${RECALL_FIRST_HEADER}
|
|
25766
|
+
|
|
25767
|
+
${RECALL_FIRST_BODY}`;
|
|
25757
25768
|
|
|
25758
25769
|
// ../../packages/context-writer/src/select-durable-memory.ts
|
|
25759
25770
|
init_src2();
|