# Shade V3.3 — Fingerprint Gates & Trust UX

**Status:** Done
**Effort:** M (2–4 uker)
**Forrige:** V3.1
**Adresserer:** V2.3 §1B
**Implementert:** se `docs/trust-ux.md`

---

## Mål

Gjør safety numbers **handlingspålagte** — ikke bare synlige — i flyt der
MITM-risikoen er reell. I dag finnes `FingerprintCompare`-widget og
`requireFingerprintVerifiedFor` i `@shade/files`, men hovedkjernen
(`Shade.send`, first-large-file, backup-import) har ingen automatisk gate.
Resultat: alert-fatigue-fri, men også gate-fri.

Dette legger inn **eksplisitt blokkerende verifisering** på et lite antall
kritiske hendelser, plus widget-støtte for å eksponere det i UI.

---

## Scope

### Inn — kritiske hendelser

1. **Før første store fil** — `Shade.upload` over en bytes-terskel uten
   verifisert peer.
2. **Før backup-import** — `Shade.importBackup` blokkerer til peer (eller egen
   identitet) er bekreftet.
3. **Ny enhet med rotert identitet** — `acceptIdentityChange` blokkerer på
   første bruk inntil verifisert.
4. **Før `@shade/inbox` fan-out** (V3.6) — gate per mottaker.

### Inn — APIer

- `Shade.beforeFirstLargeFile(threshold, handler)` — appen får mulighet til å
  vise modal og returnere bekreftelse.
- `Shade.beforeBackupImport(handler)` — samme mønster.
- `Shade.beforeNewDeviceTrust(handler)` — ditto.
- `Shade.markPeerVerified(address)` / `Shade.isPeerVerified(address)` —
  persistent state.

### Inn — widgets

- `<FingerprintGate />` — render-prop wrapper som blokkerer barn til
  verifisert.
- `<FingerprintCompare />` utvides med "kopier OOB-tekst" + "jeg har
  verifisert".

### Ut

- "Tving alle peers verifisert før hver melding" — alert fatigue.
- Cross-device sync av verified-state (kommer evt. via V3.6 inbox).

---

## Design

### Persistent verified-state

Ny tabell `peer_verifications`:

```sql
CREATE TABLE peer_verifications (
  peer_address      TEXT PRIMARY KEY,
  fingerprint       TEXT NOT NULL,
  verified_at       INTEGER NOT NULL,
  verified_by       TEXT,        -- "user" | "transitive" | "tofu-after-warning"
  identity_version  INTEGER NOT NULL  -- knytter verifikasjon til identity-rotasjon
);
```

Når peer roterer identitet → `identity_version` bumper → verifikasjon "ugyldig"
til ny verifisering.

### Hook-flyt

```text
shade.upload(peer, file)
    │
    ├─ if !verified(peer) AND file.size > threshold
    │    │
    │    └─ await beforeFirstLargeFileHandler(peer, fingerprint)
    │          ├─ true  → markPeerVerified(peer); proceed
    │          └─ false → throw FingerprintNotVerifiedError
    │
    └─ proceed
```

---

## Leveranser

### Kode

- `@shade/core` — `peer_verifications`-tabell + storage methods.
- `@shade/sdk` — gate-hooks + `markPeerVerified` / `isPeerVerified`.
- `@shade/widgets` — `<FingerprintGate />`, utvidet `<FingerprintCompare />`.

### Tester

- Unit: gate kalles, ikke kalles, retur false → throw, retur true → proceed.
- Integration: fil < threshold går gjennom uten gate; fil > threshold
  blokkerer.
- Identity-rotasjon ugyldiggjør verifikasjon.
- Backup-import blokkerer.

### Dokumentasjon

- `docs/trust-ux.md` — guide til hvilke gates som finnes og når de bør tunes.

---

## Akseptansekriterier

- [ ] Gate kan ikke bypasses ved å nulle `threshold` ut — minimum gate finnes
      alltid for backup-import og new-device.
- [ ] App uten registrerte gates får sane defaults (logger en warning, men
      kjører — ikke krasj).
- [ ] Identity-rotasjon resetter verifikasjon i en testet ende-til-ende-flow.
- [ ] Widget kan rendres SSR uten å trigge runtime-gate.

---

## Avhengigheter

- V3.1 — threat-matrise oppdatert til å vise hvilke gates som dekker hvilke
  rader.

---

## Risiko

- **Alert fatigue.** Hvis terskler er for lave → bruker klikker blindt.
  Mitiger ved å sette default-terskler høyt (10 MiB for first-large-file)
  og dokumenter justerings-guide.
- **DX-friksjon.** Apper som ikke vet om gates får uventede prompts. Mitiger
  ved å logge tydelig ved første aktivering: "Shade.beforeFirstLargeFile not
  configured — using default modal".

---

## Migrasjon

0.3.x apps får defaults aktivert med warning. Ingen breaking change.
