cocottetech/@platform/codebase/@features/ai-copilot/docs/salon.screen.md

159 lines
17 KiB
Markdown
Raw Normal View History

# salon.screen
Single-screen breakdown for an **AE4 salon** — a multi-peer ai-mediated group room with stated topic, rotating moderator quorum, and proposal→awaiting-quorum→active→archived lifecycle. Sibling to [chat-home.screen](./chat-home.screen.md) (DM-shaped stream) and [coop-drawer.screen](./coop-drawer.screen.md) (multi-member surface pattern). Inherits AD opacity, K3 PII gate, and §V6 banned-phrase enforcement on every outbound. Voice register: **hearth** on first arrival, **working** on ops, **plain** on moderation (per voice §V2c — moderation cost is too high for hearth).
## Layout (iPhone 17 logical 393×852, active salon — default)
```
┌─────────────────────────────────────────────────┐
│ ◄ status bar (system) │ 47pt
├─────────────────────────────────────────────────┤
│ ◄ Chat Berlin Tryst peers · 7 · open [⋯] │ 56pt — header (topic + member count + posture)
│ moderators: 2 of 3 active │ sub-line: quorum signal
├─────────────────────────────────────────────────┤
│ ┌───────────────────────────────────────────┐ │ ambient receipt (hearth)
│ │ Welcome to Berlin Tryst peers. │ │ first-arrival, dismissible
│ │ 7 in the room, last active 12 minutes ago.│ │
│ └───────────────────────────────────────────┘ │
│ │
│ rosa · 14:02 · • mediated │ sender handle + mediation dot
│ Anyone seeing slower bumps on Tryst tonight? │
│ │
│ mari · 14:03 · • mediated │
│ Yes — two failed retries on my side. │
│ │
│ q-berlin · 14:04 · • mediated │
│ Mine held. EU-west edge maybe. │
│ │
│ ─── Cocotte · 14:05 · ambient ──────────────── │ specialist note (hearth)
│ Three of you are watching this. Want a │
│ shared playbook in the drawer? │
│ │
│ ┌───────────────────────────────────────────┐ │ inline mod-action card
│ │ ▢ Mute sender mari for 24h? plain │ │ visible to mods only
│ │ 2 of 3 mods need to agree. You + 1 more.│ │
│ │ [ Decline ] [ Agree ] │ │
│ └───────────────────────────────────────────┘ │
│ │
├─────────────────────────────────────────────────┤
│ ╭─────────────────────────────╮ [🎤] [📷] │ 56pt — composer
│ │ Say something to the salon… │ │ placeholder rotates per state
│ ╰─────────────────────────────╯ long-press = ☎ │
└─────────────────────────────────────────────────┘
│ 34pt — home indicator
```
### Pre-activation variant (proposal · awaiting-quorum)
```
┌─────────────────────────────────────────────────┐
│ ◄ Chat Berlin Tryst peers · proposal [⋯] │
├─────────────────────────────────────────────────┤
│ Proposed by rosa · 2h ago │
│ Topic: "Tryst listing optimization, Berlin" │
│ Flavor: closed · quorum needed: 3 of 3 │
│ │
│ Founders (2 of 3 confirmed): │
│ ✓ rosa (founder, accepted) │
│ ✓ mari (founder, accepted) │
│ … q-berlin (invited, pending) │
│ │
│ [ Invite founder ] [ Withdraw proposal ] │
│ │
│ Stream is closed until quorum reached. │
└─────────────────────────────────────────────────┘
```
## Components
| Component | Brief ref | Notes |
|---|---|---|
| Header | AE4, [coop-drawer §header](./coop-drawer.screen.md) | Topic (≤ 40 char truncated), member count, posture chip (`open` / `closed`), quorum status sub-line. Tap = topic+rules sheet (see Interactions). `[⋯]` = overflow (member roster, leave salon, archive, report). |
| Mediation dot | AE3, [Brief AD](./AD-multilingual-opaque.brief.md) | Single `•` glyph next to sender handle + timestamp. Tappable → "rendered for you in {your locale} · the AI mediated this · view what {sender} literally wrote" sheet (the only AD opacity break, per AE3, requires both peers' consent at salon-join). |
| Stream | AE4 | Vertical message list. Each row: handle · time · mediation dot · body. No avatars (per chat-home parity); sender color is hash-derived for visual distinction without identity disclosure. |
| Specialist ambient | [Brief L §L2](./specialist-ai-copilot.contract.md), voice §V2a | `ai-copilot` posts hearth-register observations into salons (e.g. shared-playbook nudge). Always prefixed `── Cocotte · {time} · ambient ──`; never indistinguishable from a peer. |
| Member roster drawer | AE4, [coop-drawer §roster](./coop-drawer.screen.md) | Slide-in from right. Lists members, role (`member` / `mod`), join date, per-member muted/blocked state, and (mod-only) per-member sanction affordances. |
| Moderator quorum action sheet | AE4, AE10 | Inline card (mods-only) for any moderation action: mute, remove, archive. Each shows `N of M mods needed`, current tally, [Agree] / [Decline]. On quorum reached, the action commits + a plain-register receipt appears in stream. |
| Topic + rules sheet | AE4 | Modal opened by tapping header. Shows full topic, flavor (open/closed), rules (anonymous-OK, evidence-req., locale-mix posture), founders, archive policy, and `[Leave salon]` / `[Report to platform-admin]`. |
| Composer | A §multimodal, AE4 | Same as chat-home composer; placeholder swaps per state. Outbound passes through K3 + §V6 + AD3 pipeline before any recipient delivery. |
## States
1. **proposal** — pre-activation. Founder draft visible only to invited founders. Composer disabled with "Stream opens at quorum." Right-aligned `[Withdraw proposal]` for the originator.
2. **awaiting-quorum** (n of 3 founders) — same as proposal but with live founder tally; counter advances as each founder accepts. Visible founders see each other's confirm state; invited-but-pending founders see only "Pending your confirm." On quorum, transitions to `active` with a hearth receipt: "Berlin Tryst peers is live. 3 founders. Make the first turn yours."
3. **active (default)** — full layout as drawn. Composer placeholder: "Say something to the salon…"
4. **archived** — manual or 90d-inactivity (per AE4). Stream becomes read-only with grey wash; composer replaced by banner "Archived {date}. Reason: {manual / 90d-inactive}. Read-only." `[⋯]` retains "Report" + "Leave" only.
5. **mod-action-pending** — any state above with at least one open quorum proposal. Mods see the action card inline at the bottom-above-composer; non-mods see no card and no leak that an action is being deliberated. Receipt on commit is plain-register: "{Sender} muted by moderator quorum until {date}."
6. **per-member muted** — viewer-side state. Muted member's messages collapse to a single line "Hidden — muted by you" with `[Show]` affordance. The muted member never learns (per AE10 mute semantics).
7. **K3 leak suppressed broadcast** — outbound message tripped K3 PII gate; the message is blocked before any recipient delivery; one `peer_group_messages` row written once with `delivered_text=NULL` per recipient (per AE edge cases). Sender sees plain-register counter-action receipt: "Held a draft back — contains restricted content. See audit for the row." No recipient sees anything.
8. **empty (no messages yet)** — newly-active salon, no turns yet. Centered hearth prompt: "Welcome to {salon name} peers. 3 in the room. The first turn is yours." Composer placeholder: "Start the salon."
9. **cross-locale mixed** — multiple member locales coexist; every recipient sees stream entirely in their preferred locale per AD opacity (no "translated from…" annotation ever). The mediation dot is the only signal that ingestion happened.
10. **founder leaves before quorum**`awaiting-quorum` with one or more founders having withdrawn. Banner: "{Founder} left before quorum. {Originator} can invite a replacement or withdraw the proposal." If originator leaves, the proposal auto-withdraws + a plain-register notice to remaining founders: "{Originator} withdrew. The proposal is closed."
11. **coop deletion cascade** — salon is coop-bound (closed, `coop_id` set) and the parent coop was dissolved (per [coop-drawer state 8](./coop-drawer.screen.md)). Banner replaces stream: "The coop this salon belonged to was dissolved on {date}. The salon is archived; transcripts remain in audit." Composer disabled.
12. **VoiceOver / reduced motion / Dynamic Type XXL** — inherits chat-home accessibility patterns (per [Brief X](./X-accessibility.brief.md)). Roster drawer reads members in order; mediation dot announces "mediated by ai-copilot" as a hint; quorum cards read tally first.
## Interactions / gestures
- **Long-press a message** → action sheet: "Quote in reply" / "Report to mods" / "Report to platform-admin" / "View what {sender} literally wrote" (the AD verbatim-view, requires both-peers consent at salon-join). On `quote`, composer pre-fills with quoted snippet attribution.
- **Swipe-right on a message (mod only)** → "Mute {handle} for 24h?" opens a quorum action card inline. Non-mods get no gesture affordance here.
- **Swipe-left on a message** → set-aside / dismiss from your view only (does not affect any other recipient).
- **Tap header** → topic + rules sheet (modal).
- **Tap mediation dot** → AD opacity break sheet (verbatim sender text).
- **Tap `[⋯]`** → overflow menu (member roster · leave salon · archive (mods only) · report).
- **Pull-to-refresh** → re-pulls salon state + new messages.
- **Swipe-down on header** → dismiss back to chat / drawer.
## In-the-wild copy
- (hearth, first-arrival receipt) "Welcome to Berlin Tryst peers. 7 in the room, last active 12 minutes ago."
- (working, quorum reached) "Berlin Tryst peers is live. 3 founders. Make the first turn yours."
- (working, ambient nudge) "Three of you are watching this. Want a shared playbook in the drawer?"
- (plain, mod quorum proposed) "Mute mari for 24h? 2 of 3 mods need to agree."
- (plain, quorum committed) "mari is muted by moderator quorum until tomorrow 14:02. Reason: off-topic spam."
- (plain, K3 leak suppressed) "Held a draft back — contains restricted content. See audit for the row."
- (plain, archived 90d) "Archived March 12. Reason: 90 days no activity. Read-only."
- (plain, coop dissolved) "The coop this salon belonged to was dissolved on March 12. The salon is archived; transcripts remain in audit."
- (plain, founder withdrew pre-quorum) "rosa withdrew. The proposal is closed."
## Edge cases
- **Founder leaves before quorum** — see state 10. Originator gets the invite-replacement / withdraw-proposal affordance; remaining founders get a plain-register notice when the proposal closes.
- **90d-inactivity auto-archive** — last-message timestamp ≥ 90d ago triggers a background sweep that flips the salon to `archived` + writes a plain-register receipt audible to all members on their next open. Members can still read the transcript; no new turns accepted. Per AE4 lifecycle.
- **Coop deletion cascade** — if `coop_id` is set and the parent coop dissolves (per [Brief N §N6d](./N-provider-coop.brief.md)), the salon auto-archives with state 11's banner. Members are not removed from their personal AE plane; only the salon goes read-only. Open salons not bound to a coop are unaffected.
- **Member's posture flips to incognito mid-salon** — past messages remain visible to other members (consent was at salon-join); the incognito member can still read but cannot send. Header shows no leak; only that member sees the composer disabled with "Posture is incognito. Open posture to post." Per AE11.
- **Cross-locale founders propose a salon** — proposal-state shows founders' handles only; AD opacity holds even pre-quorum. The proposed topic is itself stored as canonical-EN + per-locale rendered per AD6 triad.
- **Right-to-left member in LTR salon** — recipient-view rendering flips per locale; mediation dot stays adjacent to the handle in reading order. Per [Brief AD §AD-Q4](./AD-multilingual-opaque.brief.md).
- **Mod proposes a quorum action while another mod is offline** — action card persists until quorum reached or 7d expires (timeout auto-declines). Plain-register receipt on timeout: "Mute proposal on mari expired without quorum."
- **Founder is also the only mod** — at salon activation, the founder is auto-`mod`; quorum threshold for mod actions in a 3-founder salon defaults to 2 of 3. Per AE4 + schema `quorum_count` default.
- **Salon ai-mediation degraded** — `@model-boss /translate` unreachable; per [Brief M §M2a](./M-error-degraded-modes.brief.md): outbound queues with a degraded chip; recipients see a plain-register banner "ai-copilot is catching up on this salon. Some messages will arrive late."
- **Reduced motion / VoiceOver / Dynamic Type XXL** — see state 12.
## Related
- [Brief AE §AE4](./AE-provider-social-network.brief.md) — parent design (lifecycle, schema, mediation).
- [Brief AE §AE10](./AE-provider-social-network.brief.md) — moderation surfaces (block, mute, report).
- [Brief AE §AE11](./AE-provider-social-network.brief.md) — opt-in posture affecting send-eligibility.
- [Brief AD](./AD-multilingual-opaque.brief.md) — opacity + storage triad + recipient-view rendering applied per salon message.
- [Brief K §K3](./K-safety-blocklist.brief.md) — PII gate that produces state 7's suppressed-broadcast.
- [Brief N](./N-provider-coop.brief.md) — parent coop lifecycle for state 11's cascade.
- [Brief L §L2](./specialist-ai-copilot.contract.md) — `ai-copilot` ambient nudges inside salons.
- [Brief I](./I-audit-trust-replay.brief.md) — every salon turn is an `agent_actions` row linked to `peer_group_messages`.
- [Brief X](./X-accessibility.brief.md) — VoiceOver / reduced-motion / Dynamic Type behavior.
- [chat-home.screen.md](./chat-home.screen.md) — DM-shaped sibling stream.
- [coop-drawer.screen.md](./coop-drawer.screen.md) — multi-member surface pattern this screen extends.
- [approval-card.screen.md](./approval-card.screen.md) — quorum action cards reuse the stakes-band + 3-action shape.
## Out of scope
- Salon discovery + join flow (lives in `peer-profile.screen.md` + AE5 directory; not authored here).
- Cross-platform variants (iPad / web; deferred per [Brief E](./E-cross-platform.brief.md)).
- Shared-playbook composer (AE6 `shared_playbook` collab kind; separate screen if surfaced).
- Platform-admin moderation queue interior (AE10 escalation target; out-of-brief signpost only).
- Founder-replacement dispute resolution (covered in AE4 proposal lifecycle; no dedicated screen at P0).
## Open questions
- **SAL-Q1** Mediation-dot affordance — does tapping the dot open the AD verbatim-view sheet by default, or is verbatim-view a long-press only (to keep tap-on-handle = profile)? `[blocking]` (lean: long-press for verbatim, tap-on-handle for profile; the dot itself is a non-interactive signal).
- **SAL-Q2** Quorum threshold for mod actions in salons larger than 3 founders — flat `2 of 3` of currently-active mods, proportional `⌈M/2⌉ + 1`, or salon-configurable at creation? `[engineering]` (lean: proportional with floor=2; configurable post-P0).
- **SAL-Q3** Specialist-ambient frequency cap — how often can `ai-copilot` post ambient nudges into a salon before it feels intrusive? Per-salon daily cap or per-member dismissibility? `[exploratory]` (lean: per-salon daily cap = 1, plus member-side mute of all ambient).