Archery Apprentice - Checkpoint Investigation Findings

Investigation Date: October 4, 2025 Current Project Status: 97% Complete Purpose: Pre-next-epoch architecture and documentation audit

Note: This is a condensed version. Full document: docs/CHECKPOINT_FINDINGS.md (962 lines)

Update (Oct 7, 2025): Since this analysis, significant progress has been made. See Implementation-Status-10-07-25 for current status.


Executive Summary

Status: Investigation Phases 1-4 complete Critical Findings: 7 major architectural issues identified Recommendation: Address critical tech debt before next major features

Critical Issues Summary

  1. 🚨 LiveScoringViewModel: 2,808 lines (+60% growth) - URGENT extraction needed

    • Update: ✅ 60% complete (3/5 services extracted, 2,304 lines as of Oct 7)
  2. 🚨 RoundViewModel refactoring created NEW god class (LiveScoringViewModel)

    • Discovery: Refactoring WAS executed - 7 ViewModels successfully extracted from 3,000-line monolith
    • Problem: LiveScoringViewModel became replacement god class
  3. 🚨 Documentation severely outdated (10+ files claiming complete features are “planned”)

  4. 🚨 N+1 query pattern confirmed (31 queries for 30-end round instead of 1)

  5. 🚨 Repository god classes (5,959 total lines across TournamentRepository + RoundRepository)

  6. 🚨 Tie-breaking NOT implemented (docs claim complete, but xCount/tenCount fields missing)

  7. 🚨 Average score always 0.0 (calculation never executed during scoring)

Phase Progress

  • ✅ Phase 1: Documentation Audit - COMPLETE
  • ✅ Phase 2: Database Architecture - COMPLETE
  • ✅ Phase 3: God Class Analysis (LiveScoringViewModel) - COMPLETE
  • ✅ Phase 4: Feature Validation - COMPLETE
  • ✅ Phase 5: Tech Debt Consolidation - COMPLETE

Critical Finding #1: LiveScoringViewModel Explosive Growth

Baseline: 1,753 lines (CLAUDE.md) Current (Oct 4): 2,808 lines (+1,055 lines, +60% growth) Current (Oct 7): 2,304 lines (504 lines extracted + 109 deduplication)

Key Findings

  • 12 distinct architectural domains identified (should be 2-3!)
  • 66 methods (should be <30)
  • 24 StateFlow properties (should be <12)
  • Tournament Phases 2.2-4.1 added ~1,300 lines without refactoring
  • Complexity Score: 9.5/10 (CRITICAL)

Extraction Progress (Per Implementation-Status-10-07-25)

Completed Extractions (Oct 2025):

  • ✅ TournamentSyncService (556 lines) - Oct 5
  • ✅ ScoreConflictResolutionService (262 lines)
  • ✅ EndCompletionService (400 lines) - Oct 6
  • ✅ Code Deduplication (109 lines removed) - Oct 7

Remaining Work:

  • ⏳ TournamentRoundLifecycleService (~200 lines)
  • ⏳ StatisticsAggregationService (~150 lines)

Target: 1,200-1,400 lines (50-57% reduction) Current Progress: 62% complete (18% size reduction achieved)

Pattern Analysis: Why It Grew

  1. Incremental Addition: Each tournament phase added 200-400 lines directly
  2. “Just One More Method” Syndrome: Small additions accumulated to +1,055 lines
  3. State Proliferation: Each feature added its own StateFlow without consolidation
  4. No Extraction Discipline: “Refactor later” → Never happens

Key Lesson vs RoundViewModel

  • RoundViewModel: 3 planning docs (1,302 lines), ZERO extraction work initially
  • LiveScoringViewModel: MUST EXECUTE, NOT JUST PLAN!
  • Proven Pattern: Copy-delegate-validate works (3/3 successful extractions)

See LiveScoringVM-Analysis for comprehensive 584-line analysis.


Critical Finding #2: RoundViewModel Refactoring WAS Executed

MAJOR DISCOVERY: Refactoring actually happened - just undocumented!

What Actually Occurred

Original RoundViewModel: ~3,000+ lines (single monolith god class)

Successfully extracted to 8 ViewModels: Total 5,987 lines distributed architecture

  • RoundViewModel: 2,058 lines (core orchestration - legitimate coordination)
  • LiveScoringViewModel: 1,753 linesNEW GOD CLASS CREATED!
  • RoundAnalyticsViewModel: 605 lines ✅
  • RoundManagementViewModel: 495 lines ✅
  • RoundCreationViewModel: 480 lines ✅
  • RoundDisplayViewModel: 216 lines ✅
  • RoundNavigationViewModel: 192 lines ✅
  • RoundScoringViewModel: 187 lines ✅

The Problem: Shifted, Not Solved

  • ✅ Successfully extracted 7 specialized ViewModels
  • ❌ Created LiveScoringViewModel as replacement god class
  • ❌ LiveScoringViewModel grew from 1,753 → 2,808 lines (+60%)
  • ⚠️ RoundViewModel still 2,058 lines (but legitimate - cross-ViewModel coordination)

Why Documentation Shows “Zero Execution”

