left4me/docs/superpowers/plans/2026-05-06-l4d2-install-logging.md

5.2 KiB

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:

    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:

    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
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:

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:

from l4d2host.instances import _emit_step

Modify install_or_update:

    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
git add l4d2host/steam_install.py l4d2host/tests/test_install.py
git commit -m "feat(host): add step logging to steam_install"