@inerrata-corporation/errata 2.0.0-dev.79 → 2.0.0-dev.80
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/consolidate-worker.mjs +121 -0
- package/errata.mjs +53 -2
- package/package.json +1 -1
- package/pass-worker.mjs +121 -0
package/consolidate-worker.mjs
CHANGED
|
@@ -15110,9 +15110,90 @@ var init_zod = __esm({
|
|
|
15110
15110
|
});
|
|
15111
15111
|
|
|
15112
15112
|
// ../../packages/shared/src/edge-rules.ts
|
|
15113
|
+
function isValidEdge(from, type, to) {
|
|
15114
|
+
const rule = EDGE_RULES[type];
|
|
15115
|
+
if (!rule) return { ok: true };
|
|
15116
|
+
if (from && rule.from && !rule.from.includes(from)) {
|
|
15117
|
+
return {
|
|
15118
|
+
ok: false,
|
|
15119
|
+
reason: `${type} cannot originate from ${from} (allowed: ${rule.from.join(", ")})`
|
|
15120
|
+
};
|
|
15121
|
+
}
|
|
15122
|
+
if (to && rule.to && !rule.to.includes(to)) {
|
|
15123
|
+
return {
|
|
15124
|
+
ok: false,
|
|
15125
|
+
reason: `${type} cannot target ${to} (allowed: ${rule.to.join(", ")})`
|
|
15126
|
+
};
|
|
15127
|
+
}
|
|
15128
|
+
return { ok: true };
|
|
15129
|
+
}
|
|
15130
|
+
var EDGE_RULES;
|
|
15113
15131
|
var init_edge_rules = __esm({
|
|
15114
15132
|
"../../packages/shared/src/edge-rules.ts"() {
|
|
15115
15133
|
"use strict";
|
|
15134
|
+
EDGE_RULES = {
|
|
15135
|
+
// ── Project anchors (PJ-anchors · PLAN_PROJECT_STORE §6c) ──
|
|
15136
|
+
// ANCHORED_AT is the ONE bridge edge admitted to the cloud, and it exists for
|
|
15137
|
+
// exactly one purpose: point a piece of knowledge at an OPAQUE project `Symbol`
|
|
15138
|
+
// so two teammates' observations about the same function converge on one node.
|
|
15139
|
+
// Constrain it to that purpose — an unconstrained ANCHORED_AT (its state before
|
|
15140
|
+
// this rule, since a missing entry means "anything goes") would let a batch
|
|
15141
|
+
// anchor anything at anything, e.g. at a public `Package`, quietly re-creating
|
|
15142
|
+
// the code↔collective bridge the membrane exists to prevent.
|
|
15143
|
+
ANCHORED_AT: {
|
|
15144
|
+
from: ["Problem", "Solution", "RootCause", "Claim"],
|
|
15145
|
+
to: ["Symbol"]
|
|
15146
|
+
},
|
|
15147
|
+
// ── Security spine (v1 taxonomy.ts SECURITY_FORWARD_ONLY commentary) ──
|
|
15148
|
+
TARGETS: { from: ["Exploit"], to: ["Vulnerability"] },
|
|
15149
|
+
ENABLES: { from: ["AntiPattern"], to: ["Vulnerability"] },
|
|
15150
|
+
MITIGATES: { from: ["Solution"], to: ["Vulnerability"] },
|
|
15151
|
+
PRESENTS: { from: ["Solution"], to: ["Problem", "Vulnerability"] },
|
|
15152
|
+
// SOLVED_BY sources: Vulnerability (v1 comment) + Problem/RootCause
|
|
15153
|
+
// (upstream design-problem.ts + triage.ts mint both).
|
|
15154
|
+
SOLVED_BY: { from: ["Vulnerability", "Problem", "RootCause"], to: ["Solution"] },
|
|
15155
|
+
// FIXED_BY sources mirror SOLVED_BY's (same ailment→fix semantics; live-graph
|
|
15156
|
+
// census 2026-07-14: 512 Problem + 13 RootCause sources, zero others besides
|
|
15157
|
+
// 3 REVERSED Solution→Problem edges the missing `from` let through — the
|
|
15158
|
+
// "Problem solved by Problem" splash bug. A reversed resolution edge is NOT
|
|
15159
|
+
// mechanically flippable (half the sample were PoC-not-fix claims), so the
|
|
15160
|
+
// door rejects rather than repairs; a correct re-emission lands via
|
|
15161
|
+
// recognition-at-the-door.
|
|
15162
|
+
FIXED_BY: { from: ["Vulnerability", "Problem", "RootCause"], to: ["Solution"] },
|
|
15163
|
+
// ── Triage family (upstream castalia.ts: Problem —TRIAGED_BY→ Triage —{INDICATES|CONFIRMS}→ cause) ──
|
|
15164
|
+
// Two-edge differential model (T3-rename): INDICATES = provisional candidate,
|
|
15165
|
+
// CONFIRMS = promoted router (a discriminator exists). Same endpoint matrix.
|
|
15166
|
+
// ROUTES_TO is the deprecated pre-split alias, kept readable during migration.
|
|
15167
|
+
TRIAGED_BY: { from: ["Problem"], to: ["Triage"] },
|
|
15168
|
+
CONFIRMS: { from: ["Triage"], to: ["RootCause", "Problem"] },
|
|
15169
|
+
INDICATES: { from: ["Triage"], to: ["RootCause", "Problem"] },
|
|
15170
|
+
ROUTES_TO: { from: ["Triage"], to: ["RootCause", "Problem"] },
|
|
15171
|
+
// ── Context grounding (v1 taxonomy.ts comments) ──
|
|
15172
|
+
WRITTEN_IN: { from: ["Component", "Package"], to: ["Language"] },
|
|
15173
|
+
OCCURS_IN: { to: ["Language"] },
|
|
15174
|
+
OCCURS_ON: { to: ["OperatingSystem"] },
|
|
15175
|
+
RUNS_ON: { to: ["OperatingSystem"] },
|
|
15176
|
+
OPERATES_ON: { from: ["Algorithm"], to: ["DataStructure"] },
|
|
15177
|
+
INVOLVES: { from: ["Problem", "Solution"], to: ["DataStructure"] },
|
|
15178
|
+
// ── Taxonomy (Track 4 Stream C: MITRE CWE `ChildOf` → `Weakness —IS_A→ Weakness`) ──
|
|
15179
|
+
IS_A: { from: ["Weakness"], to: ["Weakness"] },
|
|
15180
|
+
// ── Conceptual (v1 taxonomy.ts: instance → motif/pattern reference) ──
|
|
15181
|
+
INSTANCE_OF: { to: ["Pattern", "Weakness", "Technique"] },
|
|
15182
|
+
IMPLEMENTS: { from: ["Solution", "Language", "Component"], to: ["Pattern", "Technique"] },
|
|
15183
|
+
MATCHES: { to: ["Pattern"] },
|
|
15184
|
+
// ── Artifact evidence (v1 taxonomy.ts artifact rows) ──
|
|
15185
|
+
PRODUCED: { from: ["Report"], to: ["Artifact"] },
|
|
15186
|
+
MANIFESTED_IN: { from: ["Problem"], to: ["Artifact"] },
|
|
15187
|
+
REVEALED_BY: { from: ["RootCause"], to: ["Artifact"] },
|
|
15188
|
+
// ── Belief / abstraction gradients (upstream castalia.ts) ──
|
|
15189
|
+
CORROBORATES: { from: ["Claim"], to: ["Claim"] },
|
|
15190
|
+
GENERALIZES: { from: ["Claim"] },
|
|
15191
|
+
DERIVED_FROM: { from: ["Claim"] },
|
|
15192
|
+
// ── Decomposition (castalia.ts: a Problem fans out into independent root
|
|
15193
|
+
// problems; §5.1 also attaches SPLIT_INTO to Claim when one conflates two).
|
|
15194
|
+
// `to` left unconstrained — the replacement set's labels vary by case. ──
|
|
15195
|
+
SPLIT_INTO: { from: ["Problem", "Claim"] }
|
|
15196
|
+
};
|
|
15116
15197
|
}
|
|
15117
15198
|
});
|
|
15118
15199
|
|
|
@@ -15623,6 +15704,15 @@ import { parentPort } from "node:worker_threads";
|
|
|
15623
15704
|
|
|
15624
15705
|
// ../../packages/local-graph/src/store.ts
|
|
15625
15706
|
init_src2();
|
|
15707
|
+
init_src();
|
|
15708
|
+
var LOCAL_RULE_OVERRIDES = {
|
|
15709
|
+
ANCHORED_AT: {
|
|
15710
|
+
from: EDGE_RULES["ANCHORED_AT"]?.from,
|
|
15711
|
+
to: [...CODE_NODE_LABELS, "Symbol"]
|
|
15712
|
+
},
|
|
15713
|
+
REVEALED_BY: null,
|
|
15714
|
+
PRODUCED: null
|
|
15715
|
+
};
|
|
15626
15716
|
var SCHEMA_VERSION = 5;
|
|
15627
15717
|
var SCHEMA_SQL = `
|
|
15628
15718
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
@@ -15772,6 +15862,10 @@ var SqliteGraphStore = class {
|
|
|
15772
15862
|
* every node/edge upsert — code-index and capture alike — so the consolidation
|
|
15773
15863
|
* trigger can read "how much changed" without caring what changed it. */
|
|
15774
15864
|
mutations = 0;
|
|
15865
|
+
/** Edges refused by the local ontology gate (EDGE_RULES) since open — a
|
|
15866
|
+
* visible counter so a misbehaving extractor shows up in stats instead of
|
|
15867
|
+
* silently thinning the graph. */
|
|
15868
|
+
rejectedEdgeCount = 0;
|
|
15775
15869
|
/** Persistent monotonic ingest-sequence high-water (KN-decay-momentum). Loaded
|
|
15776
15870
|
* from store_meta on open, advanced once per knowledge ingest event via
|
|
15777
15871
|
* nextIngestSeq(). Distinct from `mutations` (in-memory, per-session, bumped by
|
|
@@ -16081,6 +16175,12 @@ var SqliteGraphStore = class {
|
|
|
16081
16175
|
this.stmts.setCommunity.run({ id, v: community });
|
|
16082
16176
|
}
|
|
16083
16177
|
mergeEdge(edge) {
|
|
16178
|
+
const violation = this.edgeRuleViolation(edge);
|
|
16179
|
+
if (violation) {
|
|
16180
|
+
this.rejectedEdgeCount++;
|
|
16181
|
+
console.warn(`[local-graph] rejected edge ${edge.from}-[:${edge.type}]->${edge.to}: ${violation}`);
|
|
16182
|
+
return;
|
|
16183
|
+
}
|
|
16084
16184
|
this.mutations++;
|
|
16085
16185
|
this.stmts.insertEdge.run({
|
|
16086
16186
|
id: edge.id,
|
|
@@ -16098,6 +16198,27 @@ var SqliteGraphStore = class {
|
|
|
16098
16198
|
attrs_json: JSON.stringify(edge.attrs ?? {})
|
|
16099
16199
|
});
|
|
16100
16200
|
}
|
|
16201
|
+
/** EDGE_RULES check against the stored endpoints' labels, with the LOCAL
|
|
16202
|
+
* overlay consulted first. Returns the reason string on a documented-
|
|
16203
|
+
* forbidden combination, else null. Point lookups on the id PK — negligible
|
|
16204
|
+
* next to the insert itself. */
|
|
16205
|
+
edgeRuleViolation(edge) {
|
|
16206
|
+
const fromLabel = this.getNode(edge.from)?.label;
|
|
16207
|
+
const toLabel = this.getNode(edge.to)?.label;
|
|
16208
|
+
if (edge.type in LOCAL_RULE_OVERRIDES) {
|
|
16209
|
+
const rule = LOCAL_RULE_OVERRIDES[edge.type];
|
|
16210
|
+
if (!rule) return null;
|
|
16211
|
+
if (fromLabel && rule.from && !rule.from.includes(fromLabel)) {
|
|
16212
|
+
return `${edge.type} cannot originate from ${fromLabel} locally (allowed: ${rule.from.join(", ")})`;
|
|
16213
|
+
}
|
|
16214
|
+
if (toLabel && rule.to && !rule.to.includes(toLabel)) {
|
|
16215
|
+
return `${edge.type} cannot target ${toLabel} locally (allowed: ${rule.to.join(", ")})`;
|
|
16216
|
+
}
|
|
16217
|
+
return null;
|
|
16218
|
+
}
|
|
16219
|
+
const verdict = isValidEdge(fromLabel, edge.type, toLabel);
|
|
16220
|
+
return verdict.ok ? null : verdict.reason ?? "edge rule violation";
|
|
16221
|
+
}
|
|
16101
16222
|
updateEdge(id, patch) {
|
|
16102
16223
|
this.stmts.updateEdge.run({
|
|
16103
16224
|
id,
|
package/errata.mjs
CHANGED
|
@@ -16188,11 +16188,20 @@ function rowToEdge(r) {
|
|
|
16188
16188
|
function openGraphStore(opts) {
|
|
16189
16189
|
return new SqliteGraphStore(opts);
|
|
16190
16190
|
}
|
|
16191
|
-
var SCHEMA_VERSION, SCHEMA_SQL, TEMPORAL_INDEX_SQL, SqliteGraphStore;
|
|
16191
|
+
var LOCAL_RULE_OVERRIDES, SCHEMA_VERSION, SCHEMA_SQL, TEMPORAL_INDEX_SQL, SqliteGraphStore;
|
|
16192
16192
|
var init_store = __esm({
|
|
16193
16193
|
"../../packages/local-graph/src/store.ts"() {
|
|
16194
16194
|
"use strict";
|
|
16195
16195
|
init_src2();
|
|
16196
|
+
init_src();
|
|
16197
|
+
LOCAL_RULE_OVERRIDES = {
|
|
16198
|
+
ANCHORED_AT: {
|
|
16199
|
+
from: EDGE_RULES["ANCHORED_AT"]?.from,
|
|
16200
|
+
to: [...CODE_NODE_LABELS, "Symbol"]
|
|
16201
|
+
},
|
|
16202
|
+
REVEALED_BY: null,
|
|
16203
|
+
PRODUCED: null
|
|
16204
|
+
};
|
|
16196
16205
|
SCHEMA_VERSION = 5;
|
|
16197
16206
|
SCHEMA_SQL = `
|
|
16198
16207
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
@@ -16285,6 +16294,10 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
|
|
|
16285
16294
|
* every node/edge upsert — code-index and capture alike — so the consolidation
|
|
16286
16295
|
* trigger can read "how much changed" without caring what changed it. */
|
|
16287
16296
|
mutations = 0;
|
|
16297
|
+
/** Edges refused by the local ontology gate (EDGE_RULES) since open — a
|
|
16298
|
+
* visible counter so a misbehaving extractor shows up in stats instead of
|
|
16299
|
+
* silently thinning the graph. */
|
|
16300
|
+
rejectedEdgeCount = 0;
|
|
16288
16301
|
/** Persistent monotonic ingest-sequence high-water (KN-decay-momentum). Loaded
|
|
16289
16302
|
* from store_meta on open, advanced once per knowledge ingest event via
|
|
16290
16303
|
* nextIngestSeq(). Distinct from `mutations` (in-memory, per-session, bumped by
|
|
@@ -16594,6 +16607,12 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
|
|
|
16594
16607
|
this.stmts.setCommunity.run({ id, v: community });
|
|
16595
16608
|
}
|
|
16596
16609
|
mergeEdge(edge2) {
|
|
16610
|
+
const violation = this.edgeRuleViolation(edge2);
|
|
16611
|
+
if (violation) {
|
|
16612
|
+
this.rejectedEdgeCount++;
|
|
16613
|
+
console.warn(`[local-graph] rejected edge ${edge2.from}-[:${edge2.type}]->${edge2.to}: ${violation}`);
|
|
16614
|
+
return;
|
|
16615
|
+
}
|
|
16597
16616
|
this.mutations++;
|
|
16598
16617
|
this.stmts.insertEdge.run({
|
|
16599
16618
|
id: edge2.id,
|
|
@@ -16611,6 +16630,27 @@ CREATE INDEX IF NOT EXISTS nodes_relpath ON nodes(json_extract(attrs_json, '$.re
|
|
|
16611
16630
|
attrs_json: JSON.stringify(edge2.attrs ?? {})
|
|
16612
16631
|
});
|
|
16613
16632
|
}
|
|
16633
|
+
/** EDGE_RULES check against the stored endpoints' labels, with the LOCAL
|
|
16634
|
+
* overlay consulted first. Returns the reason string on a documented-
|
|
16635
|
+
* forbidden combination, else null. Point lookups on the id PK — negligible
|
|
16636
|
+
* next to the insert itself. */
|
|
16637
|
+
edgeRuleViolation(edge2) {
|
|
16638
|
+
const fromLabel = this.getNode(edge2.from)?.label;
|
|
16639
|
+
const toLabel = this.getNode(edge2.to)?.label;
|
|
16640
|
+
if (edge2.type in LOCAL_RULE_OVERRIDES) {
|
|
16641
|
+
const rule = LOCAL_RULE_OVERRIDES[edge2.type];
|
|
16642
|
+
if (!rule) return null;
|
|
16643
|
+
if (fromLabel && rule.from && !rule.from.includes(fromLabel)) {
|
|
16644
|
+
return `${edge2.type} cannot originate from ${fromLabel} locally (allowed: ${rule.from.join(", ")})`;
|
|
16645
|
+
}
|
|
16646
|
+
if (toLabel && rule.to && !rule.to.includes(toLabel)) {
|
|
16647
|
+
return `${edge2.type} cannot target ${toLabel} locally (allowed: ${rule.to.join(", ")})`;
|
|
16648
|
+
}
|
|
16649
|
+
return null;
|
|
16650
|
+
}
|
|
16651
|
+
const verdict = isValidEdge(fromLabel, edge2.type, toLabel);
|
|
16652
|
+
return verdict.ok ? null : verdict.reason ?? "edge rule violation";
|
|
16653
|
+
}
|
|
16614
16654
|
updateEdge(id, patch) {
|
|
16615
16655
|
this.stmts.updateEdge.run({
|
|
16616
16656
|
id,
|
|
@@ -37675,6 +37715,17 @@ async function flushOutbox(paths, client, store) {
|
|
|
37675
37715
|
if (res.accepted > 0) uploaded++;
|
|
37676
37716
|
if (res.rejected > 0) {
|
|
37677
37717
|
failed++;
|
|
37718
|
+
const rejections = [
|
|
37719
|
+
...(res.result?.nodes ?? []).filter((n) => n.decision === "rejected"),
|
|
37720
|
+
...(res.result?.edges ?? []).filter((e) => e.decision === "rejected")
|
|
37721
|
+
];
|
|
37722
|
+
for (const r of rejections.slice(0, 5)) {
|
|
37723
|
+
const what = "type" in r ? `${r.from}-[:${r.type}]->${r.to}` : r.canonicalId ?? "node";
|
|
37724
|
+
console.warn(`[errata] outbox: cloud rejected ${what}: ${r.reason ?? "no reason given"}`);
|
|
37725
|
+
}
|
|
37726
|
+
if (rejections.length > 5) {
|
|
37727
|
+
console.warn(`[errata] outbox: \u2026and ${rejections.length - 5} more rejections in this batch`);
|
|
37728
|
+
}
|
|
37678
37729
|
quarantine(abs, `semantic rejection (${res.rejected} item${res.rejected === 1 ? "" : "s"})`);
|
|
37679
37730
|
continue;
|
|
37680
37731
|
}
|
|
@@ -43328,7 +43379,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
43328
43379
|
}
|
|
43329
43380
|
|
|
43330
43381
|
// src/engine.ts
|
|
43331
|
-
var DAEMON_VERSION = true ? "2.0.0-dev.
|
|
43382
|
+
var DAEMON_VERSION = true ? "2.0.0-dev.80" : "2.0.0-alpha.0";
|
|
43332
43383
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
43333
43384
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
43334
43385
|
var GIT_OP_MUTE_MS = 4e3;
|
package/package.json
CHANGED
package/pass-worker.mjs
CHANGED
|
@@ -14965,9 +14965,90 @@ var init_zod = __esm({
|
|
|
14965
14965
|
});
|
|
14966
14966
|
|
|
14967
14967
|
// ../../packages/shared/src/edge-rules.ts
|
|
14968
|
+
function isValidEdge(from, type, to) {
|
|
14969
|
+
const rule = EDGE_RULES[type];
|
|
14970
|
+
if (!rule) return { ok: true };
|
|
14971
|
+
if (from && rule.from && !rule.from.includes(from)) {
|
|
14972
|
+
return {
|
|
14973
|
+
ok: false,
|
|
14974
|
+
reason: `${type} cannot originate from ${from} (allowed: ${rule.from.join(", ")})`
|
|
14975
|
+
};
|
|
14976
|
+
}
|
|
14977
|
+
if (to && rule.to && !rule.to.includes(to)) {
|
|
14978
|
+
return {
|
|
14979
|
+
ok: false,
|
|
14980
|
+
reason: `${type} cannot target ${to} (allowed: ${rule.to.join(", ")})`
|
|
14981
|
+
};
|
|
14982
|
+
}
|
|
14983
|
+
return { ok: true };
|
|
14984
|
+
}
|
|
14985
|
+
var EDGE_RULES;
|
|
14968
14986
|
var init_edge_rules = __esm({
|
|
14969
14987
|
"../../packages/shared/src/edge-rules.ts"() {
|
|
14970
14988
|
"use strict";
|
|
14989
|
+
EDGE_RULES = {
|
|
14990
|
+
// ── Project anchors (PJ-anchors · PLAN_PROJECT_STORE §6c) ──
|
|
14991
|
+
// ANCHORED_AT is the ONE bridge edge admitted to the cloud, and it exists for
|
|
14992
|
+
// exactly one purpose: point a piece of knowledge at an OPAQUE project `Symbol`
|
|
14993
|
+
// so two teammates' observations about the same function converge on one node.
|
|
14994
|
+
// Constrain it to that purpose — an unconstrained ANCHORED_AT (its state before
|
|
14995
|
+
// this rule, since a missing entry means "anything goes") would let a batch
|
|
14996
|
+
// anchor anything at anything, e.g. at a public `Package`, quietly re-creating
|
|
14997
|
+
// the code↔collective bridge the membrane exists to prevent.
|
|
14998
|
+
ANCHORED_AT: {
|
|
14999
|
+
from: ["Problem", "Solution", "RootCause", "Claim"],
|
|
15000
|
+
to: ["Symbol"]
|
|
15001
|
+
},
|
|
15002
|
+
// ── Security spine (v1 taxonomy.ts SECURITY_FORWARD_ONLY commentary) ──
|
|
15003
|
+
TARGETS: { from: ["Exploit"], to: ["Vulnerability"] },
|
|
15004
|
+
ENABLES: { from: ["AntiPattern"], to: ["Vulnerability"] },
|
|
15005
|
+
MITIGATES: { from: ["Solution"], to: ["Vulnerability"] },
|
|
15006
|
+
PRESENTS: { from: ["Solution"], to: ["Problem", "Vulnerability"] },
|
|
15007
|
+
// SOLVED_BY sources: Vulnerability (v1 comment) + Problem/RootCause
|
|
15008
|
+
// (upstream design-problem.ts + triage.ts mint both).
|
|
15009
|
+
SOLVED_BY: { from: ["Vulnerability", "Problem", "RootCause"], to: ["Solution"] },
|
|
15010
|
+
// FIXED_BY sources mirror SOLVED_BY's (same ailment→fix semantics; live-graph
|
|
15011
|
+
// census 2026-07-14: 512 Problem + 13 RootCause sources, zero others besides
|
|
15012
|
+
// 3 REVERSED Solution→Problem edges the missing `from` let through — the
|
|
15013
|
+
// "Problem solved by Problem" splash bug. A reversed resolution edge is NOT
|
|
15014
|
+
// mechanically flippable (half the sample were PoC-not-fix claims), so the
|
|
15015
|
+
// door rejects rather than repairs; a correct re-emission lands via
|
|
15016
|
+
// recognition-at-the-door.
|
|
15017
|
+
FIXED_BY: { from: ["Vulnerability", "Problem", "RootCause"], to: ["Solution"] },
|
|
15018
|
+
// ── Triage family (upstream castalia.ts: Problem —TRIAGED_BY→ Triage —{INDICATES|CONFIRMS}→ cause) ──
|
|
15019
|
+
// Two-edge differential model (T3-rename): INDICATES = provisional candidate,
|
|
15020
|
+
// CONFIRMS = promoted router (a discriminator exists). Same endpoint matrix.
|
|
15021
|
+
// ROUTES_TO is the deprecated pre-split alias, kept readable during migration.
|
|
15022
|
+
TRIAGED_BY: { from: ["Problem"], to: ["Triage"] },
|
|
15023
|
+
CONFIRMS: { from: ["Triage"], to: ["RootCause", "Problem"] },
|
|
15024
|
+
INDICATES: { from: ["Triage"], to: ["RootCause", "Problem"] },
|
|
15025
|
+
ROUTES_TO: { from: ["Triage"], to: ["RootCause", "Problem"] },
|
|
15026
|
+
// ── Context grounding (v1 taxonomy.ts comments) ──
|
|
15027
|
+
WRITTEN_IN: { from: ["Component", "Package"], to: ["Language"] },
|
|
15028
|
+
OCCURS_IN: { to: ["Language"] },
|
|
15029
|
+
OCCURS_ON: { to: ["OperatingSystem"] },
|
|
15030
|
+
RUNS_ON: { to: ["OperatingSystem"] },
|
|
15031
|
+
OPERATES_ON: { from: ["Algorithm"], to: ["DataStructure"] },
|
|
15032
|
+
INVOLVES: { from: ["Problem", "Solution"], to: ["DataStructure"] },
|
|
15033
|
+
// ── Taxonomy (Track 4 Stream C: MITRE CWE `ChildOf` → `Weakness —IS_A→ Weakness`) ──
|
|
15034
|
+
IS_A: { from: ["Weakness"], to: ["Weakness"] },
|
|
15035
|
+
// ── Conceptual (v1 taxonomy.ts: instance → motif/pattern reference) ──
|
|
15036
|
+
INSTANCE_OF: { to: ["Pattern", "Weakness", "Technique"] },
|
|
15037
|
+
IMPLEMENTS: { from: ["Solution", "Language", "Component"], to: ["Pattern", "Technique"] },
|
|
15038
|
+
MATCHES: { to: ["Pattern"] },
|
|
15039
|
+
// ── Artifact evidence (v1 taxonomy.ts artifact rows) ──
|
|
15040
|
+
PRODUCED: { from: ["Report"], to: ["Artifact"] },
|
|
15041
|
+
MANIFESTED_IN: { from: ["Problem"], to: ["Artifact"] },
|
|
15042
|
+
REVEALED_BY: { from: ["RootCause"], to: ["Artifact"] },
|
|
15043
|
+
// ── Belief / abstraction gradients (upstream castalia.ts) ──
|
|
15044
|
+
CORROBORATES: { from: ["Claim"], to: ["Claim"] },
|
|
15045
|
+
GENERALIZES: { from: ["Claim"] },
|
|
15046
|
+
DERIVED_FROM: { from: ["Claim"] },
|
|
15047
|
+
// ── Decomposition (castalia.ts: a Problem fans out into independent root
|
|
15048
|
+
// problems; §5.1 also attaches SPLIT_INTO to Claim when one conflates two).
|
|
15049
|
+
// `to` left unconstrained — the replacement set's labels vary by case. ──
|
|
15050
|
+
SPLIT_INTO: { from: ["Problem", "Claim"] }
|
|
15051
|
+
};
|
|
14971
15052
|
}
|
|
14972
15053
|
});
|
|
14973
15054
|
|
|
@@ -23930,6 +24011,15 @@ import { parentPort, workerData } from "node:worker_threads";
|
|
|
23930
24011
|
|
|
23931
24012
|
// ../../packages/local-graph/src/store.ts
|
|
23932
24013
|
init_src2();
|
|
24014
|
+
init_src();
|
|
24015
|
+
var LOCAL_RULE_OVERRIDES = {
|
|
24016
|
+
ANCHORED_AT: {
|
|
24017
|
+
from: EDGE_RULES["ANCHORED_AT"]?.from,
|
|
24018
|
+
to: [...CODE_NODE_LABELS, "Symbol"]
|
|
24019
|
+
},
|
|
24020
|
+
REVEALED_BY: null,
|
|
24021
|
+
PRODUCED: null
|
|
24022
|
+
};
|
|
23933
24023
|
var SCHEMA_VERSION = 5;
|
|
23934
24024
|
var SCHEMA_SQL = `
|
|
23935
24025
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
@@ -24079,6 +24169,10 @@ var SqliteGraphStore = class {
|
|
|
24079
24169
|
* every node/edge upsert — code-index and capture alike — so the consolidation
|
|
24080
24170
|
* trigger can read "how much changed" without caring what changed it. */
|
|
24081
24171
|
mutations = 0;
|
|
24172
|
+
/** Edges refused by the local ontology gate (EDGE_RULES) since open — a
|
|
24173
|
+
* visible counter so a misbehaving extractor shows up in stats instead of
|
|
24174
|
+
* silently thinning the graph. */
|
|
24175
|
+
rejectedEdgeCount = 0;
|
|
24082
24176
|
/** Persistent monotonic ingest-sequence high-water (KN-decay-momentum). Loaded
|
|
24083
24177
|
* from store_meta on open, advanced once per knowledge ingest event via
|
|
24084
24178
|
* nextIngestSeq(). Distinct from `mutations` (in-memory, per-session, bumped by
|
|
@@ -24388,6 +24482,12 @@ var SqliteGraphStore = class {
|
|
|
24388
24482
|
this.stmts.setCommunity.run({ id, v: community });
|
|
24389
24483
|
}
|
|
24390
24484
|
mergeEdge(edge) {
|
|
24485
|
+
const violation = this.edgeRuleViolation(edge);
|
|
24486
|
+
if (violation) {
|
|
24487
|
+
this.rejectedEdgeCount++;
|
|
24488
|
+
console.warn(`[local-graph] rejected edge ${edge.from}-[:${edge.type}]->${edge.to}: ${violation}`);
|
|
24489
|
+
return;
|
|
24490
|
+
}
|
|
24391
24491
|
this.mutations++;
|
|
24392
24492
|
this.stmts.insertEdge.run({
|
|
24393
24493
|
id: edge.id,
|
|
@@ -24405,6 +24505,27 @@ var SqliteGraphStore = class {
|
|
|
24405
24505
|
attrs_json: JSON.stringify(edge.attrs ?? {})
|
|
24406
24506
|
});
|
|
24407
24507
|
}
|
|
24508
|
+
/** EDGE_RULES check against the stored endpoints' labels, with the LOCAL
|
|
24509
|
+
* overlay consulted first. Returns the reason string on a documented-
|
|
24510
|
+
* forbidden combination, else null. Point lookups on the id PK — negligible
|
|
24511
|
+
* next to the insert itself. */
|
|
24512
|
+
edgeRuleViolation(edge) {
|
|
24513
|
+
const fromLabel = this.getNode(edge.from)?.label;
|
|
24514
|
+
const toLabel = this.getNode(edge.to)?.label;
|
|
24515
|
+
if (edge.type in LOCAL_RULE_OVERRIDES) {
|
|
24516
|
+
const rule = LOCAL_RULE_OVERRIDES[edge.type];
|
|
24517
|
+
if (!rule) return null;
|
|
24518
|
+
if (fromLabel && rule.from && !rule.from.includes(fromLabel)) {
|
|
24519
|
+
return `${edge.type} cannot originate from ${fromLabel} locally (allowed: ${rule.from.join(", ")})`;
|
|
24520
|
+
}
|
|
24521
|
+
if (toLabel && rule.to && !rule.to.includes(toLabel)) {
|
|
24522
|
+
return `${edge.type} cannot target ${toLabel} locally (allowed: ${rule.to.join(", ")})`;
|
|
24523
|
+
}
|
|
24524
|
+
return null;
|
|
24525
|
+
}
|
|
24526
|
+
const verdict = isValidEdge(fromLabel, edge.type, toLabel);
|
|
24527
|
+
return verdict.ok ? null : verdict.reason ?? "edge rule violation";
|
|
24528
|
+
}
|
|
24408
24529
|
updateEdge(id, patch) {
|
|
24409
24530
|
this.stmts.updateEdge.run({
|
|
24410
24531
|
id,
|