Negative testing
Negative scenarios (crates/negative, pack negative) prove that inputs
which must be rejected are rejected, with the rejection classified and
the expected outcome explicitly declared — never assumed.
What is covered (CT-NEG-001..011)
- Invalid proof — corrupted, invalid-fixture, malformed, and tampered proofs must fail verification with the right classification.
- Wrong public inputs / ownership — a proof bound to the wrong sender/recipient/token is refused; an operation by the wrong owner fails authorization.
- Insufficient balance / invalid amount — overdrafts and invalid amounts are refused with a classified state failure.
- Stale state — an operation against already-consumed or stale state is refused.
- Replay / unauthorized / frozen — replayed operations, unauthorized actors, and frozen accounts are refused.
- Invalid commitments — operations referencing a malformed or inconsistent commitment are refused.
Declared outcomes
Every negative scenario declares the failure it expects
(DeclaredOutcome::Fails(FailureCategory::…)). A run passes only when the
system fails exactly as declared: a negative scenario that succeeds
is an unexpected acceptance and fails the gate. This is what makes the
negative pack a real gate rather than a collection of “this errors”
assertions.
Classification
Rejections carry a stable category — EXPECTED_REJECTION,
VERIFICATION_FAILURE, STATE_FAILURE, AUTHORIZATION_FAILURE,
INSUFFICIENT_BALANCE — surfaced in outcomes, reports, and CI. The mock
harness reports a refused operation as an outcome, never as a panic, so
the expected-vs-actual comparison is structural.
Boundaries
The scenarios orchestrate operations and assert on classified outcomes. They implement no protocol logic themselves — a rejection reason comes from the adapter double’s deterministic semantics, and the expectation comes from the declared input, never from asking the surface under test.