@mneme-ai/core 2.19.41 → 2.19.43
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/dist/cascade_inversion/cascade_inversion.test.d.ts +2 -0
- package/dist/cascade_inversion/cascade_inversion.test.d.ts.map +1 -0
- package/dist/cascade_inversion/cascade_inversion.test.js +101 -0
- package/dist/cascade_inversion/cascade_inversion.test.js.map +1 -0
- package/dist/cascade_inversion/index.d.ts +87 -0
- package/dist/cascade_inversion/index.d.ts.map +1 -0
- package/dist/cascade_inversion/index.js +150 -0
- package/dist/cascade_inversion/index.js.map +1 -0
- package/dist/cosmic/aurelian_v1942.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v1942.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v1942.test.js +90 -0
- package/dist/cosmic/aurelian_v1942.test.js.map +1 -0
- package/dist/cosmic/aurelian_v1943.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v1943.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v1943.test.js +76 -0
- package/dist/cosmic/aurelian_v1943.test.js.map +1 -0
- package/dist/honesty_gate/honesty_gate_v2.test.d.ts +2 -0
- package/dist/honesty_gate/honesty_gate_v2.test.d.ts.map +1 -0
- package/dist/honesty_gate/honesty_gate_v2.test.js +116 -0
- package/dist/honesty_gate/honesty_gate_v2.test.js.map +1 -0
- package/dist/honesty_gate/index.d.ts +70 -0
- package/dist/honesty_gate/index.d.ts.map +1 -1
- package/dist/honesty_gate/index.js +136 -0
- package/dist/honesty_gate/index.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/mneme_version.d.ts +18 -7
- package/dist/mneme_version.d.ts.map +1 -1
- package/dist/mneme_version.js +59 -21
- package/dist/mneme_version.js.map +1 -1
- package/dist/mneme_version.test.js +15 -0
- package/dist/mneme_version.test.js.map +1 -1
- package/dist/proof_of_saving/index.d.ts +90 -0
- package/dist/proof_of_saving/index.d.ts.map +1 -0
- package/dist/proof_of_saving/index.js +153 -0
- package/dist/proof_of_saving/index.js.map +1 -0
- package/dist/proof_of_saving/proof_of_saving.test.d.ts +2 -0
- package/dist/proof_of_saving/proof_of_saving.test.d.ts.map +1 -0
- package/dist/proof_of_saving/proof_of_saving.test.js +87 -0
- package/dist/proof_of_saving/proof_of_saving.test.js.map +1 -0
- package/dist/squadron/acgv_explain.d.ts.map +1 -1
- package/dist/squadron/acgv_explain.js +31 -1
- package/dist/squadron/acgv_explain.js.map +1 -1
- package/dist/squadron/acgv_explain.test.d.ts +2 -0
- package/dist/squadron/acgv_explain.test.d.ts.map +1 -0
- package/dist/squadron/acgv_explain.test.js +52 -0
- package/dist/squadron/acgv_explain.test.js.map +1 -0
- package/dist/whats_new.d.ts.map +1 -1
- package/dist/whats_new.js +16 -0
- package/dist/whats_new.js.map +1 -1
- package/dist/wrapper_genesis/index.d.ts.map +1 -1
- package/dist/wrapper_genesis/index.js +13 -0
- package/dist/wrapper_genesis/index.js.map +1 -1
- package/package.json +1 -1
package/dist/mneme_version.d.ts
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Resolve the running Mneme version from disk (package.json), with the
|
|
3
3
|
* env-var as a secondary source. NEVER falls back to a hard-coded
|
|
4
|
-
* string -- those bit-rot the moment a new version ships
|
|
5
|
-
* of bug #5: MCP server reporting "1.27.9" while CLI shows "1.43.0").
|
|
4
|
+
* string -- those bit-rot the moment a new version ships.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
6
|
+
* Bug history:
|
|
7
|
+
* - v1.43 bug #5: MCP server reporting "1.27.9" while CLI shows "1.43.0"
|
|
8
|
+
* (fixed by walking up for @mneme-ai/core package.json).
|
|
9
|
+
* - v2.19.41 N4: `mneme system upgrade --json '{"mode":"check"}'`
|
|
10
|
+
* reported current=0.0.0 because env was empty AND resolver only
|
|
11
|
+
* accepted @mneme-ai/core name. When MCP server runs from npm-global
|
|
12
|
+
* install, packages/mcp is a sibling of core under node_modules, not
|
|
13
|
+
* a parent -- walking up never found a "@mneme-ai/core" package.json.
|
|
14
|
+
*
|
|
15
|
+
* v2.19.43 lookup order (robust against npm-global install where sibling
|
|
16
|
+
* packages don't have core as a parent):
|
|
8
17
|
* 1. process.env.npm_package_version (set when launched via `npm run`)
|
|
9
|
-
* 2. Walk up from this module's directory
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
18
|
+
* 2. Walk up from this module's directory for ANY package.json whose
|
|
19
|
+
* name matches the Mneme family (@mneme-ai/{core,mcp,cli,embeddings,
|
|
20
|
+
* correlator}, or the umbrella mneme-ai). All 5 ship lock-step.
|
|
21
|
+
* 3. Walk up for any package.json with a Mneme-shaped name (covers
|
|
22
|
+
* future families we add).
|
|
23
|
+
* 4. Final fallback: literal "0.0.0-unknown" so the bad value is OBVIOUS.
|
|
13
24
|
*/
|
|
14
25
|
export declare function resolveMnemeVersion(): string;
|
|
15
26
|
/** For tests: clear the memoized value so a re-read happens. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mneme_version.d.ts","sourceRoot":"","sources":["../src/mneme_version.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"mneme_version.d.ts","sourceRoot":"","sources":["../src/mneme_version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAoCH,wBAAgB,mBAAmB,IAAI,MAAM,CAwB5C;AAED,gEAAgE;AAChE,wBAAgB,uBAAuB,IAAI,IAAI,CAAmB"}
|
package/dist/mneme_version.js
CHANGED
|
@@ -1,44 +1,82 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Resolve the running Mneme version from disk (package.json), with the
|
|
3
3
|
* env-var as a secondary source. NEVER falls back to a hard-coded
|
|
4
|
-
* string -- those bit-rot the moment a new version ships
|
|
5
|
-
* of bug #5: MCP server reporting "1.27.9" while CLI shows "1.43.0").
|
|
4
|
+
* string -- those bit-rot the moment a new version ships.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
6
|
+
* Bug history:
|
|
7
|
+
* - v1.43 bug #5: MCP server reporting "1.27.9" while CLI shows "1.43.0"
|
|
8
|
+
* (fixed by walking up for @mneme-ai/core package.json).
|
|
9
|
+
* - v2.19.41 N4: `mneme system upgrade --json '{"mode":"check"}'`
|
|
10
|
+
* reported current=0.0.0 because env was empty AND resolver only
|
|
11
|
+
* accepted @mneme-ai/core name. When MCP server runs from npm-global
|
|
12
|
+
* install, packages/mcp is a sibling of core under node_modules, not
|
|
13
|
+
* a parent -- walking up never found a "@mneme-ai/core" package.json.
|
|
14
|
+
*
|
|
15
|
+
* v2.19.43 lookup order (robust against npm-global install where sibling
|
|
16
|
+
* packages don't have core as a parent):
|
|
8
17
|
* 1. process.env.npm_package_version (set when launched via `npm run`)
|
|
9
|
-
* 2. Walk up from this module's directory
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
18
|
+
* 2. Walk up from this module's directory for ANY package.json whose
|
|
19
|
+
* name matches the Mneme family (@mneme-ai/{core,mcp,cli,embeddings,
|
|
20
|
+
* correlator}, or the umbrella mneme-ai). All 5 ship lock-step.
|
|
21
|
+
* 3. Walk up for any package.json with a Mneme-shaped name (covers
|
|
22
|
+
* future families we add).
|
|
23
|
+
* 4. Final fallback: literal "0.0.0-unknown" so the bad value is OBVIOUS.
|
|
13
24
|
*/
|
|
14
25
|
import { existsSync, readFileSync } from "node:fs";
|
|
15
26
|
import { dirname, join } from "node:path";
|
|
16
27
|
import { fileURLToPath } from "node:url";
|
|
17
28
|
let cached = null;
|
|
29
|
+
const MNEME_FAMILY = new Set([
|
|
30
|
+
"@mneme-ai/core",
|
|
31
|
+
"@mneme-ai/mcp",
|
|
32
|
+
"@mneme-ai/cli",
|
|
33
|
+
"@mneme-ai/embeddings",
|
|
34
|
+
"@mneme-ai/correlator",
|
|
35
|
+
"mneme-ai",
|
|
36
|
+
]);
|
|
37
|
+
function walkUpForPackageJson(startDir, accept) {
|
|
38
|
+
let dir = startDir;
|
|
39
|
+
for (let i = 0; i < 12; i++) {
|
|
40
|
+
const pkg = join(dir, "package.json");
|
|
41
|
+
if (existsSync(pkg)) {
|
|
42
|
+
try {
|
|
43
|
+
const parsed = JSON.parse(readFileSync(pkg, "utf8"));
|
|
44
|
+
if (typeof parsed.version === "string" && /^\d+\.\d+\.\d+/.test(parsed.version) && accept(parsed.name)) {
|
|
45
|
+
return parsed.version;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch { /* keep walking */ }
|
|
49
|
+
}
|
|
50
|
+
const parent = dirname(dir);
|
|
51
|
+
if (parent === dir)
|
|
52
|
+
break;
|
|
53
|
+
dir = parent;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
18
57
|
export function resolveMnemeVersion() {
|
|
19
58
|
if (cached)
|
|
20
59
|
return cached;
|
|
60
|
+
// 1) env var (npm run only)
|
|
21
61
|
const env = process.env["npm_package_version"];
|
|
22
62
|
if (env && /^\d+\.\d+\.\d+/.test(env)) {
|
|
23
63
|
cached = env;
|
|
24
64
|
return env;
|
|
25
65
|
}
|
|
66
|
+
// 2) walk up for ANY Mneme-family package.json
|
|
26
67
|
try {
|
|
27
68
|
const here = fileURLToPath(import.meta.url);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (parent === dir)
|
|
40
|
-
break;
|
|
41
|
-
dir = parent;
|
|
69
|
+
const startDir = dirname(here);
|
|
70
|
+
const familyHit = walkUpForPackageJson(startDir, (name) => !!name && MNEME_FAMILY.has(name));
|
|
71
|
+
if (familyHit) {
|
|
72
|
+
cached = familyHit;
|
|
73
|
+
return familyHit;
|
|
74
|
+
}
|
|
75
|
+
// 3) widen the net to any Mneme-shaped name
|
|
76
|
+
const anyHit = walkUpForPackageJson(startDir, (name) => !!name && (name.startsWith("@mneme-ai/") || name === "mneme-ai" || name === "mneme"));
|
|
77
|
+
if (anyHit) {
|
|
78
|
+
cached = anyHit;
|
|
79
|
+
return anyHit;
|
|
42
80
|
}
|
|
43
81
|
}
|
|
44
82
|
catch { /* fall through */ }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mneme_version.js","sourceRoot":"","sources":["../src/mneme_version.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"mneme_version.js","sourceRoot":"","sources":["../src/mneme_version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;IAC3B,gBAAgB;IAChB,eAAe;IACf,eAAe;IACf,sBAAsB;IACtB,sBAAsB;IACtB,UAAU;CACX,CAAC,CAAC;AAEH,SAAS,oBAAoB,CAAC,QAAgB,EAAE,MAA6C;IAC3F,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QACtC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAwC,CAAC;gBAC5F,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;oBACvG,OAAO,MAAM,CAAC,OAAO,CAAC;gBACxB,CAAC;YACH,CAAC;YAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC;QAChC,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,4BAA4B;IAC5B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAC/C,IAAI,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,CAAC;QACb,OAAO,GAAG,CAAC;IACb,CAAC;IAED,+CAA+C;IAC/C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,SAAS,GAAG,oBAAoB,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7F,IAAI,SAAS,EAAE,CAAC;YAAC,MAAM,GAAG,SAAS,CAAC;YAAC,OAAO,SAAS,CAAC;QAAC,CAAC;QAExD,4CAA4C;QAC5C,MAAM,MAAM,GAAG,oBAAoB,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC;QAC9I,IAAI,MAAM,EAAE,CAAC;YAAC,MAAM,GAAG,MAAM,CAAC;YAAC,OAAO,MAAM,CAAC;QAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC;IAE9B,MAAM,GAAG,eAAe,CAAC;IACzB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,uBAAuB,KAAW,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC"}
|
|
@@ -39,5 +39,20 @@ describe("mneme_version · resolution", () => {
|
|
|
39
39
|
const v = resolveMnemeVersion();
|
|
40
40
|
expect(v).not.toBe("not-a-version");
|
|
41
41
|
});
|
|
42
|
+
// v2.19.43 N4 regression — pre-v2.19.43 the resolver only accepted
|
|
43
|
+
// @mneme-ai/core; on npm-global install the MCP package is a SIBLING
|
|
44
|
+
// not a parent, so walking up never found core's package.json and the
|
|
45
|
+
// resolver returned "0.0.0-unknown". Caller (system.upgrade) then
|
|
46
|
+
// reported "current: 0.0.0" + advertised an upgrade with wrong baseline.
|
|
47
|
+
it("never returns 0.0.0 when running from a real install (regression for N4)", () => {
|
|
48
|
+
delete process.env["npm_package_version"];
|
|
49
|
+
_resetMnemeVersionCache();
|
|
50
|
+
const v = resolveMnemeVersion();
|
|
51
|
+
expect(v).not.toBe("0.0.0");
|
|
52
|
+
expect(v).not.toBe("0.0.0-unknown");
|
|
53
|
+
// Should pick up a sibling Mneme-family package.json even when running
|
|
54
|
+
// from packages/mcp or packages/cli.
|
|
55
|
+
expect(v).toMatch(/^\d+\.\d+\.\d+/);
|
|
56
|
+
});
|
|
42
57
|
});
|
|
43
58
|
//# sourceMappingURL=mneme_version.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mneme_version.test.js","sourceRoot":"","sources":["../src/mneme_version.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAElF,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,IAAI,KAAyB,CAAC;IAC9B,UAAU,CAAC,GAAG,EAAE;QACd,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QAC3C,uBAAuB,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;;YAC9D,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,GAAG,KAAK,CAAC;QAChD,uBAAuB,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,GAAG,OAAO,CAAC;QAC7C,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,GAAG,OAAO,CAAC;QAC7C,MAAM,CAAC,GAAG,mBAAmB,EAAE,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,GAAG,OAAO,CAAC;QAC7C,MAAM,CAAC,GAAG,mBAAmB,EAAE,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,OAAO,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,mBAAmB,EAAE,CAAC;QAChC,4EAA4E;QAC5E,iFAAiF;QACjF,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACpC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,GAAG,eAAe,CAAC;QACrD,MAAM,CAAC,GAAG,mBAAmB,EAAE,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"mneme_version.test.js","sourceRoot":"","sources":["../src/mneme_version.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.42 — PROOF OF SAVING (the wild idea no other AI tool ships).
|
|
3
|
+
*
|
|
4
|
+
* "OpenAI / Anthropic charge you per token. Enterprises pay millions
|
|
5
|
+
* and have no third-party-verifiable evidence of what they saved by
|
|
6
|
+
* routing through any optimisation layer. PROOF OF SAVING mints an
|
|
7
|
+
* HMAC-signed Merkle-rooted certificate from a batch of Governor
|
|
8
|
+
* decisions: a Saving Manifest the procurement team can hand to
|
|
9
|
+
* auditors. Replayable, tamper-evident, vendor-neutral. The
|
|
10
|
+
* auditor doesn't need to trust Mneme's implementation — they
|
|
11
|
+
* re-hash the decisions and re-derive the same Merkle root.
|
|
12
|
+
*
|
|
13
|
+
* This composes onto v2.19.40 TOKEN GOVERNOR (decisions are the
|
|
14
|
+
* leaves) + v2.19.34 APOSTILLE (same HMAC-chain pattern) + v2.19.34
|
|
15
|
+
* ETERNITY (certificate pins across vendors so the saving survives
|
|
16
|
+
* even if the optimiser provider disappears). It is the missing
|
|
17
|
+
* enterprise procurement primitive: 'show me PROOF you saved my
|
|
18
|
+
* company money.'
|
|
19
|
+
*
|
|
20
|
+
* Wild because no AI optimisation vendor (LangChain / Helicone /
|
|
21
|
+
* Portkey / Vellum / Braintrust) issues replayable savings
|
|
22
|
+
* certificates — they show you a dashboard chart and ask you to
|
|
23
|
+
* trust the SQL behind it. Mneme issues a 4KB JSON certificate
|
|
24
|
+
* auditors can verify offline in 5ms."
|
|
25
|
+
*/
|
|
26
|
+
declare const PROTOCOL_VERSION: 1;
|
|
27
|
+
export interface GovernedDecisionShape {
|
|
28
|
+
/** Stable id (some callers use signature; we sha256 the whole object). */
|
|
29
|
+
signature: string;
|
|
30
|
+
tokensUsedActual: number;
|
|
31
|
+
estTokensSavedVsDirect: number;
|
|
32
|
+
stage: number;
|
|
33
|
+
}
|
|
34
|
+
export interface SavingsCertificate {
|
|
35
|
+
v: typeof PROTOCOL_VERSION;
|
|
36
|
+
/** ISO timestamp of cert mint. */
|
|
37
|
+
mintedAt: string;
|
|
38
|
+
/** Window the savings cover. */
|
|
39
|
+
windowStartMs: number;
|
|
40
|
+
windowEndMs: number;
|
|
41
|
+
/** Number of governed AI calls in the window. */
|
|
42
|
+
decisionCount: number;
|
|
43
|
+
/** Total tokens that would have been spent without Mneme. */
|
|
44
|
+
totalDirectTokens: number;
|
|
45
|
+
/** Total tokens actually spent through the Governor cascade. */
|
|
46
|
+
totalActualTokens: number;
|
|
47
|
+
/** totalDirectTokens - totalActualTokens. Always >= 0 by design. */
|
|
48
|
+
totalTokensSaved: number;
|
|
49
|
+
/** Hit rate per stage (Stage 1 = cache, Stage 2 = local, etc). */
|
|
50
|
+
stageBreakdown: Record<string, {
|
|
51
|
+
calls: number;
|
|
52
|
+
tokensSaved: number;
|
|
53
|
+
}>;
|
|
54
|
+
/** Estimated USD saved at caller-supplied $-per-token. */
|
|
55
|
+
estUsdSaved: number;
|
|
56
|
+
/** Caller-supplied $-per-token used for the USD estimate. */
|
|
57
|
+
usdPerToken: number;
|
|
58
|
+
/** Merkle root over decision signatures (replay-verifiable). */
|
|
59
|
+
merkleRoot: string;
|
|
60
|
+
/** Number of leaves in the Merkle tree. */
|
|
61
|
+
merkleLeafCount: number;
|
|
62
|
+
/** HMAC over the canonicalised cert body. */
|
|
63
|
+
hmac: string;
|
|
64
|
+
}
|
|
65
|
+
export interface MintCertInput {
|
|
66
|
+
decisions: GovernedDecisionShape[];
|
|
67
|
+
windowStartMs: number;
|
|
68
|
+
windowEndMs: number;
|
|
69
|
+
/** Caller's blended $-per-token estimate. Default: $0.000002 (≈$2/1M). */
|
|
70
|
+
usdPerToken?: number;
|
|
71
|
+
/** Optional HMAC secret. Default: env MNEME_PROOF_SECRET. */
|
|
72
|
+
secret?: string;
|
|
73
|
+
/** Optional mint timestamp (defaults to Date.now). */
|
|
74
|
+
nowMs?: number;
|
|
75
|
+
}
|
|
76
|
+
/** Mint a savings certificate from a batch of Governor decisions. */
|
|
77
|
+
export declare function mintSavingsCertificate(input: MintCertInput): SavingsCertificate;
|
|
78
|
+
/**
|
|
79
|
+
* Verify a savings certificate. Returns { ok, reason } so callers can
|
|
80
|
+
* surface specific failure reasons (HMAC mismatch / Merkle mismatch /
|
|
81
|
+
* arithmetic violation).
|
|
82
|
+
*/
|
|
83
|
+
export declare function verifySavingsCertificate(cert: SavingsCertificate, decisions: GovernedDecisionShape[], secret?: string): {
|
|
84
|
+
ok: boolean;
|
|
85
|
+
reason?: string;
|
|
86
|
+
};
|
|
87
|
+
/** Render a human-readable summary safe to surface to a procurement dashboard. */
|
|
88
|
+
export declare function formatCertificate(cert: SavingsCertificate): string;
|
|
89
|
+
export {};
|
|
90
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/proof_of_saving/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,QAAA,MAAM,gBAAgB,EAAG,CAAU,CAAC;AAEpC,MAAM,WAAW,qBAAqB;IACpC,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,CAAC,EAAE,OAAO,gBAAgB,CAAC;IAC3B,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,aAAa,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,gBAAgB,EAAE,MAAM,CAAC;IACzB,kEAAkE;IAClE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvE,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,eAAe,EAAE,MAAM,CAAC;IACxB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,qBAAqB,EAAE,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAqCD,qEAAqE;AACrE,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,GAAG,kBAAkB,CA2C/E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,kBAAkB,EACxB,SAAS,EAAE,qBAAqB,EAAE,EAClC,MAAM,CAAC,EAAE,MAAM,GACd;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAwBlC;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAkBlE"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.42 — PROOF OF SAVING (the wild idea no other AI tool ships).
|
|
3
|
+
*
|
|
4
|
+
* "OpenAI / Anthropic charge you per token. Enterprises pay millions
|
|
5
|
+
* and have no third-party-verifiable evidence of what they saved by
|
|
6
|
+
* routing through any optimisation layer. PROOF OF SAVING mints an
|
|
7
|
+
* HMAC-signed Merkle-rooted certificate from a batch of Governor
|
|
8
|
+
* decisions: a Saving Manifest the procurement team can hand to
|
|
9
|
+
* auditors. Replayable, tamper-evident, vendor-neutral. The
|
|
10
|
+
* auditor doesn't need to trust Mneme's implementation — they
|
|
11
|
+
* re-hash the decisions and re-derive the same Merkle root.
|
|
12
|
+
*
|
|
13
|
+
* This composes onto v2.19.40 TOKEN GOVERNOR (decisions are the
|
|
14
|
+
* leaves) + v2.19.34 APOSTILLE (same HMAC-chain pattern) + v2.19.34
|
|
15
|
+
* ETERNITY (certificate pins across vendors so the saving survives
|
|
16
|
+
* even if the optimiser provider disappears). It is the missing
|
|
17
|
+
* enterprise procurement primitive: 'show me PROOF you saved my
|
|
18
|
+
* company money.'
|
|
19
|
+
*
|
|
20
|
+
* Wild because no AI optimisation vendor (LangChain / Helicone /
|
|
21
|
+
* Portkey / Vellum / Braintrust) issues replayable savings
|
|
22
|
+
* certificates — they show you a dashboard chart and ask you to
|
|
23
|
+
* trust the SQL behind it. Mneme issues a 4KB JSON certificate
|
|
24
|
+
* auditors can verify offline in 5ms."
|
|
25
|
+
*/
|
|
26
|
+
import { createHmac } from "node:crypto";
|
|
27
|
+
const PROTOCOL_VERSION = 1;
|
|
28
|
+
function defaultSecret() {
|
|
29
|
+
return process.env["MNEME_PROOF_SECRET"] || `mneme-proof-of-saving-v${PROTOCOL_VERSION}`;
|
|
30
|
+
}
|
|
31
|
+
function canon(v) {
|
|
32
|
+
if (v === null || typeof v !== "object")
|
|
33
|
+
return JSON.stringify(v);
|
|
34
|
+
if (Array.isArray(v))
|
|
35
|
+
return "[" + v.map(canon).join(",") + "]";
|
|
36
|
+
const keys = Object.keys(v).sort();
|
|
37
|
+
return "{" + keys.map((k) => JSON.stringify(k) + ":" + canon(v[k])).join(",") + "}";
|
|
38
|
+
}
|
|
39
|
+
function sha256Hex(s) {
|
|
40
|
+
return createHmac("sha256", "mneme-proof-leaf").update(s).digest("hex");
|
|
41
|
+
}
|
|
42
|
+
function signCert(body, secret) {
|
|
43
|
+
return createHmac("sha256", secret).update(canon(body)).digest("hex");
|
|
44
|
+
}
|
|
45
|
+
/** Build a Merkle root over an array of leaf strings. Deterministic. */
|
|
46
|
+
function merkleRoot(leaves) {
|
|
47
|
+
if (leaves.length === 0)
|
|
48
|
+
return sha256Hex("∅");
|
|
49
|
+
let level = leaves.map(sha256Hex);
|
|
50
|
+
while (level.length > 1) {
|
|
51
|
+
const next = [];
|
|
52
|
+
for (let i = 0; i < level.length; i += 2) {
|
|
53
|
+
const a = level[i];
|
|
54
|
+
const b = level[i + 1] ?? a;
|
|
55
|
+
next.push(sha256Hex(a + ":" + b));
|
|
56
|
+
}
|
|
57
|
+
level = next;
|
|
58
|
+
}
|
|
59
|
+
return level[0];
|
|
60
|
+
}
|
|
61
|
+
/** Mint a savings certificate from a batch of Governor decisions. */
|
|
62
|
+
export function mintSavingsCertificate(input) {
|
|
63
|
+
const usdPerToken = input.usdPerToken ?? 0.000002; // $2 / 1M tokens default
|
|
64
|
+
const secret = input.secret ?? defaultSecret();
|
|
65
|
+
const nowMs = input.nowMs ?? Date.now();
|
|
66
|
+
const stageBreakdown = {
|
|
67
|
+
"1": { calls: 0, tokensSaved: 0 },
|
|
68
|
+
"2": { calls: 0, tokensSaved: 0 },
|
|
69
|
+
"3": { calls: 0, tokensSaved: 0 },
|
|
70
|
+
"4": { calls: 0, tokensSaved: 0 },
|
|
71
|
+
"5": { calls: 0, tokensSaved: 0 },
|
|
72
|
+
};
|
|
73
|
+
let totalActual = 0;
|
|
74
|
+
let totalSaved = 0;
|
|
75
|
+
for (const d of input.decisions) {
|
|
76
|
+
totalActual += d.tokensUsedActual;
|
|
77
|
+
totalSaved += d.estTokensSavedVsDirect;
|
|
78
|
+
const k = String(d.stage);
|
|
79
|
+
if (stageBreakdown[k]) {
|
|
80
|
+
stageBreakdown[k].calls += 1;
|
|
81
|
+
stageBreakdown[k].tokensSaved += d.estTokensSavedVsDirect;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const totalDirect = totalActual + totalSaved;
|
|
85
|
+
const leaves = input.decisions.map((d) => d.signature);
|
|
86
|
+
const root = merkleRoot(leaves);
|
|
87
|
+
const body = {
|
|
88
|
+
v: PROTOCOL_VERSION,
|
|
89
|
+
mintedAt: new Date(nowMs).toISOString(),
|
|
90
|
+
windowStartMs: input.windowStartMs,
|
|
91
|
+
windowEndMs: input.windowEndMs,
|
|
92
|
+
decisionCount: input.decisions.length,
|
|
93
|
+
totalDirectTokens: totalDirect,
|
|
94
|
+
totalActualTokens: totalActual,
|
|
95
|
+
totalTokensSaved: totalSaved,
|
|
96
|
+
stageBreakdown,
|
|
97
|
+
estUsdSaved: totalSaved * usdPerToken,
|
|
98
|
+
usdPerToken,
|
|
99
|
+
merkleRoot: root,
|
|
100
|
+
merkleLeafCount: leaves.length,
|
|
101
|
+
};
|
|
102
|
+
return { ...body, hmac: signCert(body, secret) };
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Verify a savings certificate. Returns { ok, reason } so callers can
|
|
106
|
+
* surface specific failure reasons (HMAC mismatch / Merkle mismatch /
|
|
107
|
+
* arithmetic violation).
|
|
108
|
+
*/
|
|
109
|
+
export function verifySavingsCertificate(cert, decisions, secret) {
|
|
110
|
+
const sec = secret ?? defaultSecret();
|
|
111
|
+
// 1) Arithmetic invariants must hold internally.
|
|
112
|
+
if (cert.totalTokensSaved < 0)
|
|
113
|
+
return { ok: false, reason: "negative totalTokensSaved" };
|
|
114
|
+
if (cert.totalDirectTokens !== cert.totalActualTokens + cert.totalTokensSaved) {
|
|
115
|
+
return { ok: false, reason: "totalDirect != actual + saved" };
|
|
116
|
+
}
|
|
117
|
+
if (cert.decisionCount !== decisions.length) {
|
|
118
|
+
return { ok: false, reason: `decisionCount ${cert.decisionCount} != supplied ${decisions.length}` };
|
|
119
|
+
}
|
|
120
|
+
// 2) Merkle root must match the supplied decisions.
|
|
121
|
+
const recomputedRoot = merkleRoot(decisions.map((d) => d.signature));
|
|
122
|
+
if (recomputedRoot !== cert.merkleRoot) {
|
|
123
|
+
return { ok: false, reason: `Merkle root mismatch (expected ${cert.merkleRoot}, recomputed ${recomputedRoot})` };
|
|
124
|
+
}
|
|
125
|
+
// 3) HMAC must verify (using the same secret).
|
|
126
|
+
const { hmac, ...body } = cert;
|
|
127
|
+
const expected = signCert(body, sec);
|
|
128
|
+
if (expected !== hmac)
|
|
129
|
+
return { ok: false, reason: "HMAC mismatch — forged certificate or wrong secret" };
|
|
130
|
+
return { ok: true };
|
|
131
|
+
}
|
|
132
|
+
/** Render a human-readable summary safe to surface to a procurement dashboard. */
|
|
133
|
+
export function formatCertificate(cert) {
|
|
134
|
+
const days = Math.max(1, Math.round((cert.windowEndMs - cert.windowStartMs) / 86_400_000));
|
|
135
|
+
const lines = [];
|
|
136
|
+
lines.push(`🪙 MNEME PROOF OF SAVING — v${cert.v}`);
|
|
137
|
+
lines.push(` Window: ${new Date(cert.windowStartMs).toISOString().slice(0, 10)} → ${new Date(cert.windowEndMs).toISOString().slice(0, 10)} (${days} days)`);
|
|
138
|
+
lines.push(` Calls governed: ${cert.decisionCount.toLocaleString()}`);
|
|
139
|
+
lines.push(` Tokens that would have shipped direct: ${cert.totalDirectTokens.toLocaleString()}`);
|
|
140
|
+
lines.push(` Tokens actually spent via Governor: ${cert.totalActualTokens.toLocaleString()}`);
|
|
141
|
+
lines.push(` Tokens saved: ${cert.totalTokensSaved.toLocaleString()} (${((cert.totalTokensSaved / Math.max(1, cert.totalDirectTokens)) * 100).toFixed(1)}%)`);
|
|
142
|
+
lines.push(` USD saved (@ ${cert.usdPerToken}/token): $${cert.estUsdSaved.toFixed(2)}`);
|
|
143
|
+
lines.push(` Stage breakdown:`);
|
|
144
|
+
for (const [stage, stats] of Object.entries(cert.stageBreakdown)) {
|
|
145
|
+
if (stats.calls === 0)
|
|
146
|
+
continue;
|
|
147
|
+
lines.push(` Stage ${stage}: ${stats.calls} calls, ${stats.tokensSaved.toLocaleString()} tokens saved`);
|
|
148
|
+
}
|
|
149
|
+
lines.push(` Merkle root: ${cert.merkleRoot.slice(0, 16)}… (${cert.merkleLeafCount} leaves)`);
|
|
150
|
+
lines.push(` HMAC: ${cert.hmac.slice(0, 16)}… (verify with mneme.proof.verify)`);
|
|
151
|
+
return lines.join("\n");
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/proof_of_saving/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proof_of_saving.test.d.ts","sourceRoot":"","sources":["../../src/proof_of_saving/proof_of_saving.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { mintSavingsCertificate, verifySavingsCertificate, formatCertificate, } from "./index.js";
|
|
3
|
+
const SECRET = "proof-test-secret-77";
|
|
4
|
+
function makeDecisions(n, fixedSaving = 100, fixedActual = 50) {
|
|
5
|
+
const out = [];
|
|
6
|
+
for (let i = 0; i < n; i++) {
|
|
7
|
+
out.push({
|
|
8
|
+
signature: `sig-${i}-${Math.random().toString(36).slice(2, 10)}`,
|
|
9
|
+
tokensUsedActual: fixedActual,
|
|
10
|
+
estTokensSavedVsDirect: fixedSaving,
|
|
11
|
+
stage: ((i % 4) + 1),
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
describe("v2.19.42 PROOF OF SAVING · mint + verify round trip", () => {
|
|
17
|
+
it("mints a certificate with correct arithmetic", () => {
|
|
18
|
+
const decisions = makeDecisions(10);
|
|
19
|
+
const cert = mintSavingsCertificate({ decisions, windowStartMs: 0, windowEndMs: 1000, secret: SECRET });
|
|
20
|
+
expect(cert.decisionCount).toBe(10);
|
|
21
|
+
expect(cert.totalActualTokens).toBe(500);
|
|
22
|
+
expect(cert.totalTokensSaved).toBe(1000);
|
|
23
|
+
expect(cert.totalDirectTokens).toBe(1500);
|
|
24
|
+
expect(cert.merkleLeafCount).toBe(10);
|
|
25
|
+
expect(cert.hmac.length).toBe(64);
|
|
26
|
+
});
|
|
27
|
+
it("verify returns ok on a fresh cert", () => {
|
|
28
|
+
const decisions = makeDecisions(5);
|
|
29
|
+
const cert = mintSavingsCertificate({ decisions, windowStartMs: 0, windowEndMs: 1, secret: SECRET });
|
|
30
|
+
expect(verifySavingsCertificate(cert, decisions, SECRET).ok).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
it("verify detects tampered HMAC", () => {
|
|
33
|
+
const decisions = makeDecisions(3);
|
|
34
|
+
const cert = mintSavingsCertificate({ decisions, windowStartMs: 0, windowEndMs: 1, secret: SECRET });
|
|
35
|
+
const tampered = { ...cert, totalTokensSaved: cert.totalTokensSaved + 100 };
|
|
36
|
+
expect(verifySavingsCertificate(tampered, decisions, SECRET).ok).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
it("verify detects swapped decisions (Merkle mismatch)", () => {
|
|
39
|
+
const a = makeDecisions(3);
|
|
40
|
+
const cert = mintSavingsCertificate({ decisions: a, windowStartMs: 0, windowEndMs: 1, secret: SECRET });
|
|
41
|
+
const b = makeDecisions(3);
|
|
42
|
+
const r = verifySavingsCertificate(cert, b, SECRET);
|
|
43
|
+
expect(r.ok).toBe(false);
|
|
44
|
+
expect(r.reason).toContain("Merkle");
|
|
45
|
+
});
|
|
46
|
+
it("verify detects wrong secret", () => {
|
|
47
|
+
const decisions = makeDecisions(2);
|
|
48
|
+
const cert = mintSavingsCertificate({ decisions, windowStartMs: 0, windowEndMs: 1, secret: SECRET });
|
|
49
|
+
expect(verifySavingsCertificate(cert, decisions, "wrong-secret").ok).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
it("empty decisions list still produces a valid cert (zero savings)", () => {
|
|
52
|
+
const cert = mintSavingsCertificate({ decisions: [], windowStartMs: 0, windowEndMs: 1, secret: SECRET });
|
|
53
|
+
expect(cert.decisionCount).toBe(0);
|
|
54
|
+
expect(cert.totalTokensSaved).toBe(0);
|
|
55
|
+
expect(verifySavingsCertificate(cert, [], SECRET).ok).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
it("USD estimate uses caller-supplied usdPerToken", () => {
|
|
58
|
+
const cert = mintSavingsCertificate({ decisions: makeDecisions(10, 1000, 0), windowStartMs: 0, windowEndMs: 1, usdPerToken: 0.00001, secret: SECRET });
|
|
59
|
+
expect(cert.estUsdSaved).toBe(10000 * 0.00001);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe("v2.19.42 PROOF OF SAVING · stage breakdown + format", () => {
|
|
63
|
+
it("stage breakdown counts calls and tokens per stage", () => {
|
|
64
|
+
const decisions = makeDecisions(20);
|
|
65
|
+
const cert = mintSavingsCertificate({ decisions, windowStartMs: 0, windowEndMs: 1, secret: SECRET });
|
|
66
|
+
const total = Object.values(cert.stageBreakdown).reduce((s, b) => s + b.calls, 0);
|
|
67
|
+
expect(total).toBe(20);
|
|
68
|
+
});
|
|
69
|
+
it("formatCertificate produces multi-line human-readable text", () => {
|
|
70
|
+
const cert = mintSavingsCertificate({ decisions: makeDecisions(3), windowStartMs: 0, windowEndMs: 1, secret: SECRET });
|
|
71
|
+
const txt = formatCertificate(cert);
|
|
72
|
+
expect(txt).toContain("PROOF OF SAVING");
|
|
73
|
+
expect(txt).toContain("Tokens saved");
|
|
74
|
+
expect(txt).toContain("Merkle root");
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe("v2.19.42 PROOF OF SAVING · 1000-iter fuzz", () => {
|
|
78
|
+
it("mint + verify cycle never throws on random batches", () => {
|
|
79
|
+
for (let i = 0; i < 1000; i++) {
|
|
80
|
+
const n = Math.floor(Math.random() * 30);
|
|
81
|
+
const decisions = makeDecisions(n, Math.floor(Math.random() * 1000), Math.floor(Math.random() * 500));
|
|
82
|
+
const cert = mintSavingsCertificate({ decisions, windowStartMs: 0, windowEndMs: i, secret: SECRET, nowMs: i });
|
|
83
|
+
expect(verifySavingsCertificate(cert, decisions, SECRET).ok).toBe(true);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
//# sourceMappingURL=proof_of_saving.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proof_of_saving.test.js","sourceRoot":"","sources":["../../src/proof_of_saving/proof_of_saving.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acgv_explain.d.ts","sourceRoot":"","sources":["../../src/squadron/acgv_explain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,YAAY,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,CAAC;IACnD,sDAAsD;IACtD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,0DAA0D;AAC1D,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAyE3E;
|
|
1
|
+
{"version":3,"file":"acgv_explain.d.ts","sourceRoot":"","sources":["../../src/squadron/acgv_explain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,YAAY,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,CAAC;IACnD,sDAAsD;IACtD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,0DAA0D;AAC1D,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAyE3E;AA+BD,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAe7E"}
|
|
@@ -84,17 +84,47 @@ export function explain(result, claim) {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* v2.19.43 N8 fix — presentation consistency invariant.
|
|
89
|
+
*
|
|
90
|
+
* User audit (2026-05-18): `mneme verify "Mneme is written in Rust AND
|
|
91
|
+
* mneme.truth.forensic is registered"` rendered:
|
|
92
|
+
* 🌑 IMPOSSIBLE -- REFUTED -- language=rust is impossible ...
|
|
93
|
+
* ...
|
|
94
|
+
* ✅ TRUTH-FORENSIC verdict: ACCEPTED. Every assertion grounded ...
|
|
95
|
+
*
|
|
96
|
+
* The headline used trafficLight=black (🌑 IMPOSSIBLE) but the plain
|
|
97
|
+
* text leaked a ✅ from the appended forensic explanation. Both emoji
|
|
98
|
+
* present → user confused about which verdict won.
|
|
99
|
+
*
|
|
100
|
+
* Invariant: the headline emoji is canonical; any conflicting
|
|
101
|
+
* verdict glyphs in the plain block get neutralised to a neutral mark
|
|
102
|
+
* (●). The verdict text itself is preserved so power-users still see
|
|
103
|
+
* "TRUTH-FORENSIC verdict: ACCEPTED" — only the contradicting emoji
|
|
104
|
+
* is stripped.
|
|
105
|
+
*/
|
|
106
|
+
function neutraliseConflictingEmoji(plain, headlineLight) {
|
|
107
|
+
if (!plain)
|
|
108
|
+
return plain;
|
|
109
|
+
// Map every other-traffic-light glyph to a neutral bullet.
|
|
110
|
+
const neutralise = (glyph) => `●`;
|
|
111
|
+
const allow = { green: "✅", yellow: "⚠️", red: "❌", black: "🌑" };
|
|
112
|
+
const keep = allow[headlineLight];
|
|
113
|
+
return plain
|
|
114
|
+
.replace(/✅|⚠️|❌|🌑/g, (m) => (m === keep ? m : neutralise(m)));
|
|
115
|
+
}
|
|
87
116
|
/** Format the explained verdict for terminal output. ~10 lines, scannable. */
|
|
88
117
|
export function renderExplained(ev, claim) {
|
|
89
118
|
const glyph = ev.trafficLight === "green" ? "✅" : ev.trafficLight === "yellow" ? "⚠️" : ev.trafficLight === "red" ? "❌" : "🌑";
|
|
90
119
|
const tone = ev.trafficLight === "green" ? "TRUSTWORTHY" : ev.trafficLight === "yellow" ? "MIXED" : ev.trafficLight === "red" ? "REFUTED" : "IMPOSSIBLE";
|
|
120
|
+
const cleanPlain = neutraliseConflictingEmoji(ev.plain, ev.trafficLight);
|
|
91
121
|
return [
|
|
92
122
|
`${glyph} ${tone} -- ${ev.headline}`,
|
|
93
123
|
``,
|
|
94
124
|
`Claim: "${claim.length > 90 ? claim.slice(0, 87) + "..." : claim}"`,
|
|
95
125
|
``,
|
|
96
126
|
`What this means:`,
|
|
97
|
-
` ${
|
|
127
|
+
` ${cleanPlain}`,
|
|
98
128
|
``,
|
|
99
129
|
`Next step:`,
|
|
100
130
|
` -> ${ev.nextAction}`,
|