# sar-composer.screen Quinn fulfills a GDPR / CCPA subject access request a prospect emailed her. Pairs with [brief V §V3](./V-data-portability-erasure.brief.md) — the prospect-side SAR flow. The composer scopes, redacts, and sends an export of a single prospect's data, on the prospect's behalf, with platform internals redacted by default. Voice register: **plain** throughout — per [`voice.md`](./00-system-voice.md) §V2c. SARs are legally consequential. No metaphor; exact nouns, short sentences. ## Layout (full-screen composer) ``` ┌─────────────────────────────────────────────────┐ │ ◄ Privacy Preview │ 56pt top bar ├─────────────────────────────────────────────────┤ │ │ │ Subject access request │ title (plain) │ A prospect has asked what data you hold on them.│ │ │ │ ─── Prospect ────────────────────────────── │ │ ╭───────────────────────────────────────╮ │ │ │ Search by phone, email, or handle │ │ prospect lookup │ ╰───────────────────────────────────────╯ │ │ │ │ Felix · +49 30 12345678 · 14 messages · 8 wks │ lookup result row │ │ │ ─── Scope ────────────────────────────────── │ │ ● All data on this prospect │ │ ○ Date range [ 2026-02-01 ] → [ 2026-05-18 ] │ │ │ │ ─── Format ───────────────────────────────── │ │ ● Markdown bundle (human-readable) │ │ ○ JSON archive │ │ │ │ ─── Delivery ─────────────────────────────── │ │ ● Prepared link (you send it manually) │ │ ○ Auto-email via mail-sync to felix@example.com │ │ (verified 2026-04-02) │ │ │ │ ─── Redaction preview ────────────────────── │ │ 9 fields · 4 included · 5 redacted · review ▾ │ expandable table │ │ │ ─── Refuse instead ──────────────────────── │ │ [ Refuse this SAR ] │ secondary action │ │ └─────────────────────────────────────────────────┘ ↓ Preview routes to ready-to-send sheet ↓ ``` ## Ready-to-send sheet (state 6) ``` ┌─────────────────────────────────────────────────┐ │ Send SAR to Felix │ │ │ │ 14 message exchanges over 8 weeks. │ │ Markdown bundle · 28 KB. │ │ Delivery: prepared link. │ │ 5 fields redacted (platform internals). │ │ │ │ [ Hold off ] [ Generate link ] │ └─────────────────────────────────────────────────┘ ``` ## Component table | Component | Notes | |---|---| | Top bar | Back to Privacy (S8); Preview disabled until prospect + scope set. | | Prospect lookup | Free-text search against hashed phone / email / display name. Returns at most 5 candidates with message count + first-contact date. | | Lookup result row | Tap to select. Selected row pinned above search field. | | Scope picker | All-data default; date-range secondary with two date fields. | | Format picker | Markdown bundle default (per V3a — human-readable for SAR). JSON archive secondary. | | Delivery picker | Prepared-link default (Quinn previews + sends). Auto-email disabled until prospect has a verified email on file. | | Redaction preview | Collapsed summary line; tap to expand the per-field table (next section). | | Refuse action | Routes to refusal path (state 8). Secondary visual weight. | | Preview button | Activates when prospect + scope + format + delivery set. | ## States 1. **Default** — empty composer; only prospect lookup active; everything below greyed. 2. **Prospect-lookup-results** — search returned candidates; tap to select. Multi-match disambiguation if 2+ rows match the hash. 3. **Scope-narrowed** — date-range chosen; message-count estimate updates in real time ("8 messages in window"). 4. **Redaction-preview-rendered** — expanded table (below) visible; per-row override controls active. 5. **Auto-redaction-flipped-by-Quinn** — Quinn flipped an "included" row to "redacted" (one-tap, allowed) or attempted to flip "redacted" → "included" (gated by override modal — typed-confirm + reason). 6. **Ready-to-send** — Preview tapped; confirmation sheet shown above. 7. **Sent confirmation** — receipt strip in chat-home: "SAR sent to felix@example.com via Proton. 14 message exchanges over 8 weeks. Redacted by default." Audit row recorded with `action_type='sar_fulfilled'`. 8. **Refusal path** — refusal sheet replaces composer body. Two required fields: reason (text) + date of refusal-grounds (e.g. "active dispute since 2026-04-10"). 9. **Refusal-reason-typed** — both fields filled; "Log refusal" button activates. On submit, audit row recorded with `action_type='sar_refused'` and the reason payload; banner reminds Quinn the prospect can escalate to a regulator. ## Redaction preview table Per V3b. Renders inside the expanded "Redaction preview" section. | Field | Status | Reason | Override | |---|---|---|---| | Their messages to Quinn | included | their own data | flip to redacted (one-tap) | | Quinn's replies to them | included | their conversation | flip to redacted (one-tap) | | Their attachments | included | their own data | flip to redacted (one-tap) | | Timestamps + thread structure | included | their conversation shape | flip to redacted (one-tap) | | Quinn's drafts that never sent | redacted | Quinn's drafts, not theirs | override gated | | Specialist / agent IDs that handled them | redacted | platform internal | override gated (K platform-internals invariant — see Privacy invariants) | | Quinn's audit decisions about them | partial | event types kept; internal reasoning redacted | override gated | | Coop reports about them | redacted | shared coop data — separate request path (brief N) | not overrideable | | Prospect_id + internal flags | redacted | platform metadata | not overrideable | | Quinn's persona data | redacted | not their data | not overrideable | | Hotel addresses if mentioned in thread | redacted | brief K §K3f-2 hard rule | not overrideable | | Quinn's govt name if referenced | redacted | brief K §K3c-1 hard rule | not overrideable | Override-gated rows open a typed-confirm modal: "Include this in the export. Type `include` to confirm." Not-overrideable rows show a lock glyph + tooltip pointing to the governing brief. ## In-the-wild copy **Composer header** (plain): > A prospect has asked what data you hold on them. Build the export, review what's included, and send. **Auto-redaction explainer** (plain, in redaction-preview header): > 5 fields are redacted by default. They cover platform internals, your drafts, and other people's data. You can include a field manually — it'll ask you to confirm. **Refusal warning** (plain — per V3d): > Refuse this SAR. You'll need to give a reason and date. The refusal logs in audit. The prospect can escalate to a regulator. Continue? **Send receipt** (plain — per V3c): > SAR sent to felix@example.com via Proton. 14 message exchanges over 8 weeks. Redacted by default. **Refusal receipt** (plain): > Refusal logged. Reason on file. The prospect was notified of the refusal and their escalation right. ## Privacy invariants Cross-cut with brief K, brief N, brief Q. Enforced at the redaction layer regardless of Quinn override attempts. - **K3c-1 govt-name never** — Quinn's legal name is never in a SAR export. Lock glyph; not overrideable. Applies even if the prospect happens to know the name. - **K3f-2 hotel address never** — tour hotel addresses are scrubbed from any thread text included in the export. Not overrideable. - **Brief N coop reports separate path** — peer reports about the prospect never enter a SAR. The prospect must request from each coop separately. Not overrideable. - **Platform internals always redacted** — specialist IDs, agent_actions reasoning fields, prospect_id, internal flags. Override-gated, not free-flip — opening platform internals requires the typed-confirm modal and a logged reason. - **Quinn's drafts redacted by default** — drafts that never sent are Quinn's thinking, not the prospect's data. Override-gated. ## Edge cases - **Prospect cannot be looked up** — search returns no match. Banner: "No prospect matches that identifier. Search again, or refuse the SAR citing 'no records'." Routes to refusal path with a pre-filled reason. - **Multiple prospects match** — hash collision or shared identifier across personas. Composer shows a disambiguation list with message count + first-contact date + which surface. Quinn picks one; can also pick "all matches" if she's confident they're the same human (rare; gated by a typed-confirm). - **Prospect blocked in K1 still gets SAR** — being on Quinn's personal blocklist does not relieve the legal obligation. Composer shows a yellow banner: "This prospect is on your blocklist. SAR is still required by law. Refusal needs separate lawful basis." Send still allowed. - **Delivery failure** — auto-email bounces or prepared-link generation fails. Banner per brief M §M2: "Couldn't generate the link. Retry or switch delivery channel?" Composer state preserved; no audit row yet (the action hasn't happened). - **Prospect later disputes redaction** — the prospect replies "you redacted too much, send me everything." Composer entry from prospect drawer re-opens with the prior SAR's redaction state pre-loaded; Quinn can flip override-gated rows and re-send as an amended SAR. Original SAR's audit row stays; amended SAR gets `action_type='sar_amended'` with a back-reference. - **SAR draft kept open across vigils** — swipe-down on composer prompts "Save as draft?" Drafts live in the prospect drawer entry until sent or discarded. - **Prospect identifier hashed differently than stored** — per-coop salt rotations don't affect SAR (SAR uses Quinn's account-local data, not coop hashes). The prospect lookup is over Quinn's own messaging history. ## Voice / TTS - Section reading order: title → prospect → scope → format → delivery → redaction preview → refuse. - Required-field hints announce on focus. - Redaction preview rows read as "field: status — reason" (e.g. "their messages to Quinn: included; their own data"). - TTS prosodic shift to slower / lower on the refusal warning copy and on the typed-confirm modals — plain register stays plain when spoken aloud. - VoiceOver: prospect identifier in the lookup result reads partially masked by default ("Felix, phone ending 5678") unless Quinn taps reveal. ## Related - [brief V §V3](./V-data-portability-erasure.brief.md) — parent design (composer + redaction preview + send + refusal). - [brief B §B3](./B-drawers.brief.md) — prospect drawer entry point ("Send subject access request export"). - [brief K §K3c, §K3f](./K-safety-blocklist.brief.md) — identity invariants enforced in the redaction layer. - [brief N](./N-provider-coop.brief.md) — coop reports separate request path; never inside a SAR. - [brief S §S8](./S-settings-ia.brief.md) — Settings entry point ("Field a prospect SAR"). - [brief I](./I-audit-trust-replay.brief.md) — `sar_fulfilled` / `sar_refused` / `sar_amended` audit rows. - [publish-report.screen.md](./publish-report.screen.md) — sibling composer pattern (high-stakes, plain register, preview-then-confirm). - [`voice.md` §V2c](./00-system-voice.md) — plain register throughout.