diff --git a/tasks/in-progress/31-minisite-skeleton-and-build.md b/tasks/in-progress/31-minisite-skeleton-and-build.md new file mode 100644 index 0000000..f196260 --- /dev/null +++ b/tasks/in-progress/31-minisite-skeleton-and-build.md @@ -0,0 +1,108 @@ +# 31 — Stand up site/ and generate its pages from the repo's own markdown + +**Status:** In Progress +**Assignee:** istos +**Priority:** High — nothing else about the site can start until there is a +build and a place to put pages +**Type:** Feature + +bench has no public page. Add a `site/` directory holding a minisite whose +content is *generated* from the files that already define bench — so a +documented behaviour and the behaviour itself cannot drift apart. This card +is the machinery and the visual foundation; the pages themselves are 33 +and 34. + +## Context + +- The site is served from Cloudflare Workers at `bench.12vectors.com` + (task 32). This card only has to produce a directory of static files. +- `site/` must never reach a host repo. Releases ship exactly what + `../../manager/core/release-manifest` lists and nothing else ("Anything + not listed here does not ship"), so adding `site/` to the repo root is + free — but the artifact test should say so out loud rather than leave + it to inference. +- Content sources, all already maintained: `../../AGENTS.md` (the + workflow brief and the concepts), `../../README.md` (install, update, + the three-layer law), `../../manager/core/.env.example` (settings), + `../../manager/core/adapters/README.md` (the adapter contract). +- The design to build against is task 30's turn 2 of `Bench Docs.dc.html` + in the design project — its Daylight palette, IBM Plex Sans/Mono and + Zilla Slab display face are the visual contract. + +**Affected areas:** a new top-level `site/`, plus `.gitignore` and the +artifact test in `tests/`. No `manager/` code changes. + +## What to build + +- **`site/build.py`** — reads a manifest, renders pages into + `site/dist/`, copies `site/static/` alongside. One command, no + arguments needed: `python3 site/build.py`. +- **`site/pages.json`** — the manifest, and the only place the site's IA + is written down. One entry per route: `path`, `title`, `layout`, + `source` (a repo-relative markdown file) and the heading slice to take + from it (`from` heading, optional `to`). A landing page whose body is + authored rather than sliced says so with `source: null`. +- **Loud drift detection.** A `from`/`to` heading the source no longer + contains fails the build with the route, the file and the missing + heading named. That failure is the whole point of generating: renaming + a section in `AGENTS.md` must break the site build, not silently drop + a page. +- **Templates** in `site/templates/`, one per layout from the design + (`home`, `article` to start). Substitution uses `string.Template`'s + `$name` placeholders — not `str.format`, whose braces collide with + every line of CSS in the file. +- **Markdown rendering** via a pinned third-party library in + `site/requirements.txt` (`markdown-it-py` unless the implementer has a + better one), not a hand-rolled parser: `AGENTS.md` leans on tables, + fenced code, nested lists and inline code, and getting those subtly + wrong is a bad place to spend risk. The stdlib-only law binds + `manager/core/` — the tool people install — and `site/` is neither + shipped nor installed. +- **`site/static/site.css`** — the Daylight token set, named as + `board.html` names its own (`--accent`, `--calm`, `--alarm`, `--idle`) + so the two surfaces stay one system, plus the type scale from the + design. +- **Self-hosted fonts** in `site/static/fonts/` (woff2, subset): the + design links Google Fonts, which the shipped site must not — no + third-party request should be needed to read bench's docs. +- **Rewritten links.** Markdown that links between repo files + (`manager/core/adapters/README.md`, `../../plans/…`) must come out as + working site routes or GitHub links, never as dead relative paths. + +**Out of scope** — tempting neighbours left alone: + +- Deployment, `wrangler`, DNS — all of task 32. +- The landing page's authored content (33) and the guide/concept page + set (34). Ship this card with one placeholder route each, enough to + prove both layouts render. +- Search, a changelog, versioned docs. + +## Acceptance + +- [ ] `python3 site/build.py` on a clean checkout writes `site/dist/` + with a page per `pages.json` entry, and exits non-zero with a + readable message if a source file or a named heading is missing. +- [ ] Given a heading renamed in `AGENTS.md`, when the build runs, then + it fails naming the route and the heading — it does not emit a + page with an empty body. +- [ ] The built pages make no third-party network requests: fonts, CSS + and any script are same-origin, verified with the network tab open. +- [ ] `site/dist/` is gitignored; `site/` sources are committed. +- [ ] The release artifact test asserts `site/` is absent from + `bench.tar.gz`, so a future manifest edit cannot ship it by + accident. +- [ ] Both layout templates render with real content from `AGENTS.md`, + not lorem — one home route and one article route is enough here. + +## Notes + +The IA is deliberately a manifest rather than convention-over-directory: +the pages are slices of documents written for another purpose, and the +mapping between "a section of AGENTS.md" and "a page of the site" is +editorial judgement that deserves to be visible in one file. + +**Risks** — `AGENTS.md` is written for an agent working inside an +installed project ("read it too", "this file"). Some sections will read +oddly in public. Where a slice cannot stand alone, the fix is to improve +`AGENTS.md` — it is read by more agents than people — not to fork the +prose into the site.