# PCH-02-FIXES — Integration Contract Source of truth for integrating these drafts. Where a patch file and this contract disagree, this contract wins. ## Integration Contract ### Files in `src/drafts/PCH-02-FIXES/` | Draft file | Destination / role | |---|---| | `README.md` | index — stays in drafts (or trash after integration) | | `INTEGRATION-CONTRACT.md` | this file — keep as reference (cited by tests) | | `PCH-02-001-vault-patch-sanitizers.patch.md` | edits → `src/background/vault.ts:2375-2388` | | `vault.update-entry-sanitize.test.ts` | → `src/background/vault.update-entry-sanitize.test.ts` | | `PCH-02-002-noise-xx-msg1-hash.patch.md` | doc part → `src/shared/noise-js.ts:11-14` + `src/shared/noise-xx.ts:17`; wire part **deferred** | | `PCH-02-003-sas-trust-model-comment.patch.md` | edits → `src/shared/chirp-handshake.ts:125-154` | | `PCH-02-004-exact-pin-deps.patch.md` | edits → `package.json:40-46`; then `bun install` | | `WASM-PROVENANCE.md` | → repo root `WASM-PROVENANCE.md` (new file) | | `PCH-02-005-legacy-pbkdf2-doc.patch.md` | edits → `src/shared/backup.ts:146` + `src/popup/views/Import.tsx` (3 hunks) | | `PCH-02-006-vault-id-privacy-note.patch.md` | edits → `src/shared/sync-identity.ts:62-67` | | `PCH-02-007-hibp-add-padding.patch.md` | edits → `src/background/vault.ts:230` | | `vault.hibp-padding.test.ts` | → `src/background/vault.hibp-padding.test.ts` | | `PCH-02-008-binaryreader-bounds.patch.md` | edits → `src/crypto/peachPayload.ts:940-969` (+ `export` seam) | | `peachPayload.binaryreader-bounds.test.ts` | → `src/crypto/peachPayload.binaryreader-bounds.test.ts` | | `PCH-02-009-reject-zero-dh.patch.md` | edits → `src/shared/noise-xx.ts` (6 sites) + `src/shared/noise-js.ts` (6 sites) | | `noise.reject-zero-dh.test.ts` | → `src/shared/noise.reject-zero-dh.test.ts` | | `PCH-02-010-clipboard-hash-match.patch.md` | **Option A (recommended):** comment → `src/background/clipboard.ts:18-19`. **Option B:** `clipboard.ts` + `offscreen.ts` + `manifest.json` | | `clipboard.hash-match.test.ts` | → `src/background/clipboard.hash-match.test.ts` — **Option B ONLY; do not integrate under Option A** | ### Decisions required from the integrator (2) 1. **PCH-02-010 Option A vs B.** Option B requires adding `clipboardRead` to `manifest.json` — a store-visible permission expansion ("Read data you copy and paste"). Recommendation: Option A now, Option B parked. 2. **PCH-02-004 papaparse hunk.** The brief pins 5 packages; the report also cites `papaparse`. The patch includes it as an optional sixth line. ### ⚠ PCH-02-002 wire-change coordination (MUST land with Android) The Noise XX msg-1 empty-payload `mixHash` changes every XX handshake ciphertext from msg 2 onward. **Do not apply the wire part** until the matching peach-android change ships in the same release (PCH-01-002 / v3.9.1-android-v2.2.9 model). What lands now: the deferral comment in `noise-xx.ts`, the corrected `snow`-interop claim in `noise-js.ts`, and the ready-to-apply patch staying in this folder. When the window opens: apply the two `mixHash(new Uint8Array(0))` insertions, regenerate the XX vectors in `noise-xx.test.ts`/`noise-blake2s-kat.test.ts`, and regenerate the matching Android `CrossPlatformKATTest` vectors. ### PCH-02-004 exact versions (read from bun.lock 2026-06-12 — pin, don't upgrade) | Package | Pin | |---|---| | otpauth | 9.5.0 | | pako | 2.1.0 | | @zxing/library | 0.23.0 | | bwip-js | 4.11.1 *(lockfile had drifted above the declared ^4.10.1)* | | pdf-lib | 1.17.1 | | papaparse | 5.5.3 *(optional hunk)* | After the edit run `bun install` (regenerates `bun.lock`; resolved tree is unchanged because every pin equals the installed version). ### Estimated test count per finding | Finding | New tests | |---|---| | PCH-02-001 | 8 | | PCH-02-002 | 0 now (KAT regeneration when the wire change lands) | | PCH-02-003 | 0 — doc only (gateOnSAS already pinned by PCH-01-024 test) | | PCH-02-004 | 0 — dependency metadata only | | PCH-02-005 | 0 required (1 optional UI contract case sketched in the patch) | | PCH-02-006 | 0 — doc only | | PCH-02-007 | 3 | | PCH-02-008 | 8 | | PCH-02-009 | 5 | | PCH-02-010 | Option A: 0 — doc only / Option B: 4 | | **Total** | **24 (Option A) / 28 (Option B)** | ### Documentation-only findings (no tests needed) PCH-02-003, PCH-02-005 (comment + notice), PCH-02-006, PCH-02-002 (the part landable now), PCH-02-010 under Option A. ### Suggested integration order (one koh save each, tests green at every step) 1. PCH-02-001 (the Low) + its tests 2. PCH-02-007, PCH-02-008, PCH-02-009 + tests (independent hardening) 3. PCH-02-003, PCH-02-005, PCH-02-006 + PCH-02-002 doc part (comments/UI) 4. PCH-02-004 (package.json + `bun install` + WASM-PROVENANCE.md) 5. PCH-02-010 (whichever option is chosen) 6. Version bump + build all three targets (`npm run build`) ### Gates after every save - `npx tsc --noEmit` clean (baseline: clean) - `npx vitest run` — baseline 117 files / 3474 passed; after full integration expect **+4 test files / +24 tests** (Option A) or **+5 / +28** (Option B) - No `@ts-ignore` / type suppressions introduced (none in any draft) ### Version bump recommendation v4.0.0 → **v4.0.1** (patch: hardening + docs, no feature surface) across `package.json`, `manifest.json`, `manifest.firefox.json`, then `npm run build` (all three targets, per project rule). If PCH-02-010 Option B is chosen, bump v4.0.0 → **v4.1.0** instead — a new permission is not a patch-level change. ### Out-of-scope observations recorded during drafting - `vault.updateEntryDirect` (vault.ts:1978) spreads patches verbatim but has zero production callers — dead-code candidate, noted in the 001 patch. - The fix brief's PCH-02-005 text says "100,000 iterations"; the code and report say 250,000 — drafts use 250,000. - The brief's PCH-02-004 step references an existing `WASM-PROVENANCE.md`; no such file exists in the repo, so the draft ships one.