# pvtcoms — v1 Build Plan (the straight-to-code spec)

> The **pruned, decided, build-ready** plan. Everything here is v1 scope; everything not here is explicitly deferred.
> Reconciled from a final Codex + Gemini + Claude pass (they agreed on ~90% of the cut). The rich exploration lives in
> [`DESIGN.md`](./DESIGN.md) (v2+ reference); the boundary in [`THREAT_MODEL.md`](./THREAT_MODEL.md); the map in
> [`README.md`](./README.md). Last updated 2026-05-30.

## The v1 thesis (what we are proving)
> **Two people can exchange 1:1 messages that are anonymous, serverless, and post-quantum encrypted — and it actually works
> over a hostile network.** Nothing more. Prove the core, then expand.

## Locked v1 decisions
| Decision | v1 choice | Note |
|---|---|---|
| Platforms | **Android + Desktop (Tauri)** | iOS **deferred** (Apple background limits — months of pain for little v1 value). |
| Chat model | **1:1 only** | Groups deferred (O(N²) state complexity). |
| Transport | **Tor (`arti`) only** | No Nym, no direct mode, no transport UI. One uniform path. |
| Crypto | **Hybrid X25519+ML-KEM-768 handshake + standard Double Ratchet** | PQ *handshake* (harvest-now-decrypt-later defence) now; PQ *ongoing ratchet* deferred. |
| Delivery | **Pull-to-refresh** (oblivious rotating-token mailbox) | No push. Be honest: "open the app to get messages." |
| Media | **Text + simple attachments** | Voice/video notes deferred; live calls far deferred. |
| Identity | **One identity per device** | Multi-device/same-identity sync deferred (host/controller is v2). |
| Onboarding | **Single-use invite link + SAS verification** | Self-detecting link theft; default contact state "unverified". |
| Settings (v1 only) | SAS verify · ephemeral timer (off/1d/7d/30d) · clear local cache · Tor bootstrap status/retry · content-free notifications | Rich settings matrix deferred. |
| Storage | **SQLCipher at-rest + DB passphrase + key in OS keystore** | Mandatory from day one. |

## Scope: IN / DEFERRED
**✅ IN v1:** 1:1 text + attachments · PQ handshake + Double Ratchet · `arti` Tor transport · oblivious rotating-token
mailbox (pull) · single-use invite + SAS + key-change alerts · ephemeral messages (TTL) · SQLCipher at-rest + keystore +
FLAG_SECURE + memory zeroize · Android + Desktop · content-free notifications · simple PoW gate on mailbox submit.

**🟡 DEFER v2:** host/controller multi-device · Sender-Keys groups · async voice/video notes · iOS (with oblivious APNs relay) ·
PQ ongoing ratchet · richer settings · per-contact identity-bound transport profiles UI · introduction-by-mutual-contact ·
duress passcode / hidden profiles · key-transparency device log.

**🔴 DEFER v3+ / not now:** live voice/video calls (SFrame/WebRTC) · MLS production groups · Nym mixnet · message-franking
abuse reporting · full feature-parity polish · BLE/offline mesh transport.

## v1 architecture (minimal)
```
Rust core (one workspace)                       UniFFI ──► Android (Kotlin/Compose)
  identity keys (Ed25519+ML-DSA-65)                    └─► Desktop (Tauri, Rust in-process)
  hybrid X25519+ML-KEM-768 handshake (PQXDH-style)
  Double Ratchet + ChaCha20-Poly1305
  arti Tor transport  +  oblivious mailbox (pull, rotating tokens)
  SQLCipher store (key in Keystore/Keychain)
```
Native layer owns lifecycle/scheduling/power; Rust never an always-on daemon. (§14.2)

## Milestones (M0 → M5) with exit criteria
**M0 — Walking skeleton (this week).** Two Rust CLIs: Client A opens an ephemeral `.onion` via `arti` and listens; Client B
connects (address pasted manually) and sends "hello". *No crypto yet.* **Exit:** a string crosses Tor between two processes.

