CLAUDE: Remove defensive alignment field completely

Removed the unused alignment field from DefensiveDecision model and all
related code across backend and frontend.

Backend changes:
- models/game_models.py: Removed alignment field and validator
- terminal_client/display.py: Removed alignment from display
- core/ai_opponent.py: Updated log message
- tests/unit/models/test_game_models.py: Removed alignment tests
- tests/unit/core/test_validators.py: Removed alignment validation test

Frontend changes:
- types/game.ts: Removed alignment from DefensiveDecision interface
- components/Decisions/DefensiveSetup.vue:
  * Removed alignment section from template
  * Removed alignment from localSetup initialization
  * Removed alignmentOptions array
  * Removed alignmentDisplay computed property
  * Removed alignment from hasChanges comparison
  * Removed alignment from visual preview (reorganized to col-span-2)

Rationale: Defensive alignment is not active in the game and will not be
used. Per Cal's decision, remove completely rather than keep as dead code.

Tests: All 728 backend unit tests passing (100%)

Session 1 Part 3 - Change #6 complete
Part of cleanup work from demo review

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Cal Corum 2025-11-14 13:02:22 -06:00
parent 2f0f35f951
commit 197d91edfb
11 changed files with 515 additions and 94 deletions

View File

@ -0,0 +1,227 @@
# Context Window Handoff - Cleanup Work in Progress
**Date**: 2025-01-14
**Current Session**: Cleanup of proposed changes from demo review
**Status**: Session 1 Part 1 Complete (2/11 changes done)
---
## Copy This Prompt to New Context Window
```
I'm continuing cleanup work on the Paper Dynasty / SBA web app. We're making changes based on a review of the frontend demo pages.
Current status: Session 1 Part 1 complete (removed 4 unused config fields). Now need to continue with Session 1 Part 2 and beyond.
Please read these files for full context:
- @.claude/PROPOSED_CHANGES_2025-01-14.md (master list of all 11 changes)
- @.claude/TODO_CLEANUP_COMPLETE.md (what we just finished)
- @backend/app/config/base_config.py (we just modified this)
- @backend/tests/unit/config/test_league_configs.py (we just modified this)
Key decisions from Cal:
1. Remove supports_manual_result_selection() - DONE ✅
2. Pitching change player ID - Will use league-independent polymorphic Player ID
3. Remove defensive alignment & offensive approach - DONE, remove completely
4. Offensive workflow refactor - YES, do before Phase F6 (last thing in cleanup)
5. Hit location fix - Only needed for: GROUNDOUT, FLYOUT, LINEOUT, SINGLE_UNCAPPED, DOUBLE_UNCAPPED, ERROR
Current TODO list (in TodoWrite):
- [completed] Remove strikes_for_out and balls_for_walk fields
- [completed] Remove supports_manual_result_selection() method
- [pending] Fix hit location requirements
- [pending] Remove defensive alignment from DefensiveDecision model
- [pending] Remove offensive approach from OffensiveDecision model
- [pending] Add infield depth validation (infield_in, corners_in, normal)
- [pending] Add outfield depth validation (normal, shallow with walk-off rules)
- [pending] Refactor offensive decision workflow (swing_away, check_jump, hit_and_run, sac_bunt, squeeze_bunt)
- [pending] Add check jump validation (lead runner only)
Workflow:
- Session 1: Quick wins (Changes #1-5) - IN PROGRESS
- Session 2: Standard changes (Changes #6-7) - NOT STARTED
- Session 3: Major refactor (Changes #8-11) - NOT STARTED
Dev server is running at http://localhost:3005 with demo pages.
Please continue from Session 1 Part 2: Fix hit location requirements.
```
---
## Files Modified So Far (Session 1 Part 1)
### backend/app/config/base_config.py
**Changes**: Removed 3 items
- Line 27: `strikes_for_out` field
- Line 28: `balls_for_walk` field
- Lines 41-48: `supports_manual_result_selection()` method
**Current state**: Clean, tests passing
### backend/tests/unit/config/test_league_configs.py
**Changes**: Updated 2 test methods
- `test_sba_basic_rules`: Removed assertions for strikes/balls
- `test_sba_supports_auto_mode`: Renamed from manual_selection, tests auto mode
- `test_pd_basic_rules`: Removed assertions for strikes/balls
- `test_pd_supports_auto_mode`: Renamed from manual_selection, tests auto mode
**Current state**: 28/28 tests passing
---
## Next Steps (Session 1 Part 2)
### Change #5: Fix Hit Location Requirements
**Current Problem**:
`frontend-sba/components/Gameplay/ManualOutcomeEntry.vue:152` has:
```typescript
const outcomesNeedingHitLocation = [
'GROUNDOUT',
'FLYOUT',
'LINEOUT',
'SINGLE_1', // ❌ Too broad
'SINGLE_2', // ❌ Too broad
'SINGLE_UNCAPPED', // ✅ Correct
'DOUBLE_2', // ❌ Too broad
'DOUBLE_3', // ❌ Too broad
'DOUBLE_UNCAPPED', // ✅ Correct
'TRIPLE', // ❌ Too broad
'ERROR', // ✅ Correct
]
```
**Correct List** (per Cal):
- GROUNDOUT (all groundouts)
- FLYOUT (all flyouts)
- LINEOUT (all lineouts)
- SINGLE_UNCAPPED
- DOUBLE_UNCAPPED
- ERROR
**Files to Update**:
1. `frontend-sba/components/Gameplay/ManualOutcomeEntry.vue:152` - Update array
2. Verify `PlayOutcome.requires_hit_location()` matches in backend (if it exists)
**Expected outcome**: Only outcomes that affect defensive plays require hit location
---
## Remaining Work After Session 1
### Session 2: Standard Changes (2-4 hours)
**Change #6**: Remove defensive alignment
- File: `backend/app/models/game_models.py` - DefensiveDecision model
- File: `frontend-sba/components/Decisions/DefensiveSetup.vue`
- Action: Remove `alignment` field completely
**Change #7**: Remove offensive approach
- File: `backend/app/models/game_models.py` - OffensiveDecision model
- File: `frontend-sba/components/Decisions/OffensiveApproach.vue`
- Action: Remove `approach` field completely (will be replaced in Change #10)
**Change #8**: Add infield depth validation
- Valid values: "infield_in", "corners_in", "normal"
- Rule: infield_in and corners_in only legal with R3
- Files: validators.py, DefensiveSetup.vue
**Change #9**: Add outfield depth validation
- Valid values: "normal", "shallow"
- Rule: shallow only legal when walk-off possible (home team, bottom 9+, trailing/tied, runner on base)
- Files: validators.py, DefensiveSetup.vue
### Session 3: Major Refactor (4+ hours)
**Change #10**: Refactor offensive decision model
- Replace `approach` field with specific actions
- New actions: swing_away, check_jump, hit_and_run, sac_bunt, squeeze_bunt
- Validation rules:
- squeeze_bunt only with R3 and bases not loaded
- check_jump only with runner on base
- Files: OffensiveDecision model, OffensiveApproach.vue, tests
- **Impact**: Will break 213 Phase F3 tests - need to update
**Change #11**: Check jump validation
- Rule: Only lead runner or both if 1st and 3rd
- No trail runners
- Bundle with Change #10
---
## Git Status
**Branch**: `implement-phase-3`
**Last Commit**: `eab61ad` - "Phases 3.5, F1-F5 Complete"
**Working Tree**: Clean (all previous work committed)
**Commits This Session**:
- Will need to commit cleanup work when done
---
## Test Status Baseline
**Before cleanup started**:
- Backend: 731/731 passing (100%)
- Frontend: 446/446 passing (100%)
**After Session 1 Part 1**:
- Backend config tests: 28/28 passing (100%)
- Need to verify full suite still passing
**Expected after Session 3**:
- Backend tests: Will need updates for offensive decision refactor
- Frontend tests: 213 F3 tests will need updates
---
## Key Context Files
**Master tracking**:
- `.claude/PROPOSED_CHANGES_2025-01-14.md` - All 11 changes with analysis
- `.claude/TODO_VERIFICATION_RESULTS.md` - What TODOs were already resolved
- `.claude/TODO_SUMMARY.md` - Quick reference
**Implementation docs**:
- `backend/app/config/CLAUDE.md` - Config system docs
- `backend/app/models/CLAUDE.md` - Game models docs (will need for Changes #6-11)
- `frontend-sba/CLAUDE.md` - Frontend docs
**Modified files so far**:
- `backend/app/config/base_config.py`
- `backend/tests/unit/config/test_league_configs.py`
---
## Important Notes
1. **Dev server running**: http://localhost:3005 for testing frontend changes
2. **Always run tests** after each change
3. **Commit frequently** - don't batch all changes into one commit
4. **Session 3 is complex** - offensive decision refactor affects many files
5. **Follow workflow** - Don't skip to Session 3, do Session 1 & 2 first
---
## Questions Already Answered
Q: Remove or keep supports_manual_result_selection()?
A: Remove completely ✅
Q: What identifier for pitching change?
A: League-independent polymorphic Player ID
Q: Remove alignment and approach?
A: Yes, remove completely
Q: When to do offensive refactor?
A: Before Phase F6, as last part of cleanup
Q: Hit location requirements?
A: Only GROUNDOUT, FLYOUT, LINEOUT, SINGLE_UNCAPPED, DOUBLE_UNCAPPED, ERROR
---
**Ready to continue!** Start with Session 1 Part 2: Fix hit location requirements.

View File

@ -0,0 +1,280 @@
# Proposed Changes Analysis - 2025-01-14
**Date**: 2025-01-14
**Source**: Cal's review of demo pages
**Total Changes**: 11 items
---
## Quick Wins (Simple, Low Risk) - 3 items
### ✅ Change #1: Remove `strikes_for_out` field
**Location**: `backend/app/config/base_config.py:27`
**Change**: Delete line 27
**Impact**: 1 file
**Effort**: < 5 minutes
**Risk**: None (already marked as TODO to remove)
**Recommendation**: **PROCEED IMMEDIATELY**
---
### ✅ Change #2: Remove `balls_for_walk` field
**Location**: `backend/app/config/base_config.py:28`
**Change**: Delete line 28
**Impact**: 1 file
**Effort**: < 5 minutes
**Risk**: None (already marked as TODO to remove)
**Recommendation**: **PROCEED IMMEDIATELY**
---
### 🤔 Change #3: Remove/refactor `supports_manual_result_selection()`
**Location**: `backend/app/config/base_config.py:41`
**Current**: Method on BaseGameConfig
**Question**: When would we ever use this function?
**Current Usage**:
```python
def supports_manual_result_selection(self) -> bool:
# TODO: consider refactor: manually selecting results is default behavior
# with PD allowing auto-results as an option
return True
```
**Analysis**:
- SbaConfig: Always manual (no auto mode)
- PdConfig: Supports both manual and auto
**Options**:
1. **Remove entirely** - If we never check this
2. **Rename to `supports_auto_mode()`** - Invert logic (clearer)
3. **Keep as-is** - If we do use it
**Question for Cal**: Do we ever check if manual mode is supported? Or should this be `supports_auto_mode()` instead?
**Recommendation**: **NEEDS DECISION**
---
## Standard Changes (Need Review) - 4 items
### 🔍 Change #4: Pitching change player identification
**Location**: `backend/app/websocket/handlers.py` (pitching_change event)
**Current**: Uses `player_in_card_id`
**Question**: Is card ID the best way to identify the new player from active roster?
**Current Implementation**:
```python
@sio.event
async def request_pitching_change(sid, data):
player_in_card_id = data.get("player_in_card_id") # Card ID
```
**Analysis**:
- **PD League**: `card_id` makes sense (cards are the entity)
- **SBA League**: Uses `player_id` (different from card_id)
- **Roster**: RosterLink table has both card_id and player_id (polymorphic)
**Options**:
1. **Keep card_id** - Works for PD, need to translate for SBA
2. **Use roster_link_id** - Unified identifier
3. **League-specific fields** - `card_id` for PD, `player_id` for SBA
**Question for Cal**: What identifier does the frontend UI have access to when selecting a relief pitcher?
**Recommendation**: **NEEDS DECISION** (depends on frontend data model)
---
### 🔍 Change #5: Hit location enforcement
**Current**: Enforcing hit location on too many results
**Correct Behavior**:
- Use `PlayOutcome.requires_hit_location()` (already exists)
- Only required if runner on base who doesn't automatically score
**Files to Check**:
- `frontend-sba/components/Gameplay/ManualOutcomeEntry.vue:152` (outcomesNeedingHitLocation array)
- `backend/app/core/play_resolver.py` (validation logic)
**Analysis Needed**:
1. What outcomes currently require hit location?
2. What SHOULD require hit location per game rules?
3. Does `PlayOutcome.requires_hit_location()` match game rules?
**Recommendation**: **NEEDS CODE REVIEW** - Let me check current implementation
---
### 🔍 Change #6: Remove Defensive Alignment
**Current**: DefensiveDecision has `alignment` field
**Proposed**: Remove or mark unused (not active in game)
**Impact**:
- `backend/app/models/game_models.py` - DefensiveDecision model
- `frontend-sba/components/Decisions/DefensiveSetup.vue` - UI component
- `backend/app/websocket/handlers.py` - Event handler
**Options**:
1. **Remove completely** - Clean up unused code
2. **Keep but mark unused** - Future feature
3. **Hide from UI** - Keep model field, remove UI
**Question for Cal**: Is this NEVER going to be used, or is it a future feature?
**Recommendation**: **NEEDS DECISION**
---
### 🔍 Change #7: Remove Offensive Approach
**Current**: OffensiveDecision has `approach` field
**Proposed**: Remove or mark unused (not active in game)
**Similar to Change #6** - same questions apply
**Recommendation**: **NEEDS DECISION**
---
## Complex Changes (Workflow Changes) - 4 items
### 💬 Change #8: Infield Depths - Simplify to 3 valid options
**Current**: May have more options
**Proposed Valid Values**:
- `"infield_in"` (only legal with runner on 3rd)
- `"corners_in"` (only legal with runner on 3rd)
- `"normal"` (default)
**Impact**:
- `backend/app/models/game_models.py` - DefensiveDecision validation
- `backend/app/core/validators.py` - Add rule validation
- `frontend-sba/components/Decisions/DefensiveSetup.vue` - UI options
- Tests for validation
**Effort**: 1-2 hours
**Risk**: Medium (validation logic)
**Recommendation**: **NEEDS APPROVAL** - Good cleanup, requires validation updates
---
### 💬 Change #9: Outfield Depths - Add legal constraints
**Current**: May allow any value
**Proposed Valid Values**:
- `"normal"` (default, 99.99% of time)
- `"shallow"` (only legal when batting team could walk-off win with runner on base)
**Impact**: Same as Change #8
**Question**: How do we determine "could walk-off win"?
- Batter's team is home team
- Bottom of 9th or later
- Trailing or tied
- Runner on base
**Effort**: 1-2 hours
**Risk**: Medium (walk-off logic)
**Recommendation**: **NEEDS APPROVAL** - Adds game-accurate validation
---
### 💬 Change #10: Replace offensive approach with specific actions
**Current**: OffensiveDecision has `approach` field
**Proposed**: Replace with specific action choices:
- `"swing_away"` (default)
- `"check_jump"` (for lead runner only)
- `"hit_and_run"`
- `"sac_bunt"`
- `"squeeze_bunt"` (only legal with R3 and bases not loaded)
**Impact**:
- `backend/app/models/game_models.py` - Refactor OffensiveDecision
- `frontend-sba/components/Decisions/OffensiveApproach.vue` - Complete UI redesign
- `backend/app/websocket/handlers.py` - Update event handling
- Tests (213 tests in Phase F3 may need updates)
**Effort**: 3-4 hours
**Risk**: High (affects decision workflow, breaks existing tests)
**Recommendation**: **NEEDS DISCUSSION** - Major workflow change
---
### 💬 Change #11: Check jump only with lead runner
**Current**: May allow checking jump with any runner
**Proposed Rule**: Players may only check jump with:
- Lead runner only
- OR both runners if 1st and 3rd
- NO checking jump with trail runners
**Impact**:
- Validation logic for "check_jump" action (from Change #10)
- Frontend UI to disable invalid options
**Effort**: 30 minutes (if Change #10 implemented)
**Risk**: Low (validation rule)
**Recommendation**: **BUNDLE WITH CHANGE #10**
---
## Summary by Category
### Quick Wins (5 min each)
1. ✅ Remove strikes_for_out
2. ✅ Remove balls_for_walk
3. 🤔 Remove/refactor supports_manual_result_selection() - **NEEDS DECISION**
### Standard Changes (1-2 hours each)
4. 🔍 Pitching change identifier - **NEEDS DECISION**
5. 🔍 Hit location enforcement - **NEEDS CODE REVIEW**
6. 🔍 Remove defensive alignment - **NEEDS DECISION**
7. 🔍 Remove offensive approach - **NEEDS DECISION** (conflicts with #10)
### Complex Changes (3-4 hours each)
8. 💬 Infield depths validation - **NEEDS APPROVAL**
9. 💬 Outfield depths validation - **NEEDS APPROVAL**
10. 💬 Replace approach with actions - **NEEDS DISCUSSION** (breaks tests)
11. 💬 Check jump lead runner only - **BUNDLE WITH #10**
---
## Recommended Approach
### Phase 1: Quick Wins (15 min)
- Execute #1, #2 immediately
- Decide on #3 (remove vs refactor vs keep)
### Phase 2: Decisions Needed (discussion)
- #4: What identifier does frontend use?
- #6, #7: Remove unused fields or keep for future?
- These inform #10 (if we're removing approach anyway, don't refactor it)
### Phase 3: Code Review (30 min)
- #5: Review hit location logic, fix if needed
### Phase 4: Validation Updates (2-4 hours)
- #8, #9: Add depth validation rules
- Only if approved
### Phase 5: Workflow Refactor (4+ hours)
- #10, #11: Offensive action redesign
- Major change, do last after everything else settled
- Will break existing tests, need full re-test
---
## Questions for Cal
1. **Change #3**: Do we ever check `supports_manual_result_selection()`? Should we rename to `supports_auto_mode()` instead?
2. **Change #4**: What identifier does the frontend have when selecting a relief pitcher from the bench?
3. **Changes #6, #7**: Are alignment and approach NEVER going to be used, or future features we should keep?
4. **Change #10**: This is a major workflow change - are you sure we want to do this now (before Phase F6 integration)?
---
**Document Version**: 1.0
**Status**: Awaiting decisions on questions above

View File

@ -24,8 +24,6 @@ class BaseGameConfig(BaseModel, ABC):
# Basic baseball rules (same across leagues)
innings: int = Field(default=9, description="Standard innings per game")
outs_per_inning: int = Field(default=3, description="Outs required per half-inning")
strikes_for_out: int = Field(default=3, description="Strikes for strikeout") # TODO: remove - unneeded
balls_for_walk: int = Field(default=4, description="Balls for walk") # TODO: remove - unneeded
@abstractmethod
def get_result_chart_name(self) -> str:
@ -37,16 +35,6 @@ class BaseGameConfig(BaseModel, ABC):
"""
pass
@abstractmethod
def supports_manual_result_selection(self) -> bool: # TODO: consider refactor: manually selecting results is default behavior with PD allowing auto-results as an option
"""
Whether players manually select results after dice roll.
Returns:
True if players pick from chart, False if auto-resolved
"""
pass
@abstractmethod
def supports_auto_mode(self) -> bool:
"""

View File

@ -79,7 +79,7 @@ class AIOpponent:
# if state.is_runner_on_third() and state.outs < 2:
# decision.infield_depth = "in"
logger.info(f"AI defensive decision: {decision.alignment}, IF: {decision.infield_depth}")
logger.info(f"AI defensive decision: IF: {decision.infield_depth}, OF: {decision.outfield_depth}")
return decision
async def generate_offensive_decision(

View File

@ -151,20 +151,10 @@ class DefensiveDecision(BaseModel):
These decisions affect play outcomes (e.g., infield depth affects double play chances).
"""
alignment: str = "normal" # normal, shifted_left, shifted_right, extreme_shift
infield_depth: str = "normal" # infield_in, normal, corners_in
outfield_depth: str = "normal" # in, normal
hold_runners: List[int] = Field(default_factory=list) # [1, 3] = hold 1st and 3rd
@field_validator('alignment')
@classmethod
def validate_alignment(cls, v: str) -> str:
"""Validate alignment"""
valid = ['normal', 'shifted_left', 'shifted_right', 'extreme_shift']
if v not in valid:
raise ValueError(f"alignment must be one of {valid}")
return v
@field_validator('infield_depth')
@classmethod
def validate_infield_depth(cls, v: str) -> str:

View File

@ -188,7 +188,6 @@ def display_decision(decision_type: str, decision: Optional[DefensiveDecision |
decision_text = Text()
if isinstance(decision, DefensiveDecision):
decision_text.append(f"Alignment: {decision.alignment}\n")
decision_text.append(f"Infield Depth: {decision.infield_depth}\n")
decision_text.append(f"Outfield Depth: {decision.outfield_depth}\n")
if decision.hold_runners:

View File

@ -42,18 +42,16 @@ class TestSbaConfig:
config = SbaConfig()
assert config.innings == 9
assert config.outs_per_inning == 3
assert config.strikes_for_out == 3
assert config.balls_for_walk == 4
def test_sba_result_chart_name(self):
"""SBA uses sba_standard_v1 chart."""
config = SbaConfig()
assert config.get_result_chart_name() == "sba_standard_v1"
def test_sba_supports_manual_selection(self):
"""SBA supports manual result selection."""
def test_sba_supports_auto_mode(self):
"""SBA does not support auto mode (cards not digitized)."""
config = SbaConfig()
assert config.supports_manual_result_selection() is True
assert config.supports_auto_mode() is False
def test_sba_api_url(self):
"""SBA API URL is correct."""
@ -86,18 +84,16 @@ class TestPdConfig:
config = PdConfig()
assert config.innings == 9
assert config.outs_per_inning == 3
assert config.strikes_for_out == 3
assert config.balls_for_walk == 4
def test_pd_result_chart_name(self):
"""PD uses pd_standard_v1 chart."""
config = PdConfig()
assert config.get_result_chart_name() == "pd_standard_v1"
def test_pd_supports_manual_selection(self):
"""PD supports manual result selection (though auto is also available)."""
def test_pd_supports_auto_mode(self):
"""PD supports auto mode (digitized card data)."""
config = PdConfig()
assert config.supports_manual_result_selection() is True
assert config.supports_auto_mode() is True
def test_pd_api_url(self):
"""PD API URL is correct."""

View File

@ -177,19 +177,6 @@ class TestDefensiveDecisionValidation:
# Should not raise
validator.validate_defensive_decision(decision, state)
def test_validate_defensive_decision_invalid_alignment(self):
"""Test invalid alignment fails at Pydantic validation"""
from pydantic_core import ValidationError as PydanticValidationError
# Pydantic catches invalid alignment at model creation
with pytest.raises(PydanticValidationError) as exc_info:
decision = DefensiveDecision(
alignment="invalid_alignment",
infield_depth="normal"
)
assert "alignment" in str(exc_info.value).lower()
def test_validate_defensive_decision_invalid_depth(self):
"""Test invalid infield depth fails at Pydantic validation"""
from pydantic_core import ValidationError as PydanticValidationError

View File

@ -227,23 +227,10 @@ class TestDefensiveDecision:
def test_create_defensive_decision_defaults(self):
"""Test creating defensive decision with defaults"""
decision = DefensiveDecision()
assert decision.alignment == "normal"
assert decision.infield_depth == "normal"
assert decision.outfield_depth == "normal"
assert decision.hold_runners == []
def test_defensive_decision_valid_alignments(self):
"""Test all valid alignments"""
valid = ['normal', 'shifted_left', 'shifted_right', 'extreme_shift']
for alignment in valid:
decision = DefensiveDecision(alignment=alignment)
assert decision.alignment == alignment
def test_defensive_decision_invalid_alignment(self):
"""Test that invalid alignment raises error"""
with pytest.raises(ValidationError):
DefensiveDecision(alignment="invalid")
def test_defensive_decision_valid_infield_depths(self):
"""Test all valid infield depths"""
valid = ['infield_in', 'normal', 'corners_in']

View File

@ -16,20 +16,6 @@
<!-- Form -->
<form @submit.prevent="handleSubmit" class="space-y-6">
<!-- Defensive Alignment -->
<div>
<label class="block text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3">
Defensive Alignment
</label>
<ButtonGroup
v-model="localSetup.alignment"
:options="alignmentOptions"
:disabled="!isActive"
size="md"
variant="primary"
/>
</div>
<!-- Infield Depth -->
<div>
<label class="block text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3">
@ -92,10 +78,6 @@
Current Setup
</h4>
<div class="grid grid-cols-2 gap-2 text-xs">
<div>
<span class="font-medium text-gray-600 dark:text-gray-400">Alignment:</span>
<span class="ml-1 text-gray-900 dark:text-white">{{ alignmentDisplay }}</span>
</div>
<div>
<span class="font-medium text-gray-600 dark:text-gray-400">Infield:</span>
<span class="ml-1 text-gray-900 dark:text-white">{{ infieldDisplay }}</span>
@ -104,7 +86,7 @@
<span class="font-medium text-gray-600 dark:text-gray-400">Outfield:</span>
<span class="ml-1 text-gray-900 dark:text-white">{{ outfieldDisplay }}</span>
</div>
<div>
<div class="col-span-2">
<span class="font-medium text-gray-600 dark:text-gray-400">Holding:</span>
<span class="ml-1 text-gray-900 dark:text-white">{{ holdingDisplay }}</span>
</div>
@ -151,7 +133,6 @@ const emit = defineEmits<{
// Local state
const submitting = ref(false)
const localSetup = ref<DefensiveDecision>({
alignment: props.currentSetup?.alignment || 'normal',
infield_depth: props.currentSetup?.infield_depth || 'normal',
outfield_depth: props.currentSetup?.outfield_depth || 'normal',
hold_runners: props.currentSetup?.hold_runners || [],
@ -172,13 +153,6 @@ watch([holdFirst, holdSecond, holdThird], () => {
})
// Options for ButtonGroup components
const alignmentOptions: ButtonGroupOption[] = [
{ value: 'normal', label: 'Normal', icon: '⚾' },
{ value: 'shifted_left', label: 'Shift Left', icon: '←' },
{ value: 'shifted_right', label: 'Shift Right', icon: '→' },
{ value: 'extreme_shift', label: 'Extreme', icon: '↔️' },
]
const infieldDepthOptions: ButtonGroupOption[] = [
{ value: 'in', label: 'Infield In', icon: '⬆️' },
{ value: 'normal', label: 'Normal', icon: '•' },
@ -194,11 +168,6 @@ const outfieldDepthOptions: ButtonGroupOption[] = [
]
// Display helpers
const alignmentDisplay = computed(() => {
const option = alignmentOptions.find(opt => opt.value === localSetup.value.alignment)
return option?.label || 'Normal'
})
const infieldDisplay = computed(() => {
const option = infieldDepthOptions.find(opt => opt.value === localSetup.value.infield_depth)
return option?.label || 'Normal'
@ -223,7 +192,6 @@ const holdingDisplay = computed(() => {
const hasChanges = computed(() => {
if (!props.currentSetup) return true
return (
localSetup.value.alignment !== props.currentSetup.alignment ||
localSetup.value.infield_depth !== props.currentSetup.infield_depth ||
localSetup.value.outfield_depth !== props.currentSetup.outfield_depth ||
JSON.stringify(localSetup.value.hold_runners) !== JSON.stringify(props.currentSetup.hold_runners)

View File

@ -122,7 +122,6 @@ export interface GameState {
* Backend: DefensiveDecision
*/
export interface DefensiveDecision {
alignment: 'normal' | 'shifted_left' | 'shifted_right' | 'extreme_shift'
infield_depth: 'in' | 'normal' | 'back' | 'double_play' | 'corners_in'
outfield_depth: 'in' | 'normal' | 'back'
hold_runners: number[] // Bases to hold (e.g., [1, 3])