cocottetech/@platform/codebase/@features/ai-copilot/docs/add-blocklist-entry.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

8.6 KiB
Raw Blame History

add-blocklist-entry.screen

The sheet for adding a new entry to Quinn's personal blocklist (distinct from coop reports — that's publish-report.screen.md). Implements brief K §K1K3. Reachable from the engagement card overflow, prospect detail drawer (B3), audit-row counter-action menu, or settings → blocklist root.

Voice register: plain — per voice.md §V2c, blocklist surfaces don't use metaphor.

Layout (modal sheet, contextual to entry kind)

┌─────────────────────────────────────────────────┐
│ Cancel       Add to blocklist           Save    │ 44pt — top bar
├─────────────────────────────────────────────────┤
│                                                 │
│ Kind                                            │
│ [● Prospect ] [○ Phrase ] [○ Topic ]            │   K1 / K2 / K2 / K3 / K4
│ [○ Surface combo ] [○ Jurisdiction ]            │
│                                                 │
│ ─── Value ──────────────────────                 │
│ ╭───────────────────────────────────────╮      │   placeholder per kind
│ │ Phone, handle, or hash                 │      │
│ ╰───────────────────────────────────────╯      │
│ ⓘ Auto-detected: matches @felix on Tryst       │   if context provided context
│                                                 │
│ ─── Scope ──────────────────────                 │
│ ○ Global (everywhere)                           │
│ ● Specific surfaces                             │
│   [☑ Tryst] [☑ TS4Rent] [☐ OnlyFans] [☐ X]      │
│   [☐ All directories ] [☐ All content surfaces] │
│                                                 │
│ ─── Reason (optional) ──────────                 │
│ ╭───────────────────────────────────────╮      │
│ │ For future me — why?                   │      │
│ ╰───────────────────────────────────────╯      │
│ ⓘ Shown to you when the rule fires;            │
│   never to the blocked subject.                 │
│                                                 │
│ ─── Expires ──────────────────────              │
│ ● Never                                         │
│ ○ In: [ 7 days ▼ ]                              │
│ ○ On: [ 2026-06-01 ▼ ]                          │
│                                                 │
└─────────────────────────────────────────────────┘

Components

Component Notes
Top bar Cancel + Save. Save disabled until value + scope valid.
Kind picker Radio across 5 kinds per brief K §inputs. Layout adapts below based on kind.
Value field Polymorphic per kind: phone/handle for prospect, free-text for phrase/topic, surface combo for surface_combo, jurisdiction picker for jurisdiction.
Context chip When opened from an engagement card / prospect drawer / audit row, auto-detected value + matches indicator.
Scope Global or per-surface multi-select. Surface chips per brief F §F5 iconography.
Reason Optional free-text. Never user-visible to subject; surfaced when rule fires per brief K §inputs reason field.
Expires Permanent default; relative or absolute alternatives.

States

  1. Empty / fresh — no kind selected by default; value field hidden until kind picked.
  2. Kind selected (prospect) — value field shows phone/handle keypad-ish input. If opened from context, prefilled. Scope defaults to "Global" for prospects (rare to want surface-scoped person blocking).
  3. Kind selected (phrase) — value field is plain text input + a character count. Scope shows surface-pickers; default "Global" (most phrases are content-wide).
  4. Kind selected (topic) — value field is plain text; under it, a small "Topic mode" chip noting that this acts as a fuzzy filter, not literal-match.
  5. Kind selected (surface_combo) — value field becomes a 2-picker compound: "Don't post {kind} on {surface}." E.g. "Don't post NSFW on X." Scope is fixed to the surface in the combo.
  6. Kind selected (jurisdiction) — value field is jurisdiction picker (autocomplete from list: country / US-state / EU-region). Scope is implicit per jurisdiction's standing rules.
  7. Validation error — empty value / no surfaces selected (when "Specific surfaces" mode) / invalid date.
  8. Submitting — top banner spinner; Save disabled.
  9. Saved — sheet dismisses; chat-home receipt: "Added to blocklist: {brief description}. {Surfaces}. [Edit]". Audit row recorded per brief I.
  10. Save failed — per brief M: sheet stays with banner "Couldn't save right now. Retry?" Data preserved.
  11. Editing an existing entry (entry: tap an entry on the blocklist settings root) — sheet pre-fills; top bar says "Edit blocklist entry"; Save text "Update."
  12. Voice / accessibility — reading order: kind → value → scope → reason → expires.

Interactions / gestures

  • Tap kind radio → switches the value field, scope defaults, and any kind-specific hints.
  • Tap auto-detected context chip → fills value field; shows the source row that surfaced it.
  • Tap surface chip → toggle inclusion. Long-press → "Select all directories" / "Select all content surfaces" shortcuts.
  • Tap reason placeholder → inline expansion; voice mic also offered.
  • Tap Expires "On: {date}" → iOS date picker.
  • Save → write entry; show receipt; dismiss.
  • Swipe-down to dismiss → "Discard changes?" if any field has content.

Edge cases

  • Phrase value matches a current draft pending Quinn's approval — banner: "An OF caption draft contains 'this phrase'. Save and re-draft, or save without affecting that draft?" Routes to re-draft or save-only.
  • Adding a prospect that's also flagged in a coop Quinn belongs to — info chip: "ⓘ This prospect has 2 reports in your Berlin coop. Your personal blocklist is independent — peers won't see this entry."
  • Conflicting entries (e.g. an existing phrase entry blocks "Berlin" but Quinn declares a tour to Berlin) — Save warns: "Your tour rule conflicts with this block. Proceed?"
  • Jurisdiction kind, jurisdiction not yet supported by Cocotte — value picker shows "Limited support. I'll honor declared restrictions but auto-detection is best-effort."
  • Auto-added entry being viewed (created_by='auto', per brief K §inputs) — the kind/value/scope are read-only; only reason and expires_at editable. Banner: "Cocotte added this entry automatically on {date} because {reason}. You can refine it." Routes to confirm-or-revert.
  • PII concerns on phrase value (Quinn types a real name as the phrase) — soft banner: "This looks like your real name. Block it everywhere by default." Suggests global scope.
  • Reduced motion / Dynamic Type XXL — kind picker wraps to vertical; surface chips wrap; date picker becomes inline.

Out of scope

  • Kill switch (covered by kill-switch.flow.md).
  • The blocklist root settings page (a list view; could be its own screen if it grows).
  • Phrase-vs-persona-off-limits dedup (open question in brief K §open-questions; engineering decides storage; this UI works against either).