[3.6.0] - 2026-04-22
AeroSync UX Upgrade + Critical SSH Host-Key Fix
Release focused on making the AeroSync optimized-transfer path visible to the user and on a critical SSH host-key dialog fix. The optimization logic has been progressively landed over the last weeks; this release is the moment it becomes visible in the product.
Added
- Delta Savings widget in AeroSync: when a file travels through the optimized transfer path during sync, an inline badge next to the file's status marks it; at the end of the run an "Optimized transfer" summary card aggregates N files · bytes saved · speedup. When the effective speedup falls below 1.5x the card switches to a neutral "Optimized transfer" variant to avoid misleading framing. The widget is fully theme-aware across light/dark/tokyo/cyber and hidden entirely when no file benefited from the path. Translated in all 47 supported languages.
- Per-file breakdown in
aeroftp_sync_treeMCP tool: the response now carriessummary.delta_files[](array of{path, bytes_sent, total_size, speedup}) capped at 500 entries, plus asummary.delta_files_truncatedflag when a run crosses the cap. Aggregate counters insummary.delta_savingskeep counting past the cap. Both keys are omitted on runs where no file used the optimized path, preserving the absence-vs-null contract with the existingdelta_savingsblock.
Fixed
- Critical:
Host Key Changeddialog no longer reappears after Accept: the russh library reports the changed-key line number as 1-based; the internalsftp_remove_host_keycommand was treating it as a 0-based array index, which meant Accept surgically removed the line after the stale entry instead of the stale one itself. Repeated Accept clicks piled valid entries on top of the original stale one, and every subsequent connection hit the stale line first and re-triggered the dialog. The fix uses 1-based indexing correctly and now also prunes any other plaintext entry for the same(host, port, algorithm)tuple that matches the incoming key's algorithm — so files already corrupted by earlier broken attempts get cleaned up in the same pass. 11 new unit tests pin the regression cases (line zero rejected, 1-based indexing, duplicate pruning, host-mismatch corruption guard, hashed-entry tolerance).
Changed
- Optimized transfer path reachable from SyncPanel on SFTP: earlier releases had the decision wired in the unified sync core only — AeroSync UI actually iterates per-file commands that never entered that branch. This release extends the decision to
upload_file/download_file/provider_upload_file/provider_download_fileso sessions with SFTP + SSH key authentication + a capable remote now actually exercise the optimization in the day-to-day UI flow. The decision remains self-gated (silent fallback to classic when the session is not eligible); hard rejections (SSH host-key mismatch, permission denied) surface as transfer errors without silent retry. TransferEventnow propagates optionaldelta_stats: the event emitted to the frontend oncompletecarries per-file stats from the optimized path when applicable (serialized withskip_serializing_if, absent for classic transfers — no wire overhead for non-SFTP providers). Frontend accumulates these into the session-level summary client-side.
MCP (pre-release carryovers from v3.6.0 cycle)
aeroftp_read_filesoft-truncate dentro hard cap: oversized file (oltrepreview_kbma entro il cap 1 MB) ritornano contenuto troncato contruncated:trueinvece di errore duro. Il validator rifiuta solo oltre il hard cap 1 MB. Elimina i retry forzati che gli agent facevano quando incontravano file appena oltre la finestra di preview richiesta.aeroftp_check_treeesponecompare_methodanche sul gruppomatch: il JSON di ritorno ora includegroups.matchdettagliato alla pari didiffer/missing_local/missing_remote. Ogni entry portacompare_method: "checksum" | "size"così l'agent sa se il match è stato crittograficamente verificato o è fallback dimensionale (tipicamente su FTP che non ha checksum server-side).
Build / CI
- Dedicated
fallback-fixtureCI lane:delta-sync-integration.ymlgains a second job running against the password-only SFTP Docker fixture. Covers the silent-fallback branch (password-only sessions) and the hard-rejection contract so a regression on those paths cannot ship unnoticed. Protected bynick-fields/retry@v3(2 attempts, 10s wait) for Docker-on-runner flakiness. Both jobs block PRs on failure.
Internals
SyncReportdomain types expanded:DeltaSavingsSummary(aggregate) and newDeltaFileEntry(per-file breakdown) are public types;DELTA_FILES_CAP = 500exposed as a crate-level constant. The accumulator is one branch driving both aggregate and per-file tracking — impossible to drift.- Stderr sanitizer hardened:
/home/<user>,/Users/<user>,C:\Users\<user>and.ssh/*path segments redacted beforefallback_reason/hard_errormessages flow to UI, logs, or MCP responses. Message capped at 512 characters to keep response arrays bounded. RsyncStats.warningsdowngraded topub(crate): entries may contain remote file paths and must not leak without sanitization.
Downloads:
- Windows:
.msiinstaller,.exe, or.zipportable (no installation required) - macOS:
.dmgdisk image - Linux:
.deb,.rpm,.snap, or.AppImage