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

158 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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).