Confidence hardening: Arr hierarchy, Phase2 SoT, CI drift, live smoke#505
Confidence hardening: Arr hierarchy, Phase2 SoT, CI drift, live smoke#505Feramance wants to merge 59 commits into
Conversation
Introduce Vitest with jsdom and Testing Library so frontend refactors can be guarded by golden-master tests, and wire frontend-test into PR and any-branch CI workflows.
Extract shared getSelectStyles, normalizeNumericId, and createStandardArrFilters helpers with golden-master tests; remove verified-dead components, API exports, definition props, and orphaned context fields.
Capture current behavior for coerce_bool, normalize_url_base, qbit_sections, parse_duration, enum normalization, iter_arr_sections, tables field snapshots, load_qbit_seeding_config, and the auto_update unsupported-platform message.
The unsupported-platform message previously used the last loop variable from asset_patterns instead of the pattern that actually matched unsupported_platforms.
Drop unused ResilientSqliteDatabase, dead catalog_rollups helpers, PlaceHolderArr redundant overrides, arss no-op statements, and fold _tracker_host_matches into arr_tracker_index usage.
Remove verified dead code (format_bytes, ResilientSqliteDatabase, dead catalog_rollups helpers, unused arss helpers/no-ops). Extract shared helpers: coerce_bool, normalize_url_base, qbit_sections, load_qbit_seeding_config, parse_duration, _normalize_enum, iter_arr_sections, and ArrFileRowFieldsBase for tables.
Extend get_*_effective() pattern to PingURLS, categories, timers, FFprobeAutoUpdate, and global IgnoreTorrentsYoungerThan; migrate loop call sites in arss.py, utils.py, and ffprobe.py with golden-master tests.
Bump pyarr floor to >=6.6, replace pyarr_compat with arr_client builders and execute_command fallback; rewrite arss/webui call sites with tests.
Move Arr, PlaceHolderArr, TorrentPolicyManager, and ArrManager into separate modules with shared imports and stable qBitrr.arss re-exports.
Consolidate changelog modals into a single variant-based component, extract formatVersionLabel and persisted boolean setter factory, and fix catalog/list typing after the ConfigView split and Arr catalog dedup landings.
Extract WebUI._build_app, dual_route/_dual_route, resolve_arr_handler, and parse_catalog_filters; consolidate catalog_rollups with get_rollup_slice, _availability_counts, and get_sonarr_series_counts_total alias.
Split torrent batch/inspector/dispatcher logic into targeted mixins, move db_update_single_series into db_update_handlers with quality_profile_helpers, and add regression tests for per-type db_update paths including profile-tracking fixes.
Select grouped vs flat catalog definitions from WebUIContext so Sonarr shows series rows with modal when grouped and a flat episode table when not, and Lidarr shows artist rows when grouped vs album rows when flat. Adds vitest coverage for mode helpers and definition selection.
Share URI-keyed tracker merge across Arr, qBitCategoryManager, and arr_tracker_index; consolidate ColoredFormatter style maps in logger.py.
Register 25 identical /api+/web pairs via _dual_route, use resolve_arr_handler/parse_catalog_filters in catalog handlers, add empty_catalog_payload, and expand route contract tests.
Cover webui, quality profiles, process restart, qbit category/subcategory, HnR settings, and HitAndRunClearMode consolidation migrations. docs: update development guides for pyarr>=6.6,<7 floor
Split db_update_single_series into update_sonarr_episode/series, update_radarr_entry, and update_lidarr_album/artist dispatch targets while preserving all pre-existing per-type behavior.
Cover all 25 dual_route pairs with static registration check, keep three divergent pair assertions, and add apply_config_migrations legacy chain test.
Add vitest/RTL tests for urlBase, API URL helpers, ChangelogModal variants, Arr catalog empty/list/grid branches, filter combinations, config validation edge cases, and catalog fetch primitives hooks.
…on suites Introduce feature-detection flags for cross-branch unittest gating and add focused combination tests for arr_tracker_index, auto_update, category_paths, config_version, and quality_profile_helpers.
…e paths Add combination coverage across live-reload getters, catalog rollup cache refresh, migration no-op edge cases, spawn role matrix, webui route/token pairs, Radarr profile switches, and arr_client URL parsing with refactor-only skipUnless gates for cross-branch compatibility.
Harden branch_compat module detection, add patch-target helpers for arss multi-instance tests, and gate refactor-only characterization suites with skipUnless markers so the suite runs cleanly on both branches.
Skip coerce_bool and URL-base tests on master where helpers do not exist, and replace the last hardcoded torrent_batch_mixin patch target.
Add config_reload_policy with live/qbit_hot/Arr preserve_db paths, wire quality_profile helpers and duration/live getters, and fix Sonarr v6 enrichment. Update WebUI UrlBase handling, docs/openapi, and coverage.
Package qBitrr.arss for Docker installs, restore split-module imports needed for Arr startup, and add a v4 DB migration for Lidarr artist profile columns. Move instance Save/Delete into Configure modals and remove the redundant page footer bulk save.
Clear loading when the latest fetch generation finishes, mark empty-state ready on errors, and align albums API total with artist- vs album-paged modes so aggregate clients no longer plan hundreds of empty pages.
Carve dense Arr algorithms into focused modules, replace star imports, dedupe catalog chrome via a shared body helper, and drop dual-branch test scaffolding now that this branch is the sole target.
Drop the obsolete WebUI grouping toggles and always use series/artist row catalogs with detail modals; migrate stale config keys away.
Break monolith modules into focused packages and helpers so Arr workers, config generation, and the Flask WebUI are easier to navigate and maintain.
Fix service-worker /web caching, add TTL GET reuse, keep visited tabs warm, stabilize Arr renders, and lighten motion while dropping unused frontend deps.
…t, live smoke. Exit cleanly after first-boot config generation; split Arr into RadarrArr/SonarrArr/LidarrArr; drive config/FE from field registries with overlays; gate CI on config_fields and openapi drift; add docker-compose.test smoke docs and characterization tests.
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
MkDocs strict mode rejected the relative repo-root link from development/testing.md.
CodeQL flagged clear-text logging of sensitive data; log set/unset only.
CodeQL still taints set/unset derived from apikey; hardcode [redacted] only.
There was a problem hiding this comment.
Bug Scan Summary (Deep Bug-Finding Automation)
Date: 2026-07-17
Commits inspected: fe75c816..d436822b (33 commits on PR #505)
Result: No critical bugs found.
Tests: 263/263 unit tests pass (QBITRR_OVERRIDES_DATA_PATH required in CI-like envs).
Deduplication check
- Open PRs: searched
live reload,apply_config_refresh,SearchMissing worker— only #505 (this PR); no competing fix. - Recently merged (14d): no live-reload worker-sync fixes.
- Open issues: none matching.
Areas reviewed (no critical finding)
| Area | Verdict |
|---|---|
arss/ package split |
Factory/manager/spawn wiring intact; 263 tests green |
webui/ auth |
_dual_route still guards /api/* + /web/*; public endpoints unchanged |
ResilientSqliteDatabase removal |
get_database() uses with_database_retry on connect — equivalent |
| DB schema v4 | Adds missing Lidarr artist profile-switch columns; retries on failure |
process_lifecycle / spawn |
Behavior-preserving extract; spawn-cleanup tests pass |
First-boot CONFIG NameError |
Fixed (sys.exit(0) before unset CONFIG access) |
Below confidence bar (pre-merge note, not blocking)
Arr LIVE reload does not reach forked workers. _apply_arr_live_refresh calls apply_config_refresh on the supervisor Arr object only. Worker processes keep stale self.search_missing, self.auto_delete, self.re_search, tracker config, etc. because _sync_loop_settings_from_config() only syncs timers/limits.
Trigger: Save Radarr.Main.EntrySearch.SearchMissing=true via WebUI while search worker was never spawned (or while torrent worker is running with old AutoDelete). UI returns reloadType: "live" but automation behavior is unchanged until manual Arr respawn/restart.
This is a functional regression vs pre-PR behavior (all Arr config changes respawned workers), but it does not meet the critical bar (no crash, data loss, auth bypass, or write-loss race). Recommend either extending worker _sync_loop_settings_from_config + respawning when spawn gates change, or reclassifying behavior-affecting Arr keys to ARR_PRESERVE_DB.
Sent by Cursor Automation: qBitrr - Find critical bugs
Load generated CONFIG and skip sys.exit(0) when PyInstaller is importing, so Windows package jobs no longer die on SystemExit during freeze analysis.
Generate and load default CONFIG without sys.exit in config.py; main.run() exits 0 when CONFIG_EXISTS is false so Docker first-boot stays clean.
Keep caches, runtime dirs, and temporary docs out of commits; drop already-tracked gren-changelog.log, logo.psd, and planning markdown.
Signed-off-by: Feramance <38938175+Feramance@users.noreply.github.com>
Workers sync SearchMissing/AutoDelete/trackers each loop; FailedCategory renames require full restart; polymorphic search/DB hooks; multi-qBit category stats; SkipTLSVerify in Config FE; docs and characterization tests.
…s, and polymorphism Expand Arr LIVE worker sync, rebind Waitress on Host/Port, preserve Arr DBs on PlaceHolder renames, finish type hooks, split WebUI routes, drop Questarr docs, and wire Vitest coverage.
Docker image builds run tsc -b; keeping *.test.ts(x) in the app project broke the WebUI stage.
Supervisor reconciles search-worker topology after Arr LIVE saves so enabling SearchMissing actually starts the search process without a full Arr respawn.
Replace full-tail polling with byte-cursor JSON deltas and an SSE stream (with poll fallback), add rotated-file search, and refresh the Logs UI with follow/jump, level chips, and matching docs/OpenAPI.
…t rows Replace the flat category stats table with an Arr-style card chrome, instance sidebar, collapsible monitored categories, and VueTorrent-inspired torrent list rows backed by GET /web/qbit/overview. Also accept /ui/ so trailing-slash entry points no longer 404.
…dation Block config persist/reload until validation passes, migrate Animarr sections to Sonarr, and fix qBit overview/category stats edge cases with tests and docs.
Hide the overview tab (and its number-key binding) unless status reports at least one qBit instance, matching Arr tab visibility.
…lights Show every invalid path in save toasts, highlight matching modal fields, and accept numeric RemoveTorrent / -1 Arr seeding limits so Lidarr saves succeed.
Align qBit rate/ratio validation with docs, skip invariants on deleted sections, preserve redacted secrets across renames, and scope server errors to the open modal section.
… SW shells Reconcile qBit clients on reload so Processes no longer shows empty renamed cards, confirm and persist Arr/qBit instance deletes without a separate Save, and keep confirm dialogs above portaled modals while network-firsting HTML to avoid blank UI after deploys.
Replace Live Arr with an app-bar Live switch for Arr/qBit polling, restore user-facing Processes cards/chips with deep-links, and treat qBit as disabled when no [qBit]/[qBit-*] section exists without auto-creating one.
Shared status badges and loading overlay for Arr catalogs, app-bar Theme and Help menu, simplified Logs toolbar, Config empty/validation UX, and qBit overview scanability plus a11y/token polish.
Require AllowInsecureExposure for AuthDisabled on public binds (legacy missing key stays warn-only), keep token endpoints unchanged, and tighten FFprobe downloads, pip updates, CSP, query-token opt-in, and CI defaults.
Auto-expand was treating user-closed sections as unset on every overview reload; also stop remounting the qBit tab on visibility change.


Summary
_apply_arr_live_attrs_from_configsyncs the full LIVE-classified EntrySearch/Torrent/Ombi/Overseerr set; ARR_PRESERVE_DB identity keys (URI/APIKey/SkipTLSVerify/Managed/importMode/Category) stay respawn-only.create_server→close()→ rebind (Token/UrlBase soft-apply unchanged).db_queries/request_providers/ temp-profile / search hooks onRadarrArr/SonarrArr/LidarrArr; Sonarr Ombi partial-approve searchable when any child approved.register.pythin registrar; config/process/log/status route modules; ArrBase facades collapsed to top-level aliases.npm run test:coveragewired (no CI %-fail gate); multi-qBit category stats + SkipTLSVerify FE.Local gates
python -m unittest discover -s tests— 292 passed (.venv)cd webui && npm test— 112 passedscripts/config_fields_check.py --check-reload— OKscripts/openapi_check.py— OK (70/70)rg -i questarr— clean on tracked treeLive smoke results (
docker-compose.test.yml/ characterization)test_config_first_boot)AutoPauseResumeliveSearchMissing+ LIVE attr matrixtest_live_reload_characterization)RadarrArrspawntest_arss_startup/ factory)blocklist=test_smoke_matrix)test_smoke_matrix)test_smoke_matrix)test_webui_waitress_rebind)test_webui_config_reload)test_search_and_db_query_hooks)Test plan