# Plan: Eliminate Battalion Backstory LLM Updates

## Goal

Dramatically reduce LLM request volume by eliminating battalion backstory updates. Battalions will retain:
- An **initial backstory** (generated once when created)
- A **history of events** (structured data, not LLM-generated prose)

The history will be fed into other LLM updates (hero backstories, chronicle) but will no longer be regenerated into prose for each battalion.

## Current System Overview

### Data Flow
```
Battalion Created → Initial Backstory LLM Request → Text stored
                                    ↓
Battalion participates in events → Events accumulated → Update LLM Request → New text version
                                    ↓
BattalionView.backstoryTextId → Client displays on hover
```

### Event Types (8 total)
Events are structured data already captured in `EventForBattalionBackstory`:
- OrganizedTroops, SuppressedBeasts, ApprehendedOutlaws, FoughtInBattle
- SuppressedRiot, Trained, Armed, SurvivedStarvation

Each event has date, province, hero, and event-specific details.

### Key Files

| Component | File |
|-----------|------|
| Unity Display | `Assets/Eagle/HeroesAndBattalionsPanelController.cs` |
| View Proto | `views/battalion_view.proto` |
| View Filter | `BattalionViewFilter.scala` |
| Update Action | `BattalionBackstoryUpdateAction.scala` |
| Update Generator | `BattalionBackstoryUpdateActionGenerator.scala` |
| Update Prompt | `BattalionBackstoryUpdatePromptGenerator.scala` |
| Event-to-Text | `BattalionBackstoryUpdatePromptGenerator.textForEvent()` |
| BattalionDescriptions | `BattalionDescriptions.scala` (used in other LLM prompts) |

---

## Stage 1: Stop Displaying Battalion Backstories in Client

**Goal:** Remove the UI that shows battalion backstory text on hover.

### Files to Modify

**`Assets/Eagle/HeroesAndBattalionsPanelController.cs`**
- In `BattalionLongHoverRowChanged()` (lines 143-169):
  - Remove or comment out the backstory text population
  - Keep the header/name display, remove `battalionPopupPanelBackstory.TextId = ...`

**Unity Scene/Prefab**
- Hide or remove the `battalionPopupPanelBackstory` UI element

### Verification
- [ ] Battalion hover popup no longer shows backstory text
- [ ] No errors when hovering over battalions
- [ ] Other battalion info (name, type, size) still displays

---

## Stage 2: Stop Populating Backstory in BattalionView

**Goal:** Stop sending backstory text ID to the client.

### Files to Modify

**`BattalionViewFilter.scala`**
- In `filteredBattalionViewBelongingToPlayer()`:
  - Set `backstoryTextId = ""` instead of `battalion.backstoryTextId`
- In `limitedBattalionView()`:
  - Same change

### Verification
- [ ] BattalionView messages have empty backstoryTextId
- [ ] Client handles empty backstoryTextId gracefully (Stage 1 should have removed the display)

---

## Stage 3: Remove backstory_text_id from BattalionView Proto

**Goal:** Clean up the proto schema.

### Files to Modify

**`views/battalion_view.proto`**
- Remove field: `string backstory_text_id = 7;`
- Mark field 7 as reserved to prevent reuse

**`Assets/Eagle/HeroesAndBattalionsPanelController.cs`**
- Remove any remaining references to `BackstoryTextId`

**`BattalionViewFilter.scala`**
- Remove `backstoryTextId` from view construction

### Verification
- [ ] Proto compiles
- [ ] C# client compiles without BackstoryTextId references
- [ ] Full test suite passes

---

## Stage 4: Replace Backstory Usage in BattalionDescriptions

**Goal:** When other LLM prompts need battalion context, use initial backstory + structured history instead of the latest LLM-generated prose.

### Current Usage in `BattalionDescriptions.scala`

