@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/package.json
CHANGED
package/pass-worker.mjs
CHANGED
|
@@ -24081,7 +24081,22 @@ var LOCAL_RULE_OVERRIDES = {
|
|
|
24081
24081
|
REVEALED_BY: null,
|
|
24082
24082
|
PRODUCED: null
|
|
24083
24083
|
};
|
|
24084
|
-
|
|
24084
|
+
function localEdgeViolation(fromLabel, type, toLabel) {
|
|
24085
|
+
if (type in LOCAL_RULE_OVERRIDES) {
|
|
24086
|
+
const rule = LOCAL_RULE_OVERRIDES[type];
|
|
24087
|
+
if (!rule) return null;
|
|
24088
|
+
if (fromLabel && rule.from && !rule.from.includes(fromLabel)) {
|
|
24089
|
+
return `${type} cannot originate from ${fromLabel} locally (allowed: ${rule.from.join(", ")})`;
|
|
24090
|
+
}
|
|
24091
|
+
if (toLabel && rule.to && !rule.to.includes(toLabel)) {
|
|
24092
|
+
return `${type} cannot target ${toLabel} locally (allowed: ${rule.to.join(", ")})`;
|
|
24093
|
+
}
|
|
24094
|
+
return null;
|
|
24095
|
+
}
|
|
24096
|
+
const verdict = isValidEdge(fromLabel, type, toLabel);
|
|
24097
|
+
return verdict.ok ? null : verdict.reason ?? "edge rule violation";
|
|
24098
|
+
}
|
|
24099
|
+
var SCHEMA_VERSION = 6;
|
|
24085
24100
|
var SCHEMA_SQL = `
|
|
24086
24101
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
24087
24102
|
version INTEGER PRIMARY KEY
|
|
@@ -24096,6 +24111,21 @@ CREATE TABLE IF NOT EXISTS store_meta (
|
|
|
24096
24111
|
value TEXT NOT NULL
|
|
24097
24112
|
);
|
|
24098
24113
|
|
|
24114
|
+
-- Durable ledger of edges the ontology gate REFUSED, keyed by edge type.
|
|
24115
|
+
-- Durable rather than in-memory for one specific reason: the status command runs
|
|
24116
|
+
-- in a SEPARATE process and opens its own store handle, so a counter living on
|
|
24117
|
+
-- the instance reads 0 there forever. That is exactly how a producer rejecting
|
|
24118
|
+
-- 100% of its output stayed invisible for 17 days. Persisting it also survives
|
|
24119
|
+
-- the daemon restart that would otherwise erase the evidence.
|
|
24120
|
+
-- Keyed by type because a systematic producer bug shows up as ONE type
|
|
24121
|
+
-- dominating; sample keeps the latest reason so the count is actionable.
|
|
24122
|
+
CREATE TABLE IF NOT EXISTS edge_rejections (
|
|
24123
|
+
type TEXT PRIMARY KEY,
|
|
24124
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
24125
|
+
last_at INTEGER NOT NULL,
|
|
24126
|
+
sample TEXT
|
|
24127
|
+
);
|
|
24128
|
+
|
|
24099
24129
|
CREATE TABLE IF NOT EXISTS nodes (
|
|
24100
24130
|
id TEXT PRIMARY KEY,
|
|
24101
24131
|
label TEXT NOT NULL,
|
|
@@ -24472,6 +24502,16 @@ var SqliteGraphStore = class {
|
|
|
24472
24502
|
if (!cols.has(name2)) this.db.exec(ddl);
|
|
24473
24503
|
}
|
|
24474
24504
|
}
|
|
24505
|
+
if (from < 6) {
|
|
24506
|
+
this.db.exec(`
|
|
24507
|
+
CREATE TABLE IF NOT EXISTS edge_rejections (
|
|
24508
|
+
type TEXT PRIMARY KEY,
|
|
24509
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
24510
|
+
last_at INTEGER NOT NULL,
|
|
24511
|
+
sample TEXT
|
|
24512
|
+
)
|
|
24513
|
+
`);
|
|
24514
|
+
}
|
|
24475
24515
|
this.db.prepare("UPDATE schema_version SET version = ?").run(SCHEMA_VERSION);
|
|
24476
24516
|
});
|
|
24477
24517
|
}
|
|
@@ -24553,6 +24593,7 @@ var SqliteGraphStore = class {
|
|
|
24553
24593
|
const violation = this.edgeRuleViolation(edge);
|
|
24554
24594
|
if (violation) {
|
|
24555
24595
|
this.rejectedEdgeCount++;
|
|
24596
|
+
this.recordEdgeRejection(edge.type, violation, edge.lastSeenAt || edge.createdAt || 0);
|
|
24556
24597
|
console.warn(`[local-graph] rejected edge ${edge.from}-[:${edge.type}]->${edge.to}: ${violation}`);
|
|
24557
24598
|
return;
|
|
24558
24599
|
}
|
|
@@ -24577,22 +24618,51 @@ var SqliteGraphStore = class {
|
|
|
24577
24618
|
* overlay consulted first. Returns the reason string on a documented-
|
|
24578
24619
|
* forbidden combination, else null. Point lookups on the id PK — negligible
|
|
24579
24620
|
* next to the insert itself. */
|
|
24580
|
-
|
|
24581
|
-
|
|
24582
|
-
|
|
24583
|
-
|
|
24584
|
-
|
|
24585
|
-
|
|
24586
|
-
|
|
24587
|
-
|
|
24588
|
-
|
|
24589
|
-
|
|
24590
|
-
|
|
24591
|
-
|
|
24592
|
-
|
|
24621
|
+
/** Upsert one refusal into the durable ledger. Best-effort: a bookkeeping
|
|
24622
|
+
* failure must never turn a refused edge into a thrown write. */
|
|
24623
|
+
recordEdgeRejection(type, reason, at) {
|
|
24624
|
+
try {
|
|
24625
|
+
this.db.prepare(
|
|
24626
|
+
`INSERT INTO edge_rejections (type, count, last_at, sample) VALUES (?, 1, ?, ?)
|
|
24627
|
+
ON CONFLICT(type) DO UPDATE SET
|
|
24628
|
+
count = count + 1, last_at = excluded.last_at, sample = excluded.sample`
|
|
24629
|
+
).run(type, at, reason.slice(0, 200));
|
|
24630
|
+
} catch {
|
|
24631
|
+
}
|
|
24632
|
+
}
|
|
24633
|
+
/** Refusals recorded by the ontology gate, per edge type, newest activity first.
|
|
24634
|
+
* Durable across restarts and readable from any process (see the table note). */
|
|
24635
|
+
edgeRejections() {
|
|
24636
|
+
try {
|
|
24637
|
+
return this.db.prepare(
|
|
24638
|
+
"SELECT type, count, last_at AS lastAt, sample FROM edge_rejections ORDER BY count DESC, last_at DESC"
|
|
24639
|
+
).all();
|
|
24640
|
+
} catch {
|
|
24641
|
+
return [];
|
|
24642
|
+
}
|
|
24643
|
+
}
|
|
24644
|
+
/** Drop ledger entries whose last refusal predates `cutoff`. A still-misbehaving
|
|
24645
|
+
* producer keeps refreshing `last_at` and survives; a fixed one fades out. */
|
|
24646
|
+
pruneEdgeRejections(cutoff) {
|
|
24647
|
+
try {
|
|
24648
|
+
this.db.prepare("DELETE FROM edge_rejections WHERE last_at < ?").run(cutoff);
|
|
24649
|
+
} catch {
|
|
24593
24650
|
}
|
|
24594
|
-
|
|
24595
|
-
|
|
24651
|
+
}
|
|
24652
|
+
/** Clear the ledger outright, whole or per type — operator escape hatch. */
|
|
24653
|
+
clearEdgeRejections(type) {
|
|
24654
|
+
try {
|
|
24655
|
+
if (type) this.db.prepare("DELETE FROM edge_rejections WHERE type = ?").run(type);
|
|
24656
|
+
else this.db.exec("DELETE FROM edge_rejections");
|
|
24657
|
+
} catch {
|
|
24658
|
+
}
|
|
24659
|
+
}
|
|
24660
|
+
edgeRuleViolation(edge) {
|
|
24661
|
+
return localEdgeViolation(
|
|
24662
|
+
this.getNode(edge.from)?.label,
|
|
24663
|
+
edge.type,
|
|
24664
|
+
this.getNode(edge.to)?.label
|
|
24665
|
+
);
|
|
24596
24666
|
}
|
|
24597
24667
|
updateEdge(id, patch) {
|
|
24598
24668
|
this.stmts.updateEdge.run({
|
|
@@ -24729,6 +24799,32 @@ var SqliteGraphStore = class {
|
|
|
24729
24799
|
const rows = this.db.prepare("SELECT from_id, to_id, type FROM edges WHERE valid_to IS NULL").all();
|
|
24730
24800
|
return rows.map((r) => ({ from: r.from_id, to: r.to_id, type: r.type }));
|
|
24731
24801
|
}
|
|
24802
|
+
/**
|
|
24803
|
+
* Live edges WITH their endpoint labels and ids, resolved in ONE join.
|
|
24804
|
+
*
|
|
24805
|
+
* The ontology sweep needs (id, type, fromLabel, toLabel) for every live edge.
|
|
24806
|
+
* Doing that as `scanLiveEdges()` + two `getNode()` calls is 2N node reads —
|
|
24807
|
+
* 550,000 on this store — and each one deserializes the node's embedding blob.
|
|
24808
|
+
* Measured: the sweep did not finish in 10 minutes. As a single join it is one
|
|
24809
|
+
* query over an index-covered scan. Labels only; nothing here touches embeddings.
|
|
24810
|
+
*/
|
|
24811
|
+
scanLiveEdgeRows() {
|
|
24812
|
+
const rows = this.db.prepare(
|
|
24813
|
+
`SELECT e.id, e.from_id, e.to_id, e.type, a.label AS from_label, b.label AS to_label
|
|
24814
|
+
FROM edges e
|
|
24815
|
+
LEFT JOIN nodes a ON a.id = e.from_id AND a.valid_to IS NULL
|
|
24816
|
+
LEFT JOIN nodes b ON b.id = e.to_id AND b.valid_to IS NULL
|
|
24817
|
+
WHERE e.valid_to IS NULL`
|
|
24818
|
+
).all();
|
|
24819
|
+
return rows.map((r) => ({
|
|
24820
|
+
id: r.id,
|
|
24821
|
+
from: r.from_id,
|
|
24822
|
+
to: r.to_id,
|
|
24823
|
+
type: r.type,
|
|
24824
|
+
fromLabel: r.from_label ?? void 0,
|
|
24825
|
+
toLabel: r.to_label ?? void 0
|
|
24826
|
+
}));
|
|
24827
|
+
}
|
|
24732
24828
|
/** Live nodes whose attrs.relPath is one of `relPaths`. Uses the nodes_relpath
|
|
24733
24829
|
* expression index so the incremental reindex fetches only the changed files'
|
|
24734
24830
|
* symbols instead of scanning every versioned node. */
|