feat: subtract a warm-up boot baseline from Tia dependency edges - #1807
Open
iAmKevinMcKee wants to merge 1 commit into
Open
feat: subtract a warm-up boot baseline from Tia dependency edges#1807iAmKevinMcKee wants to merge 1 commit into
iAmKevinMcKee wants to merge 1 commit into
Conversation
…dges Frameworks that boot inside every test's setUp() re-execute the same bootstrap lines in every per-test coverage window. In a Laravel app every service provider, route file, and (with Filament) every panel resource executes getPages()/getRelations() on every boot, so Tia links every test to every bootstrap-executed file — a change to any of ~100 resource classes reruns the entire suite, defeating test impact analysis. pest()->tia()->warmupUsing(fn () => ...) registers a callback that runs once per process under the coverage driver before the first test. Every line it executes becomes a baseline that is subtracted from each test's recorded coverage before dependency edges are derived; a file only becomes an edge when a test executes lines beyond the baseline. Measured on a production Laravel 12 + Filament 5 app (~100 resources): a pure enum unit test dropped from 146 recorded edges to 6, a dashboard feature test from 1018 to 27, and editing an unrelated Filament resource went from invalidating the whole suite to invalidating nothing, while changes to genuinely shared models still selected their real dependents. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
Tia derives dependency edges from per-test coverage windows, and those windows include everything that runs in
setUp(). Frameworks that boot inside every test — Laravel being the canonical case — re-execute the same bootstrap lines in every test's window: service providers,bootstrap/app.php, route registration. Filament makes this dramatic: panel route registration executesgetPages()/getRelations()in every registered resource class on every boot (verified by dumping executed lines; Laravel route caching does not avoid it).The result on a production Laravel 12 + Filament 5 app (~100 resources):
Any Filament project will hit this; any Laravel project hits a milder version (providers/routes as universal edges).
The fix
pest()->tia()->warmupUsing(Closure $callback)— a callback that runs once per process under the coverage driver, before the first test. Every line it executes forms a warm-up baseline that is subtracted from each test's recorded coverage before edges are derived. A file only becomes a dependency when a test executes lines beyond the baseline — so a feature test that genuinely renders a resource's form keeps that edge, while a unit test that merely booted the framework loses it.Measured results (same app as above)
TestCase, the tenant models itssetUpgenuinely touches)Project)Warm-up responsibility (important caveat)
The callback runs in the test process, so it must clean up global state it mutates. For Laravel that includes a subtle one we hit in practice: booting an app loads
.envthrough Dotenv, and the staticIlluminate\Support\Envrepository then treats those variables as Dotenv-owned — when the real test application boots later, Dotenv overwrites the restoredAPP_ENV=testingwith the.envvalue, which (among other things) silently disables Filament'sfillFormDataForTesting()and produces confusing downstream failures. A working Laravel warm-up restores$_ENV/$_SERVER/putenvsnapshots, resetsEnv::$repositoryvia reflection, resets the container/facades, and unwinds error/exception handlers back to their pre-boot state. ThewarmupUsing()PHPDoc calls this out; if maintainers prefer, a follow-up could ship a ready-made Laravel warm-up (Pest already has Laravel awareness inWatchDefaults\Laravel) so users get this behavior with zero config — happy to do that in this PR or a follow-up, whichever you prefer.Implementation notes
beginTest()with coverage capture active: start driver → run callback → collect scoped lines → reset for the per-test window. No behavior change when no warm-up is registered.Recorder::filesWithExecutedLines()per file/line; the existing single-line/max-line heuristic is preserved.--coverage+ Tia) is unaffected — the warm-up only runs when the Recorder drives pcov/xdebug itself.pcov.directory) and skip otherwise, so they are safe in any CI configuration.Tests
warmupUsing()excludes files fully covered by the baseline.composer lint,composer test:type:checkpass;composer test:unitpasses apart fromBacktrace::it gets file name from called file, which fails identically on a clean checkout in this environment (pcov extension loaded) and is unrelated.🤖 Generated with Claude Code