A pipeline that fails fast is a pipeline people trust

A twelve-minute pipeline that reports a lint failure at minute eleven trains people to push and switch tasks, which is the opposite of what CI is for.

stages: [check, test, build, deploy]

lint:
  stage: check           # 40 seconds
  script: [vendor/bin/phpcs --report=summary, vendor/bin/phpstan]

unit:
  stage: test            # 2 minutes

integration:
  stage: test            # 6 minutes, in parallel with unit

# cheapest and most likely to fail, first.

Ordering by cost-to-run rather than by conceptual grouping is the whole technique, and it is free. The measure worth tracking is time-to-first-failure rather than total pipeline duration — a pipeline that takes twelve minutes to succeed and forty seconds to fail is a good pipeline. Running the two test suites in parallel within a stage costs nothing extra when the runners are there and is the other easy win.