roave/backward-compatibility-check
A CLI tool that compares two versions of a PHP library and flags backward-compatibility breaks. It reads git tags and composer.json autoload paths, then fails CI builds when public API changes would break downstream consumers.
Architecture fit
composer.json autoload paths, reflects two git revisions (default: latest SemVer tag vs. HEAD), and diffs the class-level API. It is complementary to PHPStan/Psalm (internal correctness) and conventional SemVer hygiene — it is the automated enforcement layer for the latter.x.y.z-format tags.Integration feasibility
composer require --dev roave/backward-compatibility-check plus one CI step, or the prebuilt nyholm/roave-bc-check Docker image with no local install at all.--format=github-actions (inline PR annotations), and --format=markdown (drop-in changelog/release-note input). The last one is the underrated TPM lever — it converts the gate into release documentation..roave-backward-compatibility-check.xml supports regex-based baseline suppression of known/accepted breaks, which is what makes an incremental adoption path possible.fetch-depth: 0). Without tags, the base revision is wrong or unresolvable and the check silently loses meaning.Technical risk
composer/composer, roave/better-reflection, and symfony/console into the dev dependency graph. In a Laravel app with a locked Symfony/Composer set, a --dev install can force upgrades or fail resolution. Mitigation is strong and cheap: run it in an isolated job or via the Docker image rather than co-locating it in the application lockfile.autoload coverage cause classes to be skipped without any warning.Key questions for the team
autoload section complete enough that reflection sees the whole public surface?composer/composer/symfony/console conflict with our locked versions — and if so, do we accept an isolated job/Docker runner?@internal symbols and test-only namespaces (scope suppression vs. baseline)?Stack fit
Migration path
--format=github-actions; collect the first report and measure noise level.main/release branches for that package, with an explicit break-glass label.--format=markdown into the release-notes template so changelogs are generated rather than hand-written.Compatibility
nyholm/roave-bc-check) or a dedicated tooling job to eliminate lockfile contention with Laravel's pinned Symfony and Composer versions.fetch-depth: 0 (or an explicit tag fetch) in every pipeline that runs it — this is the single most common silent misconfiguration.Sequencing
Maintenance
composer/composer); pinning and isolating the job absorbs almost all of it.Support
--help.Scaling
Failure modes and mitigations
| Failure | Impact | Mitigation |
|---|---|---|
| Missing/unfetched tags | Compares against wrong base; meaningless or noisy output | fetch-depth: 0; assert the detected base version in job logs |
Incomplete autoload coverage |
Classes silently skipped → false negative | Audit autoload coverage as part of Phase 1 |
| Baseline creep | Gate becomes a no-op; real breaks ship | Require PR review + justification per ignore rule; quarterly audit |
| Dev-dependency conflict | CI job fails, blocks unrelated work | Isolate via Docker/PHAR or dedicated tooling job |
| False positive on intentional break | Release blocked | Break-glass label + baseline entry, recorded in release notes |
| Upstream tool breakage | Gate unavailable | Pin version; runbook to disable gate without blocking delivery |
| Hotfix/patch branch semantics | Base revision differs from intent | Explicit base/head arguments in the hotfix pipeline |
Ramp-up
--help and README cover the rest. No new language or framework to learn.KPIs a TPM should track
How can I help you explore Laravel packages today?