# Static files are served first by Cloudflare Pages; these rules apply only to
# paths with no matching static asset. Known content routes (e.g. /blog/<slug>/)
# have their own generated index.html and are served directly. Unknown routes fall
# back to the SPA shell for client-side routing (progressive enhancement, ADR-0005).
#
# ORDERING IS LOAD-BEARING: Cloudflare Pages evaluates this file top-down and stops
# at the first match, so `/*  /index.html  200` MUST stay last or nothing below it
# ever runs. `site_generator/tests/route_aliases.rs` asserts that.
#
# The seventeen route aliases that lived above the catch-all were retired on
# 2026-08-03 (#468, ADR-0026): one URL per page. That decision stands, and the 301s
# below are not a step back towards it. An alias is a SECOND live URL for a page that
# also answers at its canonical one; a move is one URL replacing another. Nothing is
# emitted at /tools/stego/ any more, so this rule creates no second address — it
# forwards a path that stopped existing. `site_generator/tests/moved_routes.rs`
# holds every rule here to exactly that: a dead source, a live destination, and a
# position above the catch-all.
#
# Moved pages (#619, owner decision 2026-08-11):
/tools/stego/  /learn/stego/  301
#
# A RETIREMENT is the third case, and it is not a move. A move forwards to the same
# page at a new route; a retirement forwards to the SECTION INDEX, because the page
# it names no longer exists anywhere — the toy, its core, its component and its
# tests are all gone. The nearest truthful answer to an old link is the shelf the
# element used to stand on, so the destination is /toys/ rather than a stub saying
# it is sorry. Held to the same three rules as a move (dead source, live
# destination, above the catch-all) by the same guard, which additionally asserts
# that a retired element is in NO registry at all.
#
# Retired elements (#646, owner decision 2026-08-17):
/toys/signal-box/  /toys/  301
/assets/*  /assets/:splat  200
/*  /index.html  200
