merge: Campaign LA LA3 - Launcher.Core review-closed

This commit is contained in:
Erik 2026-08-14 17:11:25 +02:00
commit 7749545dc4
33 changed files with 4477 additions and 0 deletions

View file

@ -24,6 +24,57 @@ What does NOT go here:
- Every session: scan OPEN issues at start; promote/close anything we touched during the session before ending.
- Promoting to a Phase: mark as `DONE (promoted to Phase X)` + commit SHA where the Phase entry landed.
## #397 — Windows: LauncherProcessSupervisor.Stop has no reliable graceful-stop signal for a no-window console host
**Status:** OPEN
**Severity:** MODERATE (a hard-killed `AcDream.Headless` leaves the ACE
account session stuck for several minutes — a documented project landmine;
see CLAUDE.md "Logout-before-reconnect")
**Filed:** 2026-08-14 (Campaign LA plan §LA3 review-fix round, finding F3)
**Component:** Launcher.Core / process supervision
**Description.** `LauncherProcessSupervisor.Stop` now attempts a graceful
stop signal (`ILauncherChildProcess.TryRequestGracefulStop`) BEFORE
`CloseMainWindow`. On Linux this sends `SIGINT` via a `libc` P/Invoke
(`kill(pid, 2)`), which the K4-proven headless host already turns into an
ACE-confirmed graceful logout. On Windows there is no equivalent today for a
console process with no message-pump window: `CloseMainWindow` is a no-op
for a console host (there is no `HWND` to target), and
`GenerateConsoleCtrlEvent` cannot usefully target an arbitrary child process
today — Windows delivers console control events to every process attached
to the SAME console as the calling process, so an unscoped call would also
signal the launcher itself (and anything else sharing that console), not
just the intended child. `TryRequestGracefulStop` therefore returns `false`
on Windows unconditionally, and `Stop` degrades straight to `CloseMainWindow`
(still a no-op for a console child) and then the timeout-driven `Kill()`
exactly the hard-kill behavior this finding was written to describe, just
with a documented (rather than silent) gap.
**Known fix direction (not yet implemented).** Spawn the Windows child with
the `CREATE_NEW_PROCESS_GROUP` creation flag (available via a native
`CreateProcess` call or by setting it on the `ProcessStartInfo`/`Process`
plumbing in `SystemChildProcess`) so the child gets its own console process
group, detached from the launcher's own group. Then
`TryRequestGracefulStop` on Windows calls
`GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, childProcessGroupId)`
`CTRL_BREAK` (unlike `CTRL_C`) can target a specific process group ID and,
unlike `CTRL_CLOSE`/`CTRL_LOGOFF`/`CTRL_SHUTDOWN`, is deliverable to a
process that has installed no console-control handler at all (the default
CRT handler treats it as a terminating signal, so `AcDream.Headless` doesn't
strictly need new code to receive SOME form of shutdown from it) — though
wiring a real `SetConsoleCtrlHandler` handler that routes `CTRL_BREAK` into
the same graceful-shutdown path K4 already built for Linux SIGINT is the
better long-term target, so a Windows headless launch gets the identical
ACE-confirmed graceful logout instead of just "exits somehow."
**Acceptance for closing this issue:** `SystemChildProcess` spawns Windows
children with `CREATE_NEW_PROCESS_GROUP`; `TryRequestGracefulStop` sends
`CTRL_BREAK_EVENT` to that child's process group on Windows; a live
connected gate proves `AcDream.Headless` exits gracefully (ACE clears the
session immediately, not after the ~3-minute stale-session window) when
stopped via `LauncherProcessSupervisor.Stop` on Windows, matching the
Linux SIGINT behavior.
## #396 — Configure Keyboard: no capture-instruction dialog on a mapping-button click
**Status:** ROOT-CAUSED + FIXED — pending the user's visual re-gate of the