Files
alexei.dolgolyov 828dcf5a08 fix(phase-7): close review notes — hoist anomaly dedup query, drop dead expr
Phase 7 reviewer (Sonnet, combined backend + frontend) flagged 3 🟡 warnings;
two real fixes here, one tracking:

W1 — DetectAnomaliesUseCase had an undocumented N+1: _anomalyRepo.ListAsync
  was called inside ProcessEventAsync, once per event. Hoisted to ExecuteAsync
  before the loop and threaded into ProcessEventAsync as a parameter. The
  per-event slice happens in-memory now. O(N_events) DB round-trips → 1.

W2 — AnomalyDetector.ExtractMatchWinProbabilities had a dead expression
  '(decimal?)null ?? 0m' that always evaluated to 0m. Simplified to
  'drawBet is not null ? rawDraw / total : 0m'. The 0m is never surfaced
  anyway (PDraw in the return uses the same null guard), so behaviour is
  identical.

W3 — PLAN.md row updated with both Phase 7 commit hashes (a6ff368 backend
  + 12208a4 frontend) and review verdict.

Build 0/0, 276 tests still passing.
2026-05-05 13:46:34 +03:00

9.7 KiB
Raw Permalink Blame History

Feature: Initial Implementation (maraphon-app)

Branch: feature/initial-implementation Base branch: main Created: 2026-05-05 Status: 🟡 In Progress Strategy: Big Bang Mode: Automated Execution: Orchestrator Implementer models: Sonnet 4.6 (backend) · Opus (frontend, with frontend-design skill) Reviewer model: Sonnet 4.6

Summary

Build the maraphon-app end-to-end: a Blazor Hybrid (.NET 8 + WPF) sports-betting odds analyzer that scrapes marathonbet.by, persists snapshots in SQLite, exports to Excel matching the customer spec, and detects coefficient-flip anomalies. Architecture is Clean Architecture with all UI in a Razor Class Library so the host can later swap to ASP.NET Core Blazor Server with no UI rewrite. RU + EN localization, every variable parameter configurable.

Build & Test Commands

  • Build: dotnet build Marathon.sln
  • Test: dotnet test Marathon.sln
  • Lint: dotnet format Marathon.sln --verify-no-changes
  • Run: dotnet run --project src/Marathon.Hosts.WpfBlazor

Big Bang strategy: Build/tests are NOT run for intermediate phases (Phases 08). The full build + test suite must pass at Phase 9 before final review. An exception: a dotnet build compile-only smoke check is allowed after each phase to catch syntax/type errors early — this is faster than running tests and consistent with Big Bang ("we don't run tests until the end").

Phases

  • Phase 0: Scraping spike (research, throwaway) [domain: backend] → subplan
  • Phase 1: Solution skeleton + Domain model [domain: backend] → subplan
  • Phase 2: Infrastructure — Storage [domain: backend] → subplan
  • Phase 3: Infrastructure — Scraping [domain: backend] → subplan
  • Phase 4: Application layer + Background workers [domain: backend] → subplan
  • Phase 5: Blazor Hybrid host + Theme + i18n [domain: frontend] → subplan
  • Phase 6: Event browsing UI [domain: frontend] → subplan
  • Phase 7: Anomaly detection [domain: fullstack] → subplan
  • Phase 8: Results loader [domain: fullstack] → subplan
  • Phase 9: Packaging + polish (final phase — full build + tests required) [domain: fullstack] → subplan

Parallelization Plan (Orchestrator mode)

Round Phases Notes
1 Phase 0 Spike — gating research, no parallelism
2 Phase 1 Domain — must finish before Phases 2/3/5
3 Phases 2, 3, 5 in parallel Storage, Scraping, UI Shell — disjoint files
4 Phase 4 Application + Workers — depends on 2 + 3
5 Phase 6 Event UI — depends on 4 + 5
6 Phase 7 Anomaly detection — depends on 6
7 Phase 8 Results loader — depends on 6
8 Phase 9 Packaging — final, runs full build + tests

Phase Progress Log

Phase Domain Status Review Build Committed
Phase 0: Scraping spike backend Done ⚠️ Pass with notes (Sonnet) ⏭️ N/A (research) 070e34b
Phase 1: Solution + Domain backend Done ⚠️ Pass with notes (Sonnet) Build OK + 96/96 Domain tests 61114ea
Phase 2: Storage backend Done ⚠️ Pass with notes (Sonnet, combined batch) Build OK + 77/77 Infra tests batch (e4d8476…686550d…+)
Phase 3: Scraping backend Done ⚠️ Pass with notes (Sonnet, combined batch) Build OK + 77/77 Infra tests batch (e4d8476…686550d…+)
Phase 4: Application + Workers backend Done ⚠️ Pass with notes (Sonnet) Build OK + 202/202 tests 2acbaa5
Phase 5: Host + Theme + i18n frontend Done ⚠️ Pass with notes (Sonnet, combined batch) Build OK + 11/11 UI tests batch (e4d8476…686550d…+)
Phase 6: Event browsing UI frontend Done ⚠️ Pass with notes (Sonnet) Build OK + 228/228 tests 553db2b
Phase 7: Anomaly detection fullstack Done ⚠️ Pass with notes (Sonnet) Build OK + 276/276 tests a6ff368 + 12208a4
Phase 8: Results loader fullstack Not Started ⏭️ Big Bang
Phase 9: Packaging + polish fullstack Not Started

