@inerrata-corporation/errata 2.0.2-dev.151 → 2.0.2-dev.157

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 +98 -37
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -18572,7 +18572,8 @@ function resolveDesignProblemById(store, id, fixNote, t) {
18572
18572
  }
18573
18573
  function closeDesignProblem(store, problemId, fixNote, t) {
18574
18574
  const p = store.getNode(problemId);
18575
- if (!p || p.label !== "Problem" || p.attrs["resolvedAt"]) return false;
18575
+ if (!p || p.label !== "Problem") return false;
18576
+ if (p.attrs["resolvedAs"]) return false;
18576
18577
  if (fixNote?.trim() && store.outEdges(problemId, ["SOLVED_BY"]).length === 0) {
18577
18578
  const solId = `dfix_${digest({ problemId, fix: fixNote })}`.slice(0, 56);
18578
18579
  store.mergeNode(
@@ -18580,6 +18581,7 @@ function closeDesignProblem(store, problemId, fixNote, t) {
18580
18581
  );
18581
18582
  mergeEdge(store, problemId, solId, "SOLVED_BY", t);
18582
18583
  }
18584
+ if (p.attrs["resolvedAt"]) return false;
18583
18585
  store.updateNode(problemId, {
18584
18586
  attrs: { ...p.attrs, provisional: false, resolvedAt: t },
18585
18587
  lastUpdatedAt: t
@@ -25914,6 +25916,33 @@ function federationHint(status) {
25914
25916
  return void 0;
25915
25917
  }
25916
25918
  }
25919
+ function hasCloudNodeShape(id) {
25920
+ return CANONICAL_KNOWLEDGE_ID.test(id) || UUID_ID.test(id) || id.startsWith("pkg:");
25921
+ }
25922
+ async function collectiveDrilldown(cloud, seedId, limit) {
25923
+ try {
25924
+ const res = await cloud.search({ stack: [], domains: [], kinds: [], seed: [seedId], limit });
25925
+ if (res.nodes.length === 0) return null;
25926
+ return {
25927
+ seed: seedId,
25928
+ nodes: res.nodes.map((n) => ({
25929
+ id: n.id,
25930
+ label: n.label,
25931
+ name: n.description,
25932
+ score: Number((n.extractionConfidence ?? 0.5).toFixed(4)),
25933
+ hops: 1,
25934
+ provenance: "collective"
25935
+ })),
25936
+ edges: res.edges.map((e) => ({ from: e.from, to: e.to, type: e.type }))
25937
+ };
25938
+ } catch (err2) {
25939
+ console.error(
25940
+ "[errata] collectiveDrilldown: cloud fallback failed \u2014",
25941
+ err2 instanceof Error ? err2.message : err2
25942
+ );
25943
+ return null;
25944
+ }
25945
+ }
25917
25946
  function formatDualNodes(merged) {
25918
25947
  return merged.nodes.map((n) => ({
25919
25948
  id: n.id,
@@ -25933,7 +25962,7 @@ function formatDualNodes(merged) {
25933
25962
  } : {}
25934
25963
  }));
25935
25964
  }
25936
- var BRIDGE_LABELS;
25965
+ var BRIDGE_LABELS, CANONICAL_KNOWLEDGE_ID, UUID_ID;
25937
25966
  var init_dual_augment = __esm({
25938
25967
  "src/dual-augment.ts"() {
25939
25968
  "use strict";
@@ -25941,6 +25970,8 @@ var init_dual_augment = __esm({
25941
25970
  init_generalize_graph();
25942
25971
  init_dual_burst();
25943
25972
  BRIDGE_LABELS = new Set(SEMANTIC_NODE_LABELS);
25973
+ CANONICAL_KNOWLEDGE_ID = /^[a-z][a-z0-9]*_[0-9a-f]{8,}$/;
25974
+ UUID_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
25944
25975
  }
25945
25976
  });
25946
25977
 
@@ -36856,6 +36887,12 @@ function cosine3(a, b) {
36856
36887
  for (let i2 = 0; i2 < a.length; i2++) dot += a[i2] * b[i2];
36857
36888
  return dot;
36858
36889
  }
36890
+ async function collectiveSeedFallback(args2, ctx, defaultLimit) {
36891
+ const seedId = typeof args2["nodeId"] === "string" ? args2["nodeId"] : null;
36892
+ if (!seedId || !ctx.cloud || !hasCloudNodeShape(seedId)) return null;
36893
+ const limit = Math.max(1, Math.min(100, Number(args2["limit"] ?? defaultLimit)));
36894
+ return collectiveDrilldown(ctx.cloud, seedId, limit);
36895
+ }
36859
36896
  function resolveSymbol2(store, args2) {
36860
36897
  const id = args2["nodeId"];
36861
36898
  if (typeof id === "string" && store.getNode(id)) return id;
@@ -37206,7 +37243,7 @@ var init_mcp = __esm({
37206
37243
  },
37207
37244
  {
37208
37245
  name: "errata.neighbors",
37209
- description: "Return direct in/out edges of a node. Pass either a nodeId or a qname (e.g. ClassName.method) \u2014 resolved like the other nav verbs. Use after errata.search or errata.locate to walk the graph.",
37246
+ description: "Return direct in/out edges of a node. Pass either a nodeId or a qname (e.g. ClassName.method) \u2014 resolved like the other nav verbs. Use after errata.search or errata.locate to walk the graph. A cloud id from search's collective blend (e.g. dprob_\u2026) that isn't in the local graph falls back to its collective neighborhood, tagged provenance:collective.",
37210
37247
  inputSchema: {
37211
37248
  type: "object",
37212
37249
  properties: {
@@ -37215,9 +37252,27 @@ var init_mcp = __esm({
37215
37252
  limit: { type: "number", description: "Max edges per direction (default 30)" }
37216
37253
  }
37217
37254
  },
37218
- handler: (args2, store) => {
37255
+ handler: async (args2, store, ctx) => {
37219
37256
  const id = resolveSymbol2(store, args2);
37220
- if (!id) return unresolved(args2);
37257
+ if (!id) {
37258
+ const cn = await collectiveSeedFallback(args2, ctx, 30);
37259
+ if (cn) {
37260
+ return {
37261
+ found: true,
37262
+ node: { id: cn.seed, provenance: "collective" },
37263
+ collectiveReachable: true,
37264
+ collectiveStatus: "cloud-seed",
37265
+ // Seed-touching edge types aren't on the wire (the server's seed
37266
+ // burst excludes the seed itself, and edges to nodes outside the
37267
+ // result set are dropped), so the collective fallback reports the
37268
+ // 1-hop neighborhood + its internal topology instead of the local
37269
+ // contract's typed out/in lists.
37270
+ nearby: cn.nodes,
37271
+ edges: cn.edges
37272
+ };
37273
+ }
37274
+ return unresolved(args2);
37275
+ }
37221
37276
  const limit = Math.max(1, Math.min(200, Number(args2["limit"] ?? 30)));
37222
37277
  const node2 = store.getNode(id);
37223
37278
  if (!node2) return { found: false, reason: "not-found" };
@@ -37264,32 +37319,17 @@ var init_mcp = __esm({
37264
37319
  handler: async (args2, store, ctx) => {
37265
37320
  const id = resolveSymbol2(store, args2);
37266
37321
  if (!id) {
37267
- const seedId = typeof args2["nodeId"] === "string" ? args2["nodeId"] : null;
37268
- if (seedId && ctx.cloud) {
37269
- const res = await ctx.cloud.search({
37270
- stack: [],
37271
- domains: [],
37272
- kinds: [],
37273
- seed: [seedId],
37274
- limit: args2["limit"] != null ? Number(args2["limit"]) : 20
37275
- }).catch(() => null);
37276
- if (res && res.nodes.length > 0) {
37277
- return {
37278
- seed: seedId,
37279
- seedProvenance: "collective",
37280
- collectiveReachable: true,
37281
- collectiveStatus: "cloud-seed",
37282
- count: res.nodes.length,
37283
- results: res.nodes.map((n) => ({
37284
- id: n.id,
37285
- label: n.label,
37286
- name: n.description,
37287
- score: Number((n.extractionConfidence ?? 0.5).toFixed(4)),
37288
- hops: 1,
37289
- provenance: "collective"
37290
- }))
37291
- };
37292
- }
37322
+ const cn = await collectiveSeedFallback(args2, ctx, 20);
37323
+ if (cn) {
37324
+ return {
37325
+ seed: cn.seed,
37326
+ seedProvenance: "collective",
37327
+ collectiveReachable: true,
37328
+ collectiveStatus: "cloud-seed",
37329
+ count: cn.nodes.length,
37330
+ results: cn.nodes,
37331
+ edges: cn.edges
37332
+ };
37293
37333
  }
37294
37334
  return unresolved(args2);
37295
37335
  }
@@ -37446,7 +37486,7 @@ var init_mcp = __esm({
37446
37486
  },
37447
37487
  {
37448
37488
  name: "errata.why",
37449
- description: "Causal/resolution neighborhood along the causal edge families (CAUSED_BY, MANIFESTS_AS, FIXED_BY, SOLVED_BY, \u2026), walked in both directions. For a Problem this surfaces its root causes AND solutions; for a Solution, the problems it resolves. Merges the machine-wide shared store's triage layer (cause chains from inline `<-` diagnoses land there, keyed by the same content-derived problem id). Ranked by accumulated conductance. Pass nodeId or qname. Returns {seedId, nodes:[{id,label,description,hops,edgeType,relevance}]}.",
37489
+ description: "Causal/resolution neighborhood along the causal edge families (CAUSED_BY, MANIFESTS_AS, FIXED_BY, SOLVED_BY, \u2026), walked in both directions. For a Problem this surfaces its root causes AND solutions; for a Solution, the problems it resolves. Merges the machine-wide shared store's triage layer (cause chains from inline `<-` diagnoses land there, keyed by the same content-derived problem id). Ranked by accumulated conductance. Pass nodeId or qname. Returns {seedId, nodes:[{id,label,description,hops,edgeType,relevance}]}. A cloud id from search's collective blend (e.g. dprob_\u2026) that isn't in the local graph falls back to its collective causal neighborhood, tagged provenance:collective.",
37450
37490
  inputSchema: {
37451
37491
  type: "object",
37452
37492
  properties: {
@@ -37456,9 +37496,30 @@ var init_mcp = __esm({
37456
37496
  limit: { type: "number", description: "Default 30" }
37457
37497
  }
37458
37498
  },
37459
- handler: (args2, store) => {
37499
+ handler: async (args2, store, ctx) => {
37460
37500
  const id = resolveSymbol2(store, args2);
37461
- if (!id) return unresolved(args2);
37501
+ if (!id) {
37502
+ const cn = await collectiveSeedFallback(args2, ctx, 30);
37503
+ if (cn) {
37504
+ return {
37505
+ found: true,
37506
+ seedId: cn.seed,
37507
+ seedProvenance: "collective",
37508
+ collectiveReachable: true,
37509
+ collectiveStatus: "cloud-seed",
37510
+ nodes: cn.nodes.map((n) => ({
37511
+ id: n.id,
37512
+ label: n.label,
37513
+ description: n.name,
37514
+ hops: n.hops,
37515
+ relevance: n.score,
37516
+ provenance: n.provenance
37517
+ })),
37518
+ edges: cn.edges
37519
+ };
37520
+ }
37521
+ return unresolved(args2);
37522
+ }
37462
37523
  const maxHops = Math.max(1, Math.min(8, Number(args2["maxHops"] ?? 4)));
37463
37524
  const limit = Math.max(1, Math.min(100, Number(args2["limit"] ?? 30)));
37464
37525
  const local = causalChain(store, { seedId: id, direction: "both", maxHops, limit });
@@ -51934,7 +51995,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
51934
51995
  }
51935
51996
 
51936
51997
  // src/engine.ts
51937
- var DAEMON_VERSION = true ? "2.0.2-dev.151" : "2.0.0-alpha.0";
51998
+ var DAEMON_VERSION = true ? "2.0.2-dev.157" : "2.0.0-alpha.0";
51938
51999
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
51939
52000
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
51940
52001
  var GIT_OP_MUTE_MS = 4e3;
@@ -57371,8 +57432,8 @@ async function cmdSimilar(args2) {
57371
57432
  const limitIdx = args2.indexOf("--limit");
57372
57433
  const limit = limitIdx >= 0 && args2[limitIdx + 1] ? Number(args2[limitIdx + 1]) : 5;
57373
57434
  const { runTool: runTool2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
57374
- await withStore((store) => {
57375
- const r = runTool2("errata.similar", { nodeId: seed, qname: seed, limit }, store);
57435
+ await withStore(async (store) => {
57436
+ const r = await runTool2("errata.similar", { nodeId: seed, qname: seed, limit }, store);
57376
57437
  if (!r.found) {
57377
57438
  console.log("seed not found");
57378
57439
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.2-dev.151",
3
+ "version": "2.0.2-dev.157",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {