Commit Graph
8 Commits
Author SHA1 Message Date
istos a1b17c85cf merge main into task/36: the board shot and the reference section
One conflict, in the 480px block of site.css: main added the landing
page's .shot rules there while this branch widened the prose padding
selector to cover .page-reference. Both belong — the shot is home-only,
the padding is every long-form layout — so the resolution keeps main's
two rules and the branch's wider selector.

Everything else merged clean: the reference layout, its four routes and
the settings parser do not touch what the landing page changed.
2026-07-31 16:34:24 +02:00
istosandClaude Opus 5 38745ae0b3 site: add the reference section, generated from the settings file
The third design layout (1c Logbook) had no page. This lands it, and
with it the four routes a reader reaches for when the guides have
stopped answering: /reference/settings and the three contracts a
project implements against.

The settings page is parsed, not transcribed. site/build.py grows a
second way to make a body — a page may say "generate": "settings"
instead of a "from" heading — and manager/core/.env.example is read on
every build: its blank-line blocks become the page's entries, a comment
block documents the keys directly under it, and the file's own
NAME=value lines are the defaults shown. A key with no comment above it,
or one set twice, stops the build naming the route; a settings page that
disagrees with the settings file is worse than no settings page.

Generated bodies render with raw HTML off. The file writes
<git user.name> meaning a placeholder, and a parser honouring HTML
swallows it — it was never written to be markdown.

The reference layout is the article's three columns with the contents
gutter given over to a console: every entry on the page once more in the
machine register, keys with their defaults on the settings page and
headings on a sliced one. It links the same anchors "On this page"
carries, so the 1080px step folds the whole column away and the contents
strip hands them back — no third copy of anything, and the responsive
rules already in the sheet cover it.

The contract pages are slices like every other page: the adapter
contract and its event schema out of manager/core/adapters/README.md,
the driver and local-command contracts out of AGENTS.md. Renaming any of
those headings stops the build naming its route.

tests/test_site_reference.py holds the promise: add a key to
.env.example with its comment, rebuild, and it is on the page with its
default, with nothing in site/ edited.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 16:28:53 +02:00
istos ea93a2479d site: put the board above the fold
The page claimed 'mission control' and showed a terminal. It now shows
the board itself, directly under the hero, on bench's own repo with
three agents working — the claim demonstrated rather than described.

The terminal gives up the height for it: the .env preamble and the
Ctrl-C line go, the install command and the three setup questions stay.
tests/test_site_landing.py's TRANSCRIPT follows, and still holds every
remaining line against the source that prints it.

