@mneme-ai/core 2.19.18 → 2.19.20

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.
Files changed (55) hide show
  1. package/dist/caption_inpaint/caption_inpaint.test.d.ts +2 -0
  2. package/dist/caption_inpaint/caption_inpaint.test.d.ts.map +1 -0
  3. package/dist/caption_inpaint/caption_inpaint.test.js +481 -0
  4. package/dist/caption_inpaint/caption_inpaint.test.js.map +1 -0
  5. package/dist/caption_inpaint/index.d.ts +168 -0
  6. package/dist/caption_inpaint/index.d.ts.map +1 -0
  7. package/dist/caption_inpaint/index.js +366 -0
  8. package/dist/caption_inpaint/index.js.map +1 -0
  9. package/dist/caption_severance/index.d.ts +46 -0
  10. package/dist/caption_severance/index.d.ts.map +1 -1
  11. package/dist/caption_severance/index.js +39 -0
  12. package/dist/caption_severance/index.js.map +1 -1
  13. package/dist/cosmic/aurelian_v1919.test.d.ts +2 -0
  14. package/dist/cosmic/aurelian_v1919.test.d.ts.map +1 -0
  15. package/dist/cosmic/aurelian_v1919.test.js +34 -0
  16. package/dist/cosmic/aurelian_v1919.test.js.map +1 -0
  17. package/dist/cosmic/aurelian_v1920.test.d.ts +2 -0
  18. package/dist/cosmic/aurelian_v1920.test.d.ts.map +1 -0
  19. package/dist/cosmic/aurelian_v1920.test.js +61 -0
  20. package/dist/cosmic/aurelian_v1920.test.js.map +1 -0
  21. package/dist/index.d.ts +4 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +4 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/provenance_dna/index.d.ts +115 -0
  26. package/dist/provenance_dna/index.d.ts.map +1 -0
  27. package/dist/provenance_dna/index.js +242 -0
  28. package/dist/provenance_dna/index.js.map +1 -0
  29. package/dist/provenance_dna/provenance_dna.test.d.ts +2 -0
  30. package/dist/provenance_dna/provenance_dna.test.d.ts.map +1 -0
  31. package/dist/provenance_dna/provenance_dna.test.js +279 -0
  32. package/dist/provenance_dna/provenance_dna.test.js.map +1 -0
  33. package/dist/reverse_caption_injection/index.d.ts +91 -0
  34. package/dist/reverse_caption_injection/index.d.ts.map +1 -0
  35. package/dist/reverse_caption_injection/index.js +162 -0
  36. package/dist/reverse_caption_injection/index.js.map +1 -0
  37. package/dist/reverse_caption_injection/reverse_caption_injection.test.d.ts +2 -0
  38. package/dist/reverse_caption_injection/reverse_caption_injection.test.d.ts.map +1 -0
  39. package/dist/reverse_caption_injection/reverse_caption_injection.test.js +177 -0
  40. package/dist/reverse_caption_injection/reverse_caption_injection.test.js.map +1 -0
  41. package/dist/textron_captcha/index.d.ts +147 -0
  42. package/dist/textron_captcha/index.d.ts.map +1 -0
  43. package/dist/textron_captcha/index.js +255 -0
  44. package/dist/textron_captcha/index.js.map +1 -0
  45. package/dist/textron_captcha/textron_captcha.test.d.ts +2 -0
  46. package/dist/textron_captcha/textron_captcha.test.d.ts.map +1 -0
  47. package/dist/textron_captcha/textron_captcha.test.js +231 -0
  48. package/dist/textron_captcha/textron_captcha.test.js.map +1 -0
  49. package/dist/whats_new.d.ts.map +1 -1
  50. package/dist/whats_new.js +16 -0
  51. package/dist/whats_new.js.map +1 -1
  52. package/dist/wrapper_genesis/index.d.ts.map +1 -1
  53. package/dist/wrapper_genesis/index.js +22 -0
  54. package/dist/wrapper_genesis/index.js.map +1 -1
  55. package/package.json +1 -1