```scala
def backstoryText(): TextGenerationResult =
  battalion.backstoryVersions.lastOption
    .map(v => clientTextStore.getText(v.textId))
    .getOrElse(TextGenerationSuccess(""))

def fullDescription(): String =
  s"${battalion.name} is $description. $backstoryText"
```

### New Approach

Create `historyDescription()` that:
1. Gets initial backstory (first version's text, if available)
2. Appends structured event history using the same `textForEvent()` logic from `BattalionBackstoryUpdatePromptGenerator`

```scala
def historyDescription(): String = {
  val initialBackstory = battalion.backstoryVersions.headOption
    .map(v => clientTextStore.getText(v.textId))
    .collect { case TextGenerationSuccess(text) => text }
    .getOrElse("")

  val eventHistory = battalion.backstoryEvents
    .map(textForEvent)  // Reuse existing event-to-text conversion
    .mkString(" ")

  if eventHistory.isEmpty then initialBackstory
  else s"$initialBackstory $eventHistory"
}
```

### Files to Modify

**`BattalionDescriptions.scala`**
- Add `historyDescription()` method
- Update `fullDescription()` to use `historyDescription()` instead of `backstoryText()`
- Keep `textForEvent()` logic (move from `BattalionBackstoryUpdatePromptGenerator` if needed)

**Move/refactor `textForEvent()`**
- Currently in `BattalionBackstoryUpdatePromptGenerator.scala` (lines 78-262)
- Move to `BattalionDescriptions.scala` or a shared utility
- This converts events to human-readable text without LLM

### Verification
- [ ] Other LLM prompts that use `BattalionDescriptions` still get meaningful context
- [ ] Chronicle updates include battalion history
- [ ] Hero backstory updates include relevant battalion history

---

## Stage 5: Stop Generating Battalion Backstory Updates

**Goal:** Remove the LLM request generation entirely.

### Files to Modify

**`BattalionBackstoryUpdateActionGenerator.scala`**
- Return empty Vector instead of generating actions
- Or delete the file entirely

**`BattalionBackstoryUpdateAction.scala`**
- Delete or mark as deprecated

**`BattalionBackstoryUpdatePromptGenerator.scala`**
- Delete or keep only `textForEvent()` if moved

**`LlmResolver.scala`**
- Remove case for `BattalionBackstoryUpdateRequest`
- Optionally throw error if somehow called

**`EndPlayerCommandsPhaseAction.scala`** (and other callers)
- Find where `BattalionBackstoryUpdateActionGenerator` is called
- Remove those calls

### Files to Search for Callers
```bash
grep -r "BattalionBackstoryUpdateAction" src/
```

### Verification
- [ ] No `BattalionBackstoryUpdateRequest` LLM requests generated
- [ ] Battalions still accumulate events (for history description)
- [ ] Full test suite passes
- [ ] Game runs without errors

---

## Future Considerations

### Keep or Remove Initial Backstory Generation?
The initial backstory (`BattalionInitialBackstoryRequest`) is generated once per battalion. Options:
1. **Keep it** - Low volume, provides flavor text for history
2. **Remove it** - Use a template-based approach instead

Recommendation: Keep for now, evaluate later based on volume.

### Event History Cleanup
Events currently accumulate forever on battalions. Consider:
- Capping event history length
- Summarizing old events
- Only keeping "significant" events

### Affected Tests
Search for tests that verify backstory update behavior:
```bash
bazel query 'tests(//src/test/scala/...) intersect rdeps(//src/test/scala/..., //src/main/scala/net/eagle0/eagle/library/actions/impl/action:battalion_backstory_update_action)'
```

---

## Summary of LLM Request Reduction

| Request Type | Current Volume | After Change |
|--------------|---------------|--------------|
| BattalionInitialBackstoryRequest | 1 per battalion | 1 per battalion (unchanged) |
| BattalionBackstoryUpdateRequest | ~N per battalion per game | **0** |

For a typical game with ~50 battalions and ~20 rounds, this could eliminate **hundreds** of LLM requests.
