Search by

logic-replay / laravel

nurkarim772

Record a Laravel request as a sanitized logic trace, mark where the expected result diverged, and dry-replay it locally.

dev-main 2026-11-01 07:43 UTC

This package is auto-updated.

Last update: 2026-11-01 07:45:43 UTC


README

Record one HTTP request as a sanitized trace: route middleware, service spans, queries, jobs, and checkpoints where the expected business result did not match. Dry-replay that same request locally inside a database transaction that is rolled back.

Recording is limited to local and testing unless you change record_environments. The viewer is limited the same way. Replay never commits database writes, and it fakes HTTP, mail, notifications, and queues.

Install

composer require logic-replay/laravel

From a path checkout:

"repositories": [
    { "type": "path", "url": "../laravel-logic-reply" }
]

Publish the config when you want to change the defaults:

php artisan vendor:publish --tag=logic-replay-config

The file driver writes JSON under storage/logic-replay. For the database driver, set LOGIC_REPLAY_DRIVER=database and publish the migration:

php artisan vendor:publish --tag=logic-replay-migrations
php artisan migrate

The package prepends its trace middleware automatically.

Checkpoints

use LogicReplay\Facades\LogicReplay;

$total = LogicReplay::span('pricing.calculate', fn () => $pricing->calculate($cart));

LogicReplay::expect('cart.grand_total', expected: 1500, actual: $total->amount);

expect() returns false when the values differ. The HTTP response can still be 200. The trace status becomes failed.

Wrap a service call that is not already inside span():

LogicReplay::call($pricing, 'calculate', [$cart]);

Inspect

  • GET /logic-replay lists traces.
  • php artisan logic-replay:list
  • php artisan logic-replay:show {id}
  • php artisan logic-replay:export {id} trace.json
  • php artisan logic-replay:import trace.json

Passwords, tokens, cookies, and similar keys are stored as [redacted]. Other fields, including email addresses, are kept so a local replay still has the lookup values. Add those keys to redact_keys when they should be removed. Do not commit trace files.

Dry replay

php artisan logic-replay:run {id} --dry

The command freezes time to the original request, restores a user only when LogicReplay::resolveUserUsing() is set, fakes external calls from recorded HTTP responses, and rolls the database transaction back.

LogicReplay::resolveUserUsing(fn (int|string $id) => \App\Models\User::find($id));
LogicReplay::resolveTenantUsing(fn () => auth()->user()?->tenant_id);

During replay the request has header X-Logic-Replay-Tenant and attribute logic_replay.tenant_id.

Verdicts are same_failure, fixed, new_failure, unchanged, or incomplete. Queued jobs from the original trace are not executed.

Replay runs only in replay_environments (local, testing by default).