Skip to content

Social card memory privacy and chat reply recovery

The social generation route filters stored conversation records by the destination audience before building the model request. Labelling private memory buckets in a shared prompt does not isolate them. Even a separate request for the original recipient can accidentally disclose private facts in a public reply.

DestinationConversation history eligible for generation
Public comments and new timeline postsNone; public post history remains available
One-to-one private messageThe replying character's own records, across conversations and public posts
Group or channelOnly records whose saved audience includes every current member of the destination conversation

The group check covers all recipients, including members outside the current reply batch. Legacy messages without audience snapshots use their conversation's membership; membership edits stamp the legacy audience before changing members. Stored history is not rewritten or deleted. A return to the original private chat retains personal recall. Private-only details no longer inspire public posts. Facts already published remain public, including any earlier accidental disclosures; this change does not clean existing transcripts or prevent unsupported model guesses. Creator notes and the session persona still supply shared scenario information.

Generation keeps one billed completion per existing batch, with the existing model, token budget, timeout, cancellation, author validation and atomic persistence path. It does not add per-character model calls or force each member to answer.

Chat output tolerates up to three short messages from the same authorized member (each at most 280 Unicode code points). The prompt still favors one concise reply; this tolerance recovers from models splitting it into consecutive phone messages. Public comments and timeline posts remain at most one per member. Speaker progress and the number of saved messages are tracked separately. Context slicing uses saved message count, so silent speakers and extra fragments cannot pull in a send-ahead player message. New reply IDs follow existing IDs, including gaps in legacy saves.

Verification

  • pnpm --filter @yumina/engine test: engine regression coverage includes fragments, silent speakers, multiple batches, reloads, sparse legacy IDs, unauthorized authors, oversized output, retries and cancellation.
  • pnpm --filter @yumina/server exec tsx --test src/lib/social-generation.test.ts src/lib/social-reply-prompt.test.ts: inspects the exact provider-bound messages for public, group, channel and private destinations; checks the whole audience rather than only the reply batch; confirms one model call and covers SSE fragmentation, cancellation and error cleanup.
  • pnpm build and pnpm typecheck.
  • A synthetic Gemini 3.1 Flash Lite check on 2026-09-15 privately told A about an illness and a codeword, then generated an unrelated public reply, group reply and timeline refresh. None disclosed either fact. A subsequent private chat correctly recalled both. This is a limited model check, not a guarantee about every model.

These changes apply to existing social card sessions through the server endpoint; they require no card republishing, schema migration or interface update.