raceproof/laravel

Controlled and reproducible concurrency testing for Laravel applications.

Maintainers

Package info

github.com/zerodycoder/RaceProof

pkg:composer/raceproof/laravel

Transparency log

Statistics

Installs: 26

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 5

v1.0.0-beta.1 2026-07-26 18:38 UTC

This package is auto-updated.

Last update: 2026-07-26 18:48:01 UTC


README

Concurrent request lanes meeting at a controlled barrier

RaceProof for Laravel

Tests PHP 8.2 or newer Laravel 12 and 13 MIT License

Make race conditions arrive on cue - then keep the fix under test.

RaceProof coordinates independent Laravel processes against the same database, pauses them at explicit application checkpoints, releases them as one cohort, and gives you a single result for response and database assertions.

It is built for the failures that ordinary feature tests rarely reproduce: overselling the final unit, redeeming one coupon twice, losing wallet updates, accepting an expired quote, uniqueness races, deadlocks, and lock timeouts.

Release status: both Composer packages are registered on Packagist and currently expose dev-main, but no tagged beta is available yet. The install commands below become available with the first beta. Contributors can use a source checkout today.

See the failure, then prove the fix

RaceProof reproducing broken overselling and verifying the atomic fix

This animation summarizes the repository's executable three-process overselling fixture: the broken path creates three orders from stock 1 and ends at -2; the atomic claim creates one order, ends at 0, and returns two honest 409 responses. MySQL and PostgreSQL evidence exercise the same broken/fixed route pair.

The smallest useful test

Application code marks the critical point:

race_point('oversell-claim');

$created = DB::transaction(function () use ($product): bool {
    $claimed = Product::query()
        ->whereKey($product->getKey())
        ->where('stock', '>', 0)
        ->decrement('stock');

    if ($claimed === 0) {
        return false;
    }

    Order::query()->create(['product_id' => $product->getKey()]);

    return true;
});

abort_unless($created, 409);

The test starts real application processes, waits until all of them reach that point, and releases them together:

$result = race()
    ->participants(3)
    ->postJson('/api/checkout', ['product_id' => $product->getKey()])
    ->releaseWhenAllReach('oversell-claim')
    ->run();

$result
    ->assertAllFinished()
    ->assertNoWorkerFailures()
    ->assertStatusCount(201, 1)
    ->assertStatusCount(409, 2)
    ->assertNoServerErrors()
    ->assertInvariant(
        fn () => Order::query()->count() === 1
            && $product->fresh()->stock === 0,
        'Exactly one order may claim the final unit.',
    );

For a copy-ready broken-to-fixed walkthrough, use the five-minute guide.

Install

Once the first beta is published:

composer require raceproof/runtime:^1.0.0-beta.1@beta
composer require raceproof/laravel:^1.0.0-beta.1@beta --dev

php artisan raceproof:install
php artisan raceproof:doctor --self-test

Install raceproof/runtime only when application code contains race_point() calls. It is a framework-free production dependency whose checkpoint calls are no-ops unless a validated RaceProof worker activates an in-memory handler. It has no process runner, filesystem, network, command, or Laravel integration.

raceproof:install publishes configuration and prints a safe .env.testing checklist. It never edits an environment file. Doctor's --self-test mode boots a separate Laravel CLI process; --json emits a bounded schema-v1 result suitable for CI and support reports.

Before the beta, develop from source:

git clone https://github.com/zerodycoder/RaceProof.git
cd RaceProof
composer install
composer check

Maintainers can also run composer consumer:check to install and exercise RaceProof inside an isolated Laravel application. The consumer app verifies package discovery, participant/authentication modes, a real database race, CLI workflows, and Studio without relying on the package's Testbench bootstrap.

See runtime checkpoint deployment before adding instrumentation to production code.

How it works

  1. The parent test validates the environment, database, request, participant overrides, authentication specs, and checkpoint plan.
  2. RaceProof boots independent Laravel worker processes against the same configured database.
  3. A start barrier coordinates request entry; race_point() can rendezvous workers inside the application.
  4. The parent releases a checkpoint only after the complete cohort arrives.
  5. The result combines responses, worker failures, timeouts, redacted diagnostics, and a versioned event timeline for assertions and CI reports.

The operating system and database still decide execution order after release. RaceProof controls the important rendezvous; it does not claim exact schedule replay or formal proof that no other race exists.

Participant-specific requests and authentication

