D671 - The pad structure was measured, so the shim D345 deferred could be written

Status: decided Date: 2026-09-10

Comparing against the right leg, third time

D669 fixed orbistoun reporting itself a payload, and the conformance comparison moved to obSCEne's package leg. That was still wrong by one axis: the package leg is title/ps4-bc - previous generation, libSceGnm mapped, libSceAgc absent - and orbistoun presents prospero. Two of the divergences it produced were 165-gnm/dispatch-*, which orbistoun should differ on.

No hardware leg anywhere reports ps5-native. Eighty-eight logs, every one payload/unknown-gpu, title/unknown-gpu or title/ps4-bc. The closest match to orbistoun is a populated eboot leg, title/unknown-gpu, which is what orbistoun reports today - so that is the comparison from here. Against it: 167 hardware passes, 170 orbistoun, ten checks where hardware passes and orbistoun does not, and the generation artefacts gone.

Four of the ten were input, which is where this went.

D345 deferred it for the right reason, and the reason expired

scePadReadState was declared and unimplemented. D345 says why: the transport carrying pad state from the window to the guest was ours and testable, but the structure a guest reads was "a size and layout nobody here has measured", and building a shim around a guessed encoding is how a confident wrong answer gets made. It built the transport and left the shim, deliberately.

obSCEne has since measured it. 100-input/read-extent fills the destination with a sentinel, calls the function, and reports how far the change reached:

extent 120, changed 120
 0: 00000000 80808080 00000000 00000000
16: 00000000 00000000 0000803f 00000000
32: 0000803f 00000000 00000000 00000000
48..120: zero

100-input/batched-read reports the identical extent and contents for scePadRead.

Bytes, not a structure

The shim writes those 120 bytes verbatim. It does not declare a struct, and that is the whole of the decision.

What was measured is the byte image a console produced for a pad at rest. Which offset carries the buttons and which the sticks is an inference from it - the obvious reading is a mask in the first four bytes, four axes at 0x80 centre in the next four, and 1.0f at 24 and 32 - and a shim that laid out fields would publish that inference in the place the measurement belongs. Nothing needs the reading to answer this call correctly.

changed 120 is why the whole extent is written every time. A shim writing only the fields it believed it understood would leave the rest of the guest's buffer holding whatever was there before, which is precisely what that check exists to catch.

What it cannot do, said out loud

It cannot report input. Mapping orbistoun's live pad state onto these bytes needs the field offsets, and those are exactly the inferred part - so latest, the transport D345 built, stays unconsumed. A guest polling the pad under orbistoun sees a pad at rest, forever.

That is a limit rather than a gap to paper over, and obSCEne already names the run that would close it. Under orbistoun the two checks that would settle it now answer:

100-input/button-bits        pending  controller attached, but no button was seen in the window
100-input/stick-trigger-range pending  controller read, but nothing moved: sweep the sticks and re-run

Those are the right questions asked of the wrong machine - orbistoun cannot answer them because it is the thing that does not know. On hardware they settle it in one run, and that is filed.

What it bought

Three checks flipped: 100-input/read-extent and 100-input/batched-read from partial to pass 0x78, and 100-input/oops-sdk-poll from fail to pass 0x0. Input divergence against the matching leg went from four to one.

The count of "hardware passes, orbistoun does not" stayed at ten, and the composition is the interesting part: audio went from two to five. Those checks were reading partial on the old positive placeholder and read fail on the honest one (D670) - they were passing partially on a refusal the guest could not see. Audio is the next cluster, and it is only visible now.