Final Review

  • Comprehensive code review (final-reviewer agent)
  • Security review (auth N/A, but covers scraping HttpClient, file I/O, user input)
  • Full build passes
  • Full test suite passes
  • User merge approval
  • Merged to main

Resume Notes (2026-05-05 — paused at end of parallel batch P2/P3/P5)

Where we left off: The parallel batch (Phases 2, 3, 5) completed code-wise. Phase 5 was killed near the end of its "verify build" step. All files are committed as a single WIP snapshot on feature/initial-implementation so nothing is lost. No reviewer ran on this batch yet, and the solution does NOT build cleanly — there are known cross-phase compile issues to resolve before review.

Tomorrow's action list (in order):

  1. git pull (or just verify branch) — confirm we're on feature/initial-implementation at the WIP commit.
  2. Run dotnet build Marathon.sln to capture the current error set as a baseline.
  3. Resolve known cross-phase compile issues:
    • Phase 2 ↔ Phase 3: Phase 2's repository classes are internal; Phase 3's Marathon.Infrastructure.Tests references them directly. Fix: add <InternalsVisibleTo Include="Marathon.Infrastructure.Tests" /> to src/Marathon.Infrastructure/Marathon.Infrastructure.csproj. (Or make the repos public — choose by reading the actual csproj first.)
    • Phase 5: LocalizationOptions namespace ambiguity (Microsoft.AspNetCore vs Microsoft.Extensions). Fix in WPF host or UI project — qualify or alias.
    • Phase 5: Serilog API mismatch in WPF host (likely UseSerilog extension not found because Serilog.Extensions.Hosting wasn't pulled in transitively via the right namespace, OR the API call site uses an older Serilog API).
  4. Once dotnet build Marathon.sln is green:
    • Run dotnet test Marathon.sln to see how many tests pass.
    • Spawn the phase-reviewer agent (Sonnet) to review the parallel batch as a single combined review (Phase 2 + 3 + 5 diff). Pass git diff 144c936...HEAD.
    • Address blocker findings; re-review until pass.
  5. After review passes, finalize with one or more clean commits (the WIP commit can be git reset --soft to base and re-committed cleanly per phase, OR left as-is and the review passes apply). Update PLAN.md tracking rows for P2/P3/P5 to Done with commit hashes.
  6. Move to Phase 4 (Application + Workers — backend, Sonnet 4.6). Phase 4 composes the per-module DI extensions (PersistenceModule.AddMarathonPersistence and ScrapingModule.AddMarathonScraping) into a top-level Marathon.Infrastructure/DependencyInjection.cs and adds BackgroundService pollers (UpcomingEventsPoller, LiveOddsPoller, plus a future ResultsWatchListPoller per the Phase 8 amendment).

Useful pointers:

  • Phase 2 implementer report: see tasks/a56ecc5e24bd7ea43.output (don't read — context-heavy; the summary is in the conversation transcript).
  • Phase 3 implementer report: agent ID a8a537ba5721fba3d. Same caveat.
  • Phase 5 implementer was killed; final state is the WIP commit. The agent had finished implementation and was about to verify build — assume code is ~95% complete but unreviewed.
  • All 3 phase subplans have their ## Handoff to Next Phase sections filled.
  • Cross-phase issues already documented in the conversation by the parallel agents — see Phase 2 and Phase 3 reports for the specifics.

Do NOT:

  • Reset/discard the WIP commit without first reading what's in it.
  • Skip the cross-phase fix step — Phase 4 cannot proceed against a broken build.
  • Move to Phase 4 before reviewing the P2/P3/P5 batch.

Amendment Log

Amendment 1 — 2026-05-05 — Phase 8 strategy change (deferred — formal approval will be requested when Phase 8 begins)

Type: Modify upcoming phase (Phase 8 — Results loader) What changed: Phase 8's original subplan assumed marathonbet.by exposes a public results / archive page that we can scrape to back-fill EventResults. Phase 0 spike proved this endpoint does NOT exist (/su/results returns 404).

Why: Spike findings — see spike/SCRAPE_FINDINGS.md and the deviation note in plans/initial-implementation/phase-0-scraping-spike.md (Handoff section).

New approach (to be formalised when Phase 8 begins): Maintain a "watch list" of events whose ScheduledAt + EstimatedDuration is in the past but whose status is not Completed. Poll those event-detail URLs every 5 min until either eventJsonInfo.matchIsComplete=true (capture resultDescription, mark complete) or the URL 404s (mark ResultUnknown). Optional fallback to flashscore/sofascore is a Phase 8 design decision.

Impact on existing phases: Phase 4 (Application + Workers) may need a new ResultsWatchListPoller : BackgroundService in addition to the previously planned UpcomingEventsPoller and LiveOddsPoller. Phase 2 schema may need a WatchStatus field on Event (Pending | InWatchList | Completed | ResultUnknown). Both will be re-evaluated when Phase 8 starts.

Status: Logged — formal subplan revision and user approval will be requested at the start of Phase 8 (per skill rule: "All amendments require explicit user approval before taking effect"). Phases 17 do not depend on Phase 8's tactical implementation.