Files
eagle0/docs/actions-model-usage-analysis.md
98baf7ec66 Organize documentation into docs/ folder (#4598)
Create docs/ folder at repo root and move documentation files:
- CONNECTION_ARCHITECTURE.md (new comprehensive connection docs)
- COMMAND_PROTO_USAGE_ANALYSIS.md
- DEPROTO_PLAN.md
- SCALA3_MODERNIZATION.md
- actions-model-usage-analysis.md
- occupants-optimization-report.md
- scala3-reflection-issues.md

CLAUDE.md remains at root (project instructions for Claude Code).

Connection architecture documentation includes:
- gRPC bidirectional streaming protocol details
- Client-side connection management (PersistentClientConnection)
- Server-side implementation (EagleServiceImpl)
- nginx proxy configuration and timeouts
- Timeout settings across all layers (client, nginx, server)
- Eagle ↔ Shardok communication flow

Critical findings:
- 🔴 SECURITY: Shardok internal interface exposed without auth in nginx config
- Mystery "2-minute timeout" doesn't exist in code (all timeouts are 5-20 minutes)
- No state resync mechanism after connection drops during Shardok
- Inefficient dual-layer heartbeat (HTTP/2 + application level)

Hypotheses for remote player connection issues:
- Most likely: NAT/firewall timeout at player's router/ISP (60-120s)
- HTTP/2 keepalive (45s) may not be frequent enough to keep NAT alive
- Shardok's bursty traffic pattern may appear "idle" at transport layer

Recommendations:
1. Fix Shardok internal interface security vulnerability
2. Add precise connection drop logging with timestamps
3. Reduce HTTP/2 keepalive from 45s to 15s
4. Get network diagnostics from affected remote player
5. Implement state resync mechanism for Shardok

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-30 14:11:51 -08:00

17 KiB

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

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 (SimpleActionProtolessSimpleAction)
  • Import updates for most Scala model types
  • BUILD.bazel dependency updates for core action result types
  • Basic type conversions for simple cases
  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