From 3b859d5ad78fb63574455404ad662109824b183e Mon Sep 17 00:00:00 2001 From: 2plot-network fan-out Date: Tue, 25 Aug 2026 05:51:34 +0000 Subject: [PATCH] sync: template 1.6.17-1.6.21 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.17-1.6.21.md @ 40a06f3 (40a06f3448e56d0cec626370745e2291e20f04b4) Mechanical whole-file copy of the spec's sync-verbatim block only. Contract/conditional items are NOT in this PR — see the spec. --- tests/test_claude_kit.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/test_claude_kit.py b/tests/test_claude_kit.py index ba95ce0..9dfe7b3 100644 --- a/tests/test_claude_kit.py +++ b/tests/test_claude_kit.py @@ -42,7 +42,8 @@ def _machine_fence(kind: str, text: str, where: str) -> None: ```yaml byte-owned in DIVERGENCES.md): exactly one block, `- path` lines with `#` comments, every path repo-relative and real at HEAD. Empty is valid — an empty block is a statement, a missing one is an - omission.""" + omission. `# requires: ` lines (the fan-out's adoption gate, + 1.6.23) are validated like paths — a typo'd gate gates nothing.""" fences = re.findall( r"^```yaml " + kind + r"[ \t]*\n(.*?)^```[ \t]*$", text, re.M | re.S ) @@ -51,6 +52,17 @@ def _machine_fence(kind: str, text: str, where: str) -> None: f"found {len(fences)}" ) for raw in fences[0].splitlines(): + required = re.match(r"#\s*requires:\s*(.+)$", raw.strip()) + if required: + req = required.group(1).strip() + assert ".." not in req and not req.startswith("/"), ( + f"{where} {kind}: `# requires:` path {req!r} escapes the repo" + ) + assert (REPO / req).is_file(), ( + f"{where} {kind}: `# requires:` names {req!r} which does " + "not exist at HEAD — a typo'd gate gates nothing" + ) + continue entry = raw.split("#", 1)[0].strip() if not entry: continue