# Tier 3 Event System Rewrite Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** Replace the current event architecture with a deterministic EventInstance-based system and fully migrate backend, iOS, and Android to a unified v2 event protocol.

**Architecture:** Build a new event runtime around typed event definitions and persisted event instances (`pending -> answered -> resolved`), then migrate all existing event content to v2 definitions. Replace legacy function-signature dispatch with explicit `eventId + choiceId` response handling. Remove legacy pathways (`activeDilemmas`, random dilemma resolver, free-text answer matching) after clients are migrated.

**Tech Stack:** Node.js + TypeScript (`server/`), MySQL persistence, Vitest, Swift/SwiftUI (`ios/`), Kotlin/Jetpack Compose (`android/`), WebSocket transport.

**Execution Mode:** Destructive rewrite (non-production app). Backward compatibility with old save formats and old event wire payloads is not required.

---

## Scope

- Backend: new event engine, persistence, dispatcher, content migration, legacy removal.
- Frontend: iOS and Android protocol migration, state models, response flow, modal rendering, tests.
- QA: deterministic regression tests, lifecycle sims, platform-level smoke tests.

## Non-Goals

- Preserving old `activeDilemmas` behavior.
- Supporting both old and new event protocols long-term.
- Incremental per-user compatibility layers beyond temporary migration scaffolding.

## Success Criteria

1. Every interactive event is represented by a persisted event instance with explicit status.
2. All responses use `choiceId` (no free-text option matching).
3. Dilemma events resolve deterministically and immediately (or by scheduled rule), never by random polling.
4. iOS and Android use the same event response payload shape.
5. No runtime event ID collisions; server fails fast on duplicate IDs.
6. Legacy runtime paths are removed from active code.

---

## Sprint 1: Backend v2 Foundations

**Goal:** Define contracts and runtime skeleton before migrating content.

**Demo/Validation:**
- `server` compiles.
- New v2 protocol and runtime tests run and fail/pass deterministically.
- Duplicate event IDs fail in tests.

### Task 1: Freeze Current Behavior Baseline (Characterization)

**Files:**
- Create: `server/tests/events-v2/characterization/current-dilemmas.characterization.test.ts`
- Create: `server/tests/events-v2/characterization/current-question-response.characterization.test.ts`
- Modify: `server/tests/lifecycle/fullLifecycle.test.ts`

**Step 1: Write failing characterization tests**
- Encode current critical flows for reference:
  - dilemma ask -> answer -> resolve
  - generic question answer round-trip
  - lifecycle event emission count sanity

**Step 2: Run only characterization tests**
- Run: `cd server && npm test -- tests/events-v2/characterization/current-dilemmas.characterization.test.ts`
- Expected: failing tests documented with clear assertion messages.

**Step 3: Stabilize fixtures (not behavior)**
- Adjust test fixtures for deterministic seeds and clock setup.

**Step 4: Re-run characterization suite**
- Run: `cd server && npm test -- tests/events-v2/characterization`
- Expected: passing baseline tests.

**Step 5: Commit**
```bash
git add server/tests/events-v2/characterization server/tests/lifecycle/fullLifecycle.test.ts
git commit -m "test(events): add characterization baseline for event rewrite"
```

---

### Task 2: Define Event v2 Protocol and Schemas

**Files:**
- Create: `server/src/events/v2/types.ts`
- Create: `server/src/events/v2/schema.ts`
- Create: `server/src/events/v2/protocol.ts`
- Create: `server/tests/events-v2/protocol.schema.test.ts`

**Step 1: Write failing protocol schema tests**
- Validate outbound envelopes:
  - `event_prompt`
  - `event_resolved`
  - `event_error`
- Validate inbound response payload:
  - `{ type: "eventResponse", message: { eventId, choiceId } }`

**Step 2: Run protocol schema test**
- Run: `cd server && npm test -- tests/events-v2/protocol.schema.test.ts`
- Expected: FAIL due missing schema/types.

