diff --git a/README.md b/README.md index 04ba52f..8595bab 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ no network: plain Python over the tracked files. | `docref` | the repos' own trees | `` `FILE.md` `` naming a file that does not exist; relative markdown links that do not resolve | | `binaries` | each repo's `Cargo.toml` and `deploy/*.service` | project-yukart `REPOS.md` missing a deployed binary; `ORIN-RUNTIME.md` missing a deployed service | | `frontmatter` | the docs convention | a `docs/**/*.md` without front matter, or with an unknown `type` | +| `copy` | contracts | a file under `assets/contracts/` that is not byte-identical to contracts' `` (or has no source there) | ## Run it diff --git a/crosscheck.py b/crosscheck.py index b61ef76..daef056 100644 --- a/crosscheck.py +++ b/crosscheck.py @@ -19,6 +19,8 @@ Exit status 1 when anything is found. Checks, and the source each one trusts: binaries REPOS.md's row for a repo names every deployed [[bin]] in its Cargo.toml; ORIN-RUNTIME.md names every service a repo deploys frontmatter every docs/**/*.md starts with front matter whose type is known + copy a file under assets/contracts/ in any repo is byte-identical to + contracts' (bundled copies, e.g. the app's checklists) """ import json @@ -246,6 +248,21 @@ def check_frontmatter(ws: Workspace) -> None: find(f"{repo}/{rel}", 1, "frontmatter", f"type '{t.group(1)}' is not one of {sorted(DOC_TYPES)}") +# ── bundled copies of contracts files ──────────────────────────────────────── + + +def check_copies(ws: Workspace) -> None: + for repo in ws.repos: + for rel in ws.files[repo]: + if not rel.startswith("assets/contracts/"): + continue + src = rel.removeprefix("assets/contracts/") + if src not in ws.files["contracts"]: + find(f"{repo}/{rel}", 1, "copy", f"contracts has no {src} to copy") + elif (ws.root / repo / rel).read_bytes() != (ws.root / "contracts" / src).read_bytes(): + find(f"{repo}/{rel}", 1, "copy", f"differs from contracts {src}; run tool/sync-contracts.sh") + + def main() -> int: root = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve() ws = Workspace(root) @@ -253,7 +270,7 @@ def main() -> int: if missing: print(f"crosscheck: {root} lacks {', '.join(sorted(missing))}; nothing to check against", file=sys.stderr) return 2 - for check in (check_decisions, check_topics, check_docrefs, check_binaries, check_frontmatter): + for check in (check_decisions, check_topics, check_docrefs, check_binaries, check_frontmatter, check_copies): check(ws) for f in findings: print(f)