Where it stands
| Behavioural checks | 501 - 82 spec, 44
derived, 2 implementations, 368
assumed, 2 documented, 3
hardware |
| Census symbols | 39493 across 372 libraries |
| Sections | 53 |
| Imports placed by the manifest | 311 |
Loaders that run the whole suite: five. shadPS4,
PS5PCEM, fpPS4 and Kyty all reach the end record, and so does prosper,
which is headless and opens no window at all. Two of the five need a
local patch to get there and their reports are quarantined accordingly
(D176): Kyty's unresolved-import trampoline called EXIT,
and fpPS4's called Sleep(INFINITE) (D196).
This line previously read "shadPS4 (the full suite), Kyty (loads and relocates; names the imports it lacks), craziiEmu (loads; resolves nothing yet)" and had been true months earlier. craziiEmu was superseded by PS5PCEM and prosper; nothing struck the sentence.
The table above is generated by obscene-tool counts
from the source, and verify.sh fails if it has drifted.
Every number in it was wrong at least once when it was
hand-written.
The number that matters most is the zero, and the ranking below follows from it. Every expectation here is either settled by a public document or is this project's own guess, and an emulator built to satisfy the guesses has only been made to agree with us.
The ranking changed, and the old one was wrong
§10 used to be first: 4,459 census names, mechanically addable. That is the largest number available and close to the least valuable, for three reasons worth keeping.
An emulator author already has that list, for free and complete. Their own stub log says exactly which symbols they have not implemented. A census tells them something they can generate perfectly themselves.
It would swamp the report. 4,800 presence records against 106 behavioural checks is a report that is 98% inventory, and the headline coverage ratio would improve while the ability to find a bug did not change at all.
Presence is not even a clean measurement. shadPS4 resolves everything through a generic stub, so all 312 already report present while roughly forty per cent behave. The census measures the loader's stubbing policy as much as the platform.
The census's real justification is static - knowing what a title will need before it needs it - which argues for ranking names by how often they appear in real import tables, not for exhaustiveness.
Ranked
Refreshed after the blind prober reached the end of the corpus and a three-way consensus found a bug in this project rather than in an emulator. Four of the previous eight are done, and the shape of what is left has changed: the cheap oracle-free work is spent, and almost everything remaining is either machine time or blocked behind struct layouts.
| Item | Why here | |
|---|---|---|
| 1 | The provenance ladder has no rung for "independent implementations agree" (D166) | It has now cost something twice.
015-sync/event-flag-round-trip claimed
DOCUMENTED and was backwards; corrected, what supports it
is two open-source implementations agreeing, which is real evidence the
ladder cannot express. ASSUMED understates it,
DOCUMENTED overstates it, and overstating is what went
wrong. The sibling project raised the same gap on the
measurement axis and we declined it - that decision looks less
obviously right now |
| 2 | Behaviour described in prose has no gate | doccheck verifies that referenced things
exist, never that described behaviour is current.
PROTOCOL.md spent part of a day describing a loopback bind
that had been reverted from the code, and only got caught by accident.
Third instance of the house failure - a mechanism saying something
reasonable while being wrong (D158, D163, this) |
| 3 | §1 current generation, blind-called - in flight | The census has 89 libSceAgc* names and §1's own honest
limit was "nothing here is called". The prober calls every censused
symbol, and it had only ever run against a previous-generation
loader: all 118 AGC symbols that answered under shadPS4 returned zero,
which measures a PS4 emulator stubbing a PS5 interface. The run against
PS5PCEM is the first time these are called on a loader that implements
any of them |
| 4 | §12 consensus, four-way | Three-way already found D166. fpPS4 is the missing fourth and its last report is invalid - a concurrent build overwrote the tree mid-run. Cheap to redo and it widens the majority that made D166 legible |
| 5 | FreeBSD provenance | About nine checks, not fifty. Measured below. Reading, not research |
| 6 | §6c thread-churn threshold | Knob exists; ~20 runs per point. Pure machine time, no judgement - the best thing to leave running unattended |
| 7 | §7 census cannot detect a lying platform | Presence is self-reported. Largely answered by the runtime module census (D157) and quantified by the prober: 96.4% of 32,275 blind calls return zero, and 282 of 342 libraries never refuse anything. The entry predates both and needs closing against them rather than working on |
| 8 | §2 struct layouts | Not last because it is unimportant - it is the opposite. Everything left in §11, the equeue ordering relation, mapping isolation, directory listings and the whole of §1's behavioural half sit behind it. It is last because this project will not guess a layout (D008) and nothing short of hardware or a confirmed public definition unblocks it |
| 9 | §10 census expansion | Deliberately last. See above |
Done since the last ranking, and struck from it:
- Runtime module census was item 1. Built (D157), and its
first run settled what D149 could only argue: the address census said
373 of 373 present while
sceKernelLoadStartModulereturned ENOENT for all five paths on the same run. - Blind prober against a loader was item 2. It has now reached the end of the list - 32,275 of 32,466 answered against shadPS4, across four resumed sessions.
- Act on the consensus outliers was item 3. Done once (D156), and done again today with a third implementation, which produced D166.
- §11 relational checks was item 5. Seventeen exist; the
section has reached the far side of what routing around the layout
blocker can do. Item 5 was measured, and it is a fraction of
what was advertised. The entry said "49 assumed checks, many
settled by a public man page", which counted every assumed check and
assumed a document existed for it. Of 53 assumed checks: 31 call
sceKernel*, and 24 of those are vendor-only -GetProcessTime,IsNeoMode,DirectMemoryQuery,GetTscFrequency,GetSystemSwVersion- which no man page describes because nothing outside the vendor has them. What is genuinely settleable is roughly nine:sceKernelOpen,sceKernelClose,sceKernelMunmap(twice),sceKernelUsleep, and the four pthread/POSIX-named ones.
Worth stating rather than quietly renumbering, because the entry
would have sent somebody at a week of reading for an afternoon of it.
Two more looked like analogues by name and are not:
sceKernelReadTsc is not read(2) and
sceKernelPollEventFlag is not poll(2). A
prefix is not a provenance.
Struck in an earlier pass, kept because the reasons still
hold: the tooling port (seventeen Python scripts became
obscene-tool subcommands, and every checker ported was
found miscounting something); N-way consensus, blocked on "needs a
second reporting loader" and now having four; current-generation
graphics, blocked on "a whole layer absent" until PS5PCEM ran a
GEN=5 module to completion; and condition variables and
barriers, now four checks.
Not on the list because they need something this project
cannot supply: a Steam Deck run (make deck builds,
no hardware has run it) and the hardware run (0 hardware
confirmations, which is the number that limits every claim in
the report).
Items 5, 6 and 7 worked, 2026-08-26 - and two of the three were not what the entry said
Item 5 (FreeBSD provenance) is four checks, not nine. The entry had already been corrected once, from 44 to "roughly nine". Reading the nine settles it at four:
| check | outcome |
|---|---|
040-file/open-rejects-missing |
derived - FreeBSD open(2) gives
ENOENT for a path that is not there |
020-memory/unmap |
derived - munmap(2) returns 0 for a
valid mapping |
020-memory/unmap-rejects-null |
derived, on FreeBSD's page and not POSIX's - see below |
015-sync/mutexattr-round-trip |
derived - POSIX settles set-then-get on a mutex attribute |
040-file/open-rejects-null |
stays assumed: a null pointer is
undefined in POSIX. FreeBSD's EFAULT is an
implementation detail, not a specification |
120-measure/sleep-fidelity |
stays assumed, and its own comment always said so:
"Both bounds are this project's, not a document's" |
140-oracle/error-codes |
stays assumed: it asserts nothing.
"No expectation is asserted here at all. It records what came
back." Provenance describes an expectation; a measurement has
none |
015-sync/mutex-recursion |
stays assumed: it probes which numeric type value is
recursive, and POSIX fixes the names, not the numbers |
017-posix/spellings-agree |
stays assumed: self-consistency. "Nothing here asks
for a particular answer" - no external document can raise it |
unmap-rejects-null is the one worth reading twice.
POSIX contradicts this check: unmapping an unmapped
range "has no effect" and returns 0, so by POSIX the expectation is
backwards. FreeBSD returns EINVAL when part of the region
is outside the valid address space, and the kernel here derives from
FreeBSD - which is exactly what the derived rung means, and
exactly why it is a different rung from spec.
The entry's own warning applied to itself: "A prefix is not a provenance." Neither is a plausible-looking analogue. Five of nine had no document behind them at all.
Item 6 (thread-churn threshold) was not blocked on machine
time. scripts/repeat.sh still drove multipass and
could not run at all; four other scripts were dead the same way (D199).
Now portable. What the entry says about the measurement still
stands - separating "crashes above N" from "crashes at any N" needs
roughly 200 runs a point - but the cost of a run has changed underneath
it: the sweep deadlock in D194 meant every run took minutes, and shadPS4
now completes in 13 seconds. Two hundred runs a point is about 45
minutes, not an afternoon. Worth revisiting on economics, still
not started.
Item 7 (the census cannot detect a lying platform) is done
and can be struck. The entry already says "needs closing
against them rather than working on".
900-surface/presence-is-not-behaviour exists, never returns
pass, and escalates its wording correctly across all five
loaders that now complete the suite:
| loader | what it says |
|---|---|
| PS5PCEM | "nothing was probed for behaviour, so this census says only which symbols resolve" |
| shadPS4, fpPS4, Kyty | "most probed functions are stubs; read this census as an upper bound, not a coverage figure" |
| prosper | "presence is not behaviour…" |
And prosper is the entry's hypothetical made real: it links all 35,518 imports as stub slots, resolves both generations' exclusive symbols for free, and scores the highest pass count of any loader partly because returning zero is often the right answer. The section was written against exactly this platform before one existed to test it on.
The previous ranking, kept so the change above is checkable
Superseded. Do not read a number out of this table - two of them are known wrong and are left standing because correcting a historical record makes it stop being one. §11 said ten relational checks and there are now seventeen; the FreeBSD row said 44 assumed checks settleable by a man page, and the measurement above puts it near nine.
It lost its header row at some point and rendered as a broken table, which is how it went unread long enough to keep two stale figures beside a current list.
| rank | item | why |
|---|---|---|
| 1 | §11 relational checks - ten in
018-relational, more available |
Oracle-free, needs no struct layout and no documented error code. Routes around §2 and §5 rather than waiting on them |
| 2 | §12 N-way consensus -
obscene-tool consensus exists; needs a second reporting
loader |
Turns "you failed X" into "you are the only one of four that fails X". Actionable without authority |
| 3 | FreeBSD provenance (task #14) | 44 assumed checks, many settled by a public man page. Reading, not research |
| 4 | §1 current-generation graphics | A whole layer absent |
| 5 | §6d condvars and barriers | Now unblocked: the timed lock calls take a timeout |
| 6 | §7 census cannot detect a lying platform | Presence is self-reported |
| 7 | §6c thread-churn threshold | Knob exists; needs ~20 runs per point |
| 8 | §10 census expansion | Deliberately last. See above |