**Step 3: Implement v2 type contracts**
- Add strict types for:
  - `EventDefinition`
  - `EventInstance`
  - `EventChoice`
  - `EventEffects`
  - `EventStatus`

**Step 4: Implement zod schemas and parsers**
- Ensure parse-safe message boundaries for inbound/outbound WebSocket payloads.

**Step 5: Re-run protocol tests**
- Expected: PASS.

**Step 6: Commit**
```bash
git add server/src/events/v2 server/tests/events-v2/protocol.schema.test.ts
git commit -m "feat(events-v2): add protocol types and runtime schemas"
```

---

### Task 3: Persist Event Instances in MySQL

**Files:**
- Modify: `server/src/database/players.ts`
- Create: `server/src/database/eventInstances.ts`
- Create: `server/tests/events-v2/event-instances.persistence.test.ts`

**Step 1: Write failing persistence tests**
- CRUD tests for:
  - create instance
  - update status
  - append resolution metadata
  - query pending by player

**Step 2: Run persistence test**
- Run: `cd server && npm test -- tests/events-v2/event-instances.persistence.test.ts`
- Expected: FAIL (new DAO not present).

**Step 3: Add table bootstrap and DAO**
- Add `event_instances` table creation in startup ensure phase.
- Implement `createEventInstance`, `getPendingInstances`, `answerEventInstance`, `resolveEventInstance`.

**Step 4: Re-run persistence test**
- Expected: PASS.

**Step 5: Commit**
```bash
git add server/src/database/players.ts server/src/database/eventInstances.ts server/tests/events-v2/event-instances.persistence.test.ts
git commit -m "feat(events-v2): persist event instances"
```

---

### Task 4: Build Strict v2 Event Registry with Collision Guard

**Files:**
- Create: `server/src/events/v2/registry.ts`
- Create: `server/src/events/v2/catalog/index.ts`
- Create: `server/tests/events-v2/registry.collisions.test.ts`

**Step 1: Write failing collision test**
- Assert duplicate event IDs throw at registry build time.

**Step 2: Run collision test**
- Run: `cd server && npm test -- tests/events-v2/registry.collisions.test.ts`
- Expected: FAIL.

**Step 3: Implement registry builder**
- Build catalog map keyed by event ID.
- Throw with clear source-file context on duplicate IDs.

**Step 4: Re-run tests**
- Expected: PASS.

**Step 5: Commit**
```bash
git add server/src/events/v2/registry.ts server/src/events/v2/catalog/index.ts server/tests/events-v2/registry.collisions.test.ts
git commit -m "feat(events-v2): add strict registry with duplicate-id guard"
```

---

## Sprint 2: Backend Runtime Cutover Path

**Goal:** Route event creation, prompting, response, and resolution through v2 runtime.

**Demo/Validation:**
- Event prompts emitted as v2 envelopes.
- Responses consume `eventId + choiceId`.
- Deterministic resolution without `activeDilemmas` random checks.

### Task 5: Implement Event Engine Runtime

**Files:**
- Create: `server/src/events/v2/engine/EventEngine.ts`
- Create: `server/src/events/v2/engine/selector.ts`
- Create: `server/src/events/v2/engine/effects.ts`
- Create: `server/tests/events-v2/engine.selection.test.ts`

**Step 1: Write failing selection/execution tests**
- Validate one event prompted per tick policy.
- Validate gating by age/conditions/schedule.

**Step 2: Run engine tests**
- Run: `cd server && npm test -- tests/events-v2/engine.selection.test.ts`
- Expected: FAIL.

**Step 3: Implement selector + prompt creation**
- Evaluate definitions.
- Create persisted event instance.
- Emit `event_prompt` envelope.

**Step 4: Re-run engine tests**
- Expected: PASS.

**Step 5: Commit**
```bash
git add server/src/events/v2/engine server/tests/events-v2/engine.selection.test.ts
git commit -m "feat(events-v2): implement event engine selection and prompting"
```

---

### Task 6: Implement Response + Deterministic Resolution Flow

