# 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. 3–8 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.