A conflict rule in composer.json, and why it beat a version bound

Two packages that work individually and break together, expressed as a version bound that was wrong for anybody not using both.

{
  "require": {
    "vendor/serializer": "^3.0"
  },
  "conflict": {
    "vendor/legacy-hydrator": "<2.4"
  }
}

Narrowing the requirement would have said “this package needs serializer 3.2 or later”, which is untrue — it needs that only when the hydrator is present. A conflict rule states the actual constraint, so a consumer without the hydrator resolves freely and one with it gets an explanation at install time rather than a bug at runtime.