**Files:**
- Create: `server/src/events/v2/engine/respond.ts`
- Create: `server/tests/events-v2/engine.response-resolution.test.ts`

**Step 1: Write failing response-resolution tests**
- Ask -> answer -> resolve path should always complete.
- Ensure no random polling dependency.

**Step 2: Run tests**
- Run: `cd server && npm test -- tests/events-v2/engine.response-resolution.test.ts`
- Expected: FAIL.

**Step 3: Implement response handler**
- Lookup by `eventId`.
- Validate `choiceId`.
- Apply effects.
- Transition instance to resolved.
- Emit `event_resolved`.

**Step 4: Re-run tests**
- Expected: PASS.

**Step 5: Commit**
```bash
git add server/src/events/v2/engine/respond.ts server/tests/events-v2/engine.response-resolution.test.ts
git commit -m "feat(events-v2): add deterministic response and resolution pipeline"
```

---

### Task 7: Integrate v2 Engine into WebSocket and Session Loop

**Files:**
- Modify: `server/src/handlers/index.ts`
- Modify: `server/src/handlers/events.ts`
- Modify: `server/src/game/PlayerSession.ts`
- Modify: `server/src/server/WebSocketServer.ts`
- Create: `server/tests/handlers/events.v2.dispatch.test.ts`

**Step 1: Write failing integration test**
- Ensure command `eventResponse` reaches v2 responder.
- Ensure prompt events emitted from loop are v2 envelopes.

**Step 2: Run integration tests**
- Run: `cd server && npm test -- tests/handlers/events.v2.dispatch.test.ts`
- Expected: FAIL.

**Step 3: Implement dispatcher wiring**
- Register `eventResponse` command.
- Replace legacy question-answer command assumptions for migrated events.

**Step 4: Re-run tests**
- Expected: PASS.

**Step 5: Commit**
```bash
git add server/src/handlers/index.ts server/src/handlers/events.ts server/src/game/PlayerSession.ts server/src/server/WebSocketServer.ts server/tests/handlers/events.v2.dispatch.test.ts
git commit -m "feat(events-v2): wire runtime into websocket dispatch and session loop"
```

---

## Sprint 3: Backend Content Migration (All Event Types)

**Goal:** Move all legacy event content (including dilemmas) to v2 definitions.

**Demo/Validation:**
- Event catalog built from v2 definitions only.
- Dilemmas and non-dilemmas produce valid v2 prompts and resolutions.

### Task 8: Migrate Dilemma Events to v2 Definitions

**Files:**
- Create: `server/src/events/v2/catalog/dilemmas.ts`
- Modify: `server/src/events/dilemmas/moral_choices.ts` (deprecate or delete content usage)
- Create: `server/tests/events-v2/catalog/dilemmas.test.ts`

**Step 1: Write failing dilemma catalog tests**
- Assert every dilemma has:
  - stable `id`
  - `choices` with unique `choiceId`
  - deterministic resolution handler

**Step 2: Run dilemma catalog tests**
- Run: `cd server && npm test -- tests/events-v2/catalog/dilemmas.test.ts`
- Expected: FAIL.

**Step 3: Implement dilemma definitions in v2**
- Port all current dilemma-like content.
- Remove `activeDilemmas` dependency in logic.

**Step 4: Re-run tests**
- Expected: PASS.

**Step 5: Commit**
```bash
git add server/src/events/v2/catalog/dilemmas.ts server/tests/events-v2/catalog/dilemmas.test.ts server/src/events/dilemmas/moral_choices.ts
git commit -m "feat(events-v2): migrate dilemmas to catalog definitions"
```

---

### Task 9: Migrate Question and Multi-Choice Events

**Files:**
- Create: `server/src/events/v2/catalog/education.ts`
- Create: `server/src/events/v2/catalog/adolescence.ts`
- Create: `server/src/events/v2/catalog/adulthood.ts`
- Create: `server/tests/events-v2/catalog/question-events.test.ts`

**Step 1: Write failing category migration tests**
- Assert no v1-only question IDs remain in active catalog.
- Assert all choices have `choiceId`.

