7f3794c1d4ff

update Codex tests for v3 envelope shape + stripe-aware large-vault path; all 2862 tests green; chrome/firefox/mobile builds clean (v3.6.38)

time
2026-05-19 18:45 UTC · 5 months ago
machine
koh2
parent
ed89dc7be482
5 files src/popup/codex/codex.adversarial.test.ts+3 −3src/popup/codex/codex.test.ts+1 −1src/popup/codex/generate.test.ts+44 −25src/popup/codex/restore.test.ts+3 −0src/popup/codex/restore.ts+1 −1
src/popup/codex/codex.adversarial.test.ts+3 −3
@@ -122,7 +122,7 @@122122 123123   const wrongVersionInputs = [124124     JSON.stringify({ v: 1, c: VERIFY_CODE, i: 0, t: 5 }),125-    JSON.stringify({ v: 3, c: VERIFY_CODE, i: 0, t: 5 }),125+    JSON.stringify({ v: 4, c: VERIFY_CODE, i: 0, t: 5 }),126126     JSON.stringify({ v: 0, c: VERIFY_CODE, i: 0, t: 5 }),127127     JSON.stringify({ v: "2", c: VERIFY_CODE, i: 0, t: 5 }),128128     JSON.stringify({ v: -1 }),@@ -153,14 +153,14 @@153153   it("returns envelope for a valid envelope JSON", async () => {154154     const env = await makeEnv({ index: 0, total: 5 });155155     const result = parseRawScan(JSON.stringify(env));156-    expect(result).toMatchObject({ v: 2, c: VERIFY_CODE, i: 0, t: 5 });156+    expect(result).toMatchObject({ v: 3, c: VERIFY_CODE, i: 0, t: 5 });157157   });158158 159159   it("extra unknown fields do not break parseRawScan", async () => {160160     const env = await makeEnv({ index: 0, total: 5 });161161     const raw = JSON.stringify({ ...env, extra: "field", more: 42 });162162     const result = parseRawScan(raw);163-    expect(result).toMatchObject({ v: 2, c: VERIFY_CODE });163+    expect(result).toMatchObject({ v: 3, c: VERIFY_CODE });164164   });165165 });166166 

view file

