@inerrata-corporation/errata 2.0.22-dev.4121 → 2.0.22-dev.4127

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 CHANGED
@@ -580,11 +580,20 @@ var init_graph_events = __esm({
580
580
  // silently admitted, so the next graph-health pass either gives them a
581
581
  // trigger or retires them (D12: a record nothing reads is the defect).
582
582
  prefixes: ["ingest.", "sanitize.", "queue.", "skew."],
583
+ keys: ["inerrata.request_id"],
583
584
  consumer: "graph-health.mjs ingest triggers (edge-reject RATE, reinforcedFraction band, the volume floor) + the 'Graph \u2014 Ingest funnel & integrity' board. queue.*/skew.* currently have NO standing consumer (found unread 2026-08-14) \u2014 trigger or retirement owed"
584
585
  },
585
586
  "graph.twin": {
586
587
  prefixes: [],
587
- keys: ["rewritten", "already-generic", "rejected", "failed", "low-content", "threw", "failureFraction"],
588
+ keys: [
589
+ "rewritten",
590
+ "already-generic",
591
+ "rejected",
592
+ "failed",
593
+ "low-content",
594
+ "threw",
595
+ "failureFraction"
596
+ ],
588
597
  consumer: "failureFraction is the alertable number (twin-outcomes.ts); its graph-health.mjs trigger is pending a live baseline"
589
598
  },
590
599
  "graph.burst": {
@@ -76381,6 +76390,109 @@ init_webui();
76381
76390
  init_config();
76382
76391
  init_lock();
76383
76392
 
76393
+ // src/activity-feed.ts
76394
+ var LABEL_MAX = 120;
76395
+ var DEFAULT_TAIL = 20;
76396
+ function oneLine(text) {
76397
+ const flat = text.replace(/\s+/g, " ").trim();
76398
+ if (flat.length <= LABEL_MAX) return flat;
76399
+ const points = Array.from(flat);
76400
+ return points.length > LABEL_MAX ? `${points.slice(0, LABEL_MAX - 1).join("")}\u2026` : flat;
76401
+ }
76402
+ var ActivityFeed = class {
76403
+ constructor(capacity = 500) {
76404
+ this.capacity = capacity;
76405
+ }
76406
+ events = [];
76407
+ seq = 0;
76408
+ // The engine harvests a turn twice by design (mid-turn + turn-final) and the
76409
+ // sync lanes can re-decide the same node; one tag must flash once.
76410
+ recentKeys = /* @__PURE__ */ new Map();
76411
+ record(input) {
76412
+ const label = oneLine(input.label);
76413
+ if (!label) return null;
76414
+ const key = input.dedupKey ?? `${input.kind}|${input.workspace ?? ""}|${input.tag ?? ""}|${label}`;
76415
+ if (this.recentKeys.has(key)) return null;
76416
+ const event = {
76417
+ seq: ++this.seq,
76418
+ kind: input.kind,
76419
+ at: input.at ?? Date.now(),
76420
+ label,
76421
+ ...input.workspace ? { workspace: input.workspace } : {},
76422
+ ...input.tag ? { tag: input.tag } : {}
76423
+ };
76424
+ this.events.push(event);
76425
+ this.recentKeys.set(key, event.seq);
76426
+ while (this.events.length > this.capacity) this.events.shift();
76427
+ if (this.recentKeys.size > this.capacity * 2) {
76428
+ const floor = this.events[0]?.seq ?? this.seq;
76429
+ for (const [k, s] of this.recentKeys) if (s < floor) this.recentKeys.delete(k);
76430
+ }
76431
+ return event;
76432
+ }
76433
+ since(seq) {
76434
+ const events = seq === void 0 || !Number.isFinite(seq) || seq > this.seq ? this.events.slice(-DEFAULT_TAIL) : this.events.filter((e) => e.seq > seq);
76435
+ return { seq: this.seq, events };
76436
+ }
76437
+ };
76438
+ var activityFeed = new ActivityFeed();
76439
+ function recordHarvest(feed, plan, ctx) {
76440
+ let n = 0;
76441
+ const put = (tag, label) => {
76442
+ if (!label) return;
76443
+ const ok = feed.record({
76444
+ kind: "captured",
76445
+ tag,
76446
+ label,
76447
+ ...ctx.workspace ? { workspace: ctx.workspace } : {},
76448
+ ...ctx.at !== void 0 ? { at: ctx.at } : {},
76449
+ dedupKey: `captured|${ctx.sessionId}|${tag}|${oneLine(label)}`
76450
+ });
76451
+ if (ok) n++;
76452
+ };
76453
+ for (const p of plan.problems) {
76454
+ const tag = p.kind === "vulnerability" ? p.assessment === "suspected" ? "?vuln" : "vuln" : p.kind === "problem" ? "!" : p.kind;
76455
+ put(tag, p.statement);
76456
+ }
76457
+ for (const f of plan.fixes) put("fix", f.fixNote ?? f.boundStatement ?? (f.problemId ? ctx.describe(f.problemId) : void 0));
76458
+ for (const r of plan.refutes) put("refute", ctx.describe(r.nodeId));
76459
+ for (const c of plan.corroborations) put("confirm", ctx.describe(c.nodeId));
76460
+ for (const a of plan.attempts) put(a.outcome, a.note);
76461
+ for (const t of plan.triages) put("cause", t.causeDescription ?? ctx.describe(t.causeId));
76462
+ return n;
76463
+ }
76464
+ var harvestFeedFailed = false;
76465
+ function recordHarvestSafely(...args2) {
76466
+ try {
76467
+ return recordHarvest(...args2);
76468
+ } catch (err2) {
76469
+ if (!harvestFeedFailed) {
76470
+ harvestFeedFailed = true;
76471
+ console.warn("[errata] activity feed record failed (capture unaffected):", err2 instanceof Error ? err2.message : err2);
76472
+ }
76473
+ return 0;
76474
+ }
76475
+ }
76476
+ function mountActivityRoute(app, feed) {
76477
+ app.get("/api/activity", (c) => {
76478
+ const raw2 = c.req.query("since");
76479
+ return c.json(feed.since(raw2 === void 0 || raw2 === "" ? void 0 : Number(raw2)));
76480
+ });
76481
+ }
76482
+ var KNOWLEDGE_LABELS2 = {
76483
+ Problem: "!",
76484
+ Solution: "fix",
76485
+ RootCause: "cause",
76486
+ Pattern: "pattern",
76487
+ Vulnerability: "vuln",
76488
+ Principle: "principle"
76489
+ };
76490
+ function knowledgeTag(label, attrs) {
76491
+ const tag = KNOWLEDGE_LABELS2[label];
76492
+ if (tag === "!" && typeof attrs["kind"] === "string" && attrs["kind"] !== "problem") return attrs["kind"];
76493
+ return tag;
76494
+ }
76495
+
76384
76496
  // src/engine.ts
76385
76497
  import { execFileSync as execFileSync5 } from "node:child_process";
76386
76498
  import { existsSync as existsSync28, statSync as statSync9, appendFileSync as appendFileSync4, readdirSync as readdirSync11, renameSync as renameSync4, readFileSync as readFileSync32, writeFileSync as writeFileSync23 } from "node:fs";
@@ -85053,7 +85165,7 @@ function createWatchBreaker(deps) {
85053
85165
  }
85054
85166
 
85055
85167
  // src/engine.ts
85056
- var DAEMON_VERSION = true ? "2.0.22-dev.4121" : "2.0.0-alpha.0";
85168
+ var DAEMON_VERSION = true ? "2.0.22-dev.4127" : "2.0.0-alpha.0";
85057
85169
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
85058
85170
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
85059
85171
  var GIT_OP_MUTE_MS = 4e3;
@@ -86280,6 +86392,11 @@ function createWorkspaceEngine(opts) {
86280
86392
  sessionId,
86281
86393
  ...touched.size > 0 ? { sessionTouchedIds: touched } : {}
86282
86394
  });
86395
+ recordHarvestSafely(activityFeed, plan, {
86396
+ workspace: profile.name,
86397
+ sessionId,
86398
+ describe: (id) => store.getNode(id)?.description
86399
+ });
86283
86400
  priorEdges += plan.priorEdges;
86284
86401
  corroboratedEdges += plan.corroboratedEdges;
86285
86402
  citeAnchorsAccrued += plan.citeAnchorsAccrued;
@@ -93755,8 +93872,19 @@ async function startMultiDaemon(opts = {}) {
93755
93872
  const localId = instances.contextNodeSources[decision.canonicalId] ?? decision.canonicalId;
93756
93873
  const owner = owningStore(localId);
93757
93874
  if (!sent || !owner || blocked.has(sent.id)) continue;
93758
- const attrs = acceptedInstanceReceipt(owner.n, sent, decision, destinationKey, owner.s === store) ?? withdrawnInstanceReceipt(owner.n, destinationKey, decision, (key) => store.getMeta?.(key) ?? sharedStore.getMeta?.(key), owner.s === store);
93875
+ const accepted = acceptedInstanceReceipt(owner.n, sent, decision, destinationKey, owner.s === store);
93876
+ const attrs = accepted ?? withdrawnInstanceReceipt(owner.n, destinationKey, decision, (key) => store.getMeta?.(key) ?? sharedStore.getMeta?.(key), owner.s === store);
93759
93877
  if (attrs) owner.s.updateNode(localId, { attrs });
93878
+ const tag = accepted ? knowledgeTag(owner.n.label, owner.n.attrs) : void 0;
93879
+ if (tag) {
93880
+ activityFeed.record({
93881
+ kind: "ingested",
93882
+ tag,
93883
+ label: owner.n.description,
93884
+ workspace: projectName,
93885
+ dedupKey: `ingested|${localId}|${owner.n.description}`
93886
+ });
93887
+ }
93760
93888
  }
93761
93889
  noteFlushProgress(p.accepted, p.nodeIds.length, `instances ${p.chunkIndex}/${p.totalChunks}`);
93762
93890
  }
