@inerrata-corporation/errata 2.0.1-dev.99 → 2.0.2-dev.133

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.1-dev.99",
3
+ "version": "2.0.2-dev.133",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/pass-worker.mjs CHANGED
@@ -144,7 +144,14 @@ var init_castalia = __esm({
144
144
  "SOLVED_BY",
145
145
  "MITIGATES",
146
146
  "REPORTED_FAILURE",
147
- "CONTRADICTS"
147
+ "CONTRADICTS",
148
+ // Motif twin-faces (KN-twin-faces): failure-face motif → remedy-face motif
149
+ // across layers (AntiPattern/Weakness ↔ Technique/Pattern). Same
150
+ // problem→fix direction as FIXED_BY/SOLVED_BY. Minted by the nightly LLM
151
+ // twin-face pass — these are the near-identical cross-layer pairs the
152
+ // polarity gate (finding 5) correctly refuses to FUSE; the link carries
153
+ // what fusion can't.
154
+ "REMEDIED_BY"
148
155
  ];
149
156
  CONCEPTUAL_EDGES = [
150
157
  "INSTANCE_OF",
@@ -274,6 +281,10 @@ var init_castalia = __esm({
274
281
  CAUSED_BY: 3,
275
282
  FIXED_BY: 3,
276
283
  SOLVED_BY: 3,
284
+ // Twin-face link (failure motif → remedy motif, KN-twin-faces) — causal-grade
285
+ // but a notch below witnessed FIXED_BY/SOLVED_BY: the pairing is an LLM
286
+ // judgment over descriptions, not an agent-witnessed resolution.
287
+ REMEDIED_BY: 2.5,
277
288
  MANIFESTS_AS: 2,
278
289
  ESCALATES_TO: 1.5,
279
290
  AFFECTS: 1.2,
@@ -15049,7 +15060,10 @@ var init_edge_rules = __esm({
15049
15060
  // NOT ruled here — the type pre-exists with broader extractor senses, and a
15050
15061
  // new rule on an old type would reject legitimate live flows (reject-never-flip
15051
15062
  // cuts both ways: only rule types you introduce or senses that are documented).
15052
- CONCERNS: { from: ["Problem", "Solution", "RootCause", "Claim", "Pattern"], to: ["Tool"] },
15063
+ // `Component` joined the target set with OM-agent-anchors: an agent-named
15064
+ // component ("React Router") is the same knowledge→named-unit anchor shape as
15065
+ // a Tool — the knowledge is ABOUT it, not dependent on it.
15066
+ CONCERNS: { from: ["Problem", "Solution", "RootCause", "Claim", "Pattern"], to: ["Tool", "Component"] },
15053
15067
  OPERATES_ON: { from: ["Algorithm"], to: ["DataStructure"] },
15054
15068
  INVOLVES: { from: ["Problem", "Solution"], to: ["DataStructure"] },
15055
15069
  // ── Taxonomy (Track 4 Stream C: MITRE CWE `ChildOf` → `Weakness —IS_A→ Weakness`) ──
@@ -15156,13 +15170,27 @@ var init_wire = __esm({
15156
15170
  /** Canonical human-readable description (no raw paths — daemon scrubs; server rechecks). */
15157
15171
  description: external_exports.string().min(1).max(4e3),
15158
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(),
15159
15182
  extractionSource: external_exports.enum(INGEST_EXTRACTION_SOURCES),
15160
15183
  validationSource: external_exports.enum(VALIDATION_SOURCES).optional(),
15161
15184
  /** Org-membrane (M2): the daemon's anchor tag — it owns the lockfile, so it
15162
15185
  * knows which packages are private. The door does NOT trust a `public` claim
15163
15186
  * blindly (it re-confirms on the spine); absent ⇒ unknown ⇒ fail-closed to
15164
15187
  * org-private. Accepted-but-ignored until ORG_MEMBRANE_ENABLED flips. */
15165
- anchorVisibility: external_exports.enum(["public", "private"]).optional()
15188
+ anchorVisibility: external_exports.enum(["public", "private"]).optional(),
15189
+ /** The spine-resolvable anchor id backing a `public` tag (OM-anchor-tag): a
15190
+ * Package purl or `languageCanonicalId`. The door validates THIS on the
15191
+ * public spine (falling back to `canonicalId` when absent — context stubs
15192
+ * are self-anchored). Never trusted without spine confirmation. */
15193
+ anchor: external_exports.string().min(1).max(300).optional()
15166
15194
  });
15167
15195
  RouteContextCountWireSchema = external_exports.object({
15168
15196
  confirmed: external_exports.number().int().min(0),
@@ -24330,6 +24358,13 @@ var SqliteGraphStore = class {
24330
24358
  findByLabel: this.db.prepare(
24331
24359
  "SELECT * FROM nodes WHERE label = ? AND valid_to IS NULL"
24332
24360
  ),
24361
+ // Scalar count twin of findByLabel — same live-row semantics, no row
24362
+ // hydration. Exists because status surfaces (daemon `/` + `/health`) used
24363
+ // findNodesByLabel(...).length, materializing every row's attrs JSON and
24364
+ // embedding blob per request — seconds of synchronous loop-hold per poll.
24365
+ countByLabel: this.db.prepare(
24366
+ "SELECT COUNT(*) AS n FROM nodes WHERE label = ? AND valid_to IS NULL"
24367
+ ),
24333
24368
  // ALL versions of a label — incl frozen/closed (valid_to set). Used by the
24334
24369
  // clean-reindex purge so a true wipe removes history too, not just live rows.
24335
24370
  findByLabelAll: this.db.prepare("SELECT * FROM nodes WHERE label = ?"),
@@ -24583,6 +24618,13 @@ var SqliteGraphStore = class {
24583
24618
  const rows = this.stmts.findByLabel.all(label);
24584
24619
  return rows.map(rowToNode);
24585
24620
  }
24621
+ /** Live-row count for a label — `findNodesByLabel(label).length` without the
24622
+ * per-row hydration (attrs JSON + embedding blob). Status surfaces poll this
24623
+ * per project per request; the materializing form held the daemon's event
24624
+ * loop for seconds at scale. */
24625
+ countNodesByLabel(label) {
24626
+ return Number(this.stmts.countByLabel.get(label).n);
24627
+ }
24586
24628
  findAllVersionsByLabel(label) {
24587
24629
  const rows = this.stmts.findByLabelAll.all(label);
24588
24630
  return rows.map(rowToNode);
@@ -25112,6 +25154,9 @@ function backfillProblemContext(store2, ts) {
25112
25154
  }
25113
25155
 
25114
25156
  // ../../packages/local-graph/src/design-problem.ts
25157
+ function isConstraintProblem(node) {
25158
+ return node.attrs["kind"] === "constraint";
25159
+ }
25115
25160
  function buildNode(id, label, description, ts, attrs) {
25116
25161
  return {
25117
25162
  id,
@@ -25167,6 +25212,7 @@ function priorsForFile(store2, relPath) {
25167
25212
  }
25168
25213
  if (!file2) return null;
25169
25214
  const openProblems = [];
25215
+ const constraints = [];
25170
25216
  const seenProblem = /* @__PURE__ */ new Set();
25171
25217
  const related = /* @__PURE__ */ new Map();
25172
25218
  for (const e of store2.inEdges(file2.id, ["ANCHORED_AT"])) {
@@ -25175,14 +25221,14 @@ function priorsForFile(store2, relPath) {
25175
25221
  if (n.label === "Problem") {
25176
25222
  if (!n.attrs["resolvedAt"] && !seenProblem.has(n.id)) {
25177
25223
  seenProblem.add(n.id);
25178
- openProblems.push(n);
25224
+ (isConstraintProblem(n) ? constraints : openProblems).push(n);
25179
25225
  }
25180
25226
  } else if (CITABLE_PRIOR_LABELS.has(n.label)) {
25181
25227
  related.set(n.id, n);
25182
25228
  }
25183
25229
  }
25184
25230
  const solutionsByProblem = /* @__PURE__ */ new Map();
25185
- for (const p of openProblems) {
25231
+ for (const p of [...openProblems, ...constraints]) {
25186
25232
  for (const e of store2.outEdges(p.id, ["SOLVED_BY", "CAUSED_BY", "INSTANCE_OF"])) {
25187
25233
  const n = store2.getNode(e.to);
25188
25234
  if (n && CITABLE_PRIOR_LABELS.has(n.label)) related.set(n.id, n);
@@ -25193,9 +25239,11 @@ function priorsForFile(store2, relPath) {
25193
25239
  }
25194
25240
  }
25195
25241
  }
25196
- if (openProblems.length === 0 && related.size === 0) return null;
25197
- openProblems.sort((a, b) => (b.lastUpdatedAt ?? 0) - (a.lastUpdatedAt ?? 0));
25198
- return { file: file2, openProblems, related: [...related.values()], solutionsByProblem };
25242
+ if (openProblems.length === 0 && constraints.length === 0 && related.size === 0) return null;
25243
+ const recentFirst = (a, b) => (b.lastUpdatedAt ?? 0) - (a.lastUpdatedAt ?? 0);
25244
+ openProblems.sort(recentFirst);
25245
+ constraints.sort(recentFirst);
25246
+ return { file: file2, openProblems, constraints, related: [...related.values()], solutionsByProblem };
25199
25247
  }
25200
25248
  function recordAnchorHint(store2, problemId, relPath, provenance, ts) {
25201
25249
  const p = store2.getNode(problemId);
@@ -25206,11 +25254,13 @@ function recordAnchorHint(store2, problemId, relPath, provenance, ts) {
25206
25254
  });
25207
25255
  return true;
25208
25256
  }
25257
+ var AUTO_MINT_PREFIX = "addressed by an edit to ";
25209
25258
  function resolveDesignProblems(store2, t) {
25210
25259
  let resolved = 0;
25211
25260
  for (const p of store2.findNodesByLabel("Problem")) {
25212
25261
  if (!p.id.startsWith("dprob_")) continue;
25213
25262
  if (p.attrs["resolvedAt"]) continue;
25263
+ if (isConstraintProblem(p)) continue;
25214
25264
  let symName = "";
25215
25265
  let symRelPath;
25216
25266
  let edited = false;
@@ -25228,7 +25278,7 @@ function resolveDesignProblems(store2, t) {
25228
25278
  if (store2.outEdges(p.id, ["SOLVED_BY"]).length === 0) {
25229
25279
  const solId = `dfix_${digest({ problemId: p.id, edit: t })}`.slice(0, 56);
25230
25280
  store2.mergeNode(
25231
- buildNode(solId, "Solution", `addressed by an edit to ${symName}`, t, {
25281
+ buildNode(solId, "Solution", `${AUTO_MINT_PREFIX}${symName}`, t, {
25232
25282
  source: "convo",
25233
25283
  provisional: false,
25234
25284
  // AC-resolution-attrs: the resolving symbol/file as STRUCTURED data, not
@@ -25251,7 +25301,6 @@ function resolveDesignProblems(store2, t) {
25251
25301
  }
25252
25302
 
25253
25303
  // ../../packages/local-graph/src/anchor-backfill.ts
25254
- var AUTO_MINT_PREFIX = "addressed by an edit to ";
25255
25304
  function isLegacyAnchor(attrs) {
25256
25305
  return attrs?.["captureTime"] === true && attrs["anchorProvenance"] === void 0;
25257
25306
  }
@@ -25698,6 +25747,7 @@ function mergeDuplicateProblems(store2, opts) {
25698
25747
  if (consumed.has(b.id)) continue;
25699
25748
  const tb = tokens.get(b.id);
25700
25749
  if (Math.min(ta.size, tb.size) < minTokens) continue;
25750
+ if (isConstraintProblem(a) !== isConstraintProblem(b)) continue;
25701
25751
  if (overlap(ta, tb) >= minOverlap) {
25702
25752
  cluster.push(b);
25703
25753
  consumed.add(b.id);
@@ -26030,12 +26080,14 @@ var AGENTS_POINTER_BODY = [
26030
26080
  init_src2();
26031
26081
  function buildSnapshot(opts) {
26032
26082
  const problems = opts.store.findNodesByLabel("Problem").filter((p) => p.attrs["mergedInto"] === void 0);
26033
- const allProblems = problems.filter((p) => p.attrs["resolvedAt"] == null);
26083
+ const stillOpen = problems.filter((p) => p.attrs["resolvedAt"] == null);
26084
+ const allProblems = stillOpen.filter((p) => !isConstraintProblem(p));
26034
26085
  allProblems.sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt);
26035
26086
  const recent = allProblems.slice(0, 8).map((p) => ({
26036
26087
  node: p,
26037
26088
  anchors: opts.store.outEdges(p.id, ["MANIFESTED_IN", "EVIDENCED_BY"])
26038
26089
  }));
26090
+ const recentConstraints = stillOpen.filter((p) => isConstraintProblem(p)).sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt).slice(0, 3);
26039
26091
  const recentResolved = problems.filter((p) => p.attrs["resolvedAt"] != null && p.attrs["resolvedAs"] == null).sort((a, b) => Number(b.attrs["resolvedAt"] ?? 0) - Number(a.attrs["resolvedAt"] ?? 0)).slice(0, 4).map((p) => {
26040
26092
  const solEdge = opts.store.outEdges(p.id, ["SOLVED_BY"])[0];
26041
26093
  const solution = solEdge ? opts.store.getNode(solEdge.to) ?? void 0 : void 0;
@@ -26063,10 +26115,13 @@ function buildSnapshot(opts) {
26063
26115
  episodeId,
26064
26116
  problems: problems2
26065
26117
  }));
26066
- const needsRevisit = listNeedsRevisit(
26067
- opts.store,
26068
- (opts.now ?? /* @__PURE__ */ new Date()).getTime()
26069
- ).slice(0, 10);
26118
+ const revisitSeen = /* @__PURE__ */ new Set();
26119
+ const needsRevisit = listNeedsRevisit(opts.store, (opts.now ?? /* @__PURE__ */ new Date()).getTime()).filter((r) => {
26120
+ const key = `${r.label}:${r.description.trim().toLowerCase()}`;
26121
+ if (revisitSeen.has(key)) return false;
26122
+ revisitSeen.add(key);
26123
+ return true;
26124
+ }).slice(0, 5);
26070
26125
  const norm = (x) => x.toLowerCase().replace(/[^a-z0-9]+/g, "");
26071
26126
  const pkgBase = (x) => {
26072
26127
  const at = x.lastIndexOf("@");
@@ -26102,6 +26157,7 @@ function buildSnapshot(opts) {
26102
26157
  profileContext,
26103
26158
  recentProblems: recent,
26104
26159
  recentResolved,
26160
+ recentConstraints,
26105
26161
  ...causalNudge ? { causalNudge } : {},
26106
26162
  ...domainNudge ? { domainNudge } : {},
26107
26163
  motifs,
@@ -26154,6 +26210,7 @@ function sliceForFile(store2, relPath) {
26154
26210
  const fp = priorsForFile(store2, relPath);
26155
26211
  const priors = fp ? {
26156
26212
  openProblems: fp.openProblems.slice(0, 3).map((p) => ({ id: p.id, description: p.description })),
26213
+ constraints: fp.constraints.slice(0, 2).map((c) => ({ id: c.id, description: c.description })),
26157
26214
  related: fp.related.slice(0, 4).map((n) => ({ id: n.id, label: n.label, description: n.description })),
26158
26215
  solutionsByProblem: Object.fromEntries(
26159
26216
  fp.openProblems.slice(0, 3).map((p) => [