PropertyDamage.FailureReport (PropertyDamage v0.1.0)

View Source

Rich 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

failure_type()

@type failure_type() ::
  :check_failed
  | :idempotency_violation
  | :adapter_error
  | :linearization_failed
  | :branch_failure
  | :ref_resolution_error
  | :unknown

t()

@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

failure_type_summary(failure_report)

@spec failure_type_summary(t()) :: String.t()

Get a summary string for the failure type.

from_legacy(legacy_report, opts \\ [])

@spec from_legacy(
  map(),
  keyword()
) :: t()

Convert from the legacy failure_report map format.

This allows gradual migration from the old format.

idempotency_failure?(arg1)

@spec idempotency_failure?(t()) :: boolean()

Check if this is an idempotency failure.

new(opts)

@spec new(keyword()) :: t()

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)

parallel_failure?(failure_report)

@spec parallel_failure?(t()) :: boolean()

Check if this is a parallel execution failure.

reproduction_command(failure_report)

@spec reproduction_command(t()) :: String.t()

Get the reproduction command as a string.

to_legacy(report)

@spec to_legacy(t()) :: map()

Convert to the legacy failure_report map format.

For backwards compatibility with existing code.