···188188Teardown is same whether the workflow succeeded, failed or timed out: drain the
189189guest's pending Nix cache uploads, ask the agent to power off and wait for QEMU
190190to exit (falling back to QMP `system_powerdown` and finally a kill if it
191191-doesn't), then close the proxies and remove the work directory.
191191+doesn't), then close the proxies and remove the work directory. For non-HTTP
192192+upload targets the host-side import already happened synchronously when the
193193+guest committed each narinfo, so there is no second host-side cache drain step
194194+at teardown.
192195193196### Nix cache
194197···204207The upload proxy goes the other way: paths built inside the guest are pushed to
205208spindle's configured upload cache (if any) so the next workflow that needs them
206209doesn't rebuild. Paths already present on any configured read cache are skipped.
207207-The agent queues built paths and they're uploaded eagerly as they appear; any
208208-still in flight at teardown block the drain step until they finish.
210210+211211+For `http://` and `https://` upload targets the proxy just reverse-proxies the
212212+guest's binary-cache upload traffic to the configured remote cache, while still
213213+answering narinfo existence checks across the upload target plus the read
214214+caches.
215215+216216+For `ssh://`, `ssh-ng://`, `daemon`, and `local` targets spindle implements the
217217+small HTTP binary-cache upload surface itself. It stages uploaded `nar/` objects
218218+and narinfos under the workflow workdir, validates the narinfo, then treats the
219219+narinfo upload as the commit point: once `<hash>.narinfo` is written spindle
220220+runs:
221221+222222+```bash
223223+nix copy \
224224+ --from file://<staging-dir> \
225225+ --to <target-store> \
226226+ --no-check-sigs \
227227+ --substitute-on-destination \
228228+ <store-path>
229229+```
230230+231231+That copy is synchronous. If it fails, spindle removes the staged narinfo again
232232+so future `GET`/`HEAD <hash>.narinfo` requests do not falsely dedupe a path that
233233+never made it to the destination store. The guest still only ever sees the same
234234+HTTP binary-cache upload protocol over vsock; it never gets direct access to
235235+SSH credentials or the destination store itself.