Dialogue · Design notes · Proven Better New

Proven · Better · New

The prototype audited through Mark Pincus's product framework (Life at the Speed of Play, ch. 4, 2025) — where we've copied faithfully, where we haven't earned the right to differ yet, which "improvements" are really unproven bets, and which one New idea deserves the isolated test. Written 2026-07-16; gaps 8–9 (the long-press action bar · DMs) added the same day; re-grounded for a world audience (not China-first) the same day; gaps 10–12 (the dismissal-grammar sweep · user profiles · the emoji library) added 2026-07-17; gap 13 (the contact layer) + the shipped-card fold added 2026-07-19.

= Proven — copy, pixel for pixel, what your exact audience already loves; you haven't earned the right to change it. > Better — an objectively better aspect (free · faster · no download) that 10/10 existing users cheer. + New — your one novel idea. Pincus's mantra: "all New fails" — so isolate it and test it separately, so it fails for the right reason.

The two situational rules

RuleWhat it saysApplied to us
Platform shift → go heavy on Proven During a shift (web → mobile → AI, now) users are in discovery mode; Proven + Better alone can win — the platform itself is the New. Zynga on Facebook, Supercell on mobile, Hay Day = FarmVille-for-mobile with zero New. We are squarely inside the AI shift. The framework says: nail the group-chat Proven, keep the Betters sharp — the persona room already carries all the New the moment needs.
Stacked New → the Tribe failure Pincus's Tribe.net reinvented everything it touched — wide, shallow, confusing. Zynga Poker was the antithesis: one Better (no download), one New (real friends' faces at the table). Counted honestly, we have ≈7 New ideas live at once (§ New below). Only one of them runs as a disciplined, isolated experiment.
WHAT THE SHIFT REWARDS = Proven, heavy every pixel of the chat your audience already lives in > Better, sharp instant · free · fast — objective, visible + New: one, isolated, measured THE REPO TODAY = Proven, partial 13 gaps named — 8 shipped · 5 open the 13 gaps (below) > Better: 3 real, 6 mislabeled + New: ≈7 stacked only one isolated + measured (manners v2)
the inversion — the platform-shift moment rewards the left shape; the repo currently has the right one

= Proven — the reference set, and what's already copied

Our audience's two proven products: the WhatsApp group chat — the world's default group-conversation surface (iMessage and Telegram as siblings; WeChat for the Chinese-speaking slice) — and Character.ai (Talkie · Replika; 星野/猫箱 as the regional siblings) for the persona side: the proof that talking to characters is a mass daily habit, and the reference for how personas are discovered.

Already copied faithfully: bubbles / composer / chat list · @mentions as entities · the typing indicator · streaming replies · PWA with back-gesture + hero collapse · dark mode · persona cards + fuzzy picker search. The UX benchmark already graded us against WhatsApp / WeChat / Telegram feature by feature; this page adds the strategic frame — which borrowings are load-bearing and why now.

the test "Proven" means: rebuild the same interface, put it in front of the same people, get the same reaction. Against that bar, thirteen mechanics our audience uses daily were absent when this audit began. Pincus's rule for every one of them: don't innovate on it, don't debate it — copy it, so the product can't fail for the wrong reason. One mockup each, in the app's own bubble grammar. Eight have since shipped — their cards fold to a header line below (tap to unfold the original spec, mock, and the as-shipped record); the five open gaps stay unfolded.
gap 1Push notificationsproven in · every chat app on earth✓ shipped · v489 · 2026-07-18

The FarmVille empty-neighbor-bar lesson: Skaggs removed the friend-request step as "friction"; Pincus kept it, because the requests were the reminder to come back. A ping is our only reminder — and the manners v2 experiment is judged on return rate. Without a come-back channel, that metric fails for a Proven-gap reason, not because the New failed: false signal on our own chosen metric. The notifications rail ships everything up to the app's edge; Web Push was deferred under the China-first framing (the GFW tax) — for a world audience FCM/APNs just work, so the deferral has lost its reason. This gap is the argument for pulling it forward.

21:47● ● ●
21:47
Thursday, July 16
小胖看房 · Dialogue
那套浦东的挂牌价又降了2%——你上周问过的那套。回来聊两句?
now
M
Mary · 战队房间
Mary replied to you — "I'd hold the Pudong one…"
32m
the mock Lock screen, not app UI — that's the point: this is the one Proven mechanic that lives outside our walls. Two kinds shown: a persona ping (a persona speaks first — the greenroom pattern, already built, currently visible only if you happen to open the app) and a co-human reply.

Order of work: Web Push where it reaches (Android/desktop; iOS PWA push exists since 16.4), and the persona-initiated message as the payload — the notification is a bubble, not a badge.

