Phase 3: extract pure cores + inject functions (functional refactor plan)#72
Merged
Merged
Conversation
Failing-first tests (TDD red) for PageHeaderParser, SubscriptionHeaderParser, TopWallpapersHeaderParser, ImageLinkSelector, TagRules/TagOutcome, ScrapeError DU, PageInfo, SearchProgress functions, IDelayStrategy, IImageRetriever, IImageSaver, IFileSystem-backed DirectoryHelper. Production types intentionally absent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- ScrapeError DU + factory + LogFailure extension; PageInfo record - Pure parsers: PageHeaderParser, SubscriptionHeaderParser, TopWallpapersHeaderParser, ImageLinkSelector (frozen behaviour) - TagRules.Evaluate pure core with TagRuleContext/TagOutcome DU; DB save stays in ImagePage shell - SearchProgress record + SearchProgressFunctions pure transitions - Injected effects: IDelayStrategy/RandomDelayStrategy, IImageRetriever/ImageRetriever (HttpClient, Result-returning), IImageSaver/ImageSaver (IFileSystem); DirectoryHelper takes IFileSystem - Deleted static ImageRetrieverHelper/ImageSaveHelper - SearchWorkflow + ImagePageService rewired to injected functions; TimeProvider replaces Stopwatch; DI registrations in App.axaml.cs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
astar-development-jb
approved these changes
Jul 6, 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 of
docs/wallpaper-scrapper-functional-refactor-plan.md: extract pure, unit-testable cores from the page/workflow shells and inject effectful dependencies. Page public APIs unchanged — Result-chain conversion is Phase 4.Pure cores (frozen behaviour, quirks preserved)
PageHeaderParser,SubscriptionHeaderParser,TopWallpapersHeaderParser—string? → Result<PageInfo|int, ScrapeError>; shells Match back to existing tuple returnsImageLinkSelector.SelectWanted— pure href filter (non-null, contains/w/, Take 24)TagRules.Evaluate— pure port ofImagePage.ProcessTheImageTagsAsyncpredicates viaTagRuleContext→TagOutcomeDU (SkipImage|Accept); DB save stays in the shellSearchProgressrecord +SearchProgressFunctionspure state transitions forSearchWorkflowNew error model
ScrapeErrorDU (7 cases) +ScrapeErrorFactory+LogFailureSerilog extension (plan §4.5)Injected effects
IDelayStrategy/RandomDelayStrategy(all delay sites: category up-to-date, page navigation, already-downloaded, before-image, retry)IImageRetriever/ImageRetriever(HttpClient, returnsResult<byte[], ScrapeError>) — replaces deleted staticImageRetrieverHelperIImageSaver/ImageSaver(IFileSystem) — replaces deleted staticImageSaveHelperDirectoryHelpernow takesIFileSystem;TimeProviderreplacesStopwatchinSearchWorkflowIDelayStrategysingleton,IImageSavertransient,AddHttpClient<IImageRetriever, ImageRetriever>(2-min timeout)Documented deviations (reviewed & accepted)
PageParseFailedinstead of throwing a framework exception inside the parse logic; callers' log-and-rethrow behaviour unchanged (pinned by tests)InvalidOperationException(was effectivelyFileNotFoundExceptionvia silent-empty-array + missing file); retry-once flow unchanged (pinned by tests)[^50..]crash inImagePageServicelogging fixed with a length guardServicesnamespace (sibling-namespace visibility)Test plan
varusage,ConfigureAwait(false)on new awaits,DirectoryHelperempty-list guard, factory argument validation)🤖 Generated with Claude Code