I need dev time to make the builds understand their inputs, and then cache more aggressively than we are, or something. (But I lack the dev time.)
caching and promoting images is an absolute must. caching images has it's downsides, too though. it can be a longer time period between when something in the dockerfile breaks and when it's noticed.
generally speaking, my pipeline is generally 10-40% build time, 50-60% integration & system test time, 10% deployment time
The system tests that're run deploy the entire dependency graph of services that my project depends on, which can take a bit to settle, has a high chance of transient failures relative to other parts of the pipeline, and notably has a fixed test run time.
That last bit really raises the lower bound for how long the pipeline as a whole takes -- number of runners doesn't matter.
The pipeline generally takes between 25-45 minutes, and runs on each push and is triggered by changes to dependencies to ensure backwards compatibility.
I wouldn't do anything to make it take longer than it does now, and it can be frustrating. but the pipeline will catch things that would otherwise slip through the cracks.
E.g. we went with that route with GH Actions, until our tests didn't fit into the memory of the provided machine sizes anymore (shouldn't be a problem anymore as GH provides options for bigger runners now). So we had to spend 1-2 days on setting up a self-hosted runner in a way that it wouldn't be too heavy in maintenance, and then probably another 1-2 days of rework over the next few weeks to iron out the kinks.