What happened
On Windows, inside a restricted agent sandbox, a live Codex bridge was reported
as stale by:
scripts/delivery.sh status codex <project>
The bridge process was still running. The native PID in its pidfile and metadata
matched, but the sandbox denied the tasklist query used by
_agmsg_pid_alive. Because the probe suppresses tasklist stderr and only
checks whether the PID appears in its output, query failure is indistinguishable
from a successful query that found no process.
The resulting status line was equivalent to:
Codex bridge: demo-team/demo-agent stale pidfile (pid 4242 not running)
Names and PID above are placeholders. No host, project, team, or agent
identifier from the observed machine is included here.
Environment and preconditions
- agmsg v1.1.13 liveness path (reproduced on 2026-08-02).
- Host agent: Codex CLI — the status command ran inside its restricted sandbox.
- Windows with Git Bash / an
MSYSTEM environment.
- A live Codex bridge whose pidfile contains its native Node process PID.
- The status command runs in a sandbox that allows the pidfile and metadata to
be read but denies tasklist process enumeration.
This is different from the MSYS-PID provenance bug fixed around #567/#582/#584.
The bridge PID is correctly routed to the generic/native probe. The failure is
that the native probe has only two outcomes.
Reproduction outline
-
Start monitor delivery and wait until the Codex bridge is live.
-
Read the bridge PID from run/codex-bridge.<team>.<role>.pid and verify that
the corresponding process is still running from a context that can inspect
it.
-
From the restricted Git Bash context, run the same native query used by the
helper:
MSYS_NO_PATHCONV=1 tasklist /FI "PID eq <pid>"
The observed query failed with an access-denied error instead of returning a
process table.
-
In that same restricted context, run:
scripts/delivery.sh status codex <project>
-
Observe that the live bridge is printed as a stale pidfile.
Why this happens
The Windows branch of _agmsg_pid_alive is effectively:
MSYS_NO_PATHCONV=1 tasklist /FI "PID eq $pid" 2>/dev/null | grep -q "$pid"
Both of these cases return false from the pipeline:
tasklist ran successfully and the PID was absent.
tasklist could not enumerate processes at all.
scripts/drivers/types/codex/_delivery.sh then maps every false result to
stale pidfile (pid ... not running). The diagnostic therefore states a fact
that the probe did not establish.
Expected behavior
A failed process-table query should not be treated as positive evidence of
death.
At minimum, status should distinguish:
- alive: the requested PID was positively found;
- dead: a successful query positively established that it was absent;
- unknown: the query could not be performed or interpreted.
For the observed case, a message such as bridge liveness unverifiable would
be accurate. Destructive or ownership-changing callers should preserve records
and avoid kill/reclaim actions when the result is unknown.
Possible direction
This issue is primarily an observation report, not a proposal for the broader
Windows PID-generation design. A follow-up could add a tri-state result at the
existing liveness seam, or provide a separate detailed probe while retaining a
boolean compatibility wrapper.
Whichever shape is chosen, regression coverage should distinguish all three
native-query outcomes:
- successful output containing the PID;
- successful output not containing the PID;
- nonzero/access-denied
tasklist execution.
The third case must not produce a definitive not running status or authorize
destructive cleanup. PID reuse, process start markers, and wider ownership
generation work are intentionally out of scope for this issue.
Impact
The immediate observed impact is a false status report, which can lead an
operator to restart or tear down a healthy route. The same binary helper is also
used by lifecycle code, so preserving the distinction between dead and
unverifiable is important before a failed probe is used as authority for
cleanup.
🤖 Issue text drafted with Claude Code; the
observation and reproduction are from a real deployment.
What happened
On Windows, inside a restricted agent sandbox, a live Codex bridge was reported
as stale by:
The bridge process was still running. The native PID in its pidfile and metadata
matched, but the sandbox denied the
tasklistquery used by_agmsg_pid_alive. Because the probe suppressestaskliststderr and onlychecks whether the PID appears in its output, query failure is indistinguishable
from a successful query that found no process.
The resulting status line was equivalent to:
Names and PID above are placeholders. No host, project, team, or agent
identifier from the observed machine is included here.
Environment and preconditions
MSYSTEMenvironment.be read but denies
tasklistprocess enumeration.This is different from the MSYS-PID provenance bug fixed around #567/#582/#584.
The bridge PID is correctly routed to the generic/native probe. The failure is
that the native probe has only two outcomes.
Reproduction outline
Start monitor delivery and wait until the Codex bridge is live.
Read the bridge PID from
run/codex-bridge.<team>.<role>.pidand verify thatthe corresponding process is still running from a context that can inspect
it.
From the restricted Git Bash context, run the same native query used by the
helper:
MSYS_NO_PATHCONV=1 tasklist /FI "PID eq <pid>"The observed query failed with an access-denied error instead of returning a
process table.
In that same restricted context, run:
Observe that the live bridge is printed as a stale pidfile.
Why this happens
The Windows branch of
_agmsg_pid_aliveis effectively:Both of these cases return false from the pipeline:
tasklistran successfully and the PID was absent.tasklistcould not enumerate processes at all.scripts/drivers/types/codex/_delivery.shthen maps every false result tostale pidfile (pid ... not running). The diagnostic therefore states a factthat the probe did not establish.
Expected behavior
A failed process-table query should not be treated as positive evidence of
death.
At minimum, status should distinguish:
For the observed case, a message such as
bridge liveness unverifiablewouldbe accurate. Destructive or ownership-changing callers should preserve records
and avoid kill/reclaim actions when the result is unknown.
Possible direction
This issue is primarily an observation report, not a proposal for the broader
Windows PID-generation design. A follow-up could add a tri-state result at the
existing liveness seam, or provide a separate detailed probe while retaining a
boolean compatibility wrapper.
Whichever shape is chosen, regression coverage should distinguish all three
native-query outcomes:
tasklistexecution.The third case must not produce a definitive
not runningstatus or authorizedestructive cleanup. PID reuse, process start markers, and wider ownership
generation work are intentionally out of scope for this issue.
Impact
The immediate observed impact is a false status report, which can lead an
operator to restart or tear down a healthy route. The same binary helper is also
used by lifecycle code, so preserving the distinction between
deadandunverifiableis important before a failed probe is used as authority forcleanup.
🤖 Issue text drafted with Claude Code; the
observation and reproduction are from a real deployment.