Context
Surfaced during the #80 review (PR #99). Pre-existing behavior from #45 — affects both the deep-fuzz (libFuzzer) and deep-fuzz-afl (AFL++/CMPLOG) jobs in .github/workflows/fuzz.yml.
Problem
Each job's corpus-restore step resolves the previous corpus from the last successful whole workflow run:
run_id="$(gh run list --workflow fuzz.yml --branch main --status success --limit 1 --json databaseId --jq '.[0].databaseId // empty' ...)"
--status success reflects the aggregate conclusion of the entire matrixed run (both jobs × all targets). So if any single target in either job crashes (or the CMPLOG-confirm step fails, or a flake), the whole run is marked non-success — and the next night every target of every job fails to find a prior corpus artifact and reseeds from scratch (committed seeds + 1-byte fallback only).
Net effect: a single crash anywhere throws away the accumulated corpus for all targets on the following night. Corpus accumulation — the entire point of persisting artifacts night over night — is fragile to one unrelated failure.
Why it matters
Comparison-coverage fuzzing (value-profile + CMPLOG) depends on compounding corpus growth to reach deep parse states. A whole-fleet reseed erases that progress and wastes the runner budget re-discovering known-shallow inputs.
Possible fixes (not yet decided)
- Resolve the run id per artifact existence rather than per-run success — e.g. find the most recent run (any conclusion) that actually uploaded
corpus-<engine>-<target>, or query the artifacts API directly for the latest artifact of that name on main.
- Or upload corpus on
if: always() (like the AFL crash step) so a crashing target still persists its grown corpus for the next night, decoupling persistence from run success.
- Consider
retention-days interplay so a transient gap doesn't lose the artifact entirely.
Acceptance
- A single target's crash/failure no longer starves the other targets' corpus restore on the following night.
- Corpus continues to compound per-target across nights independent of unrelated failures.
Pointers
Context
Surfaced during the #80 review (PR #99). Pre-existing behavior from #45 — affects both the
deep-fuzz(libFuzzer) anddeep-fuzz-afl(AFL++/CMPLOG) jobs in.github/workflows/fuzz.yml.Problem
Each job's corpus-restore step resolves the previous corpus from the last successful whole workflow run:
run_id="$(gh run list --workflow fuzz.yml --branch main --status success --limit 1 --json databaseId --jq '.[0].databaseId // empty' ...)"--status successreflects the aggregate conclusion of the entire matrixed run (both jobs × all targets). So if any single target in either job crashes (or the CMPLOG-confirm step fails, or a flake), the whole run is marked non-success — and the next night every target of every job fails to find a prior corpus artifact and reseeds from scratch (committed seeds + 1-byte fallback only).Net effect: a single crash anywhere throws away the accumulated corpus for all targets on the following night. Corpus accumulation — the entire point of persisting artifacts night over night — is fragile to one unrelated failure.
Why it matters
Comparison-coverage fuzzing (value-profile + CMPLOG) depends on compounding corpus growth to reach deep parse states. A whole-fleet reseed erases that progress and wastes the runner budget re-discovering known-shallow inputs.
Possible fixes (not yet decided)
corpus-<engine>-<target>, or query the artifacts API directly for the latest artifact of that name onmain.if: always()(like the AFL crash step) so a crashing target still persists its grown corpus for the next night, decoupling persistence from run success.retention-daysinterplay so a transient gap doesn't lose the artifact entirely.Acceptance
Pointers
.github/workflows/fuzz.yml—Restore previous corpus(deep-fuzz) andRestore shared corpus (seed dir)(deep-fuzz-afl).