Adding ORDER BY to a window changes what the aggregate means, because it changes the default frame from the whole partition to everything up to the current row.
-- the customer's total
SUM(total_cents) OVER (PARTITION BY customer_id)
-- a RUNNING total — the ORDER BY did that, silently
SUM(total_cents) OVER (PARTITION BY customer_id ORDER BY placed_at)
-- so say it, every time
SUM(total_cents) OVER (
PARTITION BY customer_id ORDER BY placed_at, id
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
Ordering changing the meaning of an aggregate happens nowhere else in SQL, which is why this catches people who otherwise know the language well. Writing the frame explicitly costs three words and removes the ambiguity for every future reader. The tiebreaker in the ordering matters as much: two rows with the same timestamp produce a non-deterministic running total, which is a report that differs between runs on unchanged data.