@inerrata-corporation/errata 2.0.2-dev.245 → 2.0.2-dev.249
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 +112 -16
- package/errata.mjs +402 -231
- package/package.json +1 -1
- package/pass-worker.mjs +112 -16
package/consolidate-worker.mjs
CHANGED
|
@@ -15774,7 +15774,22 @@ var LOCAL_RULE_OVERRIDES = {
|
|
|
15774
15774
|
REVEALED_BY: null,
|
|
15775
15775
|
PRODUCED: null
|
|
15776
15776
|
};
|
|
15777
|
-
|
|
15777
|
+
function localEdgeViolation(fromLabel, type, toLabel) {
|
|
15778
|
+
if (type in LOCAL_RULE_OVERRIDES) {
|
|
15779
|
+
const rule = LOCAL_RULE_OVERRIDES[type];
|
|
15780
|
+
if (!rule) return null;
|
|
15781
|
+
if (fromLabel && rule.from && !rule.from.includes(fromLabel)) {
|
|
15782
|
+
return `${type} cannot originate from ${fromLabel} locally (allowed: ${rule.from.join(", ")})`;
|
|
15783
|
+
}
|
|
15784
|
+
if (toLabel && rule.to && !rule.to.includes(toLabel)) {
|
|
15785
|
+
return `${type} cannot target ${toLabel} locally (allowed: ${rule.to.join(", ")})`;
|
|
15786
|
+
}
|
|
15787
|
+
return null;
|
|
15788
|
+
}
|
|
15789
|
+
const verdict = isValidEdge(fromLabel, type, toLabel);
|
|
15790
|
+
return verdict.ok ? null : verdict.reason ?? "edge rule violation";
|
|
15791
|
+
}
|
|
15792
|
+
var SCHEMA_VERSION = 6;
|
|
15778
15793
|
var SCHEMA_SQL = `
|
|
15779
15794
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
15780
15795
|
version INTEGER PRIMARY KEY
|
|
@@ -15789,6 +15804,21 @@ CREATE TABLE IF NOT EXISTS store_meta (
|
|
|
15789
15804
|
value TEXT NOT NULL
|
|
15790
15805
|
);
|
|
15791
15806
|
|
|
15807
|
+
-- Durable ledger of edges the ontology gate REFUSED, keyed by edge type.
|
|
15808
|
+
-- Durable rather than in-memory for one specific reason: the status command runs
|
|
15809
|
+
-- in a SEPARATE process and opens its own store handle, so a counter living on
|
|
15810
|
+
-- the instance reads 0 there forever. That is exactly how a producer rejecting
|
|
15811
|
+
-- 100% of its output stayed invisible for 17 days. Persisting it also survives
|
|
15812
|
+
-- the daemon restart that would otherwise erase the evidence.
|
|
15813
|
+
-- Keyed by type because a systematic producer bug shows up as ONE type
|
|
15814
|
+
-- dominating; sample keeps the latest reason so the count is actionable.
|
|
15815
|
+
CREATE TABLE IF NOT EXISTS edge_rejections (
|
|
15816
|
+
type TEXT PRIMARY KEY,
|
|
15817
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
15818
|
+
last_at INTEGER NOT NULL,
|
|
15819
|
+
sample TEXT
|
|
15820
|
+
);
|
|
15821
|
+
|
|
15792
15822
|
CREATE TABLE IF NOT EXISTS nodes (
|
|
15793
15823
|
id TEXT PRIMARY KEY,
|
|
15794
15824
|
label TEXT NOT NULL,
|
|
@@ -16165,6 +16195,16 @@ var SqliteGraphStore = class {
|
|
|
16165
16195
|
if (!cols.has(name)) this.db.exec(ddl);
|
|
16166
16196
|
}
|
|
16167
16197
|
}
|
|
16198
|
+
if (from < 6) {
|
|
16199
|
+
this.db.exec(`
|
|
16200
|
+
CREATE TABLE IF NOT EXISTS edge_rejections (
|
|
16201
|
+
type TEXT PRIMARY KEY,
|
|
16202
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
16203
|
+
last_at INTEGER NOT NULL,
|
|
16204
|
+
sample TEXT
|
|
16205
|
+
)
|
|
16206
|
+
`);
|
|
16207
|
+
}
|
|
16168
16208
|
this.db.prepare("UPDATE schema_version SET version = ?").run(SCHEMA_VERSION);
|
|
16169
16209
|
});
|
|
16170
16210
|
}
|
|
@@ -16246,6 +16286,7 @@ var SqliteGraphStore = class {
|
|
|
16246
16286
|
const violation = this.edgeRuleViolation(edge);
|
|
16247
16287
|
if (violation) {
|
|
16248
16288
|
this.rejectedEdgeCount++;
|
|
16289
|
+
this.recordEdgeRejection(edge.type, violation, edge.lastSeenAt || edge.createdAt || 0);
|
|
16249
16290
|
console.warn(`[local-graph] rejected edge ${edge.from}-[:${edge.type}]->${edge.to}: ${violation}`);
|
|
16250
16291
|
return;
|
|
16251
16292
|
}
|
|
@@ -16270,22 +16311,51 @@ var SqliteGraphStore = class {
|
|
|
16270
16311
|
* overlay consulted first. Returns the reason string on a documented-
|
|
16271
16312
|
* forbidden combination, else null. Point lookups on the id PK — negligible
|
|
16272
16313
|
* next to the insert itself. */
|
|
16273
|
-
|
|
16274
|
-
|
|
16275
|
-
|
|
16276
|
-
|
|
16277
|
-
|
|
16278
|
-
|
|
16279
|
-
|
|
16280
|
-
|
|
16281
|
-
|
|
16282
|
-
|
|
16283
|
-
|
|
16284
|
-
|
|
16285
|
-
|
|
16314
|
+
/** Upsert one refusal into the durable ledger. Best-effort: a bookkeeping
|
|
16315
|
+
* failure must never turn a refused edge into a thrown write. */
|
|
16316
|
+
recordEdgeRejection(type, reason, at) {
|
|
16317
|
+
try {
|
|
16318
|
+
this.db.prepare(
|
|
16319
|
+
`INSERT INTO edge_rejections (type, count, last_at, sample) VALUES (?, 1, ?, ?)
|
|
16320
|
+
ON CONFLICT(type) DO UPDATE SET
|
|
16321
|
+
count = count + 1, last_at = excluded.last_at, sample = excluded.sample`
|
|
16322
|
+
).run(type, at, reason.slice(0, 200));
|
|
16323
|
+
} catch {
|
|
16324
|
+
}
|
|
16325
|
+
}
|
|
16326
|
+
/** Refusals recorded by the ontology gate, per edge type, newest activity first.
|
|
16327
|
+
* Durable across restarts and readable from any process (see the table note). */
|
|
16328
|
+
edgeRejections() {
|
|
16329
|
+
try {
|
|
16330
|
+
return this.db.prepare(
|
|
16331
|
+
"SELECT type, count, last_at AS lastAt, sample FROM edge_rejections ORDER BY count DESC, last_at DESC"
|
|
16332
|
+
).all();
|
|
16333
|
+
} catch {
|
|
16334
|
+
return [];
|
|
16335
|
+
}
|
|
16336
|
+
}
|
|
16337
|
+
/** Drop ledger entries whose last refusal predates `cutoff`. A still-misbehaving
|
|
16338
|
+
* producer keeps refreshing `last_at` and survives; a fixed one fades out. */
|
|
16339
|
+
pruneEdgeRejections(cutoff) {
|
|
16340
|
+
try {
|
|
16341
|
+
this.db.prepare("DELETE FROM edge_rejections WHERE last_at < ?").run(cutoff);
|
|
16342
|
+
} catch {
|
|
16343
|
+
}
|
|
16344
|
+
}
|
|
16345
|
+
/** Clear the ledger outright, whole or per type — operator escape hatch. */
|
|
16346
|
+
clearEdgeRejections(type) {
|
|
16347
|
+
try {
|
|
16348
|
+
if (type) this.db.prepare("DELETE FROM edge_rejections WHERE type = ?").run(type);
|
|
16349
|
+
else this.db.exec("DELETE FROM edge_rejections");
|
|
16350
|
+
} catch {
|
|
16286
16351
|
}
|
|
16287
|
-
|
|
16288
|
-
|
|
16352
|
+
}
|
|
16353
|
+
edgeRuleViolation(edge) {
|
|
16354
|
+
return localEdgeViolation(
|
|
16355
|
+
this.getNode(edge.from)?.label,
|
|
16356
|
+
edge.type,
|
|
16357
|
+
this.getNode(edge.to)?.label
|
|
16358
|
+
);
|
|
16289
16359
|
}
|
|
16290
16360
|
updateEdge(id, patch) {
|
|
16291
16361
|
this.stmts.updateEdge.run({
|
|
@@ -16422,6 +16492,32 @@ var SqliteGraphStore = class {
|
|
|
16422
16492
|
const rows = this.db.prepare("SELECT from_id, to_id, type FROM edges WHERE valid_to IS NULL").all();
|
|
16423
16493
|
return rows.map((r) => ({ from: r.from_id, to: r.to_id, type: r.type }));
|
|
16424
16494
|
}
|
|
16495
|
+
/**
|
|
16496
|
+
* Live edges WITH their endpoint labels and ids, resolved in ONE join.
|
|
16497
|
+
*
|
|
16498
|
+
* The ontology sweep needs (id, type, fromLabel, toLabel) for every live edge.
|
|
16499
|
+
* Doing that as `scanLiveEdges()` + two `getNode()` calls is 2N node reads —
|
|
16500
|
+
* 550,000 on this store — and each one deserializes the node's embedding blob.
|
|
16501
|
+
* Measured: the sweep did not finish in 10 minutes. As a single join it is one
|
|
16502
|
+
* query over an index-covered scan. Labels only; nothing here touches embeddings.
|
|
16503
|
+
*/
|
|
16504
|
+
scanLiveEdgeRows() {
|
|
16505
|
+
const rows = this.db.prepare(
|
|
16506
|
+
`SELECT e.id, e.from_id, e.to_id, e.type, a.label AS from_label, b.label AS to_label
|
|
16507
|
+
FROM edges e
|
|
16508
|
+
LEFT JOIN nodes a ON a.id = e.from_id AND a.valid_to IS NULL
|
|
16509
|
+
LEFT JOIN nodes b ON b.id = e.to_id AND b.valid_to IS NULL
|
|
16510
|
+
WHERE e.valid_to IS NULL`
|
|
16511
|
+
).all();
|
|
16512
|
+
return rows.map((r) => ({
|
|
16513
|
+
id: r.id,
|
|
16514
|
+
from: r.from_id,
|
|
16515
|
+
to: r.to_id,
|
|
16516
|
+
type: r.type,
|
|
16517
|
+
fromLabel: r.from_label ?? void 0,
|
|
16518
|
+
toLabel: r.to_label ?? void 0
|
|
16519
|
+
}));
|
|
16520
|
+
}
|
|
16425
16521
|
/** Live nodes whose attrs.relPath is one of `relPaths`. Uses the nodes_relpath
|
|
16426
16522
|
* expression index so the incremental reindex fetches only the changed files'
|
|
16427
16523
|
* symbols instead of scanning every versioned node. */
|