The site is a Flutter web app on Firebase Hosting. It used the webframeworks experiment, which has the Firebase CLI build the app for you.
The constraint: The app calls usePathUrlStrategy(), so /projects is a client-side route with no file behind it. The webframeworks path shipped no SPA rewrite, so hosting looked for a file that didn't exist and returned 404, but only on a direct load or a refresh. Navigating there from the home page worked perfectly, because that never touches the server.
The decision: Move to plain static hosting: serve build/web with an explicit "**" -> "/index.html" rewrite. That makes the rewrite a line in firebase.json that can be read, rather than a behaviour of a CLI experiment.
What I rejected, and why: Keeping webframeworks and adding a rewrite alongside it. It would probably have worked, but it keeps a build step inside a deploy tool: two builds per release instead of one, and a dependency on an experimental flag for the thing that puts the site on the internet.
What it cost:
Deep links returned 200 instead of 404, verified per route, not assumed.
One build per deploy instead of two.
One experimental CLI flag removed from the release path.
What I'd do differently: I would have checked the failure mode before choosing the fix. This bug was invisible from inside the app and obvious from outside it, and the thing that would have caught it is a curl against each route in CI, which is about four lines and still isn't there.