Files
transcience/tests
claudeandClaude Opus 5 20715e77cc Make the two hot decoders as careful as the six cold ones
Every colder message here checks get_available_bytes() before it reads,
and has a test named for it. Snapshots and events -- twenty and sixty
times a second, the two that actually matter -- did neither.

A snapshot's counts are a u8 and two u16s read straight off the wire and
then looped without a bounds check. A garbage enemy count is up to 65535
dictionaries built out of an empty buffer, and a garbage tick is fed
directly to the client's clock estimate and its input-lead resync. The
channel is unreliable and ENet's checksum is off, so a short snapshot is
a network event, not only an attack. It now answers valid:false and the
client drops it -- one dropped snapshot costs 50ms of interpolation.

Events were worse in kind. The decoder read a type byte and matched on
it, so a type it did not recognise consumed one byte and carried on,
reading every field after it at the wrong offset: one stray byte became a
stream of bullets spawned at invented positions, which the client then
applied. Lengths are now declared up front and an unknown type stops the
stream. The prefix is kept, because the channel is reliable and ordered
and throwing the packet away would strand every despawn in it.

Both size tables are pinned to their encoders by tests that encode one of
each record and compare, so they cannot drift -- and a new SimEvent.Type
with no declared length fails a test rather than shipping.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 17:14:14 +02:00
..