D181 - A run records what it was subject to, so a verdict can be evidence
decided ยท 2026-08-21
The loop rests on one inference: run, change one thing, run again,
attribute the difference to the change. That is valid only if everything
else was identical, and nothing recorded whether it was.
compare() rendered FURTHER or
BACK from two traces that might have been produced under
completely different settings, and could not tell.
Two settings break it, both one line of TOML away.
The wall-clock limit measures the host
--limit is in seconds, so the same build on the same
title reaches further on a faster machine. Locally that is a slow leak;
the moment results are shared - a contributed compatibility entry, a
second contributor reproducing a finding - two people comparing runs are
comparing their hardware and nothing warns them.
The stub policy is a reward hack one line wide
default_return = "ok" makes every unimplemented function
claim success. The guest stops checking, runs on, reaches imports it
never reached before, and dies much later. Every number improves
and nothing has been implemented - and worse, the guest is now
running on placeholder answers, so where it eventually dies means
nothing.
It is the highest-scoring single change available to anything steering by a call count, so an unattended loop finds it within a few iterations. Not from malice: it has no concept of cheating, only of cheapest-change-with-biggest-effect.
Recorded rather than forbidden. Answering
ok everywhere is a legitimate bisection technique and
principle 5 exists to keep exactly that loop cheap. What makes it a hack
is doing it unlabelled, so the label is the fix.
Two numbers, never one
Conditions rides on the trace - limit, default stub
answer, override count, build - and compare() reports what
changed underneath a verdict rather than refusing to render one. The
numbers are real; they just are not evidence about the emulator. The
build is recorded and deliberately not compared,
because it changes on every release and would fire constantly, drowning
the two that matter.
Alongside it, every run now prints what it stands on: how many of its calls reached an implementation rather than a placeholder. A call count is progress only to the extent the calls were answered by something real, and reporting the total alone lets the two be confused in the direction that flatters.
It was demonstrated, not argued
Against PPSA28061, unchanged except for that one line:
imports 47 distinct (+0), 933 calls (+0) -> 48 distinct (+1), 935 calls (+2)
verdict same nothing moved -> FURTHER reached imports it could not reach before
! unimplemented functions now answer ok instead of unimplemented,
so this verdict measures a settings change
The hack works. It is now impossible to read the result without being told so.