D179 - Findings, because the consumer will not be a person

decided · 2026-08-21

Every diagnostic this project has was built for a specific bug and rendered as prose for someone reading a terminal: the ranked import list, the fault, the call tail, the stack conformance line, the read counts. Reading them takes a person who knows what each shape means, and that person is the bottleneck.

The stated end goal is an emulator that is loud and clever about what it dumps - one that debugs as it goes, and eventually proposes its own fixes. That consumer is not a person. It needs the same four things every time, as data: what is wrong, where, what evidence says so, and what would address it.

So a run now produces findings rather than output. Each carries a machine-routable kind, a subject, evidence taken from the trace, a suggested action, and a weight - ranked so that taking the top item is taking the one least likely to waste the reader's time.

Confidence is the load-bearing field

A confidently wrong suggestion is worse than no suggestion, because it gets acted on.

That is not a general worry, it is this project's own history. An entry convention that looked right for months. A stub policy that looked wired to something. A name sweep whose vocabulary could not contain the answer it was looking for. Each would have produced a confident, wrong finding, and an automated consumer would have acted on all three.

So nothing reports Certain unless the trace shows it rather than suggests it, and the rule is the one obSCEne already uses: a certain finding is a defect, a possible one is a conversation. Ranking is by confidence before weight - a heavy guess must never outrank a light certainty.

What it detects, and why these

gap why it is worth a category of its own
Unimplemented The clearest instruction there is: names a function, says how much the guest leaned on it, and the work is unambiguous
ErrorUsedAsPointer The most productive signal this project has - names the function that answered wrongly and proves the guest believed it
GuestGaveUp The guest reporting its own reason, which no other signal offers
Spinning Distinguishes "not progressing" from "failed", which look identical in a call count
Unnamed A naming job, not an implementation one - "implement libkernel::0xcedb…" is not an instruction anyone can follow
AbiViolation, ShortRead Contract failures that fault far from their cause

The placeholder match deliberately allows a small offset either side. A guest that treats an error code as a struct pointer reads a field through it, so the address that faults is the code plus or minus a little - matching the bare value would miss every case where the guest did anything with it (D125).

Unimplemented needed one new fact: whether a called import has a handler behind it. Without it a trace cannot tell "the guest used this and it worked" from "the guest used this and got a placeholder" - opposite conclusions drawn from the same line.

It reproduced a day's work in one pass

Pointed at the corpus, it independently classified all three failure shapes this session found by hand: the spin on sceKernelDirectMemoryQuery, the placeholder dereferenced by PPSA21564, and the deliberate abort in two others - with the error-reporting call that precedes the abort surfaced as its evidence.

Which is the point. Those took a day of manual reading; the run now says them itself.