PropertyDamage.FailureReport (PropertyDamage v0.1.0)
View SourceRich failure report with comprehensive diagnostic information.
A FailureReport captures everything needed to understand, debug, and reproduce a test failure:
- Location: Which run, command index, and seed
- Sequences: Original and shrunk command sequences
- State: Projection states before and at failure
- Events: Complete event trail leading to failure
- Reason: Structured failure reason with context
Creating Reports
Reports are created automatically by PropertyDamage when a test fails. You can also create them manually for testing:
report = FailureReport.new(
seed: 12345,
run_number: 3,
original_sequence: sequence,
shrunk_sequence: shrunk,
failed_at_index: 5,
failure_reason: {:check_failed, :NonNegativeBalance, "..."}
)Formatting Reports
Use FailureReport.Formatter to render reports in different formats:
# Terminal output (default)
FailureReport.Formatter.format(report, :terminal)
# Markdown for documentation
FailureReport.Formatter.format(report, :markdown)
# JSON for CI integration
FailureReport.Formatter.format(report, :json)Failure Reasons
The failure_reason field contains structured data about what failed:
{:check_failed, check_name, message}- Invariant violation{:idempotency_violation, %Stutter.Violation{}}- Idempotency failure{:adapter_error, reason}- Adapter execution failed{:linearization_failed, message}- No valid linearization (parallel){:branch_failure, branch_id, reason}- Branch execution failed{:ref_resolution_error, reason}- Symbolic ref couldn't be resolved
Summary
Functions
Get a summary string for the failure type.
Convert from the legacy failure_report map format.
Check if this is an idempotency failure.
Create a new failure report from execution results.
Check if this is a parallel execution failure.
Get the reproduction command as a string.
Convert to the legacy failure_report map format.
Types
@type failure_type() ::
:check_failed
| :idempotency_violation
| :adapter_error
| :linearization_failed
| :branch_failure
| :ref_resolution_error
| :unknown
@type t() :: %PropertyDamage.FailureReport{ adapter: module() | nil, branch_events: %{required(non_neg_integer()) => [PropertyDamage.EventLog.Entry.t()]} | nil, branch_id: non_neg_integer() | nil, check_name: atom() | nil, command_at_failure: struct() | nil, event_log: [PropertyDamage.EventLog.Entry.t()], events_at_failure: [struct()], failed_at_index: non_neg_integer(), failure_message: String.t() | nil, failure_reason: term(), failure_type: failure_type(), idempotency_violation: map() | nil, linearization: [struct()] | nil, model: module() | nil, original_sequence: PropertyDamage.Sequence.t(), refs_at_failure: map() | nil, run_number: non_neg_integer(), seed: integer(), shrink_iterations: non_neg_integer(), shrink_time_ms: non_neg_integer(), shrunk_sequence: PropertyDamage.Sequence.t(), state_at_failure: %{required(atom()) => any()} | nil, state_before_failure: %{required(atom()) => any()} | nil, timestamp: DateTime.t() }
Functions
Get a summary string for the failure type.
Convert from the legacy failure_report map format.
This allows gradual migration from the old format.
Check if this is an idempotency failure.
Create a new failure report from execution results.
Options
Required:
:seed- Random seed for reproduction:run_number- Which test run failed:original_sequence- The sequence before shrinking:failed_at_index- Command index where failure occurred:failure_reason- Structured failure reason
Optional:
:shrunk_sequence- Minimized sequence (defaults to original):event_log- Complete event log:projections- Projection states at failure:projections_before- Projection states before failing command:refs- Ref resolution map at failure:shrink_iterations- Number of shrink attempts:shrink_time_ms- Time spent shrinking:model- Model module:adapter- Adapter module:linearization- Selected linearization (parallel)
Check if this is a parallel execution failure.
Get the reproduction command as a string.
Convert to the legacy failure_report map format.
For backwards compatibility with existing code.