fix: keep seen-id watermarks out of /tmp, where a reboot wipes them - #102
Conversation
Every seen-file default lived in /tmp: poller, dm_poller, automation, comments, discord. macOS clears /tmp on boot, so each reboot silently reset every watermark and the next poll replayed room history as new. That happened for real on 2026-09-13. Restarting iak-mcp-daemon on a box whose /tmp had been cleared dumped 48 messages from seven rooms into one agent's notification file, the oldest from March. Noise is the mild failure. The real one is that the replay included live-sounding instructions -- "get them trading before they close today" (6 Mar) and a request to delete messages -- which an agent reading them as new would have acted on. - defaults move to $XDG_STATE_HOME/iak or ~/.local/state/iak - stateFile() adopts an existing /tmp watermark once, so upgrading does not itself cause the replay this prevents - both writers mkdir -p first; room-poller's own hardcoded default moved too - config test asserts the property (not in /tmp, right filename) rather than a literal path, since the state dir varies by home and XDG_STATE_HOME Verified: 276/276 tests pass; a default config resolves to the state dir and adopted 1053 real ids from the legacy file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d4fbfaf442
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (!existsSync(target)) { | ||
| const legacy = `/tmp/iak-${name === 'seen-ids.txt' ? 'seen-ids' : name.replace(/\.txt$/, '')}.txt`; | ||
| mkdirSync(STATE_DIR, { recursive: true }); | ||
| if (existsSync(legacy)) copyFileSync(legacy, target); |
There was a problem hiding this comment.
Migrate explicitly configured legacy paths
When an existing JSON config explicitly contains the former default, such as poller.seen_file: "/tmp/iak-seen-ids.txt", this copies the watermark to the new target but loadConfig subsequently spreads raw.poller over the defaults and continues using the /tmp path. Since the repository's examples encouraged explicit per-agent /tmp paths, affected upgrades still lose their watermark and replay old messages after reboot; translate configured legacy paths during config normalization rather than only changing the omitted-value default.
Useful? React with 👍 / 👎.
| } catch { | ||
| // A read-only or unwritable home is not a reason to fail config load; | ||
| // the poller will fall back to an empty watermark and simply be noisy once. | ||
| } | ||
| return target; |
There was a problem hiding this comment.
Fall back when the state directory is unwritable
When XDG_STATE_HOME or the account's home is read-only or unavailable, the caught mkdirSync failure is followed by returning the same unwritable target. The active team-relay poller then calls the shared saveSeenIds, whose mkdirSync/openSync is uncaught during initial seeding, so rooms watch exits instead of merely producing the one noisy restart described here; this regresses service/container accounts that could previously write to /tmp, so return a writable fallback or reject the configuration explicitly.
Useful? React with 👍 / 👎.
Every seen-file default lived in
/tmp:poller,dm_poller,automation,comments,discord. macOS clears/tmpon boot, so each reboot silently reset every watermark and the next poll replayed room history as new.This happened for real on 2026-09-13. Restarting
iak-mcp-daemonon a box whose/tmphad been cleared dumped 48 messages from seven rooms into one agent's notification file, the oldest from March.Noise is the mild failure. The real one is that the replay carried live-sounding instructions — "get them trading before they close today" (6 Mar) and a request to delete a set of messages — which an agent reading them as new would have acted on. A watermark is not a convenience; it is what stops an agent obeying a six-month-old order.
Changes
$XDG_STATE_HOME/iakor~/.local/state/iak.stateFile()adopts an existing/tmpwatermark once, so the upgrade itself does not cause the single replay this change exists to prevent.mkdir -pfirst;room-poller.mjscarried its own hardcoded/tmpdefault, moved too./tmp, correct filename) rather than a literal path, since the state dir varies by home andXDG_STATE_HOME.Verified
🤖 Generated with Claude Code