Meta · a map that can't drift from its territory
A pattern from the gf.cx specimen book
The map the library draws of itself
A human sitemap page for the pattern library — but one whose structure and counts are generated from the library itself, so the map can never quietly disagree with the territory.
"A sitemap hand-maintained beside a growing corpus is a drift source waiting to happen. Generate the map from the corpus's own meta.json, and make the generator refuse to ship until every pattern is categorised."
See it live → /sitemap/ The generator → patterns_sitemap_render.py
The problem
The library wanted a front-page ledger — a dare.co.uk/sitemap-style three-column picture of what's held, grouped into playbooks with per-family counts. The obvious way to build it is to hand-write the columns and type the numbers. That is a second source of truth. The day a new pattern ships, the hand-typed map is silently wrong: it still says "9" where the family now holds 10, and nobody notices because nothing failed.
The shape
- Structure lives in one place. A single
TAXONOMYin the generator maps every pattern slug into exactly one playbook → family. That ordered structure is the whole design surface. - Counts are derived, never typed. The generator scans every
*/meta.jsonin the repo and computes each family / playbook / grand total from the mapping. The lede's "N patterns" islen(), not a literal. - A fail-loud validator is the anti-drift guard. Before emitting, the generator asserts that every meta.json slug is mapped exactly once, and every mapped slug has a meta.json. Any mismatch → non-zero exit, names the offending slug, no page written. Ship a new pattern without categorising it and the build stops until you do.
- Type is on-standard by construction. The emitted
<head>links the real web fonts +page-header.css; the masthead (h1/.kicker/.lede/em) comes straight from the shelf, never restyled.
The self-reference
This pattern is itself in the taxonomy — it sits in Foundation → Meta. So adding this page's meta.json moved the library from 27 to 28 patterns, and the generator counted it into its own Meta family automatically. The sitemap documents the library, and the library contains the sitemap: the map is part of the territory it maps.
When it breaks
- Hand-editing
sitemap/index.html. It is generated output. Any manual change is drift by construction and is overwritten on the next run. - Special-casing a slug past the validator. The guard only works if it applies to every slug uniformly. An exception is a hole the drift walks through.
- Typing a count anywhere. The moment a number is a literal rather than a
len(), the single source has forked.
Where it applies
- Use when a human index / ledger / sitemap sits beside a machine-readable corpus that grows — generate the index from the corpus, don't maintain it in parallel.
- Use when you want new entries to be forced into a category — a fail-loud validator turns "please remember to file it" into a build gate.
- Skip for a small, static list that will not grow — the generator's overhead is not worth it below a handful of items.
Reusable elements
tools/patterns_sitemap_render.py— the generator: orderedTAXONOMY, meta.json discovery, fail-loud validator, template-faithful HTML emitter, stderr counts summary.- The taxonomy-validator shape — "every corpus item mapped exactly once; every mapping backed by a corpus item; else exit non-zero." Portable to any generated index over a slug-keyed corpus.
- The dare/sitemap ledger form — three columns (numbered playbooks) of family rows, each a name + drift subtitle +
· Ncount, onpage-header.csstype.
Reference
- Live page
- patterns.gf.cx/sitemap/ — "The shape of the archive".
- Generator
tools/patterns_sitemap_render.py— run from the repo root; writessitemap/index.html.- Sibling
- Surface assembled from patterns — the same single-source discipline applied to a whole surface rather than an index.
- Form
- Mirrors dare.co.uk/sitemap's three-column ledger.