# Phase 4: AI Integration + Story Progression + Quest System
## Implementation Plan

> **Note:** This document contains detailed implementation tasks for developers building the API backend.
> For high-level project roadmap and progress tracking, see [/docs/ROADMAP.md](../../docs/ROADMAP.md).

**Document Version:** 1.2
**Created:** November 16, 2025
**Last Updated:** November 23, 2025
**Status:** In Progress
**Duration:** 3 weeks (21 days)
**Total Tasks:** 45 tasks
**Completed Tasks:** 22/45 (49%)

---

### Next Tasks
- Task 8.29: Create story gameplay template with HTMX

---

## Overview

Phase 4 delivers the core single-player gameplay experience for Code of Conquest. This phase integrates AI narrative generation via Replicate (Llama-3 and Claude models), implements turn-based story progression with button-based actions, and creates a context-aware quest system.

> **Architecture Note:** All AI models (Llama-3, Claude Haiku/Sonnet/Opus) are accessed through the Replicate API for unified billing and management.

**Key Deliverables:**
- AI narrative generation with tier-based model selection
- Turn-based story progression system
- YAML-driven quest system with context-aware offering
- Cost tracking and usage limits
- Complete solo gameplay loop

**Development Approach:**
- Tasks are moderately granular (4 hours each)
- Testing bundled into implementation tasks
- Verification checkpoints after major features
- YAML data created inline with features

---

## Week 8: Story Progression System (Days 8-14)

**Goal:** Implement turn-based story progression with button-based actions

### Task Group 8: Story UI & Integration (Tasks 29-31)

#### Task 8.29: Create story gameplay template with HTMX
**Duration:** 5 hours
**File:** `templates/game/story.html`

**Implementation:**
- Create main story gameplay page layout:
  - Header: Character info, turn count, location
  - Left sidebar: Quest tracker (placeholder for Week 9)
  - Main area: Latest DM response
  - Action panel: Available action buttons
  - Footer: Custom input (if Premium/Elite)
  - Right sidebar: Conversation history (collapsible)
- Add HTMX for dynamic updates:
  - Action buttons trigger `hx-post="/api/v1/sessions/{id}/action"`
  - Poll job status with `hx-trigger="every 2s"`
  - Update content when job completes
- Add loading spinner during AI processing
- Style with dark fantasy theme (match existing CSS)
- Add responsive design (mobile-friendly)
- Write Flask route to render template
- Test UI rendering

**Dependencies:** Tasks 8.25-8.28 (API endpoints)
**Deliverable:** Story gameplay UI template

**Key HTMX Patterns:**
```html
<!-- Action button -->
<button
  hx-post="/api/v1/sessions/{{ session_id }}/action"
  hx-vals='{"action_type": "button", "prompt_id": "ask_locals"}'
  hx-target="#dm-response"
  hx-swap="innerHTML"
  hx-indicator="#loading">
  Ask locals for information
</button>

<!-- Job status polling -->
<div
  hx-get="/api/v1/jobs/{{ job_id }}/status"
  hx-trigger="every 2s"
  hx-swap="outerHTML">
  Processing...
</div>
```

---

#### Task 8.30: Build action button UI with tier filtering
**Duration:** 4 hours
**File:** `templates/game/story.html` (extend), `app/routes/game.py`

**Implementation:**
- Create Jinja2 macro for rendering action buttons
- Filter actions based on user tier (passed from backend)
- Show locked actions with upgrade prompt for higher tiers
- Add tooltips with action descriptions
- Implement custom text input area:
  - Only visible for Premium/Elite
  - Character counter (250 for Premium, 500 for Elite)
  - Submit button with validation
- Add HTMX for seamless submission
- Style buttons with RPG aesthetic (icons optional)
- Disable buttons during AI processing
- Write Flask route to provide available actions

**Dependencies:** Task 8.29 (Story template)
**Deliverable:** Dynamic action button system

**Jinja2 Macro:**
```jinja
{% macro render_action(action, user_tier, locked=False) %}
<button
  class="action-btn {% if locked %}locked{% endif %}"
  {% if not locked %}
  hx-post="/api/v1/sessions/{{ session_id }}/action"
  hx-vals='{"action_type": "button", "prompt_id": "{{ action.prompt_id }}"}'
  {% else %}
  disabled
  {% endif %}
  title="{{ action.description }}">
  {{ action.display_text }}
  {% if locked %}<span class="lock-icon">🔒</span>{% endif %}
</button>
{% endmacro %}
```

