--- id: fuzz-target-every-parse name: Fuzz target — `every_parse` (the three `@every` parsers, differential) status: pending depends_on: [fuzz-scaffold, fuzz-parser-exposure] scope: moderate risk: medium impact: component level: implementation tags: [wave-7, fuzzing] --- ## Description The §3.2 target: `every_parse` — the wave's load-bearing target, since the crate's own track record (the wave-6 gate's three edge-domain findings) lives exactly here. Drives the three per-engine `parse_every_interval` implementations **differentially** through the `fuzz-parser-exposure` surfaces, plus each engine's next-boundary arithmetic (`skip_forward`): - SQLite: `alkstore-sqlite`'s re-export (substrate-owned, `Result`), - Postgres: `alkstore-postgres`'s re-export (`Result` → `InvalidSpec`), - Mem: `alkstore-mem`'s re-export (`Result` → `InvalidSpec`). Input: arbitrary `&[u8]` → UTF-8-lossy `String`s (lossy is deliberate — the engines receive `&str`, always valid UTF-8; the generator still stresses the grammar's edge shapes). Invariants (§3.2, verbatim): - **no-panic on any string** (each parser, each boundary path); - **typed rejection**: every rejection is the parser's own typed error (`InvalidSpec` on pg/mem; the substrate's typed error under the engine's mapping on SQLite) — never a panic, never a silent `Ok` on a grammar-violating shape the authored tests already reject; - **three-way agreement**: the accept-set and the interval value are identical across the three parsers for every input. Error *identity* is NOT pinned equal (the substrate's `String` vs `InvalidSpec` is a known, typed asymmetry) — the differential pins the Ok/Err partition and the `Ok` value; - **overflow posture**: the boundary paths (`skip_forward` driven with adversarial `(next_fire_at, now, interval)` triples — the `i64::MAX` neighborhood, negative shapes, `d`-unit multiplier blowups) reject-or-saturate per each engine's pinned semantics, never wrap or panic — the wave-6 scheduler-register fix's invariant over the whole domain; - **the `n <= 0` and giant-`n` arms**: leading-zero forms, digit overflow at exactly `i64::MAX/86400`, positive-zero rejection. The register-path posture (parse → first-boundary `checked_add` → reject with `InvalidSpec`, the wave-6 alignment) is suite-pinned already; the target's optional `(a)`-companion leg may drive the public `schedule()` on the mem/SQLite factories for register-path seeds — optional, recorded if used. - **`fuzz_targets/every_parse.rs`** + **`shared/src/every_parse.rs`** (invariants + `#[cfg(test)]` replay), `[[bin]]` entry, `shared` manifest gains the three engine crates (path deps — stable-buildable, they already are). - **Seeds** via `gen_fuzz_seeds.py`'s `every_parse` function: every grammar-valid unit form (`s|m|h|d`), multi-digit and leading-zero forms, `@every 0s` / `@every -5s` shapes, the `i64::MAX`-neighborhood and `i64::MAX/86400` digit-overflow forms, `d`-multiplier blowups, whitespace/garbage/truncation shapes, non-grammar prefixes (`@once`, `@hourly`-adjacent strings). Corpus committed; gitignore negation. - **`fuzz/README.md`** targets-table row. Risk note: medium because the differential may surface a real three-way divergence (that is the target's purpose) — a finding is *success*, dispositioned per the campaign task's posture (fix inline or escalate), not a task failure. ## Acceptance Criteria - [ ] `fuzz_targets/every_parse.rs` + `shared/src/every_parse.rs` exist; `cargo fuzz build` builds the target - [ ] All five §3.2 invariant classes implemented and exercised by both the fuzz path and the replay module; the three-way agreement asserted on every input (fuzz) and every seed (replay) - [ ] Seed corpus committed, deterministic-generated, gitignore negation in place - [ ] `cargo test --manifest-path fuzz/shared/Cargo.toml` green; `shared` clippy/fmt gates green - [ ] Root workspace gates still green; substrate diff still empty - [ ] Any three-way divergence found during target development is recorded in Notes with its disposition (fixed / escalated), not silently absorbed ## References - docs/research/fuzzing.md §3.2 (target spec + the exposure decision this target consumes), §4, §7 - docs/architecture/decisions/009-queue-and-scheduler.md §2 (the `@every` grammar the three parsers implement) - docs/architecture/decisions/012-forked-substrate-design.md §2 (one-owner rule — why there are three parsers to differ) - tasks/review-wave-6.md (the wave-6 finding class this target generalizes; the register-overflow alignment) - tasks/fuzz-parser-exposure.md (the surfaces this target drives) ## Notes > To be filled by implementation agent ## Summary > To be filled on completion