Skip to content

id(directory_mail): CommandSink has no timeout — a mail program that never exits hangs the directory request forever #1788

Closed

Description

@dezren39

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 bare wait() with no deadline, and the child is never killed on any path.
  • The sibling sink in the same file is bounded: SmtpSink sets RELAY_TIMEOUT = Duration::from_secs(10) (directory_mail.rs:115) on connect/read/write. OutboxSink is a single file write. Only CommandSink can 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)).await

So 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::send bounds 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_error keeps passing).
  • Existing directory_mail tests 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

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/triageQueue packet kind: verify, reproduce, and route this item
    source/creatorFiled by the new-issue-creator job
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Oct 28, 2026
  2. developing-today commented on Oct 28, 2026

    @developing-today
    Contributor
  3. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator-code-b (issue creator, Lane B)
    • Session / ID: cron job new-issue-creator-code-b, run 2026-10-28 14:20 CDT
    • Found via: filed this run
    • Task: Triage the CommandSink no-timeout hang: pin the deadline value, bound CommandSink::send (kill + reap on expiry), add the bounded-time regression test.
    • Expectation: effort/s — done looks like: send() errors with a timeout message in bounded time against a never-exiting program, slow-but-finite programs still succeed, existing directory_mail tests pass.
    • Links: evidence in the issue body; probe at ~/git/fleet/wt-laneB-mdprobe (laptop, pkgs/id/tests/mail_probe.rs, directory_mail.rs sha256 dc6f7935 on main e91098f)
  4. added
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    and removed on Nov 1, 2026
  5. 18 remaining items

  6. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked (PR awaiting safe verification)

    • Agent: repo-worker-code (OpenChamber scheduled lane)
    • Session / ID: queue task 5039; retry after 20 minutes
    • State: PR fix(id): bound directory mail command runtime (#1788) #4031 is open on queue/5039-1788-command-timeout (commit 1e47e202c; worktree /home/user/git/fleet/5039). Production cargo check --lib passes.
    • Blocker: targeted tests fail before execution on both PR branch and clean main: pkgs/id/src/idset.rs:755 has a ChainExt initializer missing note (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.
    • Resume condition: after the unrelated main test compile error is fixed or an isolated valid test path is available, rerun directory_mail tests and inspect PR checks; merge only when green and verified.
    • Links: PR fix(id): bound directory mail command runtime (#1788) #4031 · task 5039
  7. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  8. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 1, 2026
  9. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

  10. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions