← ClaudeAtlas

padosoft-atomic-invariantslisted

Use this skill whenever code enforces something that must hold only once or only so many times — a single-use code or coupon, a nonce, a rate or quota limit, "the first one wins", a stock reservation, an idempotency key, a state transition that must happen once — and whenever the user reports that two requests both succeeded where one should have failed, a coupon was redeemed twice, a job ran twice, or a counter drifted under load. It checks that the read and the write of the invariant live in one atomic step and that a constraint backs the rule where it matters. Do not use it for general transaction design, for retry policy, or for distributed consensus.
padosoft/skills · ★ 1 · AI & Automation · score 80
Install: claude install-skill padosoft/skills
# Atomic invariants **Either the invariant is recorded in the same atomic step that checked it, or the invariant does not exist.** Everything else — a check a few lines above the write, a lock released before the update, a "nobody clicks twice" assumption — is a race that shows up under exactly the conditions you care about: a retry, a double tap, a load spike, two workers on the same queue. --- ## 1. The shape of the bug ```php // ❌ two requests both read "not used yet" and both proceed $coupon = Coupon::whereCode($code)->firstOrFail(); abort_if($coupon->used_at !== null, 409); $coupon->update(['used_at' => now()]); ``` The gap between the read and the write is where the second request fits. It does not need to be wide: two requests arriving in the same millisecond is the normal case for a double tap on a phone, a retried mobile request, or two queue workers. ```php // ✅ read and write in the same transaction, with the row locked DB::transaction(function () use ($code) { $coupon = Coupon::whereCode($code)->lockForUpdate()->firstOrFail(); abort_if($coupon->used_at !== null, 409); $coupon->update(['used_at' => now()]); }); ``` **The lock is held until the invariant is recorded.** A `lockForUpdate()` whose `update()` happens after the closure returns bought nothing at all. ## 2. Back it with a constraint where the rule demands it A transaction is the fast path. A **unique constraint** is the one that is still true under a deploy, a replica that lags, a sec