**M1 — Crypto core (critical path).** Rust crate: identity keys, hybrid handshake, Double Ratchet state machine; deterministic
**test vectors** + property/fuzz tests for ratchet invariants. **Exit:** vectors committed; two in-process sessions exchange
messages; ratchet survives out-of-order/dropped messages without desync.

**M2 — Transport + session (Tor-only).** `arti` integration, circuit/session lifecycle, reconnect/backoff, fixed-size padded
envelopes; M1 crypto piped through. **Exit:** two peers session reliably over Tor under adverse-network tests; **no plaintext
metadata in logs.**

**M3 — Rendezvous + mailbox MVP.** Single-use invite + SAS flow; rotating mailbox tokens; pull/poll delivery with ack/
idempotency; simple PoW submit gate. **Exit:** async message survives an offline recipient; token rotation loses no messages;
link-theft simulation fails the thief visibly; spam cost enforced.
> Progress (2026-05-31): mailbox addressing + **production relay** done — gated/open access, request-bound PoW gate, replay/
> freshness, TTL, keep-alive, persistence (async message survives an offline recipient + relay restart); onion-only deploy
> bundle (`deploy/`). Remaining for M3: single-use invite + SAS rendezvous, and directory records (connect-by-identity).

**M4 — App integration (Android + Desktop).** UniFFI bindings; encrypted local store; 1:1 chat UI + onboarding + verification
UX; pull-to-refresh. **Exit:** a non-technical tester onboards, verifies SAS, and exchanges messages; crash-free core flows;
persistence + expiry verified.

**M5 — Hardening + closed beta.** Threat-model-to-tests mapping; red-team misuse tests (replay, token theft, MITM onboarding);
telemetry-free diagnostics; reproducible builds; packaging. **Exit:** security regression suite green; 20–50-user beta with an
issue SLA. *(Named third-party audit before any public "secure" claim.)*

**Critical path:** M0 → M1 → M2 → M3 (hard). **Parallel from day 1:** CI + reproducible-build harness; UI shell against a mock
core (after M1 interfaces stabilise); telemetry-free diagnostics.

## Non-negotiable guardrails (the project killers to avoid)
- **No serverless "anonymous push."** It doesn't exist; chasing it sinks the project. Ship **pull-to-refresh**, honestly. (The
  iOS oblivious-APNs-relay is a *v2* concession, not a v1 rabbit hole.)
- **Stop expanding `DESIGN.md`; write code that fails.** The risk now is analysis-paralysis — 16 sections of Markdown, zero
  bytes on the wire.
- **The one thing to get right in the first 3 months:** **cryptographic/session-state correctness and recoverability under
  real network failure.** If the ratchet ever desyncs or silently drops messages, trust is gone and nothing else matters.

## Final decisions — adopted defaults + the two that need Rui
Adopted (advisor consensus): **iOS = deferred**, **live calls/voice notes = deferred (text v1)**, **Tor-only**, **1:1 only**,
**per-contact transport = identity-profiles in model, no v1 UI**.

**DECIDED 2026-05-30:**
- **Target user / positioning (SR-002): high-threat first, then broaden.** Build the uncompromised high-threat core
  (activist/journalist/source) with safe defaults and embraced friction; add opt-in convenience for daily-drivers later
  *without weakening defaults*. Anonymity always wins over convenience.

- **License (SR-001): AGPL-3.0-or-later** — decided 2026-05-30 (see [ADR-002](./docs/ADR/002-license-agpl-3.0.md)).
  With an App Store additional-permission exception, a **DCO** (not CLA), a separate trademark policy, reproducible builds +
  audits as the real trust mechanism, and a `cargo-deny` license allowlist. Matches the trust-critical peer group
  (Signal/SimpleX/Molly/Element/Threema); forecloses backdoored proprietary forks; not forced by any v1 dependency. Impl: SR-004.
