After ./sorcar-cloud deployed the agent to a server, the History
panel there listed almost nothing — even though the laptop's database, with more than fourteen
thousand tasks, had been copied across. Two separate faults were responsible: one lost the data,
the other hid it.
A SQLite database in the mode KISS Sorcar uses is not one file but three. sorcar.db
holds the settled data; sorcar.db-wal — the write-ahead log — holds recent changes not
yet folded in; sorcar.db-shm is a scratch index that is meaningful only to the
processes on that particular machine.
The old deploy step copied all three with scp, one after another, while the laptop
was still writing to them. On a 2.9 GB database over a home connection that is many minutes,
so the three files that arrive need never have existed together at any single instant.
The sharper problem was on the receiving end. If an earlier deployment's web app was still
running, it had the old database open. scp does not create a new file — it truncates
the existing one and writes into it, keeping the same inode. The still-running process therefore
ended up holding a handle to bytes that had been swapped out underneath it, while its own cached
view still described the small, empty database it had made moments earlier. The next checkpoint —
and simply shutting the process down is enough to trigger one — wrote that stale view back.
a leftover web app has an empty database open 2,000 tasks in the upload
| |
v v
[ sorcar.db ] <-- scp truncates and overwrites, same inode -+
|
| the leftover process still has it open, and its
| write-ahead log still describes the empty version
v
it shuts down -> checkpoint -> file truncated to 8 KB, 1 task left
test_ship_task_db.py: a 2,000-task database reads
back as a single task and then physically shrinks.Shipping the database is now a separate, self-contained step,
scripts/ship-task-db.sh, which you can also run on its own to refresh a running
deployment's history:
| Step | Why |
|---|---|
VACUUM INTO a snapshot |
One self-contained file at one consistent instant — no -wal, no
-shm, nothing to arrive out of step. Takes about 13 seconds on 2.9 GB. |
| Stop the remote web app first | Nothing may hold the database open while it is replaced. It is started again on the way out, including when the transfer fails. |
Upload gzip-compressed |
The database compresses about four to one, so the upload takes roughly a quarter as long. |
| Land under a temporary name | The upload becomes the database only after it proves, on the remote, that it passes an integrity check and holds exactly the number of tasks that were sent. A cut-short transfer leaves the previous database untouched. |
The History panel has a Workspace chip, on by default, that narrows the list to tasks belonging to the project you have open. Every task records the directory it ran in, and the chip keeps a row only when that directory is the window's own.
On the laptop this works: 4,020 of 4,220 tasks recorded /Users/ksen/work/kiss, and
that is what the window has open. On the server, sorcar-cloud deploys the project to
/home/<user>/kiss and tells the web app so — while every imported task still
names a path on the laptop. Nothing matched. Nothing was shown.
Two changes, because there were two things wrong:
…/kiss_ai is correctly
not treated as part of …/kiss. Only the shipped copy is rewritten; the laptop's own
database is never touched. In the live run this moved 14,496 of 14,660 tasks.<project>/.kiss-worktrees/kiss_wt-…) from the very project they belong to.
Tasks running inside the workspace now count as being in it.ssh that executes the remote half
against a sandbox home; the panel tests run the real main.js in headless Chromium
against the real markup and stylesheet, driven by the same events the web app receives.uv run check --full — ruff, mypy, pyright, mdformat — passes, as do the
surrounding history and web-extension parity suites (48 tests).Re-run ./sorcar-cloud user@host, or just refresh the history in place:
scripts/ship-task-db.sh user@host ~/work/kiss /home/user/kiss
The last two arguments are the project directory here and there; without them the tasks still arrive, but the Workspace chip will hide the ones that came from another machine.