Repository navigation
Description
Assignment and review basis
Architecture audit of 7e17aec6406263378f788812d452859016fcd1ed, as of 2026-10-24. P2 priority as a planning basis. This is an integration assessment, not an additional aggregate defect.
Ranchero-Software/NetNewsWire was read only. No comments, issues, settings, branch changes or PRs were made there. No PR was applied or merged locally.
The complete inventory available through the GitHub issue interface was retrieved with every page: 4,531 issues and 952 PR entries, including 609 open issues and 19 open PRs. All 609 open issue titles and descriptions were evaluated for requirements and overlap. Historical entries were indexed, with relevant descriptions/comments inspected in greater depth. This is not a complete individual review of every historical comment thread or all 952 PR diffs.
For all 19 open PRs, descriptions and every available text patch were read: 219 files, including 211 text patches. Eight PDFs were inventoried only through metadata. Every PR targets main but starts from a different development state. The head revisions below pin the compared state; none of these PR revisions was built or tested.
Assessment of every open PR
| PR | Reviewed head | Assessment and required adaptation |
|---|---|---|
| #5480 — Move article fetch after “Mark All as Read” action | 4b5300718ab6 |
Focused repair; still open locally (#41). Moves the complete article fetch after menu action selection. A small, suitable approach; derive availability from existing state and fetch asynchronously when invoked. Verify a large feed and delayed database. |
| #5443 — add WordPress.com Reader support | 7eae95f26d2b |
New ReaderAPI-based provider; draft. AccountType.wordpressCom uses persistent raw value 24; PR #5405 assigns the same value to Miniflux. Define stable unique mapping and migration before combining them. Update current CredentialsAccountView/Inspector selection lists; older UI switches do not all match the local revision. |
| #5422 — Keep looking for a favicon when the home page can't be read | 0198d56c63d0 |
Suitable approach for #37 and #38. Decouple favicon fallback from homepage success and track results per job. A candidate/completion model is more useful than a global success flag; test multiple homepages, early/late completion and transient errors. |
| #5409 — Organize the iPad menu items to mirror macOS. | 2a97048f5421 |
Good basis for shared semantic commands. Centralizes iPad AppCommands and OPML actions; macOS retains separate menu configuration. Keep shared command IDs and availability in the state model, retaining native menu/keyboard adapters. Verify focus, keyboard conflicts and actions across different windows. |
| #5405 — Add native Miniflux account type and sync support | 2b30d1313bab |
Substantial new provider integration. The Miniflux delegate, changed_after and fallback paths provide a useful domain basis, but do not solve existing SyncQueue contracts (#5). Persistent AccountType.miniflux = 24 collides with #5443. Unify endpoint normalization, account metadata and duplicate UI configuration before adoption; isolate backfill, API-version and 404-fallback tests. |
| #5399 — feat(reader-api): add custom HTTP headers for self-hosted accounts | fd6773c6772f |
Reusable settings model; adapt to the current architecture. The patch targets an older ReaderAPIAccountViewController structure rather than local CredentialsAccountView. Apply headers at one defined boundary, accounting for session replacement on changes and in-flight jobs. Assess the included ClientLogin parser fix for '=' separately. |
| #5352 — Add offline article-image caching behind a setting | fbc8c469491f |
Useful offline components needing integration. Bounded prefetch, shared byte caching and a WK scheme adapter fit the target architecture. However, global Downloader.redirectValidator creates a shared mutable feature-dependent policy; model it per request. Use the existing HTML parser and test cache/WebKit/offline behavior together. |
| #5349 — Dual theme mode to set separate dark and light mode themes | a55ad488a555 |
Useful shared theme policy. Light/dark selection and fallback rules are reusable. Adapt old AppDefaults.shared calls to the local static structure. A global appearance manager is insufficient for future window-specific presentation; bind theme selection to ReaderSession. |
| #5342 — Add global Hide Read Articles preference with per-feed overrides | 130979e40996 |
Good shared filtering idea, without complete unification. Explicitly model the global preference, feed override and legacy migration. The patch retains separate FetchRequestOperation/macOS-window/iOS-HideReadState paths. Establish one authoritative filter source and port old AppDefaults.shared calls; avoid additional independent SwiftUI state copies. |
| #5336 — Add modern timeline UI with thumbnail previews | e476e9c9ac6f |
Design reference, not suitable unchanged. Shared row/thumbnail specifications are useful. The patch forces the new layout and introduces separate Mac/iOS caches and URLSession paths; local file organization has since changed. Preserve the existing column view, font selection, icons and previews; measure memory and scrolling before replacing lists with SwiftUI. |
| #5316 — Fix #5312 / Rewrite the iOS Feed Inspector in SwiftUI | eef14161b187 |
Suitable small SwiftUI migration slice with regressions. Renaming occurs on every keystroke instead of completion. A previous opportunity to grant notification permission is lost because the switch is disabled without permission. Link copying is already corrected elsewhere locally. Explicitly verify these behavior changes, browser choice and static AppDefaults when porting. |
| #5156 — Fix FreshRSS Reader API item discovery window based on published-date ot | 5c255622f853 |
Plausible FreshRSS improvement; server semantics still need proof. The patch changes the ot discovery window. The old local control flow exists, but the claimed server effect was not validated against a service and was therefore not recorded as an additional confirmed defect. Included tests use older Transport/AccountMetadata APIs; port to Session/AccountSettings and current test adapters. |
| #5149 — Add sidebar feed sorting options (by name, by unread count) | 2509a5c64fc1 |
A shared sorting policy is useful. The description promises stable order during reading, but the patch rebuilds it when unread counts change. Decide the policy first; iOS remains alphabetical in the patch. Preserve selection, scroll position and drag and drop across reorderings. |
| #5116 — Add Mark Unstarred as Read | 17a7456cbb6d |
Reusable shared article command and database helper. Some added menu-construction paths synchronously fetch complete article sets, repeating the failure class of #41/PR #5480. Derive availability cheaply from state; determine the working set asynchronously only on execution. Adapt old file paths. |
| #5077 — Cherry-pick 9979758 to restore Find functionality | f2efbea92d66 |
No direct adoption; port Find deliberately. The NSTextFinder adapter is a useful idea. The patch includes a debugInsetOffset incremented on each opening, debug output, active personal DYLD/XPC WebKit paths and older status-bar assumptions. Remove these development remnants and test Find's lifetime against the current web view. |
| #5068 — Add Copy Link with Highlight feature for iOS | 71912e7a943b |
Small, isolatable feature. Foundation helpers and a native UI adapter separate well. Provide a shared selection/text interface; test encoding, existing fragments and special characters. No equivalent complete local feature was found. |
| #4906 — feat(settings): add "mark as read on open" setting for iOS and macOS | 0381b1cc9afb |
Use a shared reading policy rather than distributed controller changes. The patch uses different preference keys per platform and adds only selected opening paths. Define one policy covering every entry point and existing scroll/marking rules. Do not carry over unrelated generated stub files. |
| #4781 — [Feature] Youtube inline video | 6c99c9e7adfa |
Unsuitable for direct integration. Transforms stored content only for LocalAccount and uses a synchronous global registry. It also changes global autoplay and all macOS base URLs, potentially losing path/port. A focused YouTube base-URL workaround already exists locally. Base playback policy on the renderer and content type; the registry tests do not prove the complete article/sync/WebKit path. |
| #4582 — Hide Open Settings in Mark As Read confirmation | 94e00b15d7dd |
Small independent interaction change. Seen state is set when the alert is constructed. Decide whether actual presentation or deliberate selection counts as seen; verify cancellation and repeated presentation. |
Shared conflicts and sequencing
- Repair data/job contracts first: address [P2] Author migration treats database errors as completion and deletes legacy data #2–[P2] Feed settings migration cannot resume after interruption #6, [P2] Refresh completion does not await parsing, persistence and status enqueue #17–[P2] Multiple versions of one article ID produce inconsistent database and cache states #29 and [P2] Startup cleanup deletes stars from unsubscribed feeds contrary to the retention contract #40 independently of UI migration. Refresh completion must mean persisted results; acknowledgements must bind to the status revision actually sent.
- Then small demonstrated UI/network failures: #5480 and #5422 are concrete starting points for [P2] iOS timeline synchronously fetches all feed articles while building a context menu #41 and [P2] Independent favicon fallback depends on homepage metadata success #37/[P2] Interleaved homepage favicon jobs share mutable completion state #38. Test even small patches against the current local revision.
- Shared filters, selection and commands before UI variants: align #5342, #5149, #5409 and #5116 with a shared state/query model. Otherwise new views retain existing inconsistencies.
- Integrate provider extensions separately: #5443 and #5405 both conflict on raw value 24 in Modules/Account/Sources/Account/Account.swift. These values are persistent identity; merely renumbering already stored accounts is not a solution. The combined conflict is an integration obstacle, not an existing defect in the reviewed revision.
- Presentation changes last: use #5316 as a bounded SwiftUI slice; assess #5336, #5349, #5352 and #4781 only against explicit lifetime, cache, renderer and platform contracts. Full recommendation: [Architecture] Shared state model and incremental SwiftUI app for macOS and iOS #42.
Issue requirements for the target architecture
Open requests are not automatically confirmed defects. They nevertheless provide a necessary checklist so a new shared UI does not miss existing requirements:
| Area | Relevant upstream examples | Consequence |
|---|---|---|
| Navigation and selection | #5417, #5495, #1214, #1478 | Stable identity, platform rules, restoration and multiple selection |
| Windows and presentation | #5504, #4925, #5324, #5240 | Per-window state; account for existing column view and font choice |
| Filters and bulk actions | #4184, #4409, #3923, #3926, #3743, #2843, #3434 | Consistent filter/query contract; inexpensive menu availability |
| Commands and keyboard | #5085, #4016, #2954, #4805 | Semantic commands plus native menus and focus rules |
| WebKit and article view | #5429, #4376, #3932, #5423, #4688, #3287 | Renderer as a service with explicit request/lifetime contracts |
| Performance | #5450, #4580, #4325 | No blocking UI queries; measure large datasets |
| Accessibility | #518, #4739, #3146, #4496, #2999, #4859, #3098, #5363, #3302 | Actually accept VoiceOver, Dynamic Type, focus and keyboard behavior |
| Account and feed identity | #5394, #4920, #2679, #1674, #2739 | IDs independent of display names and view positions |
| Refresh and background work | #159, #4560, #4539, #4083, #4194, #555 | Define completion, cancellation, lifetimes and resumption |
| Offline and retention | #3460, #1873, #5284, #5482, #4123, #4273, #2289 | Explicitly test cache/retention policy |
| New product features | #1993, #3247, #2806, #4093 | Assess as requirements, not audit-confirmed defects |
Numbers in this table refer to the upstream repository, which was read only. They are selected examples from the complete open-issue triage, not a claim of one common cause per row.
Historical counterevidence and existing solutions
- #5503: static AppDefaults already exist locally; no new finding.
- #5434: protection against unnecessary recreation of the hosted settings view already exists locally.
- #5428: the local SQL query already uses grouped IN lists and has a 1,200-ID test.
- #5091/PR #5114: NewsBlur batches of 100 are present; so are PR #4277 update_counts=true and PR #3067 include_hidden=false.
- #5050: Feedly async migration is present. Async syntax does not guarantee correct refresh completion ([P2] Refresh completion does not await parsing, persistence and status enqueue #17).
- PR #2091: on-demand token refresh with retry is present.
- PR #1638: the initial-subscription limit is not automatically a pagination defect.
- PR #3154 merged into swiftui3, not main; #3152 closed unmerged. PR #3778 did merge into main. PR #5189, containing architecture prose, closed unmerged and is not an adopted architecture.
- #5421: the claim that local accounts never adopt explicit feed icons does not hold for current local takeSettings processing. Separate fallback/completion failures are demonstrated in [P2] Independent favicon fallback depends on homepage metadata success #37/[P2] Interleaved homepage favicon jobs share mutable completion state #38.
- #1857: the still-present OPML homepage loss is recorded as [P3] OPML import loses parsed homepage URLs at the account boundary #39.
- #3480: the historical maintainer statement and local retention documentation were compared against the then-current cleanup path; focused runtime evidence is in [P2] Startup cleanup deletes stars from unsubscribed feeds contrary to the retention contract #40.
- Older SwiftUI prototype reports such as #2217, #2164, #2284, #2235, #2327 and #2238 inform regression tests, rather than proving present-day framework incapability.
Acceptance of a later integration
For each selected PR, recheck its current head, record scope and persistence migration, port it to the current module/UI structure and run focused tests. Then execute macOS and iOS test plans and relevant platform interactions. Upstream status and author statements provide context; the current code path and exercised behavior are decisive.
Continuation — 2026-10-24
This integration/migration report is complete as a report and remains traceable. Implementation and open acceptance are tracked in umbrella #45 and packages #46–#56. Recheck upstream revisions before each concrete adoption.
Historical scope clarification — 2026-10-26
The inventory, open statuses and recommendations above describe the dated 2026-10-24 audit, not a new upstream assessment. The owner subsequently selected the OS-27 SwiftData/FreshRSS Reader architecture under #45, superseding the incremental strategy in #42. Translation preserves the original review and does not import any upstream PR or authorize upstream writes.
Later source retirement — 2026-10-25
The original and superseded source identified by the audit was removed at e61b2fa26 under explicit owner authorization. This does not repair the historical implementation or accept unfinished Reader requirements. Retirement inventory and evidence.
Activity
[-][Architektur] Upstream-PRs und Issue-Bestand als Integrations- und Migrationsgrundlage bewerten[/-][+][Architecture] Assess upstream PRs and issue inventory as an integration and migration basis[/+]