v0.9: exploration metrics in the live status UI - #2
Merged
Conversation
StatusReporter grows an exploration panel (execs/sec, corpus size, finds by classification crash/invariant, time-since-last-find) once finds arrive, in both the TTY box and the piped one-line summary. Counters are fed from the triage layer (FuzzIO.recordSaved on every saved input), so they cover the JQF path and corpus replay alike. Wiring: the JQF harness now starts the StatusReporter render thread (it only started TriageSink before), the calculator fuzz task forwards -Dclosurejvm.status* into the fuzz JVM, CorpusRunner starts the reporter, and a shutdown-hook final frame guarantees a closing tally for any run type (JQF/corpus/generic), not just the runners that call renderFinal(). Verified with a live JQF calculator campaign: the exploration panel renders with execs=105 (36.9/s), corpus=102, crash finds climbing, last-find timer. Demo: docs/demo-explore.svg (animated, 16 real frames) shows the panel materializing as finds arrive; embedded in a new README Exploration section. Roadmap: v0.9 (exploration+UI) and v0.10.0 (coverage-guided over HTTP via a server-side coverage agent, Kubernetes deploy, auto-injection admission webhook, and a web dashboard — some likely a separate repo) added to TODO.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018kqCb2ZpmgPcLhjLo5ZbNx
… row Two issues surfaced in review of the v0.9 exploration panel: 1. Top 'crashes' counter disagreed with exploration 'finds crash' because they were fed from different paths — recordCrash() was only wired into GenericRunner, while the crash-find count came from FuzzIO in the JQF/corpus paths. Now a crash is counted wherever executeIteration() throws (JQF harness + preseed, CorpusRunner), matching GenericRunner. A leak/invariant thrown by endIteration is still counted separately, not as a crash. Verified: JQF calculator run now shows crashes=102 == finds crash=102. 2. No coverage percentage. Added StatusReporter.recordCoverage(covered, total) and a 'coverage X.X% (covered/total edges)' panel row (TTY + piped), shown once a source reports. A true % needs a covered/total denominator from instrumenting the code under test, so the source is the v0.10 server-side coverage agent (or an optional in-process JaCoCo provider) — the plumbing is in place now. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018kqCb2ZpmgPcLhjLo5ZbNx
Regenerate docs/demo-explore.svg (17 real frames) showing the consistent crash counting (top crashes == exploration finds crash), and update the README Exploration section to describe the coverage % row and the crash-counter consistency. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018kqCb2ZpmgPcLhjLo5ZbNx
…sifier) The crash count was a fuzzing false positive: every exception from a target counted as a crash, so a parser rejecting malformed input (IllegalArgumentException 'bad char', IllegalStateException 'mismatched parenthesis') flooded the count. The calculator showed 102 'crashes' that were almost all normal input validation. Add optional runner.api.CrashClassifier: a target declares which exceptions are expected rejections. The runners (GenericRunner, CorpusRunner, JQF harness + preseed) now count expected exceptions as 'rejected' (not crashes, not saved to the crash corpus); in the JQF path an expected exception becomes an assumption violation so the fuzzer discards the input. CalculatorFuzzTarget declares IllegalArgumentException/IllegalStateException expected. Result on the same run: crashes 102 -> 1, rejected 12. The single remaining crash is a genuine NoSuchElementException (empty-stack pop on a truncated expression) — exactly the robustness bug worth surfacing. StatusReporter gains a 'rejected' row. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018kqCb2ZpmgPcLhjLo5ZbNx
…ard findings + Claude analysis Regenerate docs/demo-explore.svg from a real HTTP-driven exploration run against JPetStore (220 execs, 0 crashes, 48 server-side invariant finds via the valve). Rewrite the README Exploration section around driving a real app over HTTP, the rejected-vs-crash distinction (CrashClassifier), and the runHttpDrive command. Roadmap: the v0.10 web dashboard should surface actual findings (crash detail, stacks, invariant violations, saved input, route/metrics — browse triage bundles, not just counts), and an optional Claude-API-backed analysis of findings/campaigns (cluster/dedupe, explain stacks, suggest root cause) with a server-side key. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018kqCb2ZpmgPcLhjLo5ZbNx
This was referenced Jul 20, 2026
This was referenced Jul 20, 2026
This was referenced Jul 20, 2026
This was referenced Jul 20, 2026
This was referenced Jul 21, 2026
This was referenced Jul 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes coverage-guided exploration visible: the live status screen grows an exploration panel as a fuzzing campaign runs.
Changes
StatusReporter: exploration panel (execs/sec, corpus size, finds by classification crash/invariant, time-since-last-find), shown once finds arrive, in both TTY box and piped one-line modes.FuzzIO.recordSavedon every saved input) — covers the JQF path and corpus replay.TriageSink); calculator fuzz task forwards-Dclosurejvm.status*;CorpusRunnerstarts the reporter; shutdown-hook final frame for all run types.docs/demo-explore.svg(16 real frames) + new README Exploration section.Validation
Live JQF calculator campaign renders the panel: execs=105 (36.9/s), corpus=102, crash finds climbing, last-find timer. Full
build+checkgreen on JDK 17.Scope
In-process JQF coverage guidance stays local here; feeding the app-under-test's coverage back over HTTP is v0.10 (the real "coverage-guided via HTTP requests" vision).
🤖 Generated with Claude Code