@@ -93827,6 +93955,19 @@ async function startMultiDaemon(opts = {}) {
93827
93955
  };
93828
93956
  for (const id of blocked) noteRefused(id, "blocked-gzip", () => blockedRepeat++);
93829
93957
  for (const [id, why] of rejected) noteRefused(id, why, () => rejectedRepeat++);
93958
+ for (const { id, reason } of nowHeld) {
93959
+ const owner = owningStore(id);
93960
+ const tag = owner ? knowledgeTag(owner.n.label, owner.n.attrs) : void 0;
93961
+ if (owner && tag) {
93962
+ activityFeed.record({
93963
+ kind: "rejected",
93964
+ tag,
93965
+ label: `${owner.n.description} \u2014 ${reason}`,
93966
+ workspace: projectName,
93967
+ dedupKey: `rejected|${id}|${owner.n.description}`
93968
+ });
93969
+ }
93970
+ }
93830
93971
  if (nowHeld.length > 0) {
93831
93972
  console.warn(
93832
93973
  `[sync\u2192cloud] [${projectName}] instances: HOLDING ${nowHeld.length} node(s) \u2014 refused identically ${SHIP_TERMINAL_REFUSALS}\xD7 on unchanged text; not re-sent until the text changes: ` + nowHeld.map(({ id, reason }) => `${id} "${owningStore(id)?.n.description.slice(0, 60) ?? ""}": ${reason}`).join(" | ")
@@ -94088,6 +94229,7 @@ async function startMultiDaemon(opts = {}) {
94088
94229
  return c.json({ error: err2 instanceof Error ? err2.message : String(err2) }, 503);
94089
94230
  }
94090
94231
  });
94232
+ mountActivityRoute(app, activityFeed);
94091
94233
  app.post("/api/tick", async (c) => {
94092
94234
  try {
94093
94235
  return c.json({ reports: Object.fromEntries(await daemon.tickAll()) });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.22-dev.4121",
3
+ "version": "2.0.22-dev.4127",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "errata-context",
3
- "version": "2.0.22-dev.4121",
3
+ "version": "2.0.22-dev.4127",
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
- 9f7ae426e110baef3bb27e68785897f745b77ef23fd2ee4e73188e8e6047890d .codex-plugin/plugin.json
1
+ 78dffda4706af8936449106b69d53de281d602a03d7e3aec97bf85eb19c5ddc5 .codex-plugin/plugin.json
2
2
  a7bebae9fb01c838d6c75fc784129e28be571233fa66ff5ee8039b574f35ccf7 assets/icon.png
3
3
  fc38b64e4df1e0b72c35764bef6c4c05430d97c9009ad0ecc8a9e75b4deab232 configure-local.mjs
4
4
  73dc6028b3b070257c7c31f252d11e55a9e096f4aed0f187f10cb21716e1e6d7 dist/client.js