HUD generation field: both resolve is now unknown, not a claim

The status-bar GEN field took the presence of a current-generation graphics symbol as proof of the current console. On shadPS4 that read 5 (current) on a PS4 emulator, sitting next to its own PS4-scale MEM/VRAM figures. It was the one place in the program that trusted a pointer instead of observing behaviour - the exact failure this tool exists to expose, committed in the tool's own header.

The detector had already been moved to a shared obs_detected_generation() (the other thread, D110) returning current / previous / both / unknown, which stopped the outright 5-from-a-stub. But the HUD still rendered the both case as a confident 4+5 (both). That both is not a machine with two driver stacks - it is the signature of a loader that stubs every unresolved import. Measured on one shadPS4 run: 64,183 imports stub-resolved, 1,058 of them NIDs it could not even name (Unknown !!!), 236 in libSceAgc. The plain PS4 video-out it genuinely implements logs through its real subsystem (Lib.VideoOut, driver.cpp) with parameters and behaviour; every Agc/Gnm/…2 symbol is a Core.Linker <Warning> Stub resolved. Presence and behaviour, side by side in one log.

So the HUD now reports a generation only when exactly one driver resolves; both and neither are both unknown (both as unconfirmed - something graphics-shaped resolved - neither as absent). obs_address_is_callable is a crash-guard (addr != NULL && addr >= OBS_LOWEST_CALLABLE), not an oracle, and no address-only test can separate a stub from an implementation on a stub-everything loader - so unknown is the honest floor. Change is HUD-rendering only (src/sysinfo.c); obs_detected_generation() left to the thread that owns it. Verified on shadPS4: GEN UNKNOWN. make check green (117).

Surprise worth keeping


Protocol completion: blob/run/reset (D122). The three verbs were specified and known to the checker but unimplemented in net.c (a driver got unknown-verb). Now implemented, off by default (refused not-negotiated) and enabled by make ... HATCH=1. blob uploads machine code to a fixed table (no allocation), run executes it via a new obs_net_backend_exec (host: mmap W-then-X then call; console: refuses, D008 - vendor exec-map arities unconfirmed), reset frees the table. Matched to the existing examples exactly: blob returns the chunk byte count, run returns the callee value, reset reports how many blobs it freed, no-capability build refuses not-negotiated. All builds (default + HATCH, host + module + payload) compile clean under -Werror -Wconversion. Proven end to end on the host: a stub b82a000000c3 (mov eax,0x2a; ret) uploaded and run returned 0x2a, reset then freed it and a later run refused. Protocol checker passes 11 exchanges, self-test catches all 13 mutations.

Notes


Golden GPU corpus + regression gate (D123). reports/gpu-golden.txt (1478 records) is a blessed snapshot of the VM's llvmpipe; scripts/gpu-golden.sh --capture/--check bless and check it; --check is gated in verify.sh. It catches the kernel-output regressions the reference cannot judge (the transcendentals): the reference says "still exact where it must be", the golden says "changed at all". Skips on a different device (transcendentals differ legitimately) or none, so it joined the gate without breaking the GPU-run-only-by-hand rule - it asserts zero divergence only on the matching device. Proven both ways: clean on match (0 diverged), and a one-bit mutation to an rcp lane (0xdeadbeef) made it name the lane and exit 1; re-capture restored it. Closes the last of the ahead-of-hardware items.

All six ahead-of-hardware GPU items now landed: reference oracle (D116), ISA surface census (D117), GLSL-reachable gaps (D118), integer/bit breadth (D119), controlled-ISA relaxed variants (D120), protocol completion (D122), golden gate (D123). 42 kernels; every GPU/tool gate green.