@mneme-ai/core 1.98.0 → 2.0.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.
- package/dist/bloodline/bloodline.test.d.ts +2 -0
- package/dist/bloodline/bloodline.test.d.ts.map +1 -0
- package/dist/bloodline/bloodline.test.js +96 -0
- package/dist/bloodline/bloodline.test.js.map +1 -0
- package/dist/bloodline/index.d.ts +124 -0
- package/dist/bloodline/index.d.ts.map +1 -0
- package/dist/bloodline/index.js +179 -0
- package/dist/bloodline/index.js.map +1 -0
- package/dist/dream/dream.test.d.ts +2 -0
- package/dist/dream/dream.test.d.ts.map +1 -0
- package/dist/dream/dream.test.js +61 -0
- package/dist/dream/dream.test.js.map +1 -0
- package/dist/dream/index.d.ts +59 -0
- package/dist/dream/index.d.ts.map +1 -0
- package/dist/dream/index.js +117 -0
- package/dist/dream/index.js.map +1 -0
- package/dist/flash/devils_advocate.d.ts +66 -0
- package/dist/flash/devils_advocate.d.ts.map +1 -0
- package/dist/flash/devils_advocate.js +154 -0
- package/dist/flash/devils_advocate.js.map +1 -0
- package/dist/flash/flash.d.ts +50 -0
- package/dist/flash/flash.d.ts.map +1 -0
- package/dist/flash/flash.js +67 -0
- package/dist/flash/flash.js.map +1 -0
- package/dist/flash/flash.test.d.ts +2 -0
- package/dist/flash/flash.test.d.ts.map +1 -0
- package/dist/flash/flash.test.js +221 -0
- package/dist/flash/flash.test.js.map +1 -0
- package/dist/flash/grounding.d.ts +55 -0
- package/dist/flash/grounding.d.ts.map +1 -0
- package/dist/flash/grounding.js +144 -0
- package/dist/flash/grounding.js.map +1 -0
- package/dist/flash/index.d.ts +18 -0
- package/dist/flash/index.d.ts.map +1 -0
- package/dist/flash/index.js +18 -0
- package/dist/flash/index.js.map +1 -0
- package/dist/flash/predictive.d.ts +44 -0
- package/dist/flash/predictive.d.ts.map +1 -0
- package/dist/flash/predictive.js +76 -0
- package/dist/flash/predictive.js.map +1 -0
- package/dist/flash/veracity.d.ts +99 -0
- package/dist/flash/veracity.d.ts.map +1 -0
- package/dist/flash/veracity.js +107 -0
- package/dist/flash/veracity.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -1
- package/dist/mutiny/index.d.ts +55 -0
- package/dist/mutiny/index.d.ts.map +1 -0
- package/dist/mutiny/index.js +67 -0
- package/dist/mutiny/index.js.map +1 -0
- package/dist/mutiny/mutiny.test.d.ts +2 -0
- package/dist/mutiny/mutiny.test.d.ts.map +1 -0
- package/dist/mutiny/mutiny.test.js +59 -0
- package/dist/mutiny/mutiny.test.js.map +1 -0
- package/dist/prophecy/index.d.ts +88 -0
- package/dist/prophecy/index.d.ts.map +1 -0
- package/dist/prophecy/index.js +94 -0
- package/dist/prophecy/index.js.map +1 -0
- package/dist/prophecy/prophecy.test.d.ts +2 -0
- package/dist/prophecy/prophecy.test.d.ts.map +1 -0
- package/dist/prophecy/prophecy.test.js +112 -0
- package/dist/prophecy/prophecy.test.js.map +1 -0
- package/dist/rainbow/passport.d.ts +28 -5
- package/dist/rainbow/passport.d.ts.map +1 -1
- package/dist/rainbow/passport.js +44 -9
- package/dist/rainbow/passport.js.map +1 -1
- package/dist/rainbow/passport_v99.test.d.ts +2 -0
- package/dist/rainbow/passport_v99.test.d.ts.map +1 -0
- package/dist/rainbow/passport_v99.test.js +53 -0
- package/dist/rainbow/passport_v99.test.js.map +1 -0
- package/dist/xray/index.d.ts +44 -0
- package/dist/xray/index.d.ts.map +1 -0
- package/dist/xray/index.js +139 -0
- package/dist/xray/index.js.map +1 -0
- package/dist/xray/xray.test.d.ts +2 -0
- package/dist/xray/xray.test.d.ts.map +1 -0
- package/dist/xray/xray.test.js +57 -0
- package/dist/xray/xray.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.0.0 -- PROPHECY LETTERS · time-locked cross-version messages
|
|
3
|
+
*
|
|
4
|
+
* Mneme v2.0 writes a letter to its future self (or to a different
|
|
5
|
+
* machine running a different Mneme version). The letter is sealed
|
|
6
|
+
* with the user's HMAC secret + a target-version gate. When a future
|
|
7
|
+
* Mneme version that meets the gate opens the letter, it can grade
|
|
8
|
+
* its past self's predictions:
|
|
9
|
+
*
|
|
10
|
+
* "Past Mneme (v2.0, 2026-05-13) predicted: 'by v2.5 we'll have
|
|
11
|
+
* real IBM Quantum wiring.' Current Mneme (v2.5, 2026-09-01) checks
|
|
12
|
+
* its own state: TRUE. Time-consistency score updated."
|
|
13
|
+
*
|
|
14
|
+
* Pure function. Deterministic. Composable with PASSPORT + audit log.
|
|
15
|
+
*/
|
|
16
|
+
export interface Prophecy {
|
|
17
|
+
/** Stable id. */
|
|
18
|
+
id: string;
|
|
19
|
+
/** Version (semver-ish) that wrote the letter. */
|
|
20
|
+
fromVersion: string;
|
|
21
|
+
/** Minimum semver-ish version that may open the letter. */
|
|
22
|
+
toMinVersion: string;
|
|
23
|
+
/** Wall-clock when sealed. */
|
|
24
|
+
sealedAt: number;
|
|
25
|
+
/** Earliest wall-clock at which the letter may be opened. */
|
|
26
|
+
earliestOpenAt: number;
|
|
27
|
+
/** Free-form letter body. */
|
|
28
|
+
text: string;
|
|
29
|
+
/** Topics — used by grading later. */
|
|
30
|
+
predictions: Array<{
|
|
31
|
+
topic: string;
|
|
32
|
+
claim: string;
|
|
33
|
+
verifyHint: string;
|
|
34
|
+
}>;
|
|
35
|
+
/** HMAC signature over (fromVersion || toMinVersion || sealedAt || earliestOpenAt || text || predictions). */
|
|
36
|
+
signature: string;
|
|
37
|
+
/** Public key fingerprint. */
|
|
38
|
+
keyFingerprint: string;
|
|
39
|
+
}
|
|
40
|
+
export interface SealInput {
|
|
41
|
+
fromVersion: string;
|
|
42
|
+
toMinVersion: string;
|
|
43
|
+
text: string;
|
|
44
|
+
predictions: Array<{
|
|
45
|
+
topic: string;
|
|
46
|
+
claim: string;
|
|
47
|
+
verifyHint: string;
|
|
48
|
+
}>;
|
|
49
|
+
/** Earliest wall-clock to permit opening. Default sealedAt + 30 days. */
|
|
50
|
+
earliestOpenAt?: number;
|
|
51
|
+
/** HMAC secret. */
|
|
52
|
+
secret: Buffer;
|
|
53
|
+
}
|
|
54
|
+
export declare function sealProphecy(input: SealInput): Prophecy;
|
|
55
|
+
export type ProphecyVerdict = "SEALED" | "OPENABLE" | "TAMPERED" | "WRONG_KEY";
|
|
56
|
+
export interface UnsealResult {
|
|
57
|
+
verdict: ProphecyVerdict;
|
|
58
|
+
reason: string;
|
|
59
|
+
prophecy?: Prophecy;
|
|
60
|
+
}
|
|
61
|
+
export interface UnsealInput {
|
|
62
|
+
prophecy: Prophecy;
|
|
63
|
+
currentVersion: string;
|
|
64
|
+
secret: Buffer;
|
|
65
|
+
now?: number;
|
|
66
|
+
}
|
|
67
|
+
export declare function unsealProphecy(input: UnsealInput): UnsealResult;
|
|
68
|
+
export interface GradeInput {
|
|
69
|
+
prophecy: Prophecy;
|
|
70
|
+
/** User's verdict on each prediction: did it come true? */
|
|
71
|
+
observations: Array<{
|
|
72
|
+
topic: string;
|
|
73
|
+
cameTrue: boolean;
|
|
74
|
+
}>;
|
|
75
|
+
}
|
|
76
|
+
export interface GradeResult {
|
|
77
|
+
total: number;
|
|
78
|
+
correct: number;
|
|
79
|
+
consistency: number;
|
|
80
|
+
byTopic: Array<{
|
|
81
|
+
topic: string;
|
|
82
|
+
predicted: string;
|
|
83
|
+
cameTrue: boolean;
|
|
84
|
+
}>;
|
|
85
|
+
}
|
|
86
|
+
export declare function gradeProphecy(input: GradeInput): GradeResult;
|
|
87
|
+
export declare function formatProphecyPulseLine(p: Prophecy): string;
|
|
88
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prophecy/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,MAAM,WAAW,QAAQ;IACvB,iBAAiB;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,YAAY,EAAE,MAAM,CAAC;IACrB,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,cAAc,EAAE,MAAM,CAAC;IACvB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,WAAW,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzE,8GAA8G;IAC9G,SAAS,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzE,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAYD,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAcvD;AAED,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,CAAC;AAE/E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,eAAe,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAcD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,CAkB/D;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,2DAA2D;IAC3D,YAAY,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACzE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAe5D;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAE3D"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.0.0 -- PROPHECY LETTERS · time-locked cross-version messages
|
|
3
|
+
*
|
|
4
|
+
* Mneme v2.0 writes a letter to its future self (or to a different
|
|
5
|
+
* machine running a different Mneme version). The letter is sealed
|
|
6
|
+
* with the user's HMAC secret + a target-version gate. When a future
|
|
7
|
+
* Mneme version that meets the gate opens the letter, it can grade
|
|
8
|
+
* its past self's predictions:
|
|
9
|
+
*
|
|
10
|
+
* "Past Mneme (v2.0, 2026-05-13) predicted: 'by v2.5 we'll have
|
|
11
|
+
* real IBM Quantum wiring.' Current Mneme (v2.5, 2026-09-01) checks
|
|
12
|
+
* its own state: TRUE. Time-consistency score updated."
|
|
13
|
+
*
|
|
14
|
+
* Pure function. Deterministic. Composable with PASSPORT + audit log.
|
|
15
|
+
*/
|
|
16
|
+
import { createHmac, createHash } from "node:crypto";
|
|
17
|
+
function fpSecret(secret) {
|
|
18
|
+
return createHash("sha256").update(secret).digest("hex").slice(0, 16);
|
|
19
|
+
}
|
|
20
|
+
function computeSig(p, secret) {
|
|
21
|
+
const h = createHmac("sha256", secret);
|
|
22
|
+
h.update([p.fromVersion, p.toMinVersion, p.sealedAt, p.earliestOpenAt, p.text, JSON.stringify(p.predictions)].join("|"));
|
|
23
|
+
return h.digest("hex");
|
|
24
|
+
}
|
|
25
|
+
export function sealProphecy(input) {
|
|
26
|
+
const sealedAt = Date.now();
|
|
27
|
+
const earliestOpenAt = input.earliestOpenAt ?? sealedAt + 30 * 24 * 60 * 60 * 1000;
|
|
28
|
+
const base = {
|
|
29
|
+
fromVersion: input.fromVersion,
|
|
30
|
+
toMinVersion: input.toMinVersion,
|
|
31
|
+
sealedAt,
|
|
32
|
+
earliestOpenAt,
|
|
33
|
+
text: input.text,
|
|
34
|
+
predictions: input.predictions,
|
|
35
|
+
};
|
|
36
|
+
const signature = computeSig(base, input.secret);
|
|
37
|
+
const id = createHash("sha256").update(`${input.fromVersion}|${sealedAt}|${signature.slice(0, 16)}`).digest("hex").slice(0, 12);
|
|
38
|
+
return { id, ...base, signature, keyFingerprint: fpSecret(input.secret) };
|
|
39
|
+
}
|
|
40
|
+
function semverGe(a, b) {
|
|
41
|
+
const pa = a.split(".").map((n) => parseInt(n, 10));
|
|
42
|
+
const pb = b.split(".").map((n) => parseInt(n, 10));
|
|
43
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
44
|
+
const ai = pa[i] ?? 0;
|
|
45
|
+
const bi = pb[i] ?? 0;
|
|
46
|
+
if (ai > bi)
|
|
47
|
+
return true;
|
|
48
|
+
if (ai < bi)
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
export function unsealProphecy(input) {
|
|
54
|
+
const now = input.now ?? Date.now();
|
|
55
|
+
if (fpSecret(input.secret) !== input.prophecy.keyFingerprint) {
|
|
56
|
+
return { verdict: "WRONG_KEY", reason: `secret fingerprint mismatch` };
|
|
57
|
+
}
|
|
58
|
+
if (!semverGe(input.currentVersion, input.prophecy.toMinVersion)) {
|
|
59
|
+
return { verdict: "SEALED", reason: `current version ${input.currentVersion} < required ${input.prophecy.toMinVersion}` };
|
|
60
|
+
}
|
|
61
|
+
if (now < input.prophecy.earliestOpenAt) {
|
|
62
|
+
return { verdict: "SEALED", reason: `time-lock not expired (open at ${new Date(input.prophecy.earliestOpenAt).toISOString()})` };
|
|
63
|
+
}
|
|
64
|
+
const { signature: _drop, id: _drop2, keyFingerprint: _drop3, ...rest } = input.prophecy;
|
|
65
|
+
void _drop;
|
|
66
|
+
void _drop2;
|
|
67
|
+
void _drop3;
|
|
68
|
+
const expected = computeSig(rest, input.secret);
|
|
69
|
+
if (expected !== input.prophecy.signature) {
|
|
70
|
+
return { verdict: "TAMPERED", reason: `signature mismatch` };
|
|
71
|
+
}
|
|
72
|
+
return { verdict: "OPENABLE", reason: "all checks pass", prophecy: input.prophecy };
|
|
73
|
+
}
|
|
74
|
+
export function gradeProphecy(input) {
|
|
75
|
+
const obsByTopic = new Map();
|
|
76
|
+
for (const o of input.observations)
|
|
77
|
+
obsByTopic.set(o.topic, o.cameTrue);
|
|
78
|
+
const byTopic = input.prophecy.predictions.map((p) => ({
|
|
79
|
+
topic: p.topic,
|
|
80
|
+
predicted: p.claim,
|
|
81
|
+
cameTrue: obsByTopic.get(p.topic) ?? false,
|
|
82
|
+
}));
|
|
83
|
+
const correct = byTopic.filter((b) => b.cameTrue).length;
|
|
84
|
+
return {
|
|
85
|
+
total: byTopic.length,
|
|
86
|
+
correct,
|
|
87
|
+
consistency: byTopic.length > 0 ? correct / byTopic.length : 0,
|
|
88
|
+
byTopic,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export function formatProphecyPulseLine(p) {
|
|
92
|
+
return `PROPHECY · ${p.id} · ${p.fromVersion}→${p.toMinVersion} · ${p.predictions.length} predictions`;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prophecy/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prophecy.test.d.ts","sourceRoot":"","sources":["../../src/prophecy/prophecy.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { sealProphecy, unsealProphecy, gradeProphecy, formatProphecyPulseLine } from "./index.js";
|
|
4
|
+
describe("v2.0 PROPHECY LETTERS · time-locked cross-version", () => {
|
|
5
|
+
const secret = randomBytes(32);
|
|
6
|
+
it("seal returns envelope with id + signature + keyFingerprint", () => {
|
|
7
|
+
const p = sealProphecy({
|
|
8
|
+
fromVersion: "2.0.0",
|
|
9
|
+
toMinVersion: "2.5.0",
|
|
10
|
+
text: "By v2.5 we'll have IBM Quantum wired.",
|
|
11
|
+
predictions: [{ topic: "ibm-quantum", claim: "wired by v2.5", verifyHint: "check qx_bridge providers.ts for runIbm impl" }],
|
|
12
|
+
secret,
|
|
13
|
+
});
|
|
14
|
+
expect(p.id).toMatch(/^[a-f0-9]{12}$/);
|
|
15
|
+
expect(p.signature.length).toBe(64);
|
|
16
|
+
expect(p.keyFingerprint).toBeTruthy();
|
|
17
|
+
});
|
|
18
|
+
it("SEALED verdict when current version < required", () => {
|
|
19
|
+
const p = sealProphecy({
|
|
20
|
+
fromVersion: "2.0.0",
|
|
21
|
+
toMinVersion: "2.5.0",
|
|
22
|
+
text: "x",
|
|
23
|
+
predictions: [],
|
|
24
|
+
secret,
|
|
25
|
+
earliestOpenAt: Date.now() - 1000, // time-lock already past
|
|
26
|
+
});
|
|
27
|
+
const r = unsealProphecy({ prophecy: p, currentVersion: "2.0.0", secret });
|
|
28
|
+
expect(r.verdict).toBe("SEALED");
|
|
29
|
+
expect(r.reason).toContain("version");
|
|
30
|
+
});
|
|
31
|
+
it("SEALED verdict when time-lock not yet expired", () => {
|
|
32
|
+
const p = sealProphecy({
|
|
33
|
+
fromVersion: "2.0.0",
|
|
34
|
+
toMinVersion: "2.0.0",
|
|
35
|
+
text: "x",
|
|
36
|
+
predictions: [],
|
|
37
|
+
secret,
|
|
38
|
+
earliestOpenAt: Date.now() + 1000 * 60 * 60,
|
|
39
|
+
});
|
|
40
|
+
const r = unsealProphecy({ prophecy: p, currentVersion: "2.5.0", secret });
|
|
41
|
+
expect(r.verdict).toBe("SEALED");
|
|
42
|
+
expect(r.reason).toContain("time-lock");
|
|
43
|
+
});
|
|
44
|
+
it("OPENABLE verdict when version AND time gate pass + signature valid", () => {
|
|
45
|
+
const p = sealProphecy({
|
|
46
|
+
fromVersion: "2.0.0",
|
|
47
|
+
toMinVersion: "2.0.0",
|
|
48
|
+
text: "x",
|
|
49
|
+
predictions: [],
|
|
50
|
+
secret,
|
|
51
|
+
earliestOpenAt: Date.now() - 1000,
|
|
52
|
+
});
|
|
53
|
+
const r = unsealProphecy({ prophecy: p, currentVersion: "2.5.0", secret });
|
|
54
|
+
expect(r.verdict).toBe("OPENABLE");
|
|
55
|
+
expect(r.prophecy).toBeDefined();
|
|
56
|
+
});
|
|
57
|
+
it("TAMPERED verdict when signature was forged", () => {
|
|
58
|
+
const p = sealProphecy({
|
|
59
|
+
fromVersion: "2.0.0",
|
|
60
|
+
toMinVersion: "2.0.0",
|
|
61
|
+
text: "x",
|
|
62
|
+
predictions: [],
|
|
63
|
+
secret,
|
|
64
|
+
earliestOpenAt: Date.now() - 1000,
|
|
65
|
+
});
|
|
66
|
+
p.signature = "0".repeat(64);
|
|
67
|
+
const r = unsealProphecy({ prophecy: p, currentVersion: "2.5.0", secret });
|
|
68
|
+
expect(r.verdict).toBe("TAMPERED");
|
|
69
|
+
});
|
|
70
|
+
it("WRONG_KEY verdict on wrong secret", () => {
|
|
71
|
+
const p = sealProphecy({
|
|
72
|
+
fromVersion: "2.0.0",
|
|
73
|
+
toMinVersion: "2.0.0",
|
|
74
|
+
text: "x",
|
|
75
|
+
predictions: [],
|
|
76
|
+
secret,
|
|
77
|
+
earliestOpenAt: Date.now() - 1000,
|
|
78
|
+
});
|
|
79
|
+
const wrong = randomBytes(32);
|
|
80
|
+
const r = unsealProphecy({ prophecy: p, currentVersion: "2.5.0", secret: wrong });
|
|
81
|
+
expect(r.verdict).toBe("WRONG_KEY");
|
|
82
|
+
});
|
|
83
|
+
it("gradeProphecy computes consistency 0..1", () => {
|
|
84
|
+
const p = sealProphecy({
|
|
85
|
+
fromVersion: "2.0.0",
|
|
86
|
+
toMinVersion: "2.5.0",
|
|
87
|
+
text: "x",
|
|
88
|
+
predictions: [
|
|
89
|
+
{ topic: "ibm-quantum", claim: "wired", verifyHint: "" },
|
|
90
|
+
{ topic: "dwave-qubo", claim: "wired", verifyHint: "" },
|
|
91
|
+
{ topic: "ggwave-audio", claim: "shipped", verifyHint: "" },
|
|
92
|
+
],
|
|
93
|
+
secret,
|
|
94
|
+
});
|
|
95
|
+
const r = gradeProphecy({
|
|
96
|
+
prophecy: p,
|
|
97
|
+
observations: [
|
|
98
|
+
{ topic: "ibm-quantum", cameTrue: true },
|
|
99
|
+
{ topic: "dwave-qubo", cameTrue: false },
|
|
100
|
+
{ topic: "ggwave-audio", cameTrue: true },
|
|
101
|
+
],
|
|
102
|
+
});
|
|
103
|
+
expect(r.total).toBe(3);
|
|
104
|
+
expect(r.correct).toBe(2);
|
|
105
|
+
expect(r.consistency).toBeCloseTo(2 / 3, 3);
|
|
106
|
+
});
|
|
107
|
+
it("formatProphecyPulseLine produces compact summary", () => {
|
|
108
|
+
const p = sealProphecy({ fromVersion: "2.0.0", toMinVersion: "2.5.0", text: "x", predictions: [], secret });
|
|
109
|
+
expect(formatProphecyPulseLine(p)).toContain("PROPHECY");
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
//# sourceMappingURL=prophecy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prophecy.test.js","sourceRoot":"","sources":["../../src/prophecy/prophecy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -55,7 +55,9 @@ export interface PassportEnvelope {
|
|
|
55
55
|
holder: string;
|
|
56
56
|
/** Issuance timestamp. */
|
|
57
57
|
issuedAt: number;
|
|
58
|
-
/** Expiration timestamp
|
|
58
|
+
/** Expiration timestamp.
|
|
59
|
+
* v1.99 default = `Number.MAX_SAFE_INTEGER` (effectively eternal — user-revocable).
|
|
60
|
+
* Caller can override with a finite ttl for one-time / time-boxed delegation. */
|
|
59
61
|
expiresAt: number;
|
|
60
62
|
/** Last N entries — order matters; newer first. */
|
|
61
63
|
entries: PassportEntry[];
|
|
@@ -67,6 +69,10 @@ export interface PassportEnvelope {
|
|
|
67
69
|
alg: "HMAC-SHA256";
|
|
68
70
|
/** Public key fingerprint (NOT the secret) — used as identity lookup. */
|
|
69
71
|
keyFingerprint: string;
|
|
72
|
+
/** Revocation list: passport ids the holder has explicitly invalidated. */
|
|
73
|
+
revoked?: string[];
|
|
74
|
+
/** Passport id (random 12-hex). Used by revocation. */
|
|
75
|
+
id: string;
|
|
70
76
|
}
|
|
71
77
|
/** Hash a list of entries deterministically for tamper-evidence. */
|
|
72
78
|
export declare function fingerprintEntries(entries: readonly PassportEntry[]): string;
|
|
@@ -75,13 +81,22 @@ export interface IssuePassportInput {
|
|
|
75
81
|
entries: readonly PassportEntry[];
|
|
76
82
|
/** User's local HMAC secret. Loaded from .mneme/passport.secret typically. */
|
|
77
83
|
secret: Buffer;
|
|
78
|
-
/** TTL in days. Default
|
|
84
|
+
/** TTL in days. Default: ETERNAL (v1.99). Pass a finite number for one-time
|
|
85
|
+
* delegation; otherwise the passport is valid until explicitly revoked. */
|
|
79
86
|
ttlDays?: number;
|
|
80
87
|
/** Cap on entries included. Default 50. */
|
|
81
88
|
maxEntries?: number;
|
|
89
|
+
/** Revocation list to include. Default []. */
|
|
90
|
+
revoked?: string[];
|
|
82
91
|
}
|
|
83
|
-
/** Issue a fresh passport.
|
|
92
|
+
/** Issue a fresh passport. Default = eternal. HMAC-signs.
|
|
93
|
+
* Trims to maxEntries (newest first). */
|
|
84
94
|
export declare function issuePassport(input: IssuePassportInput): PassportEnvelope;
|
|
95
|
+
/** Revoke a passport by id. Returns a NEW envelope with the revocation
|
|
96
|
+
* list updated; re-signs with the same secret. The old passport keeps
|
|
97
|
+
* its signature but verifiers that hold the new envelope's revoked[]
|
|
98
|
+
* list will reject the old id. */
|
|
99
|
+
export declare function revokePassport(envelope: PassportEnvelope, revokeId: string, secret: Buffer): PassportEnvelope;
|
|
85
100
|
export type VerificationVerdict = "VALID" | "EXPIRED" | "TAMPERED" | "WRONG_KEY";
|
|
86
101
|
export interface VerificationResult {
|
|
87
102
|
verdict: VerificationVerdict;
|
|
@@ -90,8 +105,16 @@ export interface VerificationResult {
|
|
|
90
105
|
/** True if verdict is VALID. Convenience. */
|
|
91
106
|
ok: boolean;
|
|
92
107
|
}
|
|
93
|
-
|
|
94
|
-
export
|
|
108
|
+
export type VerificationVerdictV99 = VerificationVerdict | "REVOKED";
|
|
109
|
+
export interface VerificationResultV99 {
|
|
110
|
+
verdict: VerificationVerdictV99;
|
|
111
|
+
reason: string;
|
|
112
|
+
ok: boolean;
|
|
113
|
+
}
|
|
114
|
+
/** Verify a passport using the same secret it was signed with.
|
|
115
|
+
* Also checks the envelope's revocation list — if the passport id is in
|
|
116
|
+
* envelope.revoked[], verdict is REVOKED. */
|
|
117
|
+
export declare function verifyPassport(envelope: PassportEnvelope, secret: Buffer): VerificationResultV99;
|
|
95
118
|
/** Serialize to a compact JSON string suitable for pasting into ANY AI's
|
|
96
119
|
* chat box. Includes a header comment so the AI knows what it is. */
|
|
97
120
|
export declare function serializePassport(envelope: PassportEnvelope): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"passport.d.ts","sourceRoot":"","sources":["../../src/rainbow/passport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAIH,MAAM,WAAW,aAAa;IAC5B,iBAAiB;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,8CAA8C;IAC9C,EAAE,EAAE,MAAM,CAAC;IACX,yCAAyC;IACzC,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAC;IAClE,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB
|
|
1
|
+
{"version":3,"file":"passport.d.ts","sourceRoot":"","sources":["../../src/rainbow/passport.ts"],"names":[],"mappings":"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"}
|
package/dist/rainbow/passport.js
CHANGED
|
@@ -56,16 +56,20 @@ function computeSignature(holder, issuedAt, expiresAt, entriesHash, secret) {
|
|
|
56
56
|
function fingerprintSecret(secret) {
|
|
57
57
|
return createHash("sha256").update(secret).digest("hex").slice(0, 16);
|
|
58
58
|
}
|
|
59
|
-
/** Issue a fresh passport.
|
|
59
|
+
/** Issue a fresh passport. Default = eternal. HMAC-signs.
|
|
60
|
+
* Trims to maxEntries (newest first). */
|
|
60
61
|
export function issuePassport(input) {
|
|
61
|
-
const ttlDays = input.ttlDays ?? 90;
|
|
62
62
|
const maxEntries = input.maxEntries ?? 50;
|
|
63
63
|
const issuedAt = Date.now();
|
|
64
|
-
|
|
64
|
+
// v1.99: default eternal. User explicitly revokes via the revocation list.
|
|
65
|
+
const expiresAt = input.ttlDays !== undefined ? issuedAt + input.ttlDays * 24 * 60 * 60 * 1000 : Number.MAX_SAFE_INTEGER;
|
|
65
66
|
const sorted = [...input.entries].sort((a, b) => b.ts - a.ts).slice(0, maxEntries);
|
|
66
67
|
const entriesHash = fingerprintEntries(sorted);
|
|
67
68
|
const signature = computeSignature(input.holder, issuedAt, expiresAt, entriesHash, input.secret);
|
|
69
|
+
// Deterministic id from (holder + issuedAt) for revocation lookup.
|
|
70
|
+
const id = createHash("sha256").update(`${input.holder}|${issuedAt}`).digest("hex").slice(0, 12);
|
|
68
71
|
return {
|
|
72
|
+
id,
|
|
69
73
|
holder: input.holder,
|
|
70
74
|
issuedAt,
|
|
71
75
|
expiresAt,
|
|
@@ -74,10 +78,26 @@ export function issuePassport(input) {
|
|
|
74
78
|
signature,
|
|
75
79
|
alg: "HMAC-SHA256",
|
|
76
80
|
keyFingerprint: fingerprintSecret(input.secret),
|
|
81
|
+
revoked: input.revoked ?? [],
|
|
77
82
|
};
|
|
78
83
|
}
|
|
79
|
-
/**
|
|
84
|
+
/** Revoke a passport by id. Returns a NEW envelope with the revocation
|
|
85
|
+
* list updated; re-signs with the same secret. The old passport keeps
|
|
86
|
+
* its signature but verifiers that hold the new envelope's revoked[]
|
|
87
|
+
* list will reject the old id. */
|
|
88
|
+
export function revokePassport(envelope, revokeId, secret) {
|
|
89
|
+
const newRevoked = [...(envelope.revoked ?? []), revokeId];
|
|
90
|
+
// Re-sign to keep the chain intact.
|
|
91
|
+
const newSig = computeSignature(envelope.holder, envelope.issuedAt, envelope.expiresAt, envelope.entriesHash, secret);
|
|
92
|
+
return { ...envelope, revoked: newRevoked, signature: newSig };
|
|
93
|
+
}
|
|
94
|
+
/** Verify a passport using the same secret it was signed with.
|
|
95
|
+
* Also checks the envelope's revocation list — if the passport id is in
|
|
96
|
+
* envelope.revoked[], verdict is REVOKED. */
|
|
80
97
|
export function verifyPassport(envelope, secret) {
|
|
98
|
+
if (envelope.revoked && envelope.id && envelope.revoked.includes(envelope.id)) {
|
|
99
|
+
return { verdict: "REVOKED", reason: `passport id ${envelope.id} is in revocation list`, ok: false };
|
|
100
|
+
}
|
|
81
101
|
if (Date.now() > envelope.expiresAt) {
|
|
82
102
|
return { verdict: "EXPIRED", reason: `expired at ${new Date(envelope.expiresAt).toISOString()}`, ok: false };
|
|
83
103
|
}
|
|
@@ -92,16 +112,30 @@ export function verifyPassport(envelope, secret) {
|
|
|
92
112
|
if (expectedSig !== envelope.signature) {
|
|
93
113
|
return { verdict: "TAMPERED", reason: `signature mismatch — envelope was modified`, ok: false };
|
|
94
114
|
}
|
|
95
|
-
return { verdict: "VALID", reason: `signature + hash + key +
|
|
115
|
+
return { verdict: "VALID", reason: `signature + hash + key + revocation all check out · ${envelope.expiresAt === Number.MAX_SAFE_INTEGER ? "eternal" : "ttl-bounded"}`, ok: true };
|
|
116
|
+
}
|
|
117
|
+
/** Render a timestamp safely. Number.MAX_SAFE_INTEGER lies beyond Date's
|
|
118
|
+
* valid range — print "eternal" instead of throwing. */
|
|
119
|
+
function safeIsoDate(ms) {
|
|
120
|
+
if (ms >= Number.MAX_SAFE_INTEGER || ms > 8.64e15)
|
|
121
|
+
return "eternal (user-revocable)";
|
|
122
|
+
try {
|
|
123
|
+
return new Date(ms).toISOString();
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return "eternal (user-revocable)";
|
|
127
|
+
}
|
|
96
128
|
}
|
|
97
129
|
/** Serialize to a compact JSON string suitable for pasting into ANY AI's
|
|
98
130
|
* chat box. Includes a header comment so the AI knows what it is. */
|
|
99
131
|
export function serializePassport(envelope) {
|
|
100
132
|
const header = `--- MNEME PASSPORT v1 ---\n` +
|
|
133
|
+
`id: ${envelope.id}\n` +
|
|
101
134
|
`holder: ${envelope.holder}\n` +
|
|
102
|
-
`issued: ${
|
|
103
|
-
`expires: ${
|
|
135
|
+
`issued: ${safeIsoDate(envelope.issuedAt)}\n` +
|
|
136
|
+
`expires: ${safeIsoDate(envelope.expiresAt)}\n` +
|
|
104
137
|
`entries: ${envelope.entries.length}\n` +
|
|
138
|
+
`revoked: ${envelope.revoked?.length ?? 0}\n` +
|
|
105
139
|
`signed: HMAC-SHA256 (key ${envelope.keyFingerprint})\n` +
|
|
106
140
|
`verify: any holder of the public key can verify; ANY AI agent can\n` +
|
|
107
141
|
` read the entries without verification (read-only consent).\n` +
|
|
@@ -138,8 +172,9 @@ export function estimatePassportTokens(envelope) {
|
|
|
138
172
|
/** One-line summary suitable for the pulse. */
|
|
139
173
|
export function formatPassportPulseLine(envelope, verification) {
|
|
140
174
|
const tokens = estimatePassportTokens(envelope);
|
|
141
|
-
const
|
|
175
|
+
const isEternal = envelope.expiresAt >= Number.MAX_SAFE_INTEGER;
|
|
176
|
+
const ttlStr = isEternal ? "ttl=eternal" : `ttl=${Math.round((envelope.expiresAt - Date.now()) / (24 * 60 * 60 * 1000))}d`;
|
|
142
177
|
const vStr = verification ? ` · verify=${verification.verdict}` : "";
|
|
143
|
-
return `MNEME-PASSPORT · holder=${envelope.holder} · entries=${envelope.entries.length} · ~${tokens} tokens ·
|
|
178
|
+
return `MNEME-PASSPORT · holder=${envelope.holder} · entries=${envelope.entries.length} · ~${tokens} tokens · ${ttlStr}${vStr}`;
|
|
144
179
|
}
|
|
145
180
|
//# sourceMappingURL=passport.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"passport.js","sourceRoot":"","sources":["../../src/rainbow/passport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"passport.js","sourceRoot":"","sources":["../../src/rainbow/passport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passport_v99.test.d.ts","sourceRoot":"","sources":["../../src/rainbow/passport_v99.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { issuePassport, verifyPassport, revokePassport, generatePassportSecret, } from "./passport.js";
|
|
3
|
+
const entries = () => [
|
|
4
|
+
{ id: "d1", ts: Date.now(), kind: "decision", text: "test decision" },
|
|
5
|
+
];
|
|
6
|
+
describe("v1.99 PASSPORT · eternal default + revocation", () => {
|
|
7
|
+
it("default (no ttlDays) → expiresAt = MAX_SAFE_INTEGER (eternal)", () => {
|
|
8
|
+
const secret = generatePassportSecret();
|
|
9
|
+
const env = issuePassport({ holder: "alice", entries: entries(), secret });
|
|
10
|
+
expect(env.expiresAt).toBe(Number.MAX_SAFE_INTEGER);
|
|
11
|
+
});
|
|
12
|
+
it("verifyPassport returns VALID for eternal passport (no expiry possible)", () => {
|
|
13
|
+
const secret = generatePassportSecret();
|
|
14
|
+
const env = issuePassport({ holder: "alice", entries: entries(), secret });
|
|
15
|
+
const r = verifyPassport(env, secret);
|
|
16
|
+
expect(r.verdict).toBe("VALID");
|
|
17
|
+
expect(r.reason).toContain("eternal");
|
|
18
|
+
});
|
|
19
|
+
it("envelope has stable id derived from holder + issuedAt", () => {
|
|
20
|
+
const secret = generatePassportSecret();
|
|
21
|
+
const env = issuePassport({ holder: "alice", entries: entries(), secret });
|
|
22
|
+
expect(env.id).toMatch(/^[0-9a-f]{12}$/);
|
|
23
|
+
});
|
|
24
|
+
it("revokePassport adds id to revocation list", () => {
|
|
25
|
+
const secret = generatePassportSecret();
|
|
26
|
+
const env = issuePassport({ holder: "alice", entries: entries(), secret });
|
|
27
|
+
expect(env.revoked).toEqual([]);
|
|
28
|
+
const env2 = revokePassport(env, env.id, secret);
|
|
29
|
+
expect(env2.revoked).toContain(env.id);
|
|
30
|
+
});
|
|
31
|
+
it("verifyPassport returns REVOKED when own id in revocation list", () => {
|
|
32
|
+
const secret = generatePassportSecret();
|
|
33
|
+
const env = issuePassport({ holder: "alice", entries: entries(), secret });
|
|
34
|
+
const env2 = revokePassport(env, env.id, secret);
|
|
35
|
+
const r = verifyPassport(env2, secret);
|
|
36
|
+
expect(r.verdict).toBe("REVOKED");
|
|
37
|
+
expect(r.ok).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
it("verifyPassport on non-revoked passport returns VALID even when revocation list has OTHER ids", () => {
|
|
40
|
+
const secret = generatePassportSecret();
|
|
41
|
+
const env = issuePassport({ holder: "alice", entries: entries(), secret, revoked: ["other-id-123"] });
|
|
42
|
+
const r = verifyPassport(env, secret);
|
|
43
|
+
expect(r.verdict).toBe("VALID");
|
|
44
|
+
});
|
|
45
|
+
it("explicit ttlDays still works for one-time delegation", () => {
|
|
46
|
+
const secret = generatePassportSecret();
|
|
47
|
+
const env = issuePassport({ holder: "alice", entries: entries(), secret, ttlDays: 7 });
|
|
48
|
+
expect(env.expiresAt).toBeLessThan(Number.MAX_SAFE_INTEGER);
|
|
49
|
+
expect(env.expiresAt).toBeGreaterThan(Date.now());
|
|
50
|
+
expect(env.expiresAt - Date.now()).toBeLessThanOrEqual(8 * 24 * 60 * 60 * 1000);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=passport_v99.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passport_v99.test.js","sourceRoot":"","sources":["../../src/rainbow/passport_v99.test.ts"],"names":[],"mappings":"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"}
|