Crash diagnosability + out-of-process coverage aggregation — v0.9.0 - #166
Merged
Conversation
A native crash (access violation in python.dll) killed the GUI process twice with zero diagnostic residue. faults.py arms faulthandler in the parent and every spawn child (via PYTEST_FLY_FAULTHANDLER), writes dumps to logs/faulthandler-<pid>.log, and report_previous_crashes() logs and archives non-empty dumps at startup. pytest's own faulthandler plugin is disabled in the test child so one file per PID stays authoritative. platform/wer.py reads the Windows Error Reporting LocalDumps state, builds the elevated configure/remove commands, and sweeps new *.dmp files at startup. New prefs: faulthandler_enabled, wer_*, coverage_* (UI wiring follows). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018j7yAH7CooFHFLEANWM5vM
Coverage.report() returns the total percentage for every output_format, so the total-only pass was a complete second parse of every PUT source file just to read a number the text pass already returns. Halves the cost of the step that was on the stack when the process died. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018j7yAH7CooFHFLEANWM5vM
CoverageAggregator (spawn child) runs calculate_coverage() out of the GUI process; aggregate_coverage() joins it with a timeout (coverage_timeout_seconds pref) and treats a crashed, killed, or hung child as a logged warning that keeps the last good values. CoverageTracker holds new completed-test sets for coverage_refresh_seconds (default 30) while the run is active and always does a final pass once nothing is running or queued. The Coverage tab's HTML report goes through the same child, polled from a timer so the GUI no longer blocks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018j7yAH7CooFHFLEANWM5vM
…ut fields — v0.9.0 Crash Diagnostics group (faulthandler checkbox; on Windows the WER LocalDumps status, folder/type/count, Configure (UAC) / Remove / Copy command buttons and a machine-wide caution). Coverage Refresh and Coverage Timeout fields next to Refresh Rate. Restore-defaults wiring, CLAUDE.md architecture notes, version 0.9.0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018j7yAH7CooFHFLEANWM5vM
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #166 +/- ##
==========================================
- Coverage 87.41% 86.14% -1.27%
==========================================
Files 71 74 +3
Lines 5759 6150 +391
==========================================
+ Hits 5034 5298 +264
- Misses 725 852 +127 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
Implements
crash_hardening_and_coverage_plan.md(motivated by the silent0xC0000005death of the GUI process on 2026-08-22, and once before under 0.7.3).What's in
faults.py): armed in the parent and every spawn child viaPYTEST_FLY_FAULTHANDLER; dumps to.pytest-fly/logs/faulthandler-<pid>.log.report_previous_crashes()logs + archives non-empty dumps at the next launch (Log tab,EVENT_EXTRA). pytest's own faulthandler plugin is disabled in the test child (plan option b). Preffaulthandler_enabled(default on).platform/wer.py+ Configuration tab "Crash Diagnostics" group): read-only status, dump folder/type/count prefs, Configure (UAC) / Remove / Copy command, machine-wide caution, startup sweep of new*.dmpfiles.cov.report()pass incalculate_coverage()(§4.2).coverage_aggregator.py):CoverageTrackerand the Coverage tab's HTML report runcalculate_coverage()in a spawn child with a timeout (coverage_timeout_seconds, default 300). A crashed/hung child is a warning; last good values stand; the run continues.coverage_refresh_seconds(default 30, 0 = every completion); final pass always runs once nothing is running/queued.Deliberately not done
Coverage.combine()replaces the combined data rather than merging into it (verified experimentally), so merging only new files would silently drop coverage.Tests: 486 passed locally, incl. a real segfaulting child (faulthandler end-to-end) and a dying/hung aggregator child.
🤖 Generated with Claude Code
https://claude.ai/code/session_018j7yAH7CooFHFLEANWM5vM