mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-02 14:02:22 +02:00
Task 11, step 2. Cancelling a running recording marked it `Cancelled` immediately, while the worker was still writing the file and holding the provider slot. `Cancelled` is terminal, so the recording became deletable at once -- and deleting a cancelled entry unlinks its `.partial`, which is the file the worker had open. The transfer went on streaming into an unlinked inode. `Cancelling` is now the state between asking and the worker letting go. It is deliberately not terminal, so deletion is refused until the teardown finishes. `transition` returns it only from the states where a worker actually owns the file -- Running, WaitingForCapacity, RetryWaiting. Cancelling a Queued, Scheduled or Paused recording has nothing to wait for and stays immediate, because a state nothing drives would be worse than no state at all. Restart resolves it: the worker that was going to acknowledge died with the process, so recovery commits `Cancelled`. Without that the entry is not `finished`, and the requeue path would have restarted work the user had cancelled. Writing the test for this surfaced a worse bug, present since the split made files shareable. Execution state lived on the materialization, which two entries share. `join` read `state`, `partition`, `finished`, `paused`, `error` and the retry fields from it, so whichever entry was committed last decided what every entry looked like on the next load -- one user running a transfer silently rewrote another user's queued entry as running, or the reverse. It is invisible until a restart. Execution state moves to `PersistedLibraryEntry`, where the plan's Task 7 always said it belonged and I had omitted it. The materialization keeps only what is genuinely one-per-file: path, size, url, kind, identity. Two entries on one file can now disagree about their own lifecycles, which is the entire point of them being separate entries. Consequence worth knowing: a repository written before this commit decodes with the new entry fields defaulted, so entries come back `Queued`. The plan rules out migrating old DVR state and none of this has shipped, so that is accepted rather than migrated.