September 22 planning docs were created AFTER initial extraction:

  • Docs analyze 2,058-line RoundViewModel (post-extraction state)
  • All recommend “further extraction” unaware major work already done
  • No documentation of the ACTUAL extraction that created 7 ViewModels
  • Planning docs conflict because they’re analyzing already-refactored code!

See Refactoring-Reality-Check for detailed analysis.


Critical Finding #3: README Severely Outdated

Issue: README stops at July 2025, omits 3 months of major work

Missing Features:

  • Tournament system (Phases 1-5)
  • Firebase real-time sync
  • Multi-device scoring
  • Cache system (5-10x performance)
  • Guest participants
  • Network status monitoring
  • 97% completion status

Impact: HIGH - New developers/users get wrong picture Recommendation: Major README rewrite to reflect current state


Critical Finding #4: N+1 Query Pattern Confirmed ✅ FIXED

Status (Oct 4): CONFIRMED - Active performance issue Status (Oct 7): ✅ FIXED per Tech-Debt

Original Issue

Location: RoundRepository.kt:98-102, 138-143

Performance Impact:

  • 30-end round: 31 queries (1 + 30) instead of 1
  • 60-end round: 61 queries (1 + 60) instead of 1
  • Multiplied by number of participants in multi-participant rounds

Fix Applied

  • Refactored getRoundWithDetails() to use optimized JOIN queries
  • Created similar optimized query for getEndsWithArrowsForParticipant()
  • Result: 30-60x query reduction for typical rounds

Critical Finding #5: Repository God Classes

Total Repository Code: 5,959 lines

Repository Size Analysis

Tournament Repositories:

TournamentRepository.kt (interface): 395 lines, 51 methods 🚨
├── OfflineTournamentRepository.kt: 908 lines
├── FirebaseTournamentRepository.kt: 1,707 lines 🚨🚨
└── HybridTournamentRepository.kt: 1,506 lines 🚨🚨
Total: 4,516 lines

Round Repository:

RoundRepository.kt: 1,443 lines 🚨

Comparison to Industry Standards

  • Good repository: 200-400 lines, 10-15 methods
  • TournamentRepository interface: 395 lines, 51 methods (3.4x too many!)
  • FirebaseTournamentRepository: 1,707 lines (4.3x too large!)
  • HybridTournamentRepository: 1,506 lines (3.8x too large!)
  • RoundRepository: 1,443 lines (3.6x too large!)

Split TournamentRepository into 4 focused repositories:

  1. TournamentCrudRepository (~300 lines)
  2. TournamentSyncRepository (~400 lines)
  3. TournamentScoreRepository (~500 lines)
  4. TournamentAnalyticsRepository (~200 lines)

Split RoundRepository into 3 focused repositories:

  1. RoundCrudRepository (~400 lines)
  2. RoundScoringRepository (~500 lines)
  3. RoundStatisticsRepository (~400 lines)

Effort Estimate: 6-7 weeks Priority: HIGH (but lower than LiveScoringViewModel extraction)


Critical Finding #6: Tie-Breaking Not Actually Implemented ✅ FIXED

Status (Oct 4): PLANNING DOCS CLAIM COMPLETE - ACTUALLY NOT IMPLEMENTED Status (Oct 7): ✅ FIXED per Tech-Debt

Original Issue

Documentation Claims: “Tie-breaking logic: Score → X count → 10 count - COMPLETE”

Actual Reality:

  • TournamentParticipant had NO xCount or tenCount fields
  • Firestore orderBy("currentScore") without secondary sort key
  • When two participants have same score, order was NON-DETERMINISTIC
  • Different devices could see different order for tied participants

Fix Applied

  1. Added xCount: Int and tenCount: Int to TournamentParticipant model
  2. Track X and 10 counts during score submission
  3. Updated Firestore query to use proper tie-breaking order
  4. Created Firestore composite indexes for multi-field sorting

Critical Finding #7: Average Score Never Calculated ✅ FIXED

Status (Oct 4): BUG CONFIRMED - averageScore field never updated during scoring Status (Oct 7): ✅ FIXED per Tech-Debt

Original Issue

User Report: “Avg” field on LiveLeaderboardCard displays 0.0 for participants

Root Cause:

  • TournamentParticipant.averageScore defaults to 0.0
  • Score submission never calculated or updated averageScore
  • Leaderboard displayed default 0.0 value

Fix Applied

Added averageScore calculation to score submission:

val newAverageScore = if (newArrowsShot > 0) {
    newTotal.toDouble() / newArrowsShot
} else {
    0.0
}

Database Index Analysis

Overall Status: GOOD coverage, 2 missing composite indexes

Existing Indexes: 14 indexes implemented across 3 core entities ✅

Missing Indexes (Performance Opportunities):

  1. Arrow Scores Equipment Performance (MEDIUM PRIORITY)

    • Suggested: Composite index (bowSetupId, scoredAt)
    • Estimated improvement: 2-5x for equipment queries
  2. Rounds Historical Queries (LOW PRIORITY)

    • Suggested: Composite index (status, createdAt DESC)
    • Impact: Minor - most queries use fields separately

