Files
eagle0/docs/eliminate-battalion-backstory-updates.md
94b5d95dd3 Stage 1: Stop displaying battalion backstories in client (#6001)
Disable the battalion backstory popup that appears on hover in the
Heroes & Battalions panel. This is the first stage of eliminating
battalion backstory LLM updates to reduce request volume.

The popup panel is now always hidden when hovering over battalions.
Hero backstories are unaffected.

See docs/eliminate-battalion-backstory-updates.md for the full plan.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 21:40:20 -08:00

7.5 KiB

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

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
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

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:

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.