π οΈ Action Plan (Prioritized)
Use this section as the tracked backlog for technical-debt work. Items are ordered by expected impact and ease of rollout. Each item includes a short why, recommended fix, risk, and rough estimate.
Last verified against source: 2026-08-29. Desktop + Android build: 0 warnings / 0 errors. Test suite: 733 passed (
dotnet format whitespace --verify-no-changesclean). Source version: 2.0.5 (net10.0).
- App.axaml.cs composition root (Priority: High) β β
DONE 2026-08-28
- Why: 1,906 lines β the largest file in the codebase. Manual
newwiring of 18 services, splash logic, dialog creation, action-delegate wiring, mobile init β all in one file. No DI container. - Fix:
AppServicescomposition root +DesktopUiActions/MobileUiActionsper-platform wiring. β implemented - Result:
App.axaml.cs1,978 β 376 lines (boot + dispatch + error-handling + update-check).AppServices.cs(~163 lines) builds 20 services + 8 VMs; desktopβ‘mobile duplication killed. Logging anchors added on both platforms. - Verify: build 0/0, suite green; manual smoke on desktop (wizardβconnectβtoolsβcustom install) and Android (overlay toolsβwizardβSAF).
- Why: 1,906 lines β the largest file in the codebase. Manual
- Extract coordinators from large ViewModels (Priority: High)
- Why: FileExplorerViewModel (1,809 lines), BrowseViewModel (915), InstalledViewModel (887), CustomInstallViewModel (681) all violate SRP.
- Fix: Extract
FileExplorerTransferCoordinator,BrowseInstallCoordinator,ThumbnailService, inject them. - Risk: medium-high (integration surface), perform incrementally.
- Estimate: 16β40 hours.
- Convert
async voidhandlers (Priority: High β safety) β β DONE 2026-08-27- Current: 0 remaining (was 20). All converted to
FireAndForget-wrappedasync Tasklocals orasync Task. - Why:
async voidthrows unobserved exceptions and can crash app. - Fix: Wrap body in
SafeFireAndForgethelper (already exists inTaskExtensions.cs); convert toasync Taskwhere possible. β implemented - Risk: low.
- Estimate: 4β8 hours.
- Current: 0 remaining (was 20). All converted to
- Secrets: XOR obfuscation β β
DONE 2026-08-27 (Priority: High β security)
CryptoServicenow uses SEC2: AES-256-GCM with a key derived via PBKDF2 (SHA-256, 100k it) from machine+user identity + per-install random salt. Pure managed, cross-platform (Windows/macOS/Linux/Android), zero P/Invoke, zero new UX.- Legacy XOR values (pre-SEC2 builds) still decrypt on read and are re-encrypted on the next save (lazy migration) β installed configs keep working.
- A config copied to another machine/user is undecryptable;
TryDeobfuscatereturns false and the app prompts the user to re-run the Setup Wizard (desktopConfirmWindow, mobileMobileConfirmDialogView) + inline warning in Settings with a Reconfigure button. - Shared-configs-between-OSes is not a supported scenario (user decision).
- Increase tests for Xbox domain services (Priority: High) β β
DONE 2026-08-27
- Full Xbox HTTP coverage via stubbed transport:
XboxSystemService(12: screenshot retry/cancel/fail, system-info retention, reboot/shutdown params),XboxNetworkService(12: ipconfig/interfaces/networks passthrough + errors),XboxProcessService(6: kill no-op unconfigured, running-list empty/fail, running title),XboxPerformanceService(9: not-configured guard, canceled-token, real WebSocket loopback server receiving snapshot, fragmented frames, malformed JSON). Plus earlier suites (auth, package dep-install, portal, zip, ProgressReadStream). Latest: +3 dep-settle tests (XboxPackageInstallFlowTests): dep-wait idle-then-D02 skip w/o kill, dep-wait-never-settles fallback, final-settle non-target early-break. Suite: 733 tests (was 679).
- Full Xbox HTTP coverage via stubbed transport:
- Cancellation/disposal audit β β
DONE 2026-08-27 (Priority: Medium)
- Current:
CustomInstallViewModelnow implementsIDisposable(disposes_analyzeCts); all 4 hosts callvm.Dispose()on window close / overlay close. (MobileLogsView._shareCtsIS disposed in the finally block.) - Fix: Implement IDisposable on CustomInstallViewModel. β implemented
- Risk: low.
- Estimate: 2β4 hours.
- Current:
- Bare
catch { }blocks (Priority: Medium) β β DONE 2026-08-27- Current: 0 bare
catch { }remain (was 26). All now have explicit// whycomments (self-protection / best-effort cleanup / fallback) or log. Best-effort cleanups and logger self-protection intentionally stay silent (recursive logging loop); GoFile request/response parses and QR clipboard writes now logWarnon failure. - Fix: Add explicit
// whycomments where intentional; log where possible. β implemented
- Current: 0 bare
.Resultblocking calls (Priority: Medium) β π ³ deferred (user sign-off required)- Current: 3 instances in SftpService.cs (lines 550, 595) and XrayAgentService.cs (line 263).
- Fix: Replace with proper
awaitor extract to async methods. BUT βSftpServiceandXrayAgentServiceare delicate (cmd.exe / sync calls); both work perfectly and are not to be retested. Address only as a carefully-tested refactor with explicit sign-off. - Risk: low (but platform-sensitive).
- Estimate: 1β2 hours.
- Service/ViewModel documentation (Priority: Medium)
- Current: 26/37 services missing class-level XML
<summary>docs (~8% coverage). (CryptoServicegained a full summary in the SEC2 pass.) - Fix: Add XML docs to all service classes and key ViewModel public members.
- Risk: low.
- Estimate: 4β8 hours.
- Current: 26/37 services missing class-level XML
- CI checks & analyzers (Priority: Low) β β
DONE 2026-08-27
- Current: new
formatjob in.github/workflows/build.ymlrunsdotnet format whitespace --verify-no-changesonXBVault.csproj+ tests csproj (ubuntu-latest).EnforceCodeStyleInBuild+AnalysisLevelalready active inDirectory.Build.props. Whole-repo whitespace sweep applied the same jobβs rules (46 files, whitespace only).
- Current: new
- UI clipping workaround (Priority: Low) β β
resolved
- Why: Avalonia 12 CornerRadius does not clip inner Image.
- Status: Not blocking β images render acceptably.
- Fix:
RectangleGeometryclip orImageBrushrender path if needed. - Risk: low.
- Estimate: 1β2 hours.
- Hardcoded URLs (Priority: Low) β β
DONE 2026-08-27
- Current: 33 hardcoded URL strings β 0 remaining outside the registry.
- Fix: Centralized in
XBVault/Configuration/AppUrls.cs(root namespaceXBVault, so no usings needed app-wide). API endpoints (catalog, GitHub release API, overrides raw), Gofile servers/contents/upload, Google Drive export, Discord invites (3), project/docs/legacy sites. Templated hosts viastring.Format(InvariantCulture) with cachedCompositeFormat. - Risk: low.
- Estimate: 1β2 hours. β implemented
Removed from backlog
- ConfigureAwait(false) sweep β user decision: this is a client app, not a library; the sweep is noise. Removed rather than scheduled.
Quick wins to do immediately
Wrapβ DONE 2026-08-27 (see item 3).async voidhandlers withSafeFireAndForgetCentralize API URLs in a constants fileβ DONE 2026-08-27 (see item 12).- Add IDisposable to CustomInstallViewModel (CA1001 suppressed) β β done 2026-08-27.
How to track progress in this doc
- Mark item status with emoji: β done, β οΈ in-progress, β³ planned, β blocked.
- Add per-item
owner,branch, andPRlinks when work starts.
Technical Debt
Known issues in the codebase, ordered by severity. This page is updated as items are resolved or discovered.
Last verified against code: 2026-08-29 (main worktree). Line counts and locations below reflect current source. 733 tests green, desktop + Android build 0 warnings / 0 errors. Source version: 2.0.5.
π΄ High
1. App.axaml.cs composition root β β
RESOLVED 2026-08-28
File: XBVault/App.axaml.cs (376 lines, was 1,978)
Resolved by the composition-root refactor:
- Services + VMs built in
AppServices.Create()/Initialize()(20 services + 8 VMs) β no DI container, no duplicated desktopβ‘mobile wiring. - Per-platform startup now delegates to
DesktopUiActions/MobileUiActions(named methods for dialogs, connect flows, per-platform behaviors). InitAfterSplashAsync/InitAndroidAfterSplashAsyncduplicate wiring eliminated;App.axaml.csholds only boot, dispatch, error handling, and the update check.- Logging audit closed the coverage gap with startup-completion anchors on both platforms.
Fix approach (documented for reference): the original plan called for Microsoft.Extensions.DependencyInjection + a CompositionRoot class. The implemented pass used manual AppServices composition instead β consistent with the projectβs explicit no-DI-container choice (#461), smaller diff, and no reflection/AOT risk on Android.
2. Large ViewModels β 5 files exceed 600 lines
Files:
| File | Lines | Notes |
|---|---|---|
ViewModels/FileExplorerViewModel.cs |
1,809 | SFTP nav, file ops, transfers, portal, drag/drop, toolbar state |
ViewModels/BrowseViewModel.cs |
915 | Catalog, thumbnails, install orchestration |
ViewModels/InstalledViewModel.cs |
887 | Package list, polling, launch/update actions |
ViewModels/CustomInstallViewModel.cs |
681 | Wizard orchestration |
ViewModels/InspectorViewModel.cs |
545 | XRay agent + REPL |
0 coordinator classes extracted. No *Coordinator.cs files exist.
Fix: Extract FileExplorerTransferCoordinator, BrowseInstallCoordinator, ThumbnailService and inject them.
β οΈ CUIDADO:
FileExplorerViewModel/SftpService/SftpTransferServicehandle the Xbox SSH/SFTP layer, which runs cmd.exe (not bash) β command probing and error handling are deliberately conservative. Refactor these incrementally with tests and explicit approval; do not blanket-split without preserving the probe/fallback semantics documented above (see item #8).
3. Convert async void handlers β β
DONE (2026-08-27)
All async void event handlers eliminated β 20 β 0. Converted every handler to a async Task local Handler() wrapped in FireAndForget("context") (logs unobserved exceptions instead of crashing), or to async Task for VM/App methods.
Converted:
FileExplorerView.axaml.cs(6),MobileFileExplorerView.axaml.cs(5),ErrorDialog.axaml.cs(2),MobileLogsView.axaml.cs(2),BrowseView.axaml.cs(1),InstalledView.axaml.cs(1),InspectorView.axaml.cs(1),LogsView.axaml.cs(1),Controls/DialogFadeBehavior.cs(1)- Non-handlers:
BrowseViewModel.OnConnectionChangedβWork().FireAndForget(...);App.ShowMobileCustomInstallβasync Task, lambdas call.FireAndForget("App.ShowMobileCustomInstall").
Fix: Wrap body in SafeFireAndForget helper (already exists in TaskExtensions.cs). Convert to async Task where possible. β DONE
4. Secrets: replace XOR obfuscation β β DONE (2026-08-27)
File: XBVault/Services/CryptoService.cs
Replaced XOR+salt with SEC2: AES-256-GCM, key derived via PBKDF2 (SHA-256, 100k iterations) from MachineName|UserName identity + per-install random salt. Pure managed β cross-platform, no P/Invoke, no OS keychain, no master-password UX.
Format: SEC2: + base64(salt(16) β nonce(12) β tag(16) β ciphertext). Prefix-versioned so a future format migrates cleanly.
- Legacy XOR values still decrypt on read (grandfathered) and re-encrypt to SEC2 on the next save β installed configs keep working.
- A config file copied to another machine/user is undecryptable;
TryDeobfuscatedistinguishes βno stored secretβ from βstored but undecryptableβ instead of the old silent"". - On undecryptable credentials the app prompts the user to re-run the Setup Wizard: desktop
ConfirmWindowat startup + inline Settings warning with a Reconfigure button; mobileMobileConfirmDialogViewoverlay + Settings reconfigure delegate. - Cross-OS config sharing is intentionally unsupported (user decision).
Tests: 13 β 21 in CryptoServiceTests (round-trip, prefix format, token uniqueness, tamper β fail, legacy migration, cross-machine failure, key derivation stability).
π‘ Medium
5. Cancellation/disposal audit β β DONE (2026-08-27)
CustomInstallViewModel now implements IDisposable (disposes _analyzeCts); all 4 hosts call vm.Dispose() on window close / overlay close. (MobileLogsView._shareCts IS disposed in the finally block β verified not a gap.)
Fix: Implement IDisposable on CustomInstallViewModel. β implemented
6. Bare catch { } blocks β β
DONE (2026-08-27, 0 remaining)
0 bare catch { } remain (was 26). Every catch now carries an explicit // why comment or logs. Classification:
| File | Count | Handling |
|---|---|---|
Services/Logger.cs |
10 | // logger must never throw (recursive logging loop) β silent by design |
App.axaml.cs |
1 | // best-effort cleanup (temp file delete) |
Views/MobileFileExplorerView.axaml.cs |
4 | // best-effort cleanup |
Services/LogShareService.cs |
3 | cleanup + 2 parses now Logger.Warn on failure |
Services/SftpService.cs |
2 | // best-effort teardown |
Services/PlatformDialog.cs |
2 | // fallback β platform dialog unavailable |
Views/MobileErrorDialogView.axaml.cs |
1 | // fallback β icon asset missing |
Views/MobileQrDialogView.axaml.cs |
1 | now Logger.Warn on clipboard write failure |
Views/QrDialogWindow.axaml.cs |
1 | now Logger.Warn on clipboard write failure |
Services/PreFlightChecker.cs |
1 | // best-effort cleanup |
Intentional silences kept (logging failures must never crash the app; best-effort cleanup and teardown stays quiet). Parsing and clipboard writes β the two that used to fail silently with user-visible impact β now log Warn.
7. .Result blocking calls β 3 instances (all π
³ deferred β do not touch)
β NΓO MEXER sem sign-off explΓcito. O usuΓ‘rio determinou que tanto o SFTP quanto o XrayAgentService sΓ£o delicados (sync calls / cmd.exe do Xbox). Ambos funcionam perfeitamente e nΓ£o devem ser retestados. Deixar esses
.Resultcomo estΓ£o.
| File:Line | Context | Status |
|---|---|---|
SftpService.cs:550 |
cmd.Result ?? string.Empty β SFTP command output |
π ³ deferida (SFTP/FileExplorer cauteloso) |
SftpService.cs:595 |
cmd.Result ?? string.Empty β SFTP command output |
π ³ deferida (SFTP/FileExplorer cauteloso) |
XrayAgentService.cs:263 |
return readTask.Result β after Task.WhenAny (safe but code smell) |
π ³ deferida (Xray sync-calls delicado) |
β οΈ CUIDADO β SFTP/FileExplorer/Xray (all deferred): The Xbox SSH/SFTP layer is delicate. It provides a cmd.exe instead of bash, so probing and command handling are intentionally kept conservative. The
XrayAgentServiceis likewise sensitive about sync calls. Do not refactorSftpService,FileExplorerViewModel, orXrayAgentServicewithout explicit sign-off β several code paths there are deliberate (best-effort disconnect cleanup, hardcoded drive fallback,.Resultafter guaranteed-completed tasks, Xray sync-call patterns). Address these only as part of a carefully-tested refactor later, never as a standalone quick fix.
8. Service/ViewModel documentation uneven
26/37 services missing class-level XML <summary> docs (~8% coverage). Interfaces generally have docs; implementations do not.
Missing: CacheService, CryptoService, GitHubReleaseCheckerService, NotificationCenterService, PackageOverrideService, SettingsService, SftpService, VersionCheckerService, XboxAuthService, XboxPackageService, and 16 more.
Fix: Add XML docs to all service classes.
9. BrowseViewModel β 915 lines
File: XBVault/ViewModels/BrowseViewModel.cs Β· 915 lines (+18% from 776)
Contains catalog loading, filtering, search, item selection, install orchestration, progress reporting, and image thumbnail management. Still past the god-class threshold.
Fix: Extract install orchestration into BrowseInstallCoordinator. See #2.
π’ Low
10. CI checks & analyzers β β DONE (2026-08-27)
format job added to .github/workflows/build.yml (ubuntu-latest): runs two dotnet format whitespace --verify-no-changes checks (shared+desktop, tests). EnforceCodeStyleInBuild + AnalysisLevel live in Directory.Build.props (already active). Repo swept with the same rule set (whitespace only, 46 files).
Last verified against code: 2026-08-27 (main worktree). Line counts and locations below reflect current source. 718 tests green, desktop + Android build 0 warnings / 0 errors,
dotnet format whitespace --verify-no-changesclean (2/2). Source version: 2.0.5.
11. UI clipping workaround β β resolved (2026-08-27)
Avalonia 12 Border CornerRadius does not clip inner Image. Not currently blocking β images render acceptably.
Fix: RectangleGeometry clip or ImageBrush if needed.
12. Hardcoded URLs β β DONE (2026-08-27)
API endpoints, Discord links, Gofile URLs β all centralized in XBVault/Configuration/AppUrls.cs (root namespace XBVault, no usings needed). Templated hosts use string.Format (InvariantCulture) with cached CompositeFormat.
Fix: Centralize API URLs in constants class. β implemented
β Resolved
| # | Item | Resolved | Notes |
|---|---|---|---|
| β | XboxDeviceService god class | Aug 2026 | Split into 6 domain services |
| β | FileExplorerViewModel split | Aug 2026 | Extracted ISftpService, SftpTransferService, FileSystemPathParser |
| β | _Backup/ directory in git |
v0.8.x | Removed, added to .gitignore |
| β | Title bar gradient duplicated | v0.9.1 | Extracted as TitleGradient |
| β | Close button template duplicated | v0.9.1 | Unified WindowCloseButton |
| β | Hardcoded magic delays | v0.9.1 + Aug 2026 | Named constants |
| β | CatalogApiService not injected |
v0.9.2 | Constructor injection |
| β | PerformanceViewModel CTS not disposed |
v0.9.2 | Now implements IDisposable |
| β | DllImport + System.Management Linux risk |
v0.9.2 | WINDOWS_BUILD conditional |
| β | PerformanceSnapshot catch no log |
v0.9.2 | Now logs |
| β | Orphaned _Backup icons |
v0.9.1 | Deleted |
| β | Culture-dependent formatting | Aug 2026 | All 8 formatters use InvariantCulture |
| β | UI clipping workaround | 2026-08-27 | Not needed β images render acceptably |
| β | Test coverage (240β718) | 2026-08-27 | +199% growth; 718 tests green |
| β | File Explorer drive list | 2026-08-27 | SSH probe added (fallback still hardcoded) |
| β | Logging partially adopted | 2026-08-27 | IAppLogger exists, 5 services use it |
| β | Secrets XOR | 2026-08-27 | SEC2 AES-256-GCM + PBKDF2 machine-bound |
| β | Hardcoded URLs (33) | 2026-08-27 | Centralized in AppUrls.cs |
| β | Xbox test coverage | 2026-08-27 | Full Xbox domain coverage: auth, package (dep-install), portal, zip, ProgressReadStream, System/Network/Process/Performance (39 new) β 718 total |
| β | CI format gate | 2026-08-27 | format job runs dotnet format whitespace --verify-no-changes (2 projects); whole-repo whitespace sweep applied |
| β | App.axaml.cs composition root |
2026-08-28 | AppServices + DesktopUiActions/MobileUiActions; 1,978 β 376 lines |
| β | System Info redesign (desktop + mobile) | 2026-08-28 | WDP /ext/settings + /api/os/machinename contract; hero/stat/pills; mobile overlay screen |
| β | Mobile v2.0.5 QA batch | 2026-08-28 | Tab-switch hardening, install-abort token chain, overlay stacking, dep-card fix, keyboard BringIntoView, log auto-scroll, dialog icon upscale |
| β | Dep-settle D02 hang fix | 2026-08-29 | Dep-wait requires explicit terminal state (idle β ready); non-target D02 settles early; +3 tests β 733 |
Summary
graph LR
H["π΄ High<br/>1 open (2)"]
M["π‘ Medium<br/>2 open + 1 deferred (7, 8, 9)"]
L["π’ Low<br/>0 open"]
style H fill:#CC3333,stroke:#9ACA3C,color:#fff
style M fill:#FF9900,stroke:#9ACA3C,color:#000
style L fill:#9ACA3C,stroke:#447F3E,color:#000
| Severity | Open | Resolved | Estimated effort |
|---|---|---|---|
| π΄ High | 1 | β | 16β40 hours |
| π‘ Medium | 3 (incl. 1 deferred) | β | 13β34 hours |
| π’ Low | 0 | β | β |
| Total | 4 open | 21 resolved | 29β74 hours |
Notable changes since Aug 2026 verification
- App.axaml.cs 847 β 1,978 β 376 lines: the composition-root refactor (2026-08-28) shipped
AppServices+DesktopUiActions/MobileUiActionsβ it is no longer the largest file. - async void 10 β 20 β 0 handlers: mobile views added 10 new handlers; full conversion to
async Task/SafeFireAndForget(2026-08-27). - Test coverage 240 β 733 tests: matcher exhaustive tests, service tests, ViewModel tests, Xbox package/auth/portal suites, CryptoService SEC2 suite, full Xbox domain coverage (System/Network/Process/Performance via stub + real WebSocket loopback), +3 dep-settle tests (
XboxPackageInstallFlowTests). - XboxDeviceService deleted: fully split into 6 domain services behind interfaces.
- FileExplorerViewModel 1,880 β 1,809 lines: split done but post-split growth; still the largest ViewModel.
- Bare
catch { }15 β 26 β 0: all now commented/logged (2026-08-27). - ConfigureAwait(false) backlog item removed (user decision β client app, not a library; sweep was noise).
- CI format gate added (2026-08-27):
formatjob βdotnet format whitespace --verify-no-changes. - New since last verification:
AppServices,DesktopUiActions,MobileUiActions,GitHubReleaseCheckerService,UpdateVersionCache,PackageOverrideService,PreFlightChecker,WindowSettingsService,MobileErrorDialogView,MobileLogsView,MobileSystemInfoView,MobileFileExplorerView,XBVault/Configuration/AppUrls.cs. - Resolved since last verification: secrets XOR β SEC2, hardcoded URLs β
AppUrls.cs, UI clipping, test coverage (653β733), Xbox domain tests all covered, CI format gate, App.axaml.cs composition root, System Info redesign, mobile v2.0.5 QA batch, dep-settle D02 hang.