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
↓ peach-browser-7f3794c1.tar.gzatlas at this save
files changed5 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 −1src/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 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);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 });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 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