refactor(scraper): Phase 3 class decomposition + fix all 37 pre-existing test failures#735
Merged
astar-development-jb merged 7 commits intoJul 11, 2026
Merged
Conversation
… FileClassificationService Import/export was a separate domain concern living inside the classification service. Move it, its upsert/fallback helpers, and its tests into a dedicated service; drop the now-unused Logger dependency from FileClassificationService. Closes #731 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tence, and orchestrator ImagePageService mixed orchestration with HTTP retry, file I/O, dimension probing, DB persistence, and broadcasting behind 14 constructor parameters (two of them dead). Extract ImageDownloader (retrieve + retry) and ImagePersistence (save, dimensions, broadcast, FileDetailEntity persistence); drop the dead ScrapeConfiguration and IFileSystem parameters; replace the await-then-Match loop in GetTheImagePagesAsync with a Result fold. Closes #732 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ositionRoot App mixed Avalonia framework glue with the entire composition root. Move host/builder creation and all service registrations into a dedicated AppCompositionRoot; App now only initialises the database, configures the desktop lifetime, and surfaces configuration errors. Closes #733 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…peConfigurationAsync 56 lines of property-by-property copying now reads as one step per configuration section: connection strings, user configuration, search configuration, search categories, scrape directories. Closes #734 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Test results3 169 tests +2 189 3 168 ✅ +2 205 2m 23s ⏱️ + 2m 0s Results for commit da074e5. ± Comparison against base commit c326573. This pull request removes 11 and adds 2200 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
astar-development-jb
enabled auto-merge (squash)
July 11, 2026 20:43
…ixed, production is the specification Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t production behaviour Production is the specification for all of these: - GivenADatabaseResetRepository: CombinePath rejects rooted segments; seed a RootDirectory and a relative BaseSaveDirectory. - GivenTheTagRules: tags without a category are excluded from the outcome's Tags, not kept. - GivenAnImportExportService: ScrapedTag.Category is a string; the test JSON still used the old numeric category id. - GivenAFileClassificationService: classify reuses the NOCASE-matched existing category (highest level wins); the create-under-Unclassified fallback is unreachable from tag matches, and AppDbContext seeds a 'Colour' root that whole-table counts must account for. Scraper suite: Failed: 0, Passed: 441. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…current production behaviour Production is the specification for all of these: - GivenASettingsViewModel / GivenAStartupService / GivenASyncWorker: production calls SaveAsync/SetCultureAsync/GetCachedAccountIdsAsync with the default CancellationToken; stubs and Received assertions pinned to TestContext.Current.CancellationToken never matched. Use Arg.Any<CancellationToken>(). - GivenAFileClassificationRepository: GetAllCategoriesAsync filters on IncludeInSearch; seed rows now opt in. - ScrapedTags was replaced by FileClassifications (#717): the DbSet existence test now asserts absence, and GivenAScrapedTagEntity is reworked as GivenAPersistedFileClassificationCategory — duplicate names are allowed by design (no unique index), and retrieval must not collide with the seeded 'Colour' root. OneDrive suite: Failed: 0, Passed: 2156. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
astar-development-jb
approved these changes
Jul 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 3 (class decomposition) of the scraper code review
docs/astar-dev-wallpaper-scraper/code-review-2026-07-10.v2.md, plus a follow-up applying the new leave-it-better rule: all 37 pre-existing unit-test failures on main are fixed. One commit per concern, behaviour-preserving throughout — no production code changed by the test fixes.Refactor (issues #731–#734):
FileClassificationImportExportService; the now-unusedLoggerdependency dropped fromFileClassificationService.ImageDownloader(HTTP retrieve + retry) andImagePersistence(file save, dimension probe, broadcast,FileDetailEntitypersistence); deadScrapeConfiguration/IFileSystemconstructor parameters removed (14 → 10); await-then-Match loop replaced with a short-circuitingResultfold.App.axaml.cs.Leave-it-better (new CLAUDE.md rule + fixes):
CombinePathrooted-segment rejection, tag-category filtering,ScrapedTag.Categorystring type, NOCASE category reuse, seededColourroot).IncludeInSearchfilter inGetAllCategoriesAsync, ScrapedTags → FileClassifications migration leftovers).Type of change
Related issues / links
Closes #731, Closes #732, Closes #733, Closes #734
How was this tested?
Import/export tests moved to
GivenAFileClassificationImportExportService; newGivenAnImageDownloaderandGivenAnImagePersistencetest classes; 37 stale tests realigned with production behaviour;GivenAScrapedTagEntityreworked asGivenAPersistedFileClassificationCategory.Impacted areas
apps/desktop/Scraper, apps/desktop/AStar.Dev.OneDrive.Sync.Client.Tests.Unit (tests only), CLAUDE.md
TDD Checklist (required)
dotnet test)dotnet clean && dotnet build --no-restore: 0 errors; remaining warnings are pre-existing on main (5× Avalonia AVLN3001 for DI-only view constructors, 3× NU1903 SQLitePCLRaw advisory in spikes/).dotnet test --no-build, full solution: Failed: 0 across all 13 test projects — Scraper 441/441, OneDrive Sync Client unit 2156/2156, integration 27/27. Main currently has 37 failures (16 scraper + 21 OneDrive); this branch takes the suite fully green.Public API changes
FileClassificationServiceconstructor losesLogger;ExportClassificationsAsync/ImportClassificationsAsyncmoved toFileClassificationImportExportService(bothinternal).ImagePageServiceconstructor: 14 → 10 parameters (ImageDownloader+ImagePersistencein;ScrapeConfiguration,IFileSystem,IImageRetriever,IImageSaver,ImageBroadcaster,IImageDimensionReaderout).ClassificationsViewnow takesFileClassificationImportExportService.How to run tests locally
Notes for reviewers
Nameintentionally has no unique index (same name under different parents);ScrapedTagExtensions.ToDomainstill hardcodesParentId = 1(pre-existing TODO in production, unchanged here).FileClassificationRepositoryextraction (EF tracking out ofFileClassificationService.ClassifyAsync); deferred becauseEnsureTracked/FindOrCreate*are bound to the classify unit-of-work's DbContext lifetime — splitting them without redesigning that pipeline would add indirection, not clarity.🤖 Generated with Claude Code