@inerrata-corporation/errata 2.0.2-dev.174 → 2.0.2-dev.1757
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 +644 -285
- package/errata.mjs +10119 -2086
- package/package.json +1 -1
- package/pass-worker.mjs +1344 -295
package/consolidate-worker.mjs
CHANGED
|
@@ -201,7 +201,7 @@ var init_castalia = __esm({
|
|
|
201
201
|
DECOMPOSITION_EDGES = ["SPLIT_INTO"];
|
|
202
202
|
TRANSFER_EDGES = ["MAY_RESOLVE"];
|
|
203
203
|
SOLUTION_STRUCTURE_EDGES = ["BUILDS_ON", "SUPERSEDES", "ALTERNATIVE_TO"];
|
|
204
|
-
SUSPICION_EDGES = ["SUSPECTED_LINK"];
|
|
204
|
+
SUSPICION_EDGES = ["SUSPECTED_LINK", "REGRESSION_OF"];
|
|
205
205
|
TAXONOMY_EDGES = ["IS_A"];
|
|
206
206
|
TRIAGE_EDGES = ["TRIAGED_BY", "CONFIRMS", "INDICATES", "ROUTES_TO"];
|
|
207
207
|
GIT_EDGES = ["POINTS_AT", "PARENT", "AUTHORED_BY"];
|
|
@@ -336,6 +336,7 @@ var init_castalia = __esm({
|
|
|
336
336
|
ALTERNATIVE_TO: 0,
|
|
337
337
|
// Suspicion — a hypothesis, weightless + PageRank-excluded (never flows rank / EIG).
|
|
338
338
|
SUSPECTED_LINK: 0,
|
|
339
|
+
REGRESSION_OF: 0,
|
|
339
340
|
// Git — topology/authorship, weightless (not domain signal-flow)
|
|
340
341
|
POINTS_AT: 0,
|
|
341
342
|
PARENT: 0,
|
|
@@ -365,6 +366,13 @@ var init_castalia = __esm({
|
|
|
365
366
|
}
|
|
366
367
|
});
|
|
367
368
|
|
|
369
|
+
// ../../packages/shared/src/graph-events.ts
|
|
370
|
+
var init_graph_events = __esm({
|
|
371
|
+
"../../packages/shared/src/graph-events.ts"() {
|
|
372
|
+
"use strict";
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
368
376
|
// ../../packages/shared/src/canonical/hash.ts
|
|
369
377
|
import { createHash } from "node:crypto";
|
|
370
378
|
function sha256(input) {
|
|
@@ -673,7 +681,7 @@ function lemma(token) {
|
|
|
673
681
|
}
|
|
674
682
|
return token;
|
|
675
683
|
}
|
|
676
|
-
function
|
|
684
|
+
function tokenize(text, resolve) {
|
|
677
685
|
const matches = text.normalize("NFC").toLowerCase().match(TOKEN_RE) ?? [];
|
|
678
686
|
const out = /* @__PURE__ */ new Set();
|
|
679
687
|
for (const raw of matches) {
|
|
@@ -683,11 +691,14 @@ function conceptTokens(text) {
|
|
|
683
691
|
out.add(token);
|
|
684
692
|
continue;
|
|
685
693
|
}
|
|
686
|
-
const canonical =
|
|
694
|
+
const canonical = resolve(token);
|
|
687
695
|
out.add(canonical ?? lemma(token));
|
|
688
696
|
}
|
|
689
697
|
return [...out].sort();
|
|
690
698
|
}
|
|
699
|
+
function conceptTokens(text) {
|
|
700
|
+
return tokenize(text, resolveCanonicalId);
|
|
701
|
+
}
|
|
691
702
|
function conceptBag(text) {
|
|
692
703
|
return conceptTokens(text).join(" ");
|
|
693
704
|
}
|
|
@@ -15214,7 +15225,12 @@ var init_edge_rules = __esm({
|
|
|
15214
15225
|
// ── Taxonomy (Track 4 Stream C: MITRE CWE `ChildOf` → `Weakness —IS_A→ Weakness`) ──
|
|
15215
15226
|
IS_A: { from: ["Weakness"], to: ["Weakness"] },
|
|
15216
15227
|
// ── Conceptual (v1 taxonomy.ts: instance → motif/pattern reference) ──
|
|
15217
|
-
|
|
15228
|
+
// `AntiPattern` joined the target set 2026-08-02: it is one of the three motif
|
|
15229
|
+
// kinds (generalizer motifs.ts `layerOf`: pattern | technique | antipattern) and
|
|
15230
|
+
// the SUPPRESSED-close path mints `Problem ─INSTANCE_OF→ AntiPattern` as the
|
|
15231
|
+
// negative-knowledge binding ("silenced, not solved") — the original three-label
|
|
15232
|
+
// rule predates AntiPattern joining the motif layer and silently ate that edge.
|
|
15233
|
+
INSTANCE_OF: { to: ["Pattern", "AntiPattern", "Weakness", "Technique"] },
|
|
15218
15234
|
IMPLEMENTS: { from: ["Solution", "Language", "Component"], to: ["Pattern", "Technique"] },
|
|
15219
15235
|
MATCHES: { to: ["Pattern"] },
|
|
15220
15236
|
// ── Artifact evidence (v1 taxonomy.ts artifact rows) ──
|
|
@@ -15315,6 +15331,23 @@ var init_wire = __esm({
|
|
|
15315
15331
|
/** Canonical human-readable description (no raw paths — daemon scrubs; server rechecks). */
|
|
15316
15332
|
description: external_exports.string().min(1).max(4e3),
|
|
15317
15333
|
attrs: external_exports.record(external_exports.string(), external_exports.unknown()).default({}),
|
|
15334
|
+
/** One-way origin key of the SESSION that minted this node (`ws_…`, a
|
|
15335
|
+
* truncated digest — never the raw session id). Stamped onto the created
|
|
15336
|
+
* node as `authoringSession`, which is the independence unit for the
|
|
15337
|
+
* evidence channels: the session that authored a claim may not corroborate
|
|
15338
|
+
* or refute it, while a DIFFERENT session on the same checkout may (alyssa,
|
|
15339
|
+
* 2026-07-31 — the workspace key made every witness on a single-checkout
|
|
15340
|
+
* deployment a self-corroboration). Optional + additive: absent leaves the
|
|
15341
|
+
* gate fail-open for that node, exactly today's behaviour. */
|
|
15342
|
+
originSession: external_exports.string().min(3).max(64).optional(),
|
|
15343
|
+
/** Epoch ms of the ORIGINATING local node's creation — when the knowledge was
|
|
15344
|
+
* actually captured, as opposed to when its public twin reached the cloud.
|
|
15345
|
+
* Stored as `observedAt`; the network board's chronological view orders on
|
|
15346
|
+
* it. Without this the wire carried NO timestamp at all, so a node captured
|
|
15347
|
+
* days ago surfaced as "new" the moment it was generalized and published —
|
|
15348
|
+
* the board showed ingest order wearing a chronology's clothes. Optional +
|
|
15349
|
+
* additive: absent keeps ingest-time ordering for that node. */
|
|
15350
|
+
originCreatedAtMs: external_exports.number().int().positive().optional(),
|
|
15318
15351
|
extractionSource: external_exports.enum(INGEST_EXTRACTION_SOURCES),
|
|
15319
15352
|
validationSource: external_exports.enum(VALIDATION_SOURCES).optional(),
|
|
15320
15353
|
/** Org-membrane (M2): the daemon's anchor tag — it owns the lockfile, so it
|
|
@@ -15436,6 +15469,7 @@ var init_src = __esm({
|
|
|
15436
15469
|
"../../packages/shared/src/index.ts"() {
|
|
15437
15470
|
"use strict";
|
|
15438
15471
|
init_castalia();
|
|
15472
|
+
init_graph_events();
|
|
15439
15473
|
init_identity();
|
|
15440
15474
|
init_wire();
|
|
15441
15475
|
init_edge_rules();
|
|
@@ -15497,6 +15531,51 @@ var init_review = __esm({
|
|
|
15497
15531
|
}
|
|
15498
15532
|
});
|
|
15499
15533
|
|
|
15534
|
+
// ../../packages/local-shared/src/anchorable.ts
|
|
15535
|
+
function anchorableExtensionAlternation() {
|
|
15536
|
+
return BY_LENGTH.map((e) => e.slice(1).replace(/[+.]/g, (c) => `\\${c}`)).join("|");
|
|
15537
|
+
}
|
|
15538
|
+
var ANCHORABLE_EXTENSIONS, BY_LENGTH;
|
|
15539
|
+
var init_anchorable = __esm({
|
|
15540
|
+
"../../packages/local-shared/src/anchorable.ts"() {
|
|
15541
|
+
"use strict";
|
|
15542
|
+
ANCHORABLE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
15543
|
+
// typescript provider
|
|
15544
|
+
".ts",
|
|
15545
|
+
".tsx",
|
|
15546
|
+
".js",
|
|
15547
|
+
".jsx",
|
|
15548
|
+
".mjs",
|
|
15549
|
+
".cjs",
|
|
15550
|
+
// python / go / rust / ruby / csharp providers
|
|
15551
|
+
".py",
|
|
15552
|
+
".go",
|
|
15553
|
+
".rs",
|
|
15554
|
+
".rb",
|
|
15555
|
+
".cs",
|
|
15556
|
+
// cpp provider — every variant it parses, not just the three that were listed
|
|
15557
|
+
".c",
|
|
15558
|
+
".h",
|
|
15559
|
+
".cpp",
|
|
15560
|
+
".cc",
|
|
15561
|
+
".cxx",
|
|
15562
|
+
".c++",
|
|
15563
|
+
".hpp",
|
|
15564
|
+
".hh",
|
|
15565
|
+
".hxx",
|
|
15566
|
+
".h++",
|
|
15567
|
+
// CUDA — the cpp provider parses these too. Missed when this list was first
|
|
15568
|
+
// transcribed by hand; the parity test caught them on its very first run,
|
|
15569
|
+
// which is the argument for the test existing.
|
|
15570
|
+
".cu",
|
|
15571
|
+
".cuh",
|
|
15572
|
+
// no provider yet; the grammar ships. Inert, not wrong — see above.
|
|
15573
|
+
".java"
|
|
15574
|
+
]);
|
|
15575
|
+
BY_LENGTH = [...ANCHORABLE_EXTENSIONS].sort((a, b) => b.length - a.length);
|
|
15576
|
+
}
|
|
15577
|
+
});
|
|
15578
|
+
|
|
15500
15579
|
// ../../packages/local-shared/src/sqlite-adapter.ts
|
|
15501
15580
|
function openDatabase(path) {
|
|
15502
15581
|
const db = new DatabaseSync(path);
|
|
@@ -15509,6 +15588,7 @@ function openDatabase(path) {
|
|
|
15509
15588
|
db.exec("PRAGMA journal_mode = WAL");
|
|
15510
15589
|
db.exec("PRAGMA synchronous = NORMAL");
|
|
15511
15590
|
db.exec("PRAGMA busy_timeout = 5000");
|
|
15591
|
+
db.exec("PRAGMA journal_size_limit = 67108864");
|
|
15512
15592
|
} catch {
|
|
15513
15593
|
}
|
|
15514
15594
|
}
|
|
@@ -15544,7 +15624,7 @@ function openDatabase(path) {
|
|
|
15544
15624
|
return db.prepare(`PRAGMA ${key}`).get();
|
|
15545
15625
|
},
|
|
15546
15626
|
transaction(fn) {
|
|
15547
|
-
db.exec("BEGIN");
|
|
15627
|
+
db.exec("BEGIN IMMEDIATE");
|
|
15548
15628
|
try {
|
|
15549
15629
|
const r = fn();
|
|
15550
15630
|
db.exec("COMMIT");
|
|
@@ -15598,10 +15678,21 @@ var init_src2 = __esm({
|
|
|
15598
15678
|
init_profile();
|
|
15599
15679
|
init_daemon_wire();
|
|
15600
15680
|
init_review();
|
|
15681
|
+
init_anchorable();
|
|
15601
15682
|
init_sqlite_adapter();
|
|
15602
15683
|
}
|
|
15603
15684
|
});
|
|
15604
15685
|
|
|
15686
|
+
// ../../packages/indexer/src/parse-cache.ts
|
|
15687
|
+
var ENTRY_TTL_MS, MAX_ENTRY_BYTES;
|
|
15688
|
+
var init_parse_cache = __esm({
|
|
15689
|
+
"../../packages/indexer/src/parse-cache.ts"() {
|
|
15690
|
+
"use strict";
|
|
15691
|
+
ENTRY_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
15692
|
+
MAX_ENTRY_BYTES = 2 * 1024 * 1024;
|
|
15693
|
+
}
|
|
15694
|
+
});
|
|
15695
|
+
|
|
15605
15696
|
// ../../packages/indexer/src/simhash.ts
|
|
15606
15697
|
var MASK64;
|
|
15607
15698
|
var init_simhash = __esm({
|
|
@@ -15624,6 +15715,7 @@ var init_pipeline = __esm({
|
|
|
15624
15715
|
"../../packages/indexer/src/pipeline.ts"() {
|
|
15625
15716
|
"use strict";
|
|
15626
15717
|
init_src2();
|
|
15718
|
+
init_parse_cache();
|
|
15627
15719
|
init_identity2();
|
|
15628
15720
|
}
|
|
15629
15721
|
});
|
|
@@ -15763,9 +15855,38 @@ var LOCAL_RULE_OVERRIDES = {
|
|
|
15763
15855
|
to: [...CODE_NODE_LABELS, "Symbol"]
|
|
15764
15856
|
},
|
|
15765
15857
|
REVEALED_BY: null,
|
|
15766
|
-
PRODUCED: null
|
|
15858
|
+
PRODUCED: null,
|
|
15859
|
+
// FIXED_BY locally ALSO carries the fix-provenance sense: `resolveProblem`
|
|
15860
|
+
// attributes a closed Problem to the fixing `Episode` (PLAN_PLASTICITY §2.1)
|
|
15861
|
+
// alongside the cloud's Problem→Solution knowledge claim. Same shape as
|
|
15862
|
+
// PRODUCED/REVEALED_BY above — an Episode is code-layer and never drains, so
|
|
15863
|
+
// the cloud door's `to: [Solution]` rule is untouched. The `from` constraint
|
|
15864
|
+
// stays: the reversed (Solution)-FIXED_BY->(...) splash bug is the reason
|
|
15865
|
+
// this rule exists at all.
|
|
15866
|
+
FIXED_BY: { from: EDGE_RULES["FIXED_BY"]?.from, to: ["Solution", "Episode"] },
|
|
15867
|
+
// RG-recognize: a NEW open Problem re-observing a RESOLVED one ("this is
|
|
15868
|
+
// back — the fix didn't hold"). Local-only for now: the instance drain's
|
|
15869
|
+
// INSTANCE_EDGES allowlist doesn't ship it, and the cloud door's matrix
|
|
15870
|
+
// doesn't know it — crossing the membrane is a deliberate later step, never
|
|
15871
|
+
// a side effect (the half-shipped-edge-type lesson).
|
|
15872
|
+
REGRESSION_OF: { from: ["Problem"], to: ["Problem"] }
|
|
15767
15873
|
};
|
|
15768
|
-
|
|
15874
|
+
function localEdgeViolation(fromLabel, type, toLabel) {
|
|
15875
|
+
if (type in LOCAL_RULE_OVERRIDES) {
|
|
15876
|
+
const rule = LOCAL_RULE_OVERRIDES[type];
|
|
15877
|
+
if (!rule) return null;
|
|
15878
|
+
if (fromLabel && rule.from && !rule.from.includes(fromLabel)) {
|
|
15879
|
+
return `${type} cannot originate from ${fromLabel} locally (allowed: ${rule.from.join(", ")})`;
|
|
15880
|
+
}
|
|
15881
|
+
if (toLabel && rule.to && !rule.to.includes(toLabel)) {
|
|
15882
|
+
return `${type} cannot target ${toLabel} locally (allowed: ${rule.to.join(", ")})`;
|
|
15883
|
+
}
|
|
15884
|
+
return null;
|
|
15885
|
+
}
|
|
15886
|
+
const verdict = isValidEdge(fromLabel, type, toLabel);
|
|
15887
|
+
return verdict.ok ? null : verdict.reason ?? "edge rule violation";
|
|
15888
|
+
}
|
|
15889
|
+
var SCHEMA_VERSION = 6;
|
|
15769
15890
|
var SCHEMA_SQL = `
|
|
15770
15891
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
15771
15892
|
version INTEGER PRIMARY KEY
|
|
@@ -15780,6 +15901,21 @@ CREATE TABLE IF NOT EXISTS store_meta (
|
|
|
15780
15901
|
value TEXT NOT NULL
|
|
15781
15902
|
);
|
|
15782
15903
|
|
|
15904
|
+
-- Durable ledger of edges the ontology gate REFUSED, keyed by edge type.
|
|
15905
|
+
-- Durable rather than in-memory for one specific reason: the status command runs
|
|
15906
|
+
-- in a SEPARATE process and opens its own store handle, so a counter living on
|
|
15907
|
+
-- the instance reads 0 there forever. That is exactly how a producer rejecting
|
|
15908
|
+
-- 100% of its output stayed invisible for 17 days. Persisting it also survives
|
|
15909
|
+
-- the daemon restart that would otherwise erase the evidence.
|
|
15910
|
+
-- Keyed by type because a systematic producer bug shows up as ONE type
|
|
15911
|
+
-- dominating; sample keeps the latest reason so the count is actionable.
|
|
15912
|
+
CREATE TABLE IF NOT EXISTS edge_rejections (
|
|
15913
|
+
type TEXT PRIMARY KEY,
|
|
15914
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
15915
|
+
last_at INTEGER NOT NULL,
|
|
15916
|
+
sample TEXT
|
|
15917
|
+
);
|
|
15918
|
+
|
|
15783
15919
|
CREATE TABLE IF NOT EXISTS nodes (
|
|
15784
15920
|
id TEXT PRIMARY KEY,
|
|
15785
15921
|
label TEXT NOT NULL,
|
|
@@ -16156,6 +16292,16 @@ var SqliteGraphStore = class {
|
|
|
16156
16292
|
if (!cols.has(name)) this.db.exec(ddl);
|
|
16157
16293
|
}
|
|
16158
16294
|
}
|
|
16295
|
+
if (from < 6) {
|
|
16296
|
+
this.db.exec(`
|
|
16297
|
+
CREATE TABLE IF NOT EXISTS edge_rejections (
|
|
16298
|
+
type TEXT PRIMARY KEY,
|
|
16299
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
16300
|
+
last_at INTEGER NOT NULL,
|
|
16301
|
+
sample TEXT
|
|
16302
|
+
)
|
|
16303
|
+
`);
|
|
16304
|
+
}
|
|
16159
16305
|
this.db.prepare("UPDATE schema_version SET version = ?").run(SCHEMA_VERSION);
|
|
16160
16306
|
});
|
|
16161
16307
|
}
|
|
@@ -16237,6 +16383,7 @@ var SqliteGraphStore = class {
|
|
|
16237
16383
|
const violation = this.edgeRuleViolation(edge);
|
|
16238
16384
|
if (violation) {
|
|
16239
16385
|
this.rejectedEdgeCount++;
|
|
16386
|
+
this.recordEdgeRejection(edge.type, violation, edge.lastSeenAt || edge.createdAt || 0);
|
|
16240
16387
|
console.warn(`[local-graph] rejected edge ${edge.from}-[:${edge.type}]->${edge.to}: ${violation}`);
|
|
16241
16388
|
return;
|
|
16242
16389
|
}
|
|
@@ -16261,22 +16408,51 @@ var SqliteGraphStore = class {
|
|
|
16261
16408
|
* overlay consulted first. Returns the reason string on a documented-
|
|
16262
16409
|
* forbidden combination, else null. Point lookups on the id PK — negligible
|
|
16263
16410
|
* next to the insert itself. */
|
|
16264
|
-
|
|
16265
|
-
|
|
16266
|
-
|
|
16267
|
-
|
|
16268
|
-
|
|
16269
|
-
|
|
16270
|
-
|
|
16271
|
-
|
|
16272
|
-
|
|
16273
|
-
|
|
16274
|
-
|
|
16275
|
-
|
|
16276
|
-
|
|
16411
|
+
/** Upsert one refusal into the durable ledger. Best-effort: a bookkeeping
|
|
16412
|
+
* failure must never turn a refused edge into a thrown write. */
|
|
16413
|
+
recordEdgeRejection(type, reason, at) {
|
|
16414
|
+
try {
|
|
16415
|
+
this.db.prepare(
|
|
16416
|
+
`INSERT INTO edge_rejections (type, count, last_at, sample) VALUES (?, 1, ?, ?)
|
|
16417
|
+
ON CONFLICT(type) DO UPDATE SET
|
|
16418
|
+
count = count + 1, last_at = excluded.last_at, sample = excluded.sample`
|
|
16419
|
+
).run(type, at, reason.slice(0, 200));
|
|
16420
|
+
} catch {
|
|
16421
|
+
}
|
|
16422
|
+
}
|
|
16423
|
+
/** Refusals recorded by the ontology gate, per edge type, newest activity first.
|
|
16424
|
+
* Durable across restarts and readable from any process (see the table note). */
|
|
16425
|
+
edgeRejections() {
|
|
16426
|
+
try {
|
|
16427
|
+
return this.db.prepare(
|
|
16428
|
+
"SELECT type, count, last_at AS lastAt, sample FROM edge_rejections ORDER BY count DESC, last_at DESC"
|
|
16429
|
+
).all();
|
|
16430
|
+
} catch {
|
|
16431
|
+
return [];
|
|
16432
|
+
}
|
|
16433
|
+
}
|
|
16434
|
+
/** Drop ledger entries whose last refusal predates `cutoff`. A still-misbehaving
|
|
16435
|
+
* producer keeps refreshing `last_at` and survives; a fixed one fades out. */
|
|
16436
|
+
pruneEdgeRejections(cutoff) {
|
|
16437
|
+
try {
|
|
16438
|
+
this.db.prepare("DELETE FROM edge_rejections WHERE last_at < ?").run(cutoff);
|
|
16439
|
+
} catch {
|
|
16440
|
+
}
|
|
16441
|
+
}
|
|
16442
|
+
/** Clear the ledger outright, whole or per type — operator escape hatch. */
|
|
16443
|
+
clearEdgeRejections(type) {
|
|
16444
|
+
try {
|
|
16445
|
+
if (type) this.db.prepare("DELETE FROM edge_rejections WHERE type = ?").run(type);
|
|
16446
|
+
else this.db.exec("DELETE FROM edge_rejections");
|
|
16447
|
+
} catch {
|
|
16277
16448
|
}
|
|
16278
|
-
|
|
16279
|
-
|
|
16449
|
+
}
|
|
16450
|
+
edgeRuleViolation(edge) {
|
|
16451
|
+
return localEdgeViolation(
|
|
16452
|
+
this.getNode(edge.from)?.label,
|
|
16453
|
+
edge.type,
|
|
16454
|
+
this.getNode(edge.to)?.label
|
|
16455
|
+
);
|
|
16280
16456
|
}
|
|
16281
16457
|
updateEdge(id, patch) {
|
|
16282
16458
|
this.stmts.updateEdge.run({
|
|
@@ -16413,6 +16589,163 @@ var SqliteGraphStore = class {
|
|
|
16413
16589
|
const rows = this.db.prepare("SELECT from_id, to_id, type FROM edges WHERE valid_to IS NULL").all();
|
|
16414
16590
|
return rows.map((r) => ({ from: r.from_id, to: r.to_id, type: r.type }));
|
|
16415
16591
|
}
|
|
16592
|
+
getMeta(key) {
|
|
16593
|
+
const r = this.db.prepare("SELECT value FROM store_meta WHERE key = ?").get(key);
|
|
16594
|
+
return r?.value ?? null;
|
|
16595
|
+
}
|
|
16596
|
+
setMeta(key, value) {
|
|
16597
|
+
this.db.prepare(
|
|
16598
|
+
"INSERT INTO store_meta (key, value) VALUES (:key, :value) ON CONFLICT(key) DO UPDATE SET value = excluded.value"
|
|
16599
|
+
).run({ key, value });
|
|
16600
|
+
}
|
|
16601
|
+
dirtyNodeIdsSince(ts) {
|
|
16602
|
+
const rows = this.db.prepare("SELECT id FROM nodes WHERE valid_to IS NULL AND last_updated_at > ?").all(ts);
|
|
16603
|
+
return rows.map((r) => r.id);
|
|
16604
|
+
}
|
|
16605
|
+
/** Endpoints of edges TOUCHED since `ts` — created, re-seen, or CLOSED.
|
|
16606
|
+
* Closures matter as much as additions: a node that lost inflow is rank-dirty
|
|
16607
|
+
* while its own row never updated, so removal endpoints must seed the
|
|
16608
|
+
* incremental region or the stale inflow persists until the full backstop. */
|
|
16609
|
+
edgeEndpointsTouchedSince(ts) {
|
|
16610
|
+
const rows = this.db.prepare(
|
|
16611
|
+
`SELECT from_id, to_id FROM edges
|
|
16612
|
+
WHERE (valid_to IS NULL AND (created_at > :ts OR last_seen_at > :ts))
|
|
16613
|
+
OR (valid_to IS NOT NULL AND valid_to > :ts)`
|
|
16614
|
+
).all({ ts });
|
|
16615
|
+
return rows.map((r) => ({ from: r.from_id, to: r.to_id }));
|
|
16616
|
+
}
|
|
16617
|
+
/** Lightweight out-edges for a SET of sources, chunked IN-lists — the region
|
|
16618
|
+
* assembly path for incremental PageRank (per-node outEdges() at region
|
|
16619
|
+
* scale re-creates the 106k-prepared-calls problem the batch scan solved). */
|
|
16620
|
+
outEdgesForMany(ids) {
|
|
16621
|
+
return this.edgesForMany(ids, "from_id");
|
|
16622
|
+
}
|
|
16623
|
+
inEdgesForMany(ids) {
|
|
16624
|
+
return this.edgesForMany(ids, "to_id");
|
|
16625
|
+
}
|
|
16626
|
+
/** Stored pageRank for a SET of ids (live rows only — a closed id is simply
|
|
16627
|
+
* absent, which is how incremental region assembly drops dead endpoints). */
|
|
16628
|
+
ranksForMany(ids) {
|
|
16629
|
+
const out = /* @__PURE__ */ new Map();
|
|
16630
|
+
const CHUNK = 400;
|
|
16631
|
+
for (let i = 0; i < ids.length; i += CHUNK) {
|
|
16632
|
+
const chunk = ids.slice(i, i + CHUNK);
|
|
16633
|
+
const placeholders = chunk.map(() => "?").join(", ");
|
|
16634
|
+
const rows = this.db.prepare(
|
|
16635
|
+
`SELECT id, page_rank FROM nodes WHERE id IN (${placeholders}) AND valid_to IS NULL`
|
|
16636
|
+
).all(...chunk);
|
|
16637
|
+
for (const r of rows) out.set(r.id, r.page_rank);
|
|
16638
|
+
}
|
|
16639
|
+
return out;
|
|
16640
|
+
}
|
|
16641
|
+
/** The minimal row set the landmark sweep needs — landmark CANDIDATES
|
|
16642
|
+
* (Pattern/RootCause), everything currently flagged, and every
|
|
16643
|
+
* persistent-tier node (force-landmarks). A few thousand rows, so the
|
|
16644
|
+
* incremental path can refresh the GLOBAL landmark set without the 179k-row
|
|
16645
|
+
* scanLiveNodes materialization. */
|
|
16646
|
+
landmarkSweepRows() {
|
|
16647
|
+
const rows = this.db.prepare(
|
|
16648
|
+
`SELECT id, label, page_rank, is_landmark, memory_tier, extraction_source FROM nodes
|
|
16649
|
+
WHERE valid_to IS NULL
|
|
16650
|
+
AND (memory_tier = 'persistent' OR is_landmark = 1 OR label IN ('Pattern', 'RootCause'))`
|
|
16651
|
+
).all();
|
|
16652
|
+
return rows.map((r) => ({
|
|
16653
|
+
id: r.id,
|
|
16654
|
+
label: r.label,
|
|
16655
|
+
pageRank: r.page_rank,
|
|
16656
|
+
isLandmark: r.is_landmark === 1,
|
|
16657
|
+
memoryTier: r.memory_tier,
|
|
16658
|
+
extractionSource: r.extraction_source
|
|
16659
|
+
}));
|
|
16660
|
+
}
|
|
16661
|
+
edgesForMany(ids, col) {
|
|
16662
|
+
const out = [];
|
|
16663
|
+
const CHUNK = 400;
|
|
16664
|
+
for (let i = 0; i < ids.length; i += CHUNK) {
|
|
16665
|
+
const chunk = ids.slice(i, i + CHUNK);
|
|
16666
|
+
const placeholders = chunk.map(() => "?").join(", ");
|
|
16667
|
+
const rows = this.db.prepare(
|
|
16668
|
+
`SELECT from_id, to_id, type FROM edges WHERE ${col} IN (${placeholders}) AND valid_to IS NULL`
|
|
16669
|
+
).all(...chunk);
|
|
16670
|
+
for (const r of rows) out.push({ from: r.from_id, to: r.to_id, type: r.type });
|
|
16671
|
+
}
|
|
16672
|
+
return out;
|
|
16673
|
+
}
|
|
16674
|
+
checkpointWal() {
|
|
16675
|
+
try {
|
|
16676
|
+
const r = this.db.prepare("PRAGMA wal_checkpoint(TRUNCATE)").get();
|
|
16677
|
+
return r ?? null;
|
|
16678
|
+
} catch {
|
|
16679
|
+
return null;
|
|
16680
|
+
}
|
|
16681
|
+
}
|
|
16682
|
+
reviveReobserved(relPaths, workspaceId, since) {
|
|
16683
|
+
let revived = 0;
|
|
16684
|
+
const CHUNK = 400;
|
|
16685
|
+
for (let i = 0; i < relPaths.length; i += CHUNK) {
|
|
16686
|
+
const slice = relPaths.slice(i, i + CHUNK);
|
|
16687
|
+
if (slice.length === 0) continue;
|
|
16688
|
+
const r = this.db.prepare(
|
|
16689
|
+
`UPDATE nodes SET valid_to = NULL
|
|
16690
|
+
WHERE valid_to IS NOT NULL
|
|
16691
|
+
AND last_updated_at >= ?
|
|
16692
|
+
AND json_extract(attrs_json, '$.workspaceId') = ?
|
|
16693
|
+
AND json_extract(attrs_json, '$.relPath') IN (${slice.map(() => "?").join(",")})`
|
|
16694
|
+
).run(since, workspaceId, ...slice);
|
|
16695
|
+
revived += Number(r.changes);
|
|
16696
|
+
}
|
|
16697
|
+
if (revived > 0) this.mutations++;
|
|
16698
|
+
return revived;
|
|
16699
|
+
}
|
|
16700
|
+
recentEdgeAttrCoverage(marker, attr, limit) {
|
|
16701
|
+
const r = this.db.prepare(
|
|
16702
|
+
`SELECT COUNT(*) AS total,
|
|
16703
|
+
COALESCE(SUM(CASE WHEN json_extract(attrs_json, '$.' || ?) = 1 THEN 1 ELSE 0 END), 0) AS count
|
|
16704
|
+
FROM (SELECT attrs_json FROM edges
|
|
16705
|
+
WHERE valid_to IS NULL AND attrs_json LIKE ?
|
|
16706
|
+
ORDER BY created_at DESC LIMIT ?)`
|
|
16707
|
+
).get(attr, `%${marker}%`, limit);
|
|
16708
|
+
return { count: Number(r.count), total: Number(r.total) };
|
|
16709
|
+
}
|
|
16710
|
+
liveNodeIds(ids) {
|
|
16711
|
+
const live = /* @__PURE__ */ new Set();
|
|
16712
|
+
const CHUNK = 900;
|
|
16713
|
+
for (let i = 0; i < ids.length; i += CHUNK) {
|
|
16714
|
+
const slice = ids.slice(i, i + CHUNK);
|
|
16715
|
+
if (slice.length === 0) continue;
|
|
16716
|
+
const rows = this.db.prepare(
|
|
16717
|
+
`SELECT id FROM nodes WHERE valid_to IS NULL AND id IN (${slice.map(() => "?").join(",")})`
|
|
16718
|
+
).all(...slice);
|
|
16719
|
+
for (const r of rows) live.add(r.id);
|
|
16720
|
+
}
|
|
16721
|
+
return live;
|
|
16722
|
+
}
|
|
16723
|
+
/**
|
|
16724
|
+
* Live edges WITH their endpoint labels and ids, resolved in ONE join.
|
|
16725
|
+
*
|
|
16726
|
+
* The ontology sweep needs (id, type, fromLabel, toLabel) for every live edge.
|
|
16727
|
+
* Doing that as `scanLiveEdges()` + two `getNode()` calls is 2N node reads —
|
|
16728
|
+
* 550,000 on this store — and each one deserializes the node's embedding blob.
|
|
16729
|
+
* Measured: the sweep did not finish in 10 minutes. As a single join it is one
|
|
16730
|
+
* query over an index-covered scan. Labels only; nothing here touches embeddings.
|
|
16731
|
+
*/
|
|
16732
|
+
scanLiveEdgeRows() {
|
|
16733
|
+
const rows = this.db.prepare(
|
|
16734
|
+
`SELECT e.id, e.from_id, e.to_id, e.type, a.label AS from_label, b.label AS to_label
|
|
16735
|
+
FROM edges e
|
|
16736
|
+
LEFT JOIN nodes a ON a.id = e.from_id AND a.valid_to IS NULL
|
|
16737
|
+
LEFT JOIN nodes b ON b.id = e.to_id AND b.valid_to IS NULL
|
|
16738
|
+
WHERE e.valid_to IS NULL`
|
|
16739
|
+
).all();
|
|
16740
|
+
return rows.map((r) => ({
|
|
16741
|
+
id: r.id,
|
|
16742
|
+
from: r.from_id,
|
|
16743
|
+
to: r.to_id,
|
|
16744
|
+
type: r.type,
|
|
16745
|
+
fromLabel: r.from_label ?? void 0,
|
|
16746
|
+
toLabel: r.to_label ?? void 0
|
|
16747
|
+
}));
|
|
16748
|
+
}
|
|
16416
16749
|
/** Live nodes whose attrs.relPath is one of `relPaths`. Uses the nodes_relpath
|
|
16417
16750
|
* expression index so the incremental reindex fetches only the changed files'
|
|
16418
16751
|
* symbols instead of scanning every versioned node. */
|
|
@@ -16433,6 +16766,10 @@ var SqliteGraphStore = class {
|
|
|
16433
16766
|
if (!live) return null;
|
|
16434
16767
|
const version2 = live.version ?? 1;
|
|
16435
16768
|
const frozenId = `${liveId}@v${version2}`;
|
|
16769
|
+
if (this.getNode(frozenId)) {
|
|
16770
|
+
this.stmts.advanceLive.run({ live_id: liveId, t });
|
|
16771
|
+
return frozenId;
|
|
16772
|
+
}
|
|
16436
16773
|
this.stmts.freezeCopy.run({ frozen_id: frozenId, live_id: liveId, t });
|
|
16437
16774
|
this.mergeEdge({
|
|
16438
16775
|
id: `edge_superseded_${frozenId}`,
|
|
@@ -16491,6 +16828,7 @@ var CAUSAL_FAMILY = [
|
|
|
16491
16828
|
|
|
16492
16829
|
// ../../packages/local-graph/src/justification.ts
|
|
16493
16830
|
init_src();
|
|
16831
|
+
init_src2();
|
|
16494
16832
|
|
|
16495
16833
|
// ../../packages/local-graph/src/credit.ts
|
|
16496
16834
|
init_src2();
|
|
@@ -16507,11 +16845,31 @@ init_src();
|
|
|
16507
16845
|
// ../../packages/local-graph/src/design-problem.ts
|
|
16508
16846
|
init_src();
|
|
16509
16847
|
init_src();
|
|
16510
|
-
init_src2();
|
|
16511
16848
|
|
|
16512
16849
|
// ../../packages/local-graph/src/problem-package-link.ts
|
|
16513
16850
|
init_src();
|
|
16514
16851
|
|
|
16852
|
+
// ../../packages/local-graph/src/design-problem.ts
|
|
16853
|
+
init_src2();
|
|
16854
|
+
|
|
16855
|
+
// ../../packages/local-graph/src/problem-dedup.ts
|
|
16856
|
+
init_src();
|
|
16857
|
+
init_src();
|
|
16858
|
+
|
|
16859
|
+
// ../../packages/local-graph/src/design-problem.ts
|
|
16860
|
+
var RECURRENCE_DEBOUNCE_MS = 60 * 60 * 1e3;
|
|
16861
|
+
|
|
16862
|
+
// ../../packages/local-graph/src/intent.ts
|
|
16863
|
+
init_src();
|
|
16864
|
+
|
|
16865
|
+
// ../../packages/local-graph/src/anchor-backfill.ts
|
|
16866
|
+
init_src();
|
|
16867
|
+
init_src2();
|
|
16868
|
+
var STATEMENT_PATH_RE = new RegExp(
|
|
16869
|
+
String.raw`(?:[\w.+-]+\/)+[\w.+-]+\.(?:${anchorableExtensionAlternation()})`,
|
|
16870
|
+
"g"
|
|
16871
|
+
);
|
|
16872
|
+
|
|
16515
16873
|
// ../../packages/local-graph/src/percolate.ts
|
|
16516
16874
|
init_src2();
|
|
16517
16875
|
var PERCOLATING_LABELS = ["Claim", "Problem", "Solution"];
|
|
@@ -16782,30 +17140,19 @@ function detectCommunitiesLeiden(input, opts = {}) {
|
|
|
16782
17140
|
return normalize(assignment);
|
|
16783
17141
|
}
|
|
16784
17142
|
|
|
16785
|
-
// ../../packages/local-graph/src/
|
|
16786
|
-
|
|
16787
|
-
|
|
16788
|
-
|
|
16789
|
-
|
|
16790
|
-
|
|
16791
|
-
|
|
16792
|
-
const s = l2.getNode(id)?.attrs["scope"] ?? {};
|
|
16793
|
-
if (typeof s[field] === "string") vals.add(s[field]);
|
|
16794
|
-
}
|
|
16795
|
-
return vals.size === 1 ? [...vals][0] : void 0;
|
|
16796
|
-
};
|
|
16797
|
-
const lang = shared("lang");
|
|
16798
|
-
const versionRange = shared("versionRange");
|
|
16799
|
-
return { ...lang ? { lang } : {}, ...versionRange ? { versionRange } : {} };
|
|
16800
|
-
}
|
|
16801
|
-
function buildCandidate(id, ts, members, contexts, originMachine, scope) {
|
|
17143
|
+
// ../../packages/local-graph/src/triage.ts
|
|
17144
|
+
init_src();
|
|
17145
|
+
init_src();
|
|
17146
|
+
init_src();
|
|
17147
|
+
init_src2();
|
|
17148
|
+
function semNode(store, id, label, description, ts, attrs) {
|
|
17149
|
+
const seq = SEMANTIC_NODE_LABELS.includes(label) ? store.nextIngestSeq() : void 0;
|
|
16802
17150
|
return {
|
|
16803
17151
|
id,
|
|
16804
|
-
label
|
|
16805
|
-
description
|
|
16806
|
-
|
|
16807
|
-
|
|
16808
|
-
extractionSource: "agent-observed",
|
|
17152
|
+
label,
|
|
17153
|
+
description,
|
|
17154
|
+
extractionConfidence: 0.5,
|
|
17155
|
+
extractionSource: "daemon-extracted",
|
|
16809
17156
|
embedding: [],
|
|
16810
17157
|
cumulativeSurprise: 0,
|
|
16811
17158
|
peakSurprise: 0,
|
|
@@ -16817,250 +17164,56 @@ function buildCandidate(id, ts, members, contexts, originMachine, scope) {
|
|
|
16817
17164
|
isLandmark: false,
|
|
16818
17165
|
community: null,
|
|
16819
17166
|
stability: "unstable",
|
|
16820
|
-
|
|
16821
|
-
|
|
16822
|
-
kind: "abstraction-candidate",
|
|
16823
|
-
provisional: true,
|
|
16824
|
-
pendingDistillation: true,
|
|
16825
|
-
// membership is the unit of truth — the harness validates its fence against
|
|
16826
|
-
// this set (P3 / C3) and may only phrase, never alter, it.
|
|
16827
|
-
members,
|
|
16828
|
-
memberContexts: contexts,
|
|
16829
|
-
distinctContexts: contexts.length,
|
|
16830
|
-
// standard Claim envelope so it crystallizes/syncs unchanged once distilled
|
|
16831
|
-
truthKind: "contextual",
|
|
16832
|
-
// Derived from members (P1): a single-language cluster becomes a lang-scoped
|
|
16833
|
-
// principle; a cross-language one stays universal (`{}`).
|
|
16834
|
-
scope,
|
|
16835
|
-
groundedSupport: 0,
|
|
16836
|
-
sources: [],
|
|
16837
|
-
crystallized: "hypothesis",
|
|
16838
|
-
confidence: 0.4,
|
|
16839
|
-
...originMachine ? { originMachine } : {}
|
|
16840
|
-
}
|
|
17167
|
+
...seq !== void 0 ? { createdAtSeq: seq, lastReinforcedAtSeq: seq } : {},
|
|
17168
|
+
attrs
|
|
16841
17169
|
};
|
|
16842
17170
|
}
|
|
16843
|
-
function
|
|
16844
|
-
|
|
16845
|
-
id
|
|
16846
|
-
from
|
|
16847
|
-
to
|
|
16848
|
-
type
|
|
16849
|
-
confidence: 0.
|
|
16850
|
-
extractionSource: "
|
|
17171
|
+
function semEdge(id, from, to, type, ts, attrs) {
|
|
17172
|
+
return {
|
|
17173
|
+
id,
|
|
17174
|
+
from,
|
|
17175
|
+
to,
|
|
17176
|
+
type,
|
|
17177
|
+
confidence: 0.5,
|
|
17178
|
+
extractionSource: "daemon-extracted",
|
|
16851
17179
|
createdAt: ts,
|
|
16852
17180
|
lastSeenAt: ts,
|
|
16853
17181
|
navSuccesses: 0,
|
|
16854
17182
|
navFailures: 0,
|
|
16855
|
-
attrs
|
|
16856
|
-
});
|
|
16857
|
-
}
|
|
16858
|
-
function induceAbstractions(l2, opts) {
|
|
16859
|
-
const K = opts.minClusterSize ?? DEFAULT_MIN_CLUSTER_SIZE;
|
|
16860
|
-
const minCtx = opts.minDistinctContexts ?? DEFAULT_MIN_DISTINCT_CONTEXTS;
|
|
16861
|
-
const report = {
|
|
16862
|
-
communities: 0,
|
|
16863
|
-
candidatesMinted: 0,
|
|
16864
|
-
candidatesExisting: 0,
|
|
16865
|
-
skippedSmall: 0,
|
|
16866
|
-
skippedSingleContext: 0,
|
|
16867
|
-
generalizesEdges: 0
|
|
17183
|
+
attrs
|
|
16868
17184
|
};
|
|
16869
|
-
|
|
16870
|
-
|
|
16871
|
-
|
|
16872
|
-
|
|
16873
|
-
|
|
16874
|
-
|
|
16875
|
-
|
|
16876
|
-
|
|
17185
|
+
}
|
|
17186
|
+
var routeEdgeId = (triageId, causeId) => `edge_rt_${triageId}_${causeId}`;
|
|
17187
|
+
var ROUTE_EDGE_TYPES = ["CONFIRMS", "INDICATES", "ROUTES_TO"];
|
|
17188
|
+
var routeTypeFor = (provisional) => provisional ? "INDICATES" : "CONFIRMS";
|
|
17189
|
+
var isRouterRoute = (e) => e.type === "CONFIRMS" || e.type === "ROUTES_TO" && e.attrs["provisional"] === false;
|
|
17190
|
+
function recordTriageObservation(l2, obs, ts) {
|
|
17191
|
+
const statement = obs.presentingStatement.trim();
|
|
17192
|
+
const presentingId = obs.presentingId?.trim() || identityId({ kind: "DesignProblem", statement });
|
|
17193
|
+
const triageId = identityId({ kind: "Triage", statement });
|
|
17194
|
+
const routeId = routeEdgeId(triageId, obs.causeId);
|
|
17195
|
+
const buckets = [...triageContextBuckets(canonicalizeContext(obs.context)), TRIAGE_GLOBAL_BUCKET];
|
|
17196
|
+
l2.transaction(() => {
|
|
17197
|
+
if (!l2.getNode(presentingId)) {
|
|
17198
|
+
l2.mergeNode(semNode(l2, presentingId, "Problem", statement, ts, { scope: {} }));
|
|
16877
17199
|
}
|
|
16878
|
-
|
|
16879
|
-
|
|
16880
|
-
|
|
16881
|
-
|
|
16882
|
-
|
|
16883
|
-
|
|
16884
|
-
|
|
16885
|
-
|
|
16886
|
-
|
|
16887
|
-
|
|
16888
|
-
|
|
16889
|
-
|
|
16890
|
-
|
|
16891
|
-
|
|
16892
|
-
|
|
16893
|
-
|
|
16894
|
-
|
|
16895
|
-
}
|
|
16896
|
-
}
|
|
16897
|
-
const comm = detectCommunitiesLeiden({ nodeIds: [...ids], adj }, { protect });
|
|
16898
|
-
report.communities = comm.count;
|
|
16899
|
-
const members = /* @__PURE__ */ new Map();
|
|
16900
|
-
for (const [id, c] of comm.community) {
|
|
16901
|
-
const l = members.get(c) ?? [];
|
|
16902
|
-
l.push(id);
|
|
16903
|
-
members.set(c, l);
|
|
16904
|
-
}
|
|
16905
|
-
l2.transaction(() => {
|
|
16906
|
-
for (const mem of members.values()) {
|
|
16907
|
-
if (opts.touched && !mem.some((id) => opts.touched.has(id))) continue;
|
|
16908
|
-
if (mem.length < K) {
|
|
16909
|
-
report.skippedSmall++;
|
|
16910
|
-
continue;
|
|
16911
|
-
}
|
|
16912
|
-
if (mem.some((id) => l2.inEdges(id, ["GENERALIZES"]).length > 0)) {
|
|
16913
|
-
report.candidatesExisting++;
|
|
16914
|
-
continue;
|
|
16915
|
-
}
|
|
16916
|
-
const contexts = /* @__PURE__ */ new Set();
|
|
16917
|
-
for (const id of mem) {
|
|
16918
|
-
const n = l2.getNode(id);
|
|
16919
|
-
const obs = n?.attrs["observedInProjects"];
|
|
16920
|
-
if (Array.isArray(obs)) {
|
|
16921
|
-
for (const ws of obs) contexts.add(opts.contextOf(ws) ?? `project:${ws}`);
|
|
16922
|
-
}
|
|
16923
|
-
}
|
|
16924
|
-
if (contexts.size < minCtx) {
|
|
16925
|
-
report.skippedSingleContext++;
|
|
16926
|
-
continue;
|
|
16927
|
-
}
|
|
16928
|
-
const sorted = [...mem].sort();
|
|
16929
|
-
const principleId = `princ_${digest({ members: sorted })}`.slice(0, 56);
|
|
16930
|
-
l2.mergeNode(
|
|
16931
|
-
buildCandidate(principleId, opts.ts, sorted, [...contexts].sort(), opts.originMachine, sharedScope(l2, sorted))
|
|
16932
|
-
);
|
|
16933
|
-
for (const id of sorted) {
|
|
16934
|
-
mergeGeneralizes(l2, principleId, id, opts.ts);
|
|
16935
|
-
report.generalizesEdges++;
|
|
16936
|
-
}
|
|
16937
|
-
report.candidatesMinted++;
|
|
16938
|
-
}
|
|
16939
|
-
});
|
|
16940
|
-
return report;
|
|
16941
|
-
}
|
|
16942
|
-
function revisitContradictedPrinciples(l2, ts) {
|
|
16943
|
-
const report = { flagged: 0 };
|
|
16944
|
-
l2.transaction(() => {
|
|
16945
|
-
for (const n of l2.findNodesByLabel("Claim")) {
|
|
16946
|
-
if (Number(n.attrs["abstractionLevel"] ?? ABSTRACTION_LEVEL.CONCRETE) < ABSTRACTION_LEVEL.PRINCIPLE) continue;
|
|
16947
|
-
if (n.attrs["revisit"] === true) continue;
|
|
16948
|
-
const members = Array.isArray(n.attrs["members"]) ? n.attrs["members"] : [];
|
|
16949
|
-
const memberSet = new Set(members);
|
|
16950
|
-
let reason = "";
|
|
16951
|
-
for (const id of members) {
|
|
16952
|
-
const m = l2.getNode(id);
|
|
16953
|
-
if (!m) {
|
|
16954
|
-
reason = `member ${id} was removed`;
|
|
16955
|
-
break;
|
|
16956
|
-
}
|
|
16957
|
-
if (m.attrs["revisit"] === true) {
|
|
16958
|
-
reason = `member "${m.description}" needs revisit`;
|
|
16959
|
-
break;
|
|
16960
|
-
}
|
|
16961
|
-
const contradictors = [
|
|
16962
|
-
...l2.outEdges(id, ["CONTRADICTS"]).map((e) => e.to),
|
|
16963
|
-
...l2.inEdges(id, ["CONTRADICTS"]).map((e) => e.from)
|
|
16964
|
-
];
|
|
16965
|
-
if (contradictors.some((other) => !memberSet.has(other))) {
|
|
16966
|
-
reason = `member "${m.description}" is now contradicted by external evidence`;
|
|
16967
|
-
break;
|
|
16968
|
-
}
|
|
16969
|
-
}
|
|
16970
|
-
if (!reason) continue;
|
|
16971
|
-
l2.updateNode(n.id, {
|
|
16972
|
-
attrs: {
|
|
16973
|
-
...n.attrs,
|
|
16974
|
-
revisit: true,
|
|
16975
|
-
revisitReason: reason,
|
|
16976
|
-
revisitSinceTs: ts,
|
|
16977
|
-
provisional: true,
|
|
16978
|
-
// re-queue for re-distillation (P3 re-name)
|
|
16979
|
-
pendingDistillation: true
|
|
16980
|
-
},
|
|
16981
|
-
lastUpdatedAt: ts
|
|
16982
|
-
});
|
|
16983
|
-
report.flagged++;
|
|
16984
|
-
}
|
|
16985
|
-
});
|
|
16986
|
-
return report;
|
|
16987
|
-
}
|
|
16988
|
-
|
|
16989
|
-
// ../../packages/local-graph/src/community.ts
|
|
16990
|
-
init_src2();
|
|
16991
|
-
|
|
16992
|
-
// ../../packages/local-graph/src/triage.ts
|
|
16993
|
-
init_src();
|
|
16994
|
-
init_src();
|
|
16995
|
-
init_src();
|
|
16996
|
-
init_src2();
|
|
16997
|
-
function semNode(id, label, description, ts, attrs) {
|
|
16998
|
-
return {
|
|
16999
|
-
id,
|
|
17000
|
-
label,
|
|
17001
|
-
description,
|
|
17002
|
-
extractionConfidence: 0.5,
|
|
17003
|
-
extractionSource: "daemon-extracted",
|
|
17004
|
-
embedding: [],
|
|
17005
|
-
cumulativeSurprise: 0,
|
|
17006
|
-
peakSurprise: 0,
|
|
17007
|
-
cumulativeHits: 1,
|
|
17008
|
-
lastUpdatedAt: ts,
|
|
17009
|
-
createdAt: ts,
|
|
17010
|
-
memoryTier: "short-term",
|
|
17011
|
-
pageRank: 0,
|
|
17012
|
-
isLandmark: false,
|
|
17013
|
-
community: null,
|
|
17014
|
-
stability: "unstable",
|
|
17015
|
-
attrs
|
|
17016
|
-
};
|
|
17017
|
-
}
|
|
17018
|
-
function semEdge(id, from, to, type, ts, attrs) {
|
|
17019
|
-
return {
|
|
17020
|
-
id,
|
|
17021
|
-
from,
|
|
17022
|
-
to,
|
|
17023
|
-
type,
|
|
17024
|
-
confidence: 0.5,
|
|
17025
|
-
extractionSource: "daemon-extracted",
|
|
17026
|
-
createdAt: ts,
|
|
17027
|
-
lastSeenAt: ts,
|
|
17028
|
-
navSuccesses: 0,
|
|
17029
|
-
navFailures: 0,
|
|
17030
|
-
attrs
|
|
17031
|
-
};
|
|
17032
|
-
}
|
|
17033
|
-
var routeEdgeId = (triageId, causeId) => `edge_rt_${triageId}_${causeId}`;
|
|
17034
|
-
var ROUTE_EDGE_TYPES = ["CONFIRMS", "INDICATES", "ROUTES_TO"];
|
|
17035
|
-
var routeTypeFor = (provisional) => provisional ? "INDICATES" : "CONFIRMS";
|
|
17036
|
-
var isRouterRoute = (e) => e.type === "CONFIRMS" || e.type === "ROUTES_TO" && e.attrs["provisional"] === false;
|
|
17037
|
-
function recordTriageObservation(l2, obs, ts) {
|
|
17038
|
-
const statement = obs.presentingStatement.trim();
|
|
17039
|
-
const presentingId = obs.presentingId?.trim() || identityId({ kind: "DesignProblem", statement });
|
|
17040
|
-
const triageId = identityId({ kind: "Triage", statement });
|
|
17041
|
-
const routeId = routeEdgeId(triageId, obs.causeId);
|
|
17042
|
-
const buckets = [...triageContextBuckets(canonicalizeContext(obs.context)), TRIAGE_GLOBAL_BUCKET];
|
|
17043
|
-
l2.transaction(() => {
|
|
17044
|
-
if (!l2.getNode(presentingId)) {
|
|
17045
|
-
l2.mergeNode(semNode(presentingId, "Problem", statement, ts, { scope: {} }));
|
|
17046
|
-
}
|
|
17047
|
-
const tri = l2.getNode(triageId);
|
|
17048
|
-
const seen = {
|
|
17049
|
-
...tri?.attrs["perContextSeen"] ?? {}
|
|
17050
|
-
};
|
|
17051
|
-
for (const b of buckets) seen[b] = (seen[b] ?? 0) + 1;
|
|
17052
|
-
if (tri) {
|
|
17053
|
-
l2.updateNode(triageId, {
|
|
17054
|
-
attrs: { ...tri.attrs, statement, perContextSeen: seen },
|
|
17055
|
-
lastUpdatedAt: ts
|
|
17056
|
-
});
|
|
17057
|
-
} else {
|
|
17058
|
-
l2.mergeNode(
|
|
17059
|
-
semNode(triageId, "Triage", `differential for: ${statement}`, ts, {
|
|
17060
|
-
statement,
|
|
17061
|
-
perContextSeen: seen
|
|
17062
|
-
})
|
|
17063
|
-
);
|
|
17200
|
+
const tri = l2.getNode(triageId);
|
|
17201
|
+
const seen = {
|
|
17202
|
+
...tri?.attrs["perContextSeen"] ?? {}
|
|
17203
|
+
};
|
|
17204
|
+
for (const b of buckets) seen[b] = (seen[b] ?? 0) + 1;
|
|
17205
|
+
if (tri) {
|
|
17206
|
+
l2.updateNode(triageId, {
|
|
17207
|
+
attrs: { ...tri.attrs, statement, perContextSeen: seen },
|
|
17208
|
+
lastUpdatedAt: ts
|
|
17209
|
+
});
|
|
17210
|
+
} else {
|
|
17211
|
+
l2.mergeNode(
|
|
17212
|
+
semNode(l2, triageId, "Triage", `differential for: ${statement}`, ts, {
|
|
17213
|
+
statement,
|
|
17214
|
+
perContextSeen: seen
|
|
17215
|
+
})
|
|
17216
|
+
);
|
|
17064
17217
|
}
|
|
17065
17218
|
const tbId = `edge_tb_${presentingId}_${triageId}`;
|
|
17066
17219
|
if (!l2.getEdge(tbId)) {
|
|
@@ -17068,7 +17221,7 @@ function recordTriageObservation(l2, obs, ts) {
|
|
|
17068
17221
|
}
|
|
17069
17222
|
if (!l2.getNode(obs.causeId)) {
|
|
17070
17223
|
l2.mergeNode(
|
|
17071
|
-
semNode(obs.causeId, obs.causeLabel ?? "RootCause", obs.causeDescription ?? "(cause)", ts, {
|
|
17224
|
+
semNode(l2, obs.causeId, obs.causeLabel ?? "RootCause", obs.causeDescription ?? "(cause)", ts, {
|
|
17072
17225
|
scope: {}
|
|
17073
17226
|
})
|
|
17074
17227
|
);
|
|
@@ -17241,9 +17394,212 @@ function revisitStaleRoutes(l2, ts, opts = {}) {
|
|
|
17241
17394
|
}
|
|
17242
17395
|
var DRIFT_VALUES = new Set(Object.values(DRIFT_KIND));
|
|
17243
17396
|
|
|
17244
|
-
// ../../packages/local-graph/src/
|
|
17245
|
-
|
|
17246
|
-
|
|
17397
|
+
// ../../packages/local-graph/src/abstraction.ts
|
|
17398
|
+
var DEFAULT_MIN_CLUSTER_SIZE = 3;
|
|
17399
|
+
var DEFAULT_MIN_DISTINCT_CONTEXTS = 2;
|
|
17400
|
+
function sharedScope(l2, memberIds) {
|
|
17401
|
+
const shared = (field) => {
|
|
17402
|
+
const vals = /* @__PURE__ */ new Set();
|
|
17403
|
+
for (const id of memberIds) {
|
|
17404
|
+
const s = l2.getNode(id)?.attrs["scope"] ?? {};
|
|
17405
|
+
if (typeof s[field] === "string") vals.add(s[field]);
|
|
17406
|
+
}
|
|
17407
|
+
return vals.size === 1 ? [...vals][0] : void 0;
|
|
17408
|
+
};
|
|
17409
|
+
const lang = shared("lang");
|
|
17410
|
+
const versionRange = shared("versionRange");
|
|
17411
|
+
return { ...lang ? { lang } : {}, ...versionRange ? { versionRange } : {} };
|
|
17412
|
+
}
|
|
17413
|
+
function buildCandidate(id, ts, members, contexts, originMachine, scope) {
|
|
17414
|
+
return {
|
|
17415
|
+
id,
|
|
17416
|
+
label: "Claim",
|
|
17417
|
+
description: "",
|
|
17418
|
+
// empty — the harness distills the prose in P3
|
|
17419
|
+
extractionConfidence: 0.4,
|
|
17420
|
+
extractionSource: "agent-observed",
|
|
17421
|
+
embedding: [],
|
|
17422
|
+
cumulativeSurprise: 0,
|
|
17423
|
+
peakSurprise: 0,
|
|
17424
|
+
cumulativeHits: 1,
|
|
17425
|
+
lastUpdatedAt: ts,
|
|
17426
|
+
createdAt: ts,
|
|
17427
|
+
memoryTier: "short-term",
|
|
17428
|
+
pageRank: 0,
|
|
17429
|
+
isLandmark: false,
|
|
17430
|
+
community: null,
|
|
17431
|
+
stability: "unstable",
|
|
17432
|
+
attrs: {
|
|
17433
|
+
abstractionLevel: ABSTRACTION_LEVEL.PRINCIPLE,
|
|
17434
|
+
kind: "abstraction-candidate",
|
|
17435
|
+
provisional: true,
|
|
17436
|
+
pendingDistillation: true,
|
|
17437
|
+
// membership is the unit of truth — the harness validates its fence against
|
|
17438
|
+
// this set (P3 / C3) and may only phrase, never alter, it.
|
|
17439
|
+
members,
|
|
17440
|
+
memberContexts: contexts,
|
|
17441
|
+
distinctContexts: contexts.length,
|
|
17442
|
+
// standard Claim envelope so it crystallizes/syncs unchanged once distilled
|
|
17443
|
+
truthKind: "contextual",
|
|
17444
|
+
// Derived from members (P1): a single-language cluster becomes a lang-scoped
|
|
17445
|
+
// principle; a cross-language one stays universal (`{}`).
|
|
17446
|
+
scope,
|
|
17447
|
+
groundedSupport: 0,
|
|
17448
|
+
sources: [],
|
|
17449
|
+
crystallized: "hypothesis",
|
|
17450
|
+
confidence: 0.4,
|
|
17451
|
+
...originMachine ? { originMachine } : {}
|
|
17452
|
+
}
|
|
17453
|
+
};
|
|
17454
|
+
}
|
|
17455
|
+
function mergeGeneralizes(store, principleId, memberId, ts) {
|
|
17456
|
+
store.mergeEdge({
|
|
17457
|
+
id: `edge_${digest({ from: principleId, type: "GENERALIZES", to: memberId })}`.slice(0, 24),
|
|
17458
|
+
from: principleId,
|
|
17459
|
+
to: memberId,
|
|
17460
|
+
type: "GENERALIZES",
|
|
17461
|
+
confidence: 0.4,
|
|
17462
|
+
extractionSource: "agent-observed",
|
|
17463
|
+
createdAt: ts,
|
|
17464
|
+
lastSeenAt: ts,
|
|
17465
|
+
navSuccesses: 0,
|
|
17466
|
+
navFailures: 0,
|
|
17467
|
+
attrs: { provisional: true }
|
|
17468
|
+
});
|
|
17469
|
+
}
|
|
17470
|
+
function induceAbstractions(l2, opts) {
|
|
17471
|
+
const K = opts.minClusterSize ?? DEFAULT_MIN_CLUSTER_SIZE;
|
|
17472
|
+
const minCtx = opts.minDistinctContexts ?? DEFAULT_MIN_DISTINCT_CONTEXTS;
|
|
17473
|
+
const report = {
|
|
17474
|
+
communities: 0,
|
|
17475
|
+
candidatesMinted: 0,
|
|
17476
|
+
candidatesExisting: 0,
|
|
17477
|
+
skippedSmall: 0,
|
|
17478
|
+
skippedSingleContext: 0,
|
|
17479
|
+
generalizesEdges: 0
|
|
17480
|
+
};
|
|
17481
|
+
const ids = /* @__PURE__ */ new Set();
|
|
17482
|
+
for (const label of PERCOLATING_LABELS) {
|
|
17483
|
+
for (const n of l2.findNodesByLabel(label)) {
|
|
17484
|
+
if (Number(n.attrs["abstractionLevel"] ?? ABSTRACTION_LEVEL.CONCRETE) >= ABSTRACTION_LEVEL.PRINCIPLE) {
|
|
17485
|
+
continue;
|
|
17486
|
+
}
|
|
17487
|
+
if (n.attrs["resolvedAs"] === PROBLEM_RESOLUTION.FALSE_POSITIVE) continue;
|
|
17488
|
+
ids.add(n.id);
|
|
17489
|
+
}
|
|
17490
|
+
}
|
|
17491
|
+
if (ids.size === 0) return report;
|
|
17492
|
+
const adj = /* @__PURE__ */ new Map();
|
|
17493
|
+
const protect = [];
|
|
17494
|
+
const add = (a, b, w) => {
|
|
17495
|
+
const l = adj.get(a) ?? [];
|
|
17496
|
+
l.push({ to: b, weight: w });
|
|
17497
|
+
adj.set(a, l);
|
|
17498
|
+
};
|
|
17499
|
+
for (const id of ids) {
|
|
17500
|
+
for (const e of l2.outEdges(id, [...PERCOLATING_EDGES])) {
|
|
17501
|
+
if (!ids.has(e.to)) continue;
|
|
17502
|
+
const conf = e.confidence > 0 ? e.confidence : 0.5;
|
|
17503
|
+
const w = Math.max(EDGE_WEIGHT[e.type] ?? 1, 0.1) * conf;
|
|
17504
|
+
add(id, e.to, w);
|
|
17505
|
+
add(e.to, id, w);
|
|
17506
|
+
if (isCausalProtected(e.type)) protect.push([id, e.to]);
|
|
17507
|
+
}
|
|
17508
|
+
}
|
|
17509
|
+
const comm = detectCommunitiesLeiden({ nodeIds: [...ids], adj }, { protect });
|
|
17510
|
+
report.communities = comm.count;
|
|
17511
|
+
const members = /* @__PURE__ */ new Map();
|
|
17512
|
+
for (const [id, c] of comm.community) {
|
|
17513
|
+
const l = members.get(c) ?? [];
|
|
17514
|
+
l.push(id);
|
|
17515
|
+
members.set(c, l);
|
|
17516
|
+
}
|
|
17517
|
+
l2.transaction(() => {
|
|
17518
|
+
for (const mem of members.values()) {
|
|
17519
|
+
if (opts.touched && !mem.some((id) => opts.touched.has(id))) continue;
|
|
17520
|
+
if (mem.length < K) {
|
|
17521
|
+
report.skippedSmall++;
|
|
17522
|
+
continue;
|
|
17523
|
+
}
|
|
17524
|
+
if (mem.some((id) => l2.inEdges(id, ["GENERALIZES"]).length > 0)) {
|
|
17525
|
+
report.candidatesExisting++;
|
|
17526
|
+
continue;
|
|
17527
|
+
}
|
|
17528
|
+
const contexts = /* @__PURE__ */ new Set();
|
|
17529
|
+
for (const id of mem) {
|
|
17530
|
+
const n = l2.getNode(id);
|
|
17531
|
+
const obs = n?.attrs["observedInProjects"];
|
|
17532
|
+
if (Array.isArray(obs)) {
|
|
17533
|
+
for (const ws of obs) contexts.add(opts.contextOf(ws) ?? `project:${ws}`);
|
|
17534
|
+
}
|
|
17535
|
+
}
|
|
17536
|
+
if (contexts.size < minCtx) {
|
|
17537
|
+
report.skippedSingleContext++;
|
|
17538
|
+
continue;
|
|
17539
|
+
}
|
|
17540
|
+
const sorted = [...mem].sort();
|
|
17541
|
+
const principleId = `princ_${digest({ members: sorted })}`.slice(0, 56);
|
|
17542
|
+
l2.mergeNode(
|
|
17543
|
+
buildCandidate(principleId, opts.ts, sorted, [...contexts].sort(), opts.originMachine, sharedScope(l2, sorted))
|
|
17544
|
+
);
|
|
17545
|
+
for (const id of sorted) {
|
|
17546
|
+
mergeGeneralizes(l2, principleId, id, opts.ts);
|
|
17547
|
+
report.generalizesEdges++;
|
|
17548
|
+
}
|
|
17549
|
+
report.candidatesMinted++;
|
|
17550
|
+
}
|
|
17551
|
+
});
|
|
17552
|
+
return report;
|
|
17553
|
+
}
|
|
17554
|
+
function revisitContradictedPrinciples(l2, ts) {
|
|
17555
|
+
const report = { flagged: 0 };
|
|
17556
|
+
l2.transaction(() => {
|
|
17557
|
+
for (const n of l2.findNodesByLabel("Claim")) {
|
|
17558
|
+
if (Number(n.attrs["abstractionLevel"] ?? ABSTRACTION_LEVEL.CONCRETE) < ABSTRACTION_LEVEL.PRINCIPLE) continue;
|
|
17559
|
+
if (n.attrs["revisit"] === true) continue;
|
|
17560
|
+
const members = Array.isArray(n.attrs["members"]) ? n.attrs["members"] : [];
|
|
17561
|
+
const memberSet = new Set(members);
|
|
17562
|
+
let reason = "";
|
|
17563
|
+
for (const id of members) {
|
|
17564
|
+
const m = l2.getNode(id);
|
|
17565
|
+
if (!m) {
|
|
17566
|
+
reason = `member ${id} was removed`;
|
|
17567
|
+
break;
|
|
17568
|
+
}
|
|
17569
|
+
if (m.attrs["revisit"] === true) {
|
|
17570
|
+
reason = `member "${m.description}" needs revisit`;
|
|
17571
|
+
break;
|
|
17572
|
+
}
|
|
17573
|
+
const contradictors = [
|
|
17574
|
+
...l2.outEdges(id, ["CONTRADICTS"]).map((e) => e.to),
|
|
17575
|
+
...l2.inEdges(id, ["CONTRADICTS"]).map((e) => e.from)
|
|
17576
|
+
];
|
|
17577
|
+
if (contradictors.some((other) => !memberSet.has(other))) {
|
|
17578
|
+
reason = `member "${m.description}" is now contradicted by external evidence`;
|
|
17579
|
+
break;
|
|
17580
|
+
}
|
|
17581
|
+
}
|
|
17582
|
+
if (!reason) continue;
|
|
17583
|
+
l2.updateNode(n.id, {
|
|
17584
|
+
attrs: {
|
|
17585
|
+
...n.attrs,
|
|
17586
|
+
revisit: true,
|
|
17587
|
+
revisitReason: reason,
|
|
17588
|
+
revisitSinceTs: ts,
|
|
17589
|
+
provisional: true,
|
|
17590
|
+
// re-queue for re-distillation (P3 re-name)
|
|
17591
|
+
pendingDistillation: true
|
|
17592
|
+
},
|
|
17593
|
+
lastUpdatedAt: ts
|
|
17594
|
+
});
|
|
17595
|
+
report.flagged++;
|
|
17596
|
+
}
|
|
17597
|
+
});
|
|
17598
|
+
return report;
|
|
17599
|
+
}
|
|
17600
|
+
|
|
17601
|
+
// ../../packages/local-graph/src/community.ts
|
|
17602
|
+
init_src2();
|
|
17247
17603
|
|
|
17248
17604
|
// ../../packages/local-graph/src/tools.ts
|
|
17249
17605
|
init_src();
|
|
@@ -17251,6 +17607,9 @@ init_src();
|
|
|
17251
17607
|
// ../../packages/local-graph/src/principle-sync.ts
|
|
17252
17608
|
init_src2();
|
|
17253
17609
|
|
|
17610
|
+
// ../../packages/local-graph/src/mechanism-liveness.ts
|
|
17611
|
+
var STALL_MIN_SPAN_MS = 60 * 60 * 1e3;
|
|
17612
|
+
|
|
17254
17613
|
// src/reconcile.ts
|
|
17255
17614
|
init_src3();
|
|
17256
17615
|
function isLive(n) {
|