fix: preserve CHANGE_ME qBit placeholder sections on config save#282
Conversation
Unfinished [qBit-*] sections with Host = CHANGE_ME were dropped from config.toml whenever POST /web/config or POST /api/config saved unrelated changes. ApplyDottedConfigChanges excluded them from the merge snapshot and SaveConfig omitted them from TOML output. Include all qBit instances in the Host config round-trip and write CHANGE_ME placeholders to disk so multi-instance setup stubs survive. Regression tests: - ConfigurationLoaderTests.SaveConfig_PreservesChangeMeQBitPlaceholderSection - ConfigPlaceholderPreservationTests.PostConfig_UnrelatedChange_PreservesChangeMeQBitSeedboxStubOnDisk Co-authored-by: Feramance <Feramance@users.noreply.github.com>
There was a problem hiding this comment.
PR Validation (Cursor Automation)
Recommendation: Close (obsolete)
Primary reason: PR #282 is already merged and its fix is already present on current origin/master (269fb98); the local post-merge tree has no diff against master.
Gates
| Gate | Status | Notes |
|---|---|---|
| Merge conflicts | Pass | git merge origin/master completed cleanly; conflicts: none. |
dotnet build |
Pass | Release build succeeded with 0 errors. |
dotnet test (non-live) |
Fail | Required full command failed: 8 failed, 758 passed, 766 total. The failing classes (ArrThumbnailServiceTests, ConfigReloaderTests) passed when rerun individually, indicating an isolation-sensitive baseline issue on the current merged tree. |
vitest |
Pass | 16 files passed, 154 tests passed. |
npm run build (webui) |
N/A | Original PR diff does not modify webui/; not required. |
Validation
| Axis | Score | Notes |
|---|---|---|
| Purpose | Fail | The bug is no longer present on master; this exact fix is already incorporated. |
| Correctness | Pass | The merged fix preserves all qBit instances, including CHANGE_ME placeholders, during dotted config saves; no schema version bump required. |
| Tests | Pass | Regression coverage was added for config serialization and /web/config preservation; test count did not drop below baseline. |
| Hygiene | Pass | Focused 5-file backend/test change; no generated junk or unrelated noise. |
| Overlap | Fail | Already fixed on master by this merged PR (269fb98). |
Why
gh pr view 282 reports state MERGED, and origin/master contains fix: preserve CHANGE_ME qBit placeholder sections on config save (#282). After merging current origin/master into the PR head locally, git diff origin/master HEAD is empty, so there is no remaining branch content to merge.
The full .NET non-live suite currently fails on the merged baseline with isolation-sensitive failures, but that is not the primary reason for this recommendation because the PR has already landed and the merged tree is identical to current master.
Required audit notes could not be read because docs/audits is absent in the merged checkout.
Overlap
None. This is already incorporated on master as PR #282 / commit 269fb98.
Commands run
git fetch origin master; git fetch origin cursor/bug-finding-automation-b5ee; git checkout -B pr-validate origin/cursor/bug-finding-automation-b5ee; git merge origin/master; /tmp/dotnet/dotnet restore; /tmp/dotnet/dotnet build -c Release; /tmp/dotnet/dotnet test -c Release --no-build --filter "Category!=Live"; targeted .NET reruns for failing classes; cd webui && npm ci && npx vitest run.
Sent by Cursor Automation: Torrentarr PR validation triage
There was a problem hiding this comment.
Bug scan — PR #282
Commits inspected: 3f2c16f..533c234 (1 commit)
Result: The fix is correct. No new critical bugs introduced.
Original bug (confirmed, now fixed)
Severity: Silent data loss
Trigger: User has a configured [qBit] plus an unfinished [qBit-*] stub with Host = "CHANGE_ME". Any unrelated POST /web/config or POST /api/config save (e.g. changing settings.loopSleepTimer) dropped the stub from config.toml.
Root cause: Two coordinated filters excluded CHANGE_ME qBit instances from the save round-trip:
ApplyDottedConfigChangesomitted them from the merge snapshot (currentObj)ConfigurationLoader.SaveConfigskipped them when writing TOML
Fix assessment: Removing both filters is the minimal correct change. Runtime paths (ProcessOrchestratorService, ArrWorkerManager, status endpoints) still gate on Host != "CHANGE_ME", so preserved stubs are not contacted.
Tests: SaveConfig_PreservesChangeMeQBitPlaceholderSection and PostConfig_UnrelatedChange_PreservesChangeMeQBitSeedboxStubOnDisk directly cover the failure mode. Full non-live suite: 766/766 pass.
Deduplication
- Open PRs: #282 is the fix itself (merged as
269fb98on master) - Recently merged: #281 (Imported scoping), #283 (PasswordHash section-replace bypass) — unrelated
- Open issues: none found for this bug class
Below confidence bar (not blocking)
GET /web/config on Host still omits CHANGE_ME qBit sections from the JSON payload while stubs persist on disk. That pre-existing GET/POST asymmetry can let the UI add qBit-1 while qBit-seedbox remains hidden on disk — UX confusion, not data loss, and improved by this fix.
Sent by Cursor Automation: Torrentarr - Find critical bugs


Summary
Unfinished
[qBit-*]sections withHost = "CHANGE_ME"were silently removed fromconfig.tomlwheneverPOST /web/configorPOST /api/configsaved unrelated changes (e.g. tweakingSettings.LoopSleepTimer). This is a common workflow when adding a second qBit instance stub before filling in credentials.Root cause:
ApplyDottedConfigChangesexcludedCHANGE_MEqBit instances from the merge snapshot, andConfigurationLoader.SaveConfigalso omitted them from TOML output.Fix: Include all qBit instances in the Host config round-trip and write
CHANGE_MEplaceholders to disk.Testing
ConfigurationLoaderTests.SaveConfig_PreservesChangeMeQBitPlaceholderSectionConfigPlaceholderPreservationTests.PostConfig_UnrelatedChange_PreservesChangeMeQBitSeedboxStubOnDiskdotnet test --filter "Category!=Live" -c Release— 761 passedChecklist