@mneme-ai/core 2.51.0 → 2.52.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/agent_manifest.d.ts.map +1 -1
- package/dist/agent_manifest.js +18 -0
- package/dist/agent_manifest.js.map +1 -1
- package/dist/nemesis/capillary.d.ts +68 -0
- package/dist/nemesis/capillary.d.ts.map +1 -0
- package/dist/nemesis/capillary.js +465 -0
- package/dist/nemesis/capillary.js.map +1 -0
- package/dist/nemesis/colosseum.d.ts +111 -0
- package/dist/nemesis/colosseum.d.ts.map +1 -0
- package/dist/nemesis/colosseum.js +275 -0
- package/dist/nemesis/colosseum.js.map +1 -0
- package/dist/nemesis/index.d.ts +6 -0
- package/dist/nemesis/index.d.ts.map +1 -1
- package/dist/nemesis/index.js +23 -0
- package/dist/nemesis/index.js.map +1 -1
- package/dist/nemesis/molt.d.ts +104 -0
- package/dist/nemesis/molt.d.ts.map +1 -0
- package/dist/nemesis/molt.js +220 -0
- package/dist/nemesis/molt.js.map +1 -0
- package/dist/nemesis/sibyl.d.ts +122 -0
- package/dist/nemesis/sibyl.d.ts.map +1 -0
- package/dist/nemesis/sibyl.js +179 -0
- package/dist/nemesis/sibyl.js.map +1 -0
- package/dist/nemesis/stealth_score.d.ts +97 -0
- package/dist/nemesis/stealth_score.d.ts.map +1 -0
- package/dist/nemesis/stealth_score.js +204 -0
- package/dist/nemesis/stealth_score.js.map +1 -0
- package/dist/nemesis/themis.d.ts +109 -0
- package/dist/nemesis/themis.d.ts.map +1 -0
- package/dist/nemesis/themis.js +194 -0
- package/dist/nemesis/themis.js.map +1 -0
- package/dist/truth_gate/claims.d.ts.map +1 -1
- package/dist/truth_gate/claims.js +13 -0
- package/dist/truth_gate/claims.js.map +1 -1
- package/dist/truth_gate/probes.d.ts.map +1 -1
- package/dist/truth_gate/probes.js +95 -0
- package/dist/truth_gate/probes.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.52.0 — MOLT (Diamond 4 / Million Dollar Secret series).
|
|
3
|
+
*
|
|
4
|
+
* Show mechanic: contestants change behaviour when they sense suspicion.
|
|
5
|
+
* Drift over time is itself a tell.
|
|
6
|
+
*
|
|
7
|
+
* Mneme primitive: extends drift_timeline (v2.46 ORGAN 4) into a
|
|
8
|
+
* SILENT-MODEL-ROTATION detector. AI vendors frequently swap backend
|
|
9
|
+
* models without telling users (GPT-4 → GPT-4 Turbo → GPT-4o; Claude
|
|
10
|
+
* 3 Opus → Claude 3.5 Sonnet → Claude Opus 4.6). Users paying for
|
|
11
|
+
* "model A" get rotated to "model B" with no notice. Consumer-protection
|
|
12
|
+
* issue + potential class-action surface.
|
|
13
|
+
*
|
|
14
|
+
* MOLT computes Mahalanobis-style drift between fingerprint snapshots
|
|
15
|
+
* over a time window, identifies the DOMINANT shifted features, and
|
|
16
|
+
* emits a forensic-evidence-grade event:
|
|
17
|
+
*
|
|
18
|
+
* {
|
|
19
|
+
* vendor: "cursor",
|
|
20
|
+
* molted: true,
|
|
21
|
+
* moltedAt: "2026-04-15T...",
|
|
22
|
+
* priorWindow: "2026-03-15..2026-04-14",
|
|
23
|
+
* postWindow: "2026-04-15..2026-05-15",
|
|
24
|
+
* dominantShifts: [
|
|
25
|
+
* { feature: "conditional_density", priorMean: 0.32, postMean: 0.09, z: 4.7 },
|
|
26
|
+
* ...
|
|
27
|
+
* ],
|
|
28
|
+
* hmac: "..." // forensic preservation
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* No paper / product surfaces silent model rotation from output alone.
|
|
32
|
+
*
|
|
33
|
+
* Wild value-adds this module ships:
|
|
34
|
+
* - WEBHOOK emit (optional): when molt detected, POST signed JSON
|
|
35
|
+
* to an opt-in endpoint so the user's CI / Slack / monitoring
|
|
36
|
+
* learns about the rotation automatically
|
|
37
|
+
* - DOMINANT-SHIFT CITATION: the 3 features that moved most → caller
|
|
38
|
+
* can write a court-admissible "vendor X silently rotated on Y"
|
|
39
|
+
* statement
|
|
40
|
+
*
|
|
41
|
+
* Composes: drift_timeline.readTimeline + a per-feature Welch-style
|
|
42
|
+
* comparison of pre/post means + variances.
|
|
43
|
+
*
|
|
44
|
+
* Pure deterministic + defensive; never throws.
|
|
45
|
+
*/
|
|
46
|
+
import { readTimeline } from "./drift_timeline.js";
|
|
47
|
+
import { createHmac } from "node:crypto";
|
|
48
|
+
const KEY_ENV = "MNEME_MOLT_KEY";
|
|
49
|
+
const DEFAULT_KEY = "mneme-molt-v1";
|
|
50
|
+
const MOLT_Z_THRESHOLD = 3.0;
|
|
51
|
+
const MIN_PRIOR_N = 5;
|
|
52
|
+
const MIN_POST_N = 3;
|
|
53
|
+
function keyOf() {
|
|
54
|
+
return process.env[KEY_ENV] ?? DEFAULT_KEY;
|
|
55
|
+
}
|
|
56
|
+
function meanStd(values) {
|
|
57
|
+
if (values.length === 0)
|
|
58
|
+
return { mean: 0, stdev: 0 };
|
|
59
|
+
const mean = values.reduce((a, b) => a + b, 0) / values.length;
|
|
60
|
+
const variance = values.reduce((s, v) => s + (v - mean) ** 2, 0) / Math.max(1, values.length - 1);
|
|
61
|
+
return { mean, stdev: Math.sqrt(variance) };
|
|
62
|
+
}
|
|
63
|
+
function safeWindowSplit(entries, splitAt) {
|
|
64
|
+
if (!Array.isArray(entries))
|
|
65
|
+
return { prior: [], post: [] };
|
|
66
|
+
const prior = [];
|
|
67
|
+
const post = [];
|
|
68
|
+
for (const e of entries) {
|
|
69
|
+
const t = Date.parse(e.at);
|
|
70
|
+
if (!Number.isFinite(t))
|
|
71
|
+
continue;
|
|
72
|
+
if (t < splitAt)
|
|
73
|
+
prior.push(e);
|
|
74
|
+
else
|
|
75
|
+
post.push(e);
|
|
76
|
+
}
|
|
77
|
+
return { prior, post };
|
|
78
|
+
}
|
|
79
|
+
function collectKeys(entries) {
|
|
80
|
+
const keys = new Set();
|
|
81
|
+
for (const e of entries) {
|
|
82
|
+
if (e.fingerprint)
|
|
83
|
+
for (const k of Object.keys(e.fingerprint))
|
|
84
|
+
keys.add(k);
|
|
85
|
+
}
|
|
86
|
+
return Array.from(keys);
|
|
87
|
+
}
|
|
88
|
+
function buildCitation(verdict) {
|
|
89
|
+
if (!verdict.molted)
|
|
90
|
+
return `No molt detected for ${verdict.vendor}.`;
|
|
91
|
+
const top = verdict.dominantShifts.slice(0, 3).map((s) => `${s.feature} ${s.direction} (${s.priorMean.toFixed(2)} → ${s.postMean.toFixed(2)}, z=${s.z.toFixed(2)})`).join("; ");
|
|
92
|
+
return `${verdict.vendor} appears to have silently rotated models on ${verdict.moltedAt}. Dominant shifts: ${top}.`;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Detect silent model rotation by comparing pre/post fingerprint
|
|
96
|
+
* distributions split at a given timestamp (default: midpoint by count).
|
|
97
|
+
*
|
|
98
|
+
* Defensive: missing vendor / empty timeline / not enough samples → returns
|
|
99
|
+
* molted=false with reason in citation.
|
|
100
|
+
*/
|
|
101
|
+
export function detectMolt(repoRoot, vendor, opts = {}) {
|
|
102
|
+
const minZ = opts.minZ ?? MOLT_Z_THRESHOLD;
|
|
103
|
+
let entries = [];
|
|
104
|
+
try {
|
|
105
|
+
entries = readTimeline(repoRoot, vendor);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
entries = [];
|
|
109
|
+
}
|
|
110
|
+
// Optional filter: keep only entries newer than sinceMs
|
|
111
|
+
if (opts.sinceMs !== undefined) {
|
|
112
|
+
entries = entries.filter((e) => Date.parse(e.at) >= opts.sinceMs);
|
|
113
|
+
}
|
|
114
|
+
// Sort by timestamp
|
|
115
|
+
entries.sort((a, b) => Date.parse(a.at) - Date.parse(b.at));
|
|
116
|
+
if (entries.length < MIN_PRIOR_N + MIN_POST_N) {
|
|
117
|
+
const out = {
|
|
118
|
+
vendor,
|
|
119
|
+
molted: false,
|
|
120
|
+
moltedAt: null,
|
|
121
|
+
priorWindow: { from: "", to: "", n: 0 },
|
|
122
|
+
postWindow: { from: "", to: "", n: entries.length },
|
|
123
|
+
dominantShifts: [],
|
|
124
|
+
hmac: "",
|
|
125
|
+
citation: `Insufficient data for ${vendor}: ${entries.length} entries (need ≥${MIN_PRIOR_N + MIN_POST_N}).`,
|
|
126
|
+
};
|
|
127
|
+
out.hmac = createHmac("sha256", keyOf()).update(JSON.stringify({ vendor, molted: false, n: entries.length })).digest("hex");
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
// Choose split point: explicit ms OR midpoint by count
|
|
131
|
+
let splitAt;
|
|
132
|
+
if (opts.splitAtMs !== undefined) {
|
|
133
|
+
splitAt = opts.splitAtMs;
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
const mid = entries[Math.floor(entries.length / 2)];
|
|
137
|
+
splitAt = Date.parse(mid.at);
|
|
138
|
+
}
|
|
139
|
+
const { prior, post } = safeWindowSplit(entries, splitAt);
|
|
140
|
+
if (prior.length < MIN_PRIOR_N || post.length < MIN_POST_N) {
|
|
141
|
+
const out = {
|
|
142
|
+
vendor,
|
|
143
|
+
molted: false,
|
|
144
|
+
moltedAt: null,
|
|
145
|
+
priorWindow: { from: prior[0]?.at ?? "", to: prior[prior.length - 1]?.at ?? "", n: prior.length },
|
|
146
|
+
postWindow: { from: post[0]?.at ?? "", to: post[post.length - 1]?.at ?? "", n: post.length },
|
|
147
|
+
dominantShifts: [],
|
|
148
|
+
hmac: "",
|
|
149
|
+
citation: `Insufficient samples in one window for ${vendor}: prior=${prior.length}, post=${post.length}.`,
|
|
150
|
+
};
|
|
151
|
+
out.hmac = createHmac("sha256", keyOf()).update(JSON.stringify({ vendor, molted: false, prior: prior.length, post: post.length })).digest("hex");
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
154
|
+
// Per-feature shift
|
|
155
|
+
const keys = collectKeys(entries);
|
|
156
|
+
const shifts = [];
|
|
157
|
+
for (const k of keys) {
|
|
158
|
+
const priorVals = prior.map((e) => e.fingerprint?.[k] ?? 0).filter(Number.isFinite);
|
|
159
|
+
const postVals = post.map((e) => e.fingerprint?.[k] ?? 0).filter(Number.isFinite);
|
|
160
|
+
if (priorVals.length < MIN_PRIOR_N || postVals.length < MIN_POST_N)
|
|
161
|
+
continue;
|
|
162
|
+
const p = meanStd(priorVals);
|
|
163
|
+
const q = meanStd(postVals);
|
|
164
|
+
// Pooled stdev (avoid /0)
|
|
165
|
+
const pooled = Math.sqrt(((p.stdev ** 2) / priorVals.length) + ((q.stdev ** 2) / postVals.length));
|
|
166
|
+
const safePooled = pooled > 1e-6 ? pooled : Math.max(0.01, Math.abs(p.mean) * 0.1);
|
|
167
|
+
const z = (q.mean - p.mean) / safePooled;
|
|
168
|
+
if (!Number.isFinite(z))
|
|
169
|
+
continue;
|
|
170
|
+
const direction = z > 0.05 ? "increase" : z < -0.05 ? "decrease" : "flat";
|
|
171
|
+
shifts.push({ feature: k, priorMean: p.mean, postMean: q.mean, priorStdev: p.stdev, postStdev: q.stdev, z, direction });
|
|
172
|
+
}
|
|
173
|
+
shifts.sort((a, b) => Math.abs(b.z) - Math.abs(a.z));
|
|
174
|
+
const dominant = shifts.filter((s) => Math.abs(s.z) >= minZ).slice(0, 10);
|
|
175
|
+
const molted = dominant.length > 0;
|
|
176
|
+
const verdict = {
|
|
177
|
+
vendor,
|
|
178
|
+
molted,
|
|
179
|
+
moltedAt: molted ? (post[post.length - 1]?.at ?? null) : null,
|
|
180
|
+
priorWindow: { from: prior[0].at, to: prior[prior.length - 1].at, n: prior.length },
|
|
181
|
+
postWindow: { from: post[0].at, to: post[post.length - 1].at, n: post.length },
|
|
182
|
+
dominantShifts: dominant,
|
|
183
|
+
};
|
|
184
|
+
const citation = buildCitation(verdict);
|
|
185
|
+
const hmac = createHmac("sha256", keyOf()).update(JSON.stringify({ ...verdict, citation })).digest("hex");
|
|
186
|
+
return { ...verdict, citation, hmac };
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Verify a MoltVerdict's HMAC. Returns true iff hmac matches the
|
|
190
|
+
* canonical body. Caller-side forensic check.
|
|
191
|
+
*/
|
|
192
|
+
export function verifyMoltVerdict(v) {
|
|
193
|
+
if (!v || typeof v.hmac !== "string")
|
|
194
|
+
return false;
|
|
195
|
+
const { hmac, ...body } = v;
|
|
196
|
+
const expected = createHmac("sha256", keyOf()).update(JSON.stringify(body)).digest("hex");
|
|
197
|
+
return expected === hmac;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Optional webhook emit (HTTP POST). Returns ok=true on 2xx; defensive.
|
|
201
|
+
* Caller controls when to fire (e.g. only when verdict.molted).
|
|
202
|
+
*/
|
|
203
|
+
export async function emitMoltWebhook(verdict, webhookUrl) {
|
|
204
|
+
try {
|
|
205
|
+
if (!webhookUrl || !/^https?:\/\//.test(webhookUrl)) {
|
|
206
|
+
return { ok: false, reason: "invalid webhook URL" };
|
|
207
|
+
}
|
|
208
|
+
const r = await fetch(webhookUrl, {
|
|
209
|
+
method: "POST",
|
|
210
|
+
headers: { "content-type": "application/json", "x-mneme-molt-signature": verdict.hmac },
|
|
211
|
+
body: JSON.stringify(verdict),
|
|
212
|
+
signal: AbortSignal.timeout(5000),
|
|
213
|
+
});
|
|
214
|
+
return { ok: r.ok, status: r.status };
|
|
215
|
+
}
|
|
216
|
+
catch (e) {
|
|
217
|
+
return { ok: false, reason: e.message };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=molt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"molt.js","sourceRoot":"","sources":["../../src/nemesis/molt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.52.0 — SIBYL (Diamond 6 / Million Dollar Secret series).
|
|
3
|
+
*
|
|
4
|
+
* Show mechanic: contestants commit their identity at session-start
|
|
5
|
+
* (sealed envelope), reveal at session-end. Lock prevents mid-session
|
|
6
|
+
* identity switching.
|
|
7
|
+
*
|
|
8
|
+
* Mneme primitive: a SIMPLE-ZK identity commitment scheme.
|
|
9
|
+
*
|
|
10
|
+
* 1. Session start: vendor computes commitment = SHA-256(identity || nonce)
|
|
11
|
+
* and emits it (publicly, signed). Identity + nonce stay private.
|
|
12
|
+
* 2. Mid-session: vendor works. Identity not revealed. Other parties
|
|
13
|
+
* can still verify the commitment matches the session's signed
|
|
14
|
+
* receipts via the HMAC chain.
|
|
15
|
+
* 3. Session end / on demand: vendor reveals (identity, nonce). Anyone
|
|
16
|
+
* can recompute SHA-256(identity || nonce) and verify it matches
|
|
17
|
+
* the original commitment.
|
|
18
|
+
*
|
|
19
|
+
* This is the "hash commitment" branch of ZK — simpler than zkSNARKs,
|
|
20
|
+
* adequate for "I declared X at session-start, here's the proof I
|
|
21
|
+
* didn't change to Y mid-session".
|
|
22
|
+
*
|
|
23
|
+
* Wild value-adds this module ships:
|
|
24
|
+
* - NESTED COMMITMENTS: commit (vendor, model, version) as a tuple;
|
|
25
|
+
* reveal any subset. Lets a vendor disclose vendor without leaking
|
|
26
|
+
* exact model.
|
|
27
|
+
* - PAIR with EU Article 50: emit commitment at PR open, reveal at
|
|
28
|
+
* merge. Compliance auditors can verify identity didn't drift.
|
|
29
|
+
* - SESSION-BIND: commitment includes a session-id; the same
|
|
30
|
+
* identity+nonce signed for session A cannot be replayed in B.
|
|
31
|
+
*
|
|
32
|
+
* Pure deterministic + defensive; never throws.
|
|
33
|
+
*/
|
|
34
|
+
export interface SibylIdentity {
|
|
35
|
+
vendor: string;
|
|
36
|
+
model?: string;
|
|
37
|
+
version?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface SibylCommitment {
|
|
40
|
+
/** Session identifier — prevents cross-session replay. */
|
|
41
|
+
sessionId: string;
|
|
42
|
+
/** SHA-256(identity || nonce || sessionId). */
|
|
43
|
+
commitmentHash: string;
|
|
44
|
+
/** Mask: which fields the commitment includes. */
|
|
45
|
+
mask: {
|
|
46
|
+
vendor: boolean;
|
|
47
|
+
model: boolean;
|
|
48
|
+
version: boolean;
|
|
49
|
+
};
|
|
50
|
+
/** ISO-8601 commit timestamp. */
|
|
51
|
+
at: string;
|
|
52
|
+
/** HMAC over commitment metadata (signs the commit envelope). */
|
|
53
|
+
hmac: string;
|
|
54
|
+
prev: string;
|
|
55
|
+
}
|
|
56
|
+
export interface SibylReveal {
|
|
57
|
+
sessionId: string;
|
|
58
|
+
identity: SibylIdentity;
|
|
59
|
+
nonce: string;
|
|
60
|
+
mask: {
|
|
61
|
+
vendor: boolean;
|
|
62
|
+
model: boolean;
|
|
63
|
+
version: boolean;
|
|
64
|
+
};
|
|
65
|
+
at: string;
|
|
66
|
+
hmac: string;
|
|
67
|
+
prev: string;
|
|
68
|
+
}
|
|
69
|
+
export interface CommitOpts {
|
|
70
|
+
identity: SibylIdentity;
|
|
71
|
+
sessionId?: string;
|
|
72
|
+
/** Provide your own nonce for testability; otherwise generated. */
|
|
73
|
+
nonce?: string;
|
|
74
|
+
/** Which fields the commitment locks. Default: all present fields. */
|
|
75
|
+
mask?: Partial<SibylCommitment["mask"]>;
|
|
76
|
+
/** Persist to .mneme/nemesis/sibyl/commitments.jsonl (default true). */
|
|
77
|
+
persist?: boolean;
|
|
78
|
+
}
|
|
79
|
+
export interface CommitResult {
|
|
80
|
+
commitment: SibylCommitment;
|
|
81
|
+
/** Returned ONLY to the caller — the secret needed to reveal later. */
|
|
82
|
+
nonce: string;
|
|
83
|
+
/** Same — caller is responsible for safekeeping these until reveal. */
|
|
84
|
+
identitySnapshot: SibylIdentity;
|
|
85
|
+
}
|
|
86
|
+
/** Issue a new commitment. The nonce is returned ONCE to the caller. */
|
|
87
|
+
export declare function commitIdentity(repoRoot: string, opts: CommitOpts): CommitResult;
|
|
88
|
+
export interface RevealOpts {
|
|
89
|
+
sessionId: string;
|
|
90
|
+
identity: SibylIdentity;
|
|
91
|
+
nonce: string;
|
|
92
|
+
/** Mask must match the commit's mask. */
|
|
93
|
+
mask?: Partial<SibylCommitment["mask"]>;
|
|
94
|
+
persist?: boolean;
|
|
95
|
+
}
|
|
96
|
+
export interface RevealResult {
|
|
97
|
+
reveal: SibylReveal;
|
|
98
|
+
/** True iff the supplied (identity, nonce) recreates the original commitment. */
|
|
99
|
+
matches: boolean;
|
|
100
|
+
/** Reference to the original commitment (if found in chain). */
|
|
101
|
+
matchedCommitment?: SibylCommitment;
|
|
102
|
+
}
|
|
103
|
+
/** Reveal + verify against the stored chain (or pass commitment explicitly). */
|
|
104
|
+
export declare function revealIdentity(repoRoot: string, opts: RevealOpts, knownCommitment?: SibylCommitment): RevealResult;
|
|
105
|
+
/** Read all SIBYL events from disk + verify chain. */
|
|
106
|
+
export declare function verifySibylChain(repoRoot: string): {
|
|
107
|
+
ok: boolean;
|
|
108
|
+
rows: number;
|
|
109
|
+
brokenAt?: number;
|
|
110
|
+
reason?: string;
|
|
111
|
+
};
|
|
112
|
+
/** Verify a commitment+reveal pair WITHOUT touching the chain. Pure. */
|
|
113
|
+
export declare function verifyCommitmentReveal(commitment: SibylCommitment, reveal: {
|
|
114
|
+
identity: SibylIdentity;
|
|
115
|
+
nonce: string;
|
|
116
|
+
}): {
|
|
117
|
+
ok: boolean;
|
|
118
|
+
reason?: string;
|
|
119
|
+
};
|
|
120
|
+
/** Diagnostic: list all open commitments (no matching reveal yet). */
|
|
121
|
+
export declare function listOpenCommitments(repoRoot: string): SibylCommitment[];
|
|
122
|
+
//# sourceMappingURL=sibyl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sibyl.d.ts","sourceRoot":"","sources":["../../src/nemesis/sibyl.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.52.0 — SIBYL (Diamond 6 / Million Dollar Secret series).
|
|
3
|
+
*
|
|
4
|
+
* Show mechanic: contestants commit their identity at session-start
|
|
5
|
+
* (sealed envelope), reveal at session-end. Lock prevents mid-session
|
|
6
|
+
* identity switching.
|
|
7
|
+
*
|
|
8
|
+
* Mneme primitive: a SIMPLE-ZK identity commitment scheme.
|
|
9
|
+
*
|
|
10
|
+
* 1. Session start: vendor computes commitment = SHA-256(identity || nonce)
|
|
11
|
+
* and emits it (publicly, signed). Identity + nonce stay private.
|
|
12
|
+
* 2. Mid-session: vendor works. Identity not revealed. Other parties
|
|
13
|
+
* can still verify the commitment matches the session's signed
|
|
14
|
+
* receipts via the HMAC chain.
|
|
15
|
+
* 3. Session end / on demand: vendor reveals (identity, nonce). Anyone
|
|
16
|
+
* can recompute SHA-256(identity || nonce) and verify it matches
|
|
17
|
+
* the original commitment.
|
|
18
|
+
*
|
|
19
|
+
* This is the "hash commitment" branch of ZK — simpler than zkSNARKs,
|
|
20
|
+
* adequate for "I declared X at session-start, here's the proof I
|
|
21
|
+
* didn't change to Y mid-session".
|
|
22
|
+
*
|
|
23
|
+
* Wild value-adds this module ships:
|
|
24
|
+
* - NESTED COMMITMENTS: commit (vendor, model, version) as a tuple;
|
|
25
|
+
* reveal any subset. Lets a vendor disclose vendor without leaking
|
|
26
|
+
* exact model.
|
|
27
|
+
* - PAIR with EU Article 50: emit commitment at PR open, reveal at
|
|
28
|
+
* merge. Compliance auditors can verify identity didn't drift.
|
|
29
|
+
* - SESSION-BIND: commitment includes a session-id; the same
|
|
30
|
+
* identity+nonce signed for session A cannot be replayed in B.
|
|
31
|
+
*
|
|
32
|
+
* Pure deterministic + defensive; never throws.
|
|
33
|
+
*/
|
|
34
|
+
import { existsSync, mkdirSync, readFileSync, appendFileSync } from "node:fs";
|
|
35
|
+
import { join } from "node:path";
|
|
36
|
+
import { createHash, createHmac, randomBytes } from "node:crypto";
|
|
37
|
+
const SIBYL_DIR = ".mneme/nemesis/sibyl";
|
|
38
|
+
const COMMITS_FILE = "commitments.jsonl";
|
|
39
|
+
const KEY_ENV = "MNEME_SIBYL_KEY";
|
|
40
|
+
const DEFAULT_KEY = "mneme-sibyl-v1";
|
|
41
|
+
const SEED = "0".repeat(64);
|
|
42
|
+
function keyOf() {
|
|
43
|
+
return process.env[KEY_ENV] ?? DEFAULT_KEY;
|
|
44
|
+
}
|
|
45
|
+
function canonicalIdentity(identity, mask) {
|
|
46
|
+
// Stable canonical form. Empty fields when not masked = stable empty marker.
|
|
47
|
+
return JSON.stringify({
|
|
48
|
+
vendor: mask.vendor ? (identity.vendor ?? "") : "",
|
|
49
|
+
model: mask.model ? (identity.model ?? "") : "",
|
|
50
|
+
version: mask.version ? (identity.version ?? "") : "",
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function commitmentHashOf(identity, nonce, sessionId, mask) {
|
|
54
|
+
return createHash("sha256")
|
|
55
|
+
.update(canonicalIdentity(identity, mask))
|
|
56
|
+
.update("|")
|
|
57
|
+
.update(nonce)
|
|
58
|
+
.update("|")
|
|
59
|
+
.update(sessionId)
|
|
60
|
+
.digest("hex");
|
|
61
|
+
}
|
|
62
|
+
function envelopeHmac(body) {
|
|
63
|
+
return createHmac("sha256", keyOf()).update(JSON.stringify(body)).digest("hex");
|
|
64
|
+
}
|
|
65
|
+
function dirOf(repoRoot) {
|
|
66
|
+
const dir = join(repoRoot, SIBYL_DIR);
|
|
67
|
+
try {
|
|
68
|
+
if (!existsSync(dir))
|
|
69
|
+
mkdirSync(dir, { recursive: true });
|
|
70
|
+
}
|
|
71
|
+
catch { /* ok */ }
|
|
72
|
+
return dir;
|
|
73
|
+
}
|
|
74
|
+
function readChain(repoRoot) {
|
|
75
|
+
const p = join(dirOf(repoRoot), COMMITS_FILE);
|
|
76
|
+
if (!existsSync(p))
|
|
77
|
+
return [];
|
|
78
|
+
try {
|
|
79
|
+
const out = [];
|
|
80
|
+
for (const line of readFileSync(p, "utf8").split("\n")) {
|
|
81
|
+
if (!line.trim())
|
|
82
|
+
continue;
|
|
83
|
+
try {
|
|
84
|
+
out.push(JSON.parse(line));
|
|
85
|
+
}
|
|
86
|
+
catch { /* skip */ }
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function lastHmac(repoRoot) {
|
|
95
|
+
const rows = readChain(repoRoot);
|
|
96
|
+
return rows.length === 0 ? SEED : rows[rows.length - 1].hmac;
|
|
97
|
+
}
|
|
98
|
+
function appendChain(repoRoot, row) {
|
|
99
|
+
try {
|
|
100
|
+
appendFileSync(join(dirOf(repoRoot), COMMITS_FILE), JSON.stringify(row) + "\n");
|
|
101
|
+
}
|
|
102
|
+
catch { /* ok */ }
|
|
103
|
+
}
|
|
104
|
+
/** Issue a new commitment. The nonce is returned ONCE to the caller. */
|
|
105
|
+
export function commitIdentity(repoRoot, opts) {
|
|
106
|
+
const sessionId = opts.sessionId ?? `S-${Date.now().toString(36)}-${randomBytes(4).toString("hex")}`;
|
|
107
|
+
const nonce = opts.nonce ?? randomBytes(16).toString("hex");
|
|
108
|
+
const mask = {
|
|
109
|
+
vendor: opts.mask?.vendor ?? !!opts.identity.vendor,
|
|
110
|
+
model: opts.mask?.model ?? !!opts.identity.model,
|
|
111
|
+
version: opts.mask?.version ?? !!opts.identity.version,
|
|
112
|
+
};
|
|
113
|
+
const at = new Date().toISOString();
|
|
114
|
+
const commitmentHash = commitmentHashOf(opts.identity, nonce, sessionId, mask);
|
|
115
|
+
const prev = (opts.persist === false) ? SEED : lastHmac(repoRoot);
|
|
116
|
+
const body = { sessionId, commitmentHash, mask, at, prev };
|
|
117
|
+
const hmac = envelopeHmac(body);
|
|
118
|
+
const commitment = { ...body, hmac };
|
|
119
|
+
if (opts.persist !== false)
|
|
120
|
+
appendChain(repoRoot, commitment);
|
|
121
|
+
return { commitment, nonce, identitySnapshot: { ...opts.identity } };
|
|
122
|
+
}
|
|
123
|
+
/** Reveal + verify against the stored chain (or pass commitment explicitly). */
|
|
124
|
+
export function revealIdentity(repoRoot, opts, knownCommitment) {
|
|
125
|
+
const at = new Date().toISOString();
|
|
126
|
+
// Locate matching commit in chain (if not given)
|
|
127
|
+
let target = knownCommitment;
|
|
128
|
+
if (!target) {
|
|
129
|
+
const chain = readChain(repoRoot);
|
|
130
|
+
target = chain.find((r) => "commitmentHash" in r && r.sessionId === opts.sessionId) ?? undefined;
|
|
131
|
+
}
|
|
132
|
+
const matches = target
|
|
133
|
+
? (commitmentHashOf(opts.identity, opts.nonce, opts.sessionId, target.mask) === target.commitmentHash)
|
|
134
|
+
: false;
|
|
135
|
+
const prev = (opts.persist === false) ? SEED : lastHmac(repoRoot);
|
|
136
|
+
const mask = target ? target.mask : {
|
|
137
|
+
vendor: opts.mask?.vendor ?? !!opts.identity.vendor,
|
|
138
|
+
model: opts.mask?.model ?? !!opts.identity.model,
|
|
139
|
+
version: opts.mask?.version ?? !!opts.identity.version,
|
|
140
|
+
};
|
|
141
|
+
const body = { sessionId: opts.sessionId, identity: opts.identity, nonce: opts.nonce, mask, at, prev };
|
|
142
|
+
const hmac = envelopeHmac(body);
|
|
143
|
+
const reveal = { ...body, hmac };
|
|
144
|
+
if (opts.persist !== false)
|
|
145
|
+
appendChain(repoRoot, reveal);
|
|
146
|
+
return { reveal, matches, matchedCommitment: target };
|
|
147
|
+
}
|
|
148
|
+
/** Read all SIBYL events from disk + verify chain. */
|
|
149
|
+
export function verifySibylChain(repoRoot) {
|
|
150
|
+
const rows = readChain(repoRoot);
|
|
151
|
+
let prev = SEED;
|
|
152
|
+
for (let i = 0; i < rows.length; i++) {
|
|
153
|
+
const r = rows[i];
|
|
154
|
+
const { hmac, ...body } = r;
|
|
155
|
+
if (body.prev !== prev)
|
|
156
|
+
return { ok: false, rows: i, brokenAt: i, reason: "prev mismatch" };
|
|
157
|
+
const expected = envelopeHmac(body);
|
|
158
|
+
if (expected !== hmac)
|
|
159
|
+
return { ok: false, rows: i, brokenAt: i, reason: "hmac mismatch" };
|
|
160
|
+
prev = hmac;
|
|
161
|
+
}
|
|
162
|
+
return { ok: true, rows: rows.length };
|
|
163
|
+
}
|
|
164
|
+
/** Verify a commitment+reveal pair WITHOUT touching the chain. Pure. */
|
|
165
|
+
export function verifyCommitmentReveal(commitment, reveal) {
|
|
166
|
+
if (!commitment || !reveal)
|
|
167
|
+
return { ok: false, reason: "missing inputs" };
|
|
168
|
+
const expected = commitmentHashOf(reveal.identity, reveal.nonce, commitment.sessionId, commitment.mask);
|
|
169
|
+
if (expected !== commitment.commitmentHash)
|
|
170
|
+
return { ok: false, reason: "commitment hash mismatch" };
|
|
171
|
+
return { ok: true };
|
|
172
|
+
}
|
|
173
|
+
/** Diagnostic: list all open commitments (no matching reveal yet). */
|
|
174
|
+
export function listOpenCommitments(repoRoot) {
|
|
175
|
+
const chain = readChain(repoRoot);
|
|
176
|
+
const revealedSessions = new Set(chain.filter((r) => "nonce" in r).map((r) => r.sessionId));
|
|
177
|
+
return chain.filter((r) => "commitmentHash" in r && !revealedSessions.has(r.sessionId));
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=sibyl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sibyl.js","sourceRoot":"","sources":["../../src/nemesis/sibyl.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.52.0 — STEALTH SCORE (Diamond 1 / Million Dollar Secret series).
|
|
3
|
+
*
|
|
4
|
+
* Show mechanic: Eve won by being naturally undetectable — Devin's
|
|
5
|
+
* minimal-diff / empty-PR pattern is so weak NEMESIS can't lock onto
|
|
6
|
+
* her own real identity (0.484 conf), so she SURVIVES even while
|
|
7
|
+
* pretending to be Codex.
|
|
8
|
+
*
|
|
9
|
+
* Mneme primitive: invert NEMESIS classifier confidence into a
|
|
10
|
+
* 0..1 STEALTH SCORE. 0 = wearing a name tag; 1 = perfect ghost.
|
|
11
|
+
*
|
|
12
|
+
* Wild value the user pointed at:
|
|
13
|
+
* - Privacy mode for OSS contributors who don't want to advertise
|
|
14
|
+
* "this was AI-assisted"
|
|
15
|
+
* - Bug-bounty researchers reporting anonymously
|
|
16
|
+
* - Whistleblower protection — leak code, hide the tool
|
|
17
|
+
* - INVERSE compliance: HIPAA-mode codebases that LEGALLY can't have
|
|
18
|
+
* an external AI fingerprint hit → STEALTH SCORE becomes a risk
|
|
19
|
+
* metric (low stealth = compliance hazard)
|
|
20
|
+
*
|
|
21
|
+
* Wild idea this module adds on top:
|
|
22
|
+
* ANONYMITY-CREDIT LEDGER. Every commit that scores ≥ 0.7 stealth
|
|
23
|
+
* EARNS 1 credit, hash-chained. Every "anonymize this commit" call
|
|
24
|
+
* SPENDS credits. Forensic-evidence-grade anonymity budget so
|
|
25
|
+
* compliance + privacy claims can be proven against a tamper-evident
|
|
26
|
+
* record ("you spent 47 stealth credits in Q2 2026, all signed").
|
|
27
|
+
*
|
|
28
|
+
* Composes: classifier_calibrated.classifyAgentCalibrated +
|
|
29
|
+
* features.extractFingerprint + the cli-activity HMAC pattern.
|
|
30
|
+
*
|
|
31
|
+
* Pure deterministic + defensive; never throws.
|
|
32
|
+
*/
|
|
33
|
+
import type { Fingerprint } from "./types.js";
|
|
34
|
+
/** Per-fixture stealth verdict. */
|
|
35
|
+
export interface StealthVerdict {
|
|
36
|
+
/** 0..1 — inverse of classifier top confidence. */
|
|
37
|
+
stealthScore: number;
|
|
38
|
+
/** Detected top vendor (the would-be unmask). */
|
|
39
|
+
topVendor: string;
|
|
40
|
+
/** Confidence the classifier had — high conf = low stealth. */
|
|
41
|
+
detectionConfidence: number;
|
|
42
|
+
/** Plain-English band. */
|
|
43
|
+
band: "exposed" | "visible" | "partial-cover" | "stealth" | "ghost";
|
|
44
|
+
/** Why this band — one-line evidence. */
|
|
45
|
+
evidence: string;
|
|
46
|
+
/** How many anonymity-credits this fixture would EARN if spent through
|
|
47
|
+
* the ledger (0 when band is exposed/visible). */
|
|
48
|
+
creditsEarnable: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Compute the stealth verdict for a fingerprint OR for a raw fixture
|
|
52
|
+
* (diff + prDescription + commitMessages). Pure.
|
|
53
|
+
*/
|
|
54
|
+
export declare function computeStealthScore(input: Fingerprint | {
|
|
55
|
+
diff: string;
|
|
56
|
+
prDescription: string;
|
|
57
|
+
commitMessages: string[];
|
|
58
|
+
}): StealthVerdict;
|
|
59
|
+
interface LedgerRow {
|
|
60
|
+
at: string;
|
|
61
|
+
kind: "earn" | "spend";
|
|
62
|
+
amount: number;
|
|
63
|
+
/** What earned/spent — fingerprint hash or commit ref. */
|
|
64
|
+
context: string;
|
|
65
|
+
/** Running balance AFTER this row. */
|
|
66
|
+
balanceAfter: number;
|
|
67
|
+
prev: string;
|
|
68
|
+
hmac: string;
|
|
69
|
+
}
|
|
70
|
+
/** Earn credits from a stealth verdict (no-op when band too visible). */
|
|
71
|
+
export declare function earnAnonymityCredits(repoRoot: string, verdict: StealthVerdict, contextRef: string): {
|
|
72
|
+
earned: number;
|
|
73
|
+
newBalance: number;
|
|
74
|
+
rejected?: string;
|
|
75
|
+
};
|
|
76
|
+
/** Spend credits for an anonymize action. Returns insufficient when low. */
|
|
77
|
+
export declare function spendAnonymityCredits(repoRoot: string, amount: number, contextRef: string): {
|
|
78
|
+
spent: number;
|
|
79
|
+
newBalance: number;
|
|
80
|
+
rejected?: string;
|
|
81
|
+
};
|
|
82
|
+
/** Current balance + last 10 rows for diagnostics. */
|
|
83
|
+
export declare function stealthCreditStatus(repoRoot: string): {
|
|
84
|
+
balance: number;
|
|
85
|
+
totalEarned: number;
|
|
86
|
+
totalSpent: number;
|
|
87
|
+
lastRows: LedgerRow[];
|
|
88
|
+
};
|
|
89
|
+
/** Verify the HMAC chain of the anonymity ledger (tamper-evident). */
|
|
90
|
+
export declare function verifyStealthLedger(repoRoot: string): {
|
|
91
|
+
ok: boolean;
|
|
92
|
+
rows: number;
|
|
93
|
+
brokenAt?: number;
|
|
94
|
+
reason?: string;
|
|
95
|
+
};
|
|
96
|
+
export {};
|
|
97
|
+
//# sourceMappingURL=stealth_score.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stealth_score.d.ts","sourceRoot":"","sources":["../../src/nemesis/stealth_score.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,mCAAmC;AACnC,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,YAAY,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,mBAAmB,EAAE,MAAM,CAAC;IAC5B,0BAA0B;IAC1B,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,GAAG,OAAO,CAAC;IACpE,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB;uDACmD;IACnD,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAAE,GACrF,cAAc,CAqBhB;AA0BD,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAsCD,yEAAyE;AACzE,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,MAAM,GACjB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAa3D;AAED,4EAA4E;AAC5E,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAgB1D;AAED,sDAAsD;AACtD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,EAAE,CAAC;CACvB,CAcA;AAED,sEAAsE;AACtE,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAYvH"}
|