Challenge 3 — Solution Task: Explain, in your own words and in detail, the practical difference between running "composer install" and "composer update" when a composer.lock file already exists — including which one a CI/CD pipeline or production deployment should normally use, and why getting this wrong could cause a "works on my machine" bug. "composer install" (when composer.lock already exists): Reads composer.lock directly and installs the EXACT package versions it specifies, completely ignoring composer.json's own (looser) version constraints for this step. It never tries to resolve a newer version that might also satisfy the constraints - it just reproduces exactly what's already recorded in the lock file, byte-for-byte reproducibly, every single time it's run against that same lock file. "composer update": Ignores whatever is currently in composer.lock and re-resolves every dependency from scratch against composer.json's own constraints, picking the newest version that satisfies each one. It then REWRITES composer.lock to record whatever new versions it just resolved. Which one a CI/CD pipeline or production deployment should use: "composer install" - always. A deployment should reproduce the exact same, already-tested set of package versions that a developer verified locally and committed via composer.lock - never resolve a potentially different, newer set of versions on the fly during deployment. Why getting this wrong causes a "works on my machine" bug: If a production deployment ran "composer update" instead of "composer install", it could resolve genuinely different package versions than what a developer tested locally - even though both computers are reading the identical composer.json, "composer update" might pick up a newer minor/patch release that was published to the package registry between when the developer last ran it and when the deployment ran. If that newer version happens to contain a subtle bug, a behavior change, or a genuine (if technically SemVer-compliant) incompatibility, the application could then fail in production despite passing every test on the developer's own machine - the exact "works on my machine" scenario, caused entirely by two environments silently ending up with different dependency versions instead of the identical ones composer.lock was specifically designed to guarantee. Notes: - This is precisely why composer.lock is committed to git (the opposite rule from vendor/, per the chapter's own warn-box) - it's the single source of truth that keeps "composer install" fully deterministic across every machine that runs it. - "composer update" is the right command to run deliberately and locally, when a developer genuinely wants to pull in newer allowed versions - the result (a freshly rewritten composer.lock) then gets tested and committed before ever reaching a deployment pipeline.