You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
damage: files can be broken on purpose, and something has to refuse them
The tool answered questions about size and about name. It did not answer the
third question an upload validator asks - "does it open" - because every file
it wrote was well formed by definition.
A target now takes damage, as a list from the first day because composition is
a requirement rather than an extension:
damage: [zero-head]
damage: [{type: zero-head, bytes: 16}]
and on the command line --damage zero-head:bytes=16, repeatable and applied in
the order given. The file still comes out exactly the size asked for. The
manifest records what was done to it and says the file is expected to be
rejected.
zero-head is the one damage in this build. It was chosen because all twenty
four formats have a judge that refuses the result and because it does not
change the length, so it does not touch the size arithmetic.
Three things the architecture note said turned out to be wrong, and each
changed the design rather than only the prose.
A witness is not a property of the pair (format, damage). It is a function of
the format, the damage, the SIZE and the parameter VALUES. Measured:
truncate-half has witnesses at 20 kB and none at 4 B, and zeroing one byte has
20 witnesses of 24 where four bytes have all of them. That is why the bytes
parameter starts at 4 - the bound belongs to somebody else's reader, the same
rule the column ceiling followed.
"The comparison is free because we compute the checksum anyway" was false. The
write path computes ONE checksum, so before-and-after would cost a second
sha256 per file. The damage knows for free instead: zero-head has to read the
bytes before it overwrites them. So the damage answers whether it moved
anything, not the engine - and it answers per step, because two damages can
cancel out. Measured that this is reachable rather than theoretical: ico, avif
and jxl all begin with zero bytes.
The collision between an automatic expectation and one written in a recipe was
settled nowhere. It is now a refusal, and only for accept: reject is what
damage means, while sanitize and unspecified are both sensible questions about
a broken file.
Damage sits between the generator and the counter, which gives three things
without building them: the checksum describes the bytes on disk, the existing
size check counts the FINAL bytes, and progress counts what will really be
there.
Nineteen guards, nineteen mutations, all caught. The one worth naming is the
reverse of every other oracle guard here - it asks whether a judge REFUSES what
we wrote, and its control runs first, because without it the test passes for a
build whose judge refuses everything.
Three types moved state out rather than growing past the crowding band, and one
of them turned out to be a better shape anyway: SizeIsRange, SizeMin and SizeMax
were always one statement, so engine.Target and recipe.Target now carry a
SizeRange. That refactor invalidated six mutation entries and only staleness.py
said so - a pattern that no longer matches reports SKIP, which reads as proven.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
0 commit comments