---

#### Task 8.31: ✅ CHECKPOINT - Full story turn integration test
**Duration:** 4 hours

**Verification Steps:**
1. Create a new session via UI
2. Click an action button
3. Verify loading state appears
4. Wait for AI response
5. Verify DM response displayed
6. Check conversation history updated
7. Verify turn number incremented
8. Test with different action buttons
9. Test custom text input (Premium tier)
10. Verify tier restrictions enforced (Free can't use Premium actions)
11. Test rate limiting
12. Verify Realtime updates work

**Success Criteria:**
- Full story turn loop works end-to-end
- UI updates smoothly with HTMX
- AI responses are coherent and relevant
- Tier filtering works correctly
- Rate limits enforced
- No errors in browser console or server logs

---

## Week 9: Quest System (Days 15-21)

**Goal:** Implement YAML-driven quest system with context-aware offering

### Task Group 9: Quest Data Models (Tasks 32-34)

#### Task 9.32: Create Quest dataclasses
**Duration:** 5 hours
**File:** `app/models/quest.py`

**Implementation:**
- Create `QuestObjective` dataclass:
  - `objective_id`, `description`, `objective_type` (enum)
  - `required_progress`, `current_progress`, `completed`
- Create `QuestReward` dataclass:
  - `gold`, `experience`, `items` (List[Item])
  - `reputation` (optional, for future use)
- Create `Quest` dataclass:
  - `quest_id`, `name`, `description`, `quest_giver`
  - `difficulty` (enum: EASY, MEDIUM, HARD, EPIC)
  - `objectives` (List[QuestObjective])
  - `rewards` (QuestReward)
  - `offering_triggers` (QuestTriggers)
  - `narrative_hooks` (List[str])
  - `status` (enum: AVAILABLE, ACTIVE, COMPLETED, FAILED)
- Implement methods:
  - `is_complete()` - Check if all objectives done
  - `get_next_objective()` - Get first incomplete objective
  - `update_progress(objective_id, amount)` - Increment progress
- Add to_dict() / from_dict() serialization
- Write unit tests for all methods

**Dependencies:** None
**Deliverable:** Quest data models

**Example:**
```python
quest = Quest(
    quest_id="quest_goblin_cave",
    name="Clear the Goblin Cave",
    description="A nearby cave is infested with goblins...",
    quest_giver="Village Elder",
    difficulty=QuestDifficulty.EASY,
    objectives=[
        QuestObjective(
            objective_id="kill_goblins",
            description="Defeat 5 goblins",
            objective_type=ObjectiveType.KILL,
            required_progress=5,
            current_progress=0
        )
    ],
    rewards=QuestReward(gold=50, experience=100, items=[])
)

quest.update_progress("kill_goblins", 1)
quest.is_complete()  # False (4 more goblins needed)
```

---

#### Task 9.33: Create QuestTriggers with offering logic
**Duration:** 4 hours
**File:** `app/models/quest.py` (extend)

**Implementation:**
- Create `QuestTriggers` dataclass:
  - `location_types` (List[LocationType]) - Where quest can be offered
  - `specific_locations` (List[str]) - Optional specific location names
  - `min_character_level`, `max_character_level` (int)
  - `required_quests_completed` (List[str]) - Quest prerequisites
  - `probability_weights` (Dict[LocationType, float]) - Offer chance by location
- Implement methods:
  - `can_offer(character_level, completed_quests)` - Check eligibility
  - `get_offer_probability(location_type)` - Get chance for location
- Add validation (probabilities 0.0-1.0)
- Write unit tests for offering logic
- Document trigger system in docstrings

**Dependencies:** Task 9.32 (Quest model)
**Deliverable:** Quest offering trigger system

**Example:**
```python
triggers = QuestTriggers(
    location_types=[LocationType.TOWN, LocationType.TAVERN],
    min_character_level=1,
    max_character_level=5,
    probability_weights={
        LocationType.TOWN: 0.30,
        LocationType.TAVERN: 0.35
    }
)

triggers.can_offer(character_level=3, completed_quests=[])  # True
triggers.get_offer_probability(LocationType.TAVERN)  # 0.35 (35% chance)
```

---

#### Task 9.34: ✅ CHECKPOINT - Verify quest model serialization
**Duration:** 2 hours

**Verification Steps:**
1. Create sample quest with all fields
2. Convert to dict with to_dict()
3. Serialize to JSON
4. Deserialize from JSON
5. Recreate quest with from_dict()
6. Verify all fields match original
7. Test quest methods (is_complete, update_progress)
8. Test trigger methods (can_offer, get_offer_probability)
9. Test edge cases (invalid progress, level requirements)

**Success Criteria:**
- Quest serialization round-trips correctly
- All methods work as expected
- Offering logic accurate
- No data loss during serialization

---

### Task Group 10: Quest Content & Loading (Tasks 35-38)

#### Task 9.35: Create quest YAML schema
**Duration:** 3 hours
**File:** `app/data/quests/schema.yaml` (documentation), update `docs/QUEST_SYSTEM.md`

**Implementation:**
- Document YAML structure for quests
- Define all required and optional fields
- Provide examples for each objective type
- Document narrative_hooks usage
- Create template quest file
- Add validation rules
- Update QUEST_SYSTEM.md with schema details

**Dependencies:** Task 9.32 (Quest models)
**Deliverable:** Quest YAML schema documentation

**Schema Example:**
```yaml
quest_id: quest_goblin_cave
name: Clear the Goblin Cave
description: |
  A nearby cave has been overrun by goblins who are raiding nearby farms.
  The village elder asks you to clear them out.
quest_giver: Village Elder
difficulty: EASY

objectives:
  - objective_id: kill_goblins
    description: Defeat 5 goblins
    objective_type: KILL
    required_progress: 5

rewards:
  gold: 50
  experience: 100
  items: []

offering_triggers:
  location_types: [TOWN, TAVERN]
  min_character_level: 1
  max_character_level: 5
  probability_weights:
    TOWN: 0.30
    TAVERN: 0.35

narrative_hooks:
  - "The village elder looks worried about recent goblin attacks"
  - "You hear farmers complaining about lost livestock"
  - "A town guard mentions a cave to the north"
```

---

#### Task 9.36: Write 10 example quests
**Duration:** 5 hours
**Files:** `app/data/quests/easy/*.yaml`, `app/data/quests/medium/*.yaml`, etc.

**Implementation:**
- Create quest files organized by difficulty:
  - **Easy (4 quests):** Levels 1-3, simple objectives
    1. Clear Goblin Cave (kill 5 goblins)
    2. Gather Healing Herbs (collect 10 herbs)
    3. Deliver Message to Town (travel to location)
    4. Find Lost Cat (discover location)
  - **Medium (3 quests):** Levels 3-7, multi-objective
    5. Investigate Bandit Camp (kill + collect + discover)
    6. Rescue Kidnapped Villager (travel + interact)
    7. Ancient Artifact Recovery (discover + collect)
  - **Hard (2 quests):** Levels 7-10, complex chains
    8. Stop the Necromancer (multi-step with prerequisites)
    9. Dragon's Hoard (discover + kill boss + collect)
  - **Epic (1 quest):** Level 10+, multi-chapter
    10. The Demon Lord's Return (epic multi-objective chain)
- Include rich narrative_hooks for each quest
- Vary reward amounts by difficulty
- Add location variety
- Ensure proper level gating

**Dependencies:** Task 9.35 (YAML schema)
**Deliverable:** 10 complete quest YAML files

---

#### Task 9.37: Implement QuestService with YAML loader
**Duration:** 5 hours
**File:** `app/services/quest_service.py`

**Implementation:**
- Create `QuestService` class
- Implement `load_quests_from_yaml(directory)` method
- Parse all YAML files in quest directory
- Convert to Quest objects
- Validate quest structure and fields
- Cache loaded quests in memory
- Implement methods:
  - `get_quest_by_id(quest_id)`
  - `get_eligible_quests(character_level, location_type, completed_quests)`
  - `filter_by_difficulty(difficulty)`
  - `get_all_quests()`
- Add error handling for malformed YAML
- Write unit tests with sample quests
- Add logging for quest loading

**Dependencies:** Task 9.36 (Quest YAML files)
**Deliverable:** Quest loading and filtering service

**Usage:**
```python
service = QuestService()
service.load_quests_from_yaml("app/data/quests/")

# Get eligible quests
eligible = service.get_eligible_quests(
    character_level=3,
    location_type=LocationType.TAVERN,
    completed_quests=[]
)
# Returns: [Quest(...), Quest(...)]
```

---

#### Task 9.38: ✅ CHECKPOINT - Verify quest loading and validation
**Duration:** 2 hours

**Verification Steps:**
1. Load all 10 quests from YAML files
2. Verify all quests parsed correctly
3. Check quest filtering by level works
4. Test filtering by location type
5. Verify offering probability calculations
6. Test get_eligible_quests() with various inputs
7. Verify error handling for invalid YAML
8. Check quest caching works

**Success Criteria:**
- All 10 quests load without errors
- Filtering logic accurate
- Offering probabilities correct
- No performance issues loading quests
- Error handling graceful

---

### Task Group 11: Quest Offering & Management (Tasks 39-42)

#### Task 9.39: Implement context-aware quest offering logic
**Duration:** 5 hours
**File:** `app/services/quest_offering_service.py`

**Implementation:**
- Create `QuestOfferingService` class
- Implement two-stage offering:
  1. **Location probability roll:**
     - Get location type probability from triggers
     - Roll random 0.0-1.0, check if < probability
     - If fail, no quest offered
  2. **Context-aware AI selection:**
     - Get eligible quests from QuestService
     - Build AI prompt with narrative_hooks
     - Ask AI to select most contextually relevant quest
     - Parse AI response to get selected quest_id
- Implement `should_offer_quest(location_type)` method (probability roll)
- Implement `select_quest_for_context(eligible_quests, game_context)` method (AI selection)
- Implement main `offer_quest(session_id)` method (full flow)
- Add validation (max 2 active quests)
- Write integration tests with mocked AI
- Add logging for quest offerings

**Dependencies:** Tasks 7.10 (NarrativeGenerator), 9.37 (QuestService)
**Deliverable:** Context-aware quest offering system

**Flow:**
```python
offering_service = QuestOfferingService()

# Called after each story turn
if offering_service.should_offer_quest(LocationType.TAVERN):
    eligible = quest_service.get_eligible_quests(...)
    selected_quest = offering_service.select_quest_for_context(
        eligible_quests=eligible,
        game_context={
            "location": "The Rusty Anchor",
            "recent_actions": ["talked to locals", "rested"],
            "active_quests": []
        }
    )
    # Returns: Quest object or None
```

---

#### Task 9.40: Integrate quest offering into story turns
**Duration:** 4 hours
**File:** `app/tasks/ai_tasks.py` (extend generate_dm_response job)

**Implementation:**
- Update `generate_dm_response()` RQ job
- After AI narrative generated and before saving:
  1. Check if quest should be offered (probability roll)
  2. If yes, get eligible quests
  3. Call AI to select contextually relevant quest
  4. Add quest offering to response data
  5. Store offered quest in session state (pending acceptance)
- Add quest offering to conversation entry:
  ```python
  {
    "turn": 5,
    "action": "...",
    "dm_response": "...",
    "quest_offered": {
      "quest_id": "quest_goblin_cave",
      "quest_name": "Clear the Goblin Cave"
    }
  }
  ```
- Update API response format to include quest offering
- Write integration tests for offering flow
- Add logging for quest offerings

**Dependencies:** Task 9.39 (Quest offering logic)
**Deliverable:** Integrated quest offering in story turns

**Updated Response:**
```json
{
  "status": 200,
  "result": {
    "dm_response": "As you chat with the locals...",
    "quest_offered": {
      "quest_id": "quest_goblin_cave",
      "name": "Clear the Goblin Cave",
      "description": "...",
      "rewards": {"gold": 50, "experience": 100}
    }
  }
}
```

---

#### Task 9.41: Implement quest accept endpoint
**Duration:** 4 hours
**File:** `app/routes/quests.py` (new file)

**Implementation:**
- Create `POST /api/v1/quests/accept` endpoint
- Validate request body:
  ```json
  {
    "session_id": "sess_789",
    "quest_id": "quest_goblin_cave"
  }
  ```
- Validate quest is currently offered to session
- Check max 2 active quests limit
- Add quest to session's active_quests
- Initialize quest with status ACTIVE
- Store quest state in character (or session)
- Return accepted quest details
- Add @require_auth decorator
- Write integration tests
- Document in API_REFERENCE.md

**Dependencies:** Task 9.39 (Quest offering)
**Deliverable:** Quest acceptance endpoint

**Response:**
```json
{
  "status": 200,
  "result": {
    "quest_id": "quest_goblin_cave",
    "status": "ACTIVE",
    "objectives": [
      {
        "objective_id": "kill_goblins",
        "description": "Defeat 5 goblins",
        "progress": "0/5"
      }
    ]
  }
}
```

---

#### Task 9.42: Implement quest complete endpoint with rewards
**Duration:** 5 hours
**File:** `app/routes/quests.py` (extend)

**Implementation:**
- Create `POST /api/v1/quests/complete` endpoint
- Validate request body:
  ```json
  {
    "session_id": "sess_789",
    "quest_id": "quest_goblin_cave"
  }
  ```
- Verify quest is active for session
- Check all objectives completed
- Grant rewards:
  - Add gold to character
  - Add experience to character
  - Add items to inventory
  - Check for level up
- Update quest status to COMPLETED
- Remove from active_quests
- Add to completed_quests list
- Return completion details with level up info
- Add @require_auth decorator
- Write integration tests
- Document in API_REFERENCE.md

**Dependencies:** Task 9.41 (Quest accept)
**Deliverable:** Quest completion and reward system

**Response:**
```json
{
  "status": 200,
  "result": {
    "quest_id": "quest_goblin_cave",
    "status": "COMPLETED",
    "rewards_granted": {
      "gold": 50,
      "experience": 100,
      "items": []
    },
    "level_up": {
      "leveled_up": true,
      "new_level": 4,
      "skill_points_gained": 1
    }
  }
}
```

---

### Task Group 12: Quest UI & Final Testing (Tasks 43-45)

#### Task 9.43: Create quest tracker sidebar UI
**Duration:** 4 hours
**File:** `templates/game/story.html` (extend left sidebar)

**Implementation:**
- Add quest tracker to left sidebar
- Display active quests (max 2)
- Show quest name and description
- Display objective progress (X/Y format)
- Add "View Details" button for each quest
- Style with RPG theme
- Add HTMX for dynamic updates when objectives progress
- Show "No active quests" message when empty
- Add quest complete notification (toast/modal)
- Test UI rendering

**Dependencies:** Tasks 9.41-9.42 (Quest endpoints)
**Deliverable:** Quest tracker sidebar UI

**UI Structure:**
```html
<div class="quest-tracker">
  <h3>Active Quests ({{ active_quests|length }}/2)</h3>
  {% for quest in active_quests %}
  <div class="quest-card">
    <h4>{{ quest.name }}</h4>
    <div class="objectives">
      {% for obj in quest.objectives %}
      <div class="objective {% if obj.completed %}completed{% endif %}">
        {{ obj.description }}: {{ obj.current_progress }}/{{ obj.required_progress }}
      </div>
      {% endfor %}
    </div>
    <button hx-get="/quests/{{ quest.quest_id }}/details">View Details</button>
  </div>
  {% endfor %}
</div>
```

---

#### Task 9.44: Create quest offering modal UI
**Duration:** 4 hours
**File:** `templates/game/partials/quest_offer_modal.html`

**Implementation:**
- Create modal component for quest offering
- Display when quest offered in DM response
- Show quest name, description, quest giver
- Display objectives and rewards clearly
- Add "Accept Quest" button (HTMX post to /api/v1/quests/accept)
- Add "Decline" button (closes modal)
- Style modal with RPG theme (parchment background)
- Add HTMX to update quest tracker when accepted
- Show error if max quests reached (2/2)
- Test modal behavior

**Dependencies:** Task 9.41 (Quest accept endpoint)
**Deliverable:** Quest offering modal UI

**Modal Structure:**
```html
<div class="modal quest-offer-modal">
  <div class="modal-content parchment">
    <h2>{{ quest.quest_giver }} offers you a quest!</h2>
    <h3>{{ quest.name }}</h3>
    <p>{{ quest.description }}</p>

    <div class="objectives">
      <h4>Objectives:</h4>
      <ul>
        {% for obj in quest.objectives %}
        <li>{{ obj.description }}</li>
        {% endfor %}
      </ul>
    </div>

    <div class="rewards">
      <h4>Rewards:</h4>
      <p>Gold: {{ quest.rewards.gold }} | XP: {{ quest.rewards.experience }}</p>
    </div>

    <div class="actions">
      <button
        hx-post="/api/v1/quests/accept"
        hx-vals='{"session_id": "{{ session_id }}", "quest_id": "{{ quest.quest_id }}"}'
        hx-target="#quest-tracker"
        class="btn-accept">Accept Quest</button>
      <button class="btn-decline" onclick="closeModal()">Decline</button>
    </div>
  </div>
</div>
```

---

#### Task 9.45: ✅ FINAL CHECKPOINT - Full quest integration test
**Duration:** 4 hours

**Comprehensive Test Flow:**

**Setup:**
1. Create new character (level 1)
2. Create solo session
3. Verify starting state

**Quest Offering:**
4. Take multiple story actions in a town/tavern
5. Wait for quest offering (may take several turns)
6. Verify quest modal appears
7. Check quest details display correctly
8. Accept quest
9. Verify quest appears in tracker (1/2 active)

**Quest Progress:**
10. Simulate quest progress (update objective manually via API or through combat)
11. Verify tracker updates in real-time
12. Complete all objectives
13. Verify completion indicator

**Quest Completion:**
14. Call complete quest endpoint
15. Verify rewards granted (gold, XP)
16. Check for level up if applicable
17. Verify quest removed from active list
18. Verify quest in completed list

**Edge Cases:**
19. Try accepting 3rd quest (should fail with max 2 message)
20. Try completing incomplete quest (should fail)
21. Test with ineligible quest (wrong level)
22. Verify offering probabilities work (multiple sessions)

**Success Criteria:**
- Full quest lifecycle works end-to-end
- Quest offering feels natural in story flow
- UI updates smoothly with HTMX
- Rewards granted correctly
- Level up system works
- Max 2 quest limit enforced
- Error handling graceful
- No bugs in browser console or server logs

---

## Deferred Tasks

### Task 7.15: Set up cost monitoring and alerts
**Duration:** 3 hours
**Files:** `app/tasks/monitoring_tasks.py`, `app/services/alert_service.py`

**Implementation:**
- Create `calculate_daily_cost()` RQ job (runs daily at midnight)
- Aggregate all AI usage from previous day
- Calculate total cost by summing estimated costs
- Store daily cost in Redis timeseries
- Create `AlertService` class
- Implement alert triggers:
  - Daily cost > $50 → Warning email
  - Daily cost > $100 → Critical email
  - Monthly projection > $1500 → Warning email
- Add email sending via SMTP or service (e.g., SendGrid)
- Create admin dashboard endpoint: `GET /admin/costs`
- Write tests for cost calculation

**Dependencies:** Task 7.13 (Usage tracking)
**Deliverable:** Automated cost monitoring with alerts

**Daily Job:**
```python
# Runs at midnight UTC
@job('monitoring_tasks')
def calculate_daily_cost():
    yesterday = date.today() - timedelta(days=1)
    total_cost = sum_all_user_costs(yesterday)

    if total_cost > 100:
        send_alert(f"CRITICAL: Daily AI cost ${total_cost}")
    elif total_cost > 50:
        send_alert(f"WARNING: Daily AI cost ${total_cost}")

    store_cost_metric(yesterday, total_cost)
```

---

## Phase 4 Complete!

**Deliverables Summary:**

### Week 7: AI Engine Foundation ✅
- Redis/RQ infrastructure working
- AI clients for Replicate + Anthropic (Haiku/Sonnet/Opus)
- Model selection with tier-based routing
- Jinja2 prompt templates (4 types)
- Narrative generator wrapper
- Async AI task jobs with Appwrite integration
- Usage tracking and cost monitoring
- Daily limits per tier enforced

### Week 8: Story Progression System ✅
- 10 action prompts defined in YAML
- ActionPrompt loader with tier/context filtering
- Solo GameSession model with state tracking
- SessionService for CRUD operations
- Conversation history management
- 4 API endpoints (create, state, action, history)
- Story gameplay UI with HTMX
- Dynamic action buttons with tier filtering
- Full story turn loop working

### Week 9: Quest System ✅
- Quest data models (Quest, Objective, Reward, Triggers)
- 10 example quests in YAML (4 easy, 3 medium, 2 hard, 1 epic)
- QuestService with YAML loader
- Context-aware quest offering logic
- Quest offering integrated into story turns
- Quest accept/complete API endpoints
- Quest tracker sidebar UI
- Quest offering modal UI
- Full quest lifecycle tested

**Next Phase:** Phase 5 - Combat System + Skill Tree UI (Week 10-11)

---

## Dependencies Graph

```
Week 7 (AI Engine):
Task 7.1 (Redis) → 7.2 (RQ) → 7.3 (AI jobs) → 7.4 (✅ Verify)
Task 7.5 (Replicate+Claude) → 7.7 (Model selector) → 7.8 (✅ Verify)
                                        │
Task 7.9 (Templates) ───────────────────┘→ 7.10 (Narrative gen) → 7.11 (AI jobs) → 7.12 (✅ Verify)
                                                                       │
Task 7.13 (Usage track) → 7.14 (Rate limits) ────────────────────────┘
                       └→ 7.15 (Cost monitoring)

Note: Task 7.6 merged into 7.5 (all models via Replicate API)

Week 8 (Story Progression):
Task 8.16 (ActionPrompt) → 8.17 (YAML) → 8.18 (Loader) → 8.19 (✅ Verify)
                                                           │
Task 8.20 (GameSession) → 8.21 (SessionService) ──────────┤
                       └→ 8.22 (History) ──────────────────┤
                       └→ 8.23 (State tracking) → 8.24 (✅ Verify)
                                                  │
Task 8.25 (Create API) ───────────────────────────┤
Task 8.26 (Action API) ───────────────────────────┤
Task 8.27 (State API) ────────────────────────────┤
Task 8.28 (History API) ──────────────────────────┤
                                                  │
Task 8.29 (Story UI) → 8.30 (Action buttons) → 8.31 (✅ Integration test)

Week 9 (Quest System):
Task 9.32 (Quest models) → 9.33 (Triggers) → 9.34 (✅ Verify)
                                              │
Task 9.35 (YAML schema) → 9.36 (10 quests) → 9.37 (QuestService) → 9.38 (✅ Verify)
                                                                     │
Task 9.39 (Offering logic) ──────────────────────────────────────────┤
Task 9.40 (Story integration) → 9.41 (Accept API) → 9.42 (Complete API)
                                                     │
Task 9.43 (Tracker UI) ──────────────────────────────┤
Task 9.44 (Offer modal) ─────────────────────────────┤
                                                     │
Task 9.45 (✅ Final integration test)
```

---

## Notes

**Testing Strategy:**
- Unit tests bundled into each implementation task
- Integration tests at verification checkpoints
- Manual testing for UI/UX flows
- Use docs/API_TESTING.md for endpoint testing

**Cost Management:**
- Target: < $500/month total AI costs
- Free tier users cost $0 (Replicate)
- Monitor daily costs via Task 7.15
- Adjust tier limits if costs spike

**Development Tips:**
- Start each week by reviewing previous week's work
- Commit frequently with conventional commit messages
- Update API_REFERENCE.md as you build endpoints
- Test with real AI calls periodically (not just mocks)
- Keep YAML files well-documented and validated

**Estimated Timeline:**
- Week 7: ~40 hours (5 days at 8 hours/day)
- Week 8: ~44 hours (5.5 days at 8 hours/day)
- Week 9: ~42 hours (5.25 days at 8 hours/day)
- **Total: ~126 hours (~16 days of focused work)**

**Success Metrics:**
- All 45 tasks completed
- All verification checkpoints passed
- No critical bugs in core gameplay loop
- AI costs within budget (<$50/day during development)
- Story progression feels engaging and responsive
- Quest system feels natural and rewarding

---

**Document History:**
- v1.0 (2025-11-16): Initial Phase 4 implementation plan created
