Add power Doppler seed energy schedule (--schedule doppler) - #45
Conversation
Slow time = mutants of one seed; pixel = edge; sample = log2(1+hits). Mean removal + SVD wall filter (participation ratio drops path-wide "flash" components), CFAR chi^2 detection, flow power -> [0,1] energy, scaled to [1, max_mult] like katz. Bounded LRU ensembles; Gram eigendecomposition instead of full SVD (~6x faster close). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019AERo9TJciJNQMw2uc18qM
Reviewer's GuideIntroduces a SHM-coverage-based power Doppler signal that aggregates mutant ensembles per seed, filters static/coherent coverage, detects input-sensitive flow, and converts it into a bounded mutation-energy multiplier exposed through --schedule doppler; documentation, architecture diagrams, and comprehensive unit/integration tests are included. Sequence diagram for the Doppler seed-energy feedback loopsequenceDiagram
participant Fuzzer
participant SHM as SHMcoverage
participant Doppler as PowerDoppler
participant Scorer as SeedScorer
Fuzzer->>SHM: get_edge_counts()
SHM-->>Fuzzer: hit counts per edge
Fuzzer->>Doppler: observe(seed_key, hits)
Doppler->>Doppler: doppler_power(ensemble)
Doppler-->>Fuzzer: energy(seed_key)
Fuzzer->>Scorer: score(doppler_energy)
Scorer-->>Fuzzer: mutation energy multiplier
Flow diagram for power Doppler energy computationflowchart LR
A["Mutant executions for one seed"] --> B["X[n,e] = log2(1 + SHM hits)"]
B --> C["Remove per-edge mean"]
C --> D["Gram eigendecomposition"]
D --> E["Drop coherent flash components"]
E --> F["CFAR chi-squared flow detection"]
F --> G["Sum residual flow power"]
G --> H["Log-normalize energy to 0..1"]
H --> I["Scale SeedScorer energy to 1..max_mult"]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019AERo9TJciJNQMw2uc18qM
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Multi-target correctness, empty-sample handling, cache behavior, and memory usage must be addressed.
Review effort: Balanced
Findings: 1
Open (6)
Namespace multi-target edge observations by target · New Prevent LRU eviction from blocking frame completion · New Bound retained edge memberships to control memory use · New Reject or disable Doppler without SHM availability · New Fail integration tests on unexpected compiler errors · New Regenerate the missing architecture PNG · New
What changed in this PR
Adds a coverage-driven Doppler seed-energy schedule using mutant hit-count ensembles.
Changes:
- Implements Doppler filtering, CFAR scoring, and bounded caches.
- Wires scoring into SHM execution, scheduling, CLI, and tests.
- Updates user, architecture, and release documentation.
| File | Description |
|---|---|
src/fuzzer_tool/core/power_doppler.py |
Implements Doppler analysis and caching. |
src/fuzzer_tool/core/schedules.py |
Applies Doppler energy to seed scores. |
src/fuzzer_tool/services/fuzzer.py |
Collects samples and reads seed energy. |
src/fuzzer_tool/cli/commands.py |
Adds the CLI schedule option. |
tests/test_power_doppler.py |
Adds algorithm and integration tests. |
README.md |
Lists the schedule. |
CHANGELOG.md |
Records the feature. |
docs/DEEP_DIVE.md |
Documents algorithm and behavior. |
docs/TODO.md |
Tracks benchmarking work. |
docs/architecture.dot |
Adds Doppler to the architecture source. |
docs/images/architecture.svg |
Regenerates the SVG diagram. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| and not is_crash | ||
| and not is_timeout | ||
| ): | ||
| self._doppler.observe(self._seed_key(data), scanned_shm.get_edge_counts()) |
| self._open: LRUCache = LRUCache(max_seeds) | ||
| self._scores: LRUCache = LRUCache(max_scores, on_evict=self._evicted) |
| old = self._scores.get(seed_key) | ||
| if old is not None and old[0] >= self._max_power: | ||
| self._max_stale = True | ||
| self._scores[seed_key] = (power, frozenset(ens.ids[: ens.m][flow].tolist())) |
| if schedule == "doppler": | ||
| from fuzzer_tool.core.power_doppler import PowerDoppler | ||
|
|
||
| self._doppler = PowerDoppler() |
| if r.returncode != 0: | ||
| pytest.skip(f"driver failed to build: {r.stderr[:300]}") |
| label="1 · Scheduling — what to fuzz next"; | ||
| color="#bcd0c4"; fillcolor="#f2f8f4"; fontcolor="#33604a"; | ||
| picker [label="services/seed_picker.py + core/schedules.py\lweights · Pareto front · crowding · saturation gate\lFAST COE RARE MMOPT LIN QUAD GO AFLGO ENTROPIC KATZ\lKRUSKAL-COUNT (coupling walkers · recombination)\l", | ||
| picker [label="services/seed_picker.py + core/schedules.py\lweights · Pareto front · crowding · saturation gate\lFAST COE RARE MMOPT LIN QUAD GO AFLGO ENTROPIC KATZ DOPPLER\lKRUSKAL-COUNT (coupling walkers · recombination)\l", |



Power Doppler on coverage: slow time = mutants of one seed, pixel = edge, sample =
log2(1+hits).core/power_doppler.py:doppler_power()+PowerDoppler(LRU-bounded ensembles, ≤16 MiB). Gram eigendecomposition replaces full SVD (~6× faster close).SeedScorerdopplerschedule: energy →[1, max_mult], same clamp askatz.fuzz_onefeeds SHM hit counts per execution (zero cost when off); pick path reads energy; CLI choice; enabled-features list.Tests:
tests/test_power_doppler.py— falsification (static ensemble/seed → no energy), adversarial (flash is clutter; flow survives flash; out-of-range energy clamped), Gram-vs-LAPACK equivalence, memory caps, end-to-end loop wiring (clang).Cost: ~100 µs/exec at 2k live edges, mostly
get_edge_counts()dict → numpy. Unmeasured on fuzzgoat.🤖 Generated with Claude Code
https://claude.ai/code/session_019AERo9TJciJNQMw2uc18qM
Generated by Claude Code
Summary by Sourcery
Add a coverage-driven Power Doppler schedule that prioritizes seeds whose mutants produce localized, input-sensitive edge movement.
New Features:
--schedule dopplerpower schedule to derive seed mutation energy from input-sensitive coverage changes across mutant ensembles.Enhancements:
Documentation:
Tests: