You're right that there's a finely tuned choreography between disk, the buffer pool and the write-ahead log. Each part has to work with the others to guarantee consistent recovery after an un-planned shutdown. There are many choices to make and the sequence in which actions occur is critical to the success of the whole.
Most DBMS follow a protocol called ARIES published by IBM in 1992. Certainly SQL Server does. There's a readable overview here. This protocol's steps differ a little from the question's bullet points.
Somewhere before acknowledgement is sent to the user in step 5 the transaction has to be committed. This can be explicit (COMMIT statement) or implied (at the end of a statement without an explicit BEGIN TRANSACTION). At this point the write-ahead log records are forced to disk.
Log records are written to disk when the log buffers are flushed. This happens whenever a transaction commits or the log buffers become full.
As well as "before" and "after" copies of the changed data the log also receives "transaction start" and "transaction commit" records. Each log record has a Log Sequence Number (LSN). As data changes are written to the log the corresponding LSN is written to the data page in the buffer pool. Only the most recent LSN is required in each page. (You can read this value.)
During a checkpoint not only are dirty pages flushed, the fact a checkpoint happened is also written to the log and flushed. From a previous reference: "SQL Server has logic that prevents a dirty page from being flushed before the associated log record is written."
To answer the actual question - what if there's a failure before the dirty page can be checkpointed? On restart, the system reads the log. It discovers that there was a transaction, that wrote to our page, and committed. It can read the required page back into the buffer pool. Because the just-read page contains the LSN of the most recent change made to it, the system knows what log records to re-apply -- everything after the page's LSN. Those records are re-applied and the transaction commited. Now the buffer pool contains our page as it was after our data change was made but before the outage.
In a similar way the protocol can deal with pages that were checkpointed while transactions that dirtied them were still open when the system failed, and with transactions that were rolled back before a checkpoint hardened the affected pages to disk.
There are a lot of details I've skimmed over and many corner cases that the full protocol handles (a second power loss while recovering from the first power loss?).
SQL Server 2019 introduced Accelerated Database Recovery which improves on ARIES to reduce the time required to recover from failure.