@inerrata-corporation/errata 2.0.22-dev.4128 → 2.0.22-dev.4130

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.
@@ -17702,14 +17702,16 @@ var SqliteGraphStore = class {
17702
17702
  findNodeStampsByLabel(label, attrKey) {
17703
17703
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attrKey)) throw new Error(`findNodeStampsByLabel: bad attr key ${attrKey}`);
17704
17704
  const rows = this.db.prepare(
17705
- `SELECT id, created_at, created_at_seq, json_type(attrs_json, '$.${attrKey}') IS NOT NULL AS has
17705
+ `SELECT id, created_at, created_at_seq, json_type(attrs_json, '$.${attrKey}') IS NOT NULL AS has,
17706
+ COALESCE(json_extract(attrs_json, '$.source') = 'cloud', 0) AS cloud
17706
17707
  FROM nodes WHERE label = ? AND valid_to IS NULL`
17707
17708
  ).all(label);
17708
17709
  return rows.map((r) => ({
17709
17710
  id: r.id,
17710
17711
  createdAt: r.created_at,
17711
17712
  ...r.created_at_seq != null ? { createdAtSeq: r.created_at_seq } : {},
17712
- has: r.has === 1
17713
+ has: r.has === 1,
17714
+ cloud: r.cloud === 1
17713
17715
  }));
17714
17716
  }
17715
17717
  findNodeAttrsByLabel(label) {
package/errata.mjs CHANGED
@@ -20458,14 +20458,16 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
20458
20458
  findNodeStampsByLabel(label, attrKey) {
20459
20459
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attrKey)) throw new Error(`findNodeStampsByLabel: bad attr key ${attrKey}`);
20460
20460
  const rows = this.db.prepare(
20461
- `SELECT id, created_at, created_at_seq, json_type(attrs_json, '$.${attrKey}') IS NOT NULL AS has
20461
+ `SELECT id, created_at, created_at_seq, json_type(attrs_json, '$.${attrKey}') IS NOT NULL AS has,
20462
+ COALESCE(json_extract(attrs_json, '$.source') = 'cloud', 0) AS cloud
20462
20463
  FROM nodes WHERE label = ? AND valid_to IS NULL`
20463
20464
  ).all(label);
20464
20465
  return rows.map((r) => ({
20465
20466
  id: r.id,
20466
20467
  createdAt: r.created_at,
20467
20468
  ...r.created_at_seq != null ? { createdAtSeq: r.created_at_seq } : {},
20468
- has: r.has === 1
20469
+ has: r.has === 1,
20470
+ cloud: r.cloud === 1
20469
20471
  }));
20470
20472
  }
