---
phase: quick
plan: 260416-1lc
subsystem: common/process, owl/stop, owl/cleanup, live/stop
tags: [win32-api, process-management, taskkill-migration]
dependency_graph:
  requires: []
  provides: [force_kill_process, terminate_process_tree]
  affects: [owl-stop, owl-cleanup, live-stop]
tech_stack:
  added: [CreateToolhelp32Snapshot, Process32FirstW, Process32NextW]
  patterns: [win32-ffi-inline, recursive-child-enumeration]
key_files:
  created: []
  modified:
    - src/common/process.rs
    - src/owl/cleanup.rs
    - src/owl/stop.rs
    - src/live/stop.rs
decisions:
  - "Windows graceful pass in stop --all uses force_kill_process (WM_CLOSE via taskkill was meaningless for console background processes)"
  - "terminate_process_tree uses Process32FirstW (wide) matching existing types.rs PROCESSENTRY32W pattern"
  - "Orphan PID cleanup in live/stop.rs uses platform-agnostic force_kill_process (no cfg gates needed)"
metrics:
  duration: 145s
  completed: 2026-04-16
---

# Quick 260416-1lc: Migrate Remaining taskkill Subprocess Calls to Win32 API

Eliminated all taskkill subprocess calls, replacing with direct Win32 TerminateProcess/CreateToolhelp32Snapshot API calls to fix hanging on Windows 11 26200+.

## Tasks Completed

| # | Task | Commit | Key Changes |
|---|------|--------|-------------|
| 1 | Add force_kill_process and terminate_process_tree | a33d47d | Two new Win32 API functions in process.rs |
| 2 | Replace all taskkill calls in consumer files | 305c29a | cleanup.rs, owl/stop.rs, live/stop.rs migrated |

## Changes Made

### process.rs
- Added `force_kill_process(pid)`: SIGKILL on Unix, TerminateProcess on Windows (no graceful step)
- Added `terminate_process_tree(pid)`: killpg on Unix, CreateToolhelp32Snapshot + recursive child enumeration + TerminateProcess on Windows
- Updated comments to remove taskkill references

### cleanup.rs
- Deleted local `kill_process` function (22 lines)
- Added `process` to imports, call site delegates to `process::kill_process`

### owl/stop.rs
- Deleted local `kill_process` function (25 lines)
- Added `process` to imports
- Single-perch stop: `process::kill_process(pid)`
- stop --all graceful pass: `process::force_kill_process(pid)` on Windows (SIGUSR1 on Unix preserved)
- stop --all force pass: `process::force_kill_process(pid)` on Windows (SIGKILL on Unix preserved)

### live/stop.rs
- Deleted local `kill_process_group` function (35 lines)
- Wrapper kills: `process::terminate_process_tree(wpid)` (3 call sites)
- Orphan PID cleanup: `process::force_kill_process(wpid)` (platform-agnostic, no cfg gates)

## Verification

- `cargo build --release`: passes (only pre-existing warnings)
- `cargo test`: 13 passed, 0 failed
- `grep -r "taskkill" src/ --include="*.rs"`: NO_TASKKILL_FOUND
- All kill call sites confirmed using process:: module functions

## Deviations from Plan

### Auto-fixed Issues

**1. [Rule 1 - Bug] Cleaned taskkill references in comments**
- **Found during:** Task 2
- **Issue:** process.rs doc comment and inline comment still mentioned "taskkill"
- **Fix:** Updated to reference TerminateProcess / "no subprocess calls"
- **Files modified:** src/common/process.rs
- **Commit:** 305c29a

## Known Stubs

None.

## Self-Check: PASSED
