Narrows the previous commit to the one case where the outcome is really
unknown. When the sender has already pinned a live intent (<dm>.live.json)
it may have admitted the DM and told the model not to resend; a runner
that then fails hermes_bootstrap now prints the same ambiguous payload
(same delivery id, "Do not resend") that _run_delivery prints for an
admission failure. Without an intent nothing was handed over, so the plain
repair hint stays the truth and a resend remains correct.
The payload is shared with _run_delivery via _live_outcome_unknown instead
of a second classifier, and the evidence-probing variants and the separate
test module are dropped in favour of one real -I -S subprocess test plus an
explicit negative assertion on the existing no-intent test.
The --wait-reply waiter is stdlib only and its stdout is the sender's
wake-up. Booting it through hermes_bootstrap meant an install whose
committed environment cannot be activated killed the waiter with the
repair hint on stderr before it printed anything, so the sender never
learned the delivery outcome. Only the delivery lane boots now.
Port the failure-mode test from #125754: a --run-delivery runner that
cannot activate exits with the `hermes pm repair` remedy and leaves the
DM untouched, instead of the ambiguous "No module named ..." outcome.
Co-authored-by: woriwka-ai <247827632+woriwka-ai@users.noreply.github.com>
message_agent spawns its background runner as
`<sys.executable> tools/bot_mode_dm.py --run-delivery ...`, and the relay's
reply waiter (bot_relay.waiter_command) as `... bot_mode_dm.py --wait-reply ...`.
Both enter through the shared `if __name__ == "__main__":` block, which only
put the repo root on sys.path. Under a PM-managed install sys.executable is the
bare store interpreter: dependencies are activated in-process at boot by
hermes_bootstrap (pm.environments.activate_dependencies), and the terminal
backend strips the Hermes-owned PYTHONPATH, so the child has no third-party
packages. Live, every local Bot Chat DM returned
`{"status": "ambiguous", "error": "Live admission outcome unknown: No module
named 'ruamel'. Do not resend."}` from _run_delivery -> _admit_live_dm.
The __main__ block now imports hermes_bootstrap after putting the repo root on
sys.path (run as a script path, sys.path[0] is tools/). This is the same pattern
as tui_gateway/compute_host.py and agent/transports/hermes_tools_mcp_server.py:
only the script entry bootstraps, so importing tools.bot_mode_dm as a library
stays side-effect free and the module's top-level imports stay stdlib-only.
hermes_bootstrap rather than a bare activate_dependencies() call, because the
runner is a real entry point and needs what every entry point gets: dependency
activation plus early recovery of an interrupted update, the Windows UTF-8 stdio
bootstrap (its stdout carries the teammate's reply as the completion
notification), and import-path hardening against a cwd package shadowing
Hermes modules. The runner argv is safe for the bootstrap: command_argv() reads
`--run-delivery`/`--wait-reply` as flags, so it is neither `update --post-swap`
nor `pm repair`. prepare_launch acts only on a self-updated install whose
dependencies are behind or whose interpreter is not the store Python, and its
relaunch re-runs the same script path with the same argv (runpy.run_path), so
the runner keeps its contract there too.
tests/tools/test_bot_mode_dm_entry.py launches the real script under `-I -S`
with a PM-committed dependency record in a temp HERMES_HOME as the only route to
the packages: the --run-delivery case fails on the parent commit with the exact
live `No module named 'ruamel'` error and passes here; the --wait-reply case
drives the argv waiter_command builds through the same entry.