What deploying my garden taught me about routing

The garden is live. Getting it there taught me something I had not thought about while building it locally: a single-page app and its own build output can quietly compete for the same URLs, and the dev server is too forgiving to tell you.

The collision

The compiler wrote its JSON into public/garden/. The app reads notes at /garden/<slug>. Locally, both worked, so I never questioned it. But a static host resolves the filesystem before it applies a rewrite, and /garden was a real directory with no index.html in it. So the request matched something, found nothing to serve, and never fell through to the app. The garden listing, the most-used page on the site, would have 404'd in production while working perfectly on my machine.

I found it by refusing to trust the dev server: I served the built dist/ the way the host would, filesystem first and rewrite second, and walked every route. The fix was not a clever rewrite rule. It was removing the ambiguity, moving compiled data to /garden-data/ so app routes and build output can never shadow each other.

What I'd tell myself before the next deploy

This note is also the first real test of the thing I built: it reached the live site by being a file in a folder, with no other change to the project. That was the whole promise of the compiler and of the garden itself. If publishing had needed anything more than a commit, the design would have been wrong.

The habit of checking the built artifact rather than the friendly local one is the same instinct that Spec-driven development with OpenSpec and AI agents enforces on the other end: decide what the system must do, then go and verify it actually does that, in the place it really runs.