# Seed corpora Hand-written and captured starting inputs, one directory per fuzz target. These are committed; `corpus/` is not. The split follows `astra-soak-overview`, which calls a minimized corpus "accumulated compute, not a build artifact": - **These seeds are human intent.** Most are real terminal traffic, captured under `script(1)` from the twelve vtebench benchmarks and from eight ordinary programs (`ls --color -R`, `top -b`, a coloured `git log --graph`, helix, nano, btop, less, tmux), sliced at escape boundaries. The rest is one file per protocol shape worth reaching in the first second rather than the first hour: each string state, the scroll region, the alt screen, wide characters at the right edge, truncated UTF-8, and the queries a program waits on an answer for. - **`corpus/` is machine output and lives on astra**, under the soak runner's persistent directory. Minimize with `cargo +nightly fuzz cmin vt` and commit it once it represents real soak hours, not before. ## Input format The first two bytes of every input choose the grid: `1 + b[0] % 200` columns and `1 + b[1] % 60` rows. Everything after them is the byte stream. The captured seeds carry a 100x30 header, so they are a capture with two bytes in front rather than a different format. One seed picks a 1x1 grid, which is the degenerate case every piece of the ring arithmetic has to survive. Run against these on a machine with no corpus: mkdir -p fuzz/corpus/vt cargo +nightly fuzz run vt fuzz/corpus/vt fuzz/seeds/vt The `mkdir` is needed once. `cargo fuzz` creates the default corpus directory for you only when you name no directories at all; pass them explicitly and libFuzzer requires every one to exist already. **Name the corpus directory first and this one second.** libFuzzer writes new inputs into whichever directory it is given first and treats the rest as read-only. Passing `fuzz/seeds/vt` alone dumps thousands of machine-generated files in here and buries the hand-written ones, which is exactly the split this directory exists to keep. ## Crash seeds An input that once found a bug stays here forever, and also becomes a file under `fuzz/regressions/`, which `tests/regressions.rs` replays on stable. - `63-decstbm-inverted`. `ESC [ 20 ; 3 r` sets a scroll region whose top is below its bottom, and `scroll_up_in_region` computes `bottom - top + 1`: an underflow, so a panic in debug and a region of about 65,000 rows in release, feeding a row index off the end of the ring into the unchecked store in `place_char`. - `104-delete-lines-whole-region`. `ESC [ 9999 M` on the top row of the region. DL clamps its count to the region size, and a copy loop that computes `scroll_bottom - n` underflows once the delete covers the whole region from its first row. - `106-pad-then-narrow-write`. A wide character with one column left leaves a pad at the right edge. Reading that pad as the second half of a pair makes a narrow write over it blank the cell two columns back, which is a real spacer, leaving its lead on screen as half a character. No panic, so only the wide-pair invariant catches it.