@inerrata-corporation/errata 2.0.2-dev.261 → 2.0.2-dev.282
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 +160 -9
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -20500,6 +20500,56 @@ function induceTriage(l2, opts) {
|
|
|
20500
20500
|
}
|
|
20501
20501
|
return report;
|
|
20502
20502
|
}
|
|
20503
|
+
function pendingDiscriminators(l2, opts = {}) {
|
|
20504
|
+
const minSources = opts.minSources ?? 1;
|
|
20505
|
+
const minObservations = opts.minObservations ?? 2;
|
|
20506
|
+
const out2 = [];
|
|
20507
|
+
for (const triage of l2.findNodesByLabel("Triage")) {
|
|
20508
|
+
for (const e of l2.outEdges(triage.id, [...ROUTE_EDGE_TYPES])) {
|
|
20509
|
+
if (isRouterRoute(e)) continue;
|
|
20510
|
+
if (typeof e.attrs["discriminator"] === "string") continue;
|
|
20511
|
+
if (opts.onlyUnsurfaced && e.attrs["discriminatorAsked"] === true) continue;
|
|
20512
|
+
const perContext = e.attrs["perContext"] ?? {};
|
|
20513
|
+
const global2 = perContext[TRIAGE_GLOBAL_BUCKET] ?? {};
|
|
20514
|
+
const observations = Number(global2.confirmed ?? 0);
|
|
20515
|
+
const sources = new Set(global2.contributors ?? []).size;
|
|
20516
|
+
if (sources < minSources || observations < minObservations) continue;
|
|
20517
|
+
out2.push({ route: e.id, presenting: triage.description, cause: "", sources, observations, causeId: e.to });
|
|
20518
|
+
}
|
|
20519
|
+
}
|
|
20520
|
+
out2.sort((a, b) => b.sources - a.sources || b.observations - a.observations);
|
|
20521
|
+
const top = typeof opts.limit === "number" ? out2.slice(0, opts.limit) : out2;
|
|
20522
|
+
for (const p of top) p.cause = l2.getNode(p.causeId)?.description ?? "(missing cause)";
|
|
20523
|
+
return top;
|
|
20524
|
+
}
|
|
20525
|
+
function markDiscriminatorAsked(l2, routeIds, ts) {
|
|
20526
|
+
for (const id of routeIds) {
|
|
20527
|
+
const e = l2.getEdge(id);
|
|
20528
|
+
if (!e) continue;
|
|
20529
|
+
l2.updateEdge(id, { attrs: { ...e.attrs, discriminatorAsked: true }, lastSeenAt: ts });
|
|
20530
|
+
}
|
|
20531
|
+
}
|
|
20532
|
+
function promoteRouteWithDiscriminator(l2, routeId, discriminator, ts, source) {
|
|
20533
|
+
const test = discriminator.trim();
|
|
20534
|
+
if (!test) return false;
|
|
20535
|
+
const existing = l2.getEdge(routeId);
|
|
20536
|
+
if (!existing || !ROUTE_EDGE_TYPES.includes(existing.type)) return false;
|
|
20537
|
+
const attrs = {
|
|
20538
|
+
...existing.attrs,
|
|
20539
|
+
discriminator: test,
|
|
20540
|
+
provisional: false,
|
|
20541
|
+
...source ? { discriminatorSource: source } : {}
|
|
20542
|
+
};
|
|
20543
|
+
delete attrs["discriminatorAsked"];
|
|
20544
|
+
const wantType = routeTypeFor(false);
|
|
20545
|
+
if (existing.type === wantType) {
|
|
20546
|
+
l2.updateEdge(routeId, { attrs, lastSeenAt: ts });
|
|
20547
|
+
return true;
|
|
20548
|
+
}
|
|
20549
|
+
l2.deleteEdge(routeId);
|
|
20550
|
+
l2.mergeEdge({ ...existing, type: wantType, attrs, lastSeenAt: ts });
|
|
20551
|
+
return true;
|
|
20552
|
+
}
|
|
20503
20553
|
function revisitStaleRoutes(l2, ts, opts = {}) {
|
|
20504
20554
|
const minNavFailures = opts.minNavFailures ?? 3;
|
|
20505
20555
|
const report = { flagged: 0, demoted: 0 };
|
|
@@ -20560,15 +20610,20 @@ function parseTriageFences(text) {
|
|
|
20560
20610
|
while ((m = block.exec(text)) !== null) {
|
|
20561
20611
|
const fields = {};
|
|
20562
20612
|
for (const line of m[1].split(/\r?\n/)) {
|
|
20563
|
-
const kv = /^\s*(presenting|cause|test|fix|drift)\s*:\s*(.+?)\s*$/i.exec(line);
|
|
20613
|
+
const kv = /^\s*(presenting|cause|test|fix|drift|route)\s*:\s*(.+?)\s*$/i.exec(line);
|
|
20564
20614
|
if (kv) fields[kv[1].toLowerCase()] = kv[2].trim();
|
|
20565
20615
|
}
|
|
20616
|
+
if (fields["route"] && fields["test"]) {
|
|
20617
|
+
out2.push({ presenting: "", cause: "", route: fields["route"], test: fields["test"] });
|
|
20618
|
+
continue;
|
|
20619
|
+
}
|
|
20566
20620
|
if (!fields["presenting"] || !fields["cause"]) continue;
|
|
20567
20621
|
const drift = fields["drift"]?.toLowerCase();
|
|
20568
20622
|
out2.push({
|
|
20569
20623
|
presenting: fields["presenting"],
|
|
20570
20624
|
cause: fields["cause"],
|
|
20571
20625
|
...fields["test"] ? { test: fields["test"] } : {},
|
|
20626
|
+
...fields["route"] ? { route: fields["route"] } : {},
|
|
20572
20627
|
...fields["fix"] ? { fix: fields["fix"] } : {},
|
|
20573
20628
|
...drift && DRIFT_VALUES.has(drift) ? { drift } : {}
|
|
20574
20629
|
});
|
|
@@ -20577,7 +20632,12 @@ function parseTriageFences(text) {
|
|
|
20577
20632
|
}
|
|
20578
20633
|
function harvestTriageFences(l2, text, opts) {
|
|
20579
20634
|
let recorded = 0;
|
|
20635
|
+
let promoted = 0;
|
|
20580
20636
|
for (const f of parseTriageFences(text)) {
|
|
20637
|
+
if (f.route && f.test) {
|
|
20638
|
+
if (promoteRouteWithDiscriminator(l2, f.route.trim(), f.test, opts.ts, opts.contributor)) promoted++;
|
|
20639
|
+
continue;
|
|
20640
|
+
}
|
|
20581
20641
|
const cause = f.cause.trim();
|
|
20582
20642
|
const causeId = `dcause_${digest({ statement: cause })}`.slice(0, 56);
|
|
20583
20643
|
recordTriageObservation(
|
|
@@ -20608,7 +20668,7 @@ function harvestTriageFences(l2, text, opts) {
|
|
|
20608
20668
|
}
|
|
20609
20669
|
recorded++;
|
|
20610
20670
|
}
|
|
20611
|
-
return { recorded };
|
|
20671
|
+
return { recorded, promoted };
|
|
20612
20672
|
}
|
|
20613
20673
|
var COOCCUR_BONUS, routeEdgeId, ROUTE_EDGE_TYPES, routeTypeFor, isRouterRoute, INDUCTED_MARK, DRIFT_VALUES;
|
|
20614
20674
|
var init_triage2 = __esm({
|
|
@@ -20981,6 +21041,7 @@ __export(src_exports2, {
|
|
|
20981
21041
|
linkProblemToSymbols: () => linkProblemToSymbols,
|
|
20982
21042
|
listNeedsRevisit: () => listNeedsRevisit,
|
|
20983
21043
|
localEdgeViolation: () => localEdgeViolation,
|
|
21044
|
+
markDiscriminatorAsked: () => markDiscriminatorAsked,
|
|
20984
21045
|
markRevisit: () => markRevisit,
|
|
20985
21046
|
matchLanguagesInText: () => matchLanguagesInText,
|
|
20986
21047
|
matchPackagesInText: () => matchPackagesInText,
|
|
@@ -20997,8 +21058,10 @@ __export(src_exports2, {
|
|
|
20997
21058
|
parseSemver: () => parseSemver,
|
|
20998
21059
|
parseTriageFences: () => parseTriageFences,
|
|
20999
21060
|
pendingAbstractions: () => pendingAbstractions,
|
|
21061
|
+
pendingDiscriminators: () => pendingDiscriminators,
|
|
21000
21062
|
percolate: () => percolate,
|
|
21001
21063
|
priorsForFile: () => priorsForFile,
|
|
21064
|
+
promoteRouteWithDiscriminator: () => promoteRouteWithDiscriminator,
|
|
21002
21065
|
propagateFactChange: () => propagateFactChange,
|
|
21003
21066
|
propagateVersionChange: () => propagateVersionChange,
|
|
21004
21067
|
rankToolsForHandles: () => rankToolsForHandles,
|
|
@@ -36969,6 +37032,36 @@ function takeEnrichmentNudge(store) {
|
|
|
36969
37032
|
return `\u26A1 errata \u2014 ${pulls.length} recent fix(es) await a one-line root cause (optional, answer in-flow):
|
|
36970
37033
|
` + items;
|
|
36971
37034
|
}
|
|
37035
|
+
function takeDiscriminatorNudge(path2) {
|
|
37036
|
+
if (!path2 || !existsSync10(path2)) return null;
|
|
37037
|
+
let shared;
|
|
37038
|
+
try {
|
|
37039
|
+
shared = openGraphStore({ path: path2 });
|
|
37040
|
+
} catch {
|
|
37041
|
+
return null;
|
|
37042
|
+
}
|
|
37043
|
+
try {
|
|
37044
|
+
const pending = pendingDiscriminators(shared, { limit: 1, onlyUnsurfaced: true });
|
|
37045
|
+
const top = pending[0];
|
|
37046
|
+
if (!top) return null;
|
|
37047
|
+
markDiscriminatorAsked(shared, [top.route], Date.now());
|
|
37048
|
+
return [
|
|
37049
|
+
`\u26A1 errata \u2014 a known wrong-door is one field from ranking: "${top.presenting.slice(0, 90)}"`,
|
|
37050
|
+
` usually turns out to be: ${top.cause.slice(0, 90)} (seen ${top.observations}x)`,
|
|
37051
|
+
" Know a CHEAP check that confirms it? Answer in-flow \u2014 it promotes the route so the",
|
|
37052
|
+
" next agent gets it first. Only if you actually know one: a guessed test ranks first",
|
|
37053
|
+
" and misroutes everyone after you.",
|
|
37054
|
+
" ```errata-triage",
|
|
37055
|
+
` route: ${top.route}`,
|
|
37056
|
+
" test: <the cheap check>",
|
|
37057
|
+
" ```"
|
|
37058
|
+
].join("\n");
|
|
37059
|
+
} catch {
|
|
37060
|
+
return null;
|
|
37061
|
+
} finally {
|
|
37062
|
+
shared.close();
|
|
37063
|
+
}
|
|
37064
|
+
}
|
|
36972
37065
|
function commentAnchorId(store, commentId) {
|
|
36973
37066
|
const out2 = store.outEdges(commentId, ["EXPLAINS", "ANNOTATES"]);
|
|
36974
37067
|
if (out2.length > 0) return out2[0].to;
|
|
@@ -37176,6 +37269,7 @@ function createMcpHandler(store, ctx = {}) {
|
|
|
37176
37269
|
let auditReadRun = 0;
|
|
37177
37270
|
let toolCallIndex = 0;
|
|
37178
37271
|
let lastAuditNudgeAt = Number.NEGATIVE_INFINITY;
|
|
37272
|
+
let lastDiscriminatorNudgeAt = Number.NEGATIVE_INFINITY;
|
|
37179
37273
|
return async function handle2(req) {
|
|
37180
37274
|
const id = req.id ?? null;
|
|
37181
37275
|
const isNotification = req.id === void 0;
|
|
@@ -37222,6 +37316,7 @@ function createMcpHandler(store, ctx = {}) {
|
|
|
37222
37316
|
{ type: "text", text: JSON.stringify(out2, null, 2) }
|
|
37223
37317
|
];
|
|
37224
37318
|
const isEnrichmentTool = params.name === "errata.pending_enrichment" || params.name === "errata.annotate_resolution";
|
|
37319
|
+
const isTriageTool = params.name === "errata.pending_discriminators" || params.name === "errata.triage";
|
|
37225
37320
|
toolCallIndex++;
|
|
37226
37321
|
auditReadRun = isEnrichmentTool ? 0 : auditReadRun + 1;
|
|
37227
37322
|
if (!isEnrichmentTool) {
|
|
@@ -37233,6 +37328,13 @@ function createMcpHandler(store, ctx = {}) {
|
|
|
37233
37328
|
lastAuditNudgeAt = toolCallIndex;
|
|
37234
37329
|
auditReadRun = 0;
|
|
37235
37330
|
}
|
|
37331
|
+
if (!isTriageTool && content.length === 1 && toolCallIndex - lastDiscriminatorNudgeAt >= DISCRIMINATOR_NUDGE_COOLDOWN) {
|
|
37332
|
+
const disc = takeDiscriminatorNudge(ctx.sharedDbPath);
|
|
37333
|
+
if (disc) {
|
|
37334
|
+
content.push({ type: "text", text: disc });
|
|
37335
|
+
lastDiscriminatorNudgeAt = toolCallIndex;
|
|
37336
|
+
}
|
|
37337
|
+
}
|
|
37236
37338
|
return { jsonrpc: "2.0", id, result: { content } };
|
|
37237
37339
|
}
|
|
37238
37340
|
default:
|
|
@@ -37282,7 +37384,11 @@ async function runMcpServer(workspaceRoot) {
|
|
|
37282
37384
|
}
|
|
37283
37385
|
return summariesMemo.map;
|
|
37284
37386
|
};
|
|
37285
|
-
const handle2 = createMcpHandler(store, {
|
|
37387
|
+
const handle2 = createMcpHandler(store, {
|
|
37388
|
+
...buildToolContext(),
|
|
37389
|
+
symbolSummaries,
|
|
37390
|
+
sharedDbPath: sharedStorePath()
|
|
37391
|
+
});
|
|
37286
37392
|
process.stdin.setEncoding("utf8");
|
|
37287
37393
|
let buffer = "";
|
|
37288
37394
|
process.stdin.on("data", (chunk) => {
|
|
@@ -37310,7 +37416,7 @@ async function runMcpServer(workspaceRoot) {
|
|
|
37310
37416
|
if (resp) process.stdout.write(JSON.stringify(resp) + "\n");
|
|
37311
37417
|
}
|
|
37312
37418
|
}
|
|
37313
|
-
var INSTRUCTIONS, AUDIT_RUN_THRESHOLD, AUDIT_NUDGE_COOLDOWN, AUDIT_FLAG_NUDGE, TOOLS;
|
|
37419
|
+
var INSTRUCTIONS, AUDIT_RUN_THRESHOLD, AUDIT_NUDGE_COOLDOWN, DISCRIMINATOR_NUDGE_COOLDOWN, AUDIT_FLAG_NUDGE, TOOLS;
|
|
37314
37420
|
var init_mcp = __esm({
|
|
37315
37421
|
"src/mcp.ts"() {
|
|
37316
37422
|
"use strict";
|
|
@@ -37371,6 +37477,7 @@ var init_mcp = __esm({
|
|
|
37371
37477
|
].join("\n");
|
|
37372
37478
|
AUDIT_RUN_THRESHOLD = 5;
|
|
37373
37479
|
AUDIT_NUDGE_COOLDOWN = 12;
|
|
37480
|
+
DISCRIMINATOR_NUDGE_COOLDOWN = 40;
|
|
37374
37481
|
AUDIT_FLAG_NUDGE = "\u26A1 errata \u2014 reading/auditing? anything you notice that's off, flag it inline as `[!one line]` (`[?\u2026]` = TODO) \u2014 no tool call, we harvest it.";
|
|
37375
37482
|
TOOLS = [
|
|
37376
37483
|
{
|
|
@@ -38396,6 +38503,47 @@ var init_mcp = __esm({
|
|
|
38396
38503
|
}
|
|
38397
38504
|
}
|
|
38398
38505
|
},
|
|
38506
|
+
{
|
|
38507
|
+
name: "errata.pending_discriminators",
|
|
38508
|
+
description: "Routes awaiting the ONE field that promotes them to routers (PLAN_TRIAGE). A route is a known wrong-door \u2014 symptom S usually turns out to be cause C \u2014 but it only ranks as a ROUTER once someone supplies its `discriminator`: the cheap ante-hoc test that confirms C before you commit. Returns provisional routes corroborated by 2+ DISTINCT CONTRIBUTORS, most-corroborated first; these are one field away from ranking every future `errata.triage` on that symptom. Answer only where you actually know a cheap check \u2014 a guessed test is worse than none, because it ranks first and sends the next agent down it. Empty = nothing awaiting. Reads the machine-wide shared store.",
|
|
38509
|
+
inputSchema: {
|
|
38510
|
+
type: "object",
|
|
38511
|
+
properties: {
|
|
38512
|
+
limit: { type: "number", description: "Max routes to return (default 10)." },
|
|
38513
|
+
minSources: { type: "number", description: "Min distinct contributors behind the route (default 2)." }
|
|
38514
|
+
}
|
|
38515
|
+
},
|
|
38516
|
+
handler: (args2) => {
|
|
38517
|
+
const path2 = sharedStorePath();
|
|
38518
|
+
if (!existsSync10(path2)) return { count: 0, pending: [] };
|
|
38519
|
+
const shared = openGraphStore({ path: path2 });
|
|
38520
|
+
try {
|
|
38521
|
+
const pending = pendingDiscriminators(shared, {
|
|
38522
|
+
limit: typeof args2?.limit === "number" ? args2.limit : 10,
|
|
38523
|
+
...typeof args2?.minSources === "number" ? { minSources: args2.minSources } : {}
|
|
38524
|
+
});
|
|
38525
|
+
return {
|
|
38526
|
+
count: pending.length,
|
|
38527
|
+
pending,
|
|
38528
|
+
...pending.length > 0 ? {
|
|
38529
|
+
howToAnswer: [
|
|
38530
|
+
"For each route you know a cheap test for, emit an errata-triage fence",
|
|
38531
|
+
"carrying its `route` id and the `test` \u2014 no presenting/cause needed, the",
|
|
38532
|
+
"route id identifies both endpoints. Attaching a test does NOT count as",
|
|
38533
|
+
"another sighting, so it cannot inflate the route's evidence.",
|
|
38534
|
+
"",
|
|
38535
|
+
"```errata-triage",
|
|
38536
|
+
"route: <route id from above>",
|
|
38537
|
+
"test: <the cheap check that confirms this cause>",
|
|
38538
|
+
"```"
|
|
38539
|
+
].join("\n")
|
|
38540
|
+
} : {}
|
|
38541
|
+
};
|
|
38542
|
+
} finally {
|
|
38543
|
+
shared.close();
|
|
38544
|
+
}
|
|
38545
|
+
}
|
|
38546
|
+
},
|
|
38399
38547
|
{
|
|
38400
38548
|
name: "errata.triage",
|
|
38401
38549
|
description: "Before you chase a problem, TRIAGE it \u2014 is it a known wrong-door? (PLAN_TRIAGE). Pass the problem you're about to work on (`problem`: a one-line statement, or `id`: a dprob_\u2026 id) and YOUR context (`stack`, `domain`) so the probabilities are conditioned on it \u2014 a symptom routes to different causes on different stacks. Returns the differential: candidate causes ranked router-first then by context-conditioned probability \u2014 {route, cause:{description}, probability, sampleSize, trust, router, discriminator, solutions:[\u2026]}. `probability` is P(cause | symptom, your context); `trust`/`sampleSize` tell you how much evidence stands behind it. Run the top router's `discriminator` (a cheap check) before committing. Empty = not a known wrong-door. Reads the machine-wide shared store.",
|
|
@@ -52664,7 +52812,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
52664
52812
|
}
|
|
52665
52813
|
|
|
52666
52814
|
// src/engine.ts
|
|
52667
|
-
var DAEMON_VERSION = true ? "2.0.2-dev.
|
|
52815
|
+
var DAEMON_VERSION = true ? "2.0.2-dev.282" : "2.0.0-alpha.0";
|
|
52668
52816
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
52669
52817
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
52670
52818
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -54537,8 +54685,8 @@ function contributedWireId(n) {
|
|
|
54537
54685
|
return isMembraneSaltedId(cloudId) ? cloudId : n.id;
|
|
54538
54686
|
}
|
|
54539
54687
|
var WIRE_CANONICAL_ID_MIN = 6;
|
|
54540
|
-
function unshippableReason(
|
|
54541
|
-
|
|
54688
|
+
function unshippableReason(canonical, label) {
|
|
54689
|
+
void label;
|
|
54542
54690
|
if (canonical.length < WIRE_CANONICAL_ID_MIN) {
|
|
54543
54691
|
return `canonicalId "${canonical}" is ${canonical.length} chars; the door requires >= ${WIRE_CANONICAL_ID_MIN}`;
|
|
54544
54692
|
}
|
|
@@ -54552,6 +54700,9 @@ function wireContextId(n) {
|
|
|
54552
54700
|
if (n.label === "Domain" && n.attrs["source"] !== "cloud") {
|
|
54553
54701
|
return String(n.attrs["canonicalId"] ?? n.id);
|
|
54554
54702
|
}
|
|
54703
|
+
if (n.label === "Component" && n.attrs["source"] !== "cloud") {
|
|
54704
|
+
return String(n.attrs["canonicalId"] ?? n.id);
|
|
54705
|
+
}
|
|
54555
54706
|
return n.id;
|
|
54556
54707
|
}
|
|
54557
54708
|
function langAnchor(t) {
|
|
@@ -54621,7 +54772,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
54621
54772
|
}
|
|
54622
54773
|
if (label === "Solution" && n.description.startsWith(AUTO_MINT_PREFIX)) continue;
|
|
54623
54774
|
if (!noveltyAgainst(n, ref, noveltyOpts).ready) continue;
|
|
54624
|
-
const reject = unshippableReason(n);
|
|
54775
|
+
const reject = unshippableReason(n.id, n.label);
|
|
54625
54776
|
if (reject) {
|
|
54626
54777
|
console.warn(`[errata] skipping unshippable node ${n.id} (${n.label}): ${reject}`);
|
|
54627
54778
|
continue;
|
|
@@ -54675,7 +54826,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
54675
54826
|
anchorDigests[sourceId] = dg;
|
|
54676
54827
|
const wireFrom = seen.has(sourceId) || !sourceNode ? sourceId : contributedWireId(sourceNode);
|
|
54677
54828
|
for (const { e, t, wireId } of targets) {
|
|
54678
|
-
const reject = unshippableReason(
|
|
54829
|
+
const reject = unshippableReason(wireId, t.label);
|
|
54679
54830
|
if (reject) {
|
|
54680
54831
|
console.warn(`[errata] skipping unshippable anchor ${wireId} (${t.label}): ${reject}`);
|
|
54681
54832
|
continue;
|