The shot goes through stamp() like the stylesheet, so its url carries a
?v=<hash>. Without that, /static/*'s year-long immutable cache would
make the screenshot unreplaceable. 1600px wide and palettised to 256
colours — 164K rather than 452K, and a flat dark UI loses nothing to it.

img{max-width:100%} is now a base rule rather than only .prose img: the
shot lives outside the article body, where that rule never reached.
2026-07-31 16:27:02 +02:00
istos d5c999fa79 site: keep maintainers' notes out of the build
The host uploads the assets directory whole, so a .md left in static/
becomes a public url — static/fonts/README.md was live, telling readers
how to refresh fonts they cannot write to. copy_static skips it, and
internal_targets skips it too: the link checker and the copier have to
agree, or a link to a skipped file would pass the build and 404 on the
site. The licences are .txt and still ship, which is the point of
committing them.

Card 43 records the other thing today's run turned up: the suite reads
the developer's own local/.env, so two sync tests fail here and pass in
CI.
2026-07-31 15:56:02 +02:00
istosandClaude Opus 5 7ab45f49fd site: the guides and concept pages, in the 1a Harbour layout
Fills the middle of the site. Nine routes, every body a heading slice of
AGENTS.md or README.md, and the article layout given the furniture the
design calls for.

The manifest gains the two concepts nothing covered: /concepts/task-files/
(the header format, from AGENTS.md's own section) and /concepts/adapters/
(the adapter summary, which is the other half of the three-layer law).
/concepts/stages/ now runs through "Moving a task", because the five
directories and moving between them are one idea.

The layout:

- A lede under the title — the one sentence an article authors, taken
  from the manifest's `description` or an explicit `lede` where the two
  want different words. A slice starts mid-document; a reader arriving
  from the nav is owed a line saying what they are looking at.
- Prev/next at the foot, walking the sidebar's own order so the arrows
  and the rail cannot disagree. Pages with no section (the landing page,
  the 404) are not on the flow.
- "Edit this page on GitHub" anchors to the section the page was cut
  from, built from the same `from` heading the slice starts at.

Two bugs the new pages found:

- string.Template substitutes inside HTML comments, so a comment naming
  the body placeholder emitted the whole body twice and closed itself
  early on the first `-->` in it.
- Promotion could produce a second <h1>. A slice that deliberately runs
  past its own section carries headings at the `from` level, and those
  promoted to h1 on a page that already had one. Promotion now stops at
  h2, where they read as peers — which is what putting them on one page
  said in the first place.

tests/test_site_pages.py covers the furniture on the real built site:
the routes, the layout, the sidebar marking one page, the contents list
being exactly the body's own h2s in order, the prev/next chain end to
end, the edit link's anchor, the six landing-page doors, and a table, a
fenced block and a nested list surviving the renderer. The scratch-repo
helper now copies every file a slice links to, since the builder checks
those exist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 14:29:49 +02:00
istosandClaude Opus 5 274ad6b2c6 site: the landing page, on things bench really does
Turn design 1b (Dockside) into `/`: a terminal hero, the claim README.md
already makes, six doors, and a strip at the foot. The layout is task
31's; what this commit is really about is that nothing factual on the
page is typed by hand.

- **Two facts are read, not written.** `site/build.py` reads the install
  one-liner out of README.md's "Install into a repo" block and the
  version out of `manager/core/VERSION`, and offers them to the template
  as `$install_block` and `$version`. A renamed section, a missing
  VERSION or an install section that lost its command block stops the
  build, exactly as a renamed heading already did. `pages.json` loses
  its `version` key, and a build refuses one if it comes back.

- **A dead internal link stops the build.** Every href a rendered page
  emits — a door as much as a link inside a slice — must resolve to a
  route in the manifest or a file in `static/`/`root/`. The check runs
  after rendering and before writing, so a bad link leaves the last good
  build standing rather than shipping a 404 with a nice typeface.

- **Six real doors.** `pages.json` grows the routes they open: install
  and first run, the five stages, agents on the board, PRs and review,
  team mode, the three-layer law. They are heading slices, i.e. the
  stub routes task 33 expected and task 34 will re-cut.

- **The terminal is a transcript.** README.md's own command, then lines
  install.py and board.py really print, with the abridgement declared in
  the terminal's title bar. `tests/test_site_landing.py` holds every one
  of those lines against the source that prints it, so a reworded prompt
  fails the suite instead of quietly making the page fiction.

- **No fake telemetry.** Turn 1's "most opened this week" strip becomes
  the version, read from VERSION, and a link to the releases.

The landing page no longer carries a generated body, so the tests that
read one from it now read `/concepts/stages/`, and the two scratch repos
in the suite copy VERSION alongside the markdown.

python3 -m unittest: 407 tests, OK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 12:10:25 +02:00
istosandClaude Opus 5 ad639a33d3 site: a 404 page, a root/ tree, and stamped asset urls
Three things the build owed the host before the site could have an
address, all of them visible in site/dist/ rather than in a deploy
script.

A 404 page. Cloudflare's not-found handling serves a literal 404.html
from the root of the assets directory, so a route may now name an .html
file instead of ending in "/" — the one that does is /404.html, a normal
manifest entry with its own layout. It is the site's design and the
site's nav, with a way back to the landing page, a noindex and no
canonical. A null section keeps it off the nav it renders.

site/root/, copied verbatim to the TOP of the build the way static/ is
copied to a subdirectory of it. _headers is what it holds; the host
reads that file from the root and nowhere else. A file in root/ that a
route would also write stops the build rather than letting one silently
win.

Stamped urls for the stylesheet and the icon: the templates link them
through $stylesheet and $icon, which carry a ?v=<hash> of the file's own
contents. Nothing in static/ is renamed, so the tree and the /static/*
glob stay as they were — but the url changes when the file does, which
is what will make a year-long immutable cache safe.

Tests ask the builder where a route lands rather than keeping their own
copy of the rule.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 11:46:56 +02:00
istosandClaude Opus 5 62caafe157 site: a minisite generated from the repo's own markdown
bench has no public page. site/ is the machinery for one: a manifest,
a generator, two layouts from the turn-2 docs design, and the Daylight
half of the board's own token set.

Nothing here is transcribed. Every page body is a heading slice of a
file that already documents bench, and site/pages.json is the only
place that mapping is written down — the IA is editorial judgement, so
it lives in one readable file rather than in a directory convention.

The point is the failure: a from/to heading the source no longer
contains stops the build naming the route, the file and the heading,
and every page renders before the output directory is touched, so a
drifting rebuild leaves the last good build standing instead of
replacing it with an empty one. Repo-relative links come out as site
routes or GitHub links; a dead one stops the build too.

Rendering is markdown-it-py, pinned in site/requirements.txt. The
stdlib-only law binds manager/core/ — the tool people install — and
site/ is neither shipped nor installed, so a hand-rolled parser would
have been risk spent in the wrong place on a document that leans on
fenced code, nested lists and inline code throughout.

Templates are string.Template: $name substitutes and a literal dollar
doubles, because str.format's braces collide with every line of CSS.

Fonts are self-hosted and same-origin: no page bench serves may need a
request to a third party to be read. fetch-fonts.py downloads the seven
woff2 files once; until they are there the build says which are missing
and the pages fall back to the system stack.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 11:30:34 +02:00