D266 - Three checks staged for the next hardware run: the layout of a memory type, whether a short size bounds a write, and more export candidates

The console is available again, so three measurements go on the wire now rather than waiting for the run after. Each is the confirmation half of a question a prior run left as a hypothesis, and each earns a check only because its verdict is decidable from behaviour alone.

139-exports gains six candidates. The section confirmed two vaddrs (getpid, sceKernelWrite) by calling base + vaddr and checking the function behaved (D264). The same move settles any export with a behavioural signature a wrong address is overwhelmingly unlikely to satisfy, so the table now carries eight: four id calls (getuid/geteuid/getgid/getppid, STABLE_ID - the same non-negative value twice), the counter frequency (sceKernelGetTscFrequency, TSC_FREQ - returns exactly 0x5f259b8e, the number three other measurements already agree on), and a monotonic clock (sceKernelGetProcessTime, ADVANCES - the second reading no earlier than the first). The frequency candidate is the strong one: a function answering that precise value and taking no argument is that call and almost nothing else, so a match confirms both the vaddr and, a fourth time, the frequency. A candidate's vaddr source still carries no weight; only the verdict is reported.

130-layout/memory-type asks what the third field of a direct-memory record is. The query record is (start, end, then a third word), and on hardware that word read 3 - the value of SCE_KERNEL_WB_GARLIC. So the check allocates a 16 KiB span of each of the three memory types in turn, queries it, and reads the third word: if it equals the type asked for across all three, the field is the type; if it is constant, the field is state and the 3 was a coincidence of that run; if it varies but does not track, it is neither. The verdict distinguishes the three rather than asserting the appealing one. Provenance assumed - it records bytes and names which hypothesis they support, it does not claim a layout.

130-layout/short-buffer-overrun asks whether a short declared size bounds the write. The size ladder proved every size 1-256 is accepted (the size is not validated), but acceptance is not the same as truncation: a call may ignore the size and write the whole record anyway, which corrupts a small-buffer caller. So the check poisons the buffer past a short declared size (8, 16, 24, 32) but inside it, calls, and sees whether anything past the size changed. It is the per-declared-size sibling of the ladder's tail guard - that catches a write past the whole 256-byte buffer, this catches a write past the 8 bytes the caller claimed. GetModuleInfo already carries the same guard-word test (110-modules/info-size); this closes the equivalent gap on the query. Provenance derived, like the ladder: the platform draws the boundary, the check records where it fell.

120-measure/clocks-advance also now emits each clock's absolute reading beside its busy delta - a clock's origin is a fact a later run wants and the delta discarded.

All four are green under make host (memory-type reads a constant on the stub, so it correctly reports "state, not the type"; short-buffer-overrun bounds at 24/32 and refuses 8/16; 139-exports skips with no libkernel base, as designed). guards, caps and counts pass at 171 checks across 36 sections. Status: done, awaiting the hardware run.

Hardware result (2026-08-31). 139-exports confirmed seven of eight on the payload run (getpid, sceKernelWrite, getuid, geteuid, getgid, getppid, sceKernelGetProcessTime) and refuted sceKernelGetTscFrequency at 0x1cf30 - the offset is wrong for that function. The other three skipped: the elfldr payload reaches libkernel by base + vaddr (so 139-exports runs) but resolves only a minimal import set, and memory-type / short-buffer-overrun / clocks-advance call resolved imports. They need an eboot run, or a base + vaddr rewrite. See WORKLOG 2026-08-31.