AGENT SKILL

proptest-arbitrary-review

Use when reviewing changes to Arbitrary implementations, proptest strategy parameters, or property-test generators in the OMMX Rust SDK, including changes to what a default strategy generates.

License 许可
Apache-2.0
所属仓库
Jij-Inc/ommx
最近更新
2026-11-14
Stars
★ 55
Forks
3

01 前言 Front Matter

name
proptest-arbitrary-review
description
Use when reviewing changes to Arbitrary implementations, proptest strategy parameters, or property-test generators in the OMMX Rust SDK, including changes to what a default strategy generates.

03 SKILL.md 正文

Proptest Arbitrary Review

Use this skill when a diff touches an Arbitrary implementation, a *Parameters strategy type, or the space a generator samples from. The core question is always: which domain does each property test now quantify over, and is that the domain the property actually claims?

This complements domain-responsibility-review: that skill judges whether production code preserves invariants; this skill judges whether the test generators exercise those invariants honestly.

Default-Space Blast Radius

Changing what Default parameters or any::<T>() generate silently changes the quantification domain of every property test that uses the default.

  • Enumerate all call sites before judging the diff: grep -rn "T::arbitrary\|any::<T>" rust/ (and the parameter type name). Include non-test consumers: random_deterministic, examples, doc examples, and Python bindings that expose random generation.
  • Classify each site explicitly:
    • The property should hold on the new, broader space → keep the default. A site kept on the default is a claim that the property holds for the whole space; treat an unchanged site as a positive assertion, not as "untouched code".
    • The property has a precondition (format compatibility, algebraic restriction) → it must opt into a named subspace constructor.
  • Verify by execution, not by reading: check out the branch and run every affected proptest suite. Passing N generated cases is the only proof that the new default satisfies downstream expectations.

Named Subspaces Express Preconditions

  • Prefer intent-named constructors (v1_compatible(), mps_compatible_qcqp()) over ad-hoc field overrides at test sites. The test site should read as a statement of the property's precondition.
  • A named subspace constructor is a semantic claim. Require a test that fails if the claim breaks (e.g. v1_compatible must be pinned by a v1 round-trip proptest). An alias like v1_compatible() = regular_only() is acceptable only while such a pinning test exists, because the two spaces can drift apart when either evolves.

Coverage Honesty

Distinguish sampled dimensions from constant injected structure.

  • Structure that a generator injects deterministically (fixed IDs, fixed function bodies, fixed set sizes, constant metadata) covers each new dimension at exactly one point. That is smoke coverage, not domain coverage. Either sample the dimension from a strategy, or document the limitation in the generator's rustdoc so properties over the default space do not overclaim.
  • Check presence/absence combinations. A generator in which every optional feature is always present never tests feature-absent interactions; "always everything" is as narrow as "always nothing" in that dimension.
  • Injected constant structure never shrinks away, so minimal counterexamples carry it as noise. Weigh that cost when deciding whether the structure belongs in the default space or in a dedicated named space.
  • Non-emptiness assertions over deterministically injected structure verify the generator, not the domain. Such tests are generator-regression tests; name and comment them as such, and do not count them as evidence that a domain property holds.

Generated Data Validity

  • Generators must construct values through the owning validated constructor (e.g. Instance::builder()), so that every generated case re-checks the type's own invariants. Direct field assignment is acceptable only for fields whose documentation explicitly states they are validation-free.
  • Hand-rolled resource allocation inside a generator (fresh variable IDs, next constraint ID) must match the domain's own allocator semantics. Compare against the owner's allocation function (e.g. ConstraintCollection::unused_id considers active and inactive rows); prefer calling the domain allocator over re-implementing it.
  • When the generator mutates the value after build() (conversions, direct field writes), re-check which invariants that post-processing can bypass.

Review Checklist

  • Which property tests changed quantification domain because of this diff, including the ones the diff does not touch?
  • Does every site left on the default strategy genuinely claim its property over the broader space?
  • Does every named subspace have a pinning test that fails when its claim breaks?
  • Which generated dimensions are sampled and which are constant? Is constant structure documented as smoke coverage?
  • Does generation go through the owning constructor, and does any post-build() mutation bypass validation?
  • Were the affected proptest suites actually executed on the branch?

04 同仓库更多 Skills