fix: catch a monotonic frame, closing the last gap in the structure check (#235) - #251
Merged
Merged
Conversation
…heck (#235) A flat gradient passed for Plasma. Edge density could not see it -- Plasma's baseline is 0.0001, so a drop to zero is smaller than the absolute margin -- and #229's spread check catches a UNIFORM frame, not a smooth ramp. To both of those statistics a gradient and a healthy Plasma frame are the same picture: near-zero edges, wide luminance spread. WHAT SEPARATES THEM A gradient is MONOTONIC. Its signed slope along a row never reverses; a real image, however smooth, reverses constantly. Measured across all 30 savers: healthy Plasma 0.5948 radial gradient 0.0586 (one reversal per row) linear ramp 0.0000 (none, by construction) Threshold 0.12: a 5.0x margin under the healthy value and 2x above the radial case. TWO STRIDES, AND THE MAX Falling Sand reads 0.5833 at stride 4 and 0.0000 at stride 16 -- its grains are finer than the coarse step, so one stride alone would call a sparse saver monotonic. Taking the max of strides 4 and 16 fixes that. GATED TO SUB-MARGIN SAVERS, WHICH IS PLASMA ALONE Not applied set-wide, and that is a deliberate limit rather than laziness. The lowest undulation among savers with a non-zero baseline is Julia Set at 0.1544, which clears 0.12 by only 1.3x. A set-wide floor would therefore sit within a third of a healthy saver -- the same thin margin that made the coarse-stride approach unshippable in #234, and no more acceptable here. VERIFIED BY FAULT INJECTION, NOT BY ELIMINATION Each case names the rule that fired: linear ramp fail=5 "frame is monotonic: undulation 0.0000 is below 0.12" radial gradient fail=5 "frame is monotonic: undulation 0.0586 is below 0.12" uniform grey fail=5 caught by the #229 spread rule, as intended clean ok=150 fail=0, Plasma undulation 0.5948 A SELF-INFLICTED ERROR WORTH RECORDING The first measurement read 0.0000 for all thirty savers, which looked like a finding and was a bug: the block sat AFTER lums.sort(), and a sorted array is monotonic by definition. The file already warned about this for edge density. The computation is now before the sort, with a comment saying why it must be. AND A HARNESS BUG FOUND WHILE VERIFYING The failure reason never reached CI output. scripts/shader-check.mjs extracts console lines with a per-line regex against Chrome's INFO:CONSOLE(n] "..." format, so a MULTI-LINE message is dropped entirely -- its first line has no closing quote and the rest have no prefix. The FAIL log was multi-line, so every failed run has been printing "FAILING SAVERS: <name>" with no reason attached, and the reason could only be recovered by reading the page. Now emitted on one line. That bug is why this commit can say which rule caught which fault instead of inferring it.
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #235.
The gap
A flat gradient passed for Plasma. Edge density could not see it — Plasma's baseline is
0.0001, so a drop to zero is smaller than the absolute margin — and #229's spread check
catches a uniform frame, not a smooth ramp. To both of those statistics, a gradient and a
healthy Plasma frame are the same picture: near-zero edges, wide luminance spread.
What separates them
A gradient is monotonic. Its signed slope along a row never reverses; a real image, however
smooth, reverses constantly. Measured across all 30 savers:
UNDULATION_MIN = 0.12— a 5.0× margin under the healthy value and 2× above the radial case.Two strides, and the max of them. Falling Sand reads 0.5833 at stride 4 and 0.0000 at
stride 16 — its grains are finer than the coarse step — so one stride alone would call a sparse
saver monotonic.
Gated to sub-margin savers, which is Plasma alone
Not applied set-wide, and that is a deliberate limit. The lowest undulation among savers with a
non-zero baseline is Julia Set at 0.1544, which clears 0.12 by only 1.3×. A set-wide floor
would sit within a third of a healthy saver — the same thin margin that made the coarse-stride
approach unshippable in #234, and no more acceptable here.
Verified by fault injection, naming the rule each time
fail=5— "frame is monotonic: undulation 0.0000 is below 0.12"fail=5— "frame is monotonic: undulation 0.0586 is below 0.12"fail=5— caught by the #229 spread rule, as intendedok=150 fail=0, Plasma undulation 0.5948A self-inflicted error worth recording
My first measurement read 0.0000 for all thirty savers. That looked like a finding and was a
bug: the block sat after
lums.sort(), and a sorted array is monotonic by definition. The filealready warned about exactly this for edge density. It is now computed before the sort, with a
comment saying why it must be.
And a harness bug found while verifying
The failure reason never reached CI output.
scripts/shader-check.mjsextracts console lineswith a per-line regex against Chrome's
INFO:CONSOLE(n] "..."format, so a multi-line messageis dropped entirely — its first line has no closing quote and the rest have no prefix.
The
FAILlog was multi-line. So every failed run has printedFAILING SAVERS: <name>with noreason attached, and the reason could only be recovered by opening the page. Now emitted on one
line.
That bug is why this PR can state which rule caught which fault instead of inferring it by
elimination.
Verification
main(bf83e38).npm run lintclean.npm test— 416 passed (412 + 4 new).npm run shadercheck—ok=150 fail=0clean; three injected faults each caught by theintended rule.
Not verified / honest limits
be measured before this is trusted — Julia Set would clear the threshold by only 1.3×. The
constant says so, and a test asserts the gated set is what it is.
happens to produce reversals — say banded noise. This closes the monotonic case, which was the
measured gap, not every conceivable smooth failure.
smooth" — is now argued rather than merely assumed: undulation is a property of variation, not
of sharpness, and every one of the 30 savers scores above 0.15 while gradients score under 0.06.
It still has not been tested against a deliberate new smooth redesign, because there isn't one.