✓ Shipped v489 (2026-07-18): standard VAPID Web Push as the notification rail's third mirror — the SAME durable events (room/DM messages while away · room invite · build-done greenroom) now also land on the lock screen, hooked where the rail already writes (notify() for notices, the message broadcast for chat), never a parallel path. Payload is a bubble exactly as mocked: sender name · text preview (markdown-stripped) · avatar icon · deep-link — tap focuses the app and routes to the room (no reload). Per-room coalescing so a chatty panel bursts as ONE evolving notification (WhatsApp). Suppressed only where it's genuinely redundant — the server skips a member holding that room's live stream, and the SW skips a message for the room you're focused on this second. Everything else always shows, even with the app open: a broader "app is visible → skip" rule broke the userVisibleOnly contract and got the origin flagged by Chrome as possible spam (fixed v508 — see the rail's two device-learned rules). Permission is never prompted on load — a soft-ask card in the notification centre + a one-time nudge after your first DM/invite + a per-device toggle in the Me sheet. iOS shows an Add-to-Home-Screen hint until the PWA is installed (16.4+); mainland devices that can't reach FCM degrade silently — the in-app rail still covers them. Sent/click events are logged so the return-rate loop (did a push bring them back?) is measurable. Out of v1 (New backlog): personas that INITIATE new content for a push — the greenroom she-speaks-first bubble is the embryo, not proactive outreach.
gap 2Voice messages — hold-to-talkproven in · WhatsApp (7B/day) · WeChat

The shipped dictating composer is speech-to-text — arguably a Better (searchable, quotable, no 60-second replay tax). But the proven mechanic — hold, speak, a voice bubble lands; the other side answers in a voice you can play — is what our audience's thumbs already know. Every piece exists (iFlytek STT in, TTS providers out); the mechanic just isn't assembled. Personas with voices is also the natural end of the roadmap's listen-mode thread.

9:41● ● ●
看房小分队小胖看房 · Rams · Mary
0:07
小胖看房
0:19
转写 · 首付比例你别只看数字,先问银行流水够不够…
● Release to send · slide up to cancel
the mock A human voice bubble (right, grey — waveform + length), a persona voice reply in seat colour with play + a folded transcript line (our Better riding inside the Proven: theirs is speech you can also read), and the composer in the held state.

Boundary kept: accent-bucket TTS only, never voice cloning; media never touches the box (the roadmap's listen-mode rule).

World note: the shipped dictation tier is zh+en — voice notes themselves are language-blind (audio is audio), but the transcript line needs a multi-language STT tier.
gap 3Quote-replyproven in · WhatsApp · Telegram · iMessage✓ shipped · v434 · 2026-07-16

In a room with four speakers, replying to a specific message is how threads stay legible — table stakes in every group chat our users know. Doubly valuable here: a quote is a free targeting signal for the floor producer — "this human is answering Rams's second point" arrives as structure, not inference. The UX benchmark already ranked quote-to-panel near the top of the borrow list.

9:41● ● ●
v2 flow reviewRams · Tao · you
RDieter Rams
Your v2 flow has three confirmation steps. Two of them confirm nothing the user said.
Rams · Two of them confirm nothing the user said.
Which two? The invite step feels load-bearing to me.
Replying to Rams · "…three confirmation steps…"
Message…
the mock WeChat's exact grammar: the reply bubble carries a compact quoted block (hairline accent, muted), and the composer shows a dismissible Replying-to chip while you type. Long-press a bubble → Reply is the entry point (the same long-press menu the benchmark already proposes).

Plumbing note: quotes anchor on message ids, same contract as @{p:slug} mentions — never re-matched text.

✓ Shipped v434 as mocked: a stationary long-press opens the lean Reply · Save · Copy menu; the quote rides as an id-anchored ❝{q:<lid>} marker line (the stable line id every bubble now carries); tapping the quoted block jumps to the original and flashes it. Bonus wired in: the floor producer reads a quote as a targeting signal — the quoted host is staged like an @-mention, and the v1p brief carries an explicit QUOTE-REPLY line. v436 adds WhatsApp's second door: swipe the bubble right — it rides the finger, a reply arrow fades in, release past the stake and the same quote docks.
gap 4Message reactionsproven in · iMessage · WhatsApp · Telegram · Slack/Discord✓ shipped · v453 · 2026-07-16

The lowest-friction engagement loop in messaging — one tap, social, visible to the room. We already have a 👍/👎 feedback row inside persona bubbles, but that's the analyst's instrument (it feeds the producer's brief and hides from other guests). A reaction is the social-native cousin: it lives on the message, everyone sees it, personas can notice it — and it still feeds the same guest-feedback brief for free.

9:41● ● ●
深夜局梁宁 · 王强 · Mary · you
梁宁
👍 ❤️ 😂 😮 👏 你不是怕选错,你是怕选了就没退路。这两件事不一样。
❤️ 2👏 1
…好,被你说中了。
Message… 🎤
the mock Long-press → the floating reaction bar over the bubble; landed reactions collect as small chips under the message (yours highlighted coral). Both humans and — sparingly — personas can react.

One rule from the start: reactions are message-anchored events in the room log, so the producer reads them like any other signal. The existing 👍/👎 lever row stays — different job (private calibration vs public warmth).

✓ Shipped v453 as mocked: the long-press carries two beats at once (WhatsApp) — the row selects (gap 8's wash + action bar) AND the reaction bar pops at the press point itself (v454) — twelve in a swipeable strip, 6½ showing with the half-cut one fading into a soft gradient edge — the "more to the right" cue; multi-select hides it, tapping an emoji applies and exits selection; desktop shows all twelve uncut. Landed reactions = one pill overlapping the bubble's corner (v457–459, WhatsApp's look — per-emoji counts like 👍 ❤️2 😢 🙏3, a 20%-of-glyph ride on the bubble, and a fresh reaction bounces in with the overshoot-and-settle pop); tapping it opens the details bottom sheet (pane-centred on wide) — "{n} reactions", the emoji pills as an edit control (your highlighted pill removes, another kind switches, smiley+ re-opens the twelve), who-reacted rows with "Tap to remove" on yours. Proven semantics exactly: one reaction per user per message — a second emoji replaces, your own again removes. Anchored on the stable lid, stored as append-only react events with a current-state projection on every replay (+ a react SSE push, optimistic taps, local-first cache mirror); a redaction takes its reactions with it, delete-for-me hides them per-user. The floor producer reads them as a REACTIONS warmth line in f's brief; the panel transcript deliberately carries none (§8 append-only cache). Rendering is self-hosted Twemoji SVGs (/emoji/, CC-BY 4.0) so chips look identical on every OS. Phase 2, noted not started: personas reacting sparingly (needs a new panel emission type) · a "X reacted" notice on the rail. Closed by gap 12 (v478–v480): the renderRich Twemoji pass for message-text emoji now ships, and this card's + picker — the parked curated ~300 — was retired with it: the composer's emoji panel is the one picker, reactions and text share the one asset pipeline, and a reaction feeds the same Recents the panel reads.
gap 5Send an imageproven in · chat since forever · AI chat since visiondeferred · awaiting DeepSeek vision API

Proven twice over: every chat app sends photos, and since vision landed, every serious AI chat reads them — it's table stakes on both reference products now. And it's the native use of our own advisory seats: the entire 小胖看房 corpus is about apartments people are looking at. "Here's the floor plan" is the message our users are already trying to send.

9:41● ● ●
看房小分队小胖看房 · Feddo · you
卧室 客厅 厨房
这套的户型图,89m²
小胖看房
南北不通透,主卧朝西——夏天下午会很晒。这不是否决项,但谈价的时候,这就是你的筹码。
Message… 🎤
the mock A photo bubble with caption (right, grey), and the persona answering the image itself — orientation, light, leverage — not the caption. Entry via the composer's (camera roll / camera), the slot every thumb already knows.

Scope guard: images ride the existing artifact/media rules — stored with the room, sized/stripped on upload, never re-hosted anywhere else.
provider study · 2026-07-17 Can the panel see? Verified against the providers' live docs (Anthropic vision page · DeepSeek API docs + pricing · Gemini image-understanding + pricing). Two findings up front: the app's default panel model cannot see images — DeepSeek's platform API is text-only, no vision model exists on it — and Anthropic's old w×h/750 token formula is gone: vision is now patch-based, ⌈w/28⌉ × ⌈h/28⌉ visual tokens (28-px patches), with a per-model resolution cap.
model (role)vision?formula & limits$ / 1–2 MP photounder our §8 cache (1h)
DeepSeek v4 Pro / Flash
(panel · the default)
✗ text-only no image input on the platform API, no vision model offered (confirmed 2026-07-17) a text shadow (~400 tok/photo) costs ≈$0.0002 once (miss $0.435/M), then ~$0.000002/turn (hit $0.003625/M) — free in practice
Claude Sonnet 4.6
(panel)
✓ standard tier downscaled to ≤1568 px long edge, cap 1,568 vtok · JPEG/PNG/GIF/WebP · ≤10 MB · ≤100/request ~1,300–1,570 tok → $0.004–0.005 base ($3/M) image blocks cache like text: 2× write once ($0.008–0.009 at $6/M), then 0.1× read = +$0.0005/photo/turn ($0.30/M); a cold reopen (>1h) re-writes the lot
Gemini 3.1 Flash Lite
(sidecar candidate — already in cost.py, GEMINI key already wired)
258 tok per 768×768 tile → 1–2 MP ≈ 1.0–1.5k tok · PNG/JPEG/WebP/HEIC/HEIF in $0.25/M + desc out $1.50/M → ≈$0.001 per photo call pay-once at upload; the shadow rides the room prefix as ordinary text
Claude Haiku 4.5
(sidecar candidate — already in cost.py)
✓ standard tier same patch formula, 1,568-vtok cap in $1/M + out $5/M → ≈$0.0035 per photo call pay-once at upload
Gemini 3.5 Flash
(sidecar candidate)
same tiling as Flash Lite in $1.50/M + out $9/M → ≈$0.006 per photo call pay-once at upload (overkill for a describe call)
architectureverdictthe numbers
A · native only ✗ dead on arrival The default model can't see — 小胖看房's natural home is a DeepSeek room. And rooms may switch provider mid-conversation (history is stored as plain text), so a text shadow is needed anyway. Native blocks also bloat the prefix: 3 photos on Sonnet = +4.7k tok → +$0.0014 every warm turn (3.5× the whole $0.0004 round) + $0.028 per cold reopen.
B · vision sidecar ✓ recommended ONE Flash-Lite call at upload ≈ $0.001/photo — 2.5× one round, paid once; per-turn cost unchanged. Works on every provider; the shadow is ordinary transcript text under §8, searchable (gap 7), and ledger-ready (model already priced in cost.py). Debt: the panel can never "look again" — mitigate with a domain-aware describe prompt (floor plan → orientation/light/layout/dimensions; screenshot → transcribe the text).
C · hybrid ◐ later, as upgrade Native block on the send turn for Anthropic rooms + the sidecar shadow for continuity. Costs one extra native pass ($0.005) and a one-time BP2 rewrite when the block swaps to text next turn; needs a second harness path — all to benefit only the non-default minority of rooms. Document as the per-room upgrade, don't build in v1.
Recommendation: B now, C documented as the upgrade path. Humans see the stored image in the bubble; the panel reads its text shadow. The photo answers 小胖's use case on the model 小胖 actually runs on, at a price the ledger already knows how to count.

Decision (2026-07-17): DEFERRED — gap 5 waits for DeepSeek's vision API. chat.deepseek.com entered a Vision gray test in July 2026 (the "Thinking with Visual Primitives" research model, report 2026-04-30) — but the platform API is still text-only (changelog: latest entry is still the V4 launch, four text-only model ids). A consumer gray test is usually the step before an API release, so rather than build B now and retrofit C later, we build once, C-shaped, when a vision-capable DeepSeek model id ships: native image blocks on vision-capable panels (DeepSeek's ~120× cache-hit discount makes a resident photo ≈$0.0000054/turn) + the sidecar shadow as the transcript's portable text layer (search · Seen · FP · translate · model-switch). Trigger to revisit: a vision model id on DeepSeek's pricing page.
gap 6Persona discovery feedproven in · Character.ai · Talkie · Replika

Our picker is pull: a search box (with suggested terms) that assumes you already know who you want. The proven pattern on every character app is push: a browsable feed of faces with a greeting hook — the character says something to you before you've chosen them. That's the discovery-mode front door for the user who arrives curious but empty-handed, which in a platform shift is almost everyone.

9:41● ● ●
Discover
Trending this week
小胖看房
买房陪跑
梁宁
产品·人心
R
Dieter Rams
design
Terence Tao
math
Say hi
EP
Esther Perelrelationships
"Tell me about the fight you keep having. Not the topic — the choreography."
Say hi
F
Feddomortgage prep
"带着银行合同来。我们过一遍再签。"
Say hi
王强战队
"你上次说要复盘的那件事,现在有空吗?"
Say hi
the mock A Discover surface: trending row (small cards, one-word hook), then full cards where the persona speaks first — the hook line is authored per persona (a natural extension of the profile card the room already renders), and "Say hi" drops into the greenroom flow that already exists for built personas.

Existing rails: visibility already has the may_discover predicate — this feed is just a second caller of the same filter; private personas never surface.
gap 7In-chat searchproven in · WhatsApp · Telegram · iMessage

Advisory rooms accumulate reference material — numbers, names, the thing Feddo said about the rate three weeks ago. Every messenger our users know can find it; we can't. The Notebook covers the deliberate save; search covers the other 95% — what you didn't know you'd need. Also on the benchmark's borrow list; this is the strategic why-now.

9:41● ● ●
July 12
F
Feddo
首套的话,现在谈到 LPR 减 45 个基点是常见区间,利率之外更要盯提前还款条款。
14:02
Y
You
如果明年利率再降,我是不是等等更好?
14:05
June 28
小胖看房
别赌利率,赌你自己的现金流。月供压到收入三成以内,降不降都睡得着。
21:33
the mock The room header morphs into a search field; results are date-grouped rows — avatar, name in seat colour, snippet with the term highlighted, timestamp. Tap a row → jump to the message in place (the go-to-line affordance the translate-net already has).

Cheap first cut: the client already holds the room history (local-first cache) — v1 is a client-side filter over it; server FTS can come later.
gap 8Long-press selection — the action barproven in · WhatsApp (Android) · Telegram✓ shipped · v443–v444 · 2026-07-16

v434 shipped the first door: a stationary long-press opens the lean Reply · Save · Copy menu. WhatsApp's full grammar goes further — long-press selects the message (its whole row tints edge-to-edge; the bubble itself is untouched and nothing else dims; the reaction bar of gap 4 rides the same beat), and the title bar transforms into an action bar: reply · star · copy · forward · delete · ⋮ — then tapping other bubbles grows the selection and the verbs go batch. This is the hub where quote-reply (✓), reactions, and the Notebook converge on one gesture; the two verbs we genuinely lack are forward and delete.

9:41● ● ●
1 🗑
梁宁
先说结论:这个功能砍掉一半,剩下那半才有人用。
RDieter Rams
Weniger, aber besser. She is right — ship the half you can defend.
好,那我先把导出功能拿掉试一周。
Message… 🎤
the mock Selection mode, WhatsApp's exact visual: the pressed message's whole row washes coral, edge to edge — the tint covers the empty space beside the bubble too; the bubble itself and its neighbours are untouched (no ring, no dimming). The room header is replaced by the action bar — ✕ + count, then ↩ reply (single-select only) · ☆ save (whole message → Notebook, the ✦ Save-line pill's big sibling) · ⧉ copy · ↪ forward · 🗑 delete · ⋮ more (select more · message info · report). Tap more bubbles → count grows, verbs go batch.

Forward: target-picker sheet over your chat list; the message lands in the target room with a small Forwarded tag — personas there read it as guest-shared content.

Delete, the careful one: delete for me = a per-user hide, any message; delete for everyone = your own messages, written as a redaction event honoured at replay — read-path enforcement, same philosophy as the see_from floor; never event-log surgery. Caveat to document: the panel's cached prefix can retain the text until the cache naturally expires.

Layer rule: selection mode is a dismissible layer — it registers for the back gesture like every sheet and menu.
gap 9Direct messages — human ↔ humanproven in · every messenger's spine✓ shipped · v465 · 2026-07-17

The reason WhatsApp opens twenty times a day is people, not content — DMs are the frequency engine behind Nikita Bier's Heat = Frequency × Intensity. Without them we're a destination you visit; with them we're the messenger you live in. And it's barely a new subsystem: the room architecture already implies it — a DM is the zero-persona room, the one cell of the cardinality matrix we never allowed. The twist that makes it ours: invite a persona into the conversation later — which is exactly the core New (humans + personas at one table) arriving through a proven door.

0 personas≥1 personas
1 humannotes-to-self (freebie — WhatsApp message-yourself · Telegram Saved Messages)✓ 1:1 persona chat · the greenroom
2+ humansthe gap — DM & group DM✓ multi-human room (roles · private history)
9:41● ● ●
MMaryprivate chat
那套你到底定了没?中介今天又催我了。
还差最后一步——要不把小胖拉进来,让他看看合同再定?
You invited 小胖看房 · sees the chat from here on
小胖看房
来了。合同发我,重点看三处:付款节点、违约金、交房标准。你们俩谁拿的批贷函?
Message… 🎤
the mock One phone tells the whole story: a plain DM (names drop in a 1:1, WhatsApp-style — the slate accent still marks the other human), then the invite capsule, then the persona's first bubble. Header shows the counterpart's name + avatar, rendered client-side from membership — never baked into a stored title (display names change; the two-stores trap).

Entry point: tap a co-human in any shared room → Message privately. No global user directory — your DM-able set is the people you already share a room with (invite-gated app; discovery stays social).

While the cast is empty: the panel machinery (kickoff · floor producer · batching) stays dormant — zero LLM cost, pure SSE relay; our fastest room by construction.

Inviting a persona: the existing seating flow, gated by may_discover (the v399 seating-door rules apply unchanged). The persona's history floor is set at the join moment — replay-level enforcement, the same see_from mechanism, shown honestly in the capsule. the proven pattern elsewhere is stricter still (WhatsApp and WeChat both spawn a new chat with no history when a 1:1 grows), so floor-at-join is the conservative copy; a "share the backstory" option would need both humans' consent — phase 2 at most.

N humans, no personas — the group DM: the same cell at any human count; everything above (panel dormancy · persona invites with floor-at-join · notices · roles) carries over unchanged. Two specifics: creation gets a second door — New group over the human picker (your DM-able set), zero personas allowed, titled client-side from the members per viewer (the OTHER members' names, capped; a rename stores a real title that wins — shipped v466) — and growing a 1:1 spawns a NEW group, never an in-place conversion (WhatsApp/WeChat's proven pattern, for a social reason no history floor can fix: the floor protects the past, but conversion puts a third reader on a thread two people thought was private; the new group keeps the 1:1 intact).

Open policy for the owner: whether the admin console's read-only room peek applies to human↔human DMs — decide before shipping, not after. Decided: excluded while the cast is empty (the room stays listed, just not readable); seat a persona and peek applies again.

Seating a persona converts the room (✓ v528): the first version seated the persona in place and left the room the canonical 1:1 — which quietly destroyed the pair's only private channel, because "Message privately" then handed back a room an AI was reading, and one person's invite was enough to do it. The invariant we should have held from the start: two people can always reach an AI-free thread, and no single person's action can take it away — the same rule we already applied to humans. So the conversation becomes a group (scrollback intact, persona floored at the join, titled after the persona) and the pair binding is released, so the next Message-privately mints a clean 1:1. WeCom's bots are group-only, which is the same conclusion from the other direction; WhatsApp's per-mention Meta AI is the road not taken. Two defects fell out with it: peek now reads only what the panel reads (sliced at the join floor — inviting a persona could otherwise expose the human-only lines before it), and a group can no longer lose its name when its members leave.

Departures (✓ v528): studied against both references — WeChat tells the removed person and tells the room nothing (a voluntary exit is silent to everyone but you); WhatsApp announces to the room. We had been doing the one arrangement neither app chose. Owner's call: the WhatsApp way — the room is told, and a removal names who did it.

The backlog default — reviewed and deliberately kept: both references hide a room's earlier messages from anyone who joins later; ours shows them unless the owner flips the one-way private-history switch. Flagged 2026-07-19 and kept as-is on the owner's call — our rooms are persona-centred, where handing a newcomer the thread is usually the point.

The duo-chat exits (✓ v515): a 1:1 has no leave — no messenger offers one, and ours only did because the people list was built for groups; it left a nameless one-sided room the leaver could walk straight back in through, and protected nobody. Removed, with remove, rename, private history and the owner badge (a 1:1 has no owner anywhere in the proven world). What a two-person thread actually has: mute, archive, and delete — per person, because a shared chat belongs to everyone in it and one person's housekeeping must not edit another's list; a new message brings a deleted chat back, the proven rule that stops "delete" from quietly posing as a block. Real prevention needs block, which needs a friend/discovery model we don't have — until then unwanted contact is ignorable, not preventable, and the honest lever is that the DM gate is only as strong as the room-invite gate (anyone can pull you into a room, and thereby become DM-able one hop later).
gap 10Dismissal grammar — close where thumbs expect itproven in · Material (Android) · iOS HIG✓ shipped · v516–v526 · 2026-07-18

Shipped as specified, and smaller than feared. The inventory (the standing record, one card per surface, every card owner-stamped before a line moved) found 23 of 36 layers already compliant — the newer surfaces were built to this grammar before it was written down, so the drift was concentrated in the older modal family the 2026-07-10 systemic check had standardized onto .dialog-x. Four task dialogs got their commit slot back; eight more took the door their type asks for. Two invariants kept a shared component safe: the sweep is opt-in (the bare .dialog-x default is byte-identical, so nothing unclassified could shift) and phone-only (desktop verified unchanged, gaining only Esc). The gesture half paid the bigger dividend: the iOS "reveal" turned out to be oursbody.nav-back muted two selectors while six translateX layers had shipped since — and one Esc handler now peels the same LIFO top layer Back does across 24 previously-uncovered layers. One finding deferred by decision: builder-ui.html has no back-stack, popstate or Esc at all and shares top-level history, so Back with its "Delete persona" confirm up unwinds the parent while the confirm stays painted — its own change.

Our layers close with an × in the top-right — a web idiom we standardized (the 2026-07-10 systemic check folded ~11 treatments into one scaffold), but it's our grammar, not the platform's. Native muscle memory differentiates by surface: a page goes back top-left; a task dialog cancels top-left and commits top-right; only overlays close top-right; sheets swipe down. Dismissal is a form of going back — that's why it lives on the left — and an × in the top-right steals the commit slot, creating the "did closing save my changes?" ambiguity the Material layout exists to prevent. Users should spend zero neurons learning our way. Dismissal has two halves: the affordance (where the glyph sits) and the gesture (what the thumb does) — this gap owns both.

Surface typeThe norm (muscle memory)Ours — candidates for the sweep to classify
Page you navigate into← back, top-left; never ×chat info · persona page · Seen read · notification centre
Task dialog (has a commit)× / Cancel top-LEFT · Done/Save top-RIGHThand-pick your panel (the new-chat picker) · forward target · TTS settings
Overlay / viewer× top-right (or tap-out)image viewer · artifact pane cards
Sheet / cardgrabber + swipe-down; × optionalthe Me sheet · reaction details sheet · pickers that are really menus
9:41● ● ●
Hand-pick your panelStart (2)
Search characters…
小胖看房buying prep
EPEsther Perelrelationships
RDieter Ramsdesign
Terence Taomath
FFeddomortgage prep
the mock A full-screen task dialog in the corrected grammar — the hand-pick-your-panel sheet: ✕ top-left (dismiss = go back, selection discarded), Start (2) top-right in coral (the commit slot restored, carrying the selection count). This is the one type where our current ×-right placement actively misleads; pages, overlays and sheets need smaller or no moves.

Deliberate exceptions stand: room settings is Telegram-style by choice — the sweep's classification table RECORDS such decisions (type + "decided, keep"), it doesn't relitigate them.

The sweep, concretely — three phases, gated: (1) Inventory — every dismissible layer via registerBackLayers() (that registry IS the checklist) plus every user of the shared scaffold (.dialog-x/.dialog-back in theme.css, systemic-check #21). The scaffold is one component reused by many surfaces — a single flip would move the × on surfaces where ×-right is correct, so no blanket change, ever. (2) Mock first — a review page (docs/dismissal-sweep.html, the console-redesign pattern) with one card per dialog instance: current vs proposed side by side, its four-type classification, decided exceptions marked keep; the owner stamps every card before any code moves. (3) Apply — variant classes on the shared scaffold (task · overlay · sheet), each surface opting into its approved type; per-page tweaks only where a surface genuinely deviates. Then re-base the house "main dialog / sub dialog" grammar on the four types and re-sync the Style Guide.

The gesture half — both platforms, every layer. Android's back (gesture or button) and iOS's left-edge swipe must dismiss exactly one layer, deepest first, on every surface in the inventory — the sweep audits registerBackLayers() coverage rather than assuming it (a layer shipped since the registry was written is the classic miss; the symptom is an edge swipe that leaves the room and kills the whole view instead of closing the sheet). The gesture and the glyph must always agree: whatever ← or ✕ does, the swipe does.

The iOS animation rule — crisp, never a reveal. On an edge-swipe dismissal the layer just closes. No traditional left-to-right page-slide that drags the underlying layer into view — that animation says "you left a page", and our layers are overlays on one page, not a navigation stack. Whatever the layer's own open/close transition is, the back path exits without the horizontal reveal. Worth verifying on device where the slide comes from: our own CSS transition, a view-transition, or Safari's native swipe-back treatment of a history entry — and killing it at that source (candidates: same-document history entries, no view-transition on the back path, transition-suppressed close).

Desktop stays as it is — by design. In wide mode × top-right is fully correct (that's where windows close) and it applies to every type, not just overlays; add Esc where it's missing. The whole sweep is a phone-layout change, guarded by the existing wide-mode breakpoints — desktop should come out of it unchanged.

No new capability — pure muscle-memory compliance: cheap, horizontal, and it compounds with every dialog we ship next.
gap 11User profiles — a face, a name, one lineproven in · WhatsApp's contact-info page✓ shipped · v468 · 2026-07-17

In every messenger a person is a face + a name + a one-liner, and tapping them anywhere opens the same small dossier. WhatsApp's anatomy, studied: your own profile = photo (tap to change) · display name · About — a ~139-character one-liner, preset or custom ("Hey there! I am using WhatsApp." is the famous default); someone else's = the contact-info page — big avatar (tap → full screen), name, about line, then shared media and shared groups, then the verbs (message · mute · block/report); privacy = photo, about, and last-seen/online each independently set to Everyone / My contacts / Nobody. We have the name half already (username = handle, display_name = shown, the signup preview bubble) — but our humans are still faceless monograms with no page, just as DMs (gap 9 ✓) gave them more surface than ever. The profile page is also the natural home for gap 9's Message privately door.

WhatsApp elementOurs
Profile photonew — avatar upload, monogram stays the fallback; photos/grey are human, colour stays reserved for persona seats
Display nameexists — display_name, the signup identity screen
About one-linernew — ~140 chars, shown on the profile page
Phone number (identity anchor)exists — the username handle
Per-field privacy (Everyone / Contacts / Nobody)v1 default: visible to room-mates (our whole graph IS people you share a room with); the WhatsApp matrix later
Online / last seenRAM presence already exists (never touches state.json) → a simple online dot v1; last-seen deferred
Contact-info verbsMessage privately (gap 9's door) + shared rooms list; mute/block are their own later gaps
9:41● ● ●
Profile
M
Mary
online
"Renovating. Slow replies."
Message privately
Shared rooms
FFlat-hunt crew3 humans · 2 personas
Vv2 flow review2 humans · 2 personas
the mock Another user's profile, reached by tapping them anywhere (a bubble's name, the chat-info member list): avatar hero, name, the online dot, the about line — then the one primary verb, Message privately (gap 9's door finds its home), and the WhatsApp-style shared rooms list as the social context.

Your own profile lives where identity already lives: the Me sheet → Edit profile — photo picker, name (exists), about line, with the same live-preview treatment the signup identity screen already has.

Born compliant with gap 10: this is a page (navigated into) — ← back top-left, no ×.

Plumbing notes: the avatar pipeline is gap 5's rails in miniature (resize + EXIF-strip on upload, room-scoped… but user-scoped here, served like persona card art); the human avatar shows everywhere the monogram shows today — bubbles, chat list, member lists — with the monogram as fallback forever.

Scope guard: letting personas read the about line as guest context is a New idea, not this gap — isolate it separately; the Proven core is social display between humans.
gap 12The emoji library — app-rendered, everywhere the sameproven in · WhatsApp (its own set on Android · Web · Desktop)✓ shipped · v478–v480 · 2026-07-17

WhatsApp's quiet structural choice, studied: on iOS it defers to Apple's set, but on Android, Web and Desktop it ships its own emoji art (designed in-house, 2017) and replaces every emoji codepoint with that art at display time. The result: all non-iOS users see identical emoji regardless of OS vendor or version, and an emoji sent from the newest iPhone never renders as tofu □ on an old Android. The rest of the anatomy: the composer's smiley panel — search on localized CLDR keywords, Recents first (frecency), eight category tabs, long-press skin-tone variants remembered per emoji; and the signature delight — a message that is a single emoji renders large and bubble-less (WhatsApp scales 1–3; we shipped the lone-emoji case only, v482). Gap 4 deliberately fenced this out ("message-text emoji stay native — phase 2"); this gap is that phase 2, grown to its full shape: one emoji subsystem shared by reactions, the composer, and the text renderer.

9:41● ● ●
Flat-hunt crew小胖看房 · Mary · you
MMary
Offer accepted!!
🎉
Search emoji…
Recents
😂 ❤️ 👍 🎉 😮 🙏 😅 🔥
Smileys & people
😀 😄 😁 😆 😅 😂 🤣 🙂 😊 😇 🙃 😉 😌 😍 🥰 😘
🕐🐻🍔🚗💡🚩
Message… 🎤
the mock The smiley lives inside the input field, left edge, muted — WhatsApp's exact placement (not a standalone button) — and toggles the panel: search, Recents (frecency-ordered), category grids, the tab strip. While the panel is open the icon flips to a keyboard glyph (⌨) to toggle back. Above it, the other signature: a single-emoji message rendering large and bubble-less (no outline or fill — just the emoji). (This doc mock uses your OS's glyphs — the app won't; that's the whole point.)

One subsystem, not three: extend gap 4's asset decision (self-hosted Twemoji under /emoji, CC-BY attribution line) to the full set: reactions, the picker, and the text renderer share the same assets, the same CLDR keyword search (localized — ties into the i18n layer), the same recents and tone preferences. Don't build a second pipeline.

The text pass: in renderRich() after sanitize — replace each emoji grapheme with <img class="emj" alt="<char>"> so copy/paste and screen readers keep the real characters. Segmentation must be correct: ZWJ sequences (👨‍👩‍👧), variation selectors, tone modifiers — one grapheme, one image. It applies to persona bubbles too (models emit Unicode emoji — cross-platform consistency for the cast, free). Final render only; never in the streaming hot path.

The solo-emoji rule (refined v482): a message that is exactly one emoji and nothing else renders large (35px) and bubble-less — transparent, no border or fill, a plain emoji floating in the row (WhatsApp/iMessage). Two or three emoji are just inline emoji in a normal bubble. (The first cut, v478, did a graded 1–3 jumbo with j1/j2/j3 classes; the owner scrapped it for one clear rule and two sizes only — 21px inline, 35px solo.)

Perf: virtualized picker grid, category-lazy asset loading, SW-cached; tofu fallback = native glyph if an asset is missing.

Out of scope: stickers · GIFs · custom/animated emoji (the panel's other WhatsApp tabs) — separate gaps if ever wanted.

✓ Shipped v478–v480, in three pushable parts. The audit first: gap 4's reactions were already on self-hosted Twemoji, so there was no glyph migration — the real duplication was a second pipeline, and retiring it became part 3. The vendor (v478): the curated 307 → the full 3,838-file jdecked/twemoji v15.1.0 set (all 307 verified byte-identical to upstream first, so the art stays consistent); any emoji can arrive in text, so a subset was no longer a defensible floor. The text pass (v478): emojifyHtml() runs LAST in both paths — renderRich() after DOMPurify and fmtUserText() after esc() — so personas get cross-platform art free. It walks a detached DOM, not the string (a regex over HTML can match inside an attribute — that's how a src gets hijacked), builds src from codepoints only behind a hex guard, and skips code/pre and .kx (raw TeX that typesetMath() reads back as textContent, where an <img> would have silently eaten the character). Segmentation = \p{RGI_Emoji} under the v flag (one atom per RGI sequence), with a hand-built u fallback of the same UTS-51 shape for Safari <17; both require VS16 on text-default characters, so ™ and © stay text and only ™️ becomes art — the call the OS itself makes. Verified on 19 cases (ZWJ families, mixed-tone handshakes, flags that must not merge, bare digits that must not become keycaps). Solo emoji (v478, refined v482): the first cut scaled 1–3 emoji on a graded j1/j2/j3; the owner scrapped that for two sizes only — 21px inline, and 35px for a lone emoji, rendered bubble-less (transparent, no chrome — the .bubble element stays for lid/long-press/reactions, only the styling is stripped via !important). Computed at render time so history and replay agree; the chat-list preview stays plain text. The non-obvious half: a rendered bubble became a picture of its text, and an <img> contributes nothing to innerText — an emoji-only bubble read back as the empty string. Quote-reply, the pacing matcher (it compares a rendered bubble to RAW pending text) and note lookup all now read through speechText(); tokenizeSpeech() treats an img.emj as an atomic token that contributes its real characters, which also makes notes saved before the change match a re-rendered bubble.

The panel (v479) is the piece with the teeth. The smiley sits inside the field pill at its left edge and is a sibling of #ta, never a child — the v477 tap router keys on "target is #ta or inside it", so the door can't be read as a composer tap. It is a keyboard-space occupant, not a new widget: kbSpace.occupy(h) reserves the keyboard's own measured height (mad-kbh, per orientation) and write() subtracts it from fullH, the keyboard-FREE layout height — never the live clientHeight, because Android's layout viewport shrinks with the keyboard and subtracting mid-animation would shrink the shell by ~2× the keyboard and snap back. Open = reserve THEN blur, so focusout's same-task restore (v475) computes the height the keyboard already had and setShell's dedupe makes it a no-op: zero viewport motion. The ⌨ flip goes through the v477 routing (pre-shrink + forced flush + focus({preventScroll})) — a raw .focus() re-opens the shove. The door's pointerdown only preventDefaults and does no layout: trap ② is that relayouting under a live finger makes iOS cancel the tap (exactly how v474 broke). Search runs on localized CLDR keywords (猫 → cats, 哭 → crying), Recents are frecency (count × a 14-day half-life), tones are remembered per emoji, and the grid mounts in 96-emoji chunks — a tab holds up to 552 and the set is 1,897. Data (/emoji/index.json + kw-{en,zh}.json, ~214KB from emojibase-data's CLDR) is vendored and fetched on first open only. Desktop gets a popover anchored to the smiley. Found by testing, not reasoning: when no keyboard ever materialises (a fine pointer at narrow width, a hardware keyboard) nothing re-fitted the shell after the flip — iOS leans on preShrink's write, Android on the keyboard's own resize, and that path had neither; one late guarded re-fit closes it.

Unified (v480): the parked + picker — its own hardcoded ~300-emoji set, grid, modal, stylesheet, i18n labels and back-stack entry — is retired; it was a whole parallel pipeline kept alive for a door v456 had already removed. The panel is the picker now, so a future + is still one line (window.openEmojiPanelFor(lid), deliberately unwired — twelve-only is gap 4's call) and it lands on the real thing. One prefs layer: recents and tone prefs moved into the shared core, and a reaction now feeds the same frecency store — tap 🎉 on the bar and it surfaces in the composer panel's Recents. The quick twelve stay a fixed curated strip by design.

Owed: on-device acceptance on iOS Safari + Android Chrome (keyboard → panel → keyboard with no shove/flash/scroll-jump, plus the dictation deck states) — a desktop browser has no real keyboard to shove, so the swap's zero-motion claim is verified by construction and by the shell numbers, not yet by a thumb.
gap 13Contacts — the friend layer over the user poolproven in · WeChat (request + accept) · WhatsApp (address book)

Both reference apps separate the pool (everyone on the service) from your people — by opposite philosophies, studied. WhatsApp: the pool is every phone number on earth; "your people" is simply your address book projected onto it — no ceremony, no request, not even symmetric (A can hold B while B never held A); anyone who knows your number can message you cold, and safety lives downstream — block/report plus the privacy tiers (Everyone / My contacts / Nobody) that reference the contact list. WeChat: the pool is closed — no DM until a friend request with a note is accepted; the relationship is symmetric (deletion famously unilateral — you learn you were deleted only when a message bounces); every add-path is a permission switch (phone · ID · QR · group · name card), and meeting in a group does not make you contacts — adding from a group member list is still a request. Ours today: no friend layer at all — "shares a room with me" is the accidental proxy gating DMs (gap 9) and profile visibility (gap 11), and the gap 9 duo-exit work already hit the wall it creates: block needs a relationship model we don't have, and the DM gate is only as strong as the room-invite gate. Contacts are the durable answer: my people persist beyond any room, and strangers can't reach me uninvited.

DimensionWhatsAppWeChatOurs — proposed
The poolevery phone number, openclosed; findability per-switch ("Add me via")invite-gated accounts (keep)
Becoming contactsaddress-book sync — no ceremony, one-way is finerequest + note → accept; symmetricrequest + note → accept, riding the notifications rail
Cold DMallowed; block downstreamforbidden until acceptedtoday room-mates only; contacts add the durable, room-independent key
Add pathsknowing the number IS the pathID/QR search · group member · name carda room-mate's profile page · personal QR/link · username search behind a "findable" toggle, default off
Group ≠ friendsn/a (groups already have your number)group chat ≠ contacts; adding from a group = still a requestsame — sharing a room never auto-friends
Removingdelete from address book, silentunilateral delete; the famous bounce revealunilateral remove, silent (the proven mercy)
What it unlocks— (everything was already open)DM · Moments · name cardDM beyond rooms · gap 11's "My contacts" privacy tier · block (the gap 9 v515 debt) · who-can-pull-me-into-rooms
snap's third way Snapchat sits exactly between the two models: asymmetric add, gated reach. There is no accept/decline ceremony — you "add" one-way, they see it in "Added Me" and either add back or quietly don't; messaging + story access unlock only on reciprocation (the default privacy is friends-only). The request and the add are the same act, and "decline" isn't a button — nobody ever has to reject anyone. Its add paths confirm ours: the Snapcode (WeChat-QR-inspired, by Spiegel's own account) proves the personal-code door a third time — with the detail that the scanner lives where people already are, one gesture from the camera the app opens into; Added Me is our rail-as-request-inbox, independently invented; and Quick Add — mutual-friend suggestions — is the cautionary proof for our "never": it drove Snap's growth and earned the minor-safety retrofits that followed. We keep WeChat's note-carrying request (our adds arrive with room context, and the note does real work in an invite-gated pool) — but if the accept ceremony ever feels heavy in testing, Snap's variant is the recorded fallback: accept = add back, decline = do nothing — one deletion from our design, not a redesign.
9:41● ● ●
Contacts
Search contacts…
New requests
K
Kenvia Flat-hunt crew
"Mary 说你手里有那份贷款对比表——求一份"
Accept
Contacts (3)
MMaryRenovating. Slow replies.
老周看盘中,勿扰
LLeo
the mock A Contacts page (a row in the Me sheet; a tab later if it earns one): pending requests on top — each carrying its context ("via Flat-hunt crew") and the requester's note, WeChat's exact grammar; accept is one tap, decline is silent. Contact rows show the gap 11 about line and open the profile page. The holds your add doors: my QR / my link · scan · username search (only reaches people whose "findable" toggle is on).

The chosen blend: WeChat's ceremony on our invite-gated pool — request + note → accept, symmetric, unilateral remove — with WhatsApp's lightness where it's safe: inside an already-shared room the request pre-fills its context, no interrogation wall. Group ≠ friends is kept as law: sharing a room never auto-friends; "Add to contacts" on a room-mate's profile sends a request.

What flips when it ships: gap 9's Message privately key upgrades from room-mates to contacts ∪ room-mates (room-mates keep the DM door they have — WeChat's group temp-chat is the proven precedent, and it's shipped behavior); gap 11's privacy matrix gets its real "My contacts" tier; block becomes buildable — deny requests + drop from each other's DM keys — closing the debt the v515 duo-exit note recorded; and "who can pull me into rooms" becomes an expressible permission instead of an open door.

Data shape: one symmetric friendship row per pair (requester · note · pending/accepted); request/accept events on the rail (a request is a notice with an Accept verb — the noticeSpec pattern); unilateral delete flips state and tells no one. Never: "people you may know" — no graph mining, deliberately.

Requests are the FarmVille bar, round two: the empty neighbor bar drove the requests that reminded players to come back. A friend request is our second organic push payload (gap 1 ✓ gives it the lock screen).

> Better — three real, six mislabeled

Pincus's bar: Better is objective — the existing audience cheers instantly. Not "our conversations are deeper."

Current, realWhy it clears the bar
Instant web play — no download, no store, freePincus's own number: a required download loses 80–90% of the audience. Zynga Poker's Better, verbatim. The PWA is this strategy.
Fast on bad networks — anywhereThe local-first layer (persistent cache · send outbox · delta sync) is the WhatsApp bad-network playbook, serving any flaky link in the world. Bonus, not the point: browser-direct STT + the SG paths mean it even works from inside China.
~$0.0004 a roundThe economics that make "free" sustainable — the enabler Better, like Flash-for-free enabled Zynga's no-download.
Potential nextThe 10/10 test
First-token latency~3s staging cost is the accepted debt; sub-second first paint of the reply is the clearest "instantly better" left on the table.
Reply length disciplineThe soft-length debt. "It answers like a person, not an essay" is the #1 cheer in every AI-chat review.
Zero-friction entry from a shared linkTap a shared room link → talking, no signup wall. Account creation is the same cliff as a download. (Gate abuse via the inviter's cap, not the guest's patience.)
Serve the world from the edgeThe single SG box was a China-first choice; US/EU users pay the distance on every round trip (the ~1.4s handshake in Perceived speed). Edge/multi-region is the world-audience Better.
the trap Pincus: what product makers think is Better is usually New. Reclassified honestly: the floor producer, Seen, Vibes, the Studio build machine, the manners steerings, question-back mode — all New. An existing group-chat user can't even see the floor producer, so they can't cheer it. This matters because Better is exempt from "all New fails" — New isn't. Filing these as "quality improvements" quietly exempts them from the isolate-and-test discipline they need.

+ New — seven stacked, one disciplined, one worth declaring

Live or in flight today: the multi-persona room itself · floor-producer orchestration · real-figure advisory seats · Seen · Vibes · the Studio machine · the manners steerings. That's the Tribe shape — every zone touched at once. Exactly one runs as Pincus prescribes: manners v2 — stamped per room at creation, immutable, console default, judged on a single metric (return rate). That's the template; the others get its discipline or wait their turn.

the core new Real humans and a persona cast at one table. Zynga Poker's New was "real people, often your friends, with their pictures at the table" — ours is its mirror: c.ai group rooms have no second human, WhatsApp groups have no personas; we're the only table where both sit down. It's already built (multi-human rooms, roles, private history) but has never been declared the New and measured as one. It's also the growth loop: an invite is virality and the come-back reminder (gap 1 makes it land), and gap 9's DM-that-can-seat-a-persona is its smoothest on-ramp. Measure it the way Zynga measured poker — % of rooms that gain a second human, and D1 return of the invited. Zynga's green light was 25% of players joining friends' tables.

The backlog — candidates to isolate one at a time, after the core New has its number:

The verdict

We're running the playbook inverted: heavy New, thin Proven, in the one moment (a platform shift) when Proven + Better alone can win. The move: close the Proven gaps in order — push first (it de-poisons our own return-rate metric), DMs second (gap 9 — the frequency engine, and the on-ramp to the core New) (✓ shipped v465), then the long-press selection grammar (gap 8, the hub) with its family — quote-reply (✓ shipped v434) · reactions (✓ shipped v453) · save/forward/delete (✓ shipped v444) — then user profiles (gap 11 — faces make DMs feel inhabited, and the profile page is Message-privately's home) (✓ shipped v468) · the emoji library (✓ shipped v478–v480 — it rode gap 4's rails exactly as planned: the assets were already there, so the work was the text pass, the panel, and deleting the second pipeline) · voice · images · discovery · search · contacts (gap 13 — the friend layer that makes block and the "My contacts" privacy tier buildable, and the FarmVille request loop our growth needs). Gap 10, the dismissal-grammar sweep, is horizontal: one dedicated pass over every registered layer, cheap, and it compounds with every surface shipped after it. Keep the three real Betters sharp, and declare humans + personas at one table the single isolated New, with a Zynga-style number on it.

The caveat Pincus himself makes: the framework produces B+ products; magic is what gets you to A. The floor producer and the persona pipeline are our pursuit of magic — the taste layer that makes the table worth sitting at. Keep pursuing it. Just stop calling it Better, and stop letting it queue-jump the mechanics our audience already expects from any chat app they'd return to.

Dialogue · Proven Better New · framework from Mark Pincus, Life at the Speed of Play (2025), ch. 4 · see also Roadmap · Current functions · UX benchmark · Notifications · Seven steerings