Skip to content

Boot optimization candidate decisions

This record applies the admission rules from the Capell boot performance plan to eager provider work. A candidate is retained only when its owning phase is at least 10 ms or 3% of boot, focused behavior remains unchanged, and paired p75 does not regress.

The benchmark measures full in-process Laravel application creation and bootstrap. Child-process overhead remains diagnostic data and is not used to admit an optimization.

Profiling on 24 July 2026 identified these first-party provider medians:

ProviderRegister p50Boot p50Decision
Core13.746 ms1.025 msInvestigate registration candidates
Admin28.153 ms6.838 msMove to the separate admin-activation phase
Frontend1.023 ms14.229 msPreserve required listener and component lifecycle
Marketplace0.086 ms0.993 msBelow the admission threshold

The host did not satisfy the baseline stability gate during this investigation: load averages ranged from approximately 10 to 25 on 12 cores, the corrected production median spread reached 6.62%, and IQR/median reached 18.77%. Measurements below are therefore used only to reject regressions, never to claim an improvement.

After the runtime lifecycle fixes were committed in a98aee15d, the host load settled sufficiently to establish the required optimized-cache baseline. Each profile was measured in three independent runs of 25 samples after five warmups:

ProfileRun p50 mediansMedian spreadWorst IQR / medianFingerprint
Production108.33, 107.39, 107.57 ms0.87%2.90%5fe3451cbfbeb16f022d9e38af5da5d3a4778563f9f26cb49ecffee170378ae9
Public48.93, 47.94, 47.72 ms2.52%5.97%f1b774cb70141e8eea9c1d6836eb69ab546e7bc3ee07c0da4dddf7f55ac77881
Admin108.25, 108.34, 107.37 ms0.90%6.05%a08050cf80923380cccd58e93671fc9a6f913ef2b285d3ef3cf6700a11be37d7

All three profiles satisfy the baseline gate of no more than 3% median spread and no more than 10% IQR/median. Tukey outliers remain in the retained raw samples and were not removed from the reported statistics.

The candidate moved built-in renderable and linkable-content definitions into their singleton factories. Focused link, renderable, and boot-contract tests passed, but all three optimized production pairs regressed:

Pairp50 deltap75 delta
1+0.788 ms+8.995 ms
2+6.798 ms+10.608 ms
3+9.011 ms+14.837 ms

The candidate was reverted. It is not part of a delivery branch.

  • Core settings configuration must be ready before the Spatie settings provider consumes it. Dependency default configuration is loaded from the filesystem only when configuration is uncached; cached production boot keeps that fallback disabled.
  • Core event-sourcing projectors, reactors, aggregates, and rollback validators must be registered before Spatie builds the projectionist.
  • Frontend component contributors are already materialized through lazy container bindings.
  • Frontend cache invalidation observers, the documented bounded wildcard model listeners, and route-reservation contributions must remain available during normal provider registration and boot.
  • Marketplace provider time is below the candidate threshold.

No further independently deferable Core, Frontend, or Marketplace candidate was retained. Admin surface materialization and bridge boot are handled by the separate idempotent admin runtime activation change.

This phase changes no runtime code. It preserves contribution ordering, anonymous rendering and cache contracts, wildcard listeners, routes, middleware, and extension declarations. No new database or filesystem work is introduced at boot.


Measurement environment — not comparable to the CAP-0028 baseline

Section titled “Measurement environment — not comparable to the CAP-0028 baseline”

