# Invariant audit: [feature]

Date: [YYYY-MM-DD]
Change under audit: [file paths + line ranges]
Trigger: [money path | auth/session | tenant boundary | state mutation | schema migration]
Auditor: [reviewer from CONTEXT.md; not the author of the change]

## 1. Abuse vectors (at least five for money-path or auth changes)

| # | Actor and access | Action | Outcome achieved |
|---|---|---|---|
| A1 | [e.g. logged-in user on the free plan] | [e.g. replays a checkout callback] | [e.g. gets paid credits twice] |
| A2 | | | |
| A3 | | | |
| A4 | | | |
| A5 | | | |

## 2. Invariant locks

Properties that hold for every tenant under every concurrent invocation.

| # | Invariant | Enforced by (constraint, lock, check) |
|---|---|---|
| I1 | [e.g. balance never goes negative] | [e.g. database check constraint + row lock] |
| I2 | [e.g. one idempotency key produces one ledger entry] | [e.g. unique index on the key] |
| I3 | [e.g. tenant A never reads tenant B] | |
| I4 | [e.g. a failed action never charges] | |

## 3. Cross-feature linkage

| Invariant | Other features touching the same state | Does this change break them? |
|---|---|---|
| I1 | | |

## 4. Property-based tests

Concrete properties for Hypothesis (Python) or fast-check (TypeScript/JavaScript). Properties, not examples.

- P1: for any sequence of charges and refunds, final balance equals the sum of ledger entries and is never below zero.
- P2: for any N concurrent requests sharing one idempotency key, exactly one ledger entry exists.
- P3: [your property]

## 5. Replay, concurrency and races

| Scenario | Expected behaviour | Tested? |
|---|---|---|
| Duplicate webhook delivery | | |
| N concurrent requests on one idempotency key | | |
| Job crashes mid-pipeline, then retries | | |

## 6. Failure modes

| Failure | Expected behaviour | Tested? |
|---|---|---|
| Database connection drops mid-transaction | | |
| Job timeout | | |
| Provider returns a server error | | |
| Cache evicted before retry | | |
| Key endpoint unreachable | | |
| Webhook signing credential rotated | | |

## 7. Counterfactual adversary pass

"As a valid user on plan [X], what is my highest-leverage attack right now?"

| Attack | Target invariant | Entry point | Chain | Status (blocked / partial / open) |
|---|---|---|---|---|
| | | | | |

## Verdict

- Open or partial vectors: [list; any entry here blocks the lock]
- Accepted residual risk: [vector, reason, who signed off, date]
- Lock allowed: [yes only when every vector is blocked or accepted in writing]
