On WSL2, a caller that cannot run ps reads a running agmsgd as stopped

Open Beginner friendly
#1,960 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
78/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
bash
Domain
cli

Research direction

Start with agmsg_daemon_read_state in scripts/lib/daemon-state.sh, then read the two failing cases in tests/test_agmsgd_switch.bats. Trace how an empty ps result sets health and how _agmsg_pid_signal_presence distinguishes a gone pid. Done when a live or unverifiable pid yields unchecked, a clearly gone pid stays stopped, and both named tests pass.

Written by the indexing model from the issue text.

Description

What happens

On WSL2, agmsg_daemon_read_state (scripts/lib/daemon-state.sh) reads a running agmsgd as stopped when the caller cannot run ps. On other Linux hosts the same caller gets unchecked. Two existing tests in tests/test_agmsgd_switch.bats fail on WSL2 for this reason, on main (5a42555b) as well:

  • "executor evidence recognizes a live ready owner and rejects a changed boot" (the [ "$output" = unchecked ] after ps and getconf are replaced by exit 1)
  • "warn_if_stopped never records a down_notice for 'unchecked' (cannot tell is not down)"

With /proc/sys/kernel/osrelease replaced by a non-WSL string (6.18.40.1-generic) in a copy of the scripts, both pass on the same machine.

  • agmsg: main at 5a42555b
  • OS: Ubuntu on WSL2, kernel 6.18.40.1-microsoft-standard-WSL2
  • bats 1.13.0 (npm), Node v24.21.0

Why

On WSL the kernel release contains microsoft, so the Linux branch sets start_unreliable=1: WSL2's host time sync steps the clock, so the process start time cannot show that a pid was reused. The check that turns missing evidence into "cannot tell" is skipped for that case:

if [ -z "$current_boot" ] || { [ -z "$started_epoch" ] && [ -z "$start_unreliable" ]; }; then
  case "$(_agmsg_pid_signal_presence "$pid")" in
    gone) ;;
    *) AGMSGD_HEALTH=unchecked ... return 0 ;;
  esac
fi

The function therefore goes on to the last check, ps -p "$pid" -o stat=. When ps cannot be run (denied in a sandbox, or missing), the empty output is taken as executor exited or suspended, and AGMSGD_HEALTH stays stopped. agmsg_daemon_warn_if_stopped then reports it and, in the ordinary path, self-heals by running daemon start. That bumps op_gen and makes the running daemon step aside. #1959 describes the same sequence for a pid namespace sandbox.

Suggested fix

Treat an empty ps answer as "cannot tell" unless the pid is clearly gone. For example, when process_state is empty, ask _agmsg_pid_signal_presence: gone keeps stopped, anything else is unchecked. A Z or T state still means exited or suspended. This keeps the comment's rule ("unless the pid is clearly gone, say the check is unavailable, not stopped") on the WSL path too.

The fix proposed for #1959 does not change this path: it handles a caller in another pid namespace, where even kill -0 says "No such process". It also does not fix these two tests.


This issue was written with AI assistance (Claude Code, Claude Opus 5.5). I reviewed it, and the observations above come from my own machine.

Dominant language
Shell
Stars
1.5k
Forks
156
Avg merge
15h 56m
Merged PRs (30d)
231

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from fujibee/agmsg

All issues in fujibee/agmsg

Similar issues

More Shell/Bash issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.