feat(launcher): prepare Campaign LA11 user gate
This commit is contained in:
parent
09d84387a8
commit
f881e5b467
24 changed files with 3538 additions and 58 deletions
|
|
@ -26,53 +26,41 @@ What does NOT go here:
|
|||
|
||||
## #397 — Windows: LauncherProcessSupervisor.Stop has no reliable graceful-stop signal for a no-window console host
|
||||
|
||||
**Status:** OPEN
|
||||
**Status:** IN-PROGRESS — the isolated process-group implementation and real
|
||||
Windows fixtures are complete; the LA11 connected acceptance row remains
|
||||
required before closure.
|
||||
**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.
|
||||
**Implementation checkpoint.** `LauncherProcessSupervisor.Stop` attempts
|
||||
`ILauncherChildProcess.TryRequestGracefulStop` before `CloseMainWindow` and
|
||||
the timeout/kill fallback. Linux retains its K4-proven targeted `SIGINT`.
|
||||
On Windows, console-capable launcher specs now use a narrow no-shell
|
||||
`CreateProcessW` seam with `CREATE_NEW_PROCESS_GROUP`, a suspended start, and
|
||||
an explicit inherited-handle list that preserves only redirected stdin plus
|
||||
stdout/stderr. A consoleless Avalonia parent briefly allocates and hides a
|
||||
console for the creation transaction, detaches after the new group inherits
|
||||
it, and later attaches only long enough to send
|
||||
`GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, childProcessGroupId)`. Each such
|
||||
child is therefore both the root of its own process group and, for the normal
|
||||
Explorer-launched case, attached to its own console. Graphical children opt
|
||||
out and retain the ordinary `Process`/`WM_CLOSE` path.
|
||||
|
||||
**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."
|
||||
Two real Windows fixture gates cover both a console parent and a consoleless
|
||||
WinExe parent. They prove exact complex argv, redirected stdin, receipt of a
|
||||
targeted CTRL_BREAK marker, exit code 0 before timeout, no supervisor `Kill`,
|
||||
and a sibling process group that remains running until it receives its own
|
||||
targeted break. Safe-handle cleanup, early-failure termination, and the
|
||||
Linux SIGINT gate remain covered by the Launcher.Core suite.
|
||||
|
||||
**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
|
||||
**Acceptance for closing this issue:** automated process-group and targeted-
|
||||
signal coverage is complete. Keep the issue IN-PROGRESS until the LA11 live
|
||||
connected row proves `AcDream.Headless` exits gracefully and ACE clears the
|
||||
session immediately (not after the ~3-minute stale-session window) when
|
||||
stopped through `LauncherProcessSupervisor.Stop` on Windows, matching the
|
||||
Linux SIGINT behavior.
|
||||
|
||||
## #396 — Configure Keyboard: no capture-instruction dialog on a mapping-button click
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue