cocottetech/@platform/codebase/@features/ai-copilot/docs/sar-composer.screen.md
natalie 1b719e1fd7 chore(bootstrap): initial V4 commit
Clean successor to V3 (forge: lilith/atlilith). Seeded from local Mac
working tree at ~/Code/@projects/@cocottetech/. node_modules and build
artifacts excluded via .gitignore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 08:11:41 -07:00

13 KiB

sar-composer.screen

Quinn fulfills a GDPR / CCPA subject access request a prospect emailed her. Pairs with brief V §V3 — 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 §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.
  • brief V §V3 — parent design (composer + redaction preview + send + refusal).
  • brief B §B3 — prospect drawer entry point ("Send subject access request export").
  • brief K §K3c, §K3f — identity invariants enforced in the redaction layer.
  • brief N — coop reports separate request path; never inside a SAR.
  • brief S §S8 — Settings entry point ("Field a prospect SAR").
  • brief Isar_fulfilled / sar_refused / sar_amended audit rows.
  • publish-report.screen.md — sibling composer pattern (high-stakes, plain register, preview-then-confirm).
  • voice.md §V2c — plain register throughout.