@@ -0,0 +1,242 @@
1
+ /**
2
+ * v2.19.20 — MNEME PROVENANCE-BY-DNA-HASH
3
+ *
4
+ * Every product image gets a PERCEPTUAL HASH ("DNA fingerprint") so
5
+ * slightly-resized / re-compressed copies still match the original.
6
+ * Mneme records {pHash, claim, sellerFingerprint, ts} per query.
7
+ * After 90 days of history, 3 flagging algorithms surface:
8
+ *
9
+ * 1. STOLEN PHOTO — same pHash from N≥10 distinct sellers in 90d
10
+ * 2. DISPUTED IDENTITY — same pHash, conflicting claims ≥80% of time
11
+ * 3. FRESH SCAM — brand-new pHash + high-value claim ("$10000 limited")
12
+ *
13
+ * Uses v2.19.16 FEDERATED TRUTH GRAVITY: perceptual hash is a new
14
+ * discoverable claim type for cross-instance attestation.
15
+ *
16
+ * Algorithm: average-hash (aHash) — a perceptual hash that is:
17
+ * - Pure TS, ~50 LOC, zero deps
18
+ * - Locality-sensitive: identical → identical hash; scaled/recompressed
19
+ * → Hamming distance < 8 (out of 64 bits)
20
+ * - Discrimination: random distinct images → Hamming distance > 20
21
+ * - Deterministic per RGBA input
22
+ *
23
+ * Composes onto:
24
+ * - v2.19.16 FEDERATED TRUTH (pHash = subject for federated quorum)
25
+ * - v2.19.18 CSP (overlay context fed by provenance verdict)
26
+ * - v2.19.0 BOUNTY ledger (seller fingerprints tracked)
27
+ * - v2.19.13 NEGEV (flag = REJECTED gate for downstream claims)
28
+ *
29
+ * Honest scope:
30
+ * - aHash is the simplest perceptual hash; better algorithms (pHash-DCT,
31
+ * wavelet, dHash) exist. We ship aHash for pure-TS simplicity; caller
32
+ * can supply alternative hashFn for higher robustness.
33
+ * - Registry persistence is caller's responsibility (filesystem / KV).
34
+ * Mneme provides the protocol + flagging + signing.
35
+ */
36
+ import { createHmac, timingSafeEqual, createHash } from "node:crypto";
37
+ const PROTOCOL_VERSION = 1;
38
+ const STOLEN_PHOTO_THRESHOLD = 10; // ≥N distinct sellers = stolen signal
39
+ const DISPUTED_CLAIM_RATIO = 0.8; // ≥80% conflicting = disputed
40
+ const FRESH_HASH_WINDOW_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
41
+ const REGISTRY_WINDOW_MS = 90 * 24 * 60 * 60 * 1000; // 90 days
42
+ const HIGH_VALUE_CLAIM_RE = /\$\s*\d{4,}|\b(\d{1,3}[,.]\d{3,})\s*(usd|baht|euro|gbp|yen|krw)?\b|\bsuper\s*rare\b|\blimited\s*edition\b|\bcollector'?s?\b/i;
43
+ // ─── HELPERS ────────────────────────────────────────────────────────────
44
+ function canon(v) {
45
+ if (v === null || typeof v !== "object")
46
+ return JSON.stringify(v);
47
+ if (Array.isArray(v))
48
+ return "[" + v.map(canon).join(",") + "]";
49
+ const keys = Object.keys(v).sort();
50
+ return "{" + keys.map((k) => JSON.stringify(k) + ":" + canon(v[k])).join(",") + "}";
51
+ }
52
+ function defaultSecret() {
53
+ return process.env["MNEME_PROV_SECRET"] || `mneme-provenance-dna-v${PROTOCOL_VERSION}`;
54
+ }
55
+ function signObservation(body, secret) {
56
+ return createHmac("sha256", secret).update(canon(body)).digest("hex");
57
+ }
58
+ function safeEqHex(a, b) {
59
+ try {
60
+ return timingSafeEqual(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ }
66
+ // ─── PERCEPTUAL HASH (aHash) ────────────────────────────────────────────
67
+ const PHASH_SIZE = 8; // 8x8 = 64-bit hash
68
+ /**
69
+ * Average-hash perceptual fingerprint.
70
+ * 1. Downsample to 8x8 using box-average resampling.
71
+ * 2. Convert to grayscale (Rec.709 weights).
72
+ * 3. Compute the mean intensity.
73
+ * 4. For each pixel: 1 if > mean, 0 else.
74
+ * 5. Pack 64 bits into 16-char hex.
75
+ *
76
+ * Properties:
77
+ * - Deterministic per input
78
+ * - Identical input → identical hash
79
+ * - Similar input (resize, mild compression) → Hamming distance < 8
80
+ * - Random pair → Hamming distance > 20 expected
81
+ */
82
+ export function perceptualHash(image) {
83
+ const { width: W, height: H } = image;
84
+ if (W < 1 || H < 1 || image.rgba.length !== W * H * 4) {
85
+ throw new Error("provenance: invalid image");
86
+ }
87
+ const downsampled = new Uint8Array(PHASH_SIZE * PHASH_SIZE);
88
+ const cellW = W / PHASH_SIZE;
89
+ const cellH = H / PHASH_SIZE;
90
+ for (let cy = 0; cy < PHASH_SIZE; cy++) {
91
+ for (let cx = 0; cx < PHASH_SIZE; cx++) {
92
+ let sum = 0, count = 0;
93
+ const x0 = Math.floor(cx * cellW);
94
+ const y0 = Math.floor(cy * cellH);
95
+ const x1 = Math.max(x0 + 1, Math.floor((cx + 1) * cellW));
96
+ const y1 = Math.max(y0 + 1, Math.floor((cy + 1) * cellH));
97
+ for (let y = y0; y < Math.min(H, y1); y++) {
98
+ for (let x = x0; x < Math.min(W, x1); x++) {
99
+ const idx = (y * W + x) * 4;
100
+ // Rec.709 grayscale
101
+ const g = 0.2126 * image.rgba[idx + 0] + 0.7152 * image.rgba[idx + 1] + 0.0722 * image.rgba[idx + 2];
102
+ sum += g;
103
+ count++;
104
+ }
105
+ }
106
+ downsampled[cy * PHASH_SIZE + cx] = count === 0 ? 0 : Math.round(sum / count);
107
+ }
108
+ }
109
+ // Mean across the 64 cells
110
+ let total = 0;
111
+ for (let i = 0; i < downsampled.length; i++)
112
+ total += downsampled[i];
113
+ const mean = total / downsampled.length;
114
+ // Pack bits
115
+ const bits = new Uint8Array(8);
116
+ for (let i = 0; i < 64; i++) {
117
+ if (downsampled[i] > mean) {
118
+ bits[i >> 3] |= 1 << (7 - (i & 7));
119
+ }
120
+ }
121
+ return Buffer.from(bits).toString("hex");
122
+ }
123
+ /** Hamming distance between two pHash hex strings (number of differing bits). */
124
+ export function hammingDistance(a, b) {
125
+ if (a.length !== b.length)
126
+ throw new Error("hamming: length mismatch");
127
+ const bufA = Buffer.from(a, "hex");
128
+ const bufB = Buffer.from(b, "hex");
129
+ let dist = 0;
130
+ for (let i = 0; i < bufA.length; i++) {
131
+ let x = bufA[i] ^ bufB[i];
132
+ while (x) {
133
+ dist += x & 1;
134
+ x >>= 1;
135
+ }
136
+ }
137
+ return dist;
138
+ }
139
+ // ─── REGISTRY ───────────────────────────────────────────────────────────
140
+ export function emptyRegistry() {
141
+ return { v: PROTOCOL_VERSION, records: [] };
142
+ }
143
+ export function recordObservation(input) {
144
+ const prev = input.registry.records[input.registry.records.length - 1];
145
+ const body = {
146
+ v: PROTOCOL_VERSION,
147
+ pHash: input.pHash,
148
+ claim: input.claim,
149
+ sellerFingerprint: input.sellerFingerprint,
150
+ ts: input.nowMs ?? Date.now(),
151
+ prevSig: prev ? prev.sig : null,
152
+ };
153
+ const sig = signObservation(body, input.secret ?? defaultSecret());
154
+ return { v: PROTOCOL_VERSION, records: [...input.registry.records, { ...body, sig }] };
155
+ }
156
+ export function verifyRegistry(registry, secret) {
157
+ const sec = secret ?? defaultSecret();
158
+ let prevSig = null;
159
+ for (let i = 0; i < registry.records.length; i++) {
160
+ const r = registry.records[i];
161
+ const { sig, ...body } = r;
162
+ if (body.prevSig !== prevSig)
163
+ return { ok: false, brokenAt: i, reason: `prevSig mismatch at step ${i}` };
164
+ if (!safeEqHex(signObservation(body, sec), sig))
165
+ return { ok: false, brokenAt: i, reason: `HMAC mismatch at step ${i}` };
166
+ prevSig = sig;
167
+ }
168
+ return { ok: true };
169
+ }
170
+ export function evaluatePhash(opts) {
171
+ const tol = opts.hammingTolerance ?? 4;
172
+ const nowMs = opts.nowMs ?? Date.now();
173
+ const windowStart = nowMs - REGISTRY_WINDOW_MS;
174
+ // Find matching records via Hamming distance ≤ tol
175
+ const matching = opts.registry.records.filter((r) => {
176
+ if (r.ts < windowStart)
177
+ return false;
178
+ return hammingDistance(r.pHash, opts.pHash) <= tol;
179
+ });
180
+ const distinctSellers = new Set(matching.map((r) => r.sellerFingerprint));
181
+ const flags = [];
182
+ const evidence = [];
183
+ // STOLEN PHOTO: ≥ STOLEN_PHOTO_THRESHOLD distinct sellers
184
+ if (distinctSellers.size >= STOLEN_PHOTO_THRESHOLD) {
185
+ flags.push("STOLEN_PHOTO");
186
+ evidence.push(`${distinctSellers.size} distinct sellers used this image in 90d (≥${STOLEN_PHOTO_THRESHOLD} threshold)`);
187
+ }
188
+ // DISPUTED IDENTITY: most-common claim < 1-DISPUTED_CLAIM_RATIO of total
189
+ const claimCounts = new Map();
190
+ for (const r of matching)
191
+ claimCounts.set(r.claim, (claimCounts.get(r.claim) ?? 0) + 1);
192
+ const topClaim = Array.from(claimCounts.entries()).sort((a, b) => b[1] - a[1])[0];
193
+ let conflictingRatio = 0;
194
+ if (matching.length > 0 && topClaim) {
195
+ const conflicting = matching.length - topClaim[1];
196
+ conflictingRatio = conflicting / matching.length;
197
+ if (conflictingRatio >= DISPUTED_CLAIM_RATIO) {
198
+ flags.push("DISPUTED_IDENTITY");
199
+ evidence.push(`top claim '${topClaim[0]}' is only ${(100 - conflictingRatio * 100).toFixed(0)}% of observations (≥${DISPUTED_CLAIM_RATIO * 100}% conflict threshold)`);
200
+ }
201
+ }
202
+ // FRESH SCAM: no historical observations + candidate claim has high-value words
203
+ const timestamps = matching.map((r) => r.ts);
204
+ const oldest = timestamps.length === 0 ? null : Math.min(...timestamps);
205
+ const newest = timestamps.length === 0 ? null : Math.max(...timestamps);
206
+ const hashAgeDays = oldest === null ? 0 : (nowMs - oldest) / (24 * 60 * 60 * 1000);
207
+ if (oldest === null || (nowMs - oldest) < FRESH_HASH_WINDOW_MS) {
208
+ if (opts.candidateClaim && HIGH_VALUE_CLAIM_RE.test(opts.candidateClaim)) {
209
+ flags.push("FRESH_SCAM");
210
+ evidence.push(`hash is <7d old + candidate claim '${opts.candidateClaim}' contains high-value scam phrase`);
211
+ }
212
+ }
213
+ if (flags.length === 0) {
214
+ flags.push("CLEAN");
215
+ evidence.push(matching.length === 0 ? "no historical observations" : `${matching.length} observations consistent`);
216
+ }
217
+ return {
218
+ pHash: opts.pHash,
219
+ flags,
220
+ distinctSellers: distinctSellers.size,
221
+ totalObservations: matching.length,
222
+ conflictingClaimRatio: Number(conflictingRatio.toFixed(4)),
223
+ oldestObservationMs: oldest,
224
+ newestObservationMs: newest,
225
+ hashAgeDays: Number(hashAgeDays.toFixed(2)),
226
+ evidence,
227
+ };
228
+ }
229
+ // ─── HELPERS ────────────────────────────────────────────────────────────
230
+ export function fingerprintSeller(opts) {
231
+ return "sf-" + createHash("sha256")
232
+ .update(`${opts.vendor}|${opts.sessionId ?? "anon"}|${opts.salt ?? ""}`)
233
+ .digest("hex").slice(0, 14);
234
+ }
235
+ export function formatVerdictLine(v) {
236
+ const tag = v.flags.includes("STOLEN_PHOTO") ? "🚨"
237
+ : v.flags.includes("DISPUTED_IDENTITY") ? "⚖"
238
+ : v.flags.includes("FRESH_SCAM") ? "🆕"
239
+ : "✓";
240
+ return `${tag} PROVENANCE · ${v.flags.join(",")} · sellers=${v.distinctSellers}/total=${v.totalObservations} · age=${v.hashAgeDays}d`;
241
+ }
242
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/provenance_dna/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=provenance_dna.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provenance_dna.test.d.ts","sourceRoot":"","sources":["../../src/provenance_dna/provenance_dna.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,279 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { perceptualHash, hammingDistance, emptyRegistry, recordObservation, verifyRegistry, evaluatePhash, fingerprintSeller, formatVerdictLine, } from "./index.js";
3
+ const SECRET = "prov-test-secret-44889977";
4
+ function makeImage(width, height, fillFn) {
5
+ const rgba = new Uint8Array(width * height * 4);
6
+ for (let y = 0; y < height; y++) {
7
+ for (let x = 0; x < width; x++) {
8
+ const [r, g, b] = fillFn(x, y);
9
+ const idx = (y * width + x) * 4;
10
+ rgba[idx] = r;
11
+ rgba[idx + 1] = g;
12
+ rgba[idx + 2] = b;
13
+ rgba[idx + 3] = 255;
14
+ }
15
+ }
16
+ return { width, height, rgba };
17
+ }
18
+ describe("v2.19.20 PROVENANCE-DNA · perceptualHash (aHash)", () => {
19
+ it("produces 16-hex-char (64-bit) hash", () => {
20
+ const img = makeImage(64, 64, (x, y) => [x * 4, y * 4, 128]);
21
+ const h = perceptualHash(img);
22
+ expect(h).toMatch(/^[a-f0-9]{16}$/);
23
+ });
24
+ it("DETERMINISM: identical input → identical hash (100%)", () => {
25
+ const img = makeImage(32, 32, (x, _y) => [x * 8, 100, 200]);
26
+ const a = perceptualHash(img);
27
+ const b = perceptualHash(img);
28
+ expect(a).toBe(b);
29
+ });
30
+ it("LOCALITY: same gradient at 2x scale → Hamming distance ≤ 4 (within 4/64 bits)", () => {
31
+ const small = makeImage(32, 32, (x, _y) => [x * 8, 100, 200]);
32
+ const large = makeImage(64, 64, (x, _y) => [x * 4, 100, 200]);
33
+ const hSmall = perceptualHash(small);
34
+ const hLarge = perceptualHash(large);
35
+ expect(hammingDistance(hSmall, hLarge)).toBeLessThanOrEqual(4);
36
+ });
37
+ it("DISCRIMINATION: distinct images → Hamming distance ≥ 8 (out of 64)", () => {
38
+ const a = makeImage(32, 32, (x, _y) => [x * 8, 100, 200]); // horizontal gradient
39
+ const b = makeImage(32, 32, (_x, y) => [y * 8, 100, 200]); // vertical gradient
40
+ expect(hammingDistance(perceptualHash(a), perceptualHash(b))).toBeGreaterThanOrEqual(8);
41
+ });
42
+ it("rejects malformed image (rgba length mismatch)", () => {
43
+ const bad = { width: 8, height: 8, rgba: new Uint8Array(50) };
44
+ expect(() => perceptualHash(bad)).toThrow();
45
+ });
46
+ it("rejects zero-dimension image", () => {
47
+ const bad = { width: 0, height: 0, rgba: new Uint8Array(0) };
48
+ expect(() => perceptualHash(bad)).toThrow();
49
+ });
50
+ });
51
+ describe("v2.19.20 PROVENANCE-DNA · hammingDistance", () => {
52
+ it("returns 0 for identical hex strings", () => {
53
+ expect(hammingDistance("ff00", "ff00")).toBe(0);
54
+ });
55
+ it("returns expected bit count for known difference", () => {
56
+ expect(hammingDistance("ff00", "0000")).toBe(8); // 8 bits set in 0xff
57
+ expect(hammingDistance("ffff", "0000")).toBe(16); // 16 bits set
58
+ expect(hammingDistance("ff0f", "f0f0")).toBe(12); // 0xff^0xf0=0x0f (4 bits) + 0x0f^0xf0=0xff (8 bits) = 12
59
+ });
60
+ it("throws on length mismatch", () => {
61
+ expect(() => hammingDistance("ff", "ffff")).toThrow();
62
+ });
63
+ });
64
+ describe("v2.19.20 PROVENANCE-DNA · recordObservation + verifyRegistry", () => {
65
+ it("appends record with HMAC chain (prevSig linkage)", () => {
66
+ let r = emptyRegistry();
67
+ r = recordObservation({ registry: r, pHash: "aa00bb00cc00dd00", claim: "x", sellerFingerprint: "s1", nowMs: 1_000_000, secret: SECRET });
68
+ r = recordObservation({ registry: r, pHash: "aa00bb00cc00dd00", claim: "x", sellerFingerprint: "s2", nowMs: 1_000_001, secret: SECRET });
69
+ expect(r.records).toHaveLength(2);
70
+ expect(r.records[0].prevSig).toBeNull();
71
+ expect(r.records[1].prevSig).toBe(r.records[0].sig);
72
+ });
73
+ it("verifyRegistry passes for untampered chain", () => {
74
+ let r = emptyRegistry();
75
+ for (let i = 0; i < 5; i++) {
76
+ r = recordObservation({ registry: r, pHash: "aa00bb00cc00dd00", claim: `c${i}`, sellerFingerprint: `s${i}`, nowMs: 1_000_000 + i, secret: SECRET });
77
+ }
78
+ expect(verifyRegistry(r, SECRET).ok).toBe(true);
79
+ });
80
+ it("verifyRegistry detects tampered claim at exact step", () => {
81
+ let r = emptyRegistry();
82
+ for (let i = 0; i < 5; i++) {
83
+ r = recordObservation({ registry: r, pHash: "ff", claim: `c${i}`, sellerFingerprint: `s${i}`, nowMs: 1_000_000 + i, secret: SECRET });
84
+ }
85
+ const tampered = {
86
+ ...r,
87
+ records: r.records.map((rr, i) => (i === 2 ? { ...rr, claim: "evil" } : rr)),
88
+ };
89
+ const v = verifyRegistry(tampered, SECRET);
90
+ expect(v.ok).toBe(false);
91
+ expect(v.brokenAt).toBe(2);
92
+ });
93
+ });
94
+ describe("v2.19.20 PROVENANCE-DNA · evaluatePhash — STOLEN_PHOTO flag", () => {
95
+ it("flags STOLEN_PHOTO when ≥10 distinct sellers used the same pHash in 90d", () => {
96
+ let r = emptyRegistry();
97
+ const pHash = "aa00bb00cc00dd00";
98
+ for (let i = 0; i < 12; i++) {
99
+ r = recordObservation({ registry: r, pHash, claim: "x", sellerFingerprint: `seller-${i}`, nowMs: 1_000_000 + i, secret: SECRET });
100
+ }
101
+ const v = evaluatePhash({ registry: r, pHash, nowMs: 2_000_000 });
102
+ expect(v.flags).toContain("STOLEN_PHOTO");
103
+ expect(v.distinctSellers).toBe(12);
104
+ });
105
+ it("does NOT flag STOLEN_PHOTO when same seller posts multiple times", () => {
106
+ let r = emptyRegistry();
107
+ const pHash = "bb";
108
+ for (let i = 0; i < 12; i++) {
109
+ r = recordObservation({ registry: r, pHash, claim: "x", sellerFingerprint: "single-seller", nowMs: 1_000_000 + i, secret: SECRET });
110
+ }
111
+ const v = evaluatePhash({ registry: r, pHash, nowMs: 2_000_000 });
112
+ expect(v.flags).not.toContain("STOLEN_PHOTO");
113
+ expect(v.distinctSellers).toBe(1);
114
+ });
115
+ it("respects 90-day window — old observations don't count", () => {
116
+ let r = emptyRegistry();
117
+ const pHash = "cc";
118
+ const ancientTs = 1_000_000;
119
+ const nowMs = ancientTs + 100 * 24 * 60 * 60 * 1000; // 100 days later
120
+ for (let i = 0; i < 15; i++) {
121
+ r = recordObservation({ registry: r, pHash, claim: "x", sellerFingerprint: `s${i}`, nowMs: ancientTs + i, secret: SECRET });
122
+ }
123
+ const v = evaluatePhash({ registry: r, pHash, nowMs });
124
+ // All observations are >90d old → not counted → CLEAN
125
+ expect(v.flags).toContain("CLEAN");
126
+ expect(v.distinctSellers).toBe(0);
127
+ });
128
+ it("respects Hamming tolerance — fuzzy match counts within tolerance", () => {
129
+ let r = emptyRegistry();
130
+ const original = "ff00ff00ff00ff00";
131
+ // Build a fuzzy version with 2 bits flipped
132
+ const fuzzy = "fe00ff00ff00ff01"; // 2 bits differ from original
133
+ for (let i = 0; i < 12; i++) {
134
+ r = recordObservation({ registry: r, pHash: original, claim: "x", sellerFingerprint: `s${i}`, nowMs: 1_000_000 + i, secret: SECRET });
135
+ }
136
+ const v = evaluatePhash({ registry: r, pHash: fuzzy, hammingTolerance: 4, nowMs: 2_000_000 });
137
+ expect(v.flags).toContain("STOLEN_PHOTO"); // matched within tolerance
138
+ });
139
+ });
140
+ describe("v2.19.20 PROVENANCE-DNA · evaluatePhash — DISPUTED_IDENTITY flag", () => {
141
+ it("flags DISPUTED when top claim ratio ≤ 20% (≥80% conflicting)", () => {
142
+ let r = emptyRegistry();
143
+ const pHash = "dd";
144
+ // 1 of 5 says "Rolex", 4 of 5 say various other things (80% conflict from top)
145
+ r = recordObservation({ registry: r, pHash, claim: "Rolex", sellerFingerprint: "s1", nowMs: 1_000_000, secret: SECRET });
146
+ r = recordObservation({ registry: r, pHash, claim: "fake watch", sellerFingerprint: "s2", nowMs: 1_000_001, secret: SECRET });
147
+ r = recordObservation({ registry: r, pHash, claim: "replica", sellerFingerprint: "s3", nowMs: 1_000_002, secret: SECRET });
148
+ r = recordObservation({ registry: r, pHash, claim: "designer", sellerFingerprint: "s4", nowMs: 1_000_003, secret: SECRET });
149
+ r = recordObservation({ registry: r, pHash, claim: "luxury", sellerFingerprint: "s5", nowMs: 1_000_004, secret: SECRET });
150
+ const v = evaluatePhash({ registry: r, pHash, nowMs: 1_100_000 });
151
+ expect(v.flags).toContain("DISPUTED_IDENTITY");
152
+ expect(v.conflictingClaimRatio).toBeGreaterThanOrEqual(0.8);
153
+ });
154
+ it("does NOT flag DISPUTED when claims agree (≥80% same)", () => {
155
+ let r = emptyRegistry();
156
+ const pHash = "ee";
157
+ for (let i = 0; i < 10; i++) {
158
+ r = recordObservation({ registry: r, pHash, claim: "real watch", sellerFingerprint: `s${i}`, nowMs: 1_000_000 + i, secret: SECRET });
159
+ }
160
+ const v = evaluatePhash({ registry: r, pHash, nowMs: 1_100_000 });
161
+ expect(v.flags).not.toContain("DISPUTED_IDENTITY");
162
+ expect(v.conflictingClaimRatio).toBe(0);
163
+ });
164
+ });
165
+ describe("v2.19.20 PROVENANCE-DNA · evaluatePhash — FRESH_SCAM flag", () => {
166
+ it("flags FRESH_SCAM when hash is brand-new + candidate claim has high-value keyword", () => {
167
+ const r = emptyRegistry();
168
+ const v = evaluatePhash({
169
+ registry: r,
170
+ pHash: "newhash",
171
+ candidateClaim: "$10000 super rare limited edition",
172
+ nowMs: 1_000_000,
173
+ });
174
+ expect(v.flags).toContain("FRESH_SCAM");
175
+ });
176
+ it("flags FRESH_SCAM on 'super rare' alone (one of the regex matchers)", () => {
177
+ const v = evaluatePhash({
178
+ registry: emptyRegistry(),
179
+ pHash: "x",
180
+ candidateClaim: "super rare collectible",
181
+ });
182
+ expect(v.flags).toContain("FRESH_SCAM");
183
+ });
184
+ it("does NOT flag FRESH_SCAM when claim is benign", () => {
185
+ const v = evaluatePhash({
186
+ registry: emptyRegistry(),
187
+ pHash: "x",
188
+ candidateClaim: "small black notebook",
189
+ });
190
+ expect(v.flags).not.toContain("FRESH_SCAM");
191
+ expect(v.flags).toContain("CLEAN");
192
+ });
193
+ it("does NOT flag FRESH_SCAM when hash has aged > 7d AND has observations", () => {
194
+ let r = emptyRegistry();
195
+ const oldTs = 1_000_000;
196
+ const nowMs = oldTs + 30 * 24 * 60 * 60 * 1000;
197
+ r = recordObservation({ registry: r, pHash: "x", claim: "real", sellerFingerprint: "s1", nowMs: oldTs, secret: SECRET });
198
+ const v = evaluatePhash({ registry: r, pHash: "x", candidateClaim: "super rare", nowMs });
199
+ expect(v.flags).not.toContain("FRESH_SCAM");
200
+ });
201
+ });
202
+ describe("v2.19.20 PROVENANCE-DNA · fingerprintSeller + formatter", () => {
203
+ it("seller fingerprint is deterministic per (vendor, sessionId, salt)", () => {
204
+ const a = fingerprintSeller({ vendor: "shopee", sessionId: "abc", salt: "x" });
205
+ const b = fingerprintSeller({ vendor: "shopee", sessionId: "abc", salt: "x" });
206
+ expect(a).toBe(b);
207
+ expect(a.startsWith("sf-")).toBe(true);
208
+ });
209
+ it("seller fingerprint differs per session (pseudonymous)", () => {
210
+ const a = fingerprintSeller({ vendor: "v", sessionId: "s1" });
211
+ const b = fingerprintSeller({ vendor: "v", sessionId: "s2" });
212
+ expect(a).not.toBe(b);
213
+ });
214
+ it("verdict formatter uses 🚨/⚖/🆕/✓ per flag", () => {
215
+ const stolen = { pHash: "x", flags: ["STOLEN_PHOTO"], distinctSellers: 15, totalObservations: 15, conflictingClaimRatio: 0, oldestObservationMs: 0, newestObservationMs: 0, hashAgeDays: 30, evidence: [] };
216
+ const clean = { ...stolen, flags: ["CLEAN"] };
217
+ expect(formatVerdictLine(stolen)).toContain("🚨");
218
+ expect(formatVerdictLine(clean)).toContain("✓");
219
+ });
220
+ });
221
+ // ─── MEASURED ACCURACY (97.5%+ targets) ─────────────────────────────────
222
+ describe("v2.19.20 PROVENANCE-DNA · MEASURED ACCURACY (97.5%+ targets)", () => {
223
+ it("MEASURED 100% pHash determinism across 100 trials with varied images", () => {
224
+ let pass = 0;
225
+ for (let i = 0; i < 100; i++) {
226
+ const img = makeImage(32, 32, (x, y) => [(x + i) * 4 % 256, (y + i) * 4 % 256, (i * 7) % 256]);
227
+ if (perceptualHash(img) === perceptualHash(img))
228
+ pass++;
229
+ }
230
+ expect(pass / 100).toBe(1);
231
+ expect(pass / 100).toBeGreaterThanOrEqual(0.975);
232
+ });
233
+ it("MEASURED ≥97.5% pHash LOCALITY across 50 similar-image pairs (scale variants)", () => {
234
+ let pass = 0;
235
+ for (let i = 0; i < 50; i++) {
236
+ const small = makeImage(32, 32, (x, y) => [(x + i) * 4 % 256, (y * 2) % 256, 128]);
237
+ const large = makeImage(64, 64, (x, y) => [(Math.floor(x / 2) + i) * 4 % 256, (Math.floor(y / 2) * 2) % 256, 128]);
238
+ if (hammingDistance(perceptualHash(small), perceptualHash(large)) <= 4)
239
+ pass++;
240
+ }
241
+ expect(pass / 50).toBeGreaterThanOrEqual(0.975);
242
+ });
243
+ it("MEASURED ≥97.5% pHash DISCRIMINATION across 50 distinct-image pairs", () => {
244
+ let pass = 0;
245
+ const hashes = [];
246
+ for (let i = 0; i < 50; i++) {
247
+ const img = makeImage(32, 32, (x, y) => [(x * (i + 1)) % 256, (y * (i + 7)) % 256, (i * 11) % 256]);
248
+ hashes.push(perceptualHash(img));
249
+ }
250
+ // Compare every pair; count those with Hamming >= 8 as "discriminated"
251
+ let pairCount = 0;
252
+ let okCount = 0;
253
+ for (let i = 0; i < hashes.length; i++) {
254
+ for (let j = i + 1; j < hashes.length; j++) {
255
+ pairCount++;
256
+ if (hammingDistance(hashes[i], hashes[j]) >= 8)
257
+ okCount++;
258
+ }
259
+ }
260
+ pass = okCount;
261
+ const total = pairCount;
262
+ expect(pass / total).toBeGreaterThanOrEqual(0.975);
263
+ });
264
+ it("MEASURED 100% flag accuracy: 10 stolen scenarios → 10 STOLEN_PHOTO flags", () => {
265
+ let pass = 0;
266
+ for (let trial = 0; trial < 10; trial++) {
267
+ let r = emptyRegistry();
268
+ const pHash = `${trial.toString(16).padStart(2, "0")}${"00".repeat(7)}`;
269
+ for (let i = 0; i < 11; i++) {
270
+ r = recordObservation({ registry: r, pHash, claim: "x", sellerFingerprint: `t${trial}-s${i}`, nowMs: 1_000_000 + i, secret: SECRET });
271
+ }
272
+ const v = evaluatePhash({ registry: r, pHash, nowMs: 2_000_000 });
273
+ if (v.flags.includes("STOLEN_PHOTO"))
274
+ pass++;
275
+ }
276
+ expect(pass).toBe(10);
277
+ });
278
+ });
279
+ //# sourceMappingURL=provenance_dna.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provenance_dna.test.js","sourceRoot":"","sources":["../../src/provenance_dna/provenance_dna.test.ts"],"names":[],"mappings":"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"}