449. The probe runs here too

2026-09-08 - directed, continuing 448

The premise four decisions rested on was wrong

D613, D615 and D620 all treated a thread blocked in sceKernelWaitEqueue as the wall in the two Unity titles, because the run report prints the fault and the recent calls together. The call tail is every thread's and the fault is one thread's, and nothing said which lines belonged to the thread that died.

They were different threads. With the fault naming its own:

! the guest faulted at image+0x39f7c, ..., on guest thread 0x5e2d00000a20
    just before: libSceAgc::sceAgcCreateShader(0x6000007fc538) -> 0x7fff0001
    just before: libc::memcpy(0x74000edc0200)
    just before: libc::memcpy(0x74000edc0100)
    just before: libkernel::scePthreadSelf(...) -> 0x5e2d00000a20
    just before: libkernel::sceKernelWaitEqueue(0x5e2d0000ee40)  [another thread]

scePthreadSelf on the faulting thread answers the handle the fault reports - the join confirmed from both ends. The wall is sceAgcCreateShader answering 0x7fff0001, which is still in rbx three calls later. It was one line below where anybody was looking (D621).

Same shape as D616, which found last_call answering "what am I inside" with another thread's call. Two questions answered by one function, because single-threaded they have the same answer. Third time this session the finding has been a missing distinction rather than a wrong value.

The probe runs under orbistoun

Its payload build executes here and emits the same OBS| stream the hardware reports carry. So the same binary runs in both places and its own verdicts can be compared - and a check that passes on a console and fails here is a named, sourced defect with the probe's own sentence attached.

orbistoun-cli probe <local> --against <hardware>:

256 of 635 check(s) both ran concluded differently
115 passed there and failed here - each is a defect with its own words
  020-memory/allocate            allocation was refused
  020-memory/virtual-query-text  virtual query on code address refused
  050-time/usleep                a short sleep was refused
  120-measure/sleep-fidelity     a sleep returned far sooner than asked
  102-net/sockaddr-bind          bind refused both sockaddr lengths
  900-surface/control            a symbol that does not exist reported present;
                                 every count in this section is meaningless

Only checks both sides ran are compared - one side skipping is a difference in reach, not behaviour, and listing it would bury the ones that are (D622).

900-surface/control is the probe reporting sceKernelDlsym's known divergence and its blast radius: every count in that section is meaningless because of it. No wall has ever said that.

titles/obscene-payload is in the corpus now: 223 distinct imports, 100% standing, exits cleanly - more of the interface than any title, and the only guest that terminates rather than crashing or timing out.

Surprises

The dump answered a different question

Chasing 020-memory/allocate - "allocation was refused" - the implementation turned out to be innocent. Called directly with obSCEne's own arguments (0, 0x140000000, 64 KiB, 16 KiB, 0, &out) it answers 0x0 and hands back 0x10000. So the refusal is between the probe and the implementation, not in it.

Reaching for ORBISTOUN_DUMP to see the real call found two tool defects first:

ORBISTOUN_DUMP=sceKernelWaitEqueue   on PPSA03416   -> dumped
ORBISTOUN_DUMP=sceKernelAllocateDirectMemory  on the payload -> a list without it in

A forced list was added to the default set rather than replacing it, and the default set - every import nothing implements - filled the 512-entry buffer with the payload's unimplemented maths library long before the import somebody had actually asked about. A forced list now narrows the dump to itself.

And a dropped dump printed as nothing at all, so the tool answered and omitted what it was asked for without saying so. Counted and reported now:

orbistoun: 45 argument dump(s) wanted after the buffer was full -
           name an import with ORBISTOUN_DUMP to spend the room on it

My first reading of this was wrong and is worth recording as wrong: I concluded "every diagnostic keyed on an import label is inert for a bare-ELF guest", which is not true - the labels resolve fine. It was a buffer, and the reason I believed the stronger claim is that a silent drop and a guest that never calls the thing look identical from outside (D623).

With the forced dump given the whole buffer, sceKernelAllocateDirectMemory still produces nothing - which now means something: the payload never reaches a thunk for it. That is the memory question properly posed for the first time.

Next