# SteamCMD Install Logging & Buffering Fix Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Improve live feedback during the `install` operation by adding step markers to `SteamInstaller` and fixing Python subprocess buffering so output streams immediately. **Architecture:** Modifies `l4d2host/process.py` and `l4d2web/services/host_commands.py` to add `flush=True` to `print()` statements for immediate pipeline throughput. Modifies `l4d2host/steam_install.py` to use `_emit_step` to log platform payload downloads. **Tech Stack:** Python, subprocess --- ### Task 1: Fix process output buffering **Files:** - Modify: `l4d2host/process.py` - Modify: `l4d2web/services/host_commands.py` - [ ] **Step 1: Check existing test suite** No failing test is required here because we are only modifying the `flush` parameter of `print()` inside existing pass-through functions, which are thoroughly covered by integration tests but unit-testing the buffering of `print` is notoriously flaky across OSes. We will just modify the code and run the existing suite. - [ ] **Step 2: Add flush to l4d2host process** Modify `emit_stderr_message` and `pump` inside `run_command` in `l4d2host/process.py`: ```python def emit_stderr_message(line: str) -> None: stderr_lines.append(line) if on_stderr is not None: on_stderr(line) if passthrough: print(line, file=sys.stderr, flush=True) # ... inside pump ... if passthrough: print(line, file=output_stream, flush=True) ``` - [ ] **Step 3: Add flush to l4d2web host_commands** Modify `emit_stderr_message` and `pump` inside `run_command` in `l4d2web/services/host_commands.py`: ```python def emit_stderr_message(line: str) -> None: stderr_lines.append(line) if on_stderr is not None: on_stderr(line) if passthrough: print(line, file=sys.stderr, flush=True) # ... inside pump ... if passthrough: print(line, file=output_stream, flush=True) ``` - [ ] **Step 4: Run test to verify it passes** Run: `pytest l4d2host/tests l4d2web/tests -q` Expected: PASS - [ ] **Step 5: Commit** ```bash git add l4d2host/process.py l4d2web/services/host_commands.py git commit -m "fix(host): enforce flush=True to prevent pipeline block buffering" ``` --- ### Task 2: Add step logging to SteamInstaller **Files:** - Modify: `l4d2host/steam_install.py` - Modify: `l4d2host/tests/test_install.py` - [ ] **Step 1: Write failing test** In `l4d2host/tests/test_install.py`, add a test to verify `SteamInstaller` logs steps: ```python def test_steam_installer_emits_steps(tmp_path: Path, monkeypatch) -> None: monkeypatch.setenv("LEFT4ME_ROOT", str(tmp_path)) monkeypatch.setattr("l4d2host.steam_install.run_command", lambda cmd, **kwargs: None) steps: list[str] = [] from l4d2host.steam_install import SteamInstaller SteamInstaller().install_or_update(on_stdout=steps.append) assert steps == [ "Step: downloading windows platform payload...", "Step: downloading linux platform payload...", "Step: installation complete." ] ``` - [ ] **Step 2: Run test to verify it fails** Run: `pytest l4d2host/tests/test_install.py -k test_steam_installer_emits_steps -q` Expected: FAIL because `steps` is empty. - [ ] **Step 3: Add step logs to SteamInstaller** In `l4d2host/steam_install.py`, import `_emit_step`: ```python from l4d2host.instances import _emit_step ``` Modify `install_or_update`: ```python def install_or_update( self, *, on_stdout: Callable[[str], None] | None = None, on_stderr: Callable[[str], None] | None = None, passthrough: bool = False, should_cancel: Callable[[], bool] | None = None, ) -> None: for platform in ("windows", "linux"): _emit_step(f"downloading {platform} platform payload...", on_stdout, passthrough) run_command( [ self.steamcmd, "+force_install_dir", str(self.install_dir), "+login", "anonymous", "+@sSteamCmdForcePlatformType", platform, "+app_update", "222860", "validate", "+quit", ], on_stdout=on_stdout, on_stderr=on_stderr, passthrough=passthrough, should_cancel=should_cancel, ) _emit_step("installation complete.", on_stdout, passthrough) ``` - [ ] **Step 4: Run test to verify it passes** Run: `pytest l4d2host/tests/test_install.py -k test_steam_installer_emits_steps -q` Expected: PASS - [ ] **Step 5: Run full suite** Run: `pytest l4d2host/tests l4d2web/tests -q` Expected: PASS - [ ] **Step 6: Commit** ```bash git add l4d2host/steam_install.py l4d2host/tests/test_install.py git commit -m "feat(host): add step logging to steam_install" ```