@inerrata-corporation/errata 2.0.2-dev.539 → 2.0.2-dev.545
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 +150 -10
- package/package.json +1 -1
- package/pass-worker.mjs +4 -0
package/errata.mjs
CHANGED
|
@@ -19287,16 +19287,24 @@ function closeDesignProblem(store, problemId, fixNote, t) {
|
|
|
19287
19287
|
const p = store.getNode(problemId);
|
|
19288
19288
|
if (!p || p.label !== "Problem") return false;
|
|
19289
19289
|
if (p.attrs["resolvedAs"]) return false;
|
|
19290
|
-
if (fixNote?.trim()
|
|
19291
|
-
const
|
|
19292
|
-
|
|
19293
|
-
|
|
19294
|
-
|
|
19295
|
-
|
|
19290
|
+
if (fixNote?.trim()) {
|
|
19291
|
+
const sols = store.outEdges(problemId, ["SOLVED_BY"]).map((e) => store.getNode(e.to)).filter((n) => n !== null);
|
|
19292
|
+
if (sols.every((s) => isAutoMinted(s))) {
|
|
19293
|
+
const solId = `dfix_${digest({ problemId, fix: fixNote })}`.slice(0, 56);
|
|
19294
|
+
store.mergeNode(
|
|
19295
|
+
buildNode(store, solId, "Solution", fixNote.trim(), t, { source: "convo", provisional: false })
|
|
19296
|
+
);
|
|
19297
|
+
mergeEdge(store, problemId, solId, "SOLVED_BY", t);
|
|
19298
|
+
}
|
|
19296
19299
|
}
|
|
19297
19300
|
if (p.attrs["resolvedAt"]) return false;
|
|
19298
19301
|
store.updateNode(problemId, {
|
|
19299
|
-
|
|
19302
|
+
// `resolutionWitnessed` records WHO closed it — an agent's explicit fix tag
|
|
19303
|
+
// — so the reopen sweep can tell this close from the heuristic auto-closes
|
|
19304
|
+
// it polices. The solution SET is the wrong proxy: a bare `(fix:[handle])`
|
|
19305
|
+
// mints no Solution, and a legacy placeholder beside it reads as
|
|
19306
|
+
// all-heuristic either way.
|
|
19307
|
+
attrs: { ...p.attrs, provisional: false, resolvedAt: t, resolutionWitnessed: true },
|
|
19300
19308
|
lastUpdatedAt: t
|
|
19301
19309
|
});
|
|
19302
19310
|
return true;
|
|
@@ -19307,6 +19315,10 @@ function reopenAutoClosedProblems(store, t) {
|
|
|
19307
19315
|
if (p.attrs["resolvedAt"] == null) continue;
|
|
19308
19316
|
if (p.attrs["resolvedAs"] != null) continue;
|
|
19309
19317
|
if (p.attrs["mergedInto"] !== void 0) continue;
|
|
19318
|
+
if (p.attrs["resolutionWitnessed"] === true) {
|
|
19319
|
+
report.agentDescribed++;
|
|
19320
|
+
continue;
|
|
19321
|
+
}
|
|
19310
19322
|
const sols = store.outEdges(p.id, ["SOLVED_BY"]).map((e) => store.getNode(e.to)).filter((n) => n !== null);
|
|
19311
19323
|
if (sols.length === 0) continue;
|
|
19312
19324
|
if (!sols.every((s) => String(s.description ?? "").startsWith(AUTO_MINT_PREFIX))) {
|
|
@@ -21991,6 +22003,23 @@ var init_mechanism_liveness = __esm({
|
|
|
21991
22003
|
// it is declared fed-by-liveness so the row exists and the pass is watched.
|
|
21992
22004
|
fed: { labels: ["File"], attr: "relPath", minFraction: 0.9 },
|
|
21993
22005
|
effectCounter: "reaped"
|
|
22006
|
+
},
|
|
22007
|
+
{
|
|
22008
|
+
id: "liveness-watch",
|
|
22009
|
+
what: "the daemon-side schedule of this very verdict \u2014 alarms when a mechanism stops working",
|
|
22010
|
+
// The watcher is itself a row: a probe that only runs when a human remembers
|
|
22011
|
+
// is how the original six defects shipped, and a scheduled watch that
|
|
22012
|
+
// silently stops running is the same failure one level up. Its `invoked …
|
|
22013
|
+
// ago` column is the reading that matters.
|
|
22014
|
+
pass: "liveness-watch",
|
|
22015
|
+
// It reads the pass LEDGER, not a node attribute; minFraction 0 makes the
|
|
22016
|
+
// fed gate structurally unfailable (the same "field written at all" bar as
|
|
22017
|
+
// revisit-sweep) so this row can only ever alarm on invocation.
|
|
22018
|
+
fed: { labels: ["Problem"], attr: "revisitReason", minFraction: 0 },
|
|
22019
|
+
// Alarms ARE its state transitions; zero on a healthy store, so the steady
|
|
22020
|
+
// reading is IDLE — correct, and it declares no backlog on purpose.
|
|
22021
|
+
effectCounter: "alarms",
|
|
22022
|
+
note: "steady-state IDLE is healthy; the row exists for its invocation age"
|
|
21994
22023
|
}
|
|
21995
22024
|
];
|
|
21996
22025
|
COLUMN_INPUTS = {
|
|
@@ -52540,6 +52569,50 @@ function appendPassLedger(configDir, kind, durationMs, counts) {
|
|
|
52540
52569
|
} catch {
|
|
52541
52570
|
}
|
|
52542
52571
|
}
|
|
52572
|
+
function readPassLedger(configDir) {
|
|
52573
|
+
const path2 = passLedgerPath(configDir);
|
|
52574
|
+
if (!existsSync15(path2)) return [];
|
|
52575
|
+
try {
|
|
52576
|
+
return readFileSync13(path2, "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l)).filter(
|
|
52577
|
+
(e) => typeof e?.ts === "number" && typeof e?.kind === "string" && typeof e?.durationMs === "number"
|
|
52578
|
+
).map((e) => ({ ...e, counts: e.counts ?? {} }));
|
|
52579
|
+
} catch {
|
|
52580
|
+
return [];
|
|
52581
|
+
}
|
|
52582
|
+
}
|
|
52583
|
+
function summarizePassLedger(configDir) {
|
|
52584
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
52585
|
+
const firstTs = /* @__PURE__ */ new Map();
|
|
52586
|
+
for (const e of readPassLedger(configDir)) {
|
|
52587
|
+
const s = out2.get(e.kind) ?? {
|
|
52588
|
+
kind: e.kind,
|
|
52589
|
+
runs: 0,
|
|
52590
|
+
firstTs: Number.POSITIVE_INFINITY,
|
|
52591
|
+
lastTs: 0,
|
|
52592
|
+
lastDurationMs: 0,
|
|
52593
|
+
totals: {},
|
|
52594
|
+
firstTotals: {},
|
|
52595
|
+
lastTotals: {}
|
|
52596
|
+
};
|
|
52597
|
+
s.runs++;
|
|
52598
|
+
if (e.ts >= s.lastTs) {
|
|
52599
|
+
s.lastTs = e.ts;
|
|
52600
|
+
s.lastDurationMs = e.durationMs;
|
|
52601
|
+
s.lastTotals = { ...e.counts };
|
|
52602
|
+
}
|
|
52603
|
+
const seen = firstTs.get(e.kind);
|
|
52604
|
+
if (seen === void 0 || e.ts < seen) {
|
|
52605
|
+
firstTs.set(e.kind, e.ts);
|
|
52606
|
+
s.firstTs = e.ts;
|
|
52607
|
+
s.firstTotals = { ...e.counts };
|
|
52608
|
+
}
|
|
52609
|
+
for (const [k, v] of Object.entries(e.counts)) {
|
|
52610
|
+
if (typeof v === "number") s.totals[k] = (s.totals[k] ?? 0) + v;
|
|
52611
|
+
}
|
|
52612
|
+
out2.set(e.kind, s);
|
|
52613
|
+
}
|
|
52614
|
+
return out2;
|
|
52615
|
+
}
|
|
52543
52616
|
|
|
52544
52617
|
// src/episode.ts
|
|
52545
52618
|
init_src();
|
|
@@ -54129,7 +54202,8 @@ var TITLES = {
|
|
|
54129
54202
|
"problem-resolved": "Errata \xB7 resolved \u2713",
|
|
54130
54203
|
"hotspot-problem": "Errata \xB7 high-impact problem",
|
|
54131
54204
|
"index-started": "Errata \xB7 indexing\u2026",
|
|
54132
|
-
"index-completed": "Errata \xB7 index ready \u2713"
|
|
54205
|
+
"index-completed": "Errata \xB7 index ready \u2713",
|
|
54206
|
+
"mechanism-stalled": "Errata \xB7 a mechanism is not working"
|
|
54133
54207
|
};
|
|
54134
54208
|
var lastFired = /* @__PURE__ */ new Map();
|
|
54135
54209
|
var THROTTLE_MS = 3e4;
|
|
@@ -54177,6 +54251,54 @@ function maybeFlushDigests() {
|
|
|
54177
54251
|
}
|
|
54178
54252
|
}
|
|
54179
54253
|
|
|
54254
|
+
// src/liveness-watch.ts
|
|
54255
|
+
init_src5();
|
|
54256
|
+
var LIVENESS_WATCH_INTERVAL_MS = 60 * 60 * 1e3;
|
|
54257
|
+
var ALARM_RENOTIFY_MS = 24 * 60 * 60 * 1e3;
|
|
54258
|
+
function createLivenessWatch(deps) {
|
|
54259
|
+
let lastRunAt = 0;
|
|
54260
|
+
const lastAlarmedAt = /* @__PURE__ */ new Map();
|
|
54261
|
+
return {
|
|
54262
|
+
maybeRun(nowMs = Date.now()) {
|
|
54263
|
+
if (nowMs - lastRunAt < LIVENESS_WATCH_INTERVAL_MS) return null;
|
|
54264
|
+
lastRunAt = nowMs;
|
|
54265
|
+
try {
|
|
54266
|
+
const started2 = Date.now();
|
|
54267
|
+
const invocations = /* @__PURE__ */ new Map();
|
|
54268
|
+
for (const [kind, s] of summarizePassLedger(deps.configDir)) {
|
|
54269
|
+
invocations.set(kind, {
|
|
54270
|
+
lastTs: s.lastTs,
|
|
54271
|
+
firstTs: s.firstTs,
|
|
54272
|
+
runs: s.runs,
|
|
54273
|
+
totals: s.totals,
|
|
54274
|
+
firstTotals: s.firstTotals,
|
|
54275
|
+
lastTotals: s.lastTotals
|
|
54276
|
+
});
|
|
54277
|
+
}
|
|
54278
|
+
const rows = evaluateMechanisms(deps.store, invocations);
|
|
54279
|
+
const bad = rows.filter((r) => hasStarvedMechanism([r]));
|
|
54280
|
+
appendPassLedger(deps.configDir, "liveness-watch", Date.now() - started2, {
|
|
54281
|
+
mechanisms: rows.length,
|
|
54282
|
+
alarms: bad.length
|
|
54283
|
+
});
|
|
54284
|
+
if (bad.length > 0) {
|
|
54285
|
+
const lines = formatMechanismStatus(rows, nowMs);
|
|
54286
|
+
for (const r of bad) {
|
|
54287
|
+
const at = lastAlarmedAt.get(r.id) ?? 0;
|
|
54288
|
+
if (nowMs - at < ALARM_RENOTIFY_MS) continue;
|
|
54289
|
+
lastAlarmedAt.set(r.id, nowMs);
|
|
54290
|
+
const line = lines.find((l) => l.includes(r.id)) ?? `${r.verdict} ${r.id}`;
|
|
54291
|
+
deps.onAlarm(r.id, `${line.trim()} \u2014 ${r.what}`);
|
|
54292
|
+
}
|
|
54293
|
+
}
|
|
54294
|
+
return rows;
|
|
54295
|
+
} catch {
|
|
54296
|
+
return null;
|
|
54297
|
+
}
|
|
54298
|
+
}
|
|
54299
|
+
};
|
|
54300
|
+
}
|
|
54301
|
+
|
|
54180
54302
|
// src/loop-lag.ts
|
|
54181
54303
|
var HEARTBEAT_MS = 500;
|
|
54182
54304
|
var currentPass = "idle";
|
|
@@ -54206,7 +54328,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
54206
54328
|
}
|
|
54207
54329
|
|
|
54208
54330
|
// src/engine.ts
|
|
54209
|
-
var DAEMON_VERSION = true ? "2.0.2-dev.
|
|
54331
|
+
var DAEMON_VERSION = true ? "2.0.2-dev.545" : "2.0.0-alpha.0";
|
|
54210
54332
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
54211
54333
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
54212
54334
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -54529,6 +54651,14 @@ function createWorkspaceEngine(opts) {
|
|
|
54529
54651
|
});
|
|
54530
54652
|
}
|
|
54531
54653
|
const workingFiles = createWorkingFileState();
|
|
54654
|
+
const livenessWatch = createLivenessWatch({
|
|
54655
|
+
configDir: paths.configDir,
|
|
54656
|
+
store,
|
|
54657
|
+
onAlarm: (id, line) => {
|
|
54658
|
+
console.warn(`[errata] mechanism not working: ${line}`);
|
|
54659
|
+
notifyEvent("mechanism-stalled", line, { key: id });
|
|
54660
|
+
}
|
|
54661
|
+
});
|
|
54532
54662
|
const intents = createIntentState();
|
|
54533
54663
|
const toolRuns = createToolRunState();
|
|
54534
54664
|
let ctxRefreshTimer = null;
|
|
@@ -55054,7 +55184,16 @@ function createWorkspaceEngine(opts) {
|
|
|
55054
55184
|
}
|
|
55055
55185
|
continue;
|
|
55056
55186
|
}
|
|
55057
|
-
|
|
55187
|
+
const closed = resolveDesignProblemById(store, pid, fx.fixNote, t);
|
|
55188
|
+
if (!closed) {
|
|
55189
|
+
const n = store.getNode(pid);
|
|
55190
|
+
if (!n || n.label !== "Problem" || n.attrs["resolvedAs"] != null) {
|
|
55191
|
+
console.warn(
|
|
55192
|
+
`[errata] fix tag went nowhere: ${!n ? `id ${pid.slice(0, 32)} unknown` : n.label !== "Problem" ? `${pid.slice(0, 32)} is a ${n.label}, not a Problem` : "the problem was retracted \u2014 a retraction is not fixable"} \u2014 the fix was NOT recorded`
|
|
55193
|
+
);
|
|
55194
|
+
}
|
|
55195
|
+
}
|
|
55196
|
+
if (closed) {
|
|
55058
55197
|
resolved++;
|
|
55059
55198
|
const fxAnchor = editedTurnFile ?? turnFile ?? wf;
|
|
55060
55199
|
if (fxAnchor) {
|
|
@@ -55661,6 +55800,7 @@ function createWorkspaceEngine(opts) {
|
|
|
55661
55800
|
if (report.revisitsCleared > 0 || report.fixCandidatesSettled > 0 || report.designResolved > 0) {
|
|
55662
55801
|
refreshContextNow();
|
|
55663
55802
|
}
|
|
55803
|
+
livenessWatch.maybeRun();
|
|
55664
55804
|
return report;
|
|
55665
55805
|
},
|
|
55666
55806
|
async nightly() {
|
package/package.json
CHANGED
package/pass-worker.mjs
CHANGED
|
@@ -25627,6 +25627,10 @@ function reopenAutoClosedProblems(store2, t) {
|
|
|
25627
25627
|
if (p.attrs["resolvedAt"] == null) continue;
|
|
25628
25628
|
if (p.attrs["resolvedAs"] != null) continue;
|
|
25629
25629
|
if (p.attrs["mergedInto"] !== void 0) continue;
|
|
25630
|
+
if (p.attrs["resolutionWitnessed"] === true) {
|
|
25631
|
+
report.agentDescribed++;
|
|
25632
|
+
continue;
|
|
25633
|
+
}
|
|
25630
25634
|
const sols = store2.outEdges(p.id, ["SOLVED_BY"]).map((e) => store2.getNode(e.to)).filter((n) => n !== null);
|
|
25631
25635
|
if (sols.length === 0) continue;
|
|
25632
25636
|
if (!sols.every((s) => String(s.description ?? "").startsWith(AUTO_MINT_PREFIX))) {
|