Twinned from https://github.com/cfsh/ninefold/issues/707 by tools/beads/import_github.py's reconcile pass.
The VM was resized and rebooted at 05:15 UTC. Every session lost its scratchpad, so tracked-prs.txt was gone and the poll loop was tracking nothing. Sessions restored it by hand from gh pr list. @aedanpope: *"tracked-prs.txt doesn't sound expensive, maybe stuff like this can go under ~/nf/tmp."*
⚠️ /tmp is NOT tmpfs on this box — findmnt shows no separate mount; it is on /dev/vda1 with the root filesystem. #575 (closed) was titled *"tracked-prs.txt lives on tmpfs"*, which is wrong here, so the closure rests on a premise that does not hold.
The real cause: tmpfiles.d carries D /tmp 1777 root root 30d, and D means *empty this directory at boot*. Verified — every scratchpad dir on the box now has a creation time after the 05:15 boot (05:17–05:37); nothing predates it.
So no amount of disk or RAM helps, and it will recur on every reboot.
Per session, under /tmp/claude-0/<slug>/<sid>/scratchpad/:
| file | what it costs to lose |
|---|---|
| tracked-prs.txt | the poll stops watching live PRs — and #618 says a missing file reads as an empty one, so it fails silently and can fire WRAP_UP with an open PR |
| poll-cron.txt | the poll routine's job id — the cron keeps firing with nothing able to identify or delete it |
| poll-state.txt | the idle-tick counter |
Move durable session state to ~/nf/tmp/<session-name>/:
~/nf is on the root filesystem and is not touched by tmpfiles.d.~/nf holds no repo at its root and no CLAUDE.md, so a new sibling there breaks none of the topology reasoning that keeps devs/ a sibling of office/.devs/ — nothing there should be irreplaceable.⚠️ Key it on the session NAME, not the sid. The scratchpad path embeds the session id; keying the new location the same way would reintroduce the loss the first time a sid changes. nf-dev-<topic> is stable across resumes.
⚠️ This does not close #618, and #618 is the half that fails safe. A durable path makes loss rarer; #618 makes loss *loud*. A missing tracked-prs.txt must still refuse to read as an empty one — otherwise the next thing that clears the directory produces a silent WRAP_UP with open PRs, which is #684's shape and #389's before it. Do both.
Writers today: tools/nflib/sessions.py, tools/pr/poll.py, tools/office/audit_sessions.py.
None.
No comments.