Implement v4.7.0: Intelligence & Comparison#6
Merged
Merged
Conversation
- DiffService.compare(domainA:domainB:) reuses the existing section-diff builders to compare two distinct domains' latest reports, returning a new DomainComparisonResult (parallel to the time-based DomainDiff). - DomainCompareView: pick two tracked domains and render the comparison with the existing DomainDiffView section renderer. - Entry point: "Compare Domains" in the Watchlist toolbar menu, shown once at least two domains are tracked.
- New DomainReputationResult model (status: clean/listed/unknown, listed sources, checked-at) and a `reputation(domain:)` method on ExternalDataService, mirroring the existing pluggable-URL enrichment pattern (ownership history, DNS history, extended subdomains, pricing). With no endpoint configured (the default; DomainDig ships no bundled third-party reputation dependency) it resolves to unavailable rather than "clean". - New .reputation FeatureCapability/DataCapability, gated Pro+ like domainPricing. - Threaded reputation/reputationError through LookupSnapshot and HistoryEntry (backward-compatible decode) so results persist with history entries. - Auto-fetched in performLookup alongside pricing; surfaced as a "Reputation" info row, folded into DomainInsightEngine's risk score/factors and top-level insights (a listed domain raises risk score and adds a factor/insight), and exported in text, CSV, and JSON report output. - Reputation-driven risk changes ride the existing change-severity pipeline, so a listed status flip is visible to monitoring the same way any other risk delta is, without bespoke monitoring wiring.
- TrackedDomain.tags: [String] (backward-compatible custom decode), with updateTags(_:for:) and a normalized/deduplicated write path. - Tag editing in TrackedDomainDetailView (comma-separated field, chip display). - Tag filter chips in WatchlistView (TagFilterChipRowView), integrated into filteredTrackedDomains alongside the existing filter/search. - Saved views: name + snapshot the current tag/filter/sort as a WatchlistSavedView preset (UserDefaults-backed, not part of backup/restore), with a management sheet to apply or delete presets.
Bump AppVersion/marketing version to 4.7.0 and build number to 39 across the app, widget, and share extension targets. Mark v4.7.0 (comparison, reputation, tags/saved views) shipped in RELEASE_ROADMAP.md and escalate the overdue XCTest-target gap ahead of v5.0.0.
|
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.



Delivers the v4.7.0 "Intelligence & Comparison" roadmap phase.
What
DiffService.compare(domainA:domainB:)reuses the existing section-diff builders (previously only used for time-based comparison) to diff two distinct domains' latest reports.DomainCompareView(Watchlist toolbar → "Compare Domains") lets you pick two tracked domains and renders the result with the existingDomainDiffView.ExternalDataService.reputation(domain:), a new pluggable-URL enrichment mirroring the existing ownership-history/DNS-history/pricing pattern (Pro+ gated). Ships with no bundled third-party endpoint — with nothing configured it resolves to unavailable, never fabricates "clean". A listed status folds intoDomainInsightEngine's risk score/factors and top-level insights, so it's surfaced in the report UI and rides the existing risk/change-severity pipeline that monitoring already reacts to — no bespoke monitoring wiring needed. Threaded throughLookupSnapshot/HistoryEntry(backward-compatible decode) so results persist, and exported in text/CSV/JSON.TrackedDomain.tags: [String](backward-compatible decode), tag editing UI, tag filter chips, and named saved filter/sort/tag presets (WatchlistSavedView, UserDefaults-backed).Version
Bumped to 4.7.0 (build 39) across app, widget, and share extension targets.
Verification
xcodebuild build(schemeDomainDig, iOS 26 sim) → BUILD SUCCEEDED after each commit.Honest gaps
RELEASE_ROADMAP.md: it should be the first thing v5.0.0 does, since comparison/reputation/tags all touch persisted models with hand-written backward-compatible decoders now.DomainDataPortabilityService) — they're a lightweight local preference, not user-authored content like tracked domains. Flagging in case that's wrong.ExternalReputationURLat an endpoint — deliberately, to avoid taking on a third-party dependency/ToS decision unilaterally.