PostgreSQL ORDER BY clause effect different number of rows to return in pivot table
Omitting the ORDER BY goes against what the documentation recommends:


  In practice the source_sql query should always specify ORDER BY 1 to
  ensure that values with the same row_name are brought together


This ORDER BY is a requirement of the algorithm inside crosstab() because it's counting on identical values being contiguous. What happens inside crosstab() is a black blox as far as the executor of the main query is concerned. It doesn't know and doesn't care that this algorithm is sensitive to the order of the rows inside crosstab. To start with, it doesn't know that the arguments passed to crosstab() are queries. These queries are executed by a different instance of the executor, as dynamic SQL. It seems that your reasoning in the question is ignoring that, which is why you see properties in this query that are unusual in normal SQL queries, which don't involve embedding dynamic SQL.