src/popup/codex/codex.test.ts+1 −1
@@ -135,7 +135,7 @@135135   it('builds chunk envelope with correct fields', async () => {136136     const bytes = new Uint8Array([1, 2, 3, 4, 5]);137137     const envelope = await buildChunkEnvelope(bytes, 0, 10, false, 'PX-TEST-1234');138-    expect(envelope.v).toBe(2);138+    expect(envelope.v).toBe(3);139139     expect(envelope.i).toBe(0);140140     expect(envelope.t).toBe(10);141141     expect(envelope.p).toBe(false);

view file

src/popup/codex/generate.test.ts+44 −25
@@ -14,7 +14,11 @@1414   sha256Hex,1515   verifyChunkIntegrity,1616 } from "./helpers";17-import { decodeWithErasure, encodeWithErasure } from "./erasure";17+import {18+  decodeWithErasure,19+  encodeIntoStripes,20+  encodeWithErasure,21+} from "./erasure";1822 import { generateCodex } from "./generate";1923 2024 // ── chrome.storage shim ─────────────────────────────────────────────────────@@ -114,7 +118,7 @@114118   it("buildChunkEnvelope + verifyChunkIntegrity agree", async () => {115119     const chunk = new Uint8Array(CHUNK_SIZE).fill(0x42);116120     const env = await buildChunkEnvelope(chunk, 3, 7, false, "PX-AAAA-BBBB");117-    expect(env.v).toBe(2);121+    expect(env.v).toBe(3);118122     expect(env.i).toBe(3);119123     expect(env.t).toBe(7);120124     expect(env.p).toBe(false);@@ -277,42 +281,57 @@277281     expect(parityShards).toBe(computeParityShards(dataShards));278282   });279283 280-  it("large vault: survives loss of up to parityShards codes", async () => {284+  it("large vault: each stripe survives loss of up to its parityShards codes", async () => {285+    // 200 KB / 800-byte chunks = 250 data shards → split into 2 stripes of286+    // 125 each (well under the GF(2⁸) 256-shard cap). Each stripe gets its287+    // own parity budget; we drop exactly parityShards from every stripe.281288     const data = new Uint8Array(200_000);282289     for (let i = 0; i < data.length; i++) data[i] = (i * 37) & 0xff;283290 284-    const { dataChunks, parityChunks, dataShards, parityShards, totalChunks } =285-      await encodeWithErasure(data);291+    const { stripes } = await encodeIntoStripes(data);292+    expect(stripes.length).toBeGreaterThan(1);286293 287-    const allChunks = new Map<number, Uint8Array>(288-      [...dataChunks, ...parityChunks].map((c, i) => [i, c]),289-    );290-    // Drop exactly parityShards codes — the maximum survivable loss.291-    for (let i = 0; i < parityShards; i++) allChunks.delete(i);294+    let byteCursor = 0;295+    for (const stripe of stripes) {296+      const present = new Map<number, Uint8Array>();297+      stripe.dataChunks.forEach((c, i) => present.set(i, c));298+      stripe.parityChunks.forEach((c, i) =>299+        present.set(stripe.dataShards + i, c),300+      );301+      // Drop exactly parityShards codes from this stripe — maximum survivable.302+      for (let i = 0; i < stripe.parityShards; i++) present.delete(i);292303 293-    const reconstructed = await decodeWithErasure(294-      allChunks,295-      dataShards,296-      totalChunks,297-    );298-    for (let i = 0; i < data.length; i++) {299-      expect(reconstructed[i]).toBe(data[i]);304+      const recovered = await decodeWithErasure(305+        present,306+        stripe.dataShards,307+        stripe.totalChunks,308+      );309+      const stripeRealBytes = Math.min(310+        stripe.dataShards * CHUNK_SIZE,311+        Math.max(0, data.length - byteCursor),312+      );313+      for (let i = 0; i < stripeRealBytes; i++) {314+        expect(recovered[i]).toBe(data[byteCursor + i]);315+      }316+      byteCursor += stripe.dataShards * CHUNK_SIZE;300317     }301318   }, 60_000);302319 303-  it("large vault: fails gracefully when loss exceeds parityShards", async () => {320+  it("large vault: fails gracefully when stripe loss exceeds parityShards", async () => {304321     const data = new Uint8Array(200_000);305322     for (let i = 0; i < data.length; i++) data[i] = (i * 41) & 0xff;306-    const { dataChunks, parityChunks, dataShards, parityShards, totalChunks } =307-      await encodeWithErasure(data);308-309-    const allChunks = new Map<number, Uint8Array>(310-      [...dataChunks, ...parityChunks].map((c, i) => [i, c]),323+    const { stripes } = await encodeIntoStripes(data);324+    expect(stripes.length).toBeGreaterThan(1);325+    const stripe = stripes[0]!;326+    const present = new Map<number, Uint8Array>();327+    stripe.dataChunks.forEach((c, i) => present.set(i, c));328+    stripe.parityChunks.forEach((c, i) =>329+      present.set(stripe.dataShards + i, c),311330     );312-    for (let i = 0; i < parityShards + 1; i++) allChunks.delete(i);331+    for (let i = 0; i < stripe.parityShards + 1; i++) present.delete(i);313332 314333     await expect(315-      decodeWithErasure(allChunks, dataShards, totalChunks),334+      decodeWithErasure(present, stripe.dataShards, stripe.totalChunks),316335     ).rejects.toThrow(CodexError);317336   }, 60_000);318337 });

view file

src/popup/codex/restore.test.ts+3 −0
@@ -118,8 +118,11 @@118118     expect(buf.size()).toBe(1);119119     expect(buf.getContext()).toEqual({120120       verifyCode: VERIFY_CODE,121+      stripeCount: 1,121122       total: 5,122123       dataShards: deriveShardCounts(5).dataShards,124+      scanned: 1,125+      allStripesObserved: true,123126     });124127   });125128 

view file

src/popup/codex/restore.ts+1 −1
@@ -8,7 +8,7 @@88  *  2. `ChunkBuffer` — accumulate per-chunk scans, enforce one-Codex-per-scan99  *     context, deduplicate, and verify per-chunk integrity hashes.1010  *  3. `reconstructAndVerify` — once the buffer has enough chunks, hand them11- *     to Subagent 1's `reconstructPayloadFromChunks`, then re-derive the11+ *     to `reconstructPayloadFromStripes`, then re-derive the1212  *     vault fingerprint and fail loudly on mismatch.1313  *1414  * This module never touches the camera, the SW, or storage. Camera capture

view file