-
Notifications
You must be signed in to change notification settings - Fork 0
Contributing
PHP Upgrade Preflight welcomes focused fixes, tests, documentation, framework rules, fixtures, and reproducibility improvements. This Wiki guide reflects repository policy on 2026-08-19; CONTRIBUTING.md remains the canonical in-repository source.
For a large change, open an issue first to confirm direction. Report security vulnerabilities privately through SECURITY.md, never in a public issue or pull request.
Every contribution must preserve four product rules:
- the analyzed project stays unchanged;
- conclusions remain evidence-backed;
- JSON is the canonical report and Markdown is a projection;
- Core stays framework-neutral.
The documented Docker path is:
git clone https://github.com/ValentinNikolaev/php-upgrade-preflight.git
cd php-upgrade-preflight
docker compose build php
docker compose run --rm php composer install
docker compose run --rm php composer checkWith a compatible local PHP/Composer toolchain:
composer install
composer checkThe project supports PHP 8.0 as its package floor. CI additionally exercises newer PHP versions and Windows.
During development, run the smallest relevant check:
composer test:core
composer test:cli
composer test:laravel
composer test:unit
composer test:integration
composer test:smoke
composer test:fixtures
composer analyse
composer lintBefore opening a pull request, run:
composer checkcomposer check validates all manifests, runs unit/integration/smoke tests, both PHPStan configurations, and formatting in dry-run mode. It does not update dependencies or query live vulnerability data.
If Docker stops the long integration suite near Composer's default 300-second process timeout, run:
docker compose run --rm -e COMPOSER_PROCESS_TIMEOUT=0 php composer checkThat environment variable affects the outer Composer script timeout, not the analyzer's bounded scenario timeouts.
composer test:coverage
composer test:mutationCoverage is an exact ratchet: overall and critical-module ratios cannot decline, and new uncovered fingerprints fail. Do not lower the baseline to hide missing tests. Rewrite it only after reviewing a complete successful Clover run:
php tools/verify-coverage.php build/coverage/clover.xml --write-baselineSelective mutations must all be killed by their focused tests. The integration suite also enforces process, runtime, memory, privacy, report-size, and determinism budgets for representative and worst staged chains.
Ordinary fixture tests compare current output with committed snapshots. Regeneration is explicit.
POSIX:
PHP_UPGRADE_PREFLIGHT_UPDATE_SNAPSHOTS=1 vendor/bin/phpunit --filter LaravelFixtureAnalysisTestPowerShell:
$env:PHP_UPGRADE_PREFLIGHT_UPDATE_SNAPSHOTS = '1'
vendor\bin\phpunit --filter LaravelFixtureAnalysisTest
Remove-Item Env:PHP_UPGRADE_PREFLIGHT_UPDATE_SNAPSHOTSDocker:
docker compose run --rm -e PHP_UPGRADE_PREFLIGHT_UPDATE_SNAPSHOTS=1 php composer test:fixturesReview every JSON/Markdown pair. Snapshot normalization removes host paths, separators, and timing noise but preserves meaningful commands, outcomes, findings, evidence, and lock fingerprints.
Never regenerate archived tests/fixtures/contracts/v0.1 or v0.2.1 during ordinary work. They are released compatibility evidence; correction requires explicit compatibility review and provenance.
Published schema files are immutable. Any additive or breaking serialized shape change requires:
- a new schema version and file;
- an updated canonical Core snapshot;
- consumer migration documentation;
- tests for JSON and Markdown projection;
- changelog and Wiki updates.
A finding or guidance correction may retain the schema only when the serialized shape remains compatible.
- Keep one coherent change per pull request.
- Add tests for every behavior change and failure boundary.
- Preserve target-project immutability; compare before/after digests for integration fixtures.
- Update affected
README.md,docs/,CHANGELOG.md, and Wiki pages in the same change. - Check every changed command, link, supported-version claim, and example.
- Run focused checks during development and
composer checkbefore review. - Do not commit credentials, debug workspaces, generated reports, or unrelated formatting.
Example verification for a Laravel rule change:
composer test:laravel
composer test:fixtures
composer analyse
composer lint
composer check
git status --shortAll five package manifests participate in monorepo validation:
coreclilaraveltest-adapterlegacy-test-adapter
Only core, cli, and laravel are supported external distributions. The two adapter packages are test fixtures. Do not add them to release archives or Packagist release steps.
Every behavior change must update affected public documentation in its pull request. The requirement becomes a hard release condition before any vMAJOR.MINOR.PATCH tag:
- update
CHANGELOG.mdanddocs/releases/vVERSION.md; - update all affected Wiki pages, commands, examples, compatibility tables, service descriptions, schemas, and limitations;
- verify the text is understandable to a Junior developer and a technical manager;
- run
composer release:verify -- VERSIONand complete the release checklist.
Codex, Claude, and all other coding agents are explicitly required to perform the Wiki update when their work creates or prepares a release tag. They must not defer it as optional cleanup. As of 2026-08-19, verify-release.php checks repository metadata, changelog, and release notes, but Wiki freshness remains a mandatory human/agent review item.
Use a clean release-candidate commit and follow Quality and Release Tooling. A manual Release workflow run packages without publishing. A matching signed annotated tag publishes only after metadata, quality, compatibility, security, distribution, fresh-clone, archive-consumer, and Packagist gates pass.
Do not add version fields to Composer manifests. Exact versions come from matching Git tags.
Use the package boundary to avoid coupling:
| Change | Owning package |
|---|---|
| Generic Composer scenarios, blockers, source inventory, evidence, report model | packages/core |
| Standalone options, parsing, adapter discovery, generic command delivery | packages/cli |
| Laravel catalog, rules, stages, source visitor, Artisan integration | packages/laravel |
| Current third-party adapter capability fixture | packages/test-adapter |
| Backward-compatibility adapter fixture | packages/legacy-test-adapter |
Do not solve a Laravel requirement by importing Laravel code into Core.
Do not add analysis decisions to a command controller.
Do not put fixture-only package names into production behavior.
See Package Map and Class and Service Index before introducing a new service.
| Change type | Minimum focused evidence |
|---|---|
| Request/model validation | Unit tests for accepted, rejected, and normalization cases |
| Composer command or environment | Runner tests plus an integration fixture proving external behavior |
| Blocker parsing | Transcript tests with solver and operational counterexamples |
| Source visitor | AST fixture tests with line, symbol, usage type, and parse failure |
| Adapter rule | Positive, negative, non-applicable, and throwing paths |
| Staged planning | Adjacency, exact PHP provenance, gap, collision, and budget tests |
| Report field | Model, schema, JSON/Markdown, snapshots, and migration documentation |
| Redaction/path behavior | Synthetic canary tests on strings and structured values |
| CLI option | Vocabulary, parser, help, command, and CLI documentation tests |
A happy-path unit test is not sufficient for a trust boundary.
Test the classification of failure, not only that an exception occurred.
Suppose a new field is added to a blocker.
The complete path normally includes:
- Add the validated property to
Blockeror a related value. - Populate it in the parser, attribution service, or grouper that owns the fact.
- Serialize it in
toArray(). - Update schema with the correct required/optional compatibility decision.
- Update canonical Core and relevant Laravel fixtures.
- Update Markdown rendering from canonical report data.
- Add consumer migration text if shape or meaning changed.
- Update Wiki report and concept pages.
Do not calculate the field only in MarkdownReportWriter.
That would create a second, non-canonical analysis path.
Start with applicability and sources.
Decide whether the change belongs in a catalog definition or executable rule logic.
Verify the target package appears in the correct project state.
Test the relevant hop and at least one adjacent non-applicable hop.
Check evidence class, confidence, context, and references.
Run fixture tests and review both JSON and Markdown changes.
If the rule can produce a stage remediation, test temporary target constraints separately from ordinary guidance.
Never rewrite archived released fixtures to make a new rule appear backward compatible.
For every new evidence item, confirm:
- the namespace is stable and valid;
- creation order is deterministic;
- the summary states an observation, not an unsupported conclusion;
- context contains no secret or private absolute path;
- evidence class matches the source;
- confidence matches support strength;
- a report claim references the ID;
- no orphan evidence remains.
UpgradeReport rejects missing and orphan evidence references.
Use addOnce() only when strict content identity really means one reusable observation.
Tests that run Composer must compare the target tree before and after analysis.
Expected writes belong only to analyzer-owned temporary workspaces and an explicitly requested report destination outside the target tree.
Debug mode can retain workspaces.
Retained workspaces may contain copied Composer metadata and should not be committed.
If cleanup fails, preserve the uncertainty in the report rather than hiding it.
A useful description answers:
Problem:
Owning package/service:
Behavioral change:
Evidence and trust boundaries:
Compatibility/schema impact:
Focused tests run:
Full checks run:
Documentation updated:
Known limitations:
For a manager, state user-visible scope and compatibility impact plainly.
For a reviewer, link the exact tests and canonical snapshots.
Do not describe an analyzer finding correction as a runtime guarantee.
Documentation examples must be runnable or explicitly marked abbreviated.
Use current option names from CommandLineOptions and the Artisan signature.
Use current report vocabulary from models and schema.
Cross-link the detailed page instead of copying a long canonical table into several pages.
Check every local Markdown link and every Wiki link.
Keep required Wiki pages between 300 and 900 source lines when that is the repository documentation contract.
Verify code fences are balanced.
Ensure every page in _Sidebar.md exists and important main pages are reachable from it.
Before handoff:
composer check
git diff --check
git status --shortRead the diff as a reviewer after tests pass.
Check that no unrelated user changes were reformatted or removed.
Inspect temporary paths created during the task and delete only known reproducible artifacts.
Report retained diagnostics and why they remain.
For release-tag work, complete Release Wiki Strategy in addition to normal code checks.
PHP Upgrade Preflight — common product and monorepo Wiki · Common repository
- Home
- Key Concepts
- Package Map
- Class and Service Index
- Getting Started
- CLI Reference
- Artisan Command
- Reading the Report
- Safety and Trust Boundaries
- Troubleshooting and FAQ
- Architecture Overview
- Core Package Guide
- Core Analysis Pipeline
- Core Service Reference
- Determinism and Evidence
- Report Schema
- CLI Package Internals
- Laravel Package Internals
- Test Adapters
- Writing a Framework Adapter
- Laravel Adapter Internals
- Contributing
- Roadmap and Status
- Tools Reference
- Quality and Release Tooling
- Release Wiki Strategy