<feed xmlns='http://www.w3.org/2005/Atom'>
<title>duet/tests/test-integration-duet-transfer.el, branch main</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.
</subtitle>
<id>https://git.cjennings.net/duet/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/duet/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/duet/'/>
<updated>2026-06-06T20:36:25+00:00</updated>
<entry>
<title>feat: add the local transfer execution engine and queue</title>
<updated>2026-06-06T20:36:25+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-06T20:36:25+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/duet/commit/?id=3b244ba0492fd86fca051713196067f833f34a1b'/>
<id>urn:sha1:3b244ba0492fd86fca051713196067f833f34a1b</id>
<content type='text'>
Phase 5 turns the pure transfer-specs from Phase 3 into running transfers. duet--run-transfer spawns the backend over make-process, and a serial queue (duet-max-concurrent-transfers, default 1) holds the rest until a slot frees. Each transfer carries a state machine: queued, running, stalled, cancelling, then a terminal done, failed, or cleanup-unverified.

The process filter is the hot path, so it stays cheap: it counts output, bounds it to a trailing window, and schedules one coalesced log render. It never refreshes panes. Pane refresh runs once per batch from the sentinel, also coalesced. A move deletes its sources only after the copy exits 0, so a failed move leaves the source untouched. Cancellation kills the process and, for a backend declaring verifiable cleanup, checks the destination for stray temp files before settling on failed versus cleanup-unverified.

The process boundary and the temp-file lister are injectable, so the queue and classification logic test against fake results while real rsync gets its own slow integration file. duet-copy, duet-move, duet-mkdir, and duet-delete are wired to the engine. The viewer actions stay stubs until their phase. In-process TRAMP and both-remote rsync still refuse to run here. They land with Phase 6.

172 tests, duet.el at 100% line coverage, compile/lint/complexity green.
</content>
</entry>
</feed>
