Skip to content

Session persona isolation test plan

Scope

Verify that each session retains its selected identity while using that persona's current public details. World and profile choices are defaults for new sessions. See the behavior reference and player instructions.

Validation uses code inspection, automated tests, typechecking, and builds. The interactive scenarios below are a repeatable acceptance plan, not a claim that browser or production interactions were executed.

Automated checks

Run database tests only against ephemeral PGlite with DATABASE_URL and DATABASE_READ_URL empty, PGLITE_DATA_DIR=memory://, a test BETTER_AUTH_SECRET, and REDIS_URL and POSTHOG_API_KEY empty. Do not point tests at development or production data.

sh
pnpm --filter @yumina/server exec tsx --test src/lib/session-persona.test.ts src/lib/persona-follow-profile.test.ts src/lib/persona-metadata.test.ts src/lib/persona-prompt.test.ts
pnpm --filter @yumina/server exec tsx --test src/routes/personas.test.ts
pnpm --filter @yumina/server exec tsx --import ./scripts/test-session-persona-bootstrap.mts --test --test-force-exit src/routes/sessions-branch.test.ts src/routes/sessions-revert.test.ts
pnpm --filter @yumina/app exec tsx --tsconfig tsconfig.app.json --test src/lib/refresh-chat-persona.test.ts src/lib/chat-persona-controller.test.ts src/lib/persona-profile.test.ts src/lib/persona-binding-i18n.test.ts src/stores/personas.test.ts src/features/chat/persona-manager-dialog.test.ts
pnpm build
pnpm typecheck

The bootstrap uses synthetic tables without production constraints or indexes. These tests verify resolver and route behavior, not production migration locking. Record actual results in the release report rather than treating this command list as a completed run.

Acceptance scenarios

Use synthetic personas A and B, distinguishable public details, and a private note marker that must never appear in prompts or session identity responses.

ScenarioProcedure and expected result
A/B isolationSet Session 1 to A and Session 2 to B. Alternate between them, including sessions in the same world. Send, continue, and regenerate in each. Displayed identity and prompt remain A for Session 1 and B for Session 2.
World and profile defaultsPin a world to A and select B in the profile. A new session in that world starts with A; a new session in an unbound world starts with B. Change both defaults and verify existing sessions retain their selections. Disabling the profile default must preserve world bindings.
Language variantsOpen the same card through its available language variants and start sessions. Confirm the persona picker reads and writes the same concrete world ID used to create the selected variant's session. Existing sessions keep their own identities when the displayed language or variant changes.
Edit the selected personEdit A's name, avatar, appearance, personality, or backstory without changing its ID. Sessions using A receive the latest public fields on the next load or generation. Sessions using B remain B. Private notes remain excluded.
Explicit no-personaSelect no-persona inside Session 1, then activate a profile persona and change the world's default. Session 1 remains without a persona across reopening, generation, and restore. Other sessions are unaffected.
Deleted personaDelete A while Session 1 is bound to A and the profile or world default is B. Session 1 becomes no-persona; it must not silently adopt B.
Legacy identityLoad a legacy session with saved public fields but no persona ID, including a name shared by A and B. Preserve its saved identity without guessing an ID. A legacy session with no identity stays no-persona. Concurrent explicit selection must win over initialization.
Restore and branchRevert, restore a checkpoint, branch, and restart. Preserve the session's identity independently of restored gameplay metadata and current defaults. A branch inherits the source identity.
Close immediately after saveChange a session persona and immediately close the picker. After the save succeeds, identity still refreshes. Loaded history pages, pagination state, gameplay variables, and audio stay intact.
Streaming and refreshIf a persona edit needs a refresh during streaming, defer it until the stream ends. Navigating away or receiving a response for another session must not apply stale identity. Normal turns without a persona change must not issue a full session GET for identity refresh.
Existing controls and errorsVerify the original session-picker icon and chat + entry, selected and no-persona states, and clear save failures. Users with no personas keep the original hidden-icon behavior. A failed save must preserve the previous selection.
OwnershipA user cannot choose another user's persona or update another user's session or world binding. Failed ownership checks leave existing selections untouched.

Release checks

  • Inspect the final diff for changes limited to persona behavior, its existing controls, tests, and documentation.
  • Confirm the release commit is the deployed commit and the service health check passes after deployment.
  • Report automated test results and any unexecuted interactive checks separately. Do not describe a healthy deployment as proof that all UI scenarios were exercised.