Files
bench/tests/test_site_reference.py
T
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

561 lines
25 KiB
Python

"""The reference section: /reference/settings and the three contract
pages, in the 1c Logbook layout.
The other site suites are about slices — a heading renamed in AGENTS.md
stops the build. This one is about the promise a *settings* page makes,
which is stronger and easier to break quietly: the page is not written,
it is read out of `manager/core/.env.example`, so a key added there
appears here with nobody editing site/, and a key documented nowhere
fails the build rather than reaching the site bare.
The rest is the layout: the pinned console carries the page's own
entries and nothing it invented, and a reference page keeps every piece
of furniture an article has — the sidebar, the folded menus, prev/next
and "Edit this page".
python3 -m unittest discover -s tests
"""
import json
import re
import shutil
import tempfile
import unittest
from pathlib import Path
from tests.test_site_build import (BUILDER, HAS_MARKDOWN_IT, REPO, SITE,
ScratchCase, needs_renderer, run_build)
ENV_EXAMPLE = "manager/core/.env.example"
CONSOLE_LINE = re.compile(
r'<a class="console-line" href="#([^"]+)">(.*?)</a>', re.S)
CONSOLE_KEY = re.compile(r'<span class="console-key">([^<]*)</span>')
CONSOLE_VALUE = re.compile(r'<span class="console-value">([^<]*)</span>')
HEADING_ID = re.compile(r'<h2 id="([^"]+)">(.*?)</h2>', re.S)
SIDE_HERE = re.compile(r'class="side-link side-here" href="([^"]+)"')
NAV = re.compile(r'<details class="menu">(.*?)</details>', re.S)
CONTENTS = re.compile(
r'<details class="menu menu-contents">(.*?)</details>', re.S)
def settings(text: str) -> dict:
"""{name: value} for every NAME=value line in an env file, read the
naive way on purpose — the point of comparing against it is that it
shares no code with the builder's own parser."""
found = {}
for line in text.splitlines():
if line.startswith("#") or "=" not in line.strip():
continue
name, _, value = line.partition("=")
if name.strip() and name.strip() == name:
found[name] = value
return found
class BuiltSite(unittest.TestCase):
"""The real manifest, built once into a scratch directory."""
@classmethod
def setUpClass(cls):
if not HAS_MARKDOWN_IT:
raise unittest.SkipTest("markdown-it-py is not installed")
cls.out = Path(tempfile.mkdtemp(prefix="bench-reference-")).resolve()
result = run_build(REPO, cls.out)
if result.returncode != 0: # not assert: must survive python -O
raise RuntimeError(
f"site/build.py failed:\n{result.stdout}{result.stderr}")
cls.manifest = json.loads(
(SITE / "pages.json").read_text(encoding="utf-8"))
cls.env = (REPO / ENV_EXAMPLE).read_text(encoding="utf-8")
@classmethod
def tearDownClass(cls):
if hasattr(cls, "out"):
shutil.rmtree(cls.out, ignore_errors=True)
def page(self, route: str) -> str:
return BUILDER.target_for(self.out, route).read_text("utf-8")
def entries(self) -> list:
return [page for page in self.manifest["pages"]
if page["layout"] == "reference"]
class TheSectionJoinsTheSite(BuiltSite):
"""Reference is a section beside Guides and Concepts — in the nav, in
the sidebar and on the reading order the arrows walk."""
def test_the_four_routes_are_all_there(self):
"""Named one by one rather than counted: a route quietly dropped
from the manifest is exactly the failure this catches."""
routes = {page["path"] for page in self.entries()}
for route in ("/reference/settings/", "/reference/adapters/",
"/reference/driver/", "/reference/commands/"):
self.assertIn(route, routes)
self.assertTrue(BUILDER.target_for(self.out, route).is_file(),
f"{route} produced no page")
def test_reference_is_a_section_of_its_own(self):
names = [group["name"] for group in BUILDER.sections(self.manifest)]
self.assertEqual(["Guides", "Concepts", "Reference"], names)
def test_the_nav_reaches_it_from_a_concept_page(self):
html = self.page("/concepts/stages/")
self.assertIn('href="/reference/settings/">Reference</a>', html)
def test_a_reference_page_marks_itself_in_the_sidebar(self):
for entry in self.entries():
here = SIDE_HERE.findall(self.page(entry["path"]))
self.assertTrue(here, f'{entry["path"]} does not mark itself')
self.assertEqual({entry["path"]}, set(here), entry["path"])
def test_it_is_on_the_flow_the_arrows_walk(self):
order = [page["path"] for page in BUILDER.flow(self.manifest)]
for entry in self.entries():
self.assertIn(entry["path"], order)
self.assertEqual("/reference/commands/", order[-1],
"the reference section is not the end of the flow")
class TheSettingsPageIsTheEnvFile(BuiltSite):
"""Acceptance: every setting in .env.example, exactly once, with the
default the file actually gives it."""
def setUp(self):
self.html = self.page("/reference/settings/")
self.expected = settings(self.env)
def test_it_reads_as_a_settings_file_rather_than_a_short_list(self):
"""Guards every test below from passing on an empty page."""
self.assertGreater(len(self.expected), 15,
"the env example has almost no settings in it")
self.assertIn("BOARD_PORT", self.expected)
self.assertIn("BENCH_SOURCE", self.expected)
def test_every_setting_appears_exactly_once_in_the_console(self):
listed = [CONSOLE_KEY.search(line).group(1)
for _, line in CONSOLE_LINE.findall(self.html)]
self.assertEqual(sorted(self.expected), sorted(listed),
"the console and the env file disagree about "
"which settings exist")
self.assertEqual(len(listed), len(set(listed)),
"a setting is listed twice")
def test_each_one_carries_the_default_the_file_gives_it(self):
shown = {}
for _, line in CONSOLE_LINE.findall(self.html):
value = CONSOLE_VALUE.search(line)
shown[CONSOLE_KEY.search(line).group(1)] = \
value.group(1) if value else None
for name, value in self.expected.items():
self.assertEqual(value, shown[name],
f"{name}'s default on the page is not the "
f"one in {ENV_EXAMPLE}")
def test_an_empty_default_is_shown_as_empty_rather_than_dropped(self):
"""BOARD_TITLE= is a default: the board falls back to the repo
directory's name. A page that skipped the line would read as a
setting with no default at all."""
self.assertEqual("", self.expected["BOARD_TITLE"])
self.assertIn('<span class="console-key">BOARD_TITLE</span>'
'<span class="console-sign">=</span>'
'<span class="console-value"></span>', self.html)
def test_every_console_line_points_at_a_heading_on_the_page(self):
anchors = {slug for slug, _ in HEADING_ID.findall(self.html)}
targets = {slug for slug, _ in CONSOLE_LINE.findall(self.html)}
self.assertTrue(targets)
self.assertEqual(set(), targets - anchors,
"a console line links to an anchor that is not "
"on the page")
def test_the_keys_are_grouped_the_way_the_file_groups_them(self):
"""The four model keys sit under one comment in the file, so they
are one entry on the page — and the three headings below are the
shape "grouped as that file groups them" takes."""
headings = [text for _, text in HEADING_ID.findall(self.html)]
self.assertIn("BOARD_PORT", headings)
self.assertIn("BOARD_CLAUDE_BIN, BOARD_OPENCODE_BIN", headings)
self.assertIn("BOARD_AGENT_MODEL, BOARD_AGENT_MODEL_WORK, "
"BOARD_AGENT_MODEL_ACT_PR, BOARD_AGENT_MODEL_REVIEW",
headings)
def test_a_default_is_the_files_own_line_and_says_it_is_one(self):
"""The flag under each heading is the line copied out of the
file, not a retyping of the value — and it is fenced as `env` so
the stylesheet can draw a value you set differently from a
terminal that printed something."""
self.assertIn('<pre><code class="language-env">BOARD_AGENT_COMMANDS='
"python3 -m unittest\n</code></pre>", self.html)
css = (SITE / "static" / "site.css").read_text("utf-8")
self.assertIn("code.language-env", css,
"nothing in the stylesheet tells a default from a "
"code block")
def test_the_documentation_is_the_files_own_comment(self):
"""Not a paraphrase written into site/: sentences out of the
comment blocks, arriving as the markdown they were written as."""
self.assertIn("Pinned by default so the URL is bookmarkable",
self.html)
self.assertIn("a test runner missing from this list", self.html)
self.assertIn("<code>board: &lt;number&gt; → &lt;stage&gt; "
"(&lt;name&gt;)</code>", self.html)
def test_a_placeholder_in_a_comment_survives_as_text(self):
"""`<git user.name>` is a placeholder, and a markdown parser that
honoured HTML would post it into the page as a tag and show
nothing. Generated bodies are rendered with HTML off."""
self.assertIn("&lt;git user.name&gt;", self.html)
self.assertNotIn("<git user.name>", self.html)
def test_a_comment_documenting_no_key_is_kept_as_a_remark(self):
"""The note about the `checks` file sits between two settings and
belongs to neither. It stays on the page — it is documentation —
as a blockquote rather than as the next key's description."""
self.assertIn("<blockquote>", self.html)
note = self.html.split("<blockquote>")
self.assertTrue(
any("definition-of-done check" in part for part in note),
"the note about the checks file is not on the page")
def test_edit_this_page_opens_the_file_itself(self):
"""There is no `from` heading to anchor at: the page is the whole
file."""
blob = self.manifest["site"]["blob_base"].rstrip("/") + "/"
self.assertIn(f'href="{blob}{ENV_EXAMPLE}"', self.html)
class TheContractPagesAreSlices(BuiltSite):
"""Acceptance: slices of the contract files, not paraphrases."""
def test_the_adapter_contract_is_the_adapters_readme(self):
html = self.page("/reference/adapters/")
self.assertIn("stdout is captured by the board as the job log",
html)
self.assertIn("<code>work</code>", html)
# The normalized event schema, indented in the README, arrives as
# the code block it is.
self.assertIn("<pre><code>", html)
self.assertIn("&quot;v&quot;: 1", html)
def test_the_driver_contract_is_agents_md(self):
html = self.page("/reference/driver/")
self.assertIn("refuse fast with a printed reason", html)
self.assertIn("DRIVE URL", html)
def test_the_command_contract_is_agents_md(self):
html = self.page("/reference/commands/")
self.assertIn("<code>CMD_WORKTREE</code>", html)
self.assertIn("Commands arm on first click and run on the second",
html)
def test_each_one_edits_at_the_section_it_was_cut_from(self):
blob = self.manifest["site"]["blob_base"].rstrip("/") + "/"
for entry in self.entries():
if not entry.get("from"):
continue
wanted = (blob + entry["source"] + "#"
+ BUILDER.github_anchor(entry["from"]))
self.assertIn(f'href="{wanted}"', self.page(entry["path"]),
f'{entry["path"]}: "Edit this page" does not open '
f'{entry["source"]} at {entry["from"]}')
def test_a_pages_console_is_its_own_headings(self):
"""The adapter page's entries are the contract's `###` headings,
promoted — so the console is generated for a sliced page too,
with no per-page authoring anywhere."""
html = self.page("/reference/adapters/")
anchors = dict(HEADING_ID.findall(html))
lines = CONSOLE_LINE.findall(html)
self.assertEqual(sorted(anchors), sorted(slug for slug, _ in lines))
self.assertIn("run — execute one headless job to completion",
[CONSOLE_KEY.search(line).group(1) for _, line in lines],
"the console shows the heading's markdown backticks")
class TheLayoutKeepsEveryArticlesFurniture(BuiltSite):
"""A reader must not lose the nav, the contents or the arrows by
walking into the reference section."""
def test_the_three_columns_are_there(self):
for entry in self.entries():
html = self.page(entry["path"])
for furniture in ('class="page-reference"', 'class="side"',
'class="prose"', 'class="gutter"',
'class="crumbs"', 'class="prose-lede"'):
self.assertIn(furniture, html,
f'{entry["path"]} is missing {furniture}')
def test_the_section_nav_is_folded_in_as_well(self):
listed = [page for page in self.manifest["pages"]
if page.get("section")]
for entry in self.entries():
menu = NAV.search(self.page(entry["path"]))
self.assertIsNotNone(menu, f'{entry["path"]} has no folded nav')
for page in listed:
self.assertIn(f'href="{page["path"]}"', menu.group(1),
f'{entry["path"]}\'s menu cannot reach '
f'{page["path"]}')
def test_the_folded_contents_carries_the_anchors_the_console_does(self):
"""Below 1080px the whole gutter goes, console and all. The strip
that replaces it has to reach everything the console did, or a
phone loses the index entirely."""
for entry in self.entries():
html = self.page(entry["path"])
strip = CONTENTS.search(html)
self.assertIsNotNone(strip,
f'{entry["path"]} has no contents strip')
for slug, _ in CONSOLE_LINE.findall(html):
self.assertIn(f'href="#{slug}"', strip.group(1),
f'{entry["path"]}\'s contents strip drops '
f"#{slug}")
def test_the_arrows_are_rendered(self):
for entry in self.entries():
self.assertIn('<nav class="flow">', self.page(entry["path"]),
f'{entry["path"]} has no prev/next')
def test_it_ships_no_script_of_its_own(self):
for entry in self.entries():
html = self.page(entry["path"])
for tag in re.findall(r"<script\b[^>]*>", html, re.I):
self.assertIn("cdn.usefathom.com", tag, entry["path"])
@needs_renderer
class ANewSettingReachesTheSiteByItself(ScratchCase):
"""The headline acceptance: add a key to .env.example with its
comment, rebuild, and it is on the page — no edit to site/ anywhere.
"""
def page(self) -> str:
return (self.repo.out / "reference" / "settings"
/ "index.html").read_text("utf-8")
def append(self, block: str) -> None:
path = self.repo.root / ENV_EXAMPLE
path.write_text(path.read_text("utf-8") + block, encoding="utf-8")
def test_a_new_key_appears_with_its_default_and_its_comment(self):
self.append("\n# How long the kettle boils for, in seconds. The\n"
"# board waits this long before it gives up.\n"
"BOARD_KETTLE_TIMEOUT=90\n")
result = self.repo.build()
self.assertEqual(0, result.returncode, result.stderr)
html = self.page()
self.assertIn('<h2 id="board-kettle-timeout">BOARD_KETTLE_TIMEOUT'
"</h2>", html)
self.assertIn("How long the kettle boils for", html)
self.assertIn('<span class="console-key">BOARD_KETTLE_TIMEOUT</span>'
'<span class="console-sign">=</span>'
'<span class="console-value">90</span>', html)
def test_a_multi_line_comment_does_not_swallow_the_next_key(self):
"""The edge case named on the card: two entries in a row, the
first with a three-line comment. The second keeps its own
heading, its own default and its own description."""
self.append("\n# One. This comment runs to three lines and it\n"
"# mentions BOARD_SECOND_KEY in passing, which is\n"
"# exactly how a parser gets this wrong.\n"
"BOARD_FIRST_KEY=first\n"
"\n"
"# Two. Its own comment, its own entry.\n"
"BOARD_SECOND_KEY=second\n")
result = self.repo.build()
self.assertEqual(0, result.returncode, result.stderr)
html = self.page()
self.assertIn('<h2 id="board-first-key">BOARD_FIRST_KEY</h2>', html)
self.assertIn('<h2 id="board-second-key">BOARD_SECOND_KEY</h2>', html)
first = html.split('<h2 id="board-first-key">')[1]
first, second = first.split('<h2 id="board-second-key">')
self.assertIn("This comment runs to three lines", first)
self.assertIn("BOARD_FIRST_KEY=first", first)
self.assertNotIn("BOARD_SECOND_KEY=second", first)
self.assertIn("Its own comment, its own entry.", second)
self.assertNotIn("This comment runs to three lines", second)
def test_two_keys_under_one_comment_stay_one_entry(self):
self.append("\n# A pair, documented together as the file does it.\n"
"BOARD_LEFT=l\n"
"BOARD_RIGHT=r\n")
result = self.repo.build()
self.assertEqual(0, result.returncode, result.stderr)
html = self.page()
self.assertIn("<h2 id=\"board-left-board-right\">BOARD_LEFT, "
"BOARD_RIGHT</h2>", html)
for name in ("BOARD_LEFT", "BOARD_RIGHT"):
self.assertIn(f'<a class="console-line" href="#board-left-'
f'board-right"><span class="console-key">{name}'
f"</span>", html)
@needs_renderer
class ADriftingEnvFileStopsTheBuild(ScratchCase):
"""A settings page that disagrees with the settings file is worse
than no settings page, so every way they can disagree is a failure
naming the route."""
def append(self, block: str) -> None:
path = self.repo.root / ENV_EXAMPLE
path.write_text(path.read_text("utf-8") + block, encoding="utf-8")
def test_a_key_documented_nowhere_fails_rather_than_being_skipped(self):
self.append("\nBOARD_UNDOCUMENTED=1\n")
result = self.repo.build()
self.assertNotEqual(0, result.returncode,
"an undocumented setting built cleanly")
self.assertIn("/reference/settings/", result.stderr)
self.assertIn("BOARD_UNDOCUMENTED", result.stderr)
self.assertFalse(self.repo.out.exists(),
"a failed build wrote pages anyway")
def test_a_key_set_twice_fails(self):
self.append("\n# Once.\nBOARD_PORT=1\n")
result = self.repo.build()
self.assertNotEqual(0, result.returncode)
self.assertIn("BOARD_PORT", result.stderr)
self.assertIn("twice", result.stderr)
def test_a_line_that_is_neither_a_comment_nor_a_setting_fails(self):
self.append("\nexport BOARD_PORT 26071\n")
result = self.repo.build()
self.assertNotEqual(0, result.returncode)
self.assertIn(ENV_EXAMPLE, result.stderr)
def test_a_missing_env_file_is_readable(self):
(self.repo.root / ENV_EXAMPLE).unlink()
result = self.repo.build()
self.assertNotEqual(0, result.returncode)
self.assertIn(ENV_EXAMPLE, result.stderr)
self.assertIn("does not exist", result.stderr)
def test_an_env_file_with_no_settings_at_all_fails(self):
(self.repo.root / ENV_EXAMPLE).write_text(
"# Nothing but prose in here.\n", encoding="utf-8")
result = self.repo.build()
self.assertNotEqual(0, result.returncode)
self.assertIn("/reference/settings/", result.stderr)
def test_renaming_the_command_contract_names_its_route(self):
"""The contract pages are slices, so they drift like every other
slice does — loudly. The heading renamed here is one exactly one
entry names: "## Drives" would be reported against the concept
page above it, which also ends there."""
self.repo.edit("AGENTS.md", "## Local commands", "## Chores")
result = self.repo.build()
self.assertNotEqual(0, result.returncode)
self.assertIn("/reference/commands/", result.stderr)
self.assertIn("## Local commands", result.stderr)
def test_renaming_where_the_driver_page_ends_names_its_route(self):
self.repo.edit("AGENTS.md", "## The activity bar and the archive",
"## The activity bar")
result = self.repo.build()
self.assertNotEqual(0, result.returncode)
self.assertIn("/reference/driver/", result.stderr)
self.assertIn("## The activity bar and the archive", result.stderr)
def test_renaming_the_adapter_contract_heading_names_its_route(self):
self.repo.edit("manager/core/adapters/README.md", "## The contract",
"## The interface")
result = self.repo.build()
self.assertNotEqual(0, result.returncode)
self.assertIn("/reference/adapters/", result.stderr)
@needs_renderer
class TheManifestChecksAGeneratedPage(ScratchCase):
"""`generate` is a second way to make a body, so it gets the same
treatment `from` does: a mistake in pages.json is a build failure,
not a surprise on the site."""
def one(self, page: dict):
self.repo.pages(page)
return self.repo.build()
def test_an_unknown_generator_lists_the_ones_that_exist(self):
result = self.one({
"path": "/x/", "title": "X", "layout": "reference",
"section": "Reference", "source": ENV_EXAMPLE,
"generate": "flags"})
self.assertNotEqual(0, result.returncode)
self.assertIn("flags", result.stderr)
self.assertIn("settings", result.stderr)
def test_a_generator_without_a_source_is_refused(self):
result = self.one({
"path": "/x/", "title": "X", "layout": "reference",
"section": "Reference", "source": None, "generate": "settings"})
self.assertNotEqual(0, result.returncode)
self.assertIn("generate", result.stderr)
def test_a_generated_page_may_not_also_be_a_slice(self):
result = self.one({
"path": "/x/", "title": "X", "layout": "reference",
"section": "Reference", "source": ENV_EXAMPLE,
"generate": "settings", "from": "## Anything"})
self.assertNotEqual(0, result.returncode)
self.assertIn("not a slice", result.stderr)
def test_a_source_with_neither_still_says_from(self):
result = self.one({
"path": "/x/", "title": "X", "layout": "reference",
"section": "Reference", "source": ENV_EXAMPLE})
self.assertNotEqual(0, result.returncode)
self.assertIn("from", result.stderr)
class TheEnvParserOnItsOwn(unittest.TestCase):
"""The block rule, on strings rather than on the shipped file: a
blank line separates entries, a comment belongs to the keys under it,
and a bare `#` is a paragraph break inside one."""
def blocks(self, text: str) -> list:
return BUILDER.env_blocks(text, "test.env")
def test_a_comment_binds_to_every_key_under_it(self):
blocks = self.blocks("# One comment.\nA=1\nB=2\n")
self.assertEqual(1, len(blocks))
self.assertEqual(["One comment."], blocks[0]["comment"])
self.assertEqual([("A", "1", "A=1"), ("B", "2", "B=2")],
blocks[0]["keys"])
def test_a_blank_line_ends_an_entry(self):
blocks = self.blocks("# One.\nA=1\n\n# Two.\nB=2\n")
self.assertEqual([["One."], ["Two."]],
[block["comment"] for block in blocks])
def test_a_comment_straight_after_a_key_opens_the_next_entry(self):
blocks = self.blocks("# One.\nA=1\n# Two.\nB=2\n")
self.assertEqual(2, len(blocks))
self.assertEqual([("B", "2", "B=2")], blocks[1]["keys"])
def test_a_bare_hash_is_a_paragraph_break(self):
blocks = self.blocks("# One.\n#\n# Two.\nA=1\n")
self.assertEqual(["One.", "", "Two."], blocks[0]["comment"])
self.assertEqual(["One.", "Two."],
BUILDER.comment_paragraphs(blocks[0]["comment"]))
def test_a_comment_with_no_keys_is_a_block_of_its_own(self):
blocks = self.blocks("# Just a note.\n\nA=1\n")
self.assertEqual([], blocks[0]["keys"])
self.assertEqual([], blocks[1]["comment"])
def test_a_value_containing_an_equals_sign_keeps_it(self):
self.assertEqual([("A", "x=y", "A=x=y")],
self.blocks("# c\nA=x=y\n")[0]["keys"])
def test_a_value_with_spaces_is_taken_verbatim(self):
self.assertEqual([("A", "python3 -m unittest",
"A=python3 -m unittest")],
self.blocks("# c\nA=python3 -m unittest\n")[0]["keys"])
if __name__ == "__main__":
unittest.main()