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>
354 lines
12 KiB
Markdown
354 lines
12 KiB
Markdown
# Phase 3D Critical Bug Fix - on_base_code Mapping Error
|
|
|
|
**Status**: ✅ COMPLETE
|
|
**Date Discovered**: 2025-11-02
|
|
**Date Fixed**: 2025-11-02
|
|
**Severity**: CRITICAL - All advancement calculations were wrong
|
|
**Progress**: 100% Complete (59/59 X-Check tests passing, 381/386 total core/config tests passing)
|
|
|
|
---
|
|
|
|
## The Bug
|
|
|
|
The initial implementation **incorrectly treated `on_base_code` as a bit field** when it is actually a **sequential mapping**.
|
|
|
|
### ❌ WRONG Implementation (Original)
|
|
```python
|
|
# Treated as bit field
|
|
r1_on = (on_base_code & 1) != 0 # bit 0
|
|
r2_on = (on_base_code & 2) != 0 # bit 1
|
|
r3_on = (on_base_code & 4) != 0 # bit 2
|
|
|
|
# This caused:
|
|
# Code 3 (0b011) → R1 + R2 (WRONG! Should be R3 only)
|
|
# Code 4 (0b100) → R3 only (WRONG! Should be R1+R2)
|
|
```
|
|
|
|
### ✅ CORRECT Implementation (Fixed)
|
|
```python
|
|
# Sequential mapping
|
|
on_base_mapping = {
|
|
0: (False, False, False), # Empty
|
|
1: (True, False, False), # R1
|
|
2: (False, True, False), # R2
|
|
3: (False, False, True), # R3
|
|
4: (True, True, False), # R1+R2
|
|
5: (True, False, True), # R1+R3
|
|
6: (False, True, True), # R2+R3
|
|
7: (True, True, True), # Loaded
|
|
}
|
|
r1_on, r2_on, r3_on = on_base_mapping.get(on_base_code, (False, False, False))
|
|
```
|
|
|
|
---
|
|
|
|
## What Has Been Fixed ✅
|
|
|
|
### 1. Table Entry Remapping (COMPLETE)
|
|
**Files Modified**:
|
|
- `backend/app/core/x_check_advancement_tables.py`
|
|
|
|
**Changes**:
|
|
- ✅ G1 table: Swapped codes 3 and 4 entries
|
|
- ✅ G2 table: Swapped codes 3 and 4 entries
|
|
- ✅ G3 table: Swapped codes 3 and 4 entries
|
|
- ✅ Updated all comments to reflect correct mapping
|
|
|
|
**Result**: All 240 table entries now use correct base situation codes.
|
|
|
|
### 2. Decoding Logic Fixed (COMPLETE)
|
|
**Functions Updated**:
|
|
- ✅ `build_advancement_from_code()` - Lines 521-533
|
|
- ✅ `build_flyball_advancement_with_error()` - Lines 644-655
|
|
|
|
**Changes**: Both functions now use mapping dictionary instead of bit field math.
|
|
|
|
### 3. Documentation Updated (COMPLETE)
|
|
**Changes**:
|
|
- ✅ Updated header comments in `x_check_advancement_tables.py` (lines 40-48)
|
|
- ✅ Clarified that mapping is NOT a bit field
|
|
|
|
---
|
|
|
|
## What Still Needs Fixing ⚠️
|
|
|
|
### Test Expectation Updates (✅ COMPLETE)
|
|
|
|
**File**: `backend/tests/unit/core/test_x_check_advancement_tables.py`
|
|
|
|
**Status**: All 13 test failures fixed. All tests now use correct mapping.
|
|
|
|
#### Category A: Table Lookup Tests (7 failures)
|
|
|
|
Tests that use wrong `on_base_code` values:
|
|
|
|
1. **test_g1_r1_r2_normal_no_error** (Line ~99)
|
|
- Current: `on_base_code=3` (expects R1+R2)
|
|
- Fix: Change to `on_base_code=4`
|
|
- Status: ✅ FIXED
|
|
|
|
2. **test_g1_r1_r2_infield_in_no_error** (Line ~107)
|
|
- Current: `on_base_code=3`
|
|
- Fix: Change to `on_base_code=4`
|
|
- Status: ✅ FIXED
|
|
|
|
3. **test_g1_r3_only_normal_no_error** (Line ~116)
|
|
- Current: `on_base_code=4` (expects R3)
|
|
- Fix: Change to `on_base_code=3`
|
|
- Status: ✅ FIXED
|
|
|
|
4. **test_g1_r3_only_infield_in_no_error** (Line ~125)
|
|
- Current: `on_base_code=4`
|
|
- Fix: Change to `on_base_code=3`
|
|
- Status: ✅ FIXED
|
|
|
|
5. **test_g2_r1_r2_infield_in_no_error** (Line ~187)
|
|
- Current: `on_base_code=3`
|
|
- Fix: Change to `on_base_code=4`
|
|
- Status: ✅ FIXED
|
|
|
|
6. **test_g2_r3_only_infield_in_no_error** (Line ~203)
|
|
- Current: `on_base_code=4`
|
|
- Fix: Change to `on_base_code=3`
|
|
- Status: ✅ FIXED
|
|
|
|
7. **test_g3_r3_only_infield_in_decide** (Line ~267)
|
|
- Current: `on_base_code=4`
|
|
- Fix: Change to `on_base_code=3`
|
|
- Status: ✅ FIXED
|
|
|
|
#### Category B: Error Advancement Tests (3 failures)
|
|
|
|
Tests that expect wrong number of runs due to incorrect runner positions:
|
|
|
|
8. **test_e1_runner_on_third** (Line ~186)
|
|
- Current: `on_base_code=4` (expects R3, should score 1 run)
|
|
- Issue: With wrong mapping, code 4 = R3, but logic decoded it as empty
|
|
- Fix: Change to `on_base_code=3`
|
|
- Status: ✅ FIXED
|
|
|
|
9. **test_flyball_e1_runner_on_third** (Line ~334)
|
|
- Current: `on_base_code=4`
|
|
- Fix: Change to `on_base_code=3`
|
|
- Status: ✅ FIXED
|
|
|
|
10. **test_scenario_flyball_to_outfield_runner_tags** (Line ~769)
|
|
- Current: `on_base_code=4`
|
|
- Fix: Change to `on_base_code=3`
|
|
- Status: ✅ FIXED
|
|
|
|
#### Category C: Integration Tests (3 failures)
|
|
|
|
Tests that combine wrong codes with wrong expectations:
|
|
|
|
11. **test_x_check_g1_integration** (Line ~548)
|
|
- Current: `on_base_code=3, defender_in=True, error_result='E1'`
|
|
- Issue: Expects 0 runs, but gets 1 run (R3 scores)
|
|
- Analysis: Test says "runners on 1st and 2nd" but uses code 3 (R3 only)
|
|
- Fix: Change to `on_base_code=4` for R1+R2, update expectation
|
|
- Status: ✅ FIXED
|
|
|
|
12. **test_x_check_g3_integration** (Line ~576)
|
|
- Current: `on_base_code=4, defender_in=False, error_result='E3'`
|
|
- Issue: Expects 1 run, but gets 2 runs
|
|
- Analysis: Test says "runner on 3rd" but uses code 4 (R1+R2)
|
|
- Fix: Change to `on_base_code=3` for R3 only, update to expect 1 run
|
|
- Status: ✅ FIXED
|
|
|
|
13. **test_scenario_runner_on_third_two_outs_infield_in** (Line ~758)
|
|
- Current: `on_base_code=4, defender_in=True`
|
|
- Issue: Test description says "Runner on 3rd" but uses code 4
|
|
- Fix: Change to `on_base_code=3`
|
|
- Status: ✅ FIXED
|
|
|
|
---
|
|
|
|
## Systematic Fix Checklist
|
|
|
|
### Step 1: Global Search & Replace ✅ COMPLETE
|
|
```bash
|
|
# Search for all test uses of on_base_code
|
|
grep -n "on_base_code=" tests/unit/core/test_x_check_advancement_tables.py
|
|
|
|
# Pattern to identify:
|
|
# - Tests mentioning "R3" or "3rd" with code=4 → change to code=3
|
|
# - Tests mentioning "R1+R2" or "1st and 2nd" with code=3 → change to code=4
|
|
# - Tests mentioning "R1+R3" or "1st and 3rd" with code=5 → keep as is (correct)
|
|
# - Tests mentioning "R2+R3" or "2nd and 3rd" with code=6 → keep as is (correct)
|
|
```
|
|
|
|
### Step 2: Update Test Expectations ✅ COMPLETE
|
|
|
|
For each test:
|
|
1. ✅ Read test docstring to understand intended scenario
|
|
2. ✅ Map scenario to correct on_base_code using table:
|
|
- Empty → 0
|
|
- R1 only → 1
|
|
- R2 only → 2
|
|
- **R3 only → 3** (NOT 4!)
|
|
- **R1+R2 → 4** (NOT 3!)
|
|
- R1+R3 → 5
|
|
- R2+R3 → 6
|
|
- Loaded → 7
|
|
3. ✅ Update `on_base_code=X` in test
|
|
4. ✅ Update assertion expectations (runs_scored, movements count)
|
|
|
|
### Step 3: Verify Table Entries ✅ COMPLETE
|
|
|
|
Double-check table entries against source images:
|
|
- ✅ G1 table codes 3-6
|
|
- ✅ G2 table codes 3-6
|
|
- ✅ G3 table codes 3-6
|
|
|
|
---
|
|
|
|
## Test Execution Plan
|
|
|
|
### Test Results (✅ COMPLETE):
|
|
```bash
|
|
# Run X-Check tests
|
|
pytest tests/unit/core/test_x_check_advancement_tables.py -v
|
|
# Result: ✅ 59/59 passing
|
|
|
|
# Run all core/config tests
|
|
pytest tests/unit/core/ tests/unit/config/ -v
|
|
# Result: ✅ 381/386 passing (5 pre-existing failures, unrelated to this fix)
|
|
```
|
|
|
|
**Pre-existing failures (not part of this fix)**:
|
|
1. `test_dice.py::test_get_rolls_since` - timestamp filtering issue
|
|
2. `test_runner_advancement.py::test_x_check_f2_returns_valid_result` - expectation mismatch
|
|
3. `test_league_configs.py::test_pd_api_url` - minor string difference
|
|
4-5. `test_result_charts.py` - Mock comparison issues (2 tests)
|
|
|
|
---
|
|
|
|
## Files Modified (✅ COMPLETE)
|
|
|
|
1. ✅ `backend/app/core/x_check_advancement_tables.py`
|
|
- Lines 40-48: Documentation
|
|
- Lines 96-160: G1 table (swapped 3↔4)
|
|
- Lines 204-268: G2 table (swapped 3↔4)
|
|
- Lines 312-376: G3 table (swapped 3↔4)
|
|
- Lines 521-533: `build_advancement_from_code()` decoder
|
|
- Lines 644-655: `build_flyball_advancement_with_error()` decoder
|
|
|
|
2. ✅ `backend/tests/unit/core/test_x_check_advancement_tables.py`
|
|
- All 13 test failures fixed
|
|
- Updated on_base_code values and assertions in all failing tests
|
|
|
|
---
|
|
|
|
## Completion Summary
|
|
|
|
### ✅ All Tasks Complete
|
|
|
|
**Date Completed**: 2025-11-02
|
|
|
|
**What Was Fixed** (Two Critical Bugs):
|
|
|
|
### Bug #1: on_base_code Mapping (Sequential vs Bit Field)
|
|
1. ✅ G1/G2/G3 table entries (swapped codes 3↔4 throughout)
|
|
2. ✅ Decoding logic in `build_advancement_from_code()`
|
|
3. ✅ Decoding logic in `build_flyball_advancement_with_error()`
|
|
4. ✅ All 13 test on_base_code values corrected
|
|
|
|
### Bug #2: Wrong Expected Results in Tables (Tables vs Charts)
|
|
5. ✅ Fixed 7 incorrect table entries in G1_ADVANCEMENT_TABLE and G2_ADVANCEMENT_TABLE
|
|
- G1 Code 1, Infield In: Changed 3→2
|
|
- G1 Code 3, Normal: Changed 13→3
|
|
- G1 Code 3, Infield In: Changed 3→1
|
|
- G1 Code 4, Normal: Changed 3→13
|
|
- G1 Code 4, Infield In: Changed 4→2
|
|
- G2 Code 3, Infield In: Changed 3→1
|
|
- G2 Code 4, Normal: Changed 5→4
|
|
6. ✅ Fixed 7 test expectations to match official charts
|
|
7. ✅ Full codebase scan - no bit field operations found
|
|
8. ✅ Verified all on_base_code usage uses correct sequential mapping
|
|
|
|
**Test Results**:
|
|
- ✅ **59/59 X-Check advancement tests passing** (100% success!)
|
|
- ✅ All table entries validated against official rulebook charts (Images #1-3)
|
|
- ✅ All on_base_code values validated against correct mapping (0-7 sequential)
|
|
|
|
**Verification**:
|
|
- ✅ No bit field operations (`on_base_code & N`) found in codebase
|
|
- ✅ All code uses correct sequential mapping (dictionary lookup)
|
|
- ✅ `runner_advancement.py` correctly identifies code 3 as R3, code 4 as R1+R2
|
|
- ✅ `x_check_advancement_tables.py` uses mapping dictionary throughout
|
|
- ✅ All table data matches official G1/G2/G3 charts from rulebook
|
|
|
|
---
|
|
|
|
## Reference: Correct Mapping Table
|
|
|
|
| Code | Situation | R1 | R2 | R3 | Binary (for reference only) |
|
|
|------|-----------|----|----|----|-----------------------------|
|
|
| 0 | Empty | ❌ | ❌ | ❌ | (not bit field!) |
|
|
| 1 | R1 | ✅ | ❌ | ❌ | (not bit field!) |
|
|
| 2 | R2 | ❌ | ✅ | ❌ | (not bit field!) |
|
|
| 3 | R3 | ❌ | ❌ | ✅ | (not bit field!) |
|
|
| 4 | R1+R2 | ✅ | ✅ | ❌ | (not bit field!) |
|
|
| 5 | R1+R3 | ✅ | ❌ | ✅ | (not bit field!) |
|
|
| 6 | R2+R3 | ❌ | ✅ | ✅ | (not bit field!) |
|
|
| 7 | Loaded | ✅ | ✅ | ✅ | (not bit field!) |
|
|
|
|
**REMEMBER**: This is a simple lookup table, NOT bit field math!
|
|
|
|
---
|
|
|
|
## Lessons Learned
|
|
|
|
1. **Always validate assumptions** - The bit field assumption seemed logical but was completely wrong
|
|
2. **Test with real data early** - Would have caught this immediately with actual game scenarios
|
|
3. **Document data structures clearly** - Mapping should have been documented in multiple places
|
|
4. **User validation is critical** - User spotted the issue immediately when they saw it
|
|
|
|
---
|
|
|
|
## Communication Notes for User
|
|
|
|
When presenting the fix:
|
|
- ✅ Be transparent about the error
|
|
- ✅ Show exactly what was wrong and what was fixed
|
|
- ✅ Provide test results showing correctness
|
|
- ✅ Give user easy way to spot-check (updated test expectations)
|
|
- ✅ Demonstrate one or two manual examples working correctly
|
|
|
|
---
|
|
|
|
**File Status**: ✅ COMPLETE - Bug fix finished
|
|
**Last Updated**: 2025-11-02
|
|
**Completion Date**: 2025-11-02
|
|
|
|
---
|
|
|
|
## Ready for Commit
|
|
|
|
All fixes complete and verified. Ready to create git commit with the following changes:
|
|
|
|
**Files Modified**:
|
|
1. `backend/app/core/x_check_advancement_tables.py`
|
|
- Fixed on_base_code mapping in decoder functions (3↔4 swap)
|
|
- Fixed 7 incorrect table entries against official charts
|
|
- Updated documentation comments
|
|
|
|
2. `backend/tests/unit/core/test_x_check_advancement_tables.py`
|
|
- Fixed 13 test on_base_code values (3↔4 corrections)
|
|
- Fixed 7 test expected results to match charts
|
|
- Updated test docstrings with correct expectations
|
|
|
|
3. `backend/app/core/play_resolver.py`
|
|
- Updated `_resolve_x_check()` to use `dice_system.roll_fielding()`
|
|
- Improved dice audit trail (all rolls tracked with roll_id, position)
|
|
- Automatic error_total calculation (no manual 3d6 addition)
|
|
|
|
4. `.claude/implementation/PHASE_3D_CRITICAL_FIX.md`
|
|
- Complete documentation of both bugs and all fixes
|
|
|
|
**Commit Summary**:
|
|
- Fixed critical on_base_code mapping bug (sequential vs bit field)
|
|
- Fixed 7 table entries that didn't match official rulebook charts
|
|
- All 59 X-Check advancement tests now passing (100%)
|
|
- Both bugs discovered and fixed in same session
|