Repository navigation
Description
Bug
pkgs/id/src/directory_mail.rs — CommandSink::send runs the configured mail program and waits for it with no timeout:
directory_mail.rs:107—let status = child.wait().context("wait for mail program")?;— a barewait()with no deadline, and the child is never killed on any path.- The sibling sink in the same file is bounded:
SmtpSinksetsRELAY_TIMEOUT = Duration::from_secs(10)(directory_mail.rs:115) on connect/read/write.OutboxSinkis a single file write. OnlyCommandSinkcan block forever.
The wait is on a live request path. WorldService::directory() (pkgs/id/src/world_session/mod.rs:108) awaits the send for every mail-carrying directory action (addemail, signin):
tokio::task::spawn_blocking(move || sink.send(&mail)).awaitSo a mail program that hangs (waiting on a lock, a network mount, a full pipe, a prompt) hangs that directory request — the SSH explorer / web request that asked for a confirmation or sign-in code — forever. Each retry spawns another blocked spawn_blocking thread and another hung child process; nothing is ever reaped or reported.
Evidence (verified this run)
Laptop probe (worktree of origin/main e561ab5 at ~/git/fleet/wt-laneB-mdprobe, directory_mail.rs sha256 dc6f7935…, identical to sandbox main e91098f), pkgs/id/tests/mail_probe.rs: CommandSink pointed at /bin/sh -c 'sleep 30' —
send STILL BLOCKED after 3.000162752s (program sleeps 30s; no timeout in CommandSink)
i.e. send() returns only when the program exits, however long that takes; a program that never exits blocks it indefinitely.
Why it matters
The command sink is one of the three documented mail transports an admin can configure for a world (id serve, commands/serve.rs:468). A single wedged helper program silently wedges every email-code flow for that world — no error, no log line, no recovery short of restarting the server — while the SMTP transport next door fails cleanly in 10 s.
Acceptance criteria
-
CommandSink::sendbounds the wait: after a deadline (a named constant; reusing the file's existing 10 s scale or a justified program-specific value is the triage pin), it kills the child, reaps it, and returns an error that says the program timed out. - A test with a program that sleeps past the deadline returns the timeout error in bounded time (test uses a short injected deadline, not a real multi-second sleep).
- A slow-but-finite program inside the deadline still succeeds; a program exiting non-zero still errors as before (
a_failing_command_is_an_errorkeeps passing). - Existing
directory_mailtests pass (laptop or CI).
Found by new-issue-creator-code-b. Dedup: gh issue list --search 'directory_mail OR CommandSink OR "mail program"' and 'mail timeout hang' (open + closed) returned nothing on 2026-10-28.
Activity
developing-today commentedon Oct 28, 2026
CODE-728
dezren39 commentedon Oct 28, 2026
🤖 Agent note · filed
18 remaining items
dezren39 commentedon Nov 1, 2026
🤖 Agent note · parked (PR awaiting safe verification)
queue/5039-1788-command-timeout(commit1e47e202c; worktree/home/user/git/fleet/5039). Productioncargo check --libpasses.pkgs/id/src/idset.rs:755has aChainExtinitializer missingnote(E0063). PR checks have no normal test result; CodeRabbit skipped, two daily workflows failed without jobs/logs, and Codex review was still running. No merge performed.directory_mailtests and inspect PR checks; merge only when green and verified.dezren39 commentedon Nov 1, 2026
🤖 Agent note · picked up
fix(id): kill the mail command tree on timeout; observed exit always …
test(id): zombie-aware descendant probe for the mail timeout test (#1788
Merge pull request #4031 from developing-today/queue/5039-1788-comman…
dezren39 commentedon Nov 1, 2026
🤖 Agent note · done
dezren39 commentedon Nov 1, 2026
agent-note:v1
event: done
task: 5039 (repo-health-code-pilot, OpenChamber scheduled lane)
state: Fresh GitHub confirms #1788 CLOSED and PR #4031 MERGED. Queue task completed as already_done. Prior checkpoint reported targeted directory_mail tests 11 passed; this attempt did not rerun tests.