Define what failure means first

A reproduction needs an observable success or failure criterion. “The program behaves strangely” is not enough to tell whether a reduction still preserves the bug. State whether a particular input produces the wrong sum, repeated work crashes, or an operation exceeds a meaningful time limit. Record the expected and actual outcomes together. A debugger address alone is a weak criterion because builds and runs can change it. Prefer input conditions and behavior that another person can compare.

Reduce one kind of condition at a time

Remove part of an input or simplify a code path without simultaneously changing compiler flags and the environment. Otherwise a disappearing failure has too many explanations. Keep the last version that still fails. Removing half an input, testing, and restoring as necessary can narrow the relevant portion efficiently. For intermittent failures, a single successful run is weak evidence; compare against the original frequency and observation period. Reduction is an experiment and needs the same care as other debugging observations.

Treat the environment as part of the case

The same source and input can behave differently across operating systems, architectures, optimization settings, working directories, or environment variables. Lifetime and scheduling failures are particularly sensitive to layout and timing changes introduced by simplification. If the reduced program no longer fails, record the last removed condition and restore relevant pieces individually. An apparently unrelated initialization or file operation may affect allocation or execution order. Keep hypotheses separate from confirmed observations so the record does not turn an untested explanation into a fact.

Make the case usable elsewhere

Include build and run commands, arguments, required file layout, and expected and actual results. Replace private paths and confidential data with shareable examples, then verify that the same failure remains. Explain where to stop and what to inspect if a debugger is needed. After a fix, run both the reduced case and the original failing workload. Passing the smaller case does not automatically establish that the full task is corrected. Preserve it as a check of the explanation and future changes.

Keep a short experiment log

Three lines per attempt are enough: what changed, how it ran, and whether the failure remained. Note repetitions for intermittent problems and keep the latest failing version. Shorter code is not the final objective. The objective is a precise set of conditions under which another person can observe the same discrepancy.