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

59 lines
2.7 KiB
Markdown

# 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.