|
| 1 | +#!/usr/bin/env python3 |
| 2 | +"""The provider boundary (.agents/docs/2026-10-16-xlings-provider-port-and-shared-store-design.md §4.3). |
| 3 | +
|
| 4 | +mcpp speaks the port's words (mcpp.provider): what xlings' commands, its |
| 5 | +protocol, its home layout and its store naming are is the adapter's |
| 6 | +(src/provider/xlings/), and only the composition root (src/provider/select.cppm) |
| 7 | +names the adapter. Outside them, in src/: |
| 8 | +
|
| 9 | + - no `import mcpp.provider.xlings*`; |
| 10 | + - none of the layout's spellings in code: "xpkgs", "-x-", "xim-x-", |
| 11 | + ".xlings.json", "subos", "xim-index-repos", ".mcpp_ok"; |
| 12 | + - a payload path is used as the provider answered it: no canonical / |
| 13 | + weakly_canonical / remove_all applied to one. |
| 14 | +
|
| 15 | +Comments are prose and may name anything; string literals and identifiers |
| 16 | +in code may not. An exception names its reason on the line: |
| 17 | +`// provider-boundary-ok: <why>`. |
| 18 | +
|
| 19 | +Exit 0 clean, 1 with the findings listed. |
| 20 | +""" |
| 21 | +from __future__ import annotations |
| 22 | + |
| 23 | +import argparse |
| 24 | +import pathlib |
| 25 | +import re |
| 26 | +import sys |
| 27 | + |
| 28 | +LITERALS = ['"xpkgs"', '/xpkgs', 'xpkgs/', '-x-', 'xim-x-', '.xlings.json', '"subos"', '/subos', 'subos/', |
| 29 | + 'xim-index-repos', '.mcpp_ok', '.mcpp-fixup.json'] |
| 30 | +IMPORT = re.compile(r'^\s*(export\s+)?import\s+mcpp\.provider\.xlings\b') |
| 31 | +PAYLOAD_FS = re.compile(r'\b(canonical|weakly_canonical|remove_all)\s*\([^)]*[pP]ayload') |
| 32 | + |
| 33 | + |
| 34 | +def strip_comments(text: str) -> list[str]: |
| 35 | + """Each line with // and /* */ comments blanked, string literals kept.""" |
| 36 | + out, in_block = [], False |
| 37 | + for line in text.split("\n"): |
| 38 | + res, i, in_str = [], 0, None |
| 39 | + while i < len(line): |
| 40 | + c = line[i] |
| 41 | + if in_block: |
| 42 | + if line.startswith("*/", i): |
| 43 | + in_block = False |
| 44 | + i += 2 |
| 45 | + continue |
| 46 | + i += 1 |
| 47 | + continue |
| 48 | + if in_str: |
| 49 | + res.append(c) |
| 50 | + if c == "\\" and i + 1 < len(line): |
| 51 | + res.append(line[i + 1]) |
| 52 | + i += 2 |
| 53 | + continue |
| 54 | + if c == in_str: |
| 55 | + in_str = None |
| 56 | + i += 1 |
| 57 | + continue |
| 58 | + if line.startswith("//", i): |
| 59 | + break |
| 60 | + if line.startswith("/*", i): |
| 61 | + in_block = True |
| 62 | + i += 2 |
| 63 | + continue |
| 64 | + if c in "\"'": |
| 65 | + in_str = c |
| 66 | + res.append(c) |
| 67 | + i += 1 |
| 68 | + out.append("".join(res)) |
| 69 | + return out |
| 70 | + |
| 71 | + |
| 72 | +def main() -> int: |
| 73 | + ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) |
| 74 | + ap.add_argument("--root", type=pathlib.Path, default=pathlib.Path(__file__).resolve().parents[2]) |
| 75 | + ROOT = ap.parse_args().root.resolve() |
| 76 | + SRC = ROOT / "src" |
| 77 | + ADAPTER = SRC / "provider" / "xlings" |
| 78 | + ROOT_MODULE = SRC / "provider" / "select.cppm" |
| 79 | + findings = [] |
| 80 | + for path in sorted(SRC.rglob("*")): |
| 81 | + if path.suffix not in (".cppm", ".cpp", ".hpp", ".h") or not path.is_file(): |
| 82 | + continue |
| 83 | + if ADAPTER in path.parents: |
| 84 | + continue |
| 85 | + raw = path.read_text(encoding="utf-8", errors="replace").split("\n") |
| 86 | + code = strip_comments("\n".join(raw)) |
| 87 | + for n, (line, original) in enumerate(zip(code, raw), 1): |
| 88 | + if "provider-boundary-ok:" in original: |
| 89 | + continue |
| 90 | + rel = path.relative_to(ROOT) |
| 91 | + if IMPORT.match(line) and path != ROOT_MODULE: |
| 92 | + findings.append(f"{rel}:{n}: imports the adapter; import mcpp.provider.select") |
| 93 | + for lit in LITERALS: |
| 94 | + if lit in line: |
| 95 | + findings.append(f"{rel}:{n}: names the provider's layout ({lit}): {original.strip()}") |
| 96 | + break |
| 97 | + if PAYLOAD_FS.search(line): |
| 98 | + findings.append(f"{rel}:{n}: canonicalises or removes a payload: {original.strip()}") |
| 99 | + if findings: |
| 100 | + print("provider boundary: " + str(len(findings)) + " finding(s)") |
| 101 | + for f in findings: |
| 102 | + print(" " + f) |
| 103 | + return 1 |
| 104 | + print("provider boundary: clean") |
| 105 | + return 0 |
| 106 | + |
| 107 | + |
| 108 | +if __name__ == "__main__": |
| 109 | + sys.exit(main()) |
0 commit comments