You added an index, re-ran EXPLAIN, and now you want the obvious answer: did the plan actually change? So you diff the two outputs as text. And it lights up red everywhere — because cost= and rows= shift on nearly every line, even when the strategy is identical. The one line you cared about — Seq Scan on orders becoming Index Scan using orders_created_idx on orders — is buried in a wall of numeric churn.

Text is the wrong representation. An EXPLAIN plan is a tree, and the question "what changed?" is a tree-diff, not a string-diff.

Get the tree, not the text

EXPLAIN (FORMAT JSON) hands you the plan as structured data instead of pretty-printed lines. Parse it into a small node type — node kind, the table, estimated rows, cost, and children:

@dataclass