@inerrata-corporation/errata 2.0.2-dev.85 → 2.0.2-dev.867
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 +579 -238
- package/errata.mjs +8115 -2166
- package/package.json +1 -1
- package/pass-worker.mjs +1128 -214
package/consolidate-worker.mjs
CHANGED
|
@@ -133,7 +133,14 @@ var init_castalia = __esm({
|
|
|
133
133
|
"SOLVED_BY",
|
|
134
134
|
"MITIGATES",
|
|
135
135
|
"REPORTED_FAILURE",
|
|
136
|
-
"CONTRADICTS"
|
|
136
|
+
"CONTRADICTS",
|
|
137
|
+
// Motif twin-faces (KN-twin-faces): failure-face motif → remedy-face motif
|
|
138
|
+
// across layers (AntiPattern/Weakness ↔ Technique/Pattern). Same
|
|
139
|
+
// problem→fix direction as FIXED_BY/SOLVED_BY. Minted by the nightly LLM
|
|
140
|
+
// twin-face pass — these are the near-identical cross-layer pairs the
|
|
141
|
+
// polarity gate (finding 5) correctly refuses to FUSE; the link carries
|
|
142
|
+
// what fusion can't.
|
|
143
|
+
"REMEDIED_BY"
|
|
137
144
|
];
|
|
138
145
|
CONCEPTUAL_EDGES = [
|
|
139
146
|
"INSTANCE_OF",
|
|
@@ -223,6 +230,10 @@ var init_castalia = __esm({
|
|
|
223
230
|
CAUSED_BY: 3,
|
|
224
231
|
FIXED_BY: 3,
|
|
225
232
|
SOLVED_BY: 3,
|
|
233
|
+
// Twin-face link (failure motif → remedy motif, KN-twin-faces) — causal-grade
|
|
234
|
+
// but a notch below witnessed FIXED_BY/SOLVED_BY: the pairing is an LLM
|
|
235
|
+
// judgment over descriptions, not an agent-witnessed resolution.
|
|
236
|
+
REMEDIED_BY: 2.5,
|
|
226
237
|
MANIFESTS_AS: 2,
|
|
227
238
|
ESCALATES_TO: 1.5,
|
|
228
239
|
AFFECTS: 1.2,
|
|
@@ -662,7 +673,7 @@ function lemma(token) {
|
|
|
662
673
|
}
|
|
663
674
|
return token;
|
|
664
675
|
}
|
|
665
|
-
function
|
|
676
|
+
function tokenize(text, resolve) {
|
|
666
677
|
const matches = text.normalize("NFC").toLowerCase().match(TOKEN_RE) ?? [];
|
|
667
678
|
const out = /* @__PURE__ */ new Set();
|
|
668
679
|
for (const raw of matches) {
|
|
@@ -672,11 +683,14 @@ function conceptTokens(text) {
|
|
|
672
683
|
out.add(token);
|
|
673
684
|
continue;
|
|
674
685
|
}
|
|
675
|
-
const canonical =
|
|
686
|
+
const canonical = resolve(token);
|
|
676
687
|
out.add(canonical ?? lemma(token));
|
|
677
688
|
}
|
|
678
689
|
return [...out].sort();
|
|
679
690
|
}
|
|
691
|
+
function conceptTokens(text) {
|
|
692
|
+
return tokenize(text, resolveCanonicalId);
|
|
693
|
+
}
|
|
680
694
|
function conceptBag(text) {
|
|
681
695
|
return conceptTokens(text).join(" ");
|
|
682
696
|
}
|
|
@@ -15203,7 +15217,12 @@ var init_edge_rules = __esm({
|
|
|
15203
15217
|
// ── Taxonomy (Track 4 Stream C: MITRE CWE `ChildOf` → `Weakness —IS_A→ Weakness`) ──
|
|
15204
15218
|
IS_A: { from: ["Weakness"], to: ["Weakness"] },
|
|
15205
15219
|
// ── Conceptual (v1 taxonomy.ts: instance → motif/pattern reference) ──
|
|
15206
|
-
|
|
15220
|
+
// `AntiPattern` joined the target set 2026-08-02: it is one of the three motif
|
|
15221
|
+
// kinds (generalizer motifs.ts `layerOf`: pattern | technique | antipattern) and
|
|
15222
|
+
// the SUPPRESSED-close path mints `Problem ─INSTANCE_OF→ AntiPattern` as the
|
|
15223
|
+
// negative-knowledge binding ("silenced, not solved") — the original three-label
|
|
15224
|
+
// rule predates AntiPattern joining the motif layer and silently ate that edge.
|
|
15225
|
+
INSTANCE_OF: { to: ["Pattern", "AntiPattern", "Weakness", "Technique"] },
|
|
15207
15226
|
IMPLEMENTS: { from: ["Solution", "Language", "Component"], to: ["Pattern", "Technique"] },
|
|
15208
15227
|
MATCHES: { to: ["Pattern"] },
|
|
15209
15228
|
// ── Artifact evidence (v1 taxonomy.ts artifact rows) ──
|
|
@@ -15304,6 +15323,23 @@ var init_wire = __esm({
|
|
|
15304
15323
|
/** Canonical human-readable description (no raw paths — daemon scrubs; server rechecks). */
|
|
15305
15324
|
description: external_exports.string().min(1).max(4e3),
|
|
15306
15325
|
attrs: external_exports.record(external_exports.string(), external_exports.unknown()).default({}),
|
|
15326
|
+
/** One-way origin key of the SESSION that minted this node (`ws_…`, a
|
|
15327
|
+
* truncated digest — never the raw session id). Stamped onto the created
|
|
15328
|
+
* node as `authoringSession`, which is the independence unit for the
|
|
15329
|
+
* evidence channels: the session that authored a claim may not corroborate
|
|
15330
|
+
* or refute it, while a DIFFERENT session on the same checkout may (alyssa,
|
|
15331
|
+
* 2026-07-31 — the workspace key made every witness on a single-checkout
|
|
15332
|
+
* deployment a self-corroboration). Optional + additive: absent leaves the
|
|
15333
|
+
* gate fail-open for that node, exactly today's behaviour. */
|
|
15334
|
+
originSession: external_exports.string().min(3).max(64).optional(),
|
|
15335
|
+
/** Epoch ms of the ORIGINATING local node's creation — when the knowledge was
|
|
15336
|
+
* actually captured, as opposed to when its public twin reached the cloud.
|
|
15337
|
+
* Stored as `observedAt`; the network board's chronological view orders on
|
|
15338
|
+
* it. Without this the wire carried NO timestamp at all, so a node captured
|
|
15339
|
+
* days ago surfaced as "new" the moment it was generalized and published —
|
|
15340
|
+
* the board showed ingest order wearing a chronology's clothes. Optional +
|
|
15341
|
+
* additive: absent keeps ingest-time ordering for that node. */
|
|
15342
|
+
originCreatedAtMs: external_exports.number().int().positive().optional(),
|
|
15307
15343
|
extractionSource: external_exports.enum(INGEST_EXTRACTION_SOURCES),
|
|
15308
15344
|
validationSource: external_exports.enum(VALIDATION_SOURCES).optional(),
|
|
15309
15345
|
/** Org-membrane (M2): the daemon's anchor tag — it owns the lockfile, so it
|
|
@@ -15404,7 +15440,7 @@ var init_canonicalize = __esm({
|
|
|
15404
15440
|
|
|
15405
15441
|
// ../../packages/shared/src/nlp/triage-canon.ts
|
|
15406
15442
|
function canonicalizeToken(t) {
|
|
15407
|
-
const base = t.trim().toLowerCase().replace(/
|
|
15443
|
+
const base = t.trim().toLowerCase().replace(/(?!^)@.*$|\s.*$/, "");
|
|
15408
15444
|
if (!base) return "";
|
|
15409
15445
|
return resolveCanonicalId(base) ?? base;
|
|
15410
15446
|
}
|
|
@@ -15486,6 +15522,51 @@ var init_review = __esm({
|
|
|
15486
15522
|
}
|
|
15487
15523
|
});
|
|
15488
15524
|
|
|
15525
|
+
// ../../packages/local-shared/src/anchorable.ts
|
|
15526
|
+
function anchorableExtensionAlternation() {
|
|
15527
|
+
return BY_LENGTH.map((e) => e.slice(1).replace(/[+.]/g, (c) => `\\${c}`)).join("|");
|
|
15528
|
+
}
|
|
15529
|
+
var ANCHORABLE_EXTENSIONS, BY_LENGTH;
|
|
15530
|
+
var init_anchorable = __esm({
|
|
15531
|
+
"../../packages/local-shared/src/anchorable.ts"() {
|
|
15532
|
+
"use strict";
|
|
15533
|
+
ANCHORABLE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
15534
|
+
// typescript provider
|
|
15535
|
+
".ts",
|
|
15536
|
+
".tsx",
|
|
15537
|
+
".js",
|
|
15538
|
+
".jsx",
|
|
15539
|
+
".mjs",
|
|
15540
|
+
".cjs",
|
|
15541
|
+
// python / go / rust / ruby / csharp providers
|
|
15542
|
+
".py",
|
|
15543
|
+
".go",
|
|
15544
|
+
".rs",
|
|
15545
|
+
".rb",
|
|
15546
|
+
".cs",
|
|
15547
|
+
// cpp provider — every variant it parses, not just the three that were listed
|
|
15548
|
+
".c",
|
|
15549
|
+
".h",
|
|
15550
|
+
".cpp",
|
|
15551
|
+
".cc",
|
|
15552
|
+
".cxx",
|
|
15553
|
+
".c++",
|
|
15554
|
+
".hpp",
|
|
15555
|
+
".hh",
|
|
15556
|
+
".hxx",
|
|
15557
|
+
".h++",
|
|
15558
|
+
// CUDA — the cpp provider parses these too. Missed when this list was first
|
|
15559
|
+
// transcribed by hand; the parity test caught them on its very first run,
|
|
15560
|
+
// which is the argument for the test existing.
|
|
15561
|
+
".cu",
|
|
15562
|
+
".cuh",
|
|
15563
|
+
// no provider yet; the grammar ships. Inert, not wrong — see above.
|
|
15564
|
+
".java"
|
|
15565
|
+
]);
|
|
15566
|
+
BY_LENGTH = [...ANCHORABLE_EXTENSIONS].sort((a, b) => b.length - a.length);
|
|
15567
|
+
}
|
|
15568
|
+
});
|
|
15569
|
+
|
|
15489
15570
|
// ../../packages/local-shared/src/sqlite-adapter.ts
|
|
15490
15571
|
function openDatabase(path) {
|
|
15491
15572
|
const db = new DatabaseSync(path);
|
|
@@ -15498,6 +15579,7 @@ function openDatabase(path) {
|
|
|
15498
15579
|
db.exec("PRAGMA journal_mode = WAL");
|
|
15499
15580
|
db.exec("PRAGMA synchronous = NORMAL");
|
|
15500
15581
|
db.exec("PRAGMA busy_timeout = 5000");
|
|
15582
|
+
db.exec("PRAGMA journal_size_limit = 67108864");
|
|
15501
15583
|
} catch {
|
|
15502
15584
|
}
|
|
15503
15585
|
}
|
|
@@ -15533,7 +15615,7 @@ function openDatabase(path) {
|
|
|
15533
15615
|
return db.prepare(`PRAGMA ${key}`).get();
|
|
15534
15616
|
},
|
|
15535
15617
|
transaction(fn) {
|
|
15536
|
-
db.exec("BEGIN");
|
|
15618
|
+
db.exec("BEGIN IMMEDIATE");
|
|
15537
15619
|
try {
|
|
15538
15620
|
const r = fn();
|
|
15539
15621
|
db.exec("COMMIT");
|
|
@@ -15587,6 +15669,7 @@ var init_src2 = __esm({
|
|
|
15587
15669
|
init_profile();
|
|
15588
15670
|
init_daemon_wire();
|
|
15589
15671
|
init_review();
|
|
15672
|
+
init_anchorable();
|
|
15590
15673
|
init_sqlite_adapter();
|
|
15591
15674
|
}
|
|
15592
15675
|
});
|
|
@@ -15752,9 +15835,32 @@ var LOCAL_RULE_OVERRIDES = {
|
|
|
15752
15835
|
to: [...CODE_NODE_LABELS, "Symbol"]
|
|
15753
15836
|
},
|
|
15754
15837
|
REVEALED_BY: null,
|
|
15755
|
-
PRODUCED: null
|
|
15838
|
+
PRODUCED: null,
|
|
15839
|
+
// FIXED_BY locally ALSO carries the fix-provenance sense: `resolveProblem`
|
|
15840
|
+
// attributes a closed Problem to the fixing `Episode` (PLAN_PLASTICITY §2.1)
|
|
15841
|
+
// alongside the cloud's Problem→Solution knowledge claim. Same shape as
|
|
15842
|
+
// PRODUCED/REVEALED_BY above — an Episode is code-layer and never drains, so
|
|
15843
|
+
// the cloud door's `to: [Solution]` rule is untouched. The `from` constraint
|
|
15844
|
+
// stays: the reversed (Solution)-FIXED_BY->(...) splash bug is the reason
|
|
15845
|
+
// this rule exists at all.
|
|
15846
|
+
FIXED_BY: { from: EDGE_RULES["FIXED_BY"]?.from, to: ["Solution", "Episode"] }
|
|
15756
15847
|
};
|
|
15757
|
-
|
|
15848
|
+
function localEdgeViolation(fromLabel, type, toLabel) {
|
|
15849
|
+
if (type in LOCAL_RULE_OVERRIDES) {
|
|
15850
|
+
const rule = LOCAL_RULE_OVERRIDES[type];
|
|
15851
|
+
if (!rule) return null;
|
|
15852
|
+
if (fromLabel && rule.from && !rule.from.includes(fromLabel)) {
|
|
15853
|
+
return `${type} cannot originate from ${fromLabel} locally (allowed: ${rule.from.join(", ")})`;
|
|
15854
|
+
}
|
|
15855
|
+
if (toLabel && rule.to && !rule.to.includes(toLabel)) {
|
|
15856
|
+
return `${type} cannot target ${toLabel} locally (allowed: ${rule.to.join(", ")})`;
|
|
15857
|
+
}
|
|
15858
|
+
return null;
|
|
15859
|
+
}
|
|
15860
|
+
const verdict = isValidEdge(fromLabel, type, toLabel);
|
|
15861
|
+
return verdict.ok ? null : verdict.reason ?? "edge rule violation";
|
|
15862
|
+
}
|
|
15863
|
+
var SCHEMA_VERSION = 6;
|
|
15758
15864
|
var SCHEMA_SQL = `
|
|
15759
15865
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
15760
15866
|
version INTEGER PRIMARY KEY
|
|
@@ -15769,6 +15875,21 @@ CREATE TABLE IF NOT EXISTS store_meta (
|
|
|
15769
15875
|
value TEXT NOT NULL
|
|
15770
15876
|
);
|
|
15771
15877
|
|
|
15878
|
+
-- Durable ledger of edges the ontology gate REFUSED, keyed by edge type.
|
|
15879
|
+
-- Durable rather than in-memory for one specific reason: the status command runs
|
|
15880
|
+
-- in a SEPARATE process and opens its own store handle, so a counter living on
|
|
15881
|
+
-- the instance reads 0 there forever. That is exactly how a producer rejecting
|
|
15882
|
+
-- 100% of its output stayed invisible for 17 days. Persisting it also survives
|
|
15883
|
+
-- the daemon restart that would otherwise erase the evidence.
|
|
15884
|
+
-- Keyed by type because a systematic producer bug shows up as ONE type
|
|
15885
|
+
-- dominating; sample keeps the latest reason so the count is actionable.
|
|
15886
|
+
CREATE TABLE IF NOT EXISTS edge_rejections (
|
|
15887
|
+
type TEXT PRIMARY KEY,
|
|
15888
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
15889
|
+
last_at INTEGER NOT NULL,
|
|
15890
|
+
sample TEXT
|
|
15891
|
+
);
|
|
15892
|
+
|
|
15772
15893
|
CREATE TABLE IF NOT EXISTS nodes (
|
|
15773
15894
|
id TEXT PRIMARY KEY,
|
|
15774
15895
|
label TEXT NOT NULL,
|
|
@@ -16145,6 +16266,16 @@ var SqliteGraphStore = class {
|
|
|
16145
16266
|
if (!cols.has(name)) this.db.exec(ddl);
|
|
16146
16267
|
}
|
|
16147
16268
|
}
|
|
16269
|
+
if (from < 6) {
|
|
16270
|
+
this.db.exec(`
|
|
16271
|
+
CREATE TABLE IF NOT EXISTS edge_rejections (
|
|
16272
|
+
type TEXT PRIMARY KEY,
|
|
16273
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
16274
|
+
last_at INTEGER NOT NULL,
|
|
16275
|
+
sample TEXT
|
|
16276
|
+
)
|
|
16277
|
+
`);
|
|
16278
|
+
}
|
|
16148
16279
|
this.db.prepare("UPDATE schema_version SET version = ?").run(SCHEMA_VERSION);
|
|
16149
16280
|
});
|
|
16150
16281
|
}
|
|
@@ -16226,6 +16357,7 @@ var SqliteGraphStore = class {
|
|
|
16226
16357
|
const violation = this.edgeRuleViolation(edge);
|
|
16227
16358
|
if (violation) {
|
|
16228
16359
|
this.rejectedEdgeCount++;
|
|
16360
|
+
this.recordEdgeRejection(edge.type, violation, edge.lastSeenAt || edge.createdAt || 0);
|
|
16229
16361
|
console.warn(`[local-graph] rejected edge ${edge.from}-[:${edge.type}]->${edge.to}: ${violation}`);
|
|
16230
16362
|
return;
|
|
16231
16363
|
}
|
|
@@ -16250,22 +16382,51 @@ var SqliteGraphStore = class {
|
|
|
16250
16382
|
* overlay consulted first. Returns the reason string on a documented-
|
|
16251
16383
|
* forbidden combination, else null. Point lookups on the id PK — negligible
|
|
16252
16384
|
* next to the insert itself. */
|
|
16253
|
-
|
|
16254
|
-
|
|
16255
|
-
|
|
16256
|
-
|
|
16257
|
-
|
|
16258
|
-
|
|
16259
|
-
|
|
16260
|
-
|
|
16261
|
-
|
|
16262
|
-
|
|
16263
|
-
|
|
16264
|
-
|
|
16265
|
-
|
|
16385
|
+
/** Upsert one refusal into the durable ledger. Best-effort: a bookkeeping
|
|
16386
|
+
* failure must never turn a refused edge into a thrown write. */
|
|
16387
|
+
recordEdgeRejection(type, reason, at) {
|
|
16388
|
+
try {
|
|
16389
|
+
this.db.prepare(
|
|
16390
|
+
`INSERT INTO edge_rejections (type, count, last_at, sample) VALUES (?, 1, ?, ?)
|
|
16391
|
+
ON CONFLICT(type) DO UPDATE SET
|
|
16392
|
+
count = count + 1, last_at = excluded.last_at, sample = excluded.sample`
|
|
16393
|
+
).run(type, at, reason.slice(0, 200));
|
|
16394
|
+
} catch {
|
|
16395
|
+
}
|
|
16396
|
+
}
|
|
16397
|
+
/** Refusals recorded by the ontology gate, per edge type, newest activity first.
|
|
16398
|
+
* Durable across restarts and readable from any process (see the table note). */
|
|
16399
|
+
edgeRejections() {
|
|
16400
|
+
try {
|
|
16401
|
+
return this.db.prepare(
|
|
16402
|
+
"SELECT type, count, last_at AS lastAt, sample FROM edge_rejections ORDER BY count DESC, last_at DESC"
|
|
16403
|
+
).all();
|
|
16404
|
+
} catch {
|
|
16405
|
+
return [];
|
|
16406
|
+
}
|
|
16407
|
+
}
|
|
16408
|
+
/** Drop ledger entries whose last refusal predates `cutoff`. A still-misbehaving
|
|
16409
|
+
* producer keeps refreshing `last_at` and survives; a fixed one fades out. */
|
|
16410
|
+
pruneEdgeRejections(cutoff) {
|
|
16411
|
+
try {
|
|
16412
|
+
this.db.prepare("DELETE FROM edge_rejections WHERE last_at < ?").run(cutoff);
|
|
16413
|
+
} catch {
|
|
16414
|
+
}
|
|
16415
|
+
}
|
|
16416
|
+
/** Clear the ledger outright, whole or per type — operator escape hatch. */
|
|
16417
|
+
clearEdgeRejections(type) {
|
|
16418
|
+
try {
|
|
16419
|
+
if (type) this.db.prepare("DELETE FROM edge_rejections WHERE type = ?").run(type);
|
|
16420
|
+
else this.db.exec("DELETE FROM edge_rejections");
|
|
16421
|
+
} catch {
|
|
16266
16422
|
}
|
|
16267
|
-
|
|
16268
|
-
|
|
16423
|
+
}
|
|
16424
|
+
edgeRuleViolation(edge) {
|
|
16425
|
+
return localEdgeViolation(
|
|
16426
|
+
this.getNode(edge.from)?.label,
|
|
16427
|
+
edge.type,
|
|
16428
|
+
this.getNode(edge.to)?.label
|
|
16429
|
+
);
|
|
16269
16430
|
}
|
|
16270
16431
|
updateEdge(id, patch) {
|
|
16271
16432
|
this.stmts.updateEdge.run({
|
|
@@ -16402,6 +16563,163 @@ var SqliteGraphStore = class {
|
|
|
16402
16563
|
const rows = this.db.prepare("SELECT from_id, to_id, type FROM edges WHERE valid_to IS NULL").all();
|
|
16403
16564
|
return rows.map((r) => ({ from: r.from_id, to: r.to_id, type: r.type }));
|
|
16404
16565
|
}
|
|
16566
|
+
getMeta(key) {
|
|
16567
|
+
const r = this.db.prepare("SELECT value FROM store_meta WHERE key = ?").get(key);
|
|
16568
|
+
return r?.value ?? null;
|
|
16569
|
+
}
|
|
16570
|
+
setMeta(key, value) {
|
|
16571
|
+
this.db.prepare(
|
|
16572
|
+
"INSERT INTO store_meta (key, value) VALUES (:key, :value) ON CONFLICT(key) DO UPDATE SET value = excluded.value"
|
|
16573
|
+
).run({ key, value });
|
|
16574
|
+
}
|
|
16575
|
+
dirtyNodeIdsSince(ts) {
|
|
16576
|
+
const rows = this.db.prepare("SELECT id FROM nodes WHERE valid_to IS NULL AND last_updated_at > ?").all(ts);
|
|
16577
|
+
return rows.map((r) => r.id);
|
|
16578
|
+
}
|
|
16579
|
+
/** Endpoints of edges TOUCHED since `ts` — created, re-seen, or CLOSED.
|
|
16580
|
+
* Closures matter as much as additions: a node that lost inflow is rank-dirty
|
|
16581
|
+
* while its own row never updated, so removal endpoints must seed the
|
|
16582
|
+
* incremental region or the stale inflow persists until the full backstop. */
|
|
16583
|
+
edgeEndpointsTouchedSince(ts) {
|
|
16584
|
+
const rows = this.db.prepare(
|
|
16585
|
+
`SELECT from_id, to_id FROM edges
|
|
16586
|
+
WHERE (valid_to IS NULL AND (created_at > :ts OR last_seen_at > :ts))
|
|
16587
|
+
OR (valid_to IS NOT NULL AND valid_to > :ts)`
|
|
16588
|
+
).all({ ts });
|
|
16589
|
+
return rows.map((r) => ({ from: r.from_id, to: r.to_id }));
|
|
16590
|
+
}
|
|
16591
|
+
/** Lightweight out-edges for a SET of sources, chunked IN-lists — the region
|
|
16592
|
+
* assembly path for incremental PageRank (per-node outEdges() at region
|
|
16593
|
+
* scale re-creates the 106k-prepared-calls problem the batch scan solved). */
|
|
16594
|
+
outEdgesForMany(ids) {
|
|
16595
|
+
return this.edgesForMany(ids, "from_id");
|
|
16596
|
+
}
|
|
16597
|
+
inEdgesForMany(ids) {
|
|
16598
|
+
return this.edgesForMany(ids, "to_id");
|
|
16599
|
+
}
|
|
16600
|
+
/** Stored pageRank for a SET of ids (live rows only — a closed id is simply
|
|
16601
|
+
* absent, which is how incremental region assembly drops dead endpoints). */
|
|
16602
|
+
ranksForMany(ids) {
|
|
16603
|
+
const out = /* @__PURE__ */ new Map();
|
|
16604
|
+
const CHUNK = 400;
|
|
16605
|
+
for (let i = 0; i < ids.length; i += CHUNK) {
|
|
16606
|
+
const chunk = ids.slice(i, i + CHUNK);
|
|
16607
|
+
const placeholders = chunk.map(() => "?").join(", ");
|
|
16608
|
+
const rows = this.db.prepare(
|
|
16609
|
+
`SELECT id, page_rank FROM nodes WHERE id IN (${placeholders}) AND valid_to IS NULL`
|
|
16610
|
+
).all(...chunk);
|
|
16611
|
+
for (const r of rows) out.set(r.id, r.page_rank);
|
|
16612
|
+
}
|
|
16613
|
+
return out;
|
|
16614
|
+
}
|
|
16615
|
+
/** The minimal row set the landmark sweep needs — landmark CANDIDATES
|
|
16616
|
+
* (Pattern/RootCause), everything currently flagged, and every
|
|
16617
|
+
* persistent-tier node (force-landmarks). A few thousand rows, so the
|
|
16618
|
+
* incremental path can refresh the GLOBAL landmark set without the 179k-row
|
|
16619
|
+
* scanLiveNodes materialization. */
|
|
16620
|
+
landmarkSweepRows() {
|
|
16621
|
+
const rows = this.db.prepare(
|
|
16622
|
+
`SELECT id, label, page_rank, is_landmark, memory_tier, extraction_source FROM nodes
|
|
16623
|
+
WHERE valid_to IS NULL
|
|
16624
|
+
AND (memory_tier = 'persistent' OR is_landmark = 1 OR label IN ('Pattern', 'RootCause'))`
|
|
16625
|
+
).all();
|
|
16626
|
+
return rows.map((r) => ({
|
|
16627
|
+
id: r.id,
|
|
16628
|
+
label: r.label,
|
|
16629
|
+
pageRank: r.page_rank,
|
|
16630
|
+
isLandmark: r.is_landmark === 1,
|
|
16631
|
+
memoryTier: r.memory_tier,
|
|
16632
|
+
extractionSource: r.extraction_source
|
|
16633
|
+
}));
|
|
16634
|
+
}
|
|
16635
|
+
edgesForMany(ids, col) {
|
|
16636
|
+
const out = [];
|
|
16637
|
+
const CHUNK = 400;
|
|
16638
|
+
for (let i = 0; i < ids.length; i += CHUNK) {
|
|
16639
|
+
const chunk = ids.slice(i, i + CHUNK);
|
|
16640
|
+
const placeholders = chunk.map(() => "?").join(", ");
|
|
16641
|
+
const rows = this.db.prepare(
|
|
16642
|
+
`SELECT from_id, to_id, type FROM edges WHERE ${col} IN (${placeholders}) AND valid_to IS NULL`
|
|
16643
|
+
).all(...chunk);
|
|
16644
|
+
for (const r of rows) out.push({ from: r.from_id, to: r.to_id, type: r.type });
|
|
16645
|
+
}
|
|
16646
|
+
return out;
|
|
16647
|
+
}
|
|
16648
|
+
checkpointWal() {
|
|
16649
|
+
try {
|
|
16650
|
+
const r = this.db.prepare("PRAGMA wal_checkpoint(TRUNCATE)").get();
|
|
16651
|
+
return r ?? null;
|
|
16652
|
+
} catch {
|
|
16653
|
+
return null;
|
|
16654
|
+
}
|
|
16655
|
+
}
|
|
16656
|
+
reviveReobserved(relPaths, workspaceId, since) {
|
|
16657
|
+
let revived = 0;
|
|
16658
|
+
const CHUNK = 400;
|
|
16659
|
+
for (let i = 0; i < relPaths.length; i += CHUNK) {
|
|
16660
|
+
const slice = relPaths.slice(i, i + CHUNK);
|
|
16661
|
+
if (slice.length === 0) continue;
|
|
16662
|
+
const r = this.db.prepare(
|
|
16663
|
+
`UPDATE nodes SET valid_to = NULL
|
|
16664
|
+
WHERE valid_to IS NOT NULL
|
|
16665
|
+
AND last_updated_at >= ?
|
|
16666
|
+
AND json_extract(attrs_json, '$.workspaceId') = ?
|
|
16667
|
+
AND json_extract(attrs_json, '$.relPath') IN (${slice.map(() => "?").join(",")})`
|
|
16668
|
+
).run(since, workspaceId, ...slice);
|
|
16669
|
+
revived += Number(r.changes);
|
|
16670
|
+
}
|
|
16671
|
+
if (revived > 0) this.mutations++;
|
|
16672
|
+
return revived;
|
|
16673
|
+
}
|
|
16674
|
+
recentEdgeAttrCoverage(marker, attr, limit) {
|
|
16675
|
+
const r = this.db.prepare(
|
|
16676
|
+
`SELECT COUNT(*) AS total,
|
|
16677
|
+
COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
|
|
16678
|
+
FROM (SELECT attrs_json FROM edges
|
|
16679
|
+
WHERE valid_to IS NULL AND attrs_json LIKE ?
|
|
16680
|
+
ORDER BY created_at DESC LIMIT ?)`
|
|
16681
|
+
).get(attr, `%${marker}%`, limit);
|
|
16682
|
+
return { count: Number(r.count), total: Number(r.total) };
|
|
16683
|
+
}
|
|
16684
|
+
liveNodeIds(ids) {
|
|
16685
|
+
const live = /* @__PURE__ */ new Set();
|
|
16686
|
+
const CHUNK = 900;
|
|
16687
|
+
for (let i = 0; i < ids.length; i += CHUNK) {
|
|
16688
|
+
const slice = ids.slice(i, i + CHUNK);
|
|
16689
|
+
if (slice.length === 0) continue;
|
|
16690
|
+
const rows = this.db.prepare(
|
|
16691
|
+
`SELECT id FROM nodes WHERE valid_to IS NULL AND id IN (${slice.map(() => "?").join(",")})`
|
|
16692
|
+
).all(...slice);
|
|
16693
|
+
for (const r of rows) live.add(r.id);
|
|
16694
|
+
}
|
|
16695
|
+
return live;
|
|
16696
|
+
}
|
|
16697
|
+
/**
|
|
16698
|
+
* Live edges WITH their endpoint labels and ids, resolved in ONE join.
|
|
16699
|
+
*
|
|
16700
|
+
* The ontology sweep needs (id, type, fromLabel, toLabel) for every live edge.
|
|
16701
|
+
* Doing that as `scanLiveEdges()` + two `getNode()` calls is 2N node reads —
|
|
16702
|
+
* 550,000 on this store — and each one deserializes the node's embedding blob.
|
|
16703
|
+
* Measured: the sweep did not finish in 10 minutes. As a single join it is one
|
|
16704
|
+
* query over an index-covered scan. Labels only; nothing here touches embeddings.
|
|
16705
|
+
*/
|
|
16706
|
+
scanLiveEdgeRows() {
|
|
16707
|
+
const rows = this.db.prepare(
|
|
16708
|
+
`SELECT e.id, e.from_id, e.to_id, e.type, a.label AS from_label, b.label AS to_label
|
|
16709
|
+
FROM edges e
|
|
16710
|
+
LEFT JOIN nodes a ON a.id = e.from_id AND a.valid_to IS NULL
|
|
16711
|
+
LEFT JOIN nodes b ON b.id = e.to_id AND b.valid_to IS NULL
|
|
16712
|
+
WHERE e.valid_to IS NULL`
|
|
16713
|
+
).all();
|
|
16714
|
+
return rows.map((r) => ({
|
|
16715
|
+
id: r.id,
|
|
16716
|
+
from: r.from_id,
|
|
16717
|
+
to: r.to_id,
|
|
16718
|
+
type: r.type,
|
|
16719
|
+
fromLabel: r.from_label ?? void 0,
|
|
16720
|
+
toLabel: r.to_label ?? void 0
|
|
16721
|
+
}));
|
|
16722
|
+
}
|
|
16405
16723
|
/** Live nodes whose attrs.relPath is one of `relPaths`. Uses the nodes_relpath
|
|
16406
16724
|
* expression index so the incremental reindex fetches only the changed files'
|
|
16407
16725
|
* symbols instead of scanning every versioned node. */
|
|
@@ -16422,6 +16740,10 @@ var SqliteGraphStore = class {
|
|
|
16422
16740
|
if (!live) return null;
|
|
16423
16741
|
const version2 = live.version ?? 1;
|
|
16424
16742
|
const frozenId = `${liveId}@v${version2}`;
|
|
16743
|
+
if (this.getNode(frozenId)) {
|
|
16744
|
+
this.stmts.advanceLive.run({ live_id: liveId, t });
|
|
16745
|
+
return frozenId;
|
|
16746
|
+
}
|
|
16425
16747
|
this.stmts.freezeCopy.run({ frozen_id: frozenId, live_id: liveId, t });
|
|
16426
16748
|
this.mergeEdge({
|
|
16427
16749
|
id: `edge_superseded_${frozenId}`,
|
|
@@ -16480,6 +16802,7 @@ var CAUSAL_FAMILY = [
|
|
|
16480
16802
|
|
|
16481
16803
|
// ../../packages/local-graph/src/justification.ts
|
|
16482
16804
|
init_src();
|
|
16805
|
+
init_src2();
|
|
16483
16806
|
|
|
16484
16807
|
// ../../packages/local-graph/src/credit.ts
|
|
16485
16808
|
init_src2();
|
|
@@ -16496,11 +16819,28 @@ init_src();
|
|
|
16496
16819
|
// ../../packages/local-graph/src/design-problem.ts
|
|
16497
16820
|
init_src();
|
|
16498
16821
|
init_src();
|
|
16499
|
-
init_src2();
|
|
16500
16822
|
|
|
16501
16823
|
// ../../packages/local-graph/src/problem-package-link.ts
|
|
16502
16824
|
init_src();
|
|
16503
16825
|
|
|
16826
|
+
// ../../packages/local-graph/src/design-problem.ts
|
|
16827
|
+
init_src2();
|
|
16828
|
+
|
|
16829
|
+
// ../../packages/local-graph/src/problem-dedup.ts
|
|
16830
|
+
init_src();
|
|
16831
|
+
init_src();
|
|
16832
|
+
|
|
16833
|
+
// ../../packages/local-graph/src/intent.ts
|
|
16834
|
+
init_src();
|
|
16835
|
+
|
|
16836
|
+
// ../../packages/local-graph/src/anchor-backfill.ts
|
|
16837
|
+
init_src();
|
|
16838
|
+
init_src2();
|
|
16839
|
+
var STATEMENT_PATH_RE = new RegExp(
|
|
16840
|
+
String.raw`(?:[\w.+-]+\/)+[\w.+-]+\.(?:${anchorableExtensionAlternation()})`,
|
|
16841
|
+
"g"
|
|
16842
|
+
);
|
|
16843
|
+
|
|
16504
16844
|
// ../../packages/local-graph/src/percolate.ts
|
|
16505
16845
|
init_src2();
|
|
16506
16846
|
var PERCOLATING_LABELS = ["Claim", "Problem", "Solution"];
|
|
@@ -16771,219 +17111,13 @@ function detectCommunitiesLeiden(input, opts = {}) {
|
|
|
16771
17111
|
return normalize(assignment);
|
|
16772
17112
|
}
|
|
16773
17113
|
|
|
16774
|
-
// ../../packages/local-graph/src/abstraction.ts
|
|
16775
|
-
var DEFAULT_MIN_CLUSTER_SIZE = 3;
|
|
16776
|
-
var DEFAULT_MIN_DISTINCT_CONTEXTS = 2;
|
|
16777
|
-
function sharedScope(l2, memberIds) {
|
|
16778
|
-
const shared = (field) => {
|
|
16779
|
-
const vals = /* @__PURE__ */ new Set();
|
|
16780
|
-
for (const id of memberIds) {
|
|
16781
|
-
const s = l2.getNode(id)?.attrs["scope"] ?? {};
|
|
16782
|
-
if (typeof s[field] === "string") vals.add(s[field]);
|
|
16783
|
-
}
|
|
16784
|
-
return vals.size === 1 ? [...vals][0] : void 0;
|
|
16785
|
-
};
|
|
16786
|
-
const lang = shared("lang");
|
|
16787
|
-
const versionRange = shared("versionRange");
|
|
16788
|
-
return { ...lang ? { lang } : {}, ...versionRange ? { versionRange } : {} };
|
|
16789
|
-
}
|
|
16790
|
-
function buildCandidate(id, ts, members, contexts, originMachine, scope) {
|
|
16791
|
-
return {
|
|
16792
|
-
id,
|
|
16793
|
-
label: "Claim",
|
|
16794
|
-
description: "",
|
|
16795
|
-
// empty — the harness distills the prose in P3
|
|
16796
|
-
extractionConfidence: 0.4,
|
|
16797
|
-
extractionSource: "agent-observed",
|
|
16798
|
-
embedding: [],
|
|
16799
|
-
cumulativeSurprise: 0,
|
|
16800
|
-
peakSurprise: 0,
|
|
16801
|
-
cumulativeHits: 1,
|
|
16802
|
-
lastUpdatedAt: ts,
|
|
16803
|
-
createdAt: ts,
|
|
16804
|
-
memoryTier: "short-term",
|
|
16805
|
-
pageRank: 0,
|
|
16806
|
-
isLandmark: false,
|
|
16807
|
-
community: null,
|
|
16808
|
-
stability: "unstable",
|
|
16809
|
-
attrs: {
|
|
16810
|
-
abstractionLevel: ABSTRACTION_LEVEL.PRINCIPLE,
|
|
16811
|
-
kind: "abstraction-candidate",
|
|
16812
|
-
provisional: true,
|
|
16813
|
-
pendingDistillation: true,
|
|
16814
|
-
// membership is the unit of truth — the harness validates its fence against
|
|
16815
|
-
// this set (P3 / C3) and may only phrase, never alter, it.
|
|
16816
|
-
members,
|
|
16817
|
-
memberContexts: contexts,
|
|
16818
|
-
distinctContexts: contexts.length,
|
|
16819
|
-
// standard Claim envelope so it crystallizes/syncs unchanged once distilled
|
|
16820
|
-
truthKind: "contextual",
|
|
16821
|
-
// Derived from members (P1): a single-language cluster becomes a lang-scoped
|
|
16822
|
-
// principle; a cross-language one stays universal (`{}`).
|
|
16823
|
-
scope,
|
|
16824
|
-
groundedSupport: 0,
|
|
16825
|
-
sources: [],
|
|
16826
|
-
crystallized: "hypothesis",
|
|
16827
|
-
confidence: 0.4,
|
|
16828
|
-
...originMachine ? { originMachine } : {}
|
|
16829
|
-
}
|
|
16830
|
-
};
|
|
16831
|
-
}
|
|
16832
|
-
function mergeGeneralizes(store, principleId, memberId, ts) {
|
|
16833
|
-
store.mergeEdge({
|
|
16834
|
-
id: `edge_${digest({ from: principleId, type: "GENERALIZES", to: memberId })}`.slice(0, 24),
|
|
16835
|
-
from: principleId,
|
|
16836
|
-
to: memberId,
|
|
16837
|
-
type: "GENERALIZES",
|
|
16838
|
-
confidence: 0.4,
|
|
16839
|
-
extractionSource: "agent-observed",
|
|
16840
|
-
createdAt: ts,
|
|
16841
|
-
lastSeenAt: ts,
|
|
16842
|
-
navSuccesses: 0,
|
|
16843
|
-
navFailures: 0,
|
|
16844
|
-
attrs: { provisional: true }
|
|
16845
|
-
});
|
|
16846
|
-
}
|
|
16847
|
-
function induceAbstractions(l2, opts) {
|
|
16848
|
-
const K = opts.minClusterSize ?? DEFAULT_MIN_CLUSTER_SIZE;
|
|
16849
|
-
const minCtx = opts.minDistinctContexts ?? DEFAULT_MIN_DISTINCT_CONTEXTS;
|
|
16850
|
-
const report = {
|
|
16851
|
-
communities: 0,
|
|
16852
|
-
candidatesMinted: 0,
|
|
16853
|
-
candidatesExisting: 0,
|
|
16854
|
-
skippedSmall: 0,
|
|
16855
|
-
skippedSingleContext: 0,
|
|
16856
|
-
generalizesEdges: 0
|
|
16857
|
-
};
|
|
16858
|
-
const ids = /* @__PURE__ */ new Set();
|
|
16859
|
-
for (const label of PERCOLATING_LABELS) {
|
|
16860
|
-
for (const n of l2.findNodesByLabel(label)) {
|
|
16861
|
-
if (Number(n.attrs["abstractionLevel"] ?? ABSTRACTION_LEVEL.CONCRETE) >= ABSTRACTION_LEVEL.PRINCIPLE) {
|
|
16862
|
-
continue;
|
|
16863
|
-
}
|
|
16864
|
-
if (n.attrs["resolvedAs"] === PROBLEM_RESOLUTION.FALSE_POSITIVE) continue;
|
|
16865
|
-
ids.add(n.id);
|
|
16866
|
-
}
|
|
16867
|
-
}
|
|
16868
|
-
if (ids.size === 0) return report;
|
|
16869
|
-
const adj = /* @__PURE__ */ new Map();
|
|
16870
|
-
const protect = [];
|
|
16871
|
-
const add = (a, b, w) => {
|
|
16872
|
-
const l = adj.get(a) ?? [];
|
|
16873
|
-
l.push({ to: b, weight: w });
|
|
16874
|
-
adj.set(a, l);
|
|
16875
|
-
};
|
|
16876
|
-
for (const id of ids) {
|
|
16877
|
-
for (const e of l2.outEdges(id, [...PERCOLATING_EDGES])) {
|
|
16878
|
-
if (!ids.has(e.to)) continue;
|
|
16879
|
-
const conf = e.confidence > 0 ? e.confidence : 0.5;
|
|
16880
|
-
const w = Math.max(EDGE_WEIGHT[e.type] ?? 1, 0.1) * conf;
|
|
16881
|
-
add(id, e.to, w);
|
|
16882
|
-
add(e.to, id, w);
|
|
16883
|
-
if (isCausalProtected(e.type)) protect.push([id, e.to]);
|
|
16884
|
-
}
|
|
16885
|
-
}
|
|
16886
|
-
const comm = detectCommunitiesLeiden({ nodeIds: [...ids], adj }, { protect });
|
|
16887
|
-
report.communities = comm.count;
|
|
16888
|
-
const members = /* @__PURE__ */ new Map();
|
|
16889
|
-
for (const [id, c] of comm.community) {
|
|
16890
|
-
const l = members.get(c) ?? [];
|
|
16891
|
-
l.push(id);
|
|
16892
|
-
members.set(c, l);
|
|
16893
|
-
}
|
|
16894
|
-
l2.transaction(() => {
|
|
16895
|
-
for (const mem of members.values()) {
|
|
16896
|
-
if (opts.touched && !mem.some((id) => opts.touched.has(id))) continue;
|
|
16897
|
-
if (mem.length < K) {
|
|
16898
|
-
report.skippedSmall++;
|
|
16899
|
-
continue;
|
|
16900
|
-
}
|
|
16901
|
-
if (mem.some((id) => l2.inEdges(id, ["GENERALIZES"]).length > 0)) {
|
|
16902
|
-
report.candidatesExisting++;
|
|
16903
|
-
continue;
|
|
16904
|
-
}
|
|
16905
|
-
const contexts = /* @__PURE__ */ new Set();
|
|
16906
|
-
for (const id of mem) {
|
|
16907
|
-
const n = l2.getNode(id);
|
|
16908
|
-
const obs = n?.attrs["observedInProjects"];
|
|
16909
|
-
if (Array.isArray(obs)) {
|
|
16910
|
-
for (const ws of obs) contexts.add(opts.contextOf(ws) ?? `project:${ws}`);
|
|
16911
|
-
}
|
|
16912
|
-
}
|
|
16913
|
-
if (contexts.size < minCtx) {
|
|
16914
|
-
report.skippedSingleContext++;
|
|
16915
|
-
continue;
|
|
16916
|
-
}
|
|
16917
|
-
const sorted = [...mem].sort();
|
|
16918
|
-
const principleId = `princ_${digest({ members: sorted })}`.slice(0, 56);
|
|
16919
|
-
l2.mergeNode(
|
|
16920
|
-
buildCandidate(principleId, opts.ts, sorted, [...contexts].sort(), opts.originMachine, sharedScope(l2, sorted))
|
|
16921
|
-
);
|
|
16922
|
-
for (const id of sorted) {
|
|
16923
|
-
mergeGeneralizes(l2, principleId, id, opts.ts);
|
|
16924
|
-
report.generalizesEdges++;
|
|
16925
|
-
}
|
|
16926
|
-
report.candidatesMinted++;
|
|
16927
|
-
}
|
|
16928
|
-
});
|
|
16929
|
-
return report;
|
|
16930
|
-
}
|
|
16931
|
-
function revisitContradictedPrinciples(l2, ts) {
|
|
16932
|
-
const report = { flagged: 0 };
|
|
16933
|
-
l2.transaction(() => {
|
|
16934
|
-
for (const n of l2.findNodesByLabel("Claim")) {
|
|
16935
|
-
if (Number(n.attrs["abstractionLevel"] ?? ABSTRACTION_LEVEL.CONCRETE) < ABSTRACTION_LEVEL.PRINCIPLE) continue;
|
|
16936
|
-
if (n.attrs["revisit"] === true) continue;
|
|
16937
|
-
const members = Array.isArray(n.attrs["members"]) ? n.attrs["members"] : [];
|
|
16938
|
-
const memberSet = new Set(members);
|
|
16939
|
-
let reason = "";
|
|
16940
|
-
for (const id of members) {
|
|
16941
|
-
const m = l2.getNode(id);
|
|
16942
|
-
if (!m) {
|
|
16943
|
-
reason = `member ${id} was removed`;
|
|
16944
|
-
break;
|
|
16945
|
-
}
|
|
16946
|
-
if (m.attrs["revisit"] === true) {
|
|
16947
|
-
reason = `member "${m.description}" needs revisit`;
|
|
16948
|
-
break;
|
|
16949
|
-
}
|
|
16950
|
-
const contradictors = [
|
|
16951
|
-
...l2.outEdges(id, ["CONTRADICTS"]).map((e) => e.to),
|
|
16952
|
-
...l2.inEdges(id, ["CONTRADICTS"]).map((e) => e.from)
|
|
16953
|
-
];
|
|
16954
|
-
if (contradictors.some((other) => !memberSet.has(other))) {
|
|
16955
|
-
reason = `member "${m.description}" is now contradicted by external evidence`;
|
|
16956
|
-
break;
|
|
16957
|
-
}
|
|
16958
|
-
}
|
|
16959
|
-
if (!reason) continue;
|
|
16960
|
-
l2.updateNode(n.id, {
|
|
16961
|
-
attrs: {
|
|
16962
|
-
...n.attrs,
|
|
16963
|
-
revisit: true,
|
|
16964
|
-
revisitReason: reason,
|
|
16965
|
-
revisitSinceTs: ts,
|
|
16966
|
-
provisional: true,
|
|
16967
|
-
// re-queue for re-distillation (P3 re-name)
|
|
16968
|
-
pendingDistillation: true
|
|
16969
|
-
},
|
|
16970
|
-
lastUpdatedAt: ts
|
|
16971
|
-
});
|
|
16972
|
-
report.flagged++;
|
|
16973
|
-
}
|
|
16974
|
-
});
|
|
16975
|
-
return report;
|
|
16976
|
-
}
|
|
16977
|
-
|
|
16978
|
-
// ../../packages/local-graph/src/community.ts
|
|
16979
|
-
init_src2();
|
|
16980
|
-
|
|
16981
17114
|
// ../../packages/local-graph/src/triage.ts
|
|
16982
17115
|
init_src();
|
|
16983
17116
|
init_src();
|
|
16984
17117
|
init_src();
|
|
16985
17118
|
init_src2();
|
|
16986
|
-
function semNode(id, label, description, ts, attrs) {
|
|
17119
|
+
function semNode(store, id, label, description, ts, attrs) {
|
|
17120
|
+
const seq = SEMANTIC_NODE_LABELS.includes(label) ? store.nextIngestSeq() : void 0;
|
|
16987
17121
|
return {
|
|
16988
17122
|
id,
|
|
16989
17123
|
label,
|
|
@@ -17001,6 +17135,7 @@ function semNode(id, label, description, ts, attrs) {
|
|
|
17001
17135
|
isLandmark: false,
|
|
17002
17136
|
community: null,
|
|
17003
17137
|
stability: "unstable",
|
|
17138
|
+
...seq !== void 0 ? { createdAtSeq: seq, lastReinforcedAtSeq: seq } : {},
|
|
17004
17139
|
attrs
|
|
17005
17140
|
};
|
|
17006
17141
|
}
|
|
@@ -17031,7 +17166,7 @@ function recordTriageObservation(l2, obs, ts) {
|
|
|
17031
17166
|
const buckets = [...triageContextBuckets(canonicalizeContext(obs.context)), TRIAGE_GLOBAL_BUCKET];
|
|
17032
17167
|
l2.transaction(() => {
|
|
17033
17168
|
if (!l2.getNode(presentingId)) {
|
|
17034
|
-
l2.mergeNode(semNode(presentingId, "Problem", statement, ts, { scope: {} }));
|
|
17169
|
+
l2.mergeNode(semNode(l2, presentingId, "Problem", statement, ts, { scope: {} }));
|
|
17035
17170
|
}
|
|
17036
17171
|
const tri = l2.getNode(triageId);
|
|
17037
17172
|
const seen = {
|
|
@@ -17045,7 +17180,7 @@ function recordTriageObservation(l2, obs, ts) {
|
|
|
17045
17180
|
});
|
|
17046
17181
|
} else {
|
|
17047
17182
|
l2.mergeNode(
|
|
17048
|
-
semNode(triageId, "Triage", `differential for: ${statement}`, ts, {
|
|
17183
|
+
semNode(l2, triageId, "Triage", `differential for: ${statement}`, ts, {
|
|
17049
17184
|
statement,
|
|
17050
17185
|
perContextSeen: seen
|
|
17051
17186
|
})
|
|
@@ -17057,7 +17192,7 @@ function recordTriageObservation(l2, obs, ts) {
|
|
|
17057
17192
|
}
|
|
17058
17193
|
if (!l2.getNode(obs.causeId)) {
|
|
17059
17194
|
l2.mergeNode(
|
|
17060
|
-
semNode(obs.causeId, obs.causeLabel ?? "RootCause", obs.causeDescription ?? "(cause)", ts, {
|
|
17195
|
+
semNode(l2, obs.causeId, obs.causeLabel ?? "RootCause", obs.causeDescription ?? "(cause)", ts, {
|
|
17061
17196
|
scope: {}
|
|
17062
17197
|
})
|
|
17063
17198
|
);
|
|
@@ -17230,9 +17365,212 @@ function revisitStaleRoutes(l2, ts, opts = {}) {
|
|
|
17230
17365
|
}
|
|
17231
17366
|
var DRIFT_VALUES = new Set(Object.values(DRIFT_KIND));
|
|
17232
17367
|
|
|
17233
|
-
// ../../packages/local-graph/src/
|
|
17234
|
-
|
|
17235
|
-
|
|
17368
|
+
// ../../packages/local-graph/src/abstraction.ts
|
|
17369
|
+
var DEFAULT_MIN_CLUSTER_SIZE = 3;
|
|
17370
|
+
var DEFAULT_MIN_DISTINCT_CONTEXTS = 2;
|
|
17371
|
+
function sharedScope(l2, memberIds) {
|
|
17372
|
+
const shared = (field) => {
|
|
17373
|
+
const vals = /* @__PURE__ */ new Set();
|
|
17374
|
+
for (const id of memberIds) {
|
|
17375
|
+
const s = l2.getNode(id)?.attrs["scope"] ?? {};
|
|
17376
|
+
if (typeof s[field] === "string") vals.add(s[field]);
|
|
17377
|
+
}
|
|
17378
|
+
return vals.size === 1 ? [...vals][0] : void 0;
|
|
17379
|
+
};
|
|
17380
|
+
const lang = shared("lang");
|
|
17381
|
+
const versionRange = shared("versionRange");
|
|
17382
|
+
return { ...lang ? { lang } : {}, ...versionRange ? { versionRange } : {} };
|
|
17383
|
+
}
|
|
17384
|
+
function buildCandidate(id, ts, members, contexts, originMachine, scope) {
|
|
17385
|
+
return {
|
|
17386
|
+
id,
|
|
17387
|
+
label: "Claim",
|
|
17388
|
+
description: "",
|
|
17389
|
+
// empty — the harness distills the prose in P3
|
|
17390
|
+
extractionConfidence: 0.4,
|
|
17391
|
+
extractionSource: "agent-observed",
|
|
17392
|
+
embedding: [],
|
|
17393
|
+
cumulativeSurprise: 0,
|
|
17394
|
+
peakSurprise: 0,
|
|
17395
|
+
cumulativeHits: 1,
|
|
17396
|
+
lastUpdatedAt: ts,
|
|
17397
|
+
createdAt: ts,
|
|
17398
|
+
memoryTier: "short-term",
|
|
17399
|
+
pageRank: 0,
|
|
17400
|
+
isLandmark: false,
|
|
17401
|
+
community: null,
|
|
17402
|
+
stability: "unstable",
|
|
17403
|
+
attrs: {
|
|
17404
|
+
abstractionLevel: ABSTRACTION_LEVEL.PRINCIPLE,
|
|
17405
|
+
kind: "abstraction-candidate",
|
|
17406
|
+
provisional: true,
|
|
17407
|
+
pendingDistillation: true,
|
|
17408
|
+
// membership is the unit of truth — the harness validates its fence against
|
|
17409
|
+
// this set (P3 / C3) and may only phrase, never alter, it.
|
|
17410
|
+
members,
|
|
17411
|
+
memberContexts: contexts,
|
|
17412
|
+
distinctContexts: contexts.length,
|
|
17413
|
+
// standard Claim envelope so it crystallizes/syncs unchanged once distilled
|
|
17414
|
+
truthKind: "contextual",
|
|
17415
|
+
// Derived from members (P1): a single-language cluster becomes a lang-scoped
|
|
17416
|
+
// principle; a cross-language one stays universal (`{}`).
|
|
17417
|
+
scope,
|
|
17418
|
+
groundedSupport: 0,
|
|
17419
|
+
sources: [],
|
|
17420
|
+
crystallized: "hypothesis",
|
|
17421
|
+
confidence: 0.4,
|
|
17422
|
+
...originMachine ? { originMachine } : {}
|
|
17423
|
+
}
|
|
17424
|
+
};
|
|
17425
|
+
}
|
|
17426
|
+
function mergeGeneralizes(store, principleId, memberId, ts) {
|
|
17427
|
+
store.mergeEdge({
|
|
17428
|
+
id: `edge_${digest({ from: principleId, type: "GENERALIZES", to: memberId })}`.slice(0, 24),
|
|
17429
|
+
from: principleId,
|
|
17430
|
+
to: memberId,
|
|
17431
|
+
type: "GENERALIZES",
|
|
17432
|
+
confidence: 0.4,
|
|
17433
|
+
extractionSource: "agent-observed",
|
|
17434
|
+
createdAt: ts,
|
|
17435
|
+
lastSeenAt: ts,
|
|
17436
|
+
navSuccesses: 0,
|
|
17437
|
+
navFailures: 0,
|
|
17438
|
+
attrs: { provisional: true }
|
|
17439
|
+
});
|
|
17440
|
+
}
|
|
17441
|
+
function induceAbstractions(l2, opts) {
|
|
17442
|
+
const K = opts.minClusterSize ?? DEFAULT_MIN_CLUSTER_SIZE;
|
|
17443
|
+
const minCtx = opts.minDistinctContexts ?? DEFAULT_MIN_DISTINCT_CONTEXTS;
|
|
17444
|
+
const report = {
|
|
17445
|
+
communities: 0,
|
|
17446
|
+
candidatesMinted: 0,
|
|
17447
|
+
candidatesExisting: 0,
|
|
17448
|
+
skippedSmall: 0,
|
|
17449
|
+
skippedSingleContext: 0,
|
|
17450
|
+
generalizesEdges: 0
|
|
17451
|
+
};
|
|
17452
|
+
const ids = /* @__PURE__ */ new Set();
|
|
17453
|
+
for (const label of PERCOLATING_LABELS) {
|
|
17454
|
+
for (const n of l2.findNodesByLabel(label)) {
|
|
17455
|
+
if (Number(n.attrs["abstractionLevel"] ?? ABSTRACTION_LEVEL.CONCRETE) >= ABSTRACTION_LEVEL.PRINCIPLE) {
|
|
17456
|
+
continue;
|
|
17457
|
+
}
|
|
17458
|
+
if (n.attrs["resolvedAs"] === PROBLEM_RESOLUTION.FALSE_POSITIVE) continue;
|
|
17459
|
+
ids.add(n.id);
|
|
17460
|
+
}
|
|
17461
|
+
}
|
|
17462
|
+
if (ids.size === 0) return report;
|
|
17463
|
+
const adj = /* @__PURE__ */ new Map();
|
|
17464
|
+
const protect = [];
|
|
17465
|
+
const add = (a, b, w) => {
|
|
17466
|
+
const l = adj.get(a) ?? [];
|
|
17467
|
+
l.push({ to: b, weight: w });
|
|
17468
|
+
adj.set(a, l);
|
|
17469
|
+
};
|
|
17470
|
+
for (const id of ids) {
|
|
17471
|
+
for (const e of l2.outEdges(id, [...PERCOLATING_EDGES])) {
|
|
17472
|
+
if (!ids.has(e.to)) continue;
|
|
17473
|
+
const conf = e.confidence > 0 ? e.confidence : 0.5;
|
|
17474
|
+
const w = Math.max(EDGE_WEIGHT[e.type] ?? 1, 0.1) * conf;
|
|
17475
|
+
add(id, e.to, w);
|
|
17476
|
+
add(e.to, id, w);
|
|
17477
|
+
if (isCausalProtected(e.type)) protect.push([id, e.to]);
|
|
17478
|
+
}
|
|
17479
|
+
}
|
|
17480
|
+
const comm = detectCommunitiesLeiden({ nodeIds: [...ids], adj }, { protect });
|
|
17481
|
+
report.communities = comm.count;
|
|
17482
|
+
const members = /* @__PURE__ */ new Map();
|
|
17483
|
+
for (const [id, c] of comm.community) {
|
|
17484
|
+
const l = members.get(c) ?? [];
|
|
17485
|
+
l.push(id);
|
|
17486
|
+
members.set(c, l);
|
|
17487
|
+
}
|
|
17488
|
+
l2.transaction(() => {
|
|
17489
|
+
for (const mem of members.values()) {
|
|
17490
|
+
if (opts.touched && !mem.some((id) => opts.touched.has(id))) continue;
|
|
17491
|
+
if (mem.length < K) {
|
|
17492
|
+
report.skippedSmall++;
|
|
17493
|
+
continue;
|
|
17494
|
+
}
|
|
17495
|
+
if (mem.some((id) => l2.inEdges(id, ["GENERALIZES"]).length > 0)) {
|
|
17496
|
+
report.candidatesExisting++;
|
|
17497
|
+
continue;
|
|
17498
|
+
}
|
|
17499
|
+
const contexts = /* @__PURE__ */ new Set();
|
|
17500
|
+
for (const id of mem) {
|
|
17501
|
+
const n = l2.getNode(id);
|
|
17502
|
+
const obs = n?.attrs["observedInProjects"];
|
|
17503
|
+
if (Array.isArray(obs)) {
|
|
17504
|
+
for (const ws of obs) contexts.add(opts.contextOf(ws) ?? `project:${ws}`);
|
|
17505
|
+
}
|
|
17506
|
+
}
|
|
17507
|
+
if (contexts.size < minCtx) {
|
|
17508
|
+
report.skippedSingleContext++;
|
|
17509
|
+
continue;
|
|
17510
|
+
}
|
|
17511
|
+
const sorted = [...mem].sort();
|
|
17512
|
+
const principleId = `princ_${digest({ members: sorted })}`.slice(0, 56);
|
|
17513
|
+
l2.mergeNode(
|
|
17514
|
+
buildCandidate(principleId, opts.ts, sorted, [...contexts].sort(), opts.originMachine, sharedScope(l2, sorted))
|
|
17515
|
+
);
|
|
17516
|
+
for (const id of sorted) {
|
|
17517
|
+
mergeGeneralizes(l2, principleId, id, opts.ts);
|
|
17518
|
+
report.generalizesEdges++;
|
|
17519
|
+
}
|
|
17520
|
+
report.candidatesMinted++;
|
|
17521
|
+
}
|
|
17522
|
+
});
|
|
17523
|
+
return report;
|
|
17524
|
+
}
|
|
17525
|
+
function revisitContradictedPrinciples(l2, ts) {
|
|
17526
|
+
const report = { flagged: 0 };
|
|
17527
|
+
l2.transaction(() => {
|
|
17528
|
+
for (const n of l2.findNodesByLabel("Claim")) {
|
|
17529
|
+
if (Number(n.attrs["abstractionLevel"] ?? ABSTRACTION_LEVEL.CONCRETE) < ABSTRACTION_LEVEL.PRINCIPLE) continue;
|
|
17530
|
+
if (n.attrs["revisit"] === true) continue;
|
|
17531
|
+
const members = Array.isArray(n.attrs["members"]) ? n.attrs["members"] : [];
|
|
17532
|
+
const memberSet = new Set(members);
|
|
17533
|
+
let reason = "";
|
|
17534
|
+
for (const id of members) {
|
|
17535
|
+
const m = l2.getNode(id);
|
|
17536
|
+
if (!m) {
|
|
17537
|
+
reason = `member ${id} was removed`;
|
|
17538
|
+
break;
|
|
17539
|
+
}
|
|
17540
|
+
if (m.attrs["revisit"] === true) {
|
|
17541
|
+
reason = `member "${m.description}" needs revisit`;
|
|
17542
|
+
break;
|
|
17543
|
+
}
|
|
17544
|
+
const contradictors = [
|
|
17545
|
+
...l2.outEdges(id, ["CONTRADICTS"]).map((e) => e.to),
|
|
17546
|
+
...l2.inEdges(id, ["CONTRADICTS"]).map((e) => e.from)
|
|
17547
|
+
];
|
|
17548
|
+
if (contradictors.some((other) => !memberSet.has(other))) {
|
|
17549
|
+
reason = `member "${m.description}" is now contradicted by external evidence`;
|
|
17550
|
+
break;
|
|
17551
|
+
}
|
|
17552
|
+
}
|
|
17553
|
+
if (!reason) continue;
|
|
17554
|
+
l2.updateNode(n.id, {
|
|
17555
|
+
attrs: {
|
|
17556
|
+
...n.attrs,
|
|
17557
|
+
revisit: true,
|
|
17558
|
+
revisitReason: reason,
|
|
17559
|
+
revisitSinceTs: ts,
|
|
17560
|
+
provisional: true,
|
|
17561
|
+
// re-queue for re-distillation (P3 re-name)
|
|
17562
|
+
pendingDistillation: true
|
|
17563
|
+
},
|
|
17564
|
+
lastUpdatedAt: ts
|
|
17565
|
+
});
|
|
17566
|
+
report.flagged++;
|
|
17567
|
+
}
|
|
17568
|
+
});
|
|
17569
|
+
return report;
|
|
17570
|
+
}
|
|
17571
|
+
|
|
17572
|
+
// ../../packages/local-graph/src/community.ts
|
|
17573
|
+
init_src2();
|
|
17236
17574
|
|
|
17237
17575
|
// ../../packages/local-graph/src/tools.ts
|
|
17238
17576
|
init_src();
|
|
@@ -17240,6 +17578,9 @@ init_src();
|
|
|
17240
17578
|
// ../../packages/local-graph/src/principle-sync.ts
|
|
17241
17579
|
init_src2();
|
|
17242
17580
|
|
|
17581
|
+
// ../../packages/local-graph/src/mechanism-liveness.ts
|
|
17582
|
+
var STALL_MIN_SPAN_MS = 60 * 60 * 1e3;
|
|
17583
|
+
|
|
17243
17584
|
// src/reconcile.ts
|
|
17244
17585
|
init_src3();
|
|
17245
17586
|
function isLive(n) {
|