Index Coverage Assessment: 90% ✅


God Class Scorecard (Oct 4 Snapshot)

ClassCurrent LinesChange from BaselineStatus
LiveScoringViewModel2,808+1,055 (+60%)🚨 CRITICAL
RoundViewModel2,079+21 (+1%) from 2,058*🟡 STABLE*
ActiveScoringScreen1,958+62 (+3%)🟠 HIGH
TOTAL6,845+1,138 (+20%)SEVERE

*RoundViewModel baseline was 2,058 AFTER successful extraction of 7 ViewModels from original 3,000-line monolith

Update (Oct 7):

  • LiveScoringViewModel: 2,304 lines (down from 2,808)
  • Progress: 18% reduction achieved, 62% of extraction plan complete

Documentation Audit Summary

Files Reviewed: 41/41 (100%) ✅

Severely Outdated Docs: 10+

  • README (stops at July 2025)
  • tournament/README.md (claims features “in progress” that are complete)
  • TOURNAMENT_SYSTEM_DOCUMENTATION.md (8-9 months old)
  • 3 RoundViewModel planning docs analyzing already-refactored code
  • Firebase/README.md (shows features as “planned” that are complete)

Historical Documents Needing Archival:

  • NETWORK_SCORING_SESSION_1_SUMMARY.md
  • NETWORK_SCORING_SESSION_2_SUMMARY.md
  • PHASE_2_TOURNAMENT_DISCOVERY.md
  • Phase 2 cache docs (3 files)

Consolidation Needed:

  • 3 RoundViewModel docs → 1 status doc documenting successful extraction

Key Discoveries

  1. RoundViewModel refactoring WAS executed!

    • Successfully extracted 7 ViewModels from 3,000-line monolith
    • Created distributed architecture: 8 ViewModels totaling 5,987 lines
    • But created LiveScoringViewModel as replacement god class
  2. LiveScoringViewModel explosive growth

    • Grew 60% (1,753 → 2,808) from tournament features
    • Now being addressed: 3/5 services extracted (60% complete)
  3. Documentation crisis

    • 10+ severely outdated docs
    • Planning docs analyzing wrong state
    • Major features undocumented in README
  4. Critical bugs identified and fixed

    • N+1 query pattern → Fixed
    • Tie-breaking missing → Implemented
    • Average score calculation → Fixed

Immediate Action Items

Priority 1: URGENT (Before Any New Features) - ⏳ IN PROGRESS

LiveScoringViewModel Refactoring

  • Status (Oct 4): 2,808 lines (60% growth)
  • Status (Oct 7): 2,304 lines (18% reduction, 62% complete)
  • Target: <1,500 lines
  • Remaining: 2 services to extract (~350 lines)
  • Timeline: 1-2 weeks to completion

Priority 2: HIGH - 🔄 PARTIALLY COMPLETE

  1. README Major Rewrite - ⏳ Pending
  2. Bug Fixes - ✅ Complete (N+1, tie-breaking, averages)
  3. Documentation Consolidation - ⏳ Pending

Priority 3: MEDIUM - ⏳ PENDING

  1. Repository god class refactoring (6-7 weeks)
  2. Complete documentation audit updates
  3. Archive historical documents

Lessons Learned

Pattern: Documentation Debt

Issue: Completed phases leave reference docs in root directory Solution: Create docs/completed-phases/ or docs/COLD_STORAGE/ structure

Pattern: Refactoring Planning Debt

Issue: Extensive refactoring plans created but not executed Example: RoundViewModel (3 docs, 1,302 lines of planning analyzing wrong code) Success: LiveScoringViewModel EXECUTION pattern works (3/3 extractions successful)

Pattern: God Class Migration

Issue: Extracting god class creates NEW god class Example: RoundViewModel → LiveScoringViewModel Solution: Be aware when creating “coordinator” ViewModels - they can become new bottlenecks


Investigation Phases Completed

  • Phase 1: Documentation Audit (41/41 files reviewed)
  • Phase 2: Database Architecture Assessment
  • Phase 3: God Class Analysis (LiveScoringViewModel deep dive)
  • Phase 4: Feature Validation (found 3 critical bugs)
  • Phase 5: Tech Debt Consolidation

Current Status (Oct 7, 2025)

Since this checkpoint investigation:

Completed:

  • ✅ 3 of 7 critical issues FIXED (N+1 queries, tie-breaking, average scores)
  • ✅ LiveScoringViewModel extraction 60% complete (3/5 services)
  • ✅ Code deduplication (109 lines removed via delegation pattern)
  • ✅ All 1,879 tests passing

In Progress:

  • 🔄 LiveScoringViewModel extraction (2 services remaining)
  • 🔄 Documentation updates

Pending:

  • ⏳ Repository god class refactoring
  • ⏳ README major rewrite
  • ⏳ Documentation consolidation

See Implementation-Status-10-07-25 for detailed current status.


Investigation Date: October 4, 2025 Last Updated: October 7, 2025 (Progress tracking) Status: Historical reference - Most critical issues addressed


Full Source: docs/CHECKPOINT_FINDINGS.md (962 lines)

Related Documentation: