# Actions and Commands Model Usage Analysis This document analyzes all actions and commands in `src/main/scala/net/eagle0/eagle/library/actions/impl` to determine which use Scala models vs protobuf models, based on BUILD.bazel dependencies. **Legend:** - ✅ **Scala Models Only** - Uses only `//src/main/scala/net/eagle0/eagle/model` dependencies - ❌ **Uses Protobuf** - Has dependencies on `//src/main/protobuf` targets - 🔄 **Partial Conversion** - Conversion attempted but blocked by dependencies ## Summary Based on BUILD.bazel dependency analysis (2025-09-16, updated 2025-09-17): - **Total Commands Analyzed:** 41 - **Commands Fully Migrated (No Protobuf):** 41 (100%) ✅ - **Commands Still Using Protobuf:** 0 (0%) ✅ - **Total Actions Analyzed:** 48 - **Actions Fully Migrated (No Protobuf):** 5 (10.4%) - **Actions Partially Migrated:** 19 (39.6%) - **Actions Still Using Protobuf:** 24 (50%) - **Base Classes:** 8 protoless variants available, 6 still use protobuf - **Shared Components:** `ResolvedEagleUnit` migrated to use `Option[BattalionT]` for proper null handling ## Conversion Insights Based on conversion attempt of `ResolveTruceOfferCommand` (see [PR #4379](https://github.com/nolen777/eagle0/pull/4379)): ### Key Challenges Discovered 1. **LLM Integration Dependencies**: Commands that use `DiplomacyResolutionLlmRequestGenerator` face challenges because the LLM system still expects protobuf enum types, not Scala model enums. 2. **Inconsistent Package Naming**: Some files have inconsistent package declarations vs BUILD file locations (e.g., `generated_text_request_generators` in package vs `llm_request_generators` in BUILD). 3. **Model Constructor Differences**: Scala model constructors (e.g., `TruceOffer`) have different required parameters than their protobuf counterparts, requiring more complex data mapping. 4. **Type System Complexity**: Union types and type constraints become more complex when mixing protobuf and Scala model types during transition. 5. **Cascading Dependency Issues**: Converting to `ActionResultC` requires extensive trait dependencies (`ChangedBattalionT`, `ChangedHeroT`, `GeneratedTextRequestT`, etc.) that create complex BUILD dependency graphs, unlike simple protobuf `ActionResult`. 6. **BUILD Complexity**: Each Scala model conversion requires significantly more BUILD dependencies than protobuf equivalents, making incremental conversion difficult. 7. **Build Verification Critical**: Any conversion must maintain working build state - even simple commands like `DefendCommand` can break main server build due to dependency cascades. ### Successful Conversion Elements - ✅ Base class conversion (`SimpleAction` → `ProtolessSimpleAction`) - ✅ Import updates for most Scala model types - ✅ BUILD.bazel dependency updates for core action result types - ✅ Basic type conversions for simple cases ### Recommended Conversion Strategy 1. **Architecture-First Approach**: Convert base infrastructure (LLM generators, action result builders) before individual commands 2. **Wrapper Pattern**: Use existing `Protoless*ActionWrapper` classes as templates for gradual transition 3. **Dependency Analysis**: Map full dependency trees before attempting conversions to avoid cascading build failures 4. **Batch Conversions**: Convert related commands together to minimize dependency conflicts 5. **Build Verification**: **ALWAYS** verify `//src/main/scala/net/eagle0/eagle:eagle_server` and test suite build before creating PRs ### Conversion Requirements **Before creating any PR:** - ✅ `bazel build //src/main/scala/net/eagle0/eagle:eagle_server` succeeds - ✅ `bazel test //src/test/scala/... --keep_going` passes (or doesn't introduce new failures) - ✅ All BUILD dependencies are correctly specified - ✅ Scalafmt and other linters pass --- ## Common Base Classes | File | Type | Model Usage | Notes | |------|------|-------------|-------| | Action.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto`, `game_state_scala_proto` | | ActionWithResultingState.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto`, `game_state_scala_proto` | | DeterministicSingleResultAction.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto`, `game_state_scala_proto` | | DeterministicSequentialResultsAction.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto`, `game_state_scala_proto` | | ProtolessRandomSequentialResultsAction.scala | Base Class | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model/action_result` | | ProtolessRandomSimpleAction.scala | Base Class | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model/action_result` | | ProtolessSequentialResultsAction.scala | Base Class | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model/action_result` | | ProtolessSimpleAction.scala | Base Class | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model/action_result` | | RandomSequentialResultsAction.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto`, `game_state_scala_proto` | | RandomSimpleAction.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto` | | RandomStateProtoSequencer.scala | Sequencer | ❌ Uses Protobuf | Bridge class, depends on both protobuf and Scala models | | RandomStateTSequencer.scala | Sequencer | ❌ Uses Protobuf | Bridge class, depends on both protobuf and Scala models | | SimpleAction.scala | Base Class | ❌ Uses Protobuf | Depends on `action_result_scala_proto` | | VigorXPApplier.scala | Utility | ❌ Uses Protobuf | Depends on `action_result_scala_proto` | --- ## Actions ### ✅ Fully Migrated Actions (No Protobuf Dependencies) These actions have been successfully migrated to use Scala models only: | File | Base Class | Notes | |------|------------|-------| | HeroBackstoryUpdateAction.scala | ProtolessSequentialResultsAction | Processes hero backstory updates with LLM integration | | ProvinceConqueredAction.scala | ProtolessSimpleAction | Uses component-based design (gameId, currentRoundId, currentDate, Scala models) | | ProvinceHeldAction.scala | ProtolessSimpleAction | Uses specific components (gameId, currentRoundId, defendingProvince, etc.) instead of full GameState | | UnaffiliatedHeroAppearedAction.scala | ProtolessSimpleAction | Handles unaffiliated hero appearance with name generation | | WithdrawnArmiesReturnHomeAction.scala | ProtolessSequentialResultsAction | Manages army withdrawal and return mechanics | ### 🔄 Actions Partially Migrated (Using Protoless Base Classes) These actions use protoless base classes but still have some protobuf dependencies: | File | Model Usage | Notes | |------|-------------|-------| | CheckForFactionChangesAction.scala | ProtolessSequentialResultsAction | Still has some protobuf dependencies | | CheckForFailedQuestsAction.scala | ProtolessSequentialResultsAction | Depends on `unaffiliated_hero_quest_scala_proto` | | CheckForFulfilledQuestsAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets | | EndAttackDecisionPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets | | EndBattleAftermathPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets | | EndFreeForAllDecisionPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets | | EndPlayerCommandsPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets | | EndUnaffiliatedHeroActionsPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets | | EndVassalCommandsPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets | | FreeForAllDrawAction.scala | ProtolessSimpleAction | Depends on multiple protobuf targets | | FriendlyMoveAction.scala | ProtolessSimpleAction | Depends on multiple protobuf targets | | PerformUncontestedConquestAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets | | ProvinceConqueredAction.scala | ProtolessSimpleAction | **CONVERTED** - Uses specific components (gameId, currentRoundId, currentDate, Scala models) | | SafePassageArmiesProceedAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets | | ShipmentArrivedAction.scala | ProtolessSimpleAction | Depends on multiple protobuf targets | | TruceTurnBackPhaseAction.scala | ProtolessSequentialResultsAction | Depends on multiple protobuf targets | | UnaffiliatedHeroRejoinedAction.scala | ProtolessSimpleAction | Depends on multiple protobuf targets | | WonFreeForAllAction.scala | ProtolessSimpleAction | Depends on multiple protobuf targets | ### ❌ Actions Still Using Protobuf (Not Yet Using Protoless Base Classes) | File | Notes | |------|-------| | ChronicleEventGenerator.scala | Depends on multiple protobuf targets | | EndBattleRequestPhaseAction.scala | Depends on `diplomacy_offer_status_scala_proto` | | EndBattleResolutionPhaseAction.scala | Depends on multiple protobuf targets | | EndDefenseDecisionPhaseAction.scala | Depends on multiple protobuf targets | | EndDiplomacyResolutionPhaseAction.scala | Depends on multiple protobuf targets | | EndFreeForAllBattleRequestPhaseAction.scala | Depends on multiple protobuf targets | | EndFreeForAllBattleResolutionPhaseAction.scala | Depends on multiple protobuf targets | | EndHandleRiotsPhaseAction.scala | Depends on multiple protobuf targets | | EndPleaseRecruitMePhaseAction.scala | Depends on multiple protobuf targets | | EndProvinceMoveResolutionPhaseAction.scala | Depends on multiple protobuf targets | | NewRoundAction.scala | Depends on multiple protobuf targets | | NewYearAction.scala | Depends on multiple protobuf targets | | PerformFoodConsumptionPhaseAction.scala | Depends on multiple protobuf targets | | PerformForcedTurnBackAction.scala | Depends on multiple protobuf targets | | PerformHeroDeparturesAction.scala | Depends on multiple protobuf targets | | PerformHostileArmySetupAction.scala | Depends on multiple protobuf targets | | PerformProvinceEventsAction.scala | Depends on `province_event_scala_proto` | | PerformProvinceMoveResolutionAction.scala | Depends on multiple protobuf targets | | PerformReconResolutionAction.scala | Depends on multiple protobuf targets | | PerformUnaffiliatedHeroesAction.scala | Depends on `unaffiliated_hero_quest_scala_proto` | | PerformVassalCommandsPhaseAction.scala | Depends on multiple protobuf targets | | PerformVassalDefenseDecisionsAction.scala | Depends on multiple protobuf targets | | PrisonerEscapeAction.scala | Depends on `game_state_scala_proto` | | PrisonerExchangeAction.scala | Depends on multiple protobuf targets | | RequestBattlesAction.scala | Depends on multiple protobuf targets | | RequestFreeForAllBattlesAction.scala | Depends on multiple protobuf targets | | ResolveBattleAction.scala | Depends on `shardok_internal_interface_scala_grpc` | | UnaffiliatedHeroMovedAction.scala | Depends on multiple protobuf targets | | UnaffiliatedHeroesChangedAction.scala | Depends on multiple protobuf targets | --- ## Commands ✅ **ALL COMMANDS FULLY MIGRATED** (100% - 41/41 commands) All 41 commands in the codebase have been successfully migrated to use Scala models only, with no protobuf dependencies. This includes: - **Simple Actions**: Use `ProtolessSimpleAction` base class - **Random Actions**: Use `ProtolessRandomSimpleAction` base class - **Complex Domain Models**: Successfully integrated with LLM systems, diplomacy, quest fulfillment, and state management - **Complete Type Safety**: All commands now use type-safe Scala domain models **Key Migration Achievements:** - ✅ All military commands (ArmTroops, Train, Organize, etc.) - ✅ All diplomacy commands (Resolve Alliance/Truce/Ransom offers, etc.) - ✅ All LLM-integrated commands (backstory generation, diplomacy resolution) - ✅ All quest and event commands - ✅ Final remaining command (FreeForAllDecisionCommand) migrated --- ## Diplomacy Helpers All diplomacy helpers use **Scala models only**: | File | Model Usage | Notes | |------|-------------|-------| | AllianceResolutionHelpers.scala | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model` only | | BreakAllianceResolutionHelpers.scala | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model` only | | InvitationResolutionHelpers.scala | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model` only | | RansomResolutionHelpers.scala | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model` only | | TruceResolutionHelpers.scala | ✅ Scala Models Only | Uses `//src/main/scala/net/eagle0/eagle/model` only | --- ## Migration Priority Analysis Based on the BUILD.bazel dependency analysis, here are the key findings and recommendations: ### 🎯 High Impact Migration Targets **Core Dependencies Blocking Multiple Commands:** 1. **`action_result_scala_proto`** - Used by 12+ commands - Blocks: `DefendCommand`, `FreeForAllDecisionCommand`, diplomacy resolvers - Impact: Would unlock many command migrations 2. **`available_command_scala_proto` / `selected_command_scala_proto`** - Used by 10+ commands - Blocks: All UI-interactive commands - Impact: Would enable client-server interaction model migration 3. **`game_state_scala_proto`** - Used by 8+ commands - Blocks: Complex state-dependent commands - Impact: Core state representation migration ### 📊 Migration Tiers by Complexity **Tier 1 - Quick Wins (2 commands):** - `ArmTroopsCommand` - Only `battalion_type` dependency - `TrainCommand` - Only `battalion_type` dependency - **Effort:** Low, **Impact:** Demonstrates battalion model usage **Tier 2 - API Layer (5 commands):** - Commands blocked by `available_command`/`selected_command` - **Effort:** Medium, **Impact:** High (enables UI interaction models) **Tier 3 - Diplomacy Suite (6 commands):** - All `Resolve*Command` diplomacy commands - **Effort:** High, **Impact:** High (complete diplomacy model migration) - **Strategy:** Migrate as a group after diplomacy models are ready ### 🏆 Success Metrics **Current Status:** - ✅ **100% of commands fully migrated** (41/41) 🎉 - ✅ **All diplomacy helpers use Scala models** - ✅ **All protoless base classes available** - ✅ **ALL command migration completed** **Completed Milestones:** - ✅ **70% target:** Migrate Tier 1 + some Tier 2 commands **COMPLETED** - ✅ **80% target:** Continue with remaining non-diplomacy commands **COMPLETED** - ✅ **85% target:** Complete API layer migration **COMPLETED** - ✅ **95% target:** Complete diplomacy migration **COMPLETED** - ✅ **100% target:** Migrate final remaining command (FreeForAllDecisionCommand) **COMPLETED** ### 🎯 Action Migration Progress **Migration Statistics:** - 5/48 Actions fully migrated (10.4%) - 20/48 Actions using protoless base classes but with protobuf dependencies (41.7%) - 24/48 Actions still fully on protobuf (50%) **Successfully Migrated Actions:** 1. **HeroBackstoryUpdateAction** - LLM integration for hero backstories 2. **ProvinceConqueredAction** - Component-based design with prisoner handling and province conquest 3. **ProvinceHeldAction** - Component-based design pattern (gameId, currentRoundId, specific models) 4. **UnaffiliatedHeroAppearedAction** - Hero appearance with name generation 5. **WithdrawnArmiesReturnHomeAction** - Army withdrawal mechanics **Recent Migration Updates (2025-09-17):** - **ResolvedEagleUnit** - Changed `battalion: BattalionT` to `battalion: Option[BattalionT]` - Properly handles units without battalions (battalion ID -1) - Updated `ShardokInterfaceGrpcClient` to check for `defaultBattalionId` and use `None` - Updated `ResolveBattleAction`, `ProvinceConqueredAction`, `RequestBattlesAction` - All tests updated to handle optional battalions **Key Migration Patterns:** - ✅ Use specific components instead of full GameState (see ProvinceHeldAction, ProvinceConqueredAction) - ✅ Convert protobuf models to Scala models at Action boundaries - ✅ Update BUILD.bazel to remove protobuf dependencies - ✅ Update all call sites and tests - ✅ Use `Option[T]` for optional fields instead of special sentinel values (e.g., battalion ID -1) **Next Migration Candidates (Simple Actions with Protoless Base):** 1. **FreeForAllDrawAction** - Already uses ProtolessSimpleAction 2. **FriendlyMoveAction** - Already uses ProtolessSimpleAction 3. **ShipmentArrivedAction** - Already uses ProtolessSimpleAction 4. **WonFreeForAllAction** - Already uses ProtolessSimpleAction 5. **ProvinceConqueredAction** - Already uses ProtolessSimpleAction, only needs `common_unit` migration ### 🔄 Conversion Strategy Updates **Revised Approach Based on Analysis:** 1. **Focus on Core Dependencies First** - Migrate `battalion_type` model (unlocks 2 commands immediately) - Migrate `action_result` model (unlocks 12+ commands) - Migrate `available_command`/`selected_command` (unlocks UI layer) 2. **Leverage Existing Success** - 77.5% of commands already fully migrated - Use migrated commands as reference implementations - Diplomacy helpers prove complex business logic can work with Scala models 3. **Group Related Migrations** - Military commands: `ArmTroopsCommand`, `TrainCommand`, `OrganizeTroopsCommand` - UI commands: All using `available_command`/`selected_command` - Diplomacy commands: All `Resolve*Command` variants --- *Updated on 2025-09-17 - Analysis based on BUILD.bazel dependencies and code review* *Latest update: ResolvedEagleUnit migrated to use Option[BattalionT] for proper battalion handling*