# Pre-audit checklist

What we prepare before the attestation engagement kicks off. This list is
public so customers and prospective auditors can see we already do the
work — they don't have to take "we're audit-ready" on faith.

## 1. RLS posture documented

- [x] Every table is covered by `enable row level security` (see
  `supabase/migrations/0002_rls.sql` and every subsequent migration).
- [x] `revoke insert, update, delete from anon, authenticated` is the
  default; mutations go through service-role code paths or explicit
  per-table grants.
- [x] `is_admin()`, `owns_profile()`, `current_user_id()` helpers are
  defined once and re-used so the auditor only needs to read the
  helpers, not every policy.
- [x] No public table exposes PII without a SELECT policy gated by
  `current_user_id()` or `is_admin()`.

## 2. Success-rate measurement methodology

- [x] `public.broker_success_rates` view aggregates the last 180 days
  per broker. Suppresses below 5 attempts to keep small-sample noise
  out. Re-checked by the audit-metrics endpoint with a 50-decisive
  threshold for the overall percentage.
- [x] The view is `security_invoker = true` so RLS still applies — no
  PII leakage path even to an unauthenticated reader.

## 3. Sample data export

- [x] We can produce on demand: 30 random `request_ids` with status
  `verified_removed`, their full event log, attached evidence, and
  signed storage URLs.
- [x] Production data export tooling lives under
  `apps/worker/src/scripts/` and is exercised manually before each
  attestation period.

## 4. Evidence retention proof

- [x] Storage buckets (`evidence`, `mandates`, `identity-docs`, `audit`)
  are private — no anonymous bucket policies.
- [x] Every uploaded object is content-addressed via SHA-256
  (`apps/worker/src/lib/storage.ts`) and stored under a path that
  includes the request id; the auditor can verify a screenshot has
  not been tampered with by re-hashing.
- [x] `request_events` is INSERT-only via service-role; we have never
  truncated it.

## 5. PII handling code paths

- [x] Customer DOB is encrypted at rest via `encryptPII()` /
  `decryptPII()` (see `packages/core/src/lib/encryption.ts`). The
  database column type is text; the value is opaque ciphertext.
- [x] No call to a third-party API in the codebase sends customer
  PII outside the per-broker opt-out submission path. The auditor
  can grep for `fetch(` and `axios(` and verify.
- [x] Identity documents (when supplied for high-friction brokers)
  live in the `identity-docs` bucket and are deleted once the
  opt-out is verified or the related manual task is closed.

## 6. Pause / cancel respected

- [x] `provisionRequests()` skips subscriptions with
  `paused_at IS NOT NULL`.
- [x] `runRecheckCron()` joins to profiles and filters out paused
  users before processing.
- [x] Tested under load: 1 000 paused profiles, zero new
  optout_requests created in a 24-h window.

## 7. Per-removal evidence trail

- [x] Each opt-out request transitions through a fixed state machine
  (see `packages/core/src/engine/transitions.ts`). Invalid
  transitions throw.
- [x] PDF removal certificates are generated on demand from the
  on-record state and the latest screenshot
  (`apps/web/src/lib/pdf-certificate.ts`).
- [x] Per-broker removal diff (introduced 2026 Q2) captures a
  before/after snapshot of the broker's public profile page so the
  user can see what was actually removed.

## 8. What we are knowingly NOT claiming

- We do not claim 100 % removal success — broker non-compliance is
  real, especially for `manual` brokers. The published rate is the
  measured rate, not an aspirational one.
- We do not claim the audit covers our security posture
  (encryption-at-rest hosting, network controls) — that is a separate
  SOC-2 engagement, not part of the privacy attestation scope.
- We do not pre-announce the audit's outcome. The first published
  report will say verbatim what passed, what was qualified, and what
  failed.
