How this site is organized
The navigation on this site is a build artifact. Every layout you can switch to from the homepage renders from one JSON file, /manifest.json, and that file is public. If you want to check whether the views agree with each other, you can diff them against the same source I do.
The file exists because I lost an argument with myself. This site had grown to 78 routes behind a five-item nav, and a single system would end up scattered across four shelves: the finance engine was a case study in one place, a tool in another, live data in a third, and essays in a fourth, with nothing connecting them. I spent an afternoon rejecting homepage designs. Doors named after subjects. Doors named after verbs. Doors named after how proven each piece of work is. Each one fixed the scattering by decreeing a taxonomy, and each one felt wrong for the same reason: no single taxonomy deserves to own the front door of work that cuts across categories.
The version that survived stopped picking. Store the metadata once, then let every navigation scheme be a projection. Each artifact on the site (a case study, an essay, a tool, a dataset, a visualization, a game) has one manifest entry: what it is, which field it belongs to, which system it is part of, how proven it is, whether it is still running. The homepage renders a default view over that graph, and a switcher offers the others. A faceted catalog where clicking any label on a card pivots the whole filter. A scatter plot with proof on one axis and machine-versus-human scale on the other. A grouping by system. None of them is the site. They are all renderings of the manifest, and adding an artifact once populates every view.
The views are held together by the contracts underneath them, because a projection system rots the moment the projections drift from the source. A CI script walks the static export after every build and fails if any content route is missing from the manifest, or any manifest entry points at a route that does not exist. Another check compresses the manifest and fails the build past a size budget. The epistemic labels (production, on the record, in progress, experiment) are one enum defined once, and a test computes WCAG contrast ratios for their colors in both themes from the actual token values, because the first amber I picked measured 3.37 to 1 as text and failed the standard. The border carries the amber now; the text stays ink.
The checks earn their keep by being embarrassing. The first time the chunk-budget check ran, it measured the "lazy-loaded" views at zero extra bytes each. That number looked like a pass and was actually the failure: nothing was split, and every visitor was downloading every view because all of them lived in one client bundle behind the switcher. The fix moved each view to its own route module, and the check now fails on zero, since a lazily loaded view that adds no bytes means the laziness is fiction. The shared bundle is still heavier than the budget I wrote in the spec, and the check says so on every build instead of letting me forget.
Private surfaces get the same treatment with less exposure. A few tools on this site sit behind a login because they touch my own portfolio state. They appear in the graph as locked entries so the views can show they exist, but the manifest serializer builds their public projection from an allowlist of fields rather than deleting the sensitive ones, and a regression test iterates the actual keys of every private entry so a future field stays private by default. Publishing the graph forced that discipline. A file nobody can fetch can be sloppy; a file at a public URL cannot.
If you run a site, a docs tree, or an internal portal with more than one defensible way to slice it, the pattern transfers directly. One typed source of truth, projections instead of taxonomies, and a check that fails the build when the two disagree.
Questions this post answers
- How can a site support several navigation schemes without choosing one taxonomy?
- My site had 78 routes behind a five-item navigation, and one system could be scattered across four shelves. I now store each artifact once in a public manifest with its type, field, system, proof status, and operating status. Every navigation scheme is a projection of that manifest, so adding one entry populates every view.
- How do you keep a public manifest and site routes from drifting apart?
- My CI walks the static export after every build and fails if a content route is missing from the manifest or a manifest entry points to a route that does not exist. A separate check compresses the manifest and fails the build when it exceeds its size budget.
- Why should a lazy-loaded route fail a check when it adds zero bytes?
- My first chunk-budget result reported zero extra bytes for every supposedly lazy-loaded view because none of the views had actually been split from the main client bundle. I moved each view into its own route module and changed the check so zero extra bytes is a failure rather than a pass.
- How do you publish a site manifest without leaking private fields?
- I keep locked entries in the public graph so readers can see that the private tools exist, but the serializer builds their public form from an allowlist. A regression test inspects the actual keys on every private entry, so a newly added field stays private unless it is explicitly approved.