Finding
The can_transition_to match in DownloadState allows Seeding → SeedPolicySatisfied but has no Seeding → Failed arm. If a torrent in the Seeding state encounters a runtime error (the librqbit session is lost, the peer disconnects permanently, or disk becomes unavailable), the caller cannot legally transition the entry to Failed. Any call to entry.transition_to(DownloadState::Failed) from Seeding returns Err(InvalidStateTransition). The entry is then permanently stuck in Seeding with no path to Deleted or any terminal state.
Evidence
crates/ergasia/src/state.rs:30-38 — the allowed transitions:
(Queued, Initializing) | (Initializing, Downloading) | (Initializing, Failed)
| (Downloading, Completed) | (Downloading, Failed) | (Completed, Seeding)
| (Seeding, SeedPolicySatisfied) | (SeedPolicySatisfied, Deleted) | (Queued, Failed)
There is no (Seeding, Failed) arm. The invalid-transition test at line 132 explicitly asserts Seeding → Downloading fails, but there is no corresponding Seeding → Failed in the valid set.
Why this matters
A download stuck in Seeding with no legal exit transition can never be cleaned up or retried. Any retry or housekeeping logic that calls transition_to(Failed) receives an error and cannot proceed, leaking the entry forever. On a counter-surveillance device, abandoned seeding entries that cannot be terminated keep the node advertising itself to the swarm and consuming bandwidth past the operator's intent, widening the network-observable footprint. A similar gap exists for Completed → Deleted (the path must always pass through Seeding), preventing manual deletion of a completed download that should skip the seeding phase.
Desired correction
Add (Seeding, Failed) to the transition set. Consider also (Completed, Deleted) to allow forced deletion. Update the valid-transitions test to cover these cases and the invalid-transitions test to document what remains forbidden. Done when: entry.transition_to(DownloadState::Failed) from Seeding returns Ok(()) and the unit test passes.
Finding
The
can_transition_tomatch inDownloadStateallowsSeeding → SeedPolicySatisfiedbut has noSeeding → Failedarm. If a torrent in theSeedingstate encounters a runtime error (the librqbit session is lost, the peer disconnects permanently, or disk becomes unavailable), the caller cannot legally transition the entry toFailed. Any call toentry.transition_to(DownloadState::Failed)fromSeedingreturnsErr(InvalidStateTransition). The entry is then permanently stuck inSeedingwith no path toDeletedor any terminal state.Evidence
crates/ergasia/src/state.rs:30-38— the allowed transitions:There is no
(Seeding, Failed)arm. The invalid-transition test at line 132 explicitly assertsSeeding → Downloadingfails, but there is no correspondingSeeding → Failedin the valid set.Why this matters
A download stuck in
Seedingwith no legal exit transition can never be cleaned up or retried. Any retry or housekeeping logic that callstransition_to(Failed)receives an error and cannot proceed, leaking the entry forever. On a counter-surveillance device, abandoned seeding entries that cannot be terminated keep the node advertising itself to the swarm and consuming bandwidth past the operator's intent, widening the network-observable footprint. A similar gap exists forCompleted → Deleted(the path must always pass throughSeeding), preventing manual deletion of a completed download that should skip the seeding phase.Desired correction
Add
(Seeding, Failed)to the transition set. Consider also(Completed, Deleted)to allow forced deletion. Update the valid-transitions test to cover these cases and the invalid-transitions test to document what remains forbidden. Done when:entry.transition_to(DownloadState::Failed)fromSeedingreturnsOk(())and the unit test passes.