feat(reverse): inject controlled original ball states

Add an atomic live-state injector for the traceable Wine process. It updates
all recovered global and object copies of ball position and velocity while the
process is stopped, clears pending impulses, and re-enables normal collision
processing before resuming the unmodified executable.

This makes individual walls, circles, gates, and mechanisms reachable without
relying on random gameplay. Document the first controlled claw probe, including
its original terminal-18 animation, exact release state, and three-substep
gravity behavior.

Test Plan:
- `ruff check original/tools/trace_original_state.py original/tools/inject_original_state.py` -- passed
- controlled `(289,94)` injection and one-second live claw trace -- passed
- terminal-18 release matched `(325000,92000)` and `(0,1000)` -- passed
- `shellcheck original/tools/run_traceable_original.sh` -- passed
- `git diff --cached --check` -- passed
This commit is contained in:
2026-08-22 20:20:26 +02:00
parent dcc664346c
commit d24ef6612f
4 changed files with 173 additions and 9 deletions
+7 -2
View File
@@ -60,12 +60,12 @@ class MemoryMap:
class ProcessMemory:
def __init__(self, pid: int) -> None:
def __init__(self, pid: int, *, writable: bool = False) -> None:
self.pid = pid
self.maps = self._read_maps()
try:
self.stream = open( # noqa: SIM115 - closed by the context protocol
f"/proc/{pid}/mem", "rb", buffering=0
f"/proc/{pid}/mem", "r+b" if writable else "rb", buffering=0
)
except PermissionError as error:
raise RuntimeError(
@@ -101,6 +101,11 @@ class ProcessMemory:
raise RuntimeError(f"short process read at {address:#x}: {len(data)}/{size}")
return data
def write(self, address: int, data: bytes) -> None:
written = os.pwrite(self.stream.fileno(), data, address)
if written != len(data):
raise RuntimeError(f"short process write at {address:#x}: {written}/{len(data)}")
def search_live_writable_memory(self, needle: bytes) -> list[int]:
matches = []
for mapping in self.maps: