From c88ce3d72ff5520e2e42b6909410e7c5091955c5 Mon Sep 17 00:00:00 2001 From: 2plot-network fan-out Date: Sat, 29 Aug 2026 00:24:25 +0000 Subject: [PATCH] sync: template 1.6.22-1.6.33 verbatim block (F3b fan-out) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spec: sync/SYNC-1.6.22-1.6.33.md @ c3d444d (c3d444da000824a6fd9448c1dd8f86a259d74427) Mechanical whole-file copy of the spec's sync-verbatim block only. Contract/conditional items are NOT in this PR — see the spec. --- .claude/skills/wire-verify/SKILL.md | 23 +++++-- tests/test_claude_kit.py | 100 ++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 5 deletions(-) diff --git a/.claude/skills/wire-verify/SKILL.md b/.claude/skills/wire-verify/SKILL.md index e4f08b0..1ee5e50 100644 --- a/.claude/skills/wire-verify/SKILL.md +++ b/.claude/skills/wire-verify/SKILL.md @@ -25,11 +25,24 @@ pasted output; a claim without the artifact is not verified. - `geo.resolved` naming a country via cf-ipcountry proves the edge's country header reaches the app. -3. **Machine lane**: `curl -s /` (no browser UA) must - return the static crawler document — real prose, exactly one - `

` (strip HTML comments before counting), no "Loading..." - stub. Spot-check one content page's `//llms.txt`: markdown, - not an HTML shell. +3. **Machine lane** — name the crawler, do not rely on curl's + default UA (1.6.30): which document you get is the package's UA + classification, and an unnamed agent can land in either lane + (the template serves `curl/8.x` the crawler document; muicharts + saw the browser one). Probe explicitly, and confirm from the + body which lane answered: + + curl -s -A "Mozilla/5.0 (compatible; Googlebot/2.1; \ + +http://www.google.com/bot.html)" / + + The crawler document is small (tens of KB, not hundreds) and + carries real prose, exactly one `

` (strip HTML comments + before counting) and no "Loading..." stub. Spot-check one + content page's `//llms.txt`: markdown, not an HTML shell. + If this host blocks AI vendors, its DIVERGENCES.md posture block + says which paths 403 — check those with a vendor UA too, and + treat a mismatch as either the posture drifting or the block + drifting, never as noise. 4. **Browser lane**: with a browser User-Agent, the app shell must carry the visible prerender div (no `hidden` attribute) and the diff --git a/tests/test_claude_kit.py b/tests/test_claude_kit.py index b98da15..4a27031 100644 --- a/tests/test_claude_kit.py +++ b/tests/test_claude_kit.py @@ -136,6 +136,70 @@ def _machine_fence(kind: str, text: str, where: str) -> None: ) +_POSTURE_KEYS = {"ai_bots", "healthz", "runtime"} +_POSTURE_ENUMS = {"healthz": {"minimal", "full"}, "runtime": {"docker", "python"}} + + +def _posture_fence(text: str, where: str) -> dict: + """The ```yaml posture block in DIVERGENCES.md (1.6.30, F4). + + Declared postures used to live in the hub's own table — a copy of a + measurement somebody took once, aging in a repo that cannot see the + host. The fence homes each posture in the repo that serves it. SHAPE + is all this validates: no test can tell a stale 200 from a fresh one, + so the grammar is kept narrow enough that a wrong value is visibly + wrong. Empty is valid and means "the template defaults". + """ + fences = re.findall( + r"^```yaml posture[ \t]*\n(.*?)^```[ \t]*$", text, re.M | re.S + ) + assert len(fences) == 1, ( + f"{where}: expected exactly one ```yaml posture fence, " + f"found {len(fences)}" + ) + declared: dict = {} + for raw in fences[0].splitlines(): + stripped = raw.strip() + if not stripped or stripped.startswith("#"): + continue + key, sep, value = stripped.partition(":") + key, value = key.strip(), value.strip() + assert sep, f"{where} posture: {raw!r} is not a `key: value` line" + assert key in _POSTURE_KEYS, ( + f"{where} posture: unknown key {key!r} — the hub reads " + f"{sorted(_POSTURE_KEYS)} and would ignore this one silently" + ) + assert key not in declared, f"{where} posture: {key!r} declared twice" + if key in _POSTURE_ENUMS: + assert value in _POSTURE_ENUMS[key], ( + f"{where} posture: {key}: {value!r} — expected one of " + f"{sorted(_POSTURE_ENUMS[key])}" + ) + declared[key] = value + continue + try: + statuses = json.loads(value) + except ValueError as exc: + raise AssertionError( + f"{where} posture: ai_bots must be a JSON object like " + f'{{"/": 403, "/llms.txt": 200}} — {exc}' + ) from None + assert isinstance(statuses, dict) and statuses, ( + f"{where} posture: ai_bots is {statuses!r} — a non-empty JSON " + "object of path -> status, or omit the key entirely" + ) + for path, status in statuses.items(): + assert path.startswith("/"), ( + f"{where} posture: ai_bots key {path!r} is not a path" + ) + assert isinstance(status, int) and 100 <= status <= 599, ( + f"{where} posture: ai_bots[{path!r}] is {status!r} — an " + "HTTP status, measured with a real vendor UA" + ) + declared[key] = statuses + return declared + + def test_kit_files_exist_and_are_not_ignored(): """The blanket `.claude/` ignore kept the contract local-only for the template's whole life — every fork inherited nothing. The allow-list @@ -278,3 +342,39 @@ def test_divergences_carry_the_byte_owned_block(): "mention heuristic" ) _machine_fence("byte-owned", text, "DIVERGENCES.md") + + +def test_divergences_posture_fence_is_wellformed(): + """The declared posture (1.6.30, F4): shape only, plus the one value + the repo can contradict by itself. + + ABSENCE SKIPS, like the byte-owned fence and for the same reason — a + fork that has not ported the item yet keeps its CI green and gets the + contract item, not a red on arrival. What is declared is held: an + unknown key would be read by nobody, and a `runtime:` disagreeing with + render.yaml is the posture lying about something in its own tree. + """ + import pytest + + div = REPO / "DIVERGENCES.md" + if not div.is_file(): + pytest.skip("no DIVERGENCES.md — nothing to declare a posture in") + text = div.read_text() + if not re.search(r"^```yaml posture[ \t]*$", text, re.M): + pytest.skip( + "DIVERGENCES.md has no posture fence — port the 1.6.30 item; " + "until then the hub reads its own seeded table" + ) + declared = _posture_fence(text, "DIVERGENCES.md") + + render = REPO / "render.yaml" + if "runtime" in declared and render.is_file(): + for line in render.read_text().splitlines(): + m = re.match(r"\s*runtime:\s*(\S+)", line) + if m: + assert declared["runtime"] == m.group(1), ( + f"posture declares runtime {declared['runtime']!r}, " + f"render.yaml says {m.group(1)!r} — the posture is " + "wrong about this repo's own tree" + ) + break