Aggregation order is not promised — the engine feeds rows to the aggregate in whatever order the plan produced, and for SUM that's invisible, but for order-sensitive aggregates (string concatenation, array_agg) the output silently encodes scan order. The fix is the aggregate-internal ORDER BY with a unique tiebreaker; the habit is a question: does this aggregate's output depend on row order?
SELECT string_agg( f, ' -> ' ) AS lineup FROM floats;
SELECT string_agg( f, ' -> ' ORDER BY f ) AS lineup FROM floats;
The parade lineup banner flickered between refreshes though nothing wrote — string_agg without an internal ORDER BY concatenates in whatever order the plan produced, so the same rows yield different strings; string_agg(f, ... ORDER BY f) is stable.
string_agg(x, sep ORDER BY key, tiebreak); same for array_agg; audit every order-sensitive aggregate in anything diffed or cached.