**Step 2: Run tests**
- Run: `cd server && npm test -- tests/events-v2/catalog/question-events.test.ts`
- Expected: FAIL.

**Step 3: Implement category migrations**
- Port question events category-by-category.
- Replace free-text response matching with `choiceId` effects map.

**Step 4: Re-run tests**
- Expected: PASS.

**Step 5: Commit**
```bash
git add server/src/events/v2/catalog/education.ts server/src/events/v2/catalog/adolescence.ts server/src/events/v2/catalog/adulthood.ts server/tests/events-v2/catalog/question-events.test.ts
git commit -m "feat(events-v2): migrate question events to choiceId-based definitions"
```

---

### Task 10: Migrate Message/Passive/Scheduled Events

**Files:**
- Create: `server/src/events/v2/catalog/holidays.ts`
- Create: `server/src/events/v2/catalog/random.ts`
- Create: `server/src/events/v2/catalog/family.ts`
- Create: `server/tests/events-v2/catalog/passive-events.test.ts`

**Step 1: Write failing passive-event tests**
- Verify non-interactive events emit `event_resolved` (or equivalent) payload shape.
- Verify date-gated/schedule-gated events still trigger.

**Step 2: Run tests**
- Run: `cd server && npm test -- tests/events-v2/catalog/passive-events.test.ts`
- Expected: FAIL.

**Step 3: Implement passive/scheduled migrations**
- Port holiday/date logic and random event logic to v2 trigger definitions.

**Step 4: Re-run tests**
- Expected: PASS.

**Step 5: Commit**
```bash
git add server/src/events/v2/catalog/holidays.ts server/src/events/v2/catalog/random.ts server/src/events/v2/catalog/family.ts server/tests/events-v2/catalog/passive-events.test.ts
git commit -m "feat(events-v2): migrate passive and scheduled event categories"
```

---

### Task 11: Remove Legacy Event Runtime Usage

**Files:**
- Modify: `server/src/stats/stats_manager.ts`
- Modify: `server/src/events/index.ts`
- Modify: `server/src/game/engine/EventRegistry.ts`
- Modify: `server/src/models/Player.ts`
- Create: `server/tests/events-v2/legacy-removal.guard.test.ts`

**Step 1: Write failing guard test**
- Assert runtime no longer calls:
  - `checkDilemmas`
  - legacy `allEvents` dispatch for interactive events
  - `activeDilemmas` path

**Step 2: Run guard test**
- Run: `cd server && npm test -- tests/events-v2/legacy-removal.guard.test.ts`
- Expected: FAIL.

**Step 3: Remove legacy pathways**
- Delete or disable legacy hooks from active loop.
- Keep only v2 catalog selection path.

**Step 4: Re-run tests**
- Expected: PASS.

**Step 5: Commit**
```bash
git add server/src/stats/stats_manager.ts server/src/events/index.ts server/src/game/engine/EventRegistry.ts server/src/models/Player.ts server/tests/events-v2/legacy-removal.guard.test.ts
git commit -m "refactor(events-v2): remove legacy event runtime paths"
```

---

## Sprint 4: iOS Frontend Migration

**Goal:** Move iOS to the v2 event protocol and deterministic response flow.

**Demo/Validation:**
- iOS decodes v2 prompt/resolution envelopes.
- iOS sends `{eventId, choiceId}` responses only.
- Event modal and queue behavior remain stable.

### Task 12: Add iOS v2 Event Models and Decoders

**Files:**
- Create: `ios/lichunWebsocket/Core/Models/EventV2.swift`
- Modify: `ios/lichunWebsocket/WebSocketService.swift`
- Create: `ios/lichunWebsocketTests/EventV2DecodingTests.swift`

**Step 1: Write failing decode tests**
- Test decoding `event_prompt`, `event_resolved`, `event_error` payloads.

**Step 2: Run iOS unit tests**
- Run: `cd ios && xcodebuild test -project lichunWebsocket.xcodeproj -scheme lichunWebsocket -destination 'platform=iOS Simulator,name=iPhone 15'`
- Expected: FAIL in new tests.

