wave-7 decomposition — seven fuzzing tasks: scaffold, parser exposure (§3.2 resolved as option b), three targets, campaigns + gate wiring, review gate
This commit is contained in:
1 parent
62cddade00
commit
67d1d7e34f
8 files changed
+685
-1
No files matched your search
@@ -0,0 +1,108 @@
|
||||
---
|
||||
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<i64, String>`),
|
||||
- Postgres: `alkstore-postgres`'s re-export (`Result<i64>` →
|
||||
`InvalidSpec`),
|
||||
- Mem: `alkstore-mem`'s re-export (`Result<i64>` → `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
|
||||
Reference in new issue
Block a user