feat(mosstank): add VTank-style automation PoC

This commit is contained in:
Erik 2026-08-27 18:57:21 +02:00
parent f6fe0f2a4f
commit 4e6e9bc9d9
212 changed files with 49462 additions and 416 deletions

View file

@ -24,6 +24,79 @@ 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.
## #451 — GLFW can dereference another acdream process's private window pointer after cross-process activation
**Status:** IN-PROGRESS — exact root fixed; 100-switch/30-minute dual-client
stress passed 2026-08-27. Graceful exit of both sessions remains before closure.
**Component:** graphical host / GLFW Win32 event pump / multi-process stability.
**Severity:** HIGH for multi-account play; one of the two sessions is lost without
an orderly disconnect.
Running two copies of the exact isolated `app-release23` graphical artifact
against local ACE reproduced the same access violation three times. The
faulting process varied: secondary PID 13688 at 15:01:39, primary PID 15300 at
15:03:35, and fresh primary PID 31412 at 15:08:58. The last occurrence fired
while the fresh primary was still on character selection, before EnterWorld;
the already-in-world secondary survived. Windows Application Error reports
all three as `coreclr.dll` exception `0xC0000005`, fault offset `0x356d4f`.
The managed terminal stack is only:
```text
Silk.NET.Windowing.WindowExtensions...Run
Silk.NET.Windowing.Internals.ViewImplementationBase.Run
Silk.NET.Windowing.Glfw.GlfwWindow.Run
AcDream.App.Rendering.GameWindow.Run
```
This is not #422's rare `0xC0000374` heap corruption during graceful process
exit: #451 happens while both graphical clients are active and reproduces
quickly. It is also not a MossTank/plugin-API, CoreCLR, Vulkan, PAK, or world-
cache failure.
**Exact root (first-chance cdb proof):** the access violation is in packaged
GLFW's Win32 event pump at `glfw3+0x10681`, not in CoreCLR. During its modifier-
key repair pass `_glfwPollEventsWin32` calls `GetActiveWindow`, then
`GetPropW(hwnd, L"GLFW")`, and dereferences the returned value as this
process's `_GLFWwindow*`. Windows UI automation temporarily joins input queues,
so the primary process can receive the secondary process's HWND. Because every
GLFW process uses the same `GLFW` property name, `GetPropW` succeeds but returns
the secondary process's private pointer. The crashed primary had
`rbx=00000202a7180ab0`; a debugger breakpoint in the surviving secondary
reported its own valid `ACTIVE_GLFW_WINDOW=00000202a7180ab0` — exact pointer
identity across the process boundary.
**Fix:** `Win32GlfwActiveWindowGuard` patches only `glfw3.dll`'s import-address-
table slot for `USER32!GetActiveWindow`, after the GLFW library is loaded and
before `glfwInit`/window creation. The replacement returns the real HWND only
when `GetWindowThreadProcessId` says it belongs to the current process;
otherwise it returns zero, GLFW's existing safe "nothing to repair" branch.
There is no system-wide hook and no other module is changed. Four focused
tests cover local, foreign, null and unowned HWNDs.
The isolated `app-release24` live gate launched two graphical clients, both
logged `GLFW foreign-active-window guard installed (#451)`, entered the world,
and remained responsive through 100 rapid forced cross-process activation
switches — the exact prior trigger — plus a 30-minute combined in-world soak.
The local peer API then passed in both directions: the secondary evaluated the
primary heartbeat and returned `+Acdream`. A two-member fellowship gate also
passed with both canonical rosters populated and the secondary returning `2`
from `getfellowshipcount[]`; both processes remained alive and responsive.
Evidence:
- `artifacts/live-gates/mosstank-final23-secondary/`
- `artifacts/live-gates/mosstank-final23-secondary2/`
- `artifacts/live-gates/mosstank-final23-primary5/`
- `artifacts/live-gates/i451-cdb-primary-attach/cdb.log`
- `artifacts/live-gates/i451-cdb-secondary/cdb.log`
- `artifacts/live-gates/i451-guard-primary2/`
- `artifacts/live-gates/i451-guard-secondary/`
- Windows Application Error events at 2026-08-27 15:01:39, 15:03:35 and
15:08:58 (same module, exception and offset).
**Next:** close only after both `app-release24` sessions exit gracefully; the
activation and sustained in-world portions of the regression gate have passed.
## #450 — Fast character re-entry after logout can remain in portal space at `lb 0/0`
**Status:** DONE — OWNER-ACCEPTED 2026-08-26 in the combined client-parity gate.