Reindex behind an alias that swaps atomically

Every application should read and write through an alias rather than an index name, which turns a mapping change from an outage into a swap.

POST /_reindex
{ "source": { "index": "products-v3" },
  "dest":   { "index": "products-v4" } }

POST /_aliases
{ "actions": [
  { "remove": { "index": "products-v3", "alias": "products" } },
  { "add":    { "index": "products-v4", "alias": "products" } }
] }

# both actions in one request: atomic. no window.

The two actions in a single request is what makes it atomic — doing them as two requests leaves a moment with no index behind the alias, which is a burst of 404s. Writes during the reindex are the remaining problem and need either a dual-write window or a second pass over anything modified since the reindex started.