20471
20473
  findNodeAttrsByLabel(label) {
@@ -25748,7 +25750,9 @@ function evaluateFed(store, d) {
25748
25750
  if (!d.fed) return { count: 0, total: 0, fraction: 0 };
25749
25751
  const column2 = COLUMN_INPUTS[d.fed.attr];
25750
25752
  const fed = d.fed;
25751
- const nodes = fed.labels.flatMap((label) => store.findNodeStampsByLabel ? store.findNodeStampsByLabel(label, fed.attr) : store.findNodeAttrsByLabel(label));
25753
+ const all = fed.labels.flatMap((label) => store.findNodeStampsByLabel ? store.findNodeStampsByLabel(label, fed.attr) : store.findNodeAttrsByLabel(label));
25754
+ const isCloudMirror = (n) => n.cloud ?? n.attrs?.["source"] === "cloud";
25755
+ const nodes = fed.localOnly ? all.filter((n) => !isCloudMirror(n)) : all;
25752
25756
  const has = (n) => column2 ? column2(n) : n.has ?? n.attrs?.[fed.attr] !== void 0;
25753
25757
  let window2 = nodes;
25754
25758
  if (fed.recent !== void 0) {
@@ -25764,6 +25768,11 @@ function evaluateFed(store, d) {
25764
25768
  return { count, total: window2.length, fraction: window2.length === 0 ? 0 : count / window2.length };
25765
25769
  }
25766
25770
  function evaluateMechanisms(store, invocations = /* @__PURE__ */ new Map(), mechanisms = MECHANISMS) {
25771
+ const counts = /* @__PURE__ */ new Map();
25772
+ const count = (label) => {
25773
+ if (!counts.has(label)) counts.set(label, store.countNodesByLabel(label));
25774
+ return counts.get(label);
25775
+ };
25767
25776
  return mechanisms.map((d) => {
25768
25777
  const fed = evaluateFed(store, d);
25769
25778
  const inv = invocations.get(d.pass);
@@ -25776,8 +25785,11 @@ function evaluateMechanisms(store, invocations = /* @__PURE__ */ new Map(), mech
25776
25785
  const span = inv?.firstTs === void 0 ? 0 : inv.lastTs - inv.firstTs;
25777
25786
  const stalled = backlog !== void 0 && backlog > 0 && effectCount === 0 && (inv?.runs ?? 0) >= STALL_MIN_RUNS && span >= STALL_MIN_SPAN_MS && (backlogWas === void 0 || backlog >= backlogWas);
25778
25787
  let verdict;
25779
- if (!inv || inv.runs === 0) verdict = "never-invoked";
25780
- else if (d.configCounter && inv.lastTotals?.[d.configCounter] === 0) verdict = "unconfigured";
25788
+ const hasInput = fed.total > 0 || Boolean(d.fed?.sinceFirstStamp && d.fed.labels.some((label) => count(label) > 0));
25789
+ const missingRequiredNodes = d.requiresNodes?.some((label) => count(label) === 0) ?? false;
25790
+ if (d.configCounter && inv?.lastTotals?.[d.configCounter] === 0) verdict = "unconfigured";
25791
+ else if ((backlog ?? 0) === 0 && (!hasInput && !d.inputOptional || missingRequiredNodes)) verdict = "no-input";
25792
+ else if (!inv || inv.runs === 0) verdict = "never-invoked";
25781
25793
  else if (fed.fraction < (d.fedEdges?.minFraction ?? d.fed?.minFraction ?? 0)) verdict = "starved";
25782
25794
  else if (stalled) verdict = "stalled";
25783
25795
  else if (effectCount === 0) verdict = "no-effect";
@@ -25805,11 +25817,11 @@ function formatMechanismStatus(rows, nowMs) {
25805
25817
  return rows.map((r) => {
25806
25818
  const pct = (r.fedFraction * 100).toFixed(r.fedFraction < 0.01 ? 2 : 1);
25807
25819
  const age = r.lastInvokedMs === void 0 ? "never" : `${Math.max(0, Math.round((nowMs - r.lastInvokedMs) / 6e4))}m ago`;
25808
- const mark = r.verdict === "ok" ? "ok " : r.verdict === "no-effect" ? "IDLE" : r.verdict === "unconfigured" ? "OFF" : r.verdict === "stalled" ? "STUCK" : "DEAD";
25820
+ const mark = r.verdict === "ok" ? "ok " : r.verdict === "no-effect" ? "IDLE" : r.verdict === "no-input" ? "WAIT" : r.verdict === "unconfigured" ? "OFF" : r.verdict === "stalled" ? "STUCK" : "DEAD";
25809
25821
  const hours = r.spanMs === void 0 ? 0 : Math.floor(r.spanMs / 36e5);
25810
25822
  const over = hours >= 24 ? `${Math.floor(hours / 24)}d` : `${hours}h`;
25811
25823
  const trend = r.verdict === "stalled" && r.backlog !== void 0 ? ` \u2014 ${r.backlog} waiting${r.backlogWas !== void 0 ? ` (was ${r.backlogWas})` : ""}, none cleared in ${over}` : "";
25812
- return `${mark.padEnd(6)}${r.id.padEnd(20)} invoked ${age.padEnd(9)} ` + `fed ${pct}% (${r.fedCount}/${r.fedTotal})`.padEnd(28) + `effect ${r.effectCount}` + trend + (r.verdict !== "ok" && r.note ? ` \u2014 ${r.note}` : "");
25824
+ return `${mark.padEnd(6)}${r.id.padEnd(20)} invoked ${age.padEnd(9)} ` + `fed ${pct}% (${r.fedCount}/${r.fedTotal})`.padEnd(28) + `effect ${r.effectCount}` + trend + (r.verdict === "no-input" ? " \u2014 no eligible input yet" : r.verdict !== "ok" && r.note ? ` \u2014 ${r.note}` : "");
25813
25825
  });
25814
25826
  }
25815
25827
  function hasStarvedMechanism(rows) {
@@ -25870,6 +25882,7 @@ var init_mechanism_liveness = __esm({
25870
25882
  },
25871
25883
  {
25872
25884
  id: "fix-candidate-ask",
25885
+ requiresNodes: ["Problem"],
25873
25886
  what: "asks an agent whether an edit to a problem's anchor fixed it",
25874
25887
  pass: "semantic-maintenance",
25875
25888
  // markFixCandidates fails CLOSED on a File anchor with no contentChangedAt —
@@ -25921,7 +25934,12 @@ var init_mechanism_liveness = __esm({
25921
25934
  // the producer was verifiably stamping every new node.
25922
25935
  minFraction: 0.9,
25923
25936
  recent: 200,
25924
- sinceFirstStamp: true
25937
+ sinceFirstStamp: true,
25938
+ // The anchor-feed pull lands cloud mirrors by the hundreds every ten
25939
+ // minutes (createdAt = pull time, no local seq — stamping them would age
25940
+ // every local node by Δseq). On 2026-10-09 1,146 mirrors in a few hours
25941
+ // dragged this to 62% and toasted "ingest-sequence DEAD" with effect 41.
25942
+ localOnly: true
25925
25943
  },
25926
25944
  effectCounter: "seqAdvanced",
25927
25945
  note: "column, not attr; measured over nodes born since the first stamp in the recent window"
@@ -26066,6 +26084,7 @@ var init_mechanism_liveness = __esm({
26066
26084
  },
26067
26085
  {
26068
26086
  id: "liveness-watch",
26087
+ inputOptional: true,
26069
26088
  what: "the daemon-side schedule of this very verdict \u2014 alarms when a mechanism stops working",
26070
26089
  // The watcher is itself a row: a probe that only runs when a human remembers
26071
26090
  // is how the original six defects shipped, and a scheduled watch that
@@ -84772,23 +84791,25 @@ var lastFired = /* @__PURE__ */ new Map();
84772
84791
  var THROTTLE_MS = 3e4;
84773
84792
  function notifyEvent(kind, body2, opts = {}) {
84774
84793
  try {
84775
- if (process.env["ERRATA_NO_NOTIFY"]) return;
84776
- if (!loadConfig().notifications) return;
84794
+ if (process.env["ERRATA_NO_NOTIFY"]) return false;
84795
+ if (!loadConfig().notifications) return false;
84777
84796
  const k = `${kind}:${opts.key ?? ""}`;
84778
84797
  const now = Date.now();
84779
- if (now - (lastFired.get(k) ?? 0) < THROTTLE_MS) return;
84798
+ if (now - (lastFired.get(k) ?? 0) < THROTTLE_MS) return false;
84780
84799
  lastFired.set(k, now);
84781
84800
  notify(TITLES[kind], body2);
84801
+ return true;
84782
84802
  } catch {
84803
+ return false;
84783
84804
  }
84784
84805
  }
84785
84806
  function notifyOpsEvent(kind, body2, opts = {}) {
84786
84807
  try {
84787
- if (!loadConfig().opsNotices) return;
84808
+ if (!loadConfig().opsNotices) return false;
84788
84809
  } catch {
84789
- return;
84810
+ return false;
84790
84811
  }
84791
- notifyEvent(kind, body2, opts);
84812
+ return notifyEvent(kind, body2, opts);
84792
84813
  }
84793
84814
  function notifyTick(delta) {
84794
84815
  const { problemsResolved, reviewsTriggered } = delta;
@@ -84958,24 +84979,49 @@ var ALARM_RENOTIFY_MS = 24 * 60 * 60 * 1e3;
84958
84979
  function alarmStatePath(configDir) {
84959
84980
  return join34(configDir, "liveness-alarms.json");
84960
84981
  }
84961
- function loadAlarmState(configDir) {
84982
+ function loadAlarmState(path3) {
84962
84983
  try {
84963
- const raw2 = JSON.parse(readFileSync31(alarmStatePath(configDir), "utf8"));
84984
+ const raw2 = JSON.parse(readFileSync31(path3, "utf8"));
84964
84985
  return new Map(Object.entries(raw2).filter((e) => typeof e[1] === "number"));
84965
84986
  } catch {
84966
84987
  return /* @__PURE__ */ new Map();
84967
84988
  }
84968
84989
  }
84969
- function saveAlarmState(configDir, state) {
84990
+ function saveAlarmState(path3, state) {
84970
84991
  try {
84971
- writeFileSync22(alarmStatePath(configDir), JSON.stringify(Object.fromEntries(state)));
84992
+ writeFileSync22(path3, JSON.stringify(Object.fromEntries(state)));
84972
84993
  } catch {
84973
84994
  }
84974
84995
  }
84996
+ function createAlarmToastGate(statePath) {
84997
+ const lastToastedAt = loadAlarmState(statePath);
84998
+ return {
84999
+ pending: (ids, nowMs) => ids.filter((id) => nowMs - (lastToastedAt.get(id) ?? 0) >= ALARM_RENOTIFY_MS),
85000
+ markToasted: (ids, nowMs) => {
85001
+ if (ids.length === 0) return;
85002
+ for (const id of ids) lastToastedAt.set(id, nowMs);
85003
+ saveAlarmState(statePath, lastToastedAt);
85004
+ }
85005
+ };
85006
+ }
85007
+ var sharedToastGates = /* @__PURE__ */ new Map();
85008
+ function sharedAlarmToastGate(statePath) {
85009
+ let gate = sharedToastGates.get(statePath);
85010
+ if (!gate) sharedToastGates.set(statePath, gate = createAlarmToastGate(statePath));
85011
+ return gate;
85012
+ }
85013
+ function toastLivenessAlarms(gate, workspace, alarms, deliver, nowMs) {
85014
+ const fresh = gate.pending(alarms.map((a) => a.id), nowMs);
85015
+ if (fresh.length === 0) return [];
85016
+ const body2 = fresh.length === 1 ? `${workspace.name}: ${alarms.find((a) => a.id === fresh[0]).line}` : `${workspace.name}: ${fresh.join(", ")} \u2014 see daemon.log`;
85017
+ if (!deliver(body2, `liveness:${workspace.root}`)) return [];
85018
+ gate.markToasted(fresh, nowMs);
85019
+ return fresh;
85020
+ }
84975
85021
  function createLivenessWatch(deps) {
84976
85022
  let lastRunAt = 0;
84977
85023
  let running = false;
84978
- const lastAlarmedAt = loadAlarmState(deps.configDir);
85024
+ const lastAlarmedAt = loadAlarmState(alarmStatePath(deps.configDir));
84979
85025
  return {
84980
85026
  async maybeRun(nowMs = Date.now()) {
84981
85027
  if (running || nowMs - lastRunAt < LIVENESS_WATCH_INTERVAL_MS) return null;
@@ -84995,8 +85041,8 @@ function createLivenessWatch(deps) {
84995
85041
  });
84996
85042
  }
84997
85043
  const rows = deps.evaluate ? await deps.evaluate(invocations) : evaluateMechanisms(deps.store, invocations);
84998
- const workspaceActive = invocations.has("capture") || invocations.has("render");
84999
- const bad = workspaceActive ? rows.filter((r) => hasStarvedMechanism([r])) : [];
85044
+ const workspaceActive = invocations.has("capture");
85045
+ const bad = workspaceActive ? rows.filter((r) => r.id !== "liveness-watch" && hasStarvedMechanism([r])) : [];
85000
85046
  const watch3 = watchCensus();
85001
85047
  const pass = passState();
85002
85048
  appendPassLedger(deps.configDir, "liveness-watch", Date.now() - started2, {
@@ -85021,14 +85067,17 @@ function createLivenessWatch(deps) {
85021
85067
  });
85022
85068
  if (bad.length > 0) {
85023
85069
  const lines = formatMechanismStatus(rows, nowMs);
85070
+ const fresh = [];
85024
85071
  for (const r of bad) {
85025
85072
  const at = lastAlarmedAt.get(r.id) ?? 0;
85026
85073
  if (nowMs - at < ALARM_RENOTIFY_MS) continue;
85027
85074
  lastAlarmedAt.set(r.id, nowMs);
85028
- saveAlarmState(deps.configDir, lastAlarmedAt);
85029
85075
  const line = lines.find((l) => l.includes(r.id)) ?? `${r.verdict} ${r.id}`;
85030
- deps.onAlarm(r.id, `${line.trim()} \u2014 ${r.what}`);
85076
+ fresh.push({ id: r.id, line: `${line.trim()} \u2014 ${r.what}` });
85031
85077
  }
85078
+ if (fresh.length > 0) saveAlarmState(alarmStatePath(deps.configDir), lastAlarmedAt);
85079
+ for (const a of fresh) deps.onAlarm(a.id, a.line);
85080
+ if (fresh.length > 0) deps.onAlarms?.(fresh);
85032
85081
  }
85033
85082
  return rows;
85034
85083
  } catch (err2) {
@@ -85168,7 +85217,7 @@ function createWatchBreaker(deps) {
85168
85217
  }
85169
85218
 
85170
85219
  // src/engine.ts
85171
- var DAEMON_VERSION = true ? "2.0.22-dev.4128" : "2.0.0-alpha.0";
85220
+ var DAEMON_VERSION = true ? "2.0.22-dev.4130" : "2.0.0-alpha.0";
85172
85221
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
85173
85222
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
85174
85223
  var GIT_OP_MUTE_MS = 4e3;
@@ -85549,9 +85598,17 @@ function createWorkspaceEngine(opts) {
85549
85598
  configDir: paths.configDir,
85550
85599
  store,
85551
85600
  ...passWorker ? { evaluate: (invocations) => passWorker.liveness(invocations) } : {},
85552
- onAlarm: (id, line) => {
85553
- console.warn(`[errata] mechanism not working: ${line}`);
85554
- notifyEvent("mechanism-stalled", line, { key: id });
85601
+ onAlarm: (_id, line) => {
85602
+ console.warn(`[errata] mechanism not working (${profile.name}): ${line}`);
85603
+ },
85604
+ onAlarms: (alarms) => {
85605
+ toastLivenessAlarms(
85606
+ sharedAlarmToastGate(join35(globalDir(), "liveness-toasts.json")),
85607
+ { root: opts.workspaceRoot, name: profile.name },
85608
+ alarms,
85609
+ (body2, key) => notifyEvent("mechanism-stalled", body2, { key }),
85610
+ Date.now()
85611
+ );
85555
85612
  },
85556
85613
  // Read through a closure, not captured once: `witnessQueue` is reassigned
85557
85614
  // on every harvest, so a snapshot would freeze the depth at boot — which is
@@ -87672,23 +87729,20 @@ B: ${b}`,
87672
87729
  ts: fjStart,
87673
87730
  ...foldJudge ? { judge: foldJudge } : {}
87674
87731
  });
87675
- if (fj.examined > 0) {
87676
- appendPassLedger(paths.configDir, "fold-judge", Date.now() - fjStart, {
87677
- examined: fj.examined,
87678
- folded: fj.folded,
87679
- foldedEmbedding: fj.foldedEmbedding,
87680
- foldedJudge: fj.foldedJudge,
87681
- rejected: fj.rejected,
87682
- standing: fj.standing,
87683
- judgeErrors: fj.judgeErrors,
87684
- retargeted: fj.retargeted,
87685
- // Opt-in lane: 0 tells the liveness watch "off by choice", not "stuck".
87686
- judgeConfigured: foldJudge ? 1 : 0
87687
- });
87688
- if (fj.folded > 0) {
87689
- console.log(`[errata] fold-judge: folded ${fj.folded} paraphrase pair(s) (${fj.foldedEmbedding} by embedding, ${fj.foldedJudge} by judge), ${fj.standing} standing`);
87690
- refreshContextNow();
87691
- }
87732
+ appendPassLedger(paths.configDir, "fold-judge", Date.now() - fjStart, {
87733
+ examined: fj.examined,
87734
+ folded: fj.folded,
87735
+ foldedEmbedding: fj.foldedEmbedding,
87736
+ foldedJudge: fj.foldedJudge,
87737
+ rejected: fj.rejected,
87738
+ standing: fj.standing,
87739
+ judgeErrors: fj.judgeErrors,
87740
+ retargeted: fj.retargeted,
87741
+ judgeConfigured: foldJudge ? 1 : 0
87742
+ });
87743
+ if (fj.folded > 0) {
87744
+ console.log(`[errata] fold-judge: folded ${fj.folded} paraphrase pair(s) (${fj.foldedEmbedding} by embedding, ${fj.foldedJudge} by judge), ${fj.standing} standing`);
87745
+ refreshContextNow();
87692
87746
  }
87693
87747
  return { embedded: sem.embedded };
87694
87748
  } catch (err2) {
@@ -87973,6 +88027,21 @@ async function listenServer(fetchFn, port) {
87973
88027
  });
87974
88028
  }
87975
88029
 
88030
+ // src/capture-status.ts
88031
+ function captureStatusLines(capture, nowMs = Date.now()) {
88032
+ if (!capture) return ["no processed agent turns recorded for this workspace; machine-wide hook activity does not prove capture here"];
88033
+ const value = (key) => capture.totals[key] === void 0 ? "unrecorded" : String(capture.totals[key]);
88034
+ const age = Math.max(0, Math.floor((nowMs - capture.lastTs) / 6e4));
88035
+ const lines = [
88036
+ `${value("turns")} turns \xB7 ${value("tagsSeen")} tags seen \xB7 ${value("minted")} nodes minted across ${capture.runs} retained passes (last ${age}m ago)`
88037
+ ];
88038
+ if (capture.totals.tagsSeen === 0) lines.push("turns arrived, but no knowledge tags were detected");
88039
+ else if ((capture.totals.tagsSeen ?? 0) > 0 && capture.totals.minted === 0) {
88040
+ lines.push(`${value("tagsRejected")} tags rejected \xB7 ${value("tagsRestated")} restatements; zero new nodes alone does not establish capture failure`);
88041
+ }
88042
+ return lines;
88043
+ }
88044
+
87976
88045
  // src/cli.ts
87977
88046
  init_registry();
87978
88047
  init_identity2();
@@ -94690,8 +94759,8 @@ async function diagnoseInstallation(cfg, dependencies) {
94690
94759
  checks.push(
94691
94760
  profile ? { id: "installation_profile", status: "pass", detail: `${profileName} is selected` } : {
94692
94761
  id: "installation_profile",
94693
- status: "fail",
94694
- detail: "No installation profile is selected"
94762
+ status: profileName ? "fail" : "pass",
94763
+ detail: profileName ? `Selected installation profile "${profileName}" does not exist` : "Using the machine-default credential; a named installation profile is optional"
94695
94764
  }
94696
94765
  );
94697
94766
  const credentialType = cfg.accessToken ? "oauth" : cfg.apiKey ? "api_key" : "none";
@@ -94702,8 +94771,8 @@ async function diagnoseInstallation(cfg, dependencies) {
94702
94771
  checks.push(
94703
94772
  authorityMatches ? {
94704
94773
  id: "profile_authority",
94705
- status: profile ? "pass" : "warn",
94706
- detail: profile ? "Selected profile and active credential set match" : "Cannot compare authority without a selected profile"
94774
+ status: profileName && !profile ? "warn" : "pass",
94775
+ detail: profile ? "Selected profile and active credential set match" : profileName ? "Selected profile is missing; authority cannot be compared" : "No named profile selected; credential authentication is checked below"
94707
94776
  } : {
94708
94777
  id: "profile_authority",
94709
94778
  status: "fail",
@@ -95069,6 +95138,8 @@ function inspectCodexContext(cwd) {
95069
95138
  }
95070
95139
  return { id: "codex_context", status: "fail", detail: "No usable saved workspace context; run errata start here and check the daemon log if context.md remains unavailable" };
95071
95140
  }
95141
+ var CodexRuntimeUnavailableError = class extends Error {
95142
+ };
95072
95143
  function readCodexHookState(cwd, options = {}) {
95073
95144
  return new Promise((resolve10, reject) => {
95074
95145
  const child = spawn4(options.bin ?? resolveCodexExecutable(), options.args ?? ["app-server", "--stdio"], {
@@ -95099,7 +95170,7 @@ function readCodexHookState(cwd, options = {}) {
95099
95170
  const send = (id, method, params) => {
95100
95171
  child.stdin.write(JSON.stringify({ id, method, params }) + "\n");
95101
95172
  };
95102
- child.on("error", () => finish(new Error(`Codex could not be started for hook inspection. ${CODEX_HOOK_REVIEW_HELP}`)));
95173
+ child.on("error", (error48) => finish(error48.code === "ENOENT" ? new CodexRuntimeUnavailableError("Codex executable was not found; hook status is unverified. If you use Codex on this machine, make its runtime available and rerun errata doctor.") : new Error(`Codex could not be started for hook inspection (${error48.code ?? "launch error"}); hook trust was not checked.`)));
95103
95174
  child.on("exit", () => finish(new Error("Codex exited before returning its hook state")));
95104
95175
  child.stdin.on("error", () => finish(new Error("Codex hook inspection connection closed")));
95105
95176
  child.stderr.resume();
@@ -95157,12 +95228,12 @@ function assessCodexHooks(state, platform = process.platform) {
95157
95228
  }
95158
95229
  return checks.length ? checks : check2("pass", "Codex discovers enabled, trusted Errata hooks; verify live context and capture in a session");
95159
95230
  }
95160
- async function diagnoseCodexHooks(cwd) {
95231
+ async function diagnoseCodexHooks(cwd, options = {}) {
95161
95232
  const local = [inspectCodexRelay(cwd), inspectCodexContext(cwd)];
95162
95233
  try {
95163
- return [...local, ...assessCodexHooks(await readCodexHookState(cwd))];
95234
+ return [...local, ...assessCodexHooks(await readCodexHookState(cwd, options))];
95164
95235
  } catch (error48) {
95165
- return [...local, { id: "codex_hooks", status: "fail", detail: error48 instanceof Error ? error48.message : "Cannot verify Codex hooks" }];
95236
+ return [...local, { id: "codex_hooks", status: error48 instanceof CodexRuntimeUnavailableError ? "warn" : "fail", detail: error48 instanceof Error ? error48.message : "Cannot verify Codex hooks" }];
95166
95237
  }
95167
95238
  }
95168
95239
 
@@ -96981,6 +97052,9 @@ async function cmdStatus() {
96981
97052
  }
96982
97053
  console.log(` graph db: ${existsSync40(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
96983
97054
  console.log(` event log: ${existsSync40(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
97055
+ for (const line of captureStatusLines(summarizePassLedger(paths.configDir).get("capture"))) {
97056
+ console.log(` capture: ${line}`);
97057
+ }
96984
97058
  if (existsSync40(paths.castalia)) {
96985
97059
  try {
96986
97060
  const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src5(), src_exports2));
@@ -97067,11 +97141,11 @@ async function cmdStatus() {
97067
97141
  }
97068
97142
  if (h.lastHook !== void 0) {
97069
97143
  if (h.lastHook === null) {
97070
- console.log(` hooks: none received since the daemon started`);
97144
+ console.log(` hooks: none received machine-wide since the daemon started`);
97071
97145
  } else {
97072
97146
  const min = Math.round((Date.now() - h.lastHook.at) / 6e4);
97073
97147
  const ago2 = min < 1 ? "just now" : min < 60 ? `${min}m ago` : `${Math.floor(min / 60)}h ${min % 60}m ago`;
97074
- console.log(` hooks: last received ${ago2} (${h.lastHook.event})`);
97148
+ console.log(` hooks: last received machine-wide ${ago2} (${h.lastHook.event})`);
97075
97149
  }
97076
97150
  }
97077
97151
  }
@@ -97101,16 +97175,16 @@ async function cmdStatus() {
97101
97175
  }
97102
97176
  const shown = reportedIdentity(cfg, workspaceEntryForPath(ROOT));
97103
97177
  const ecfg = shown.ok ? shown.config : cfg;
97104
- console.log(` profile: ${ecfg.activeInstallationProfile ?? "(unbound legacy credential)"}`);
97178
+ console.log(` profile: ${ecfg.activeInstallationProfile ?? "(machine default; no named profile)"}`);
97105
97179
  if (!shown.ok) console.log(` \u26A0 ${shown.reason} \u2014 this workspace's capture holds locally until fixed`);
97106
97180
  else if (shown.note) console.log(` \u21B3 ${shown.note}`);
97107
97181
  const who = shown.ok && shown.note ? "" : ` (${ecfg.email})`;
97108
97182
  if (!hasCloudCredential(ecfg)) {
97109
- console.log(` logged in: no`);
97183
+ console.log(` credential: none`);
97110
97184
  } else if (ecfg.accessToken) {
97111
- console.log(` logged in: yes${who} \u2014 attested daemon, can contribute`);
97185
+ console.log(` credential: OAuth stored${who} \u2014 authentication checked below`);
97112
97186
  } else {
97113
- console.log(` logged in: yes${who} \u2014 key capability enforced by Console installation/scopes`);
97187
+ console.log(` credential: API key stored${who} \u2014 authentication checked below`);
97114
97188
  }
97115
97189
  const active3 = getActiveAgent(ecfg);
97116
97190
  console.log(
@@ -97137,7 +97211,8 @@ async function cmdStatus() {
97137
97211
  const me = await c.me();
97138
97212
  console.log(` reachable: yes \xB7 authenticated as ${me.handle} (${me.tier})`);
97139
97213
  } catch (err2) {
97140
- console.log(` reachable: no (${err2 instanceof Error ? err2.message : err2})`);
97214
+ console.log(` reachable: ${inspection.reachable ? `yes (${inspection.probe})` : "no"}`);
97215
+ console.log(` authenticated: no (${err2 instanceof Error ? err2.message : err2})`);
97141
97216
  }
97142
97217
  } else {
97143
97218
  console.log(
@@ -16110,14 +16110,16 @@ var SqliteGraphStore = class {
16110
16110
  findNodeStampsByLabel(label, attrKey) {
16111
16111
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attrKey)) throw new Error(`findNodeStampsByLabel: bad attr key ${attrKey}`);
16112
16112
  const rows = this.db.prepare(
16113
- `SELECT id, created_at, created_at_seq, json_type(attrs_json, '$.${attrKey}') IS NOT NULL AS has
16113
+ `SELECT id, created_at, created_at_seq, json_type(attrs_json, '$.${attrKey}') IS NOT NULL AS has,
16114
+ COALESCE(json_extract(attrs_json, '$.source') = 'cloud', 0) AS cloud
16114
16115
  FROM nodes WHERE label = ? AND valid_to IS NULL`
16115
16116
  ).all(label);
16116
16117
  return rows.map((r) => ({
16117
16118
  id: r.id,
16118
16119
  createdAt: r.created_at,
16119
16120
  ...r.created_at_seq != null ? { createdAtSeq: r.created_at_seq } : {},
16120
- has: r.has === 1
16121
+ has: r.has === 1,
16122
+ cloud: r.cloud === 1
16121
16123
  }));
16122
16124
  }
16123
16125
  findNodeAttrsByLabel(label) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.22-dev.4128",
3
+ "version": "2.0.22-dev.4130",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -26969,14 +26969,16 @@ var SqliteGraphStore = class {
26969
26969
  findNodeStampsByLabel(label, attrKey) {
26970
26970
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attrKey)) throw new Error(`findNodeStampsByLabel: bad attr key ${attrKey}`);
26971
26971
  const rows = this.db.prepare(
26972
- `SELECT id, created_at, created_at_seq, json_type(attrs_json, '$.${attrKey}') IS NOT NULL AS has
26972
+ `SELECT id, created_at, created_at_seq, json_type(attrs_json, '$.${attrKey}') IS NOT NULL AS has,
26973
+ COALESCE(json_extract(attrs_json, '$.source') = 'cloud', 0) AS cloud
26973
26974
  FROM nodes WHERE label = ? AND valid_to IS NULL`
26974
26975
  ).all(label);
26975
26976
  return rows.map((r) => ({
26976
26977
  id: r.id,
26977
26978
  createdAt: r.created_at,
26978
26979
  ...r.created_at_seq != null ? { createdAtSeq: r.created_at_seq } : {},
26979
- has: r.has === 1
26980
+ has: r.has === 1,
26981
+ cloud: r.cloud === 1
26980
26982
  }));
26981
26983
  }
26982
26984
  findNodeAttrsByLabel(label) {
@@ -28934,6 +28936,7 @@ var MECHANISMS = [
28934
28936
  },
28935
28937
  {
28936
28938
  id: "fix-candidate-ask",
28939
+ requiresNodes: ["Problem"],
28937
28940
  what: "asks an agent whether an edit to a problem's anchor fixed it",
28938
28941
  pass: "semantic-maintenance",
28939
28942
  // markFixCandidates fails CLOSED on a File anchor with no contentChangedAt —
@@ -28985,7 +28988,12 @@ var MECHANISMS = [
28985
28988
  // the producer was verifiably stamping every new node.
28986
28989
  minFraction: 0.9,
28987
28990
  recent: 200,
28988
- sinceFirstStamp: true
28991
+ sinceFirstStamp: true,
28992
+ // The anchor-feed pull lands cloud mirrors by the hundreds every ten
28993
+ // minutes (createdAt = pull time, no local seq — stamping them would age
28994
+ // every local node by Δseq). On 2026-10-09 1,146 mirrors in a few hours
28995
+ // dragged this to 62% and toasted "ingest-sequence DEAD" with effect 41.
28996
+ localOnly: true
28989
28997
  },
28990
28998
  effectCounter: "seqAdvanced",
28991
28999
  note: "column, not attr; measured over nodes born since the first stamp in the recent window"
@@ -29130,6 +29138,7 @@ var MECHANISMS = [
29130
29138
  },
29131
29139
  {
29132
29140
  id: "liveness-watch",
29141
+ inputOptional: true,
29133
29142
  what: "the daemon-side schedule of this very verdict \u2014 alarms when a mechanism stops working",
29134
29143
  // The watcher is itself a row: a probe that only runs when a human remembers
29135
29144
  // is how the original six defects shipped, and a scheduled watch that
@@ -29161,7 +29170,9 @@ function evaluateFed(store2, d) {
29161
29170
  if (!d.fed) return { count: 0, total: 0, fraction: 0 };
29162
29171
  const column2 = COLUMN_INPUTS[d.fed.attr];
29163
29172
  const fed = d.fed;
29164
- const nodes = fed.labels.flatMap((label) => store2.findNodeStampsByLabel ? store2.findNodeStampsByLabel(label, fed.attr) : store2.findNodeAttrsByLabel(label));
29173
+ const all = fed.labels.flatMap((label) => store2.findNodeStampsByLabel ? store2.findNodeStampsByLabel(label, fed.attr) : store2.findNodeAttrsByLabel(label));
29174
+ const isCloudMirror = (n) => n.cloud ?? n.attrs?.["source"] === "cloud";
29175
+ const nodes = fed.localOnly ? all.filter((n) => !isCloudMirror(n)) : all;
29165
29176
  const has = (n) => column2 ? column2(n) : n.has ?? n.attrs?.[fed.attr] !== void 0;
29166
29177
  let window2 = nodes;
29167
29178
  if (fed.recent !== void 0) {
@@ -29177,6 +29188,11 @@ function evaluateFed(store2, d) {
29177
29188
  return { count, total: window2.length, fraction: window2.length === 0 ? 0 : count / window2.length };
29178
29189
  }
29179
29190
  function evaluateMechanisms(store2, invocations = /* @__PURE__ */ new Map(), mechanisms = MECHANISMS) {
29191
+ const counts = /* @__PURE__ */ new Map();
29192
+ const count = (label) => {
29193
+ if (!counts.has(label)) counts.set(label, store2.countNodesByLabel(label));
29194
+ return counts.get(label);
29195
+ };
29180
29196
  return mechanisms.map((d) => {
29181
29197
  const fed = evaluateFed(store2, d);
29182
29198
  const inv = invocations.get(d.pass);
@@ -29189,8 +29205,11 @@ function evaluateMechanisms(store2, invocations = /* @__PURE__ */ new Map(), mec
29189
29205
  const span = inv?.firstTs === void 0 ? 0 : inv.lastTs - inv.firstTs;
29190
29206
  const stalled = backlog !== void 0 && backlog > 0 && effectCount === 0 && (inv?.runs ?? 0) >= STALL_MIN_RUNS && span >= STALL_MIN_SPAN_MS && (backlogWas === void 0 || backlog >= backlogWas);
29191
29207
  let verdict;
29192
- if (!inv || inv.runs === 0) verdict = "never-invoked";
29193
- else if (d.configCounter && inv.lastTotals?.[d.configCounter] === 0) verdict = "unconfigured";
29208
+ const hasInput = fed.total > 0 || Boolean(d.fed?.sinceFirstStamp && d.fed.labels.some((label) => count(label) > 0));
29209
+ const missingRequiredNodes = d.requiresNodes?.some((label) => count(label) === 0) ?? false;
29210
+ if (d.configCounter && inv?.lastTotals?.[d.configCounter] === 0) verdict = "unconfigured";
29211
+ else if ((backlog ?? 0) === 0 && (!hasInput && !d.inputOptional || missingRequiredNodes)) verdict = "no-input";
29212
+ else if (!inv || inv.runs === 0) verdict = "never-invoked";
29194
29213
  else if (fed.fraction < (d.fedEdges?.minFraction ?? d.fed?.minFraction ?? 0)) verdict = "starved";
29195
29214
  else if (stalled) verdict = "stalled";
29196
29215
  else if (effectCount === 0) verdict = "no-effect";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "errata-context",
3
- "version": "2.0.22-dev.4128",
3
+ "version": "2.0.22-dev.4130",
4
4
  "description": "A minimal 3D view of loaded Errata priors and recent graph bursts.",
5
5
  "author": {
6
6
  "name": "inErrata"
@@ -1,4 +1,4 @@
1
- 7df6ba4eca83c1c8e6b452e826aa8d4b6c59ed63ded7cf6267d007634a087605 .codex-plugin/plugin.json
1
+ 322d5559f1d35b1d729e868a803e8374c8332974495f4683ad547fe5c1df207d .codex-plugin/plugin.json
2
2
  a7bebae9fb01c838d6c75fc784129e28be571233fa66ff5ee8039b574f35ccf7 assets/icon.png
3
3
  fc38b64e4df1e0b72c35764bef6c4c05430d97c9009ad0ecc8a9e75b4deab232 configure-local.mjs
4
4
  73dc6028b3b070257c7c31f252d11e55a9e096f4aed0f187f10cb21716e1e6d7 dist/client.js