@mneme-ai/core 3.77.0 → 3.78.0

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.
@@ -0,0 +1,141 @@
1
+ /**
2
+ * ARCHITECTURAL INVARIANTS — design-by-contract for your cross-layer architecture, PROVEN.
3
+ *
4
+ * A type system proves invariants about values. Nothing proves invariants about your ARCHITECTURE: "the
5
+ * `payments` table has exactly one writer", "`credentials` is never reachable from an HTTP endpoint",
6
+ * "no endpoint writes a sensitive table without auth", "`POST /v1/charge` exists". Teams hold these
7
+ * rules in their heads and break them silently. This lets a team DECLARE such invariants in a tiny DSL
8
+ * and, every PR, get a deterministic verdict per rule — HOLDS, or VIOLATED with the exact counterexample
9
+ * (the second writer, the endpoint that reaches the private table) — derived from the cross-layer graph,
10
+ * never guessed. It is the rarest composition: custom, declarative, machine-checked architectural
11
+ * contracts with proof-carrying counterexamples.
12
+ *
13
+ * ★HONEST (DIAKRISIS): the invariants are checked against the structural contract the deterministic
14
+ * extractors see (measured precision 1.0); a VIOLATED carries a real cited counterexample, an UNKNOWN
15
+ * (e.g. a single-writer rule for a table with zero detected writers) is reported as such, never a false
16
+ * HOLDS. It proves what the graph can prove — a CI gate over architecture, not a runtime guarantee.
17
+ */
18
+ import { buildCrossLayerGraph } from "../cross_layer_graph/index.js";
19
+ import { authzGaps } from "../authz_gap/index.js";
20
+ import { reachesProof } from "../graph_logic/index.js";
21
+ import { normPath } from "../cross_service/index.js";
22
+ const lc = (s) => String(s ?? "").toLowerCase();
23
+ /** Parse the invariant DSL. Lines: `table <T> single-writer|guarded|private` · `endpoint [METHOD] <path> exists` · `# comment`. */
24
+ export function parseInvariants(text) {
25
+ const out = [];
26
+ for (const raw0 of String(text ?? "").split(/\r?\n/)) {
27
+ const raw = raw0.replace(/#.*$/, "").trim();
28
+ if (!raw)
29
+ continue;
30
+ let m;
31
+ if ((m = raw.match(/^table\s+([A-Za-z_]\w*)\s+(single-writer|guarded|private)$/i))) {
32
+ out.push({ raw, kind: m[2].toLowerCase(), table: m[1] });
33
+ continue;
34
+ }
35
+ if ((m = raw.match(/^endpoint\s+(?:(GET|POST|PUT|PATCH|DELETE|ANY|RPC)\s+)?(\S+)\s+exists$/i))) {
36
+ out.push({ raw, kind: "exists", method: m[1] ? m[1].toUpperCase() : "", path: m[2] });
37
+ continue;
38
+ }
39
+ out.push({ raw, kind: "invalid" });
40
+ }
41
+ return out;
42
+ }
43
+ function writersOf(g, table) {
44
+ const byId = new Map(g.nodes.map((n) => [n.id, n]));
45
+ const tbl = g.nodes.find((n) => n.type === "db_table" && lc(n.name) === lc(table));
46
+ if (!tbl)
47
+ return [];
48
+ return [...new Set(g.edges.filter((e) => e.relation === "WRITES_TO" && e.target === tbl.id).map((e) => byId.get(e.source)?.name || "").filter(Boolean))];
49
+ }
50
+ /** Check each invariant against the repo → HOLDS / VIOLATED (with counterexample) / UNKNOWN. */
51
+ export function checkInvariants(files, invariants) {
52
+ const g = buildCrossLayerGraph((files ?? []));
53
+ const endpoints = g.nodes.filter((n) => n.type === "api_endpoint");
54
+ const gaps = authzGaps(g);
55
+ const results = [];
56
+ for (const inv of invariants ?? []) {
57
+ if (inv.kind === "invalid") {
58
+ results.push({ invariant: inv, status: "UNKNOWN", reason: `unrecognized invariant: "${inv.raw}"` });
59
+ continue;
60
+ }
61
+ if (inv.kind === "single-writer") {
62
+ const w = writersOf(g, inv.table);
63
+ if (w.length === 1)
64
+ results.push({ invariant: inv, status: "HOLDS", reason: `'${inv.table}' has exactly one writer: ${w[0]}` });
65
+ else if (w.length > 1)
66
+ results.push({ invariant: inv, status: "VIOLATED", counterexample: w.join(", "), reason: `'${inv.table}' has ${w.length} writers: ${w.join(", ")}` });
67
+ else
68
+ results.push({ invariant: inv, status: "UNKNOWN", reason: `no writer of '${inv.table}' detected in the scanned code` });
69
+ }
70
+ else if (inv.kind === "guarded") {
71
+ const bad = gaps.find((x) => x.sensitiveTables.some((t) => lc(t) === lc(inv.table)));
72
+ if (bad)
73
+ results.push({ invariant: inv, status: "VIOLATED", counterexample: `${bad.method} ${bad.endpoint} → ${bad.handler}`, reason: `'${inv.table}' has an unguarded write path: ${bad.method} ${bad.endpoint} via ${bad.handler}` });
74
+ else
75
+ results.push({ invariant: inv, status: "HOLDS", reason: `no unguarded sensitive-write path to '${inv.table}' detected` });
76
+ }
77
+ else if (inv.kind === "private") {
78
+ let hit = null;
79
+ for (const ep of endpoints) {
80
+ const r = reachesProof(g, `${ep.method || ""} ${ep.name}`.trim(), inv.table);
81
+ if (r.reachable) {
82
+ hit = `${ep.method || ""} ${ep.name}`.trim();
83
+ break;
84
+ }
85
+ }
86
+ if (hit)
87
+ results.push({ invariant: inv, status: "VIOLATED", counterexample: hit, reason: `'${inv.table}' is reachable from endpoint ${hit} (should be internal-only)` });
88
+ else
89
+ results.push({ invariant: inv, status: "HOLDS", reason: `no endpoint reaches '${inv.table}' — it stays internal` });
90
+ }
91
+ else if (inv.kind === "exists") {
92
+ const want = normPath(inv.path);
93
+ const found = endpoints.some((ep) => normPath(ep.name) === want && (!inv.method || (ep.method || "") === inv.method));
94
+ results.push(found ? { invariant: inv, status: "HOLDS", reason: `endpoint ${inv.method || ""} ${inv.path} exists` } : { invariant: inv, status: "VIOLATED", reason: `endpoint ${inv.method || ""} ${inv.path} is NOT in the API surface` });
95
+ }
96
+ }
97
+ const violated = results.filter((r) => r.status === "VIOLATED").length;
98
+ return { results, allHold: violated === 0, violated };
99
+ }
100
+ export function invariantsGauntlet() {
101
+ const files = [
102
+ { path: "schema.prisma", content: "model Payment { id Int @id }\nmodel Audit { id Int @id }\nmodel Secret { id Int @id }\nmodel Account { id Int @id }" },
103
+ { path: "routes.ts", content: "router.post(\"/v1/charge\", charge);\nrouter.get(\"/v1/secret\", leakSecret);\nrouter.post(\"/v1/xfer\", xfer);" },
104
+ { path: "h.ts", content: "export function charge(req){ requireAuth(req); return prisma.payment.create({data:{}}); }\nexport function requireAuth(r){ return r.user; }\nexport function leakSecret(){ return prisma.secret.findMany(); }\nexport function xfer(){ return prisma.account.update({where:{}}); }\nexport function aw(){ return prisma.audit.create({data:{}}); }\nexport function aw2(){ return prisma.audit.update({where:{}}); }" },
105
+ ];
106
+ const inv = parseInvariants([
107
+ "table Payment single-writer", // 1 writer (charge) → HOLDS
108
+ "table Audit single-writer", // 2 writers (aw, aw2) → VIOLATED
109
+ "table Secret private", // reached by GET /v1/secret → VIOLATED
110
+ "table Audit private", // no endpoint reaches Audit → HOLDS
111
+ "table Account guarded", // xfer writes account with no auth → VIOLATED
112
+ "endpoint POST /v1/charge exists", // HOLDS
113
+ "endpoint GET /v1/nope exists", // VIOLATED
114
+ ].join("\n"));
115
+ const r = checkInvariants(files, inv);
116
+ const by = (raw) => r.results.find((x) => x.invariant.raw === raw);
117
+ const swHold = by("table Payment single-writer").status === "HOLDS";
118
+ const swViol = by("table Audit single-writer").status === "VIOLATED" && (by("table Audit single-writer").counterexample || "").includes("aw");
119
+ const privViol = by("table Secret private").status === "VIOLATED";
120
+ const privHold = by("table Audit private").status === "HOLDS";
121
+ const guardViol = by("table Account guarded").status === "VIOLATED";
122
+ const existHold = by("endpoint POST /v1/charge exists").status === "HOLDS";
123
+ const existViol = by("endpoint GET /v1/nope exists").status === "VIOLATED";
124
+ const total = (() => { try {
125
+ checkInvariants(null, null);
126
+ parseInvariants(null);
127
+ return true;
128
+ }
129
+ catch {
130
+ return false;
131
+ } })();
132
+ const checks = [
133
+ { name: "SINGLE-WRITER", pass: swHold && swViol, detail: "single-writer HOLDS for one writer; VIOLATED (names the writers) for two" },
134
+ { name: "PRIVATE-TABLE", pass: privViol && privHold, detail: "private VIOLATED when an endpoint reaches the table (counterexample), HOLDS when none does" },
135
+ { name: "GUARDED-TABLE", pass: guardViol, detail: "guarded VIOLATED when there is an unguarded sensitive-write path" },
136
+ { name: "ENDPOINT-EXISTS", pass: existHold && existViol, detail: "exists HOLDS when the endpoint is in the API surface, VIOLATED when absent" },
137
+ { name: "TOTAL", pass: total, detail: "null/garbage never throws" },
138
+ ];
139
+ return { score: checks.every((c) => c.pass) ? 100 : 0, checks };
140
+ }
141
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/invariants/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=invariants.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariants.test.d.ts","sourceRoot":"","sources":["../../src/invariants/invariants.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { parseInvariants, checkInvariants, invariantsGauntlet } from "./index.js";
3
+ const files = [
4
+ { path: "schema.prisma", content: "model Payment { id Int @id }\nmodel Audit { id Int @id }\nmodel Secret { id Int @id }\nmodel Account { id Int @id }" },
5
+ { path: "routes.ts", content: "router.post(\"/v1/charge\", charge);\nrouter.get(\"/v1/secret\", leakSecret);\nrouter.post(\"/v1/xfer\", xfer);" },
6
+ { path: "h.ts", content: "export function charge(req){ requireAuth(req); return prisma.payment.create({data:{}}); }\nexport function requireAuth(r){ return r.user; }\nexport function leakSecret(){ return prisma.secret.findMany(); }\nexport function xfer(){ return prisma.account.update({where:{}}); }\nexport function aw(){ return prisma.audit.create({data:{}}); }\nexport function aw2(){ return prisma.audit.update({where:{}}); }" },
7
+ ];
8
+ describe("invariants", () => {
9
+ it("gauntlet is 100", () => expect(invariantsGauntlet().score).toBe(100));
10
+ it("parses the DSL", () => {
11
+ const inv = parseInvariants("table users single-writer\ntable creds private\nendpoint POST /x exists\n# comment\ngarbage line");
12
+ expect(inv.map((i) => i.kind)).toEqual(["single-writer", "private", "exists", "invalid"]);
13
+ });
14
+ it("single-writer: HOLDS for 1, VIOLATED (names writers) for 2", () => {
15
+ const r = checkInvariants(files, parseInvariants("table Payment single-writer\ntable Audit single-writer"));
16
+ expect(r.results[0].status).toBe("HOLDS");
17
+ expect(r.results[1].status).toBe("VIOLATED");
18
+ expect(r.results[1].counterexample).toMatch(/aw/);
19
+ });
20
+ it("private: VIOLATED when an endpoint reaches it, HOLDS when none", () => {
21
+ const r = checkInvariants(files, parseInvariants("table Secret private\ntable Audit private"));
22
+ expect(r.results[0].status).toBe("VIOLATED");
23
+ expect(r.results[1].status).toBe("HOLDS");
24
+ });
25
+ it("guarded VIOLATED on an unguarded sensitive write; exists HOLDS/VIOLATED", () => {
26
+ const r = checkInvariants(files, parseInvariants("table Account guarded\nendpoint POST /v1/charge exists\nendpoint GET /nope exists"));
27
+ expect(r.results[0].status).toBe("VIOLATED");
28
+ expect(r.results[1].status).toBe("HOLDS");
29
+ expect(r.results[2].status).toBe("VIOLATED");
30
+ expect(r.allHold).toBe(false);
31
+ });
32
+ it("never throws on garbage", () => {
33
+ expect(() => checkInvariants(null, null)).not.toThrow();
34
+ expect(() => parseInvariants(null)).not.toThrow();
35
+ });
36
+ });
37
+ //# sourceMappingURL=invariants.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariants.test.js","sourceRoot":"","sources":["../../src/invariants/invariants.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAElF,MAAM,KAAK,GAAG;IACZ,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,qHAAqH,EAAE;IACzJ,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,iHAAiH,EAAE;IACjJ,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,sZAAsZ,EAAE;CAClb,CAAC;AAEF,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAE1E,EAAE,CAAC,gBAAgB,EAAE,GAAG,EAAE;QACxB,MAAM,GAAG,GAAG,eAAe,CAAC,kGAAkG,CAAC,CAAC;QAChI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,eAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,CAAC,GAAG,eAAe,CAAC,KAAK,EAAE,eAAe,CAAC,wDAAwD,CAAC,CAAC,CAAC;QAC5G,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,CAAC,GAAG,eAAe,CAAC,KAAK,EAAE,eAAe,CAAC,2CAA2C,CAAC,CAAC,CAAC;QAC/F,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACjF,MAAM,CAAC,GAAG,eAAe,CAAC,KAAK,EAAE,eAAe,CAAC,mFAAmF,CAAC,CAAC,CAAC;QACvI,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,IAAa,EAAE,IAAa,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAC1E,MAAM,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,IAAa,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mneme-ai/core",
3
- "version": "3.77.0",
3
+ "version": "3.78.0",
4
4
  "description": "Core indexing, retrieval, and graph engine for Mneme",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",