Skip to content

Run phases ​

A run has four stages, in this order: the pinned examples, the regression corpus replay, the random phase, and the shrink descent. They are a set, not a fixed sequence — PropertyConfig takes the ones to perform:

php
use Rasuvaeff\PropertyTesting\Runner\Phase;
use Rasuvaeff\PropertyTesting\Runner\PropertyConfig;

new PropertyConfig(phases: [Phase::Examples, Phase::Corpus]);  // examples and corpus only
new PropertyConfig();                                          // every phase — the default

The first of those runs in seconds where the full set runs in minutes, and it serves two purposes. One is a pull-request gate that replays only what is already known to have failed, leaving the full random phase to a nightly job. The other is an honest measurement of a property with corpus replay off — which until now meant deleting the corpus directory, and so losing the corpus.

Rules ​

RuleBehaviour
An empty phase setInvalidArgumentException: a run with no stages has nothing to report
A set without Phase::ShrinkExactly ShrinkMode::Off — one behaviour, one implementation, and the stricter of the two knobs always wins
Phase::CorpusGates corpus replay only. Both it and PropertyDefinition::$replayRegressions must allow the replay, and neither stops a fresh falsification from being recorded: storing is not a stage
A set without Phase::RandomNothing is generated: attempts: 0, checks: 0, and Passed once the enabled earlier phases pass
A phase set holding anything but a PhaseInvalidArgumentException: an unrecognised stage would simply not run, and the property would report green having checked nothing

That second-to-last row is the one to read twice. With no random phase the statistics report zeros rather than the configured run count, and coverage requirements are dropped instead of being assessed against an empty denominator — a Classify::cover() gate cannot be satisfied by runs that never happened, and failing on that would make the fast gate unusable on any property that has one. Passed is the result of the phases that did run, not a shortcut around them: a pinned example or a corpus entry that fails still reports ExampleFailed or RegressionFailed, exactly as it would in a full run.

Where to set it ​

These are engine-level knobs on PropertyConfig, available to any caller that builds a PropertyDefinition itself — see the standalone runner — and exposed by both adapters: #[Property(phases: [Phase::Examples, Phase::Corpus])] under Testo, ->phases(Phase::Examples, Phase::Corpus) under PHPUnit, and PROPERTY_PHASES from the command line for either (see Environment overrides).