CAP-0028’s figures come from the local Testbench boot benchmark. CAP-0029 was measured against a real Laravel 13.22 install of the public Capell packages (12 capell-app/* packages, MariaDB 10.5, Redis, demo content) on a shared 2-core host, with the benchmark confined to one core at nice 19.

Absolute milliseconds therefore do not transfer between the two documents; proportions do. Observed run-to-run spread on this host is roughly 45%, which means it cannot resolve differences below about 50 ms. Every verdict below is stated against that floor.

Bootstrapper split ($kernel->bootstrap() is ~96% of boot):

Bootstrapperms%
BootProviders528.968.4%
RegisterProviders222.628.8%
RegisterFacades10.71.4%
HandleExceptions5.50.7%
LoadConfiguration4.80.6%
LoadEnvironmentVariables0.30.0%

89 providers total: 14 first-party, 54 third-party, 21 Laravel.

Slowest boot contributors: Filament 221.6 ms (36.8%), Livewire 68.5 ms, FilamentTinyEditor 66.2 ms, HtmlCache 55.5 ms, LayoutBuilder 32.2 ms, BlockLibrary 29.2 ms. Slowest register contributors: CapellServiceProvider 92.5 ms (39.7%), PowerJoins 27.2 ms, AdminServiceProvider 17.9 ms.

End-to-end cached public homepage through nginx + PHP-FPM: n=20, min 56.0 ms, p50 65.3 ms, p95 78.8 ms. Render alone once booted is ~1.7 ms, so boot dominates a public request almost entirely.

Config caching is not the lever. LoadConfiguration is 0.6% of boot, which matches the measured result that caching config/routes/events/views moved CLI boot only 433 ms -> ~404 ms, inside noise.

Rejected: batch manifest registration and de-duplicated registry write

Section titled “Rejected: batch manifest registration and de-duplicated registry write”

ManagesPackages::registerManifestPackages() collapsing per-package memo wipes into one, plus removing the duplicate CapellPackageRegistry write already performed by fill(). 12 interleaved pairs: baseline median 86.0 ms, candidate median 86.3 ms. Reverted; not part of a delivery branch.

Rejected: process-constant probe memoisation

Section titled “Rejected: process-constant probe memoisation”

Static memoisation of isLivewireV3(), isDiscoveringPackages() and resolvePackagePath() on AbstractPackageServiceProvider. 10 interleaved pairs: baseline median 104.3 ms, candidate median 97.7 ms, but paired median delta +0.7 ms. resolvePackagePath() is called once per provider class per boot, so there are no repeat calls to memoise. Reverted.

Rejected: Filament component caching as a measured win

Section titled “Rejected: Filament component caching as a measured win”

filament:cache-components showed no improvement here: baseline median 229.8 ms vs cached median 279.8 ms, with fully overlapping ranges. The test install has a nearly empty panel, so there is almost nothing to discover — this result does not generalise to a production panel. It is still applied at deploy time as documented Filament hardening, but no measured gain is claimed.

Accepted: targeted reflection in extension page navigation suppression

Section titled “Accepted: targeted reflection in extension page navigation suppression”

CapellAdminManager::suppressExtensionPageNativeNavigation() built a full ReflectionClass and walked hasProperty()/getProperty()/isStatic() to reach one protected static property, forcing the whole Filament Page ancestor property table to resolve. Replaced with a single targeted ReflectionProperty plus a per-manager memo so a page registered twice does not pay twice.

Pairbaselinecandidatedelta
160.4 ms58.6 ms-1.8 ms
288.5 ms42.2 ms-46.3 ms
354.8 ms42.7 ms-12.1 ms
456.3 ms55.1 ms-1.2 ms
542.3 ms44.8 ms+2.5 ms

Mean 60.5 ms -> 48.7 ms (-19.5%), 4 of 5 pairs improved. Reflection remains required because the property is protected; the behaviour, including the silent no-op when the property is absent or non-static, is unchanged and pinned by ExtensionsPageTest.

  • Provider boot performs database work. A Schema::hasTable() probe runs during boot via RuntimeSchemaState. It is already scoped() and memoised per request, and a process-level cache was rejected as unsafe (test isolation and staleness across an Octane worker). config/deploy.php in capell-app documents forcing an in-memory connection for its control plane because of this behaviour.
  • Deploys shipped with no warm caches. The build phase deleted bootstrap/cache/filament and bootstrap/cache/capell and never rebuilt them. Fixed in capell-app’s config/deploy.php.
  • CLI has no opcache. opcache.enable_cli=0, so every artisan invocation recompiles all sources. Enabling it with a file cache measured CLI boot at 215-253 ms versus ~404 ms.
  • Admin-only providers boot on public requests. Filament, TinyEditor, Shield and Curator together are ~320 instrumented ms that a public page never needs. Deferring them is architecturally sound but was assessed as the last lever to pull, worth an estimated 25-35 ms real p50, and is not attempted here.

Measured on one shared 2-core host; absolute values are host-specific. No throughput or concurrency testing was performed, deliberately, because the host also serves unrelated production sites. packages/core/tests/Arch/PackagesTest.php could not be executed in this environment and its state is unverified.