left4me/docs/superpowers/specs/2026-05-06-l4d2host-step-logging-design.md

2.7 KiB

Host Lifecycle Step Logging Design

Goal

Provide granular, live progress feedback in the web GUI during lifecycle operations (initialize, start, stop, delete) without exposing sensitive internal paths or raw subprocess mechanics unless they fail.

Approach

Currently, l4d2ctl executes operations silently unless a subprocess fails. l4d2web captures stdout and stderr from l4d2ctl and pushes it to the browser via Server-Sent Events.

We will modify l4d2host/instances.py to emit safe, high-level step markers to stdout.

Since l4d2web uses subprocess.Popen(..., stdout=subprocess.PIPE) to execute l4d2ctl, any standard Python print(..., flush=True) in l4d2host will be naturally captured by job_worker.py and forwarded to the GUI as stdout events.

Logging Strategy

We will introduce an explicit _emit_step(msg: str, on_stdout: Callable | None, passthrough: bool) helper in l4d2host/instances.py to correctly route step output based on the calling context:

  • If on_stdout is provided (e.g. programmatic use), call it.
  • If passthrough is true (e.g. l4d2ctl CLI), print(..., flush=True).

Step Messages

initialize_instance

  • creating instance directories...
  • writing instance.env...
  • writing server.cfg...
  • initialization complete.

start_instance

  • mounting runtime overlay...
  • copying server.cfg to runtime...
  • starting systemd service...
  • start complete.

stop_instance

  • stopping systemd service...
  • unmounting runtime overlay...
  • stop complete.

delete_instance

  • stopping systemd service (if running)...
  • unmounting runtime overlay (if mounted)...
  • removing instance files...
  • delete complete.

File Changes

  • l4d2host/instances.py

    • Add _emit_step helper.
    • Insert calls to _emit_step at key locations in all lifecycle functions.
  • l4d2web/services/job_worker.py

    • Add synthetic web-layer boundary logs (starting initialize for test-server, finished initialize successfully) to clearly distinguish the boundaries between multiple l4d2ctl operations in compound jobs like start (which calls initialize then start).

Safety & Secrets

  • print statements must not include full absolute paths (e.g. avoid printing /var/lib/left4me/runtime/alpha/merged).
  • print statements must not echo spec data or env vars that might contain future RCON passwords or sensitive args.

Test Impact

  • test_l4d2_facade.py and test_job_worker.py that use fake run_command handlers might need to explicitly emit stdout if tests assert exact sequences.
  • Existing tests that call initialize_instance without passthrough will silently ignore steps as expected.