Apollo Download ManagerApollo Download Manager
On this page

Parity map: V1 to Apollo Download Manager

Every user-visible behaviour of the original Velocity Download Manager (V1), with where it lives in V1, the V1 tests that prove it, what Apollo Download Manager does with it, and the issue that delivers it (#22). The default is keep every V1 feature. Rows that changed meaning without aria2 were decided in #23 (ADR-0005); any further scope change needs a new PO decision.

  • V1 reference: Singlbase-Technologies-Limited/velocity-download-manager at commit e9d717a8. Every link below opens that exact commit.

  • Dispositions:

    • Reuse: the same behaviour, ported in substance.

    • Reimplement: the same behaviour, written again for Apollo Download Manager's architecture.

    • Adapt: the same user outcome, on Apollo Download Manager's own engine.

    • Decided (ADR-0005): a behaviour whose meaning changed without aria2, with the PO's decision.

  • V1 tests: where a behaviour has no V1 test, the row says so, and the issue that delivers it adds one (#15).

  • Final acceptance of this map is #85 (V1 against Apollo Download Manager parity).

Tauri commands (46)

All commands in commands.rs.

CommandV1 codeV1 testsApollo DM dispositionApollo DM tests neededApollo DM issue
get_bootstrapcommands.rs:71tests/unit/app.test.tsxReimplemented (#29) as app_info (with the contract check), get_shell_settings and get_snapshot; the start-up states in src/app/App.test.tsxContract fixture; UI startup and error states#58, #29
get_snapshotcommands.rs:91tests/unit/app.test.tsx (live updates)Adapt: snapshot from the Apollo DM engine's events, not aria2 pollingSnapshot contract; event-driven updates#58, #59, #25
add_downloadscommands.rs:100tests/unit/app.test.tsx, tests/unit/torrent.test.tsx; engine_integration: http_download_completes_with_integrity, engine_integration: invalid_urls_are_rejected_before_the_engine, engine_integration: typed_names_keep_the_file_type_of_the_link, engine_integration: links_without_a_file_name_use_the_server_nameReimplemented (#60) as add_downloads on the Apollo DM engine: a result for each link, duplicates by link and info hash, .torrent links fetched first (velocity-core manager::adding, manager::torrent_links; src/features/add/)Fixture download with SHA-256; validation and naming unit tests#60, #58, #31, #67
check_destinationcommands.rs:108tests/unit/app.test.tsxReimplemented (#31): conflict check before adding. Ask or rename only: an existing file is never replaced, and V1's partial downloads are never resumed (PO decision on #31). The Add dialog (#60) shows it before adding and asks afterConflict tests: ask, rename, a V1 download in the same folder#60, #31
pause_downloadscommands.rs:129tests/unit/app.test.tsx; engine_integration: pause_and_resumeAdapt: pause through DirectTransfer; resume from checkpointsPause during a split; resume after restart#58, #43
resume_downloadscommands.rs:135tests/unit/app.test.tsx; engine_integration: pause_and_resumeAdapt (as pause)Resume with validators (#45)#58, #43, #45
cancel_downloadscommands.rs:141engine_integration: queue_reordering_and_cancel_and_remove_with_filesReimplementCancel closes files before any deletion#58, #72
retry_downloadscommands.rs:147tests/unit/app.test.tsx; engine_integration: not_found_fails_and_manual_retry_succeedsReimplement on the Apollo DM retry classesManual retry after a permanent failure#58, #48
retry_failedcommands.rs:153none in V1: Apollo DM adds oneReimplementRetry-all over mixed failure classes#58
remove_downloadscommands.rs:158tests/unit/api.test.ts, tests/unit/app.test.tsx; engine_integration: queue_reordering_and_cancel_and_remove_with_filesReimplement; delete only owned filesRemove with and without files; never follow links#58, #72
move_downloadcommands.rs:168engine_integration: queue_reordering_and_cancel_and_remove_with_filesAdapt: a Velocity-owned queue instead of aria2 changePositionQueue reordering#50
pause_allcommands.rs:177none in V1: Apollo DM adds oneReimplementPause-all and resume-all over a mixed queue#58, #50
resume_allcommands.rs:182none in V1: Apollo DM adds oneReimplement(as above)#58, #50
clear_completedcommands.rs:187none in V1: Apollo DM adds oneReimplementClears completed records only, keeps files#58, #32
set_download_connectionscommands.rs:192tests/unit/app.test.tsx; engine_integration: connections_can_be_changed_while_downloading_and_the_file_stays_intactAdapt: live change without a restart (aria2 restarted the transfer)Change connections mid-download; file intact#47, #57
set_download_speed_limitcommands.rs:201engine_integration: per_download_speed_limit_is_enforcedAdapt: Apollo DM token-bucket limits (set_limits), applied live; at least 1 KiB/sA limit holds within the tolerance#49
set_download_categorycommands.rs:206none in V1: Apollo DM adds oneReimplementCategory change moves nothing unexpectedly#31
open_download_filecommands.rs:229none in V1: Apollo DM adds oneReimplemented (#61): Manager::file_to_open checks the file is the download’s own and not a link, and refuses a program with CONFIRMATION_REQUIRED until the user confirms; src-tauri/src/opening.rs opens it with Explorer or xdg-open, with an argument listProgram warning; missing file; link refused (manager::tests::opening, DetailsPanel.test.tsx)#61, #72
open_download_foldercommands.rs:250none in V1: Apollo DM adds oneReimplemented (#61): Manager::folder_to_open; Explorer selects the file, xdg-open opens its folderSelects the file, or shows the folder if the file is gone (manager::tests::opening)#61
get_download_detailscommands.rs:268none in V1: Apollo DM adds oneDecided (PO, #61): not needed. The panel reads the live snapshot, which carries the connection detail (#47), the download’s options and the torrent activity—#61, #47
get_historycommands.rs:273none in V1: Apollo DM adds oneReimplemented (#32): Manager::history, with search, a status filter and pagesPaging, filters (manager::tests::history, HistoryView.test.tsx)#32
clear_historycommands.rs:278none in V1: Apollo DM adds oneReimplemented (#32): entries out of the list are forgotten, those in it only leave the historyClears history, keeps files (manager::tests::history)#32
delete_history_entriescommands.rs:283none in V1: Apollo DM adds oneReimplemented (#32); only finished downloads, never a running oneDeletes selected entries only (manager::tests::history)#32
get_settingscommands.rs:289tests/unit/app.test.tsxReimplemented (#30): get_settings, every sectionSettings contract (settings.json)#30
update_settingscommands.rs:294tests/unit/app.test.tsx, tests/unit/layout.test.tsx, tests/unit/torrent.test.tsx, tests/unit/torrentControls.test.tsxReimplemented (#30): set_settings, checked whole, saved in one write and applied at onceRefused natively out of bounds (settings_screen)#30
reset_settingscommands.rs:302tests/unit/app.test.tsx, tests/unit/layout.test.tsxReimplemented (#30): keeps the download folder, after askingReset to defaults (SettingsView.test.tsx)#30
list_categoriescommands.rs:317none in V1: Apollo DM adds oneReimplementCategory CRUD#31
create_categorycommands.rs:322none in V1: Apollo DM adds oneReimplement(as above)#31
update_categorycommands.rs:330none in V1: Apollo DM adds oneReimplement(as above)#31
delete_categorycommands.rs:339none in V1: Apollo DM adds oneReimplement: downloads in it fall back to no categoryDelete with downloads assigned#31
choose_directorycommands.rs:358none in V1: Apollo DM adds oneReuse in substance (native dialog)Manual on each platform#60, #30
choose_metadata_filecommands.rs:369none in V1: Apollo DM adds oneReuse: .torrent and Metalink filesManual on each platform#60, #54, #62
inspect_torrent_filecommands.rs:384tests/unit/torrent.test.tsx; torrent_integration: corrupt_and_malicious_torrents_are_rejected_before_the_engineReimplemented (#63): preview_torrent_file, with the duplicate it would repeat; the Add dialog shows its file treeMalicious torrent corpus; preview (manager::tests::adding)#62, #63
start_torrent_filescommands.rs:390tests/unit/torrent.test.tsx; torrent_integration: magnet_can_wait_for_file_selectionReimplemented (#63): choose_torrent_files, from the Choose files dialogChoose files after metadata (Torrents.test.tsx)#62, #63
stop_seedingcommands.rs:400tests/unit/torrent.test.tsx, tests/unit/torrentControls.test.tsx; torrent_integration: unlimited_seeding_can_be_paused_resumed_and_stoppedReimplemented (#58, #63): set_torrent_seeding with { "mode": "never" }; "Stop seeding" and "Leave seeding queue" in the detailsSeeding stop#62, #63
set_upload_limitcommands.rs:406torrent_integration: download_limit_and_global_upload_limit_reach_the_engineReimplemented (#63): set_torrent_upload_limit, live and stored; the Add dialog sets one tooPer-torrent upload limit (manager::tests::torrents)#62, #63
reannouncecommands.rs:412tests/unit/torrentControls.test.tsx; torrent_integration: tracker_errors_are_shown_and_a_reannounce_recoversReimplemented (#63): reannounce_torrent; trackers asked for every second while shownTracker error and re-announce#62, #63
change_torrent_filescommands.rs:420tests/unit/torrentControls.test.tsx; torrent_integration: files_can_be_added_and_dropped_while_a_torrent_downloads, torrent_integration: file_changes_are_validated_and_never_delete_kept_or_foreign_filesReimplemented (#63): choose_torrent_files with deleteDropped; only the torrent’s own dropped files are deleted, with delete_ownedFile changes; never deleting kept files (manager::tests::torrents)#62, #63, #72
choose_torrent_filescommands.rs:437none in V1: Apollo DM adds oneReimplemented (#60) as choose_torrents, from Rust only (Apollo DM's choose_torrent_files chooses files inside a torrent, #58)Manual on each platform#60, #63
get_diagnosticscommands.rs:459torrent_integration: diagnostics_describe_bittorrent_without_secretsReimplemented (#28): DiagnosticReport, with libcurl's and libtorrent's versions, the engines' health and logs, and download counts without namesReport fields; no names or links (diagnostics::tests)#28
export_diagnosticscommands.rs:464none in V1: Apollo DM adds oneReimplemented (#28): every string redacted again; the panel has no CopyNo test secret in the export (an_export_holds_no_secret_from_any_log)#28
restart_enginecommands.rs:480engine_integration: engine_crash_is_restarted_and_download_resumes, engine_integration: engine_restart_recovers_unfinished_downloadDecided (ADR-0005): "Restart transfer engine" kept, because the engine is a helper process (ADR-0012)Crash and restart recovery#38, #39, #28
complete_onboardingcommands.rs:489tests/unit/app.test.tsxReimplemented (#29): the folder must exist and can't be a link; it doesn't wait for the engine (velocity-core manager::settings, src/app/App.test.tsx)Onboarding flow#29
get_browser_integrationcommands.rs:518none in V1: Apollo DM adds oneReimplemented (#65): src-tauri/src/browser.rs, BrowserIntegration in crates/velocity-core/src/browser/registration.rsRegistration state per browser#65
register_browsercommands.rs:538tests/unit/app.test.tsxReimplemented (#65) with Apollo DM's host name; the Browser section's tests in src/features/settings/SettingsView.test.tsxRegister and unregister per browser and OS#65
unregister_browsercommands.rs:550none in V1: Apollo DM adds oneReimplemented (#65); unregistering leaves V1's registration alone (tested)(as above)#65

Settings (71 fields)

Every field of AppSettings and its nested sections in models.rs (AppSettings at models.rs:897). Fields that were aria2 options carry the PO's decision from #23. Every field Apollo Download Manager saves is on the Settings screen (#30), saved whole and refused natively when out of bounds; its tests are manager::tests::settings_screen, settings::tests and src/features/settings/SettingsView.test.tsx, and the contract fixture settings.json holds the defaults.

FieldV1 codeApollo DM dispositionApollo DM issue
onboarding_completedmodels.rs:898Reused in app_settings.rs (#29; SETTINGS.md) Apollo DM (#30): onboarding.completed, on the Settings screen#29, #30
general.close_to_traymodels.rs:485Reused in app_settings.rs (#29; SETTINGS.md) Apollo DM (#30): general.closeToTray, on the Settings screen#29, #30
general.start_minimizedmodels.rs:486Reused in app_settings.rs (#29; SETTINGS.md) Apollo DM (#30): general.startMinimized, on the Settings screen#29, #30
general.confirm_exit_with_activemodels.rs:487Reused in app_settings.rs (#29; SETTINGS.md) Apollo DM (#30): general.confirmExitWithActive, on the Settings screen#29, #30
downloads.default_directorymodels.rs:504Reuse Apollo DM (#30): downloads.defaultDirectory, on the Settings screen#30, #31
downloads.category_subfoldersmodels.rs:508Reuse (V1 test: saved_settings_keep_category_subfolders_off) Apollo DM (#30): downloads.categorySubfolders, on the Settings screen#31, #30
downloads.start_immediatelymodels.rs:509Reuse Apollo DM (#30): queue.startImmediately, on the Settings screen#58, #30
downloads.auto_categorizemodels.rs:510Reuse (V1 tests: automatic_category_also_chooses_the_category_folder, turning_automatic_categories_off_keeps_the_default_folder) Apollo DM (#30): downloads.autoCategorize, on the Settings screen#31, #30
queue.max_concurrent_downloadsmodels.rs:407Adapt: Apollo Download Manager's own queue, 2 at once by default (#351; V1's was 3) (V1 test: concurrent_downloads_respect_engine_queue) Apollo DM (#30): queue.maxConcurrentDownloads, on the Settings screen#50, #30
queue.max_connections_per_downloadmodels.rs:408Adapt: per-download budget Apollo DM (#30): performance.custom.maxConnectionsPerServer (the profile's cap), on the Settings screen#47, #30
queue.global_download_limit_kibmodels.rs:410Adapt: global token bucket (set_global_limits, contract 3), shared among active downloads, kept across engine restarts; the setting itself is #30 Apollo DM (#30): advanced.globalDownloadLimitKib, on the Settings screen#49, #30
queue.schedule.enabledmodels.rs:384Reuse (schedule window) Apollo DM (#30): queue.schedule.enabled, on the Settings screen#50, #30
queue.schedule.start_timemodels.rs:386Reuse Apollo DM (#30): queue.schedule.startTime, on the Settings screen#50, #30
queue.schedule.stop_timemodels.rs:388Reuse Apollo DM (#30): queue.schedule.stopTime, on the Settings screen#50, #30
A download's own start time, and the time formatnone in V1: Apollo DM adds them (#350)—#350
queue.schedule.daysmodels.rs:390Reuse Apollo DM (#30): queue.schedule.days, on the Settings screen#50, #30
performance.profilemodels.rs:446Decided (ADR-0005): kept; each profile sets caps for the adaptive engine Apollo DM (#30): performance.profile, on the Settings screen#57, #30
performance.custom.splitmodels.rs:428Decided (ADR-0005): removed; Apollo DM splits adaptively#57, #30
performance.custom.max_connection_per_servermodels.rs:429Decided (ADR-0005): kept as the per-host connection cap Apollo DM (#30): performance.custom.maxConnectionsPerServer, on the Settings screen#47, #57, #30
performance.custom.min_split_size_mibmodels.rs:430Decided (ADR-0005): kept as the minimum segment size Apollo DM (#30): performance.custom.minSegmentMib, on the Settings screen#42, #57, #30
performance.adaptivemodels.rs:449Adapt: measured ramp-up (Apollo DM changes connections live)#47, #57
performance.allow_mid_download_tuningmodels.rs:451Decided (ADR-0005): removed (live changes are always safe; profile caps still apply); upgrade note#30, #47
performance.connection_budgetmodels.rs:453Adapt: global connection budget Apollo DM (#30): engine.connectionBudget, on the Settings screen#47, #30
performance.max_triesmodels.rs:454Adapt: Apollo DM retry classes; a download gives up after 5 failures in a row with no new byte (RetryPolicy::failures_in_a_row) Apollo DM (#30): engine.failuresInARow, on the Settings screen#48, #30
performance.retry_wait_secsmodels.rs:455Adapt: waits doubling from 1 s up to 60 s, with full jitter; at least Retry-After (up to 10 min), or 60 s, after throttling Apollo DM (#30): engine.maxRetryWaitSecs, on the Settings screen#48, #30
performance.timeout_secsmodels.rs:456Adapt: aria2's timeout was a read timeout; Apollo DM resets a request after 30 s without a byte (RetryPolicy::reset_after), with no limit on the whole transfer Apollo DM (#30): engine.resetAfterSecs, on the Settings screen#48, #30
performance.connect_timeout_secsmodels.rs:457Adapt: LoopOptions::connect_timeout, 30 s Apollo DM (#30): engine.connectTimeoutSecs, on the Settings screen#48, #30
performance.lowest_speed_limit_kibmodels.rs:459Adapt: stall watchdog on time without bytes, not speed: Stalled after 15 s, reset after 30 s; a slow but steady transfer is never reset Apollo DM (#30): engine.stalledAfterSecs, on the Settings screen#48, #30
performance.app_retriesmodels.rs:461Adapt: the engine starts a failed download again up to 2 times, after 5 s and 10 s, or 60 s and 120 s after throttling (PO decision on #48) Apollo DM (#30): engine.downloadRetries, on the Settings screen#48, #30
browser.accept_requestsmodels.rs:528Reused (#65): BrowserSettings::accept_requests, the Browser section#65
browser.confirm_before_addingmodels.rs:530Reused (#65): BrowserSettings::confirm_before_adding, on by default as in V1; torrents always ask#64, #65
notifications.on_completemodels.rs:545Reused in app_settings.rs (#29; SETTINGS.md) Apollo DM (#30): notifications.onComplete, on the Settings screen#29, #30
notifications.on_failuremodels.rs:546Reused in app_settings.rs (#29; SETTINGS.md) Apollo DM (#30): notifications.onFailure, on the Settings screen#29, #30
notifications.on_startmodels.rs:547Reused in app_settings.rs (#29; SETTINGS.md) Apollo DM (#30): notifications.onStart, on the Settings screen#29, #30
notifications.on_engine_failuremodels.rs:548Decided (ADR-0005): kept, because the engine is a helper process (ADR-0012). Reused in app_settings.rs (#29), for the transfer engine and the torrent helper Apollo DM (#30): notifications.onEngineFailure, on the Settings screen#38, #29, #30
appearance.thememodels.rs:586Reused in app_settings.rs (#29; SETTINGS.md) Apollo DM (#30): appearance.theme, on the Settings screen#29, #30
appearance.densitymodels.rs:587Reused in app_settings.rs (#29; SETTINGS.md) Apollo DM (#30): appearance.density, on the Settings screen#29, #30
appearance.visible_columnsmodels.rs:589Reused (#59): visibleColumns in the appearance settings, as typed ColumnIds (SETTINGS.md)#59
appearance.column_widthsmodels.rs:594Reused (#59): columnWidths, 48 to 1200 px, saved once a drag ends#59
appearance.layout.sidebar_widthmodels.rs:624Reused in app_settings.rs (#29; SETTINGS.md)#29
appearance.layout.sidebar_collapsedmodels.rs:626Reused in app_settings.rs (#29; SETTINGS.md)#29
appearance.layout.sidebar_visiblemodels.rs:627Reused in app_settings.rs (#29; SETTINGS.md)#29
appearance.layout.details_widthmodels.rs:629Reused in app_settings.rs (#29; SETTINGS.md)#29, #61
appearance.layout.details_visiblemodels.rs:630Reused in app_settings.rs (#29; SETTINGS.md)#29, #61
storage.history_retention_daysmodels.rs:699Reuse Apollo DM (#30): storage.historyRetentionDays, on the Settings screenReused (#32): StorageSettings (SETTINGS.md); applied at start and on change
storage.max_history_entriesmodels.rs:700Reuse Apollo DM (#30): storage.maxHistoryEntries, on the Settings screenReused (#32): StorageSettings (SETTINGS.md)
advanced.poll_interval_msmodels.rs:736Decided (ADR-0005): removed (progress arrives as events); upgrade note#30, #58
advanced.file_allocationmodels.rs:737Decided (ADR-0005): mapped to Apollo DM preallocation (none, sparse, full); default by measurement Apollo DM (#30): engine.preallocation, on the Settings screen#43, #30
advanced.enable_bittorrentmodels.rs:739Reuse Apollo DM (#30): advanced.enableBittorrent, on the Settings screen#62, #30
advanced.enable_metalinkmodels.rs:741Reuse (Apollo DM implements Metalink itself) Apollo DM (#30): advanced.enableMetalink, on the Settings screen#54, #30
advanced.user_agentmodels.rs:743Reuse: TransferSpec::user_agent, at most 256 bytes as in V1; without one, ApolloDownloadManager/<version> (PO decision on #40; VelocityDownloadManager/… until 0.2.0, #347) Apollo DM (#30): advanced.userAgent, on the Settings screen#40, #30
advanced.disk_cache_mibmodels.rs:744Decided (ADR-0005): mapped to the writer buffer size Apollo DM (#30): engine.writeBufferMib, on the Settings screen#49, #30
torrent.listen_portmodels.rs:766Adapt (libtorrent): one port, listenPort, for TCP, uTP and DHT (TORRENTS.md) Apollo DM (#30): torrent.listenPort, on the Settings screen#62, #30
torrent.dht_listen_portmodels.rs:768Adapt (libtorrent): DHT uses listenPort (TORRENTS.md) Apollo DM (#30): torrent.listenPort, on the Settings screen#62, #30
torrent.enable_dhtmodels.rs:769Reuse Apollo DM (#30): torrent.dht, on the Settings screen#62, #30
torrent.enable_dht6models.rs:770Adapt: libtorrent runs DHT on IPv4 and IPv6 together, under dht, as V1's libtorrent engine did (TORRENTS.md) Apollo DM (#30): torrent.dht, on the Settings screen#62, #30
torrent.enable_peer_exchangemodels.rs:771Reuse Apollo DM (#30): torrent.peerExchange, on the Settings screen#62, #30
torrent.enable_local_peer_discoverymodels.rs:772Reuse Apollo DM (#30): torrent.localPeerDiscovery, on the Settings screen#62, #30
torrent.dht_entry_pointmodels.rs:774Adapt (libtorrent bootstrap nodes): dhtBootstrapNodes (TORRENTS.md) Apollo DM (#30): torrent.dhtBootstrapNodes, on the Settings screen#62, #30
torrent.extra_trackersmodels.rs:776Reuse Apollo DM (#30): torrent.extraTrackers, on the Settings screen#62, #30
torrent.max_peers_per_torrentmodels.rs:777Reuse Apollo DM (#30): torrent.maxPeersPerTorrent, on the Settings screen#62, #30
torrent.global_upload_limit_kibmodels.rs:779Reuse Apollo DM (#30): torrent.uploadLimit, on the Settings screen#62, #63, #30
torrent.default_upload_limit_kibmodels.rs:781Reuse Apollo DM (#30): newTorrents.uploadLimitKib, on the Settings screen#62, #63, #30
torrent.request_peer_speed_limit_kibmodels.rs:783Decided (ADR-0005): kept if libtorrent supports it; otherwise dropped with a note. Dropped: libtorrent 2.0.15 has no such setting (TORRENTS.md)#62
torrent.seeding.modemodels.rs:147Reuse (V1 tests: seeding ratio, queue and restart) Apollo DM (#30): newTorrents.seeding, on the Settings screen#62, #63, #30
torrent.seeding.time_minutesmodels.rs:148Reuse Apollo DM (#30): newTorrents.seeding.minutes, on the Settings screen#62, #63, #30
torrent.seeding.ratiomodels.rs:149Reuse Apollo DM (#30): newTorrents.seeding.ratio, on the Settings screen#62, #63, #30
torrent.choose_files_for_magnetsmodels.rs:787Reuse Apollo DM (#30): newTorrents.chooseFilesForMagnets, on the Settings screen#63, #30
torrent.enginemodels.rs:791Decided (ADR-0005): removed; libtorrent is the only torrent engine#62, #30
torrent.libtorrent_listen_portmodels.rs:794Reuse Apollo DM (#30): torrent.listenPort, on the Settings screen#62, #30
torrent.port_mappingmodels.rs:797Reuse Apollo DM (#30): torrent.portMapping, on the Settings screen#62, #30
torrent.max_active_seedsmodels.rs:800Reuse Apollo DM (#30): torrent.maxActiveSeeds, on the Settings screen#62, #63, #30

Views and UI (22)

View or behaviourV1 codeV1 testsApollo DM dispositionApollo DM issue
App shell, routing and startupApp.tsxtests/unit/app.test.tsxReimplemented (#29): src/app/App.tsx, src/app/App.test.tsx#29
Shell layout and splittersShell.tsxtests/unit/layout.test.tsx, tests/unit/splitter.test.tsx, tests/unit/layoutLogic.test.tsReimplemented (#29): src/app/Shell.tsx; V1's layoutLogic and splitter tests ported (src/layout/layoutLogic.test.ts, src/components/Splitter.test.tsx)#29
Sidebar (filters, categories, collapse)Sidebar.tsxtests/unit/layout.test.tsxReimplemented (#29): src/app/Sidebar.tsx, with History (#32). Settings come with #30#29, #32
Status bar (speeds, counts, engine state)StatusBar.tsxnone in V1: Apollo DM adds oneAdapted (#29): the transfer engine and the torrent helper's health, not aria2's (src/app/StatusBar.tsx)#29
Downloads view (search, filters, bulk actions)DownloadsView.tsxtests/unit/app.test.tsxReimplemented (#59): src/features/downloads/DownloadsView.tsx, with the retry countdown, partial results and the login dialog (UI_ARCHITECTURE.md)#59
Download table (columns, resizing, checkboxes, keyboard)DownloadTable.tsxtests/unit/app.test.tsx (keyboard navigation), tests/unit/logic.test.tsReimplemented (#59): DownloadTable.tsx and src/downloads/list.ts; the accessibility audit is #66#59, #66
Columnscolumns.tsxtests/unit/format.test.tsReimplemented (#59): columns.tsx, with Apollo DM's binary units in src/lib/format.ts#59
Context menusmenus.tsxtests/unit/app.test.tsxReimplemented (#59, #61): menus.tsx, with "Open file", "Open folder" and "Details" (#61); choosing a torrent’s files is #63’s#59, #61
Add dialog (single, multiple, conflicts, browser prefill, .torrent, magnets, duplicates)AddDownloadDialog.tsxtests/unit/app.test.tsx, tests/unit/addLogic.test.ts, tests/unit/torrent.test.tsxReimplemented (#60): src/features/add/, with FTP, FTPS and SFTP links, the SFTP host-key question, and what the engine can't do. V1's tests ported in src/features/add/AddDownloadDialog.test.tsx and addLogic.test.ts; the file tree of a .torrent is #63's#60
Details panel (connections, errors, files, torrent sections)DetailsPanel.tsxtests/unit/app.test.tsxReimplemented (#61): DetailsPanel.tsx, from the live snapshot; V1’s tests ported in DetailsPanel.test.tsx. No per-connection or per-segment figures (the engine reports none); trackers, peers and re-announce are #63’s#61, #63
Categories viewCategoriesView.tsxnone in V1: Apollo DM adds oneReimplemented with the sidebar (#29), on #31's commands: src/features/categories/#29, #31
History viewHistoryView.tsxnone in V1: Apollo DM adds oneReimplemented (#32): src/features/history/HistoryView.tsx; "Again" opens the Add dialog with the link#32
Settings view (every section)SettingsView.tsxtests/unit/app.test.tsx, tests/unit/torrent.test.tsxReimplemented (#30): src/features/settings/; the Browser section since #65; the Proxy section since #192; V1's tests in SettingsView.test.tsx#30
Diagnostics panelDiagnosticsPanel.tsxnone in V1: Apollo DM adds oneAdapt (no aria2)#28
OnboardingOnboarding.tsxtests/unit/app.test.tsxReimplemented (#29): src/features/onboarding/Onboarding.tsx. The browser extension step since #65, pointing to Settings, Browser, as V1's did#29
Torrents: choose filesChooseFilesDialog.tsxtests/unit/torrent.test.tsx, tests/unit/torrentLogic.test.tsReimplemented (#63): src/features/torrents/ChooseFilesDialog.tsx; V1’s tests in Torrents.test.tsx#63
Torrents: file treeFileTree.tsxtests/unit/torrentLogic.test.tsReimplemented (#63): FileTree.tsx and torrentLogic.ts, without per-file progress, which the helper doesn’t report; V1’s tests in torrentLogic.test.ts#63
Torrents: seeding fieldsSeedingFields.tsxtests/unit/torrentControls.test.tsxReimplemented (#63): SeedingFields.tsx, in the Add dialog; the settings’ default is #30’s#63, #30
Torrents: details sectionTorrentSection.tsxtests/unit/torrentControls.test.tsxReimplemented (#61, #63): TorrentSection.tsx: hashes, version, peers, seeding, the seeding queue, trackers, peers, re-announce, upload limit and file changes#61, #63
Confirm dialogs and shared UIconfirm.tsxtests/unit/app.test.tsxReimplemented (#29): src/components/#29
Tray and notificationslib.rsnone in V1: Apollo DM adds oneReimplemented (#29): src-tauri/src/tray.rs and shell.rs; what is notified is velocity_core::notices. Checked by hand per platform#29
Accessibility: keyboard, focus, labels, reduced motion, themesDownloadTable.tsxtests/unit/app.test.tsxAudited (#66): each behaviour with its test or a manual check in ACCESSIBILITY.md; src/app/Accessibility.test.tsx, src/a11y.test.ts#66

Engine and manager behaviours without their own UI (26)

These behaviours run behind the scenes, so they're easy to drop without anyone noticing (issue risk). V1's integration tests are in engine_integration.rs and torrent_integration.rs.

BehaviourV1 codeV1 testsApollo DM dispositionApollo DM issue
Finalisation: Completed only when the file exists with the expected length; size-only otherwisemanager.rs:2250engine_integration: incomplete_transfer_is_not_reported_complete, engine_integration: checksum_mismatch_fails_verificationAdapt: Apollo DM completion gate (coverage, length, hash; no-clobber rename)#46, #43
Reconcile: re-add a lost download after three missed polls; ENGINE_LOST otherwisemanager.rs:1889, manager.rs:1960engine_integration: engine_restart_recovers_unfinished_downloadDecided (ADR-0005): follows #38, a helper process (ADR-0012); Apollo DM resumes from checkpoints, no GIDs. A download an engine crash, hang or restart lost resumes on its own once an engine runs (PO decision on #58, ENGINE_CONTRACT.md)#43, #58, #38
Failure classes (transient, throttled, permanent) and app-level retries; 429/503 wait ≥ 60 scodes.rs:9engine_integration: transient_failures_are_retried_with_bounded_backoff, engine_integration: rate_limited_server_is_reported_as_throttlingAdapt: classify libcurl results and HTTP status; honour Retry-After#48
Engine supervision: restart back-off (at most five restarts in five minutes)mod.rs:6engine_integration: engine_crash_is_restarted_and_download_resumesDecided (ADR-0005): follows #38, a helper process (ADR-0012)#38, #39
Session scrubbing: credentials never kept in the engine sessionmod.rs:193engine_integration: engine_session_file_never_keeps_credentialsDecided (ADR-0005): no aria2 session; checkpoints never hold secrets#43, #71
Secrets handling: credentials held in memory, never storedsecret.rsengine_integration: ftp_login_is_sent_as_ftp_credentials_and_never_stored, engine_integration: ftp_user_and_password_in_the_link_are_used_and_removed_from_itReimplement. The FTP part is reimplemented (#51): the login goes out as FTP's USER and PASS (velocity-transfer tests/engine_contract.rs), and a login in an FTP link is split off and never stored (velocity-core's database secret scan). The keychain and the leak scan remain. Since #70: a Secret type wiped when dropped (crates/velocity-core/src/secret.rs), and the system keychain on consent per login (ADR-0015); the leak test in crates/velocity-transfer/tests/secret_leaks.rs#70, #71
Redaction of URLs, headers and keys in logs and diagnosticsredact.rs:14none in V1: Apollo DM adds oneReimplemented (#28): velocity_core::redact, V1's patterns and tests, plus private keys, proxy logins, libcurl debug lines, JSON passwords and logins with an @ in the password; the child processes' logs use it too#28
URL validation: scheme allowlist, IDN, credentials out of the URLvalidation.rs:42engine_integration: invalid_urls_are_rejected_before_the_engineReimplement; SFTP allowed in Apollo DM#67
File naming: typed names, server names, extensions, reserved namesvalidation.rs:148engine_integration: typed_names_keep_the_file_type_of_the_link, engine_integration: links_without_a_file_name_use_the_server_nameReuse in substance#31, #40, #72
Destination conflicts never overwritten silentlycommands.rs:108engine_integration: destination_conflicts_are_never_overwritten_silentlyReimplement#31, #43
Schedule windowschedule.rs:13none in V1: Apollo DM adds oneReuse in substance#50
Optimizer: chooses aria2 options per profile; halves connections on throttled retriesoptimizer.rs:30none in V1: Apollo DM adds oneDecided (ADR-0005): replaced by profile caps and adaptive budgets#47, #57
Multiple connections on range servers; one connection without ranges—engine_integration: range_server_uses_multiple_connections, engine_integration: non_range_server_downloads_with_one_connectionAdapt: bounded probe, leases#41, #42
HTTPS certificate rules (trusted, untrusted, purpose, host, expiry)—engine_integration: https_download_with_trusted_certificate, engine_integration: https_with_untrusted_certificate_fails, engine_integration: https_certificate_not_valid_for_server_auth_is_rejected, engine_integration: https_certificate_for_another_host_is_rejected, engine_integration: https_expired_certificate_is_rejectedReimplemented per TLS backend: velocity-curl tests/tls.rs and tests/windows_store.rs, velocity-transfer-h2c tests/tls.rs; results per platform in SECURITY.md#69
FTP downloads—engine_integration: ftp_download_completes_with_integrity, engine_integration: ftp_missing_file_fails_with_an_errorReimplemented on libcurl, with REST resume and explicit and implicit FTPS: velocity-transfer tests/ftp.rs and tests/engine_contract.rs, velocity-curl tests/ftp.rs, velocity-transfer-h2c tests/ftps.rs (ENGINE_INTERNALS.md)#51
Engine missing is reported—engine_integration: engine_missing_is_reportedDecided (ADR-0005): follows #38, a helper process (ADR-0012)#38
Browser bridge: IPC with a per-launch token; 30 requests per 10 sipc.rs:12none in V1: Apollo DM adds oneReimplemented (#65): crates/velocity-core/src/browser/ipc.rs and bridge.rs, with Apollo DM's endpoint and token file#65
Native-host registration per browsernative_registration.rs:144none in V1: Apollo DM adds oneReimplemented (#65): crates/velocity-core/src/browser/registration.rs, Windows' registry through windows-sys#65
Single instancelib.rs:36none in V1: Apollo DM adds oneReimplement with Apollo DM identifier#27
Torrent duplicates by info hash; corrupt and malicious torrents rejected—torrent_integration: duplicates_are_detected_by_info_hash, torrent_integration: corrupt_and_malicious_torrents_are_rejected_before_the_engineReimplement on libtorrent#62
Torrent v1, v2-only, hybrid and magnet downloads—torrent_integration: torrent_file_multi_file_downloads_and_verifies, torrent_integration: v2_only_torrents_download_on_libtorrent, torrent_integration: v2_magnet_downloads_on_libtorrent, torrent_integration: hybrid_downloads_on_libtorrent_from_libtorrent_and_knows_both_hashesReimplement on libtorrent#62
Torrent recovery after restart and engine crash—torrent_integration: restart_recovers_interrupted_torrent_without_duplicates, torrent_integration: magnet_recovers_after_restart_using_saved_metadata, torrent_integration: engine_crash_recovers_torrent, torrent_integration: a_paused_torrent_stays_paused_after_restartReimplement#62
Seeding policies and the seeding queue—torrent_integration: seeding_stops_when_the_share_ratio_is_reached, torrent_integration: the_seeding_queue_limits_active_seeders_and_starts_the_next, torrent_integration: lowering_the_seeding_limit_queues_the_newest_seeders, torrent_integration: seeding_resumes_after_restart_without_redownloadingReimplement#62, #63
Torrent deletion: only the torrent's files, never through links—torrent_integration: deleting_a_completed_multi_file_torrent_removes_only_its_files, torrent_integration: deleting_an_active_torrent_removes_partial_data_and_control_file, torrent_integration: deletion_never_follows_links_out_of_the_download_folderReimplement#62, #72
Missing peers show as stalled, not failed—torrent_integration: missing_peers_show_as_stalled_not_failedReimplement#62
aria2-only torrent behaviours (aria2 torrents, switching torrent engine, aria2 hybrid handling)—torrent_integration: switching_the_engine_never_moves_existing_torrents, torrent_integration: reannounce_is_refused_for_aria2_torrents_with_a_reason, torrent_integration: v2_only_torrents_are_refused_on_aria2_with_an_explanationDecided (ADR-0005): dropped; libtorrent is the only torrent engine#62

Browser extension and native host (11)

BehaviourV1 codeV1 testsApollo DM dispositionApollo DM issue
Download interception and modes (ask, add directly, off)background-core.ts:152browser-extension/tests/background.test.tsReimplemented with Apollo DM identity (#64): browser-extension/src/background-core.ts; V1's tests in browser-extension/tests/background.test.ts#64
Allow and deny rulesrules.ts:16browser-extension/tests/rules.test.tsReused (#64): browser-extension/src/shared/rules.ts; V1's tests in browser-extension/tests/rules.test.ts#64
Context menu ("Download with Velocity")background.ts:50browser-extension/tests/background.test.tsReimplemented (#64) as "Download with Apollo Download Manager" (#347): browser-extension/src/background.ts#64
Popuppopup.tsnone in V1: Apollo DM adds oneReimplemented (#64): browser-extension/src/popup.ts#64
Options pageoptions.tsnone in V1: Apollo DM adds oneReimplemented (#64): browser-extension/src/options.ts#64
Confirmation promptprompt.tsnone in V1: Apollo DM adds oneReimplemented (#64): browser-extension/src/prompt.ts#64
Magnet capture (always through the Add dialog)magnet.ts:2browser-extension/tests/background.test.tsReimplemented (#64): browser-extension/src/magnet.ts, off by default#64, #63
Extension settings storagesettings.tsnone in V1: Apollo DM adds oneReimplemented (#64): browser-extension/src/shared/settings.ts#64
Native messaging client and protocol v1native.ts, protocol.tsbrowser-extension/tests/protocol.test.tsReimplemented (#64): protocol v1 unchanged, to Apollo DM's host name; V1's tests in browser-extension/tests/protocol.test.ts. The host side is #65#64, #65
Native host: framing, caller allowlist, message filtering, desktop unavailable, wrong tokenmain.rscrates/velocity-native-host/tests/host_e2e.rsReimplemented (#65): crates/velocity-native-host, the program velocity-native-host-v2; V1's tests in crates/velocity-native-host/tests/host_e2e.rs#65
Shared message protocol and validation (core side)protocol.rs:18none in V1: Apollo DM adds oneReimplemented (#65): crates/velocity-core/src/browser/protocol.rs, checked by the host and again by the app#65, #67

Persistence (6)

BehaviourV1 codeV1 testsApollo DM dispositionApollo DM issue
Initial schema: settings, categories, downloads0001_initial.sql:4none in V1: Apollo DM adds oneNot reused: Apollo DM has its own schema and migrations (Apollo DM never opens V1's database, ADR-0003)#26
Torrent columns (info hash, uploaded bytes, seeding start)0002_torrents.sql:4none in V1: Apollo DM adds oneApollo DM schema equivalent#26, #62
Torrent engine columns (v2 info hash, engine)0003_torrent_engines.sql:3none in V1: Apollo DM adds oneApollo DM schema: engine holds Apollo DM engines only; unknown values become unavailable#26
Settings JSON migration on load (older settings get defaults)settings.rs:11Reimplemented (#30): Database::section reads a section merged over its defaults; an unknown field is refused#30
Backup before migrating (VACUUM INTO); refuse a newer schema unmodifiedmod.rs:7none in V1: Apollo DM adds oneReimplement#26
Importing anything from a V1 installation——Decided (ADR-0007): no import in the first releases; revisit after parity#85

Apollo Download Manager additions (not V1 features)

Behaviours Apollo Download Manager adds by PO decision. They aren't parity rows, because V1 didn't have them, but they're first-release scope.

AdditionDecisionApollo DM issue
SFTP downloads with strict host-key checksADR-0001 (HTTP, HTTPS, FTP and SFTP required); built on russh (ADR-0013): velocity-sftp tests/sftp.rs, velocity-transfer tests/sftp.rs#52, #53
Proxy settings (HTTP, HTTPS, SOCKS5) for every download, torrents included, with the password in the OS keychain on consent; ambient proxy variables ignoredADR-0008, PO decisions on #192: velocity_core::proxy, the Settings screen's Proxy section (SETTINGS.md)#192, #70
Confirmation for browser links to loopback or private addressesADR-0006#67, #65
Changed-object detection, validator-checked resume and atomic no-clobber completionADR-0001, research report section 5#43, #45, #46

Decided in #23

18 rows changed meaning without aria2. The PO decided each one on 2026-10-22 (ADR-0005); the rows above say Decided (ADR-0005).