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.
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 typecheckThe 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.
| Scenario | Procedure and expected result |
|---|---|
| A/B isolation | Set 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 defaults | Pin 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 variants | Open 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 person | Edit 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-persona | Select 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 persona | Delete 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 identity | Load 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 branch | Revert, 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 save | Change 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 refresh | If 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 errors | Verify 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. |
| Ownership | A 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.