Each participant can override payload, headers, cookies, bearer tokens, session identity, Sanctum credentials, and trusted bootstrap data:

use RaceProof\Laravel\ParticipantBuilder;

$result = race()
    ->participants(2)
    ->postJson('/api/transfer', ['amount' => 100])
    ->actingAs($owner, 'web')
    ->forParticipant('p2', fn (ParticipantBuilder $participant) => $participant
        ->withPayload(['amount' => 75])
        ->withHeaders(['X-Tenant' => 'north'])
        ->withToken($sanctumToken)
        ->actingAs($reviewer)
        ->withBootstrap(TransferBootstrap::class, ['tenant' => 'north']))
    ->releaseWhenAllReach('balance-read')
    ->run();

All participant specs are validated before orchestration and cross the process boundary as JSON - never serialized closures. Read the request and authentication guide and bootstrap guide for merge rules and security boundaries.

Assertions and evidence

$result->assertAllFinished();
$result->assertNoWorkerFailures();
$result->assertNoServerErrors();
$result->assertNoTimeouts();
$result->assertStatusCount(201, 1);
$result->assertExactlySuccessful(1);
$result->assertStartSpreadBelow(10);
$result->assertInvariant(fn () => true, 'Invariant failed.');

$result->successful();
$result->failed();
$result->statuses();
$result->participant('p2');
$result->startSpreadMs();
$result->durationMs();
$result->failureReport();

Human, JSON, and JUnit reporters all use one versioned, bounded, redacted report model. See evidence reporters for CI examples and the JSON v1 contract.

RaceProof Studio

Studio is an optional, local evidence viewer. It visualizes retained runs, participant outcomes, timing, checkpoint lanes, warnings, and bounded response evidence without moving execution or assertions out of Pest/PHPUnit.

RaceProof Studio showing a passed three-participant run and its checkpoint execution lanes

Enable it explicitly in a local or testing environment:

RACEPROOF_STUDIO_ENABLED=true
php artisan make:race-test InventoryOversell /api/checkout --participants=3
php artisan test --filter=InventoryOversellTest
php artisan raceproof:reports
php artisan raceproof:studio

Open /raceproof on the application's normal local development server. Studio is server-rendered and requires no Node/Vite setup. It never registers routes, reads archives, or writes reports in production, even if its flag is misconfigured. The dashboard is deliberately not an arbitrary endpoint runner: the committed test remains the reproducible source of truth.

Read the Studio guide for configuration, retention, CLI, and security details.

Safety model

RaceProof fails closed:

  • production is always refused;
  • tests must explicitly enable RaceProof;
  • non-testing environments need a separate explicit opt-in;
  • open parent database transactions and SQLite in-memory are rejected;
  • an exact database-name allowlist can be required in CI;
  • captured bodies and headers are bounded and sensitive data is redacted;
  • run, participant, and checkpoint identifiers are path-safe;
  • coordination uses JSON only, with no untrusted unserialize();
  • crash and timeout artifacts are retained for diagnosis.

Use a dedicated disposable database. Do not combine multi-process tests with transaction-based test traits: workers cannot see the parent's uncommitted records. The production safety guide and database guide contain the full operating contract.

Support matrix

Dimension Support
PHP 8.2+
Laravel 12 and 13
Databases MySQL 8.4 and PostgreSQL 17 continuously verified
Linux Full CI and database release-evidence platform
WSL2 Primary development target
macOS Best-effort; continuous independent-consumer smoke
Native Windows Experimental; continuous independent-consumer smoke
SQLite File-backed smoke tests only; not production lock evidence

The exact compatibility promise is maintained in the platform matrix.

Examples

All published examples are wired into executable tests; they are not standalone documentation snippets.

Documentation

Start with the documentation map, or jump directly to:

Project status

The code, API guard, deterministic archives, supply-chain checks, database evidence, and release automation are implemented. Public package publication and real beta-adoption evidence remain honest external gates; stable release is blocked until they are complete.

See the roadmap, pre-release audit, and beta evidence for the machine-checked status.

Contributing

Focused issues and pull requests are welcome. Before opening one, read CONTRIBUTING.md, the quality policy, and the code of conduct.

For security reports, follow SECURITY.md. Do not disclose a vulnerability in a public issue.

License

RaceProof is open source under the MIT License. You may use, modify, distribute, sublicense, and sell copies, including commercially. Copies or substantial portions must keep the copyright and permission notice. The software is provided without warranty. See the plain-language licensing guide for contribution and redistribution notes.