@inerrata-corporation/errata 2.0.2-dev.226 → 2.0.2-dev.227

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.
@@ -15315,6 +15315,15 @@ var init_wire = __esm({
15315
15315
  /** Canonical human-readable description (no raw paths — daemon scrubs; server rechecks). */
15316
15316
  description: external_exports.string().min(1).max(4e3),
15317
15317
  attrs: external_exports.record(external_exports.string(), external_exports.unknown()).default({}),
15318
+ /** One-way origin key of the SESSION that minted this node (`ws_…`, a
15319
+ * truncated digest — never the raw session id). Stamped onto the created
15320
+ * node as `authoringSession`, which is the independence unit for the
15321
+ * evidence channels: the session that authored a claim may not corroborate
15322
+ * or refute it, while a DIFFERENT session on the same checkout may (alyssa,
15323
+ * 2026-07-31 — the workspace key made every witness on a single-checkout
15324
+ * deployment a self-corroboration). Optional + additive: absent leaves the
15325
+ * gate fail-open for that node, exactly today's behaviour. */
15326
+ originSession: external_exports.string().min(3).max(64).optional(),
15318
15327
  extractionSource: external_exports.enum(INGEST_EXTRACTION_SOURCES),
15319
15328
  validationSource: external_exports.enum(VALIDATION_SOURCES).optional(),
15320
15329
  /** Org-membrane (M2): the daemon's anchor tag — it owns the lockfile, so it
package/errata.mjs CHANGED
@@ -15616,6 +15616,15 @@ var init_wire = __esm({
15616
15616
  /** Canonical human-readable description (no raw paths — daemon scrubs; server rechecks). */
15617
15617
  description: external_exports.string().min(1).max(4e3),
15618
15618
  attrs: external_exports.record(external_exports.string(), external_exports.unknown()).default({}),
15619
+ /** One-way origin key of the SESSION that minted this node (`ws_…`, a
15620
+ * truncated digest — never the raw session id). Stamped onto the created
15621
+ * node as `authoringSession`, which is the independence unit for the
15622
+ * evidence channels: the session that authored a claim may not corroborate
15623
+ * or refute it, while a DIFFERENT session on the same checkout may (alyssa,
15624
+ * 2026-07-31 — the workspace key made every witness on a single-checkout
15625
+ * deployment a self-corroboration). Optional + additive: absent leaves the
15626
+ * gate fail-open for that node, exactly today's behaviour. */
15627
+ originSession: external_exports.string().min(3).max(64).optional(),
15619
15628
  extractionSource: external_exports.enum(INGEST_EXTRACTION_SOURCES),
15620
15629
  validationSource: external_exports.enum(VALIDATION_SOURCES).optional(),
15621
15630
  /** Org-membrane (M2): the daemon's anchor tag — it owns the lockfile, so it
@@ -16279,6 +16288,9 @@ var init_profile = __esm({
16279
16288
  });
16280
16289
 
16281
16290
  // ../../packages/local-shared/src/daemon-wire.ts
16291
+ function formatDisposition(d) {
16292
+ return `${d.recorded} recorded \xB7 ${d.unmatched} unmatched (queued) \xB7 ${d.duplicate} dup \xB7 ${d.selfGated} self`;
16293
+ }
16282
16294
  var init_daemon_wire = __esm({
16283
16295
  "../../packages/local-shared/src/daemon-wire.ts"() {
16284
16296
  "use strict";
@@ -47250,12 +47262,12 @@ var init_report_render = __esm({
47250
47262
 
47251
47263
  // src/cli.ts
47252
47264
  init_src5();
47253
- import { closeSync as closeSync2, existsSync as existsSync25, openSync as openSync2, readFileSync as readFileSync23, renameSync as renameSync3, statSync as statSync6 } from "node:fs";
47254
- import { join as join27 } from "node:path";
47265
+ import { closeSync as closeSync2, existsSync as existsSync25, openSync as openSync2, readFileSync as readFileSync24, renameSync as renameSync4, statSync as statSync6 } from "node:fs";
47266
+ import { join as join28 } from "node:path";
47255
47267
  import { spawn as spawn3 } from "node:child_process";
47256
47268
 
47257
47269
  // src/daemon.ts
47258
- import { existsSync as existsSync20, writeFileSync as writeFileSync16 } from "node:fs";
47270
+ import { existsSync as existsSync20, writeFileSync as writeFileSync17 } from "node:fs";
47259
47271
 
47260
47272
  // ../../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.8/node_modules/@hono/node-server/dist/index.mjs
47261
47273
  import { createServer as createServerHTTP } from "http";
@@ -47835,8 +47847,8 @@ init_config();
47835
47847
 
47836
47848
  // src/engine.ts
47837
47849
  import { execFileSync as execFileSync3 } from "node:child_process";
47838
- import { existsSync as existsSync19, statSync as statSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync9, renameSync as renameSync2, readFileSync as readFileSync18, writeFileSync as writeFileSync15 } from "node:fs";
47839
- import { join as join23, relative as relative6, sep as sep4 } from "node:path";
47850
+ import { existsSync as existsSync19, statSync as statSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync9, renameSync as renameSync3, readFileSync as readFileSync19, writeFileSync as writeFileSync16 } from "node:fs";
47851
+ import { join as join24, relative as relative6, sep as sep4 } from "node:path";
47840
47852
 
47841
47853
  // ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
47842
47854
  import { stat as statcb } from "fs";
@@ -48567,9 +48579,9 @@ var NodeFsHandler = class {
48567
48579
  if (this.fsw.closed) {
48568
48580
  return;
48569
48581
  }
48570
- const dirname10 = sysPath.dirname(file2);
48582
+ const dirname11 = sysPath.dirname(file2);
48571
48583
  const basename5 = sysPath.basename(file2);
48572
- const parent = this.fsw._getWatchedDir(dirname10);
48584
+ const parent = this.fsw._getWatchedDir(dirname11);
48573
48585
  let prevStats = stats;
48574
48586
  if (parent.has(basename5))
48575
48587
  return;
@@ -48596,7 +48608,7 @@ var NodeFsHandler = class {
48596
48608
  prevStats = newStats2;
48597
48609
  }
48598
48610
  } catch (error48) {
48599
- this.fsw._remove(dirname10, basename5);
48611
+ this.fsw._remove(dirname11, basename5);
48600
48612
  }
48601
48613
  } else if (parent.has(basename5)) {
48602
48614
  const at = newStats.atimeMs;
@@ -51997,109 +52009,6 @@ function createToolRunState() {
51997
52009
  // src/engine.ts
51998
52010
  init_paths();
51999
52011
 
52000
- // src/causal.ts
52001
- var SUPPRESSORS = [
52002
- { kind: "ts-nocheck", re: /@ts-nocheck\b/g },
52003
- { kind: "ts-ignore", re: /@ts-(?:ignore|expect-error)\b/g },
52004
- { kind: "eslint-disable", re: /eslint-disable(?:-next-line|-line)?\b/g },
52005
- { kind: "py-ignore", re: /#\s*(?:noqa|type:\s*ignore|pyright:\s*ignore|mypy:\s*ignore|nosec|pragma:\s*no\s*cover)\b/gi },
52006
- { kind: "test-skip", re: /\bx(?:it|describe|test)\s*\(|\.(?:skip|todo)\s*\(|@(?:pytest\.mark\.skip|unittest\.skip)|\bxfail\b|\bt\.Skip\s*\(/g },
52007
- { kind: "lint-allow", re: /\/\/\s*nolint\b|#\[allow\(|istanbul\s+ignore|c8\s+ignore/g },
52008
- { kind: "config-loosen", re: /"strict"\s*:\s*false|"skipLibCheck"\s*:\s*true|ignore_errors\s*=\s*True/gi }
52009
- ];
52010
- function detectSuppression(oldStr, newStr) {
52011
- if (!newStr) return null;
52012
- const old = oldStr ?? "";
52013
- for (const { kind, re } of SUPPRESSORS) {
52014
- const inNew = (newStr.match(re) ?? []).length;
52015
- const inOld = (old.match(re) ?? []).length;
52016
- if (inNew > inOld) return kind;
52017
- }
52018
- return null;
52019
- }
52020
- var DECL_RE = /\b(?:function|class|const|let|var|def|interface|type|enum)\s+([A-Za-z_$][\w$]*)/g;
52021
- function deriveIntentHints(tool, oldStr, newStr) {
52022
- const hints = /* @__PURE__ */ new Set();
52023
- if (tool === "Write" && (oldStr == null || oldStr === "")) hints.add("add");
52024
- if (detectSuppression(oldStr, newStr)) hints.add("suppress");
52025
- if (oldStr != null && newStr != null) {
52026
- const oldNames = new Set([...oldStr.matchAll(DECL_RE)].map((m) => m[1]));
52027
- const newNames = new Set([...newStr.matchAll(DECL_RE)].map((m) => m[1]));
52028
- const removed = [...oldNames].filter((n) => !newNames.has(n));
52029
- const added = [...newNames].filter((n) => !oldNames.has(n));
52030
- if (removed.length > 0 && added.length > 0) hints.add("rename");
52031
- else if (added.length > 0) hints.add("add");
52032
- else if (removed.length > 0) hints.add("delete");
52033
- }
52034
- return [...hints];
52035
- }
52036
- function deriveDeclaredRenames(oldStr, newStr) {
52037
- if (oldStr == null || newStr == null) return [];
52038
- const oldNames = [...oldStr.matchAll(DECL_RE)].map((m) => m[1]);
52039
- const newNames = [...newStr.matchAll(DECL_RE)].map((m) => m[1]);
52040
- const oldSet = new Set(oldNames);
52041
- const newSet = new Set(newNames);
52042
- const removed = [...new Set(oldNames.filter((n) => !newSet.has(n)))];
52043
- const added = [...new Set(newNames.filter((n) => !oldSet.has(n)))];
52044
- if (removed.length === 1 && added.length === 1) {
52045
- return [{ from: removed[0], to: added[0] }];
52046
- }
52047
- return [];
52048
- }
52049
- var CausalBuffer = class {
52050
- constructor(windowMs = 5e3, maxAgeMs = 3e4) {
52051
- this.windowMs = windowMs;
52052
- this.maxAgeMs = maxAgeMs;
52053
- }
52054
- events = [];
52055
- record(e) {
52056
- this.events.push(e);
52057
- this.prune(e.ts);
52058
- }
52059
- prune(now) {
52060
- const cutoff = now - this.maxAgeMs;
52061
- if (this.events.length > 0 && this.events[0].ts < cutoff) {
52062
- this.events = this.events.filter((e) => e.ts >= cutoff);
52063
- }
52064
- }
52065
- /**
52066
- * Correlate a reindex flush (the changed relPaths at instant `t`) to a causal
52067
- * context, if any buffered tool event touched one of those paths within the
52068
- * window. The most recent match wins for session/tool; hints are unioned.
52069
- */
52070
- correlate(relPaths, t) {
52071
- const set2 = new Set(relPaths);
52072
- const matches = this.events.filter(
52073
- (e) => set2.has(e.relPath) && Math.abs(e.ts - t) <= this.windowMs
52074
- );
52075
- if (matches.length === 0) return null;
52076
- matches.sort((a, b) => b.ts - a.ts);
52077
- const top = matches[0];
52078
- const hints = /* @__PURE__ */ new Set();
52079
- const renames = [];
52080
- const seen = /* @__PURE__ */ new Set();
52081
- for (const m of matches) {
52082
- for (const h of m.intentHints) hints.add(h);
52083
- for (const r of m.declaredRenames) {
52084
- const key = `${r.from}->${r.to}`;
52085
- if (!seen.has(key)) {
52086
- seen.add(key);
52087
- renames.push(r);
52088
- }
52089
- }
52090
- }
52091
- return {
52092
- sessionId: top.sessionId,
52093
- tool: top.tool,
52094
- intentHints: [...hints],
52095
- declaredRenames: renames
52096
- };
52097
- }
52098
- size() {
52099
- return this.events.length;
52100
- }
52101
- };
52102
-
52103
52012
  // src/profile.ts
52104
52013
  init_src2();
52105
52014
  init_paths();
@@ -52163,6 +52072,10 @@ function detectRepoLocator(root, remote) {
52163
52072
  function workspaceId(root) {
52164
52073
  return "wp_" + createHash12("sha256").update(root).digest("hex").slice(0, 12);
52165
52074
  }
52075
+ function sessionOriginKey(sessionId) {
52076
+ if (!sessionId) return void 0;
52077
+ return "ws_" + createHash12("sha256").update(sessionId).digest("hex").slice(0, 12);
52078
+ }
52166
52079
  function refreshRepoLocator(root, profile) {
52167
52080
  const detected = detectRepoLocator(root, profile.repoRemote);
52168
52081
  if (!detected || detected === profile.repoLocator) return false;
@@ -52242,6 +52155,160 @@ function autodetectProfile(root) {
52242
52155
  return p;
52243
52156
  }
52244
52157
 
52158
+ // src/witness-queue.ts
52159
+ import { readFileSync as readFileSync18, renameSync as renameSync2, writeFileSync as writeFileSync15 } from "node:fs";
52160
+ import { dirname as dirname9, join as join23 } from "node:path";
52161
+ var WITNESS_QUEUE_CAP = 500;
52162
+ var WITNESS_TTL_MS = 14 * 24 * 60 * 60 * 1e3;
52163
+ var WITNESS_MAX_ATTEMPTS = 5;
52164
+ function witnessQueuePath(workspaceConfigDir) {
52165
+ return join23(workspaceConfigDir, "witness-queue.json");
52166
+ }
52167
+ function loadWitnessQueue(path2) {
52168
+ try {
52169
+ const raw2 = JSON.parse(readFileSync18(path2, "utf8"));
52170
+ if (!Array.isArray(raw2)) return [];
52171
+ return raw2.filter(
52172
+ (w) => !!w && typeof w === "object" && typeof w.nodeId === "string" && typeof w.witnessKey === "string"
52173
+ );
52174
+ } catch {
52175
+ return [];
52176
+ }
52177
+ }
52178
+ function saveWitnessQueue(path2, queue) {
52179
+ try {
52180
+ const tmp = join23(dirname9(path2), `.${Date.now()}.witness-queue.tmp`);
52181
+ writeFileSync15(tmp, JSON.stringify(queue), "utf8");
52182
+ renameSync2(tmp, path2);
52183
+ } catch {
52184
+ }
52185
+ }
52186
+ function pruneWitnessQueue(queue, now) {
52187
+ const live = queue.filter(
52188
+ (w) => now - w.ts < WITNESS_TTL_MS && w.attempts < WITNESS_MAX_ATTEMPTS
52189
+ );
52190
+ return live.length > WITNESS_QUEUE_CAP ? live.slice(live.length - WITNESS_QUEUE_CAP) : live;
52191
+ }
52192
+ function enqueueWitnesses(queue, fresh, now) {
52193
+ const byKey = new Map(queue.map((w) => [`${w.channel}:${w.witnessKey}`, w]));
52194
+ for (const f of fresh) {
52195
+ const k = `${f.channel}:${f.witnessKey}`;
52196
+ const existing = byKey.get(k);
52197
+ if (existing) existing.attempts += 1;
52198
+ else byKey.set(k, { ...f, ts: now, attempts: 1 });
52199
+ }
52200
+ return pruneWitnessQueue([...byKey.values()], now);
52201
+ }
52202
+ function pendingFor(queue, channel) {
52203
+ return queue.filter((w) => w.channel === channel);
52204
+ }
52205
+ function retireWitnesses(queue, channel, settledKeys) {
52206
+ return queue.filter((w) => !(w.channel === channel && settledKeys.has(w.witnessKey)));
52207
+ }
52208
+
52209
+ // src/causal.ts
52210
+ var SUPPRESSORS = [
52211
+ { kind: "ts-nocheck", re: /@ts-nocheck\b/g },
52212
+ { kind: "ts-ignore", re: /@ts-(?:ignore|expect-error)\b/g },
52213
+ { kind: "eslint-disable", re: /eslint-disable(?:-next-line|-line)?\b/g },
52214
+ { kind: "py-ignore", re: /#\s*(?:noqa|type:\s*ignore|pyright:\s*ignore|mypy:\s*ignore|nosec|pragma:\s*no\s*cover)\b/gi },
52215
+ { kind: "test-skip", re: /\bx(?:it|describe|test)\s*\(|\.(?:skip|todo)\s*\(|@(?:pytest\.mark\.skip|unittest\.skip)|\bxfail\b|\bt\.Skip\s*\(/g },
52216
+ { kind: "lint-allow", re: /\/\/\s*nolint\b|#\[allow\(|istanbul\s+ignore|c8\s+ignore/g },
52217
+ { kind: "config-loosen", re: /"strict"\s*:\s*false|"skipLibCheck"\s*:\s*true|ignore_errors\s*=\s*True/gi }
52218
+ ];
52219
+ function detectSuppression(oldStr, newStr) {
52220
+ if (!newStr) return null;
52221
+ const old = oldStr ?? "";
52222
+ for (const { kind, re } of SUPPRESSORS) {
52223
+ const inNew = (newStr.match(re) ?? []).length;
52224
+ const inOld = (old.match(re) ?? []).length;
52225
+ if (inNew > inOld) return kind;
52226
+ }
52227
+ return null;
52228
+ }
52229
+ var DECL_RE = /\b(?:function|class|const|let|var|def|interface|type|enum)\s+([A-Za-z_$][\w$]*)/g;
52230
+ function deriveIntentHints(tool, oldStr, newStr) {
52231
+ const hints = /* @__PURE__ */ new Set();
52232
+ if (tool === "Write" && (oldStr == null || oldStr === "")) hints.add("add");
52233
+ if (detectSuppression(oldStr, newStr)) hints.add("suppress");
52234
+ if (oldStr != null && newStr != null) {
52235
+ const oldNames = new Set([...oldStr.matchAll(DECL_RE)].map((m) => m[1]));
52236
+ const newNames = new Set([...newStr.matchAll(DECL_RE)].map((m) => m[1]));
52237
+ const removed = [...oldNames].filter((n) => !newNames.has(n));
52238
+ const added = [...newNames].filter((n) => !oldNames.has(n));
52239
+ if (removed.length > 0 && added.length > 0) hints.add("rename");
52240
+ else if (added.length > 0) hints.add("add");
52241
+ else if (removed.length > 0) hints.add("delete");
52242
+ }
52243
+ return [...hints];
52244
+ }
52245
+ function deriveDeclaredRenames(oldStr, newStr) {
52246
+ if (oldStr == null || newStr == null) return [];
52247
+ const oldNames = [...oldStr.matchAll(DECL_RE)].map((m) => m[1]);
52248
+ const newNames = [...newStr.matchAll(DECL_RE)].map((m) => m[1]);
52249
+ const oldSet = new Set(oldNames);
52250
+ const newSet = new Set(newNames);
52251
+ const removed = [...new Set(oldNames.filter((n) => !newSet.has(n)))];
52252
+ const added = [...new Set(newNames.filter((n) => !oldSet.has(n)))];
52253
+ if (removed.length === 1 && added.length === 1) {
52254
+ return [{ from: removed[0], to: added[0] }];
52255
+ }
52256
+ return [];
52257
+ }
52258
+ var CausalBuffer = class {
52259
+ constructor(windowMs = 5e3, maxAgeMs = 3e4) {
52260
+ this.windowMs = windowMs;
52261
+ this.maxAgeMs = maxAgeMs;
52262
+ }
52263
+ events = [];
52264
+ record(e) {
52265
+ this.events.push(e);
52266
+ this.prune(e.ts);
52267
+ }
52268
+ prune(now) {
52269
+ const cutoff = now - this.maxAgeMs;
52270
+ if (this.events.length > 0 && this.events[0].ts < cutoff) {
52271
+ this.events = this.events.filter((e) => e.ts >= cutoff);
52272
+ }
52273
+ }
52274
+ /**
52275
+ * Correlate a reindex flush (the changed relPaths at instant `t`) to a causal
52276
+ * context, if any buffered tool event touched one of those paths within the
52277
+ * window. The most recent match wins for session/tool; hints are unioned.
52278
+ */
52279
+ correlate(relPaths, t) {
52280
+ const set2 = new Set(relPaths);
52281
+ const matches = this.events.filter(
52282
+ (e) => set2.has(e.relPath) && Math.abs(e.ts - t) <= this.windowMs
52283
+ );
52284
+ if (matches.length === 0) return null;
52285
+ matches.sort((a, b) => b.ts - a.ts);
52286
+ const top = matches[0];
52287
+ const hints = /* @__PURE__ */ new Set();
52288
+ const renames = [];
52289
+ const seen = /* @__PURE__ */ new Set();
52290
+ for (const m of matches) {
52291
+ for (const h of m.intentHints) hints.add(h);
52292
+ for (const r of m.declaredRenames) {
52293
+ const key = `${r.from}->${r.to}`;
52294
+ if (!seen.has(key)) {
52295
+ seen.add(key);
52296
+ renames.push(r);
52297
+ }
52298
+ }
52299
+ }
52300
+ return {
52301
+ sessionId: top.sessionId,
52302
+ tool: top.tool,
52303
+ intentHints: [...hints],
52304
+ declaredRenames: renames
52305
+ };
52306
+ }
52307
+ size() {
52308
+ return this.events.length;
52309
+ }
52310
+ };
52311
+
52245
52312
  // src/engine.ts
52246
52313
  init_config();
52247
52314
  init_cloud_auth();
@@ -52391,7 +52458,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
52391
52458
  }
52392
52459
 
52393
52460
  // src/engine.ts
52394
- var DAEMON_VERSION = true ? "2.0.2-dev.226" : "2.0.0-alpha.0";
52461
+ var DAEMON_VERSION = true ? "2.0.2-dev.227" : "2.0.0-alpha.0";
52395
52462
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
52396
52463
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
52397
52464
  var GIT_OP_MUTE_MS = 4e3;
@@ -52402,7 +52469,7 @@ function appendIdentityAudit(path2, record2, line) {
52402
52469
  if (!record2.accepted && record2.score <= 0) return;
52403
52470
  try {
52404
52471
  if (existsSync19(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
52405
- renameSync2(path2, `${path2}.1`);
52472
+ renameSync3(path2, `${path2}.1`);
52406
52473
  }
52407
52474
  appendFileSync2(path2, line);
52408
52475
  } catch {
@@ -52411,7 +52478,7 @@ function appendIdentityAudit(path2, record2, line) {
52411
52478
  var yieldToLoop = () => new Promise((r) => setImmediate(r));
52412
52479
  function loadTurnCursors(path2) {
52413
52480
  try {
52414
- const raw2 = JSON.parse(readFileSync18(path2, "utf8"));
52481
+ const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
52415
52482
  return new Map(
52416
52483
  Object.entries(raw2).map(([k, v]) => [k, typeof v === "string" ? v : String(v?.uuid ?? "")])
52417
52484
  );
@@ -52421,7 +52488,7 @@ function loadTurnCursors(path2) {
52421
52488
  }
52422
52489
  function loadTurnOffsets(path2) {
52423
52490
  try {
52424
- const raw2 = JSON.parse(readFileSync18(path2, "utf8"));
52491
+ const raw2 = JSON.parse(readFileSync19(path2, "utf8"));
52425
52492
  const out2 = /* @__PURE__ */ new Map();
52426
52493
  for (const [k, v] of Object.entries(raw2)) {
52427
52494
  const off = typeof v === "object" && v !== null ? v.offset : void 0;
@@ -52437,7 +52504,7 @@ function saveTurnCursors(path2, cursors, offsets) {
52437
52504
  const merged = {};
52438
52505
  for (const [k, uuid3] of cursors) merged[k] = { uuid: uuid3, offset: offsets.get(k) ?? 0 };
52439
52506
  for (const [k, offset] of offsets) if (!merged[k]) merged[k] = { uuid: "", offset };
52440
- writeFileSync15(path2, JSON.stringify(merged), "utf8");
52507
+ writeFileSync16(path2, JSON.stringify(merged), "utf8");
52441
52508
  } catch {
52442
52509
  }
52443
52510
  }
@@ -52459,7 +52526,7 @@ function gitSourceWatchTargets(root) {
52459
52526
  ["-C", root, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"],
52460
52527
  { encoding: "utf8", maxBuffer: 256 * 1024 * 1024, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
52461
52528
  );
52462
- ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join23(root, d) + sep4));
52529
+ ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join24(root, d) + sep4));
52463
52530
  } catch {
52464
52531
  }
52465
52532
  const hasIgnoredChild = (dir) => ignoredDirs.some((ig) => ig.startsWith(dir + "/"));
@@ -52471,19 +52538,19 @@ function gitSourceWatchTargets(root) {
52471
52538
  if (!f.startsWith(prefix)) continue;
52472
52539
  const rest2 = f.slice(prefix.length);
52473
52540
  if (rest2.includes("/")) children.add(dir === "" ? rest2.slice(0, rest2.indexOf("/")) : dir + "/" + rest2.slice(0, rest2.indexOf("/")));
52474
- else targets.add(join23(root, f));
52541
+ else targets.add(join24(root, f));
52475
52542
  }
52476
52543
  for (const c of children) {
52477
- if (IGNORED_PATH.test(join23(root, c) + sep4)) continue;
52544
+ if (IGNORED_PATH.test(join24(root, c) + sep4)) continue;
52478
52545
  if (hasIgnoredChild(c)) addUnder(c);
52479
- else targets.add(join23(root, c));
52546
+ else targets.add(join24(root, c));
52480
52547
  }
52481
52548
  };
52482
52549
  addUnder("");
52483
52550
  if (targets.size > 0) return [...targets];
52484
52551
  } catch {
52485
52552
  }
52486
- return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join23(root, String(e.name)) + sep4)).map((e) => join23(root, String(e.name)));
52553
+ return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join24(root, String(e.name)) + sep4)).map((e) => join24(root, String(e.name)));
52487
52554
  }
52488
52555
  function createWorkspaceEngine(opts) {
52489
52556
  const paths = workspacePaths(opts.workspaceRoot);
@@ -52498,6 +52565,10 @@ function createWorkspaceEngine(opts) {
52498
52565
  refreshRepoLocator(opts.workspaceRoot, profile);
52499
52566
  }
52500
52567
  const store = openGraphStore({ path: paths.castalia });
52568
+ let witnessQueue = pruneWitnessQueue(
52569
+ loadWitnessQueue(witnessQueuePath(paths.configDir)),
52570
+ Date.now()
52571
+ );
52501
52572
  const log = openEventLog({ path: paths.eventLog });
52502
52573
  const bundled = import.meta.url.endsWith(".mjs");
52503
52574
  const passWorker = bundled && paths.castalia !== ":memory:" ? new PassWorker({
@@ -52637,7 +52708,7 @@ function createWorkspaceEngine(opts) {
52637
52708
  const srcPaths = diff.changedPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(p));
52638
52709
  let episodeId2;
52639
52710
  if (srcPaths.length > 0) {
52640
- const abs = srcPaths.map((p) => join23(opts.workspaceRoot, p));
52711
+ const abs = srcPaths.map((p) => join24(opts.workspaceRoot, p));
52641
52712
  try {
52642
52713
  const r = await runReindexPass(
52643
52714
  `git-reindex:${profile.name} (${abs.length} files)`,
@@ -52673,7 +52744,7 @@ function createWorkspaceEngine(opts) {
52673
52744
  `[errata] git: ${ev.kind} ${ev.newSha.slice(0, 7)} by ${meta3.authorName} \u2014 ${diff.changedPaths.length} file(s), ${diff.renames.length} rename(s)`
52674
52745
  );
52675
52746
  };
52676
- const gitDir = join23(opts.workspaceRoot, ".git");
52747
+ const gitDir = join24(opts.workspaceRoot, ".git");
52677
52748
  if (existsSync19(gitDir)) {
52678
52749
  stopGit = startGitSensor(gitDir, (ev) => {
52679
52750
  void handleGitEvent(ev).catch((err2) => {
@@ -52744,10 +52815,10 @@ function createWorkspaceEngine(opts) {
52744
52815
  });
52745
52816
  doneRender?.();
52746
52817
  writeContextFile(opts.workspaceRoot, body2);
52747
- const target = join23(opts.workspaceRoot, "AGENTS.md");
52818
+ const target = join24(opts.workspaceRoot, "AGENTS.md");
52748
52819
  writeManagedBlock(target, { body: AGENTS_POINTER_BODY, stable: true, force: true });
52749
52820
  if (elicit) {
52750
- writePrimingHandles(join23(paths.configDir, "priming-handles.json"), [
52821
+ writePrimingHandles(join24(paths.configDir, "priming-handles.json"), [
52751
52822
  ...snapshot.recentProblems.map((r) => r.node),
52752
52823
  // Resolved-band handles: the ✓ problem AND its Solution are citable
52753
52824
  // (a fix tag on an already-resolved problem no-ops idempotently; the
@@ -52952,7 +53023,7 @@ function createWorkspaceEngine(opts) {
52952
53023
  resultSummary: { exitCode: e.exitCode ?? 1, errorTokens: e.errorTokens }
52953
53024
  });
52954
53025
  };
52955
- const turnCursorPath = join23(paths.configDir, "turn-cursors.json");
53026
+ const turnCursorPath = join24(paths.configDir, "turn-cursors.json");
52956
53027
  const lastTurnUuid = loadTurnCursors(turnCursorPath);
52957
53028
  const turnOffset = loadTurnOffsets(turnCursorPath);
52958
53029
  const sessionLastProblem = /* @__PURE__ */ new Map();
@@ -52976,7 +53047,7 @@ function createWorkspaceEngine(opts) {
52976
53047
  const t = Date.now();
52977
53048
  let processedTurns = 0;
52978
53049
  const elicit = isEdgeElicitationEnabled();
52979
- const handleMap = elicit ? readPrimingHandles(join23(paths.configDir, "priming-handles.json")) : {};
53050
+ const handleMap = elicit ? readPrimingHandles(join24(paths.configDir, "priming-handles.json")) : {};
52980
53051
  const wsRoot = (opts.workspaceRoot ?? "").replace(/\\/g, "/");
52981
53052
  const toRel = (abs) => {
52982
53053
  const p = abs.replace(/\\/g, "/");
@@ -53318,18 +53389,83 @@ function createWorkspaceEngine(opts) {
53318
53389
  mintCiteEdge(solId, targetId, sl.relation, 0.4, { solutionStructure: true, hypothesis: true });
53319
53390
  }
53320
53391
  }
53321
- if (plan.refutes.length > 0 && typeof cloud.reportContradictions === "function") {
53322
- void cloud.reportContradictions({ daemonVersion: DAEMON_VERSION, projectId: profile.id, items: stampWitnessOrigin(plan.refutes, profile.id) }).then((r) => {
53323
- if (r?.recorded) console.log(`[errata] refute: ${r.recorded} contradiction(s) recorded`);
53324
- }).catch(
53325
- (err2) => console.warn("[errata] refute transport failed (continuing):", err2 instanceof Error ? err2.message : err2)
53392
+ const citingSession = sessionOriginKey(sessionId);
53393
+ const mintedHere = (nodeId) => store.getNode(nodeId)?.attrs["sources"]?.[0] === sessionId;
53394
+ const sendWitnesses = async (channel, fresh, send) => {
53395
+ const queued = pendingFor(witnessQueue, channel);
53396
+ if (fresh.length === 0 && queued.length === 0) return;
53397
+ const groups = /* @__PURE__ */ new Map();
53398
+ for (const q of queued) {
53399
+ const g = groups.get(q.sessionKey) ?? [];
53400
+ g.push({ nodeId: q.nodeId, witnessKey: q.witnessKey });
53401
+ groups.set(q.sessionKey, g);
53402
+ }
53403
+ const freshGroup = groups.get(citingSession) ?? [];
53404
+ for (const f of fresh) {
53405
+ if (freshGroup.some((x) => x.witnessKey === f.witnessKey)) continue;
53406
+ freshGroup.push(f);
53407
+ }
53408
+ groups.set(citingSession, freshGroup);
53409
+ const settled = /* @__PURE__ */ new Set();
53410
+ const stillUnmatched = [];
53411
+ let recorded = 0, unmatched = 0, duplicate = 0, selfGated = 0;
53412
+ for (const [session, items2] of groups) {
53413
+ if (items2.length === 0) continue;
53414
+ try {
53415
+ const raw2 = await send(items2, session);
53416
+ const d = {
53417
+ recorded: raw2?.recorded ?? 0,
53418
+ unmatched: raw2?.unmatched ?? 0,
53419
+ duplicate: raw2?.duplicate ?? 0,
53420
+ selfGated: raw2?.selfGated ?? 0,
53421
+ unmatchedIds: raw2?.unmatchedIds ?? []
53422
+ };
53423
+ recorded += d.recorded;
53424
+ unmatched += d.unmatched;
53425
+ duplicate += d.duplicate;
53426
+ selfGated += d.selfGated;
53427
+ const missing = new Set(d.unmatchedIds);
53428
+ for (const it of items2) {
53429
+ if (missing.has(it.nodeId)) stillUnmatched.push({ channel, ...it, sessionKey: session });
53430
+ else settled.add(it.witnessKey);
53431
+ }
53432
+ } catch (err2) {
53433
+ console.warn(`[errata] ${channel} transport failed (witnesses kept for retry):`, err2 instanceof Error ? err2.message : err2);
53434
+ for (const it of items2) stillUnmatched.push({ channel, ...it, sessionKey: session });
53435
+ }
53436
+ }
53437
+ witnessQueue = retireWitnesses(witnessQueue, channel, settled);
53438
+ witnessQueue = enqueueWitnesses(witnessQueue, stillUnmatched, Date.now());
53439
+ saveWitnessQueue(witnessQueuePath(paths.configDir), witnessQueue);
53440
+ console.log(
53441
+ `[errata] ${channel}: ${formatDisposition({ recorded, unmatched, duplicate, selfGated })}` + (queued.length > 0 ? ` (incl. ${queued.length} replayed)` : "")
53442
+ );
53443
+ };
53444
+ if (typeof cloud.reportContradictions === "function") {
53445
+ await sendWitnesses(
53446
+ "contradict",
53447
+ plan.refutes,
53448
+ (items2, session) => cloud.reportContradictions({
53449
+ daemonVersion: DAEMON_VERSION,
53450
+ projectId: profile.id,
53451
+ ...session ? { sessionId: session } : {},
53452
+ items: stampWitnessOrigin(items2, profile.id)
53453
+ })
53326
53454
  );
53327
53455
  }
53328
- if (plan.corroborations.length > 0 && typeof cloud.reportCorroborations === "function") {
53329
- void cloud.reportCorroborations({ daemonVersion: DAEMON_VERSION, projectId: profile.id, items: stampWitnessOrigin(plan.corroborations, profile.id) }).then((r) => {
53330
- if (r?.recorded) console.log(`[errata] corroborate: ${r.recorded} corroboration(s) recorded`);
53331
- }).catch(
53332
- (err2) => console.warn("[errata] corroboration transport failed (continuing):", err2 instanceof Error ? err2.message : err2)
53456
+ if (typeof cloud.reportCorroborations === "function") {
53457
+ const emit = plan.corroborations.filter((c) => !mintedHere(c.nodeId));
53458
+ const skipped = plan.corroborations.length - emit.length;
53459
+ if (skipped > 0) console.log(`[errata] corroborate: ${skipped} skipped (this session authored the node)`);
53460
+ await sendWitnesses(
53461
+ "corroborate",
53462
+ emit,
53463
+ (items2, session) => cloud.reportCorroborations({
53464
+ daemonVersion: DAEMON_VERSION,
53465
+ projectId: profile.id,
53466
+ ...session ? { sessionId: session } : {},
53467
+ items: stampWitnessOrigin(items2, profile.id)
53468
+ })
53333
53469
  );
53334
53470
  }
53335
53471
  } catch (err2) {
@@ -53522,7 +53658,7 @@ function createWorkspaceEngine(opts) {
53522
53658
  try {
53523
53659
  const inputs = emitInputsFromManifest(paths.configDir, paths.skillsManifest);
53524
53660
  emitAndProjectSkills(opts.workspaceRoot, inputs);
53525
- writePrimingHandles(join23(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
53661
+ writePrimingHandles(join24(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
53526
53662
  } catch (err2) {
53527
53663
  console.warn("[skills] agent-skills projection failed (non-fatal):", err2 instanceof Error ? err2.message : err2);
53528
53664
  }
@@ -53796,7 +53932,7 @@ async function startDaemon(opts) {
53796
53932
  reviewUrl: () => webUiUrl + "/review"
53797
53933
  });
53798
53934
  const writeLockFile = (url2) => {
53799
- writeFileSync16(
53935
+ writeFileSync17(
53800
53936
  engine.paths.daemonLock,
53801
53937
  JSON.stringify({ pid: process.pid, webUiUrl: url2, startedAt: Date.now() }),
53802
53938
  "utf8"
@@ -53856,16 +53992,16 @@ async function listenServer(fetchFn, port) {
53856
53992
 
53857
53993
  // src/registry.ts
53858
53994
  init_paths();
53859
- import { existsSync as existsSync21, readFileSync as readFileSync19, writeFileSync as writeFileSync17 } from "node:fs";
53860
- import { join as join24 } from "node:path";
53995
+ import { existsSync as existsSync21, readFileSync as readFileSync20, writeFileSync as writeFileSync18 } from "node:fs";
53996
+ import { join as join25 } from "node:path";
53861
53997
  function registryPath() {
53862
- return process.env["ERRATA_REGISTRY_PATH"] ?? join24(globalDir(), "workspaces.json");
53998
+ return process.env["ERRATA_REGISTRY_PATH"] ?? join25(globalDir(), "workspaces.json");
53863
53999
  }
53864
54000
  function read() {
53865
54001
  const p = registryPath();
53866
54002
  if (!existsSync21(p)) return { version: 1, workspaces: {} };
53867
54003
  try {
53868
- const parsed = JSON.parse(readFileSync19(p, "utf8"));
54004
+ const parsed = JSON.parse(readFileSync20(p, "utf8"));
53869
54005
  return { version: 1, workspaces: parsed.workspaces ?? {} };
53870
54006
  } catch {
53871
54007
  return { version: 1, workspaces: {} };
@@ -53873,7 +54009,7 @@ function read() {
53873
54009
  }
53874
54010
  function write(reg) {
53875
54011
  ensureDir(globalDir());
53876
- writeFileSync17(registryPath(), JSON.stringify(reg, null, 2), "utf8");
54012
+ writeFileSync18(registryPath(), JSON.stringify(reg, null, 2), "utf8");
53877
54013
  }
53878
54014
  function registerWorkspace(profile, root, now = Date.now()) {
53879
54015
  const reg = read();
@@ -53905,7 +54041,7 @@ function workspaceStatus(entry) {
53905
54041
  let webUiUrl = null;
53906
54042
  if (existsSync21(lockPath)) {
53907
54043
  try {
53908
- const lock = JSON.parse(readFileSync19(lockPath, "utf8"));
54044
+ const lock = JSON.parse(readFileSync20(lockPath, "utf8"));
53909
54045
  if (lock.pid && lock.webUiUrl && pidAlive(lock.pid)) {
53910
54046
  running = true;
53911
54047
  webUiUrl = lock.webUiUrl;
@@ -53933,7 +54069,7 @@ function pidAlive(pid) {
53933
54069
  // src/multi.ts
53934
54070
  init_dist();
53935
54071
  init_src4();
53936
- import { readFileSync as readFileSync22, unlinkSync as unlinkSync3, writeFileSync as writeFileSync18 } from "node:fs";
54072
+ import { readFileSync as readFileSync23, unlinkSync as unlinkSync3, writeFileSync as writeFileSync19 } from "node:fs";
53937
54073
 
53938
54074
  // src/principle-sync.ts
53939
54075
  init_src4();
@@ -53961,8 +54097,8 @@ init_reconcile();
53961
54097
 
53962
54098
  // src/lockfile-auto.ts
53963
54099
  init_src();
53964
- import { existsSync as existsSync22, readFileSync as readFileSync20 } from "node:fs";
53965
- import { join as join25 } from "node:path";
54100
+ import { existsSync as existsSync22, readFileSync as readFileSync21 } from "node:fs";
54101
+ import { join as join26 } from "node:path";
53966
54102
 
53967
54103
  // src/package-index.ts
53968
54104
  init_src();
@@ -54111,11 +54247,11 @@ function runLockfilePass(opts) {
54111
54247
  { file: "package-lock.json", parse: parsePackageLockJson }
54112
54248
  ];
54113
54249
  for (const c of candidates) {
54114
- const p = join25(opts.root, c.file);
54250
+ const p = join26(opts.root, c.file);
54115
54251
  if (!existsSync22(p)) continue;
54116
54252
  let sbom;
54117
54253
  try {
54118
- sbom = c.parse(readFileSync20(p, "utf8"));
54254
+ sbom = c.parse(readFileSync21(p, "utf8"));
54119
54255
  } catch {
54120
54256
  continue;
54121
54257
  }
@@ -54225,10 +54361,15 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
54225
54361
  const level = opts.level ?? 1;
54226
54362
  const noveltyOpts = opts.dedupCosine != null ? { dedupCosine: opts.dedupCosine } : {};
54227
54363
  const ignored = (text) => ignorePatterns.length > 0 && ignorePatterns.some((p) => text.toLowerCase().includes(p));
54364
+ const originSessionOf = (n) => {
54365
+ const key = sessionOriginKey(n.attrs["sources"]?.[0]);
54366
+ return key ? { originSession: key } : {};
54367
+ };
54228
54368
  const shareable = (n) => ({
54229
54369
  ...n,
54230
54370
  description: generalize(n.description, { level }).text,
54231
54371
  embedding: [],
54372
+ ...originSessionOf(n),
54232
54373
  attrs: {
54233
54374
  scope: stripCodebaseScope(n.attrs["scope"]),
54234
54375
  ...n.attrs["kind"] ? { kind: n.attrs["kind"] } : {},
@@ -54558,7 +54699,7 @@ var ConsolidateWorker = class {
54558
54699
  init_paths();
54559
54700
 
54560
54701
  // src/lock.ts
54561
- import { existsSync as existsSync23, readFileSync as readFileSync21 } from "node:fs";
54702
+ import { existsSync as existsSync23, readFileSync as readFileSync22 } from "node:fs";
54562
54703
  function isProcessAlive(pid) {
54563
54704
  if (!pid || pid <= 0) return false;
54564
54705
  try {
@@ -54571,7 +54712,7 @@ function isProcessAlive(pid) {
54571
54712
  function readDaemonLock(lockPath) {
54572
54713
  if (!existsSync23(lockPath)) return null;
54573
54714
  try {
54574
- const lock = JSON.parse(readFileSync21(lockPath, "utf8"));
54715
+ const lock = JSON.parse(readFileSync22(lockPath, "utf8"));
54575
54716
  return typeof lock.pid === "number" ? lock : null;
54576
54717
  } catch {
54577
54718
  return null;
@@ -54814,12 +54955,12 @@ async function reanchorProject(opts) {
54814
54955
 
54815
54956
  // src/adopt.ts
54816
54957
  import { existsSync as existsSync24 } from "node:fs";
54817
- import { dirname as dirname9, join as join26 } from "node:path";
54958
+ import { dirname as dirname10, join as join27 } from "node:path";
54818
54959
  function findGitRoot(absPath) {
54819
54960
  let dir = absPath;
54820
54961
  for (let depth = 0; depth < 64; depth++) {
54821
- if (existsSync24(join26(dir, ".git"))) return dir;
54822
- const parent = dirname9(dir);
54962
+ if (existsSync24(join27(dir, ".git"))) return dir;
54963
+ const parent = dirname10(dir);
54823
54964
  if (parent === dir) return null;
54824
54965
  dir = parent;
54825
54966
  }
@@ -55067,7 +55208,7 @@ async function startMultiDaemon(opts = {}) {
55067
55208
  void ambientLinkAll();
55068
55209
  app.route(`/ws/${rec.id}`, rec.webApp);
55069
55210
  try {
55070
- writeFileSync18(
55211
+ writeFileSync19(
55071
55212
  rec.engine.paths.daemonLock,
55072
55213
  JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
55073
55214
  "utf8"
@@ -55256,7 +55397,7 @@ async function startMultiDaemon(opts = {}) {
55256
55397
  baseUrl = `http://127.0.0.1:${port}`;
55257
55398
  try {
55258
55399
  ensureDir(globalDir());
55259
- writeFileSync18(
55400
+ writeFileSync19(
55260
55401
  lockPath,
55261
55402
  JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
55262
55403
  "utf8"
@@ -55265,7 +55406,7 @@ async function startMultiDaemon(opts = {}) {
55265
55406
  }
55266
55407
  for (const r of records) {
55267
55408
  try {
55268
- writeFileSync18(
55409
+ writeFileSync19(
55269
55410
  r.engine.paths.daemonLock,
55270
55411
  JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
55271
55412
  "utf8"
@@ -55748,7 +55889,7 @@ async function startMultiDaemon(opts = {}) {
55748
55889
  },
55749
55890
  async stop() {
55750
55891
  try {
55751
- const cur = readFileSync22(lockPath, "utf8");
55892
+ const cur = readFileSync23(lockPath, "utf8");
55752
55893
  if (JSON.parse(cur).pid === process.pid) unlinkSync3(lockPath);
55753
55894
  } catch {
55754
55895
  }
@@ -56766,20 +56907,20 @@ async function cmdInit() {
56766
56907
  console.log("");
56767
56908
  console.log("installing harness hooks...");
56768
56909
  const { existsSync: existsSync26 } = await import("node:fs");
56769
- const { join: join28 } = await import("node:path");
56910
+ const { join: join29 } = await import("node:path");
56770
56911
  try {
56771
56912
  await installClaudeHooks(port);
56772
56913
  } catch (err2) {
56773
56914
  console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
56774
56915
  }
56775
- if (existsSync26(join28(ROOT, ".cursor"))) {
56916
+ if (existsSync26(join29(ROOT, ".cursor"))) {
56776
56917
  try {
56777
56918
  await installCursorMcpConfig();
56778
56919
  } catch (err2) {
56779
56920
  console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
56780
56921
  }
56781
56922
  }
56782
- if (existsSync26(join28(ROOT, ".codex"))) {
56923
+ if (existsSync26(join29(ROOT, ".codex"))) {
56783
56924
  try {
56784
56925
  await installCodexHooks(port);
56785
56926
  } catch (err2) {
@@ -57593,7 +57734,7 @@ async function cmdReview() {
57593
57734
  console.log("(review queue empty)");
57594
57735
  return;
57595
57736
  }
57596
- const queue = JSON.parse(readFileSync23(paths.reviewQueue, "utf8"));
57737
+ const queue = JSON.parse(readFileSync24(paths.reviewQueue, "utf8"));
57597
57738
  if (queue.length === 0) {
57598
57739
  console.log("(review queue empty)");
57599
57740
  return;
@@ -58303,7 +58444,7 @@ async function gatherReportData(generatedAt) {
58303
58444
  };
58304
58445
  }
58305
58446
  async function cmdReport(args2) {
58306
- const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync19 } = await import("node:fs");
58447
+ const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync20 } = await import("node:fs");
58307
58448
  const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
58308
58449
  const includeFutureVerbs = args2.includes("--future-verbs");
58309
58450
  const now = /* @__PURE__ */ new Date();
@@ -58316,8 +58457,8 @@ async function cmdReport(args2) {
58316
58457
  const outDir = workspacePaths(ROOT).configDir;
58317
58458
  mkdirSync8(outDir, { recursive: true });
58318
58459
  const files = renderReport2(data, { includeFutureVerbs });
58319
- for (const f of files) writeFileSync19(join27(outDir, f.name), f.html, "utf8");
58320
- const indexPath = join27(outDir, "report.html");
58460
+ for (const f of files) writeFileSync20(join28(outDir, f.name), f.html, "utf8");
58461
+ const indexPath = join28(outDir, "report.html");
58321
58462
  console.log(`report \u2192 ${indexPath}`);
58322
58463
  console.log(
58323
58464
  ` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
@@ -58369,7 +58510,7 @@ function spawnDaemonDetached() {
58369
58510
  try {
58370
58511
  const logPath = daemonLogPath();
58371
58512
  try {
58372
- if (statSync6(logPath).size > 5 * 1024 * 1024) renameSync3(logPath, `${logPath}.1`);
58513
+ if (statSync6(logPath).size > 5 * 1024 * 1024) renameSync4(logPath, `${logPath}.1`);
58373
58514
  } catch {
58374
58515
  }
58375
58516
  out2 = openSync2(logPath, "a");
@@ -58435,15 +58576,15 @@ function hookRelayCommand(port, path2) {
58435
58576
  return process.platform === "win32" ? `cmd //c "curl -s --connect-timeout 1 --max-time 2 -X POST -H \\"Content-Type: application/json\\" --data-binary @- ${url2} 2>NUL || echo {}"` : `curl -s --connect-timeout 1 --max-time 2 -X POST -H 'Content-Type: application/json' --data-binary @- ${url2} 2>/dev/null || echo '{}'`;
58436
58577
  }
58437
58578
  async function installClaudeHooks(port) {
58438
- const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync24, writeFileSync: writeFileSync19 } = await import("node:fs");
58439
- const { join: join28 } = await import("node:path");
58440
- const dir = join28(ROOT, ".claude");
58579
+ const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
58580
+ const { join: join29 } = await import("node:path");
58581
+ const dir = join29(ROOT, ".claude");
58441
58582
  if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
58442
- const file2 = join28(dir, "settings.json");
58583
+ const file2 = join29(dir, "settings.json");
58443
58584
  let settings = {};
58444
58585
  if (existsSync26(file2)) {
58445
58586
  try {
58446
- settings = JSON.parse(readFileSync24(file2, "utf8"));
58587
+ settings = JSON.parse(readFileSync25(file2, "utf8"));
58447
58588
  } catch {
58448
58589
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
58449
58590
  process.exit(2);
@@ -58489,10 +58630,10 @@ async function installClaudeHooks(port) {
58489
58630
  dropErrata(list);
58490
58631
  list.push({ hooks: [{ type: "command", command: injectCmd }] });
58491
58632
  }
58492
- writeFileSync19(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
58633
+ writeFileSync20(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
58493
58634
  console.log(`installed Claude Code hooks \u2192 ${file2}`);
58494
58635
  await installClaudeMcpConfig();
58495
- const claudeMd = join28(ROOT, "CLAUDE.md");
58636
+ const claudeMd = join29(ROOT, "CLAUDE.md");
58496
58637
  const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
58497
58638
  if (recall.kind === "collision") {
58498
58639
  console.warn(
@@ -58504,15 +58645,15 @@ async function installClaudeHooks(port) {
58504
58645
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
58505
58646
  }
58506
58647
  async function installClaudeMcpConfig() {
58507
- const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync24, writeFileSync: writeFileSync19 } = await import("node:fs");
58508
- const { join: join28, dirname: dirname10 } = await import("node:path");
58509
- const file2 = join28(ROOT, ".mcp.json");
58510
- const dir = dirname10(file2);
58648
+ const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
58649
+ const { join: join29, dirname: dirname11 } = await import("node:path");
58650
+ const file2 = join29(ROOT, ".mcp.json");
58651
+ const dir = dirname11(file2);
58511
58652
  if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
58512
58653
  let cfg = {};
58513
58654
  if (existsSync26(file2)) {
58514
58655
  try {
58515
- cfg = JSON.parse(readFileSync24(file2, "utf8"));
58656
+ cfg = JSON.parse(readFileSync25(file2, "utf8"));
58516
58657
  } catch {
58517
58658
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
58518
58659
  process.exit(2);
@@ -58520,21 +58661,21 @@ async function installClaudeMcpConfig() {
58520
58661
  }
58521
58662
  cfg.mcpServers ??= {};
58522
58663
  cfg.mcpServers["errata"] = errataMcpInvocation();
58523
- writeFileSync19(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58664
+ writeFileSync20(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58524
58665
  console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
58525
58666
  console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
58526
58667
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
58527
58668
  }
58528
58669
  async function installCursorMcpConfig() {
58529
- const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync24, writeFileSync: writeFileSync19 } = await import("node:fs");
58530
- const { join: join28 } = await import("node:path");
58531
- const dir = join28(ROOT, ".cursor");
58670
+ const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
58671
+ const { join: join29 } = await import("node:path");
58672
+ const dir = join29(ROOT, ".cursor");
58532
58673
  if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
58533
- const file2 = join28(dir, "mcp.json");
58674
+ const file2 = join29(dir, "mcp.json");
58534
58675
  let cfg = {};
58535
58676
  if (existsSync26(file2)) {
58536
58677
  try {
58537
- cfg = JSON.parse(readFileSync24(file2, "utf8"));
58678
+ cfg = JSON.parse(readFileSync25(file2, "utf8"));
58538
58679
  } catch {
58539
58680
  console.error(`refusing to overwrite invalid JSON at ${file2}`);
58540
58681
  process.exit(2);
@@ -58542,7 +58683,7 @@ async function installCursorMcpConfig() {
58542
58683
  }
58543
58684
  cfg.mcpServers ??= {};
58544
58685
  cfg.mcpServers["errata"] = errataMcpInvocation();
58545
- writeFileSync19(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58686
+ writeFileSync20(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
58546
58687
  console.log(`installed Cursor MCP server config \u2192 ${file2}`);
58547
58688
  console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
58548
58689
  console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
@@ -58550,16 +58691,16 @@ async function installCursorMcpConfig() {
58550
58691
  console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
58551
58692
  }
58552
58693
  async function installCodexHooks(port) {
58553
- const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync24, writeFileSync: writeFileSync19 } = await import("node:fs");
58554
- const { join: join28 } = await import("node:path");
58555
- const dir = join28(ROOT, ".codex");
58694
+ const { mkdirSync: mkdirSync8, existsSync: existsSync26, readFileSync: readFileSync25, writeFileSync: writeFileSync20 } = await import("node:fs");
58695
+ const { join: join29 } = await import("node:path");
58696
+ const dir = join29(ROOT, ".codex");
58556
58697
  if (!existsSync26(dir)) mkdirSync8(dir, { recursive: true });
58557
- const file2 = join28(dir, "config.toml");
58698
+ const file2 = join29(dir, "config.toml");
58558
58699
  const BEGIN = `# >>> errata hooks (errata-managed)`;
58559
58700
  const END = `# <<< errata hooks`;
58560
58701
  let existing = "";
58561
58702
  if (existsSync26(file2)) {
58562
- existing = readFileSync24(file2, "utf8");
58703
+ existing = readFileSync25(file2, "utf8");
58563
58704
  const beginIdx = existing.indexOf(BEGIN);
58564
58705
  const endIdx = existing.indexOf(END);
58565
58706
  if (beginIdx >= 0 && endIdx > beginIdx) {
@@ -58588,7 +58729,7 @@ ${END}
58588
58729
  const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
58589
58730
 
58590
58731
  ${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
58591
- writeFileSync19(file2, final, "utf8");
58732
+ writeFileSync20(file2, final, "utf8");
58592
58733
  console.log(`installed Codex hooks \u2192 ${file2}`);
58593
58734
  console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
58594
58735
  console.log("");
@@ -58902,7 +59043,7 @@ async function cmdDash(args2) {
58902
59043
  await yieldToLoop2();
58903
59044
  try {
58904
59045
  const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
58905
- const res = bleedRules(join27(r.root, ".claude", "rules"), items);
59046
+ const res = bleedRules(join28(r.root, ".claude", "rules"), items);
58906
59047
  if (res.written || res.pruned) {
58907
59048
  console.log(
58908
59049
  `[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.2-dev.226",
3
+ "version": "2.0.2-dev.227",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -15170,6 +15170,15 @@ var init_wire = __esm({
15170
15170
  /** Canonical human-readable description (no raw paths — daemon scrubs; server rechecks). */
15171
15171
  description: external_exports.string().min(1).max(4e3),
15172
15172
  attrs: external_exports.record(external_exports.string(), external_exports.unknown()).default({}),
15173
+ /** One-way origin key of the SESSION that minted this node (`ws_…`, a
15174
+ * truncated digest — never the raw session id). Stamped onto the created
15175
+ * node as `authoringSession`, which is the independence unit for the
15176
+ * evidence channels: the session that authored a claim may not corroborate
15177
+ * or refute it, while a DIFFERENT session on the same checkout may (alyssa,
15178
+ * 2026-07-31 — the workspace key made every witness on a single-checkout
15179
+ * deployment a self-corroboration). Optional + additive: absent leaves the
15180
+ * gate fail-open for that node, exactly today's behaviour. */
15181
+ originSession: external_exports.string().min(3).max(64).optional(),
15173
15182
  extractionSource: external_exports.enum(INGEST_EXTRACTION_SOURCES),
15174
15183
  validationSource: external_exports.enum(VALIDATION_SOURCES).optional(),
15175
15184
  /** Org-membrane (M2): the daemon's anchor tag — it owns the lockfile, so it