**Step 3: Implement models and parser routing**
- Add Codable models.
- Route v2 event envelope parsing in `WebSocketService`.

**Step 4: Re-run tests**
- Expected: PASS.

**Step 5: Commit**
```bash
git add ios/lichunWebsocket/Core/Models/EventV2.swift ios/lichunWebsocket/WebSocketService.swift ios/lichunWebsocketTests/EventV2DecodingTests.swift
git commit -m "feat(ios): add v2 event models and websocket decoding"
```

---

### Task 13: Replace iOS Answer Flow with eventId + choiceId

**Files:**
- Modify: `ios/lichunWebsocket/Core/Models/Question.swift`
- Modify: `ios/lichunWebsocket/Features/Events/Views/EventModalView.swift`
- Modify: `ios/lichunWebsocket/WebSocketService.swift`
- Create: `ios/lichunWebsocketTests/EventV2ResponseTests.swift`

**Step 1: Write failing response payload tests**
- Assert outbound payload uses:
  - `type: "eventResponse"`
  - `message: { eventId, choiceId }`

**Step 2: Run tests**
- Expected: FAIL.

**Step 3: Implement UI + service response changes**
- Bind selection to `choiceId`.
- Ensure queue removal is by `eventId`, not stack last-item behavior.

**Step 4: Re-run tests**
- Expected: PASS.

**Step 5: Commit**
```bash
git add ios/lichunWebsocket/Core/Models/Question.swift ios/lichunWebsocket/Features/Events/Views/EventModalView.swift ios/lichunWebsocket/WebSocketService.swift ios/lichunWebsocketTests/EventV2ResponseTests.swift
git commit -m "refactor(ios): send eventResponse with eventId and choiceId"
```

---

### Task 14: iOS UI/UX Compatibility Pass for v2 Metadata

**Files:**
- Modify: `ios/lichunWebsocket/Features/Home/Components/LifeEventCard.swift`
- Modify: `ios/lichunWebsocket/Core/Models/MessageEvent.swift`
- Create: `ios/lichunWebsocketTests/EventV2RenderingTests.swift`

**Step 1: Write failing rendering tests**
- Verify resolved events and optional metadata render safely.

**Step 2: Run tests**
- Expected: FAIL.

**Step 3: Implement rendering updates**
- Support v2 category/status fields.
- Ensure no crash on missing optional image/characters.

**Step 4: Re-run tests/build**
- Run build: `cd ios && xcodebuild -project lichunWebsocket.xcodeproj -scheme lichunWebsocket -configuration Debug build`
- Expected: SUCCESS.

**Step 5: Commit**
```bash
git add ios/lichunWebsocket/Features/Home/Components/LifeEventCard.swift ios/lichunWebsocket/Core/Models/MessageEvent.swift ios/lichunWebsocketTests/EventV2RenderingTests.swift
git commit -m "feat(ios): update event rendering for v2 payloads"
```

---

## Sprint 5: Android Frontend Migration

**Goal:** Move Android to the same v2 event protocol and response shape.

**Demo/Validation:**
- Android decodes v2 envelopes.
- Android sends `{eventId, choiceId}` response payload.
- Modal flow works with v2 metadata.

### Task 15: Add Android v2 Event Models and WebSocket Parsing

**Files:**
- Create: `android/app/src/main/java/com/craigvg/lichun_android/domain/models/EventV2.kt`
- Modify: `android/app/src/main/java/com/craigvg/lichun_android/network/WebSocketManager.kt`
- Create: `android/app/src/test/java/com/craigvg/lichun_android/network/EventV2ParsingTest.kt`

**Step 1: Write failing parsing tests**
- Decode v2 prompt/resolution envelopes.

**Step 2: Run android unit tests**
- Run: `cd android && ./gradlew test`
- Expected: FAIL.

**Step 3: Implement parser and state updates**
- Add model mapping and queue handling for v2 prompts.

**Step 4: Re-run tests**
- Expected: PASS.

