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

132 lines
13 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.

# peer-feed.screen
Implements [brief AE §AE9](./AE-provider-social-network.brief.md) — the aggregated peer feed. "What your peers are doing this week" as **anonymized aggregations only**. No avatars, no per-peer breakdowns, no PII, no cross-provider prospect rows. Powered by the `peer-aggregator` worker (extension of `prospect-resolver` per brief L), which enforces a k=5 anonymity floor before any rollup is published.
Reached from chat-home top-bar overflow → "Peer feed" (per FEED-Q2 lean: feed only at P0; chat-home placement deferred). Voice register: **working** by default, **hearth** on positive movement, **plain** on degraded / opted-out states (per [`00-system-voice.md`](./00-system-voice.md) §V2).
## Layout (iPhone — scrolling card stream; web companion mirrors)
```
┌─────────────────────────────────────────────────┐
│ ◄ Chat ⚙ │ 56pt — top bar; ⚙ = mute mgmt
├─────────────────────────────────────────────────┤
│ Peer feed · this week │ working register header
│ refreshed 4h ago · daily │ cadence per FEED-Q1 lean
├─────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────┐ │ working register card
│ │ Threads activity │ │
│ │ Your colleagues posted 4× more on Threads │ │ anonymized stat
│ │ this week than last. │ │
│ │ from 12 peers · methodology → │ │ k≥5 disclosure
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │ hearth register card
│ │ Berlin coop │ │
│ │ A salon you're in published 2 shared │ │
│ │ playbooks. Worth a look in the drawer. │ │
│ │ from 7 peers · methodology → │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │ working — low-confidence flag
│ │ Coop intel │ │
│ │ 3 of your colleagues marked Berlin reports │ │
│ │ low-confidence this week. │ │
│ │ from 8 peers · methodology → │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │ platform-wide rolling card
│ │ Platform-wide · 90d │ │
│ │ Tryst bumps are accepting 12% slower this │ │
│ │ quarter than last. │ │
│ │ from 240 peers · methodology → │ │
│ └─────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────┘
```
## Components
| Component | Notes |
|---|---|
| Top bar | Back + ⚙ (settings: muted card types, refresh cadence preview, posture quick-link to brief S settings). |
| Cadence header | "this week" anchor + last-refresh stamp + cadence label (per FEED-Q1 lean: **daily**). |
| Aggregator card | One per anonymized rollup. Three parts: kind label (e.g. "Threads activity", "Coop intel", "Platform-wide · 90d"), the anonymized stat sentence, a peer-count + methodology link. NO avatars, NO peer handles, NO per-peer detail. |
| k≥5 disclosure | Every card shows `from N peers` where N ≥ 5 per the AE9 anonymity floor. Cards with N < 5 are auto-suppressed (see `sensitive-segment` state). |
| Methodology blurb | Tap to expand: short explainer of what's measured, the comparison window, and the anonymization floor. Working register. |
| Register cue | Card-level register matches the sentiment: hearth on positive ("worth a look"), working on neutral, plain when a number signals trouble (e.g. "12% slower"). |
## States
1. **`empty`** no peers in any coop yet, OR all peers below k=5 across all aggregators. Copy: "Nothing to show yet. Once your coops have a handful of active peers, weekly aggregations land here." Hearth register, single line, no fake-empty placeholders.
2. **`populated`** default; the layout drawn above. 38 cards typical; pull-to-refresh re-pulls (rate-limited).
3. **`degraded`** `peer-aggregator` worker hit the k=5 anonymity floor on most card types this cycle. Single visible card: "Not enough peer data this week to show aggregations safely. Back next cycle." Plain register. Per AE9 brief never lower the anonymity floor to fill the surface.
4. **`opted-out`** provider switched posture to incognito (AE11). The feed surface disappears from the overflow menu entirely (no "you're opted out" placeholder incognito means no peer-facing surface, per AE11). If reached by deep link: plain cue: "Peer feed is off while you're incognito. Switch posture in settings to surface it."
5. **`sensitive-segment`** a candidate card would identify < 5 peers (e.g. "1 of your colleagues did X"). Auto-suppressed at worker level; never reaches the surface. If somehow surfaced: card replaced by methodology stub: "Held a card back too few peers to publish safely."
6. **`stale`** last successful aggregator run > 36h ago (brief M §M2 degraded mode). Cadence header shows "refreshed 38h ago · stale" with plain register tint. Existing cards remain readable; no new ones added.
7. **`muted-card-type`** — provider long-pressed a card kind ("mute Threads activity"). That kind suppresses; ⚙ shows it in the muted list with un-mute affordance.
8. **`cold-load`** — skeleton placeholders per card (4 typical).
9. **`VoiceOver`** — cards read top-to-bottom; methodology link explicitly announced; `from N peers` read aloud as part of each card.
## Interactions
- **Tap card** → expand context / methodology blurb inline (what's measured, comparison window, k-floor disclosure, last refresh).
- **Long-press card** → "Mute this card type" / "Mute for one cycle" / "Why this card?" sheet. Mute persists until un-muted from ⚙.
- **Pull-to-refresh** → re-pulls the latest aggregator output (rate-limited; daily cadence per FEED-Q1 lean — pull-refresh just re-fetches the same daily rollup, doesn't trigger a fresh worker run).
- **Tap ⚙** → settings sheet (muted card types, refresh cadence preview, link to brief S posture settings).
- **Tap methodology →** → expand inline; tap again to collapse.
- **VoiceOver swipe order** — cadence header → each card (kind label → stat sentence → peer count) → methodology where expanded.
## In-the-wild copy
- (working, default) "Your colleagues posted 4× more on Threads this week than last. from 12 peers · methodology →"
- (hearth, positive) "A salon you're in published 2 shared playbooks. Worth a look in the drawer."
- (working, watch-out) "3 of your colleagues marked Berlin reports low-confidence this week."
- (working, platform-wide 90d) "Tryst bumps are accepting 12% slower this quarter than last. from 240 peers · methodology →"
- (plain, degraded) "Not enough peer data this week to show aggregations safely. Back next cycle."
- (plain, opted-out via deep link) "Peer feed is off while you're incognito. Switch posture in settings to surface it."
- (working, methodology expand) "Counts posts published by peers who share at least one coop with you, rolling 7 days. Comparison: prior 7d. Floor: 5 peers minimum before publishing."
## Edge cases
- **Incognito posture (AE11) ↔ feed surface** — feed-disable is automatic; the surface is hidden from the overflow menu entirely. No badges, no nudges, no "you're missing out" copy. Per AE11: incognito means no peer-facing surface, ever.
- **Rare event with only one matching peer** — auto-suppressed at the `peer-aggregator` worker per k=5. Never reaches the device. If a worker bug surfaces one anyway, the surface drops the card silently + logs to audit (brief I).
- **Platform-wide aggregations** — drawn from the rolling 90d window across all consenting providers (not coop-scoped). Always show "Platform-wide · 90d" label so the scope is unambiguous.
- **Peer leaves all shared coops** — their contribution drops out of next cycle's rollup; no retroactive recompute. Past cards remain (they were anonymized at publish time).
- **All peers in one coop block the provider** — that coop's aggregations disappear from the feed (no peers visible → k=5 not met). No notice given (giving notice would leak the block).
- **Provider changes preferred language** — card stat sentences re-author per AD opacity (no "translated from" annotation); methodology blurb localized from the per-locale `voice-{locale}.yaml` bank.
- **Worker disagreement** — `peer-aggregator` and `prospect-resolver` produce conflicting counts (brief M §M7 conflict): card is suppressed for the cycle; plain row in audit.
- **Reduced motion** — card-enter animations replaced by crossfade.
- **Dynamic Type XXL** — peer count moves to its own line under the stat sentence.
- **VoiceOver + dense feed** — group cards under a single landmark; each card announces its kind label first.
## Related
- [Brief AE §AE9](./AE-provider-social-network.brief.md) — parent spec; aggregator + anonymity floor.
- [Brief AE §AE11](./AE-provider-social-network.brief.md) — incognito posture; feed-disable.
- [Brief AE §AE2](./AE-provider-social-network.brief.md) — coop / connection scope informs which peers feed into a rollup.
- [Brief AE §AE5](./AE-provider-social-network.brief.md) — directory scope informs the peer pool for platform-wide cards.
- [Brief L](./L-specialists-fleet.brief.md) — `peer-aggregator` worker is a `prospect-resolver` extension.
- [Brief I](./I-audit-trust-replay.brief.md) — each aggregator run + each surfaced card writes audit rows.
- [Brief K §K3](./K-safety-blocklist.brief.md) — PII gate on any free-text fragment surfaced in a card.
- [Brief AD](./AD-multilingual-opaque.brief.md) — locale-faithful re-authoring of stat sentences + methodology blurbs.
- [Brief M §M2a](./M-error-degraded-modes.brief.md) — stale / degraded surface behavior.
- [analytics-dashboard.screen.md](./analytics-dashboard.screen.md) — panel-card register pattern shared.
- [daily-digest.screen.md](./daily-digest.screen.md) — register usage + working/hearth/plain split pattern shared.
- [`00-system-voice.md`](./00-system-voice.md) §V2, §V5 — register selection.
## Out of scope
- Per-peer breakdowns of any kind ("Sarah posted X") — never. Per AE9 brief.
- Cross-provider prospect rows — never; preserved from brief Y §Y7.
- Specific prospect data leaking into aggregations — gated by K3 + the aggregator's anonymization step.
- Real-time / push-driven feed (P0 is daily-pull only per FEED-Q1 lean).
- Chat-home placement (per FEED-Q2 lean: feed-only at P0; chat-home embed deferred).
- Web-first feed companion (P0 surfaces iOS; web inherits later).
- Configurable card types beyond mute (custom cards / SQL-style queries are P5+).
- Provider-authored aggregations (this surface is read-only; peers can't publish into the feed).
## Open questions
- **FEED-Q1** Refresh cadence — daily / per-vigil / live? Lean: **daily**. Per-vigil risks oversharing micro-movements; live risks small-N leaks under the k=5 floor. Daily lets the aggregator run cleanly + matches the daily-digest rhythm.
- **FEED-Q2** Surface in chat-home as well as dedicated feed? Lean: **feed only at P0**. Chat-home is already dense; the dedicated feed proves the aggregations are valuable before embedding. Revisit after a cycle of usage data.