@inerrata-corporation/errata 2.0.0-dev.24 → 2.0.0-dev.26

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.
@@ -15701,6 +15701,7 @@ var SqliteGraphStore = class {
15701
15701
  // cheaper (one bound column, no COALESCE evaluation per row).
15702
15702
  setPageRank: this.db.prepare("UPDATE nodes SET page_rank = :v WHERE id = :id"),
15703
15703
  setLandmark: this.db.prepare("UPDATE nodes SET is_landmark = :v WHERE id = :id"),
15704
+ setCommunity: this.db.prepare("UPDATE nodes SET community = :v WHERE id = :id"),
15704
15705
  updateNode: this.db.prepare(`
15705
15706
  UPDATE nodes SET
15706
15707
  description = COALESCE(:description, description),
@@ -15941,6 +15942,9 @@ var SqliteGraphStore = class {
15941
15942
  setLandmark(id, isLandmark) {
15942
15943
  this.stmts.setLandmark.run({ id, v: isLandmark ? 1 : 0 });
15943
15944
  }
15945
+ setCommunity(id, community) {
15946
+ this.stmts.setCommunity.run({ id, v: community });
15947
+ }
15944
15948
  mergeEdge(edge) {
15945
15949
  this.mutations++;
15946
15950
  this.stmts.insertEdge.run({
@@ -16660,6 +16664,9 @@ function revisitContradictedPrinciples(l2, ts) {
16660
16664
  return report;
16661
16665
  }
16662
16666
 
16667
+ // ../../packages/local-graph/src/community.ts
16668
+ init_src2();
16669
+
16663
16670
  // ../../packages/local-graph/src/triage.ts
16664
16671
  init_src();
16665
16672
  init_src();
package/errata.mjs CHANGED
@@ -15790,6 +15790,7 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
15790
15790
  // cheaper (one bound column, no COALESCE evaluation per row).
15791
15791
  setPageRank: this.db.prepare("UPDATE nodes SET page_rank = :v WHERE id = :id"),
15792
15792
  setLandmark: this.db.prepare("UPDATE nodes SET is_landmark = :v WHERE id = :id"),
15793
+ setCommunity: this.db.prepare("UPDATE nodes SET community = :v WHERE id = :id"),
15793
15794
  updateNode: this.db.prepare(`
15794
15795
  UPDATE nodes SET
15795
15796
  description = COALESCE(:description, description),
@@ -16030,6 +16031,9 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
16030
16031
  setLandmark(id, isLandmark) {
16031
16032
  this.stmts.setLandmark.run({ id, v: isLandmark ? 1 : 0 });
16032
16033
  }
16034
+ setCommunity(id, community) {
16035
+ this.stmts.setCommunity.run({ id, v: community });
16036
+ }
16033
16037
  mergeEdge(edge2) {
16034
16038
  this.mutations++;
16035
16039
  this.stmts.insertEdge.run({
@@ -18721,6 +18725,172 @@ var init_abstraction = __esm({
18721
18725
  }
18722
18726
  });
18723
18727
 
18728
+ // ../../packages/local-graph/src/community.ts
18729
+ function detectLocalCommunities(store, opts = {}) {
18730
+ const minSize = opts.minCommunitySize ?? DEFAULT_MIN_COMMUNITY_SIZE;
18731
+ const report = { candidates: 0, communities: 0, joint: 0, assigned: 0 };
18732
+ const ids = /* @__PURE__ */ new Set();
18733
+ for (const label of JOINT_COMMUNITY_LABELS) {
18734
+ for (const n of store.findNodesByLabel(label)) {
18735
+ if (label === "Problem" && n.attrs["resolvedAs"] === PROBLEM_RESOLUTION.FALSE_POSITIVE) continue;
18736
+ ids.add(n.id);
18737
+ }
18738
+ }
18739
+ report.candidates = ids.size;
18740
+ if (ids.size === 0) return report;
18741
+ const adj = /* @__PURE__ */ new Map();
18742
+ const protect = [];
18743
+ const add = (a, b, w) => {
18744
+ const l = adj.get(a) ?? [];
18745
+ l.push({ to: b, weight: w });
18746
+ adj.set(a, l);
18747
+ };
18748
+ for (const id of ids) {
18749
+ for (const e of store.outEdges(id, [...JOINT_COMMUNITY_EDGES])) {
18750
+ if (!ids.has(e.to)) continue;
18751
+ const conf = e.confidence > 0 ? e.confidence : 0.5;
18752
+ const w = Math.max(EDGE_WEIGHT[e.type] ?? 1, 0.1) * conf;
18753
+ add(id, e.to, w);
18754
+ add(e.to, id, w);
18755
+ if (isCausalProtected(e.type)) protect.push([id, e.to]);
18756
+ }
18757
+ }
18758
+ const comm = detectCommunitiesLeiden({ nodeIds: [...ids], adj }, { protect });
18759
+ const members = /* @__PURE__ */ new Map();
18760
+ for (const [id, c] of comm.community) {
18761
+ const l = members.get(c) ?? [];
18762
+ l.push(id);
18763
+ members.set(c, l);
18764
+ }
18765
+ store.transaction(() => {
18766
+ for (const [cid, mem] of members) {
18767
+ const qualifies = mem.length >= minSize;
18768
+ let hasLocal = false;
18769
+ let hasCloud = false;
18770
+ for (const id of mem) {
18771
+ const n = store.getNode(id);
18772
+ if (!n) continue;
18773
+ const pulled = n.attrs["source"] === "cloud";
18774
+ if (pulled) hasCloud = true;
18775
+ else hasLocal = true;
18776
+ const nextAttrs = { ...n.attrs };
18777
+ if (qualifies) nextAttrs["localCommunity"] = cid;
18778
+ else delete nextAttrs["localCommunity"];
18779
+ store.updateNode(id, { attrs: nextAttrs });
18780
+ if (!pulled) store.setCommunity(id, qualifies ? cid : null);
18781
+ }
18782
+ if (qualifies) {
18783
+ report.communities++;
18784
+ report.assigned += mem.length;
18785
+ if (hasLocal && hasCloud) report.joint++;
18786
+ }
18787
+ }
18788
+ });
18789
+ return report;
18790
+ }
18791
+ function communitySeeds(store, opts = {}) {
18792
+ const maxCommunities = opts.maxCommunities ?? 4;
18793
+ const maxSeeds = opts.maxSeeds ?? 32;
18794
+ const byCommunity = /* @__PURE__ */ new Map();
18795
+ for (const label of JOINT_COMMUNITY_LABELS) {
18796
+ for (const n of store.findNodesByLabel(label)) {
18797
+ const cid = n.attrs["localCommunity"];
18798
+ if (typeof cid !== "string") continue;
18799
+ const cloudId = n.attrs["cloudNodeId"];
18800
+ const l = byCommunity.get(cid) ?? [];
18801
+ l.push({
18802
+ id: n.id,
18803
+ pulled: n.attrs["source"] === "cloud",
18804
+ cloudId: typeof cloudId === "string" && cloudId !== n.id ? cloudId : null,
18805
+ ts: n.lastUpdatedAt
18806
+ });
18807
+ byCommunity.set(cid, l);
18808
+ }
18809
+ }
18810
+ if (byCommunity.size === 0) return [];
18811
+ const ranked = [...byCommunity.entries()].map(([cid, mem]) => ({ cid, mem, fresh: Math.max(...mem.map((m) => m.ts)) })).sort((a, b) => b.fresh - a.fresh).slice(0, maxCommunities);
18812
+ const seeds = [];
18813
+ const seen = /* @__PURE__ */ new Set();
18814
+ const push = (id) => {
18815
+ if (seeds.length >= maxSeeds || seen.has(id)) return;
18816
+ seen.add(id);
18817
+ seeds.push(id);
18818
+ };
18819
+ for (const { mem } of ranked) {
18820
+ const ordered = [...mem].sort(
18821
+ (a, b) => a.pulled === b.pulled ? b.ts - a.ts : a.pulled ? -1 : 1
18822
+ );
18823
+ for (const m of ordered) {
18824
+ push(m.id);
18825
+ if (m.cloudId) push(m.cloudId);
18826
+ }
18827
+ }
18828
+ return seeds;
18829
+ }
18830
+ function communityInductionRequests(store, opts = {}) {
18831
+ const maxCommunities = opts.maxCommunities ?? 2;
18832
+ const byCommunity = /* @__PURE__ */ new Map();
18833
+ for (const label of JOINT_COMMUNITY_LABELS) {
18834
+ for (const n of store.findNodesByLabel(label)) {
18835
+ const cid = n.attrs["localCommunity"];
18836
+ if (typeof cid !== "string") continue;
18837
+ const cloudId = n.attrs["cloudNodeId"];
18838
+ const l = byCommunity.get(cid) ?? [];
18839
+ l.push({
18840
+ id: n.id,
18841
+ pulled: n.attrs["source"] === "cloud",
18842
+ cloudId: typeof cloudId === "string" && cloudId !== n.id ? cloudId : null,
18843
+ ts: n.lastUpdatedAt,
18844
+ description: n.description
18845
+ });
18846
+ byCommunity.set(cid, l);
18847
+ }
18848
+ }
18849
+ if (byCommunity.size === 0) return [];
18850
+ return [...byCommunity.entries()].map(([cid, mem]) => ({ cid, mem, fresh: Math.max(...mem.map((m) => m.ts)) })).sort((a, b) => b.fresh - a.fresh).map(({ cid, mem }) => {
18851
+ const ids = /* @__PURE__ */ new Set();
18852
+ for (const m of mem) {
18853
+ ids.add(m.id);
18854
+ if (m.cloudId) ids.add(m.cloudId);
18855
+ }
18856
+ const freshestLocal = [...mem].filter((m) => !m.pulled).sort((a, b) => b.ts - a.ts)[0];
18857
+ return {
18858
+ communityId: cid,
18859
+ members: [...ids].slice(0, 64),
18860
+ context: (freshestLocal?.description ?? "recurring workspace problem cluster").slice(0, 200)
18861
+ };
18862
+ }).filter((r) => r.members.length >= MIN_INDUCTION_MEMBERS).slice(0, maxCommunities);
18863
+ }
18864
+ var JOINT_COMMUNITY_LABELS, JOINT_COMMUNITY_EDGES, DEFAULT_MIN_COMMUNITY_SIZE, MIN_INDUCTION_MEMBERS;
18865
+ var init_community2 = __esm({
18866
+ "../../packages/local-graph/src/community.ts"() {
18867
+ "use strict";
18868
+ init_src2();
18869
+ init_src3();
18870
+ JOINT_COMMUNITY_LABELS = [
18871
+ "Problem",
18872
+ "Solution",
18873
+ "RootCause",
18874
+ "Pattern"
18875
+ ];
18876
+ JOINT_COMMUNITY_EDGES = [
18877
+ "CAUSED_BY",
18878
+ "SOLVED_BY",
18879
+ "FIXED_BY",
18880
+ "CONTRADICTS",
18881
+ "INSTANCE_OF",
18882
+ "MATCHES",
18883
+ "IMPLEMENTS",
18884
+ "TRIAGED_BY",
18885
+ "INDICATES",
18886
+ "CONFIRMS",
18887
+ "RELATES_TO"
18888
+ ];
18889
+ DEFAULT_MIN_COMMUNITY_SIZE = 2;
18890
+ MIN_INDUCTION_MEMBERS = 3;
18891
+ }
18892
+ });
18893
+
18724
18894
  // ../../packages/local-graph/src/triage.ts
18725
18895
  function semNode(id, label, description, ts, attrs) {
18726
18896
  return {
@@ -19339,6 +19509,8 @@ __export(src_exports, {
19339
19509
  CITABLE_PRIOR_LABELS: () => CITABLE_PRIOR_LABELS,
19340
19510
  CODE_REACH_EDGES: () => CODE_REACH_EDGES,
19341
19511
  CREDIT_FAMILY: () => CREDIT_FAMILY,
19512
+ JOINT_COMMUNITY_EDGES: () => JOINT_COMMUNITY_EDGES,
19513
+ JOINT_COMMUNITY_LABELS: () => JOINT_COMMUNITY_LABELS,
19342
19514
  MAX_ANCHOR_FILES: () => MAX_ANCHOR_FILES,
19343
19515
  PERCOLATING_DRIFT_EDGES: () => PERCOLATING_DRIFT_EDGES,
19344
19516
  PERCOLATING_EDGES: () => PERCOLATING_EDGES,
@@ -19359,12 +19531,15 @@ __export(src_exports, {
19359
19531
  causalChain: () => causalChain,
19360
19532
  claimId: () => claimId,
19361
19533
  clearRevisit: () => clearRevisit,
19534
+ communityInductionRequests: () => communityInductionRequests,
19535
+ communitySeeds: () => communitySeeds,
19362
19536
  compareSemver: () => compareSemver,
19363
19537
  corroborateClaim: () => corroborateClaim,
19364
19538
  creditAssignment: () => creditAssignment,
19365
19539
  crystallize: () => crystallize,
19366
19540
  deriveContextFromAnchors: () => deriveContextFromAnchors,
19367
19541
  designProblemId: () => designProblemId,
19542
+ detectLocalCommunities: () => detectLocalCommunities,
19368
19543
  edgeConductance: () => edgeConductance,
19369
19544
  evaluateDependency: () => evaluateDependency,
19370
19545
  findOrCreatePackage: () => findOrCreatePackage,
@@ -19424,6 +19599,7 @@ var init_src4 = __esm({
19424
19599
  init_design_problem();
19425
19600
  init_percolate();
19426
19601
  init_abstraction();
19602
+ init_community2();
19427
19603
  init_triage2();
19428
19604
  init_problem_dedup();
19429
19605
  init_problem_package_link();
@@ -20204,6 +20380,13 @@ var init_client = __esm({
20204
20380
  if (seed && seed.length > 0) qs.set("seed", seed.join(","));
20205
20381
  return this.json("GET", `/v2/skills?${qs.toString()}`);
20206
20382
  }
20383
+ /** CL-induce: request a skill for a locally-detected community's cloud-
20384
+ * resolvable member ids. AUTHED. Always HTTP 200 — the `status` field
20385
+ * discriminates outcomes (incl. the autophagy-floor refusal, which is a
20386
+ * normal "not enough collective grounding yet" result, not an error). */
20387
+ async induceSkill(body2) {
20388
+ return this.json("POST", "/v2/skills/induce", body2);
20389
+ }
20207
20390
  /** Dependency-spine neighborhood. Accepts purls (Package canonicalId = purl)
20208
20391
  * or bare name@version slugs. A miss 404s AND registers demand (Stream B). */
20209
20392
  async packages(purlOrSlug, limit) {
@@ -41091,7 +41274,7 @@ function maybeFlushDigests() {
41091
41274
  }
41092
41275
 
41093
41276
  // src/engine.ts
41094
- var DAEMON_VERSION = true ? "2.0.0-dev.24" : "2.0.0-alpha.0";
41277
+ var DAEMON_VERSION = true ? "2.0.0-dev.26" : "2.0.0-alpha.0";
41095
41278
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
41096
41279
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
41097
41280
  var GIT_OP_MUTE_MS = 4e3;
@@ -41449,6 +41632,14 @@ function createWorkspaceEngine(opts) {
41449
41632
  } catch (err2) {
41450
41633
  console.warn("[errata] problem context derivation failed:", err2);
41451
41634
  }
41635
+ try {
41636
+ const lc = detectLocalCommunities(store);
41637
+ if (lc.communities > 0) {
41638
+ console.log(`[errata] communities: ${lc.communities} detected (${lc.joint} joint local+cloud) across ${lc.assigned}/${lc.candidates} node(s)`);
41639
+ }
41640
+ } catch (err2) {
41641
+ console.warn("[errata] joint community pass failed:", err2);
41642
+ }
41452
41643
  return { report, localSkills: 0 };
41453
41644
  };
41454
41645
  const onWorkingFileChanged = (rel, sessionId) => {
@@ -41888,8 +42079,21 @@ function createWorkspaceEngine(opts) {
41888
42079
  }
41889
42080
  });
41890
42081
  }
41891
- const pullSkills = () => {
41892
- const skillSeed = store.findNodesByLabel("Problem").sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt).slice(0, 6).flatMap((p) => {
42082
+ const pullSkills = async () => {
42083
+ if ((opts.syncConsent ?? loadConfig().consent.sync) === true) {
42084
+ for (const req of communityInductionRequests(store)) {
42085
+ try {
42086
+ const r = await cloud.induceSkill({ members: req.members, context: req.context });
42087
+ if (r.status === "induced" || r.status === "refreshed") {
42088
+ console.log(`[errata] skill ${r.status} for community ${req.communityId}: ${r.title ?? r.skillId}`);
42089
+ }
42090
+ } catch {
42091
+ break;
42092
+ }
42093
+ }
42094
+ }
42095
+ const communitySeed = communitySeeds(store);
42096
+ const skillSeed = communitySeed.length > 0 ? communitySeed : store.findNodesByLabel("Problem").sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt).slice(0, 6).flatMap((p) => {
41893
42097
  const cloudId = p.attrs["cloudNodeId"];
41894
42098
  return typeof cloudId === "string" && cloudId !== p.id ? [p.id, cloudId] : [p.id];
41895
42099
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.0-dev.24",
3
+ "version": "2.0.0-dev.26",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -23961,6 +23961,7 @@ var SqliteGraphStore = class {
23961
23961
  // cheaper (one bound column, no COALESCE evaluation per row).
23962
23962
  setPageRank: this.db.prepare("UPDATE nodes SET page_rank = :v WHERE id = :id"),
23963
23963
  setLandmark: this.db.prepare("UPDATE nodes SET is_landmark = :v WHERE id = :id"),
23964
+ setCommunity: this.db.prepare("UPDATE nodes SET community = :v WHERE id = :id"),
23964
23965
  updateNode: this.db.prepare(`
23965
23966
  UPDATE nodes SET
23966
23967
  description = COALESCE(:description, description),
@@ -24201,6 +24202,9 @@ var SqliteGraphStore = class {
24201
24202
  setLandmark(id, isLandmark) {
24202
24203
  this.stmts.setLandmark.run({ id, v: isLandmark ? 1 : 0 });
24203
24204
  }
24205
+ setCommunity(id, community) {
24206
+ this.stmts.setCommunity.run({ id, v: community });
24207
+ }
24204
24208
  mergeEdge(edge) {
24205
24209
  this.mutations++;
24206
24210
  this.stmts.insertEdge.run({
@@ -25167,6 +25171,9 @@ function motifDecision(input) {
25167
25171
  };
25168
25172
  }
25169
25173
 
25174
+ // ../../packages/local-graph/src/community.ts
25175
+ init_src2();
25176
+
25170
25177
  // ../../packages/local-graph/src/triage.ts
25171
25178
  init_src();
25172
25179
  init_src();