**Step 5: Commit**
```bash
git add android/app/src/main/java/com/craigvg/lichun_android/domain/models/EventV2.kt android/app/src/main/java/com/craigvg/lichun_android/network/WebSocketManager.kt android/app/src/test/java/com/craigvg/lichun_android/network/EventV2ParsingTest.kt
git commit -m "feat(android): add v2 event models and websocket parsing"
```

---

### Task 16: Replace Android Answer Flow with eventId + choiceId

**Files:**
- Modify: `android/app/src/main/java/com/craigvg/lichun_android/domain/models/Question.kt`
- Modify: `android/app/src/main/java/com/craigvg/lichun_android/ui/screens/events/EventModal.kt`
- Modify: `android/app/src/main/java/com/craigvg/lichun_android/network/WebSocketManager.kt`
- Create: `android/app/src/test/java/com/craigvg/lichun_android/network/EventV2ResponsePayloadTest.kt`

**Step 1: Write failing response payload tests**
- Assert outbound message shape equals backend v2 contract.

**Step 2: Run tests**
- Run: `cd android && ./gradlew test`
- Expected: FAIL.

**Step 3: Implement response updates**
- Bind selection to `choiceId` and send `eventResponse` command.

**Step 4: Re-run tests**
- Expected: PASS.

**Step 5: Commit**
```bash
git add android/app/src/main/java/com/craigvg/lichun_android/domain/models/Question.kt android/app/src/main/java/com/craigvg/lichun_android/ui/screens/events/EventModal.kt android/app/src/main/java/com/craigvg/lichun_android/network/WebSocketManager.kt android/app/src/test/java/com/craigvg/lichun_android/network/EventV2ResponsePayloadTest.kt
git commit -m "refactor(android): send eventResponse with eventId and choiceId"
```

---

### Task 17: Android UI Rendering Compatibility Pass

**Files:**
- Modify: `android/app/src/main/java/com/craigvg/lichun_android/domain/models/MessageEvent.kt`
- Modify: `android/app/src/main/java/com/craigvg/lichun_android/ui/components/ModalOverlayHost.kt`
- Create: `android/app/src/test/java/com/craigvg/lichun_android/ui/EventV2RenderTest.kt`

**Step 1: Write failing render tests**
- Validate rendering with v2 metadata and optional fields.

**Step 2: Run tests**
- Expected: FAIL.

**Step 3: Implement rendering updates**
- Parse and display v2 resolution info in feed/modals.

**Step 4: Re-run tests and lint**
- Run: `cd android && ./gradlew test lint`
- Expected: SUCCESS.

**Step 5: Commit**
```bash
git add android/app/src/main/java/com/craigvg/lichun_android/domain/models/MessageEvent.kt android/app/src/main/java/com/craigvg/lichun_android/ui/components/ModalOverlayHost.kt android/app/src/test/java/com/craigvg/lichun_android/ui/EventV2RenderTest.kt
git commit -m "feat(android): update event rendering for v2 payloads"
```

---

## Sprint 6: Final Cutover and Cleanup

**Goal:** Remove dead code, old payload handlers, and obsolete player state.

**Demo/Validation:**
- No legacy event dispatch path used in runtime.
- Full backend test suite passes.
- iOS and Android build and tests pass.

### Task 18: Delete Legacy Event Paths and Dead Data Fields

**Files:**
- Modify: `server/src/handlers/events.ts`
- Modify: `server/src/events/base.ts`
- Modify: `server/src/stats/stats_manager.ts`
- Modify: `server/src/models/Player.ts`
- Modify: `server/src/testing/AutoResponder.ts`
- Create: `server/tests/events-v2/no-legacy-runtime.test.ts`

**Step 1: Write failing guard tests**
- Assert no references in active runtime to:
  - `activeDilemmas`
  - `checkDilemmas`
  - legacy answer text matching.

**Step 2: Run tests**
- Expected: FAIL.

**Step 3: Remove legacy code paths**
- Keep only v2 engine + response handling.

