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>
12 KiB
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)
# 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)
# 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:
-
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
- Current:
-
test_g1_r1_r2_infield_in_no_error (Line ~107)
- Current:
on_base_code=3 - Fix: Change to
on_base_code=4 - Status: ✅ FIXED
- Current:
-
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
- Current:
-
test_g1_r3_only_infield_in_no_error (Line ~125)
- Current:
on_base_code=4 - Fix: Change to
on_base_code=3 - Status: ✅ FIXED
- Current:
-
test_g2_r1_r2_infield_in_no_error (Line ~187)
- Current:
on_base_code=3 - Fix: Change to
on_base_code=4 - Status: ✅ FIXED
- Current:
-
test_g2_r3_only_infield_in_no_error (Line ~203)
- Current:
on_base_code=4 - Fix: Change to
on_base_code=3 - Status: ✅ FIXED
- Current:
-
test_g3_r3_only_infield_in_decide (Line ~267)
- Current:
on_base_code=4 - Fix: Change to
on_base_code=3 - Status: ✅ FIXED
- Current:
Category B: Error Advancement Tests (3 failures)
Tests that expect wrong number of runs due to incorrect runner positions:
-
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
- Current:
-
test_flyball_e1_runner_on_third (Line ~334)
- Current:
on_base_code=4 - Fix: Change to
on_base_code=3 - Status: ✅ FIXED
- Current:
-
test_scenario_flyball_to_outfield_runner_tags (Line ~769)
- Current:
on_base_code=4 - Fix: Change to
on_base_code=3 - Status: ✅ FIXED
- Current:
Category C: Integration Tests (3 failures)
Tests that combine wrong codes with wrong expectations:
-
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=4for R1+R2, update expectation - Status: ✅ FIXED
- Current:
-
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=3for R3 only, update to expect 1 run - Status: ✅ FIXED
- Current:
-
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
- Current:
Systematic Fix Checklist
Step 1: Global Search & Replace ✅ COMPLETE
# 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:
- ✅ Read test docstring to understand intended scenario
- ✅ 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
- ✅ Update
on_base_code=Xin test - ✅ 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):
# 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):
test_dice.py::test_get_rolls_since- timestamp filtering issuetest_runner_advancement.py::test_x_check_f2_returns_valid_result- expectation mismatchtest_league_configs.py::test_pd_api_url- minor string difference 4-5.test_result_charts.py- Mock comparison issues (2 tests)
Files Modified (✅ COMPLETE)
-
✅
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
-
✅
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)
- ✅ G1/G2/G3 table entries (swapped codes 3↔4 throughout)
- ✅ Decoding logic in
build_advancement_from_code() - ✅ Decoding logic in
build_flyball_advancement_with_error() - ✅ All 13 test on_base_code values corrected
Bug #2: Wrong Expected Results in Tables (Tables vs Charts)
- ✅ 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
- ✅ Fixed 7 test expectations to match official charts
- ✅ Full codebase scan - no bit field operations found
- ✅ 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.pycorrectly identifies code 3 as R3, code 4 as R1+R2 - ✅
x_check_advancement_tables.pyuses 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
- Always validate assumptions - The bit field assumption seemed logical but was completely wrong
- Test with real data early - Would have caught this immediately with actual game scenarios
- Document data structures clearly - Mapping should have been documented in multiple places
- 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:
-
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
-
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
-
backend/app/core/play_resolver.py- Updated
_resolve_x_check()to usedice_system.roll_fielding() - Improved dice audit trail (all rolls tracked with roll_id, position)
- Automatic error_total calculation (no manual 3d6 addition)
- Updated
-
.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