feat: hold the site to page and index budgets

validate_site.py fails a page over 1 MB of HTML, a search index over
8.5 MB (1.7 MB gzip), a skipped heading level, a table header without
text, a script from another host and a diagram drawn at runtime. The
limits sit above what the site now measures (0.88 MB, 7.2 MB, 1.43 MB),
each with its reason, and each has a test.
This commit is contained in:
Abdessamad Derraz committed 2026-10-22 13:13:55 +02:00
1 parent 36ac7b0cd6
commit be5be996db
5 files changed
+166 -12

No files matched your search

+26 -8
View File
@@ -71,14 +71,32 @@ dist/ generated packs (gitignored)
Documentation changes belong in `wiki/` or in the generator.
The site search splits each page at its headings and sends a result to the
heading above the match. Every file card is therefore a level 4 heading with
the card's anchor, and every platform system a heading of its own: a hash
pasted in the search opens that card or that system, not the top of the page.
Level 4 stays out of the table of contents (`toc_depth: 3`). The lines that
list other pages (platforms, packs, source citations, collection paths) sit
in a `data-search-exclude` block, since the browser downloads and indexes the
whole search index before it shows a first result. File names, hashes, the
paths an emulator reads and the notes stay searchable.
heading above the match. Every file card is therefore a level 3 heading with
the card's anchor, under its console or a Files heading, and every platform
system a heading of its own: a file name typed in the search opens that card,
not the top of the page. On pages of cards (systems, emulators, platforms) the
table of contents stops at level 2 (`scripts/mkdocs_hooks.py`).
The browser downloads and indexes the whole search index before it shows a
first result, so the index holds names and prose only. Hashes, lists of other
pages, install commands, member tables and long reference tables sit in
`data-search-exclude` blocks. Those blocks are `section` elements: the search
plugin compares elements by tag, and a `div` stopped excluding at the first
`div` closed inside it. A hash goes to [Find a file](../files/index.md), which
reads one shard of `api/v1/lookup/` named by the first two characters of the
value.
A page has a budget. A manufacturer page over 500 KB of Markdown becomes a
summary: its largest consoles move to pages of their own, cut into parts when
one console alone is over the budget, and every console keeps its heading on
the summary. An emulator with more than 400 entries (MAME) lists them in a
table on its page, each row holding the old anchor of the card, and the cards
move to pages of 400. A platform system whose list is over 200 KB moves to a
page of its own. A card anchor (`#sha1-...`) that a page no longer holds is
looked up by content, so a link cited before a split still opens the card.
`validate_site.py` fails a page over 1 MB of HTML, a search index over 8.5 MB
(1.7 MB compressed), a skipped heading level, a table header without text, a
script from another host and a diagram drawn at runtime.
## Data flow
+2 -1
View File
@@ -54,7 +54,8 @@ is missing.
6. Run `generate_readme.py` (rebuilds README.md and CONTRIBUTING.md)
7. `mkdocs build --strict` to produce the static site
8. Run `validate_site.py` on the rendered HTML (metadata, headings, image
alternatives, duplicate ids, local links and fragments)
alternatives, duplicate ids, local links and fragments, page and search
index budgets)
9. Require the committed README and CONTRIBUTING to match what the generator
just produced. `write_if_changed()` compares content with the timestamp line
stripped, so a run that only moves the clock leaves the files untouched and
+1 -1
View File
@@ -692,7 +692,7 @@ python scripts/refresh_stale.py --only platforms,targets --jobs 6
| `find_pinned_revision.py` | Walk the upstream commits that touched a file and return the revision whose bytes match a platform's pinned md5 (`--write` saves them) |
| `generate_readme.py` | Generate README.md and CONTRIBUTING.md from database |
| `generate_site.py` | Generate all MkDocs site pages (this documentation) |
| `validate_site.py` | Validate rendered metadata, headings, image alternatives, JSON-LD, local resources, links and fragments |
| `validate_site.py` | Validate rendered metadata, heading order, image alternatives, JSON-LD, local resources, links and fragments, and the page size and search index budgets |
| `romset_recipes.py` | Identify which emulator version an arcade archive matches, and rebuild a pinned archive from ROMs already held |
| `scraper/romset_dat_importer.py` | Fetch and import per-set recipes from MAME `-listxml` or FBNeo DATs into `recipes/`. `--fetch` alone takes the newest MAME release, and FBNeo DATs are refreshed by git blob sha. `--fetch <revision>` reads FBNeo at that tag, branch or commit |
| `deterministic_zip.py` | Rebuild MAME BIOS ZIPs deterministically (same ROMs = same hash) |