**Step 4: Re-run server tests**
- Run: `cd server && npm test`
- Expected: SUCCESS.

**Step 5: Commit**
```bash
git add server/src/handlers/events.ts server/src/events/base.ts server/src/stats/stats_manager.ts server/src/models/Player.ts server/src/testing/AutoResponder.ts server/tests/events-v2/no-legacy-runtime.test.ts
git commit -m "chore(events-v2): remove legacy event runtime and state"
```

---

### Task 19: Update Documentation and Developer Runbooks

**Files:**
- Modify: `docs/TESTING.md`
- Create: `docs/EVENT_SYSTEM_V2.md`
- Modify: `AGENTS.md`

**Step 1: Write docs coverage checklist test (manual checklist file)**
- Create checklist in `docs/EVENT_SYSTEM_V2.md` with required sections.

**Step 2: Update docs with v2 protocol and migration notes**
- Include command examples for response payload and test suites.

**Step 3: Validate documentation commands**
- Run all listed commands once:
  - `cd server && npm test`
  - `cd ios && xcodebuild -project lichunWebsocket.xcodeproj -scheme lichunWebsocket -configuration Debug build`
  - `cd android && ./gradlew test lint`

**Step 4: Commit**
```bash
git add docs/TESTING.md docs/EVENT_SYSTEM_V2.md AGENTS.md
git commit -m "docs(events-v2): update runbooks and protocol documentation"
```

---

## End-to-End Verification Matrix

### Backend
- `cd server && npm run build`
- `cd server && npm test`
- `cd server && npm run test:coverage`

### iOS
- `cd ios && xcodebuild -project lichunWebsocket.xcodeproj -scheme lichunWebsocket -configuration Debug build`
- `cd ios && xcodebuild test -project lichunWebsocket.xcodeproj -scheme lichunWebsocket -destination 'platform=iOS Simulator,name=iPhone 15'`

### Android
- `cd android && ./gradlew assembleDebug`
- `cd android && ./gradlew test`
- `cd android && ./gradlew lint`

### Cross-Platform Scenario Tests
1. Create player and trigger a deterministic dilemma prompt.
2. Answer from iOS with `choiceId`; verify server instance resolved and reflected in player state.
3. Repeat same scenario from Android.
4. Confirm no `activeDilemmas` mutations occur.
5. Confirm event history entries are identical in semantic outcome across platforms.

---

## Risks and Gotchas

1. **Catalog migration drift:** legacy content semantics can change during porting.
   - Mitigation: characterization tests + explicit acceptance snapshots per migrated category.
2. **Hidden collision after modularization:** duplicate IDs can reappear as files move.
   - Mitigation: startup collision guard + CI test.
3. **Protocol mismatch on one client:** one platform sends stale payload format.
   - Mitigation: strict server schema parse + platform unit tests for outbound payload.
4. **Runtime deadlocks in paused state:** improper game speed reset after response.
   - Mitigation: integration tests around prompt/answer/resume lifecycle.
5. **Data reset assumptions:** destructive rewrite can break local fixtures.
   - Mitigation: add a dev reset script and document mandatory reset before QA pass.

---

## Rollback Plan (Development)

Because this is a destructive rewrite in a non-production app:

1. Keep all Tier 3 work isolated on a long-lived branch.
2. If blocked, reset branch to last green commit before Sprint 3 content migration.
3. Re-run baseline characterization tests from Task 1 before resuming.

---

## Suggested Branch Strategy

- `codex/events-v2-foundation`
- `codex/events-v2-runtime`
- `codex/events-v2-content`
- `codex/events-v2-ios`
- `codex/events-v2-android`
- `codex/events-v2-cleanup`

Merge in sprint order only after each sprint’s verification matrix is green.

---

## Definition of Done

- v2 event engine is the only active event runtime.
- All migrated event content is served from v2 catalog definitions.
- iOS and Android consume/emit v2 protocol only.
- No references to `activeDilemmas` in active runtime path.
- Full backend + iOS + Android verification matrix passes.
- Updated docs are committed and accurate.
