@inerrata-corporation/errata 2.0.0-dev.77 → 2.0.0-dev.79

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.
Files changed (2) hide show
  1. package/errata.mjs +85 -3
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -15290,7 +15290,14 @@ var init_edge_rules = __esm({
15290
15290
  // SOLVED_BY sources: Vulnerability (v1 comment) + Problem/RootCause
15291
15291
  // (upstream design-problem.ts + triage.ts mint both).
15292
15292
  SOLVED_BY: { from: ["Vulnerability", "Problem", "RootCause"], to: ["Solution"] },
15293
- FIXED_BY: { to: ["Solution"] },
15293
+ // FIXED_BY sources mirror SOLVED_BY's (same ailment→fix semantics; live-graph
15294
+ // census 2026-07-14: 512 Problem + 13 RootCause sources, zero others besides
15295
+ // 3 REVERSED Solution→Problem edges the missing `from` let through — the
15296
+ // "Problem solved by Problem" splash bug. A reversed resolution edge is NOT
15297
+ // mechanically flippable (half the sample were PoC-not-fix claims), so the
15298
+ // door rejects rather than repairs; a correct re-emission lands via
15299
+ // recognition-at-the-door.
15300
+ FIXED_BY: { from: ["Vulnerability", "Problem", "RootCause"], to: ["Solution"] },
15294
15301
  // ── Triage family (upstream castalia.ts: Problem —TRIAGED_BY→ Triage —{INDICATES|CONFIRMS}→ cause) ──
15295
15302
  // Two-edge differential model (T3-rename): INDICATES = provisional candidate,
15296
15303
  // CONFIRMS = promoted router (a discriminator exists). Same endpoint matrix.
@@ -21353,6 +21360,16 @@ var init_client = __esm({
21353
21360
  if (q.seed?.length) qs.set("seed", q.seed.join(","));
21354
21361
  if (q.q) qs.set("q", q.q);
21355
21362
  const res = await this.json("GET", `/v2/search?${qs.toString()}`);
21363
+ const { nodes, edges } = this.toCastalia(res);
21364
+ return { nodes, edges, generatedAt: res.generatedAt };
21365
+ }
21366
+ /**
21367
+ * The castalia wire shape → local-mergeable graph. Extracted so the priming fetch
21368
+ * (`getProjectPriors`) lands nodes through the EXACT same mapper as `search`: a
21369
+ * second mapper would be a second convergence-key convention to keep in sync, and
21370
+ * an id-keying drift between the two is a silent no-op, not a crash.
21371
+ */
21372
+ toCastalia(res) {
21356
21373
  const now = Date.now();
21357
21374
  const nodes = res.nodes.map((n) => ({
21358
21375
  id: n.canonicalId,
@@ -21386,7 +21403,25 @@ var init_client = __esm({
21386
21403
  navFailures: 0,
21387
21404
  attrs: { ...e.attrs, source: "cloud" }
21388
21405
  }));
21389
- return { nodes, edges, generatedAt: res.generatedAt };
21406
+ return { nodes, edges };
21407
+ }
21408
+ /**
21409
+ * PJ-hydrate: the one-time seeded prime a fresh clone pulls at attach.
21410
+ *
21411
+ * A clone can already READ its project stratum (query-time federation, PJ-read) —
21412
+ * what it can't do is PRIME, because the passive block builds from the local store
21413
+ * and the remote blend is seeded from local problems a new checkout doesn't have.
21414
+ * This lands the top of the stratum locally so both have something to stand on.
21415
+ *
21416
+ * Membership-gated server-side by the same fail-closed check as ingest: a caller
21417
+ * who couldn't write this project's stratum can't prime from it.
21418
+ */
21419
+ async getProjectPriors(projectId, limit = 50) {
21420
+ const res = await this.json(
21421
+ "GET",
21422
+ `/v2/projects/${encodeURIComponent(projectId)}/priors?limit=${String(limit)}`
21423
+ );
21424
+ return this.toCastalia(res);
21390
21425
  }
21391
21426
  /** Pull cloud-induced skills + the session-bootstrap prime payload. `seed` is the
21392
21427
  * canonical ids of the agent's recent problems — the cloud ranks the skills whose
@@ -43293,7 +43328,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
43293
43328
  }
43294
43329
 
43295
43330
  // src/engine.ts
43296
- var DAEMON_VERSION = true ? "2.0.0-dev.77" : "2.0.0-alpha.0";
43331
+ var DAEMON_VERSION = true ? "2.0.0-dev.79" : "2.0.0-alpha.0";
43297
43332
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
43298
43333
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
43299
43334
  var GIT_OP_MUTE_MS = 4e3;
@@ -45463,6 +45498,39 @@ async function ensureProjectLink(root, profile, client) {
45463
45498
  }
45464
45499
  }
45465
45500
 
45501
+ // src/project-hydrate.ts
45502
+ var DEFAULT_LIMIT = 50;
45503
+ async function hydrateProject(opts) {
45504
+ const { root, profile, store, cloud } = opts;
45505
+ if (!profile.projectId) return { hydrated: false, reason: "no-project" };
45506
+ if (profile.projectHydratedAt) return { hydrated: false, reason: "already-hydrated" };
45507
+ try {
45508
+ const res = await cloud.getProjectPriors(profile.projectId, opts.limit ?? DEFAULT_LIMIT);
45509
+ let landedNodes = 0;
45510
+ for (const n of res.nodes) {
45511
+ if (store.getNode(n.id)) continue;
45512
+ store.mergeNode(n);
45513
+ landedNodes++;
45514
+ }
45515
+ let landedEdges = 0;
45516
+ for (const e of res.edges) {
45517
+ if (!store.getNode(e.from) || !store.getNode(e.to)) continue;
45518
+ if (store.getEdge(e.id)) continue;
45519
+ store.mergeEdge(e);
45520
+ landedEdges++;
45521
+ }
45522
+ profile.projectHydratedAt = Date.now();
45523
+ saveProfile(root, profile);
45524
+ return { hydrated: true, nodes: landedNodes, edges: landedEdges };
45525
+ } catch (err2) {
45526
+ return {
45527
+ hydrated: false,
45528
+ reason: "error",
45529
+ detail: err2 instanceof Error ? err2.message : String(err2)
45530
+ };
45531
+ }
45532
+ }
45533
+
45466
45534
  // src/adopt.ts
45467
45535
  import { existsSync as existsSync22 } from "node:fs";
45468
45536
  import { dirname as dirname8, join as join25 } from "node:path";
@@ -45904,6 +45972,20 @@ async function startMultiDaemon(opts = {}) {
45904
45972
  } else if (out2.reason === "error") {
45905
45973
  console.warn(`[errata] project link failed for ${r.engine.profile.name}: ${out2.detail}`);
45906
45974
  }
45975
+ const hyd = await hydrateProject({
45976
+ root: r.root,
45977
+ profile: r.engine.profile,
45978
+ store: r.engine.store,
45979
+ cloud: client
45980
+ });
45981
+ if (hyd.hydrated) {
45982
+ r.engine.markContextDirty();
45983
+ console.log(
45984
+ `[errata] primed ${r.engine.profile.name} from project \u2014 ${hyd.nodes} priors, ${hyd.edges} links`
45985
+ );
45986
+ } else if (hyd.reason === "error") {
45987
+ console.warn(`[errata] project prime failed for ${r.engine.profile.name}: ${hyd.detail}`);
45988
+ }
45907
45989
  }
45908
45990
  };
45909
45991
  void ambientLinkAll();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.0-dev.77",
3
+ "version": "2.0.0-dev.79",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {