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>
8.6 KiB
8.6 KiB
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 §K1–K3. 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
- Empty / fresh — no kind selected by default; value field hidden until kind picked.
- 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).
- Kind selected (phrase) — value field is plain text input + a character count. Scope shows surface-pickers; default "Global" (most phrases are content-wide).
- 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.
- 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.
- Kind selected (jurisdiction) — value field is jurisdiction picker (autocomplete from list: country / US-state / EU-region). Scope is implicit per jurisdiction's standing rules.
- Validation error — empty value / no surfaces selected (when "Specific surfaces" mode) / invalid date.
- Submitting — top banner spinner; Save disabled.
- Saved — sheet dismisses; chat-home receipt: "Added to blocklist: {brief description}. {Surfaces}. [Edit]". Audit row recorded per brief I.
- Save failed — per brief M: sheet stays with banner "Couldn't save right now. Retry?" Data preserved.
- 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."
- 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
reasonandexpires_ateditable. 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.
Related
- Brief K §K1–K3 — parent design.
- Brief I — every blocklist add is an
agent_actionsrow. - Brief L §L3
triage— primary consumer of K1 prospect entries. - Brief N — distinct from coop reports; this brief covers PERSONAL blocking only.
voice.md§V2c — plain register.- publish-report.screen.md — the coop counterpart (deliberate / inter-tenant).
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).