From cbd48fc84aca3dbe7defd6a7c6fbfe7905fb74a1 Mon Sep 17 00:00:00 2001 From: arpan Date: Mon, 14 Sep 2026 01:42:14 +0530 Subject: [PATCH 1/3] The README says what the homepage says, and a test reads both The library's README now opens with index.mdx's H1 and lede verbatim, closes on its footer line, and walks the seven steps of the how-it-works diagram in the same order. tests/test_home_and_readme_agree.py reads those sentences out of index.mdx and the diagram and asserts the README carries them, so a rewrite of the homepage fails here until the README follows; the library pins the same strings on its side. --- tests/test_home_and_readme_agree.py | 73 +++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 tests/test_home_and_readme_agree.py diff --git a/tests/test_home_and_readme_agree.py b/tests/test_home_and_readme_agree.py new file mode 100644 index 0000000..c78ddb6 --- /dev/null +++ b/tests/test_home_and_readme_agree.py @@ -0,0 +1,73 @@ +"""The README's first screen says what the homepage says. + +ctrlrun.dev's homepage is the marketing surface and the library's README is the GitHub and PyPI +one. Until 2026-09-14 they led with different sentences: the site said *stops AI agents from +taking wrong, restricted, or malicious actions in your workflows* and the README said +*Execution safety for AI agents*, so a stranger arriving from one to the other met a second +pitch. The README now opens with the homepage's H1 and lede, verbatim, closes on its footer +line, and walks the seven steps of its diagram in the same order. This file is what keeps the +two from drifting apart again: it reads the sentences out of `index.mdx` and the diagram, so a +rewrite of the homepage fails here until the README follows. The library pins the same strings +on its side, in `tests/test_readme_assets.py`, so a rewrite of the README fails there first. +""" + +from __future__ import annotations + +import re +from pathlib import Path + +from _core import CORE_ROOT + +REPO_ROOT = Path(__file__).resolve().parents[1] +HOME = REPO_ROOT / "index.mdx" +DIAGRAM = REPO_ROOT / "snippets" / "how-diagram.jsx" +README = CORE_ROOT / "README.md" + + +def _prose(markup: str) -> str: + """Tags removed and whitespace collapsed. A `
` is a space, so it reads as a line break + does; every other tag is nothing, so `workflows.` keeps its full stop.""" + text = re.sub(r"", " ", markup) + return " ".join(re.sub(r"<[^>]+>", "", text).split()) + + +def _homepage(pattern: str) -> str: + match = re.search(pattern, HOME.read_text(encoding="utf-8"), re.S) + assert match, f"index.mdx no longer carries {pattern!r}" + return _prose(match.group(1)) + + +def _readme() -> str: + return README.read_text(encoding="utf-8") + + +def test_the_readme_opens_with_the_homepage_h1_and_lede(): + head = _prose(_readme().split("\n## ", 1)[0]) + h1 = _homepage(r'

(.*?)

') + lede = _homepage(r'

(.*?)

') + + assert h1.startswith("CTRLRun ") and h1.endswith("."), h1 + assert h1 in head, f"the README header does not carry the homepage H1: {h1!r}" + assert lede in head, f"the README header does not carry the homepage lede: {lede!r}" + + +def test_the_readme_closes_on_the_homepage_footer_line(): + footer = _homepage(r'
(.*?)') + tail = _prose(_readme().rsplit("## License", 1)[1]) + + assert footer, "the homepage footer is empty" + assert footer in tail, f"the README does not close on the homepage's line: {footer!r}" + + +def test_the_readme_walks_the_homepage_seven_steps_in_order(): + """The diagram names seven steps, normalize to record. The README's *How it works* is the + same walk in prose, and a step the diagram gained or lost is a step the README follows.""" + diagram = DIAGRAM.read_text(encoding="utf-8") + steps = ["Normalize", "Decide", "Approve", "Reserve", "Execute", "Resolve", "Record"] + for step in steps: + assert f"{step}" in diagram or f">{step}<" in diagram, step + + section = _readme().split("## How it works", 1)[1].split("\n## ", 1)[0] + positions = [section.find(f"**{step}:") for step in steps] + assert all(p >= 0 for p in positions), dict(zip(steps, positions, strict=True)) + assert positions == sorted(positions), "the README walks the steps in the diagram's order" From 23257da33ea76219899ef9fab9d2212dcde8c4bb Mon Sep 17 00:00:00 2001 From: arpan Date: Mon, 14 Sep 2026 03:38:35 +0530 Subject: [PATCH 2/3] The badges point at docs.ctrlrun.dev, and nothing commercial is asserted of the README The docs badge, the tests badge and the verify badge link to the documentation host, which serves every page under ctrlrun.dev/docs at the same path. The README carries no commercial material, so the test that expected the site's closing line there is gone; the H1, the lede and the seven steps are still asserted. --- generated/badges.readme.md | 6 +++--- tests/test_home_and_readme_agree.py | 12 ++---------- tools/docs_audit/render_badges.py | 8 ++++---- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/generated/badges.readme.md b/generated/badges.readme.md index 0db6930..ae02d9c 100644 --- a/generated/badges.readme.md +++ b/generated/badges.readme.md @@ -3,12 +3,12 @@ Clones PyPI Downloads - Docs + Docs CI CodeQL Fuzz - Tests - CTRLRun verified + Tests + CTRLRun verified OpenSSF Scorecard OpenSSF Best Practices License diff --git a/tests/test_home_and_readme_agree.py b/tests/test_home_and_readme_agree.py index c78ddb6..23a0cdd 100644 --- a/tests/test_home_and_readme_agree.py +++ b/tests/test_home_and_readme_agree.py @@ -4,8 +4,8 @@ one. Until 2026-09-14 they led with different sentences: the site said *stops AI agents from taking wrong, restricted, or malicious actions in your workflows* and the README said *Execution safety for AI agents*, so a stranger arriving from one to the other met a second -pitch. The README now opens with the homepage's H1 and lede, verbatim, closes on its footer -line, and walks the seven steps of its diagram in the same order. This file is what keeps the +pitch. The README now opens with the homepage's H1 and lede, verbatim, and walks the seven +steps of its diagram in the same order; nothing commercial crosses over. This file is what keeps the two from drifting apart again: it reads the sentences out of `index.mdx` and the diagram, so a rewrite of the homepage fails here until the README follows. The library pins the same strings on its side, in `tests/test_readme_assets.py`, so a rewrite of the README fails there first. @@ -51,14 +51,6 @@ def test_the_readme_opens_with_the_homepage_h1_and_lede(): assert lede in head, f"the README header does not carry the homepage lede: {lede!r}" -def test_the_readme_closes_on_the_homepage_footer_line(): - footer = _homepage(r'
(.*?)') - tail = _prose(_readme().rsplit("## License", 1)[1]) - - assert footer, "the homepage footer is empty" - assert footer in tail, f"the README does not close on the homepage's line: {footer!r}" - - def test_the_readme_walks_the_homepage_seven_steps_in_order(): """The diagram names seven steps, normalize to record. The README's *How it works* is the same walk in prose, and a step the diagram gained or lost is a step the README follows.""" diff --git a/tools/docs_audit/render_badges.py b/tools/docs_audit/render_badges.py index e61fb36..70649a4 100644 --- a/tools/docs_audit/render_badges.py +++ b/tools/docs_audit/render_badges.py @@ -105,8 +105,8 @@ class Badge: ), Badge( "Docs", - "https://img.shields.io/badge/docs-ctrlrun.dev-B8730A", - "https://ctrlrun.dev", + "https://img.shields.io/badge/docs-docs.ctrlrun.dev-B8730A", + "https://docs.ctrlrun.dev/", ), Badge( "CI", @@ -126,12 +126,12 @@ class Badge: Badge( "Tests", f"https://img.shields.io/endpoint?url={BADGES_BRANCH}/tests-badge.json", - "https://ctrlrun.dev/docs/how-this-is-built", + "https://docs.ctrlrun.dev/how-this-is-built", ), Badge( "CTRLRun verified", f"https://img.shields.io/endpoint?url={BADGES_BRANCH}/verify-badge.json", - "https://ctrlrun.dev/docs/security/verify-guarantees", + "https://docs.ctrlrun.dev/security/verify-guarantees", ), Badge( "OpenSSF Scorecard", From 0dcafcf0283fb8709dcee8d932b10f6cb27d89f2 Mon Sep 17 00:00:00 2001 From: arpan Date: Mon, 14 Sep 2026 04:13:56 +0530 Subject: [PATCH 3/3] The README test asserts the opening in sequence and reads the steps off the diagram Two review findings: the H1 must open the README's prose and the lede must follow it directly, rather than both merely appearing somewhere before the first section; and the seven steps come from the diagram's own labels in source order (the wide and narrow drawings have to agree), so a reordered or added step fails here instead of passing a fixed list. Signed-off-by: arpan --- tests/test_home_and_readme_agree.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tests/test_home_and_readme_agree.py b/tests/test_home_and_readme_agree.py index 23a0cdd..0f59280 100644 --- a/tests/test_home_and_readme_agree.py +++ b/tests/test_home_and_readme_agree.py @@ -42,22 +42,38 @@ def _readme() -> str: def test_the_readme_opens_with_the_homepage_h1_and_lede(): + """In sequence, not merely present: the README's prose opens with the H1 and the lede + follows it directly. Prose before the H1, or the lede ahead of it, fails here.""" head = _prose(_readme().split("\n## ", 1)[0]) h1 = _homepage(r'

(.*?)

') lede = _homepage(r'

(.*?)

') assert h1.startswith("CTRLRun ") and h1.endswith("."), h1 - assert h1 in head, f"the README header does not carry the homepage H1: {h1!r}" - assert lede in head, f"the README header does not carry the homepage lede: {lede!r}" + assert head.startswith(h1), f"the README does not open with the homepage H1: {head[:120]!r}" + after_h1 = head[len(h1) :].lstrip() + assert after_h1.startswith(lede), ( + f"the homepage lede does not follow the H1 directly: {after_h1[:120]!r}" + ) + + +def _diagram_steps() -> list[str]: + """The step names as the diagram draws them, in source order. The file carries the diagram + twice, wide and narrow, so the two sequences have to agree and one of them is the answer.""" + names = re.findall( + r'className="cr-dia-name"[^>]*>([^<]+)<', DIAGRAM.read_text(encoding="utf-8") + ) + assert names and len(names) % 2 == 0, names + wide, narrow = names[: len(names) // 2], names[len(names) // 2 :] + assert wide == narrow, f"the wide and narrow diagrams name different steps: {wide} vs {narrow}" + return wide def test_the_readme_walks_the_homepage_seven_steps_in_order(): """The diagram names seven steps, normalize to record. The README's *How it works* is the same walk in prose, and a step the diagram gained or lost is a step the README follows.""" - diagram = DIAGRAM.read_text(encoding="utf-8") - steps = ["Normalize", "Decide", "Approve", "Reserve", "Execute", "Resolve", "Record"] - for step in steps: - assert f"{step}" in diagram or f">{step}<" in diagram, step + steps = _diagram_steps() + assert len(steps) == 7, steps + assert steps[0] == "Normalize" and steps[-1] == "Record", steps section = _readme().split("## How it works", 1)[1].split("\n## ", 1)[0] positions = [section.find(f"**{step}:") for step in steps]