strat-gameplay-webapp/.claude/implementation/PHASE_3D_CRITICAL_FIX.md
Cal Corum fb282a5e54 CLAUDE: Fix critical X-Check bugs and improve dice rolling
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>
2025-11-02 23:09:16 -06:00

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