2 Commits

Author SHA1 Message Date
4957497d02 A mutation run found the four-byte overlong nobody was testing
Relaxing 0xf0's second-byte floor from 0x90 to 0x80 left the whole suite
green: every other row of the table had a case pinning it and that one did
not, so f0 80 80 af decoded happily as "/". The same smuggled slash the
two- and three-byte cases exist to catch, missed in the fourth width.

Seven mutations verified red after this: the lead-byte floor at 0xc2 and the
second-byte bounds on 0xe0, 0xed, 0xf0 and 0xf4, the truncated-sequence
width, and the split cursor dropping its trailing empty field. An eighth,
lower-ascii written as a bit-xor, is red on the bytes either side of the
letters — which is why those are in the table and the letters alone are not.
2026-09-12 03:56:40 +07:00
273dd18eb0 The valid decodes prove almost nothing; the malformed ones are the test
A decoder that only masks and shifts gets every well-formed character right,
so a corpus of real text passes it. What separates it from a correct one is
the second group here: an overlong two- and three-byte "/", a surrogate, a
code point past U+10FFFF, a lead byte that leads nothing, a lone continuation
byte, and a character truncated by the end of its slice. Each isolates one row
of the accept_sizes table, and each must answer width 1 so a scan advances.

The invalid sequences are byte arrays because no valid string contains them
and the reader has no \xNN escape to spell them with.

Encoding is checked by round trip. An encoder and a decoder wrong in the same
direction agree with each other, and expected bytes would not catch that.

The emoji line caught a use-after-return while this was being written: a
(defn whole [a [4 u8]] [u8] (slice a 0 4)) helper returns a slice into the
copy a [n T] parameter makes in the callee's frame. The compiler accepts it in
silence. The comment stays where the helper was.
2026-09-12 03:53:18 +07:00