Fixed two critical bugs in Phase 3D X-Check implementation plus improved dice audit trail for better tracking. BUG #1: on_base_code Mapping Error (Sequential vs Bit Field) ============================================================ The implementation incorrectly treated on_base_code as a bit field when it is actually a sequential lookup mapping. WRONG (bit field): Code 3 (0b011) → R1 + R2 Code 4 (0b100) → R3 only CORRECT (sequential): Code 3 → R3 only Code 4 → R1 + R2 Fixed: - build_advancement_from_code() decoder (sequential mapping) - build_flyball_advancement_with_error() decoder (sequential mapping) - 13 test on_base_code values (3↔4 corrections) - Updated documentation to clarify NOT a bit field BUG #2: Table Data Not Matching Official Charts ================================================ 7 table entries in G1_ADVANCEMENT_TABLE and G2_ADVANCEMENT_TABLE did not match the official rulebook charts provided by user. Fixed table entries: - G1 Code 1, Infield In: Changed Result 3 → 2 - G1 Code 3, Normal: Changed Result 13 → 3 - G1 Code 3, Infield In: Changed Result 3 → 1 - G1 Code 4, Normal: Changed Result 3 → 13 - G1 Code 4, Infield In: Changed Result 4 → 2 - G2 Code 3, Infield In: Changed Result 3 → 1 - G2 Code 4, Normal: Changed Result 5 → 4 Also fixed 7 test expectations to match corrected tables. IMPROVEMENT: Better Dice Audit Trail ===================================== Updated _resolve_x_check() in PlayResolver to use proper dice_system.roll_fielding() instead of manual die rolling. Benefits: - All dice tracked in audit trail (roll_id, timestamp, position) - Automatic error_total calculation (no manual 3d6 addition) - Consistent with codebase patterns - Position recorded for historical analysis Testing: - All 59 X-Check advancement tests passing (100%) - All 9 PlayResolver tests passing (100%) - All table entries validated against official charts - Complete codebase scan: no bit field operations found Files modified: - backend/app/core/x_check_advancement_tables.py - backend/tests/unit/core/test_x_check_advancement_tables.py - backend/app/core/play_resolver.py - .claude/implementation/PHASE_3D_CRITICAL_FIX.md (documentation) - .claude/implementation/GROUNDBALL_CHART_REFERENCE.md (new) - .claude/implementation/XCHECK_TEST_VALIDATION.md (new) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
343 lines
11 KiB
Markdown
343 lines
11 KiB
Markdown
# X-Check Test Validation Table
|
|
|
|
**Purpose**: Map each test to its correct expected GroundballResultType based on official charts
|
|
**Source**: Images #1 (G1), #2 (G2), #3 (G3)
|
|
**Date**: 2025-11-02
|
|
|
|
---
|
|
|
|
## Result Type Reference (from Images #4-5)
|
|
|
|
```
|
|
1 = BATTER_OUT_RUNNERS_HOLD
|
|
2 = DOUBLE_PLAY_AT_SECOND
|
|
3 = BATTER_OUT_RUNNERS_ADVANCE
|
|
4 = BATTER_SAFE_FORCE_OUT_AT_SECOND
|
|
5 = CONDITIONAL_ON_MIDDLE_INFIELD
|
|
6 = CONDITIONAL_ON_RIGHT_SIDE
|
|
7 = BATTER_OUT_FORCED_ONLY
|
|
8 = BATTER_OUT_FORCED_ONLY_ALT
|
|
9 = LEAD_HOLDS_TRAIL_ADVANCES
|
|
10 = DOUBLE_PLAY_HOME_TO_FIRST
|
|
11 = BATTER_SAFE_LEAD_OUT
|
|
12 = DECIDE_OPPORTUNITY
|
|
13 = CONDITIONAL_DOUBLE_PLAY
|
|
```
|
|
|
|
---
|
|
|
|
## G1 Chart Reference (Image #1)
|
|
|
|
| Bases (on_base_code) | Infield Normal | Infield In |
|
|
|----------------------|----------------|------------|
|
|
| Empty (0) | 1 | N/A |
|
|
| 1st (1) | 2 | 2 |
|
|
| 2nd (2) | 12 | 12 |
|
|
| 3rd (3) | 3 | 1 |
|
|
| 1st & 2nd (4) | 13 | 2 |
|
|
| 1st & 3rd (5) | 2 | 1 |
|
|
| 2nd & 3rd (6) | 3 | 1 |
|
|
| Loaded (7) | 2 | 10 |
|
|
|
|
---
|
|
|
|
## G2 Chart Reference (Image #2)
|
|
|
|
| Bases (on_base_code) | Infield Normal | Infield In |
|
|
|----------------------|----------------|------------|
|
|
| Empty (0) | 1 | N/A |
|
|
| 1st (1) | 4 | 4 |
|
|
| 2nd (2) | 12 | 12 |
|
|
| 3rd (3) | 5 | 1 |
|
|
| 1st & 2nd (4) | 4 | 4 |
|
|
| 1st & 3rd (5) | 4 | 1 |
|
|
| 2nd & 3rd (6) | 5 | 1 |
|
|
| Loaded (7) | 4 | 11 |
|
|
|
|
---
|
|
|
|
## G3 Chart Reference (Image #3)
|
|
|
|
| Bases (on_base_code) | Infield Normal | Infield In |
|
|
|----------------------|----------------|------------|
|
|
| Empty (0) | 1 | N/A |
|
|
| 1st (1) | 3 | 3 |
|
|
| 2nd (2) | 12 | 3 |
|
|
| 3rd (3) | 3 | 12 (DECIDE)|
|
|
| 1st & 2nd (4) | 3 | 3 |
|
|
| 1st & 3rd (5) | 3 | 3 |
|
|
| 2nd & 3rd (6) | 3 | 12 (DECIDE)|
|
|
| Loaded (7) | 3 | 11 |
|
|
|
|
---
|
|
|
|
## Test Validation - G1 Tests
|
|
|
|
### test_g1_bases_empty_normal_no_error
|
|
- **Scenario**: G1, Empty, Normal, NO
|
|
- **Current on_base_code**: 0 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 1 (BATTER_OUT_RUNNERS_HOLD)
|
|
- **Current Expectation**: BATTER_OUT_RUNNERS_HOLD ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g1_r1_only_normal_no_error
|
|
- **Scenario**: G1, 1st, Normal, NO
|
|
- **Current on_base_code**: 1 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 2 (DOUBLE_PLAY_AT_SECOND)
|
|
- **Current Expectation**: DOUBLE_PLAY_AT_SECOND ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g1_r1_only_infield_in_no_error
|
|
- **Scenario**: G1, 1st, In, NO
|
|
- **Current on_base_code**: 1 ✅
|
|
- **Current defender_in**: True ✅
|
|
- **Expected Result**: 2 (DOUBLE_PLAY_AT_SECOND)
|
|
- **Chart Says**: 2 ✅
|
|
- **Current Expectation**: BATTER_OUT_RUNNERS_ADVANCE (3) ❌
|
|
- **Status**: ❌ WRONG - Should be DOUBLE_PLAY_AT_SECOND (2)
|
|
|
|
### test_g1_r2_only_normal_no_error
|
|
- **Scenario**: G1, 2nd, Normal, NO
|
|
- **Current on_base_code**: 2 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 12 (DECIDE_OPPORTUNITY)
|
|
- **Current Expectation**: DECIDE_OPPORTUNITY ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g1_r1_r2_normal_no_error
|
|
- **Scenario**: G1, 1st & 2nd, Normal, NO
|
|
- **Current on_base_code**: 4 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 13 (CONDITIONAL_DOUBLE_PLAY)
|
|
- **Chart Says**: 13 ✅
|
|
- **Current Expectation**: BATTER_OUT_RUNNERS_ADVANCE (3) ❌
|
|
- **Status**: ❌ WRONG - Should be CONDITIONAL_DOUBLE_PLAY (13)
|
|
|
|
### test_g1_r1_r2_infield_in_no_error
|
|
- **Scenario**: G1, 1st & 2nd, In, NO
|
|
- **Current on_base_code**: 4 ✅
|
|
- **Current defender_in**: True ✅
|
|
- **Expected Result**: 2 (DOUBLE_PLAY_AT_SECOND)
|
|
- **Chart Says**: 2 ✅
|
|
- **Current Expectation**: BATTER_SAFE_FORCE_OUT_AT_SECOND (4) ❌
|
|
- **Status**: ❌ WRONG - Should be DOUBLE_PLAY_AT_SECOND (2)
|
|
|
|
### test_g1_r3_only_normal_no_error
|
|
- **Scenario**: G1, 3rd, Normal, NO
|
|
- **Current on_base_code**: 3 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 3 (BATTER_OUT_RUNNERS_ADVANCE)
|
|
- **Chart Says**: 3 ✅
|
|
- **Current Expectation**: CONDITIONAL_DOUBLE_PLAY (13) ❌
|
|
- **Status**: ❌ WRONG - Should be BATTER_OUT_RUNNERS_ADVANCE (3)
|
|
|
|
### test_g1_r3_only_infield_in_no_error
|
|
- **Scenario**: G1, 3rd, In, NO
|
|
- **Current on_base_code**: 3 ✅
|
|
- **Current defender_in**: True ✅
|
|
- **Expected Result**: 1 (BATTER_OUT_RUNNERS_HOLD)
|
|
- **Chart Says**: 1 ✅
|
|
- **Current Expectation**: BATTER_OUT_RUNNERS_ADVANCE (3) ❌
|
|
- **Status**: ❌ WRONG - Should be BATTER_OUT_RUNNERS_HOLD (1)
|
|
|
|
### test_g1_loaded_normal_no_error
|
|
- **Scenario**: G1, Loaded, Normal, NO
|
|
- **Current on_base_code**: 7 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 2 (DOUBLE_PLAY_AT_SECOND)
|
|
- **Current Expectation**: DOUBLE_PLAY_AT_SECOND ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g1_loaded_infield_in_no_error
|
|
- **Scenario**: G1, Loaded, In, NO
|
|
- **Current on_base_code**: 7 ✅
|
|
- **Current defender_in**: True ✅
|
|
- **Expected Result**: 10 (DOUBLE_PLAY_HOME_TO_FIRST)
|
|
- **Current Expectation**: DOUBLE_PLAY_HOME_TO_FIRST ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
---
|
|
|
|
## Test Validation - G2 Tests
|
|
|
|
### test_g2_bases_empty_normal_no_error
|
|
- **Scenario**: G2, Empty, Normal, NO
|
|
- **Current on_base_code**: 0 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 1 (BATTER_OUT_RUNNERS_HOLD)
|
|
- **Current Expectation**: BATTER_OUT_RUNNERS_HOLD ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g2_r1_only_normal_no_error
|
|
- **Scenario**: G2, 1st, Normal, NO
|
|
- **Current on_base_code**: 1 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 4 (BATTER_SAFE_FORCE_OUT_AT_SECOND)
|
|
- **Current Expectation**: BATTER_SAFE_FORCE_OUT_AT_SECOND ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g2_r1_r2_normal_no_error
|
|
- **Scenario**: G2, 1st & 2nd, Normal, NO
|
|
- **Current on_base_code**: 4 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 4 (BATTER_SAFE_FORCE_OUT_AT_SECOND)
|
|
- **Chart Says**: 4 ✅
|
|
- **Current Expectation**: CONDITIONAL_ON_MIDDLE_INFIELD (5) ❌
|
|
- **Status**: ❌ WRONG - Should be BATTER_SAFE_FORCE_OUT_AT_SECOND (4)
|
|
|
|
### test_g2_r1_r2_infield_in_no_error
|
|
- **Scenario**: G2, 1st & 2nd, In, NO
|
|
- **Current on_base_code**: 4 ✅
|
|
- **Current defender_in**: True ✅
|
|
- **Expected Result**: 4 (BATTER_SAFE_FORCE_OUT_AT_SECOND)
|
|
- **Current Expectation**: BATTER_SAFE_FORCE_OUT_AT_SECOND ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g2_r3_only_normal_no_error
|
|
- **Scenario**: G2, 3rd, Normal, NO
|
|
- **Current on_base_code**: 3 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 5 (CONDITIONAL_ON_MIDDLE_INFIELD)
|
|
- **Current Expectation**: CONDITIONAL_ON_MIDDLE_INFIELD ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g2_r3_only_infield_in_no_error
|
|
- **Scenario**: G2, 3rd, In, NO
|
|
- **Current on_base_code**: 3 ✅
|
|
- **Current defender_in**: True ✅
|
|
- **Expected Result**: 1 (BATTER_OUT_RUNNERS_HOLD)
|
|
- **Chart Says**: 1 ✅
|
|
- **Current Expectation**: BATTER_OUT_RUNNERS_ADVANCE (3) ❌
|
|
- **Status**: ❌ WRONG - Should be BATTER_OUT_RUNNERS_HOLD (1)
|
|
|
|
### test_g2_loaded_normal_no_error
|
|
- **Scenario**: G2, Loaded, Normal, NO
|
|
- **Current on_base_code**: 7 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 4 (BATTER_SAFE_FORCE_OUT_AT_SECOND)
|
|
- **Current Expectation**: BATTER_SAFE_FORCE_OUT_AT_SECOND ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g2_loaded_infield_in_no_error
|
|
- **Scenario**: G2, Loaded, In, NO
|
|
- **Current on_base_code**: 7 ✅
|
|
- **Current defender_in**: True ✅
|
|
- **Expected Result**: 11 (BATTER_SAFE_LEAD_OUT)
|
|
- **Current Expectation**: BATTER_SAFE_LEAD_OUT ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
---
|
|
|
|
## Test Validation - G3 Tests
|
|
|
|
### test_g3_bases_empty_normal_no_error
|
|
- **Scenario**: G3, Empty, Normal, NO
|
|
- **Current on_base_code**: 0 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 1 (BATTER_OUT_RUNNERS_HOLD)
|
|
- **Current Expectation**: BATTER_OUT_RUNNERS_HOLD ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g3_r1_only_normal_no_error
|
|
- **Scenario**: G3, 1st, Normal, NO
|
|
- **Current on_base_code**: 1 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 3 (BATTER_OUT_RUNNERS_ADVANCE)
|
|
- **Current Expectation**: BATTER_OUT_RUNNERS_ADVANCE ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g3_r2_only_normal_no_error
|
|
- **Scenario**: G3, 2nd, Normal, NO
|
|
- **Current on_base_code**: 2 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 12 (DECIDE_OPPORTUNITY)
|
|
- **Current Expectation**: DECIDE_OPPORTUNITY ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g3_r2_only_infield_in_no_error
|
|
- **Scenario**: G3, 2nd, In, NO
|
|
- **Current on_base_code**: 2 ✅
|
|
- **Current defender_in**: True ✅
|
|
- **Expected Result**: 3 (BATTER_OUT_RUNNERS_ADVANCE)
|
|
- **Current Expectation**: BATTER_OUT_RUNNERS_ADVANCE ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g3_r3_only_infield_in_decide
|
|
- **Scenario**: G3, 3rd, In, NO
|
|
- **Current on_base_code**: 3 ✅
|
|
- **Current defender_in**: True ✅
|
|
- **Expected Result**: 12 (DECIDE_OPPORTUNITY)
|
|
- **Current Expectation**: DECIDE_OPPORTUNITY ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g3_r2_r3_infield_in_decide
|
|
- **Scenario**: G3, 2nd & 3rd, In, NO
|
|
- **Current on_base_code**: 6 ✅
|
|
- **Current defender_in**: True ✅
|
|
- **Expected Result**: 12 (DECIDE_OPPORTUNITY)
|
|
- **Current Expectation**: DECIDE_OPPORTUNITY ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g3_loaded_normal_no_error
|
|
- **Scenario**: G3, Loaded, Normal, NO
|
|
- **Current on_base_code**: 7 ✅
|
|
- **Current defender_in**: False ✅
|
|
- **Expected Result**: 3 (BATTER_OUT_RUNNERS_ADVANCE)
|
|
- **Current Expectation**: BATTER_OUT_RUNNERS_ADVANCE ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
### test_g3_loaded_infield_in_no_error
|
|
- **Scenario**: G3, Loaded, In, NO
|
|
- **Current on_base_code**: 7 ✅
|
|
- **Current defender_in**: True ✅
|
|
- **Expected Result**: 11 (BATTER_SAFE_LEAD_OUT)
|
|
- **Current Expectation**: BATTER_SAFE_LEAD_OUT ✅
|
|
- **Status**: ✅ CORRECT
|
|
|
|
---
|
|
|
|
## Summary of Test Failures
|
|
|
|
**Total Tests with Wrong Expectations**: 6
|
|
|
|
### Tests That Need Fixing:
|
|
|
|
1. **test_g1_r1_only_infield_in_no_error**
|
|
- Current: BATTER_OUT_RUNNERS_ADVANCE (3)
|
|
- Should be: DOUBLE_PLAY_AT_SECOND (2)
|
|
|
|
2. **test_g1_r1_r2_normal_no_error**
|
|
- Current: BATTER_OUT_RUNNERS_ADVANCE (3)
|
|
- Should be: CONDITIONAL_DOUBLE_PLAY (13)
|
|
|
|
3. **test_g1_r1_r2_infield_in_no_error**
|
|
- Current: BATTER_SAFE_FORCE_OUT_AT_SECOND (4)
|
|
- Should be: DOUBLE_PLAY_AT_SECOND (2)
|
|
|
|
4. **test_g1_r3_only_normal_no_error**
|
|
- Current: CONDITIONAL_DOUBLE_PLAY (13)
|
|
- Should be: BATTER_OUT_RUNNERS_ADVANCE (3)
|
|
|
|
5. **test_g1_r3_only_infield_in_no_error**
|
|
- Current: BATTER_OUT_RUNNERS_ADVANCE (3)
|
|
- Should be: BATTER_OUT_RUNNERS_HOLD (1)
|
|
|
|
6. **test_g2_r1_r2_normal_no_error**
|
|
- Current: CONDITIONAL_ON_MIDDLE_INFIELD (5)
|
|
- Should be: BATTER_SAFE_FORCE_OUT_AT_SECOND (4)
|
|
|
|
7. **test_g2_r3_only_infield_in_no_error**
|
|
- Current: BATTER_OUT_RUNNERS_ADVANCE (3)
|
|
- Should be: BATTER_OUT_RUNNERS_HOLD (1)
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
1. ✅ Validation table complete
|
|
2. ⏳ Fix the 7 tests with wrong expectations
|
|
3. ⏳ Re-run test suite to verify 59/59 passing
|
|
4. ⏳ Create git commit with ALL fixes (on_base_code + expectations)
|