@inerrata-corporation/errata 2.0.0-dev.40 → 2.0.0-dev.41
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 +68 -13
- package/package.json +1 -1
- package/pass-worker.mjs +9 -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:_");
|
|
@@ -21361,7 +21371,7 @@ function loadConfig() {
|
|
|
21361
21371
|
saveConfig(cfg);
|
|
21362
21372
|
return cfg;
|
|
21363
21373
|
}
|
|
21364
|
-
const raw2 = readFileSync3(p, "utf8");
|
|
21374
|
+
const raw2 = readFileSync3(p, "utf8").replace(/^\uFEFF/, "");
|
|
21365
21375
|
const parsed = JSON.parse(raw2);
|
|
21366
21376
|
const base = defaultConfig();
|
|
21367
21377
|
return {
|
|
@@ -24583,6 +24593,18 @@ import { mkdirSync as mkdirSync4, existsSync as existsSync6 } from "node:fs";
|
|
|
24583
24593
|
import { homedir as homedir2 } from "node:os";
|
|
24584
24594
|
import { dirname as dirname3, join as join4 } from "node:path";
|
|
24585
24595
|
import { createRequire } from "node:module";
|
|
24596
|
+
function semanticFloorFor(version2) {
|
|
24597
|
+
if (version2 === EMBEDDING_VERSION) return 0.25;
|
|
24598
|
+
return 0.5;
|
|
24599
|
+
}
|
|
24600
|
+
function noteHashFallback() {
|
|
24601
|
+
if (warnedHashFallback) return;
|
|
24602
|
+
if (process.env["ERRATA_EMBED_HASH_ONLY"] === "1") return;
|
|
24603
|
+
warnedHashFallback = true;
|
|
24604
|
+
console.warn(
|
|
24605
|
+
`[errata] embedding model unavailable (${lastError?.message ?? "unknown"}) \u2014 falling back to ${EMBEDDING_VERSION} hash vectors; semantic ranking runs at reduced fidelity`
|
|
24606
|
+
);
|
|
24607
|
+
}
|
|
24586
24608
|
function getCacheDir() {
|
|
24587
24609
|
return process.env["ERRATA_MODEL_CACHE"] ?? join4(homedir2(), ".errata", "models");
|
|
24588
24610
|
}
|
|
@@ -24673,6 +24695,7 @@ async function embedBatchWithModelOrHash(texts) {
|
|
|
24673
24695
|
}
|
|
24674
24696
|
} catch {
|
|
24675
24697
|
}
|
|
24698
|
+
noteHashFallback();
|
|
24676
24699
|
return texts.map((t) => {
|
|
24677
24700
|
const v = embed(t);
|
|
24678
24701
|
return { vector: v, version: EMBEDDING_VERSION, dim: v.length };
|
|
@@ -24687,11 +24710,12 @@ async function embedTextWithModelOrHash(text) {
|
|
|
24687
24710
|
const v = await embedTextWithModel(text);
|
|
24688
24711
|
return { vector: v, version: MODEL_EMBEDDING_VERSION, dim: v.length };
|
|
24689
24712
|
} catch {
|
|
24713
|
+
noteHashFallback();
|
|
24690
24714
|
const v = embed(text);
|
|
24691
24715
|
return { vector: v, version: EMBEDDING_VERSION, dim: v.length };
|
|
24692
24716
|
}
|
|
24693
24717
|
}
|
|
24694
|
-
var MODEL_NAME, MODEL_EMBEDDING_DIM, MODEL_EMBEDDING_VERSION, pipelinePromise, lastError;
|
|
24718
|
+
var MODEL_NAME, MODEL_EMBEDDING_DIM, MODEL_EMBEDDING_VERSION, pipelinePromise, lastError, warnedHashFallback;
|
|
24695
24719
|
var init_model = __esm({
|
|
24696
24720
|
"../../packages/embedding/src/model.ts"() {
|
|
24697
24721
|
"use strict";
|
|
@@ -24701,6 +24725,7 @@ var init_model = __esm({
|
|
|
24701
24725
|
MODEL_EMBEDDING_VERSION = "minilm-l6-v2";
|
|
24702
24726
|
pipelinePromise = null;
|
|
24703
24727
|
lastError = null;
|
|
24728
|
+
warnedHashFallback = false;
|
|
24704
24729
|
}
|
|
24705
24730
|
});
|
|
24706
24731
|
|
|
@@ -25860,11 +25885,11 @@ var init_generalizer = __esm({
|
|
|
25860
25885
|
function layerOf(kind) {
|
|
25861
25886
|
return kind === "Technique" ? "technique" : kind === "AntiPattern" ? "antipattern" : "pattern";
|
|
25862
25887
|
}
|
|
25863
|
-
function motifTitle(members, layer) {
|
|
25888
|
+
function motifTitle(members, layer, instanceCount) {
|
|
25864
25889
|
const top = [...members].sort(
|
|
25865
25890
|
(a, b) => b.extractionConfidence - a.extractionConfidence
|
|
25866
25891
|
)[0];
|
|
25867
|
-
return `${layer}: ${top?.description ?? "recurring problem cluster"}`;
|
|
25892
|
+
return `${layer} \xD7${instanceCount} (exemplar): ${top?.description ?? "recurring problem cluster"}`;
|
|
25868
25893
|
}
|
|
25869
25894
|
function classifyMotif(store, instances, promoted) {
|
|
25870
25895
|
if (!promoted || instances.length === 0) return "Pattern";
|
|
@@ -25910,7 +25935,9 @@ function promoteMotifs(store, t) {
|
|
|
25910
25935
|
const motif = {
|
|
25911
25936
|
id: motifId,
|
|
25912
25937
|
label: kind,
|
|
25913
|
-
|
|
25938
|
+
// Refresh the deterministic title every run (exemplar/count/kind drift),
|
|
25939
|
+
// but never clobber a distilled one — a distillation pass owns it then.
|
|
25940
|
+
description: existing?.attrs["titleDistilled"] === true ? existing.description : motifTitle(members, layerOf(kind), instanceCount),
|
|
25914
25941
|
extractionConfidence: d.motifConfidence,
|
|
25915
25942
|
extractionSource: "bko-inferred",
|
|
25916
25943
|
embedding: existing?.embedding ?? [],
|
|
@@ -26121,8 +26148,8 @@ async function embedNodesByLabels(store, labels, opts = {}) {
|
|
|
26121
26148
|
durationMs: 0,
|
|
26122
26149
|
versionsSeen: {}
|
|
26123
26150
|
};
|
|
26124
|
-
const
|
|
26125
|
-
const currentVersion = probe[0]?.version ?? "unknown";
|
|
26151
|
+
const hashOnly = opts.mode === "hash";
|
|
26152
|
+
const currentVersion = hashOnly ? EMBEDDING_VERSION : (await embedBatchWithModelOrHash(["probe"]))[0]?.version ?? "unknown";
|
|
26126
26153
|
const todo = [];
|
|
26127
26154
|
for (const label of labels) {
|
|
26128
26155
|
for (const node2 of store.findNodesByLabel(label)) {
|
|
@@ -26131,6 +26158,10 @@ async function embedNodesByLabels(store, labels, opts = {}) {
|
|
|
26131
26158
|
if (existingVersion) {
|
|
26132
26159
|
report.versionsSeen[existingVersion] = (report.versionsSeen[existingVersion] ?? 0) + 1;
|
|
26133
26160
|
}
|
|
26161
|
+
if (hashOnly && node2.embedding.length > 0) {
|
|
26162
|
+
report.skippedFresh++;
|
|
26163
|
+
continue;
|
|
26164
|
+
}
|
|
26134
26165
|
if (!opts.force && existingVersion === currentVersion && node2.embedding.length > 0) {
|
|
26135
26166
|
report.skippedFresh++;
|
|
26136
26167
|
continue;
|
|
@@ -26144,7 +26175,10 @@ async function embedNodesByLabels(store, labels, opts = {}) {
|
|
|
26144
26175
|
const batch = todo.slice(i2, i2 + BATCH_SIZE);
|
|
26145
26176
|
let results;
|
|
26146
26177
|
try {
|
|
26147
|
-
results =
|
|
26178
|
+
results = hashOnly ? batch.map((b) => {
|
|
26179
|
+
const v = embed(b.text);
|
|
26180
|
+
return { vector: v, version: EMBEDDING_VERSION, dim: v.length };
|
|
26181
|
+
}) : await embedBatchWithModelOrHash(batch.map((b) => b.text));
|
|
26148
26182
|
} catch {
|
|
26149
26183
|
report.failed += batch.length;
|
|
26150
26184
|
continue;
|
|
@@ -26210,12 +26244,15 @@ function nodeFreshness(node2, currentIngestSeq) {
|
|
|
26210
26244
|
}
|
|
26211
26245
|
function scoreCandidate(candidate, ctx = {}, weights) {
|
|
26212
26246
|
const sameVersion = !ctx.seedEmbeddingVersion || !candidate.attrs["embeddingVersion"] || candidate.attrs["embeddingVersion"] === ctx.seedEmbeddingVersion;
|
|
26213
|
-
const
|
|
26247
|
+
const comparable = ctx.seedEmbedding != null && candidate.embedding.length === ctx.seedEmbedding.length && sameVersion;
|
|
26248
|
+
const semantic = comparable ? cosine(ctx.seedEmbedding, candidate.embedding) : void 0;
|
|
26249
|
+
const semanticUnknown = ctx.seedEmbedding != null && !comparable;
|
|
26214
26250
|
const quality = typeof candidate.attrs["effectivenessScore"] === "number" ? candidate.attrs["effectivenessScore"] : void 0;
|
|
26215
26251
|
const trustTier = candidate.attrs["trustTier"];
|
|
26216
26252
|
return scoreRelevance(
|
|
26217
26253
|
{
|
|
26218
26254
|
...semantic !== void 0 ? { semantic } : {},
|
|
26255
|
+
...semanticUnknown ? { semanticUnknown } : {},
|
|
26219
26256
|
centrality: candidate.pageRank,
|
|
26220
26257
|
...quality !== void 0 ? { quality } : {},
|
|
26221
26258
|
...ctx.specificity !== void 0 ? { specificity: ctx.specificity } : {},
|
|
@@ -26235,7 +26272,11 @@ function rankByRelevance(store, seedId, candidateIds, opts = {}) {
|
|
|
26235
26272
|
};
|
|
26236
26273
|
const nodes = candidateIds.map((id) => store.getNode(id)).filter((n) => n != null);
|
|
26237
26274
|
const maxPr = Math.max(1e-9, ...nodes.map((n) => n.pageRank));
|
|
26238
|
-
const weights = {
|
|
26275
|
+
const weights = {
|
|
26276
|
+
centralityScale: maxPr,
|
|
26277
|
+
...ctx.seedEmbedding ? { semanticFloor: semanticFloorFor(ctx.seedEmbeddingVersion) } : {},
|
|
26278
|
+
...opts.weights
|
|
26279
|
+
};
|
|
26239
26280
|
const now = store.currentIngestSeq();
|
|
26240
26281
|
return nodes.map((node2) => {
|
|
26241
26282
|
const r = scoreCandidate(node2, { ...ctx, decay: nodeFreshness(node2, now) }, weights);
|
|
@@ -26270,7 +26311,11 @@ function localBurst(store, seedId, opts = {}) {
|
|
|
26270
26311
|
const gated = seed.embedding.length > 0;
|
|
26271
26312
|
const nodes = [...hopOf.entries()].map(([id, hops]) => ({ node: store.getNode(id), hops })).filter((x) => x.node != null);
|
|
26272
26313
|
const maxPr = Math.max(1e-9, ...nodes.map((x) => x.node.pageRank));
|
|
26273
|
-
const weights = {
|
|
26314
|
+
const weights = {
|
|
26315
|
+
centralityScale: maxPr,
|
|
26316
|
+
...gated ? { semanticFloor: semanticFloorFor(ctxSeed.seedEmbeddingVersion) } : {},
|
|
26317
|
+
...opts.weights
|
|
26318
|
+
};
|
|
26274
26319
|
const now = store.currentIngestSeq();
|
|
26275
26320
|
return nodes.map(({ node: node2, hops }) => {
|
|
26276
26321
|
const r = scoreCandidate(node2, { ...ctxSeed, hops, decay: nodeFreshness(node2, now) }, weights);
|
|
@@ -42504,7 +42549,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
42504
42549
|
}
|
|
42505
42550
|
|
|
42506
42551
|
// src/engine.ts
|
|
42507
|
-
var DAEMON_VERSION = true ? "2.0.0-dev.
|
|
42552
|
+
var DAEMON_VERSION = true ? "2.0.0-dev.41" : "2.0.0-alpha.0";
|
|
42508
42553
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
42509
42554
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
42510
42555
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -43532,6 +43577,16 @@ function createWorkspaceEngine(opts) {
|
|
|
43532
43577
|
telemetry.count("problems_resolved", gen.problemsResolved);
|
|
43533
43578
|
telemetry.count("reviews_triggered", gen.reviewsTriggered);
|
|
43534
43579
|
telemetry.count("signals_credited", report.signalsCredited);
|
|
43580
|
+
if (gen.problemsWritten > 0) {
|
|
43581
|
+
try {
|
|
43582
|
+
const inline = await embedSemanticNodes(store, { mode: "hash" });
|
|
43583
|
+
if (inline.embedded > 0) {
|
|
43584
|
+
console.log(`[errata] inline-embedded ${inline.embedded} fresh semantic node(s) (hash)`);
|
|
43585
|
+
}
|
|
43586
|
+
} catch (err2) {
|
|
43587
|
+
console.warn("[errata] inline semantic embed failed:", err2 instanceof Error ? err2.message : err2);
|
|
43588
|
+
}
|
|
43589
|
+
}
|
|
43535
43590
|
const graphChanged = gen.problemsWritten + gen.problemsResolved + gen.problemsReinforced + gen.reviewsTriggered + report.signalsCredited > 0;
|
|
43536
43591
|
if (!opts.skipContextWriter && (graphChanged || contextDirty)) {
|
|
43537
43592
|
refreshContextNow();
|
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,
|