Pulse/scripts/ci_browser_proof_only.py
pulse-triage[bot] a3fe70feb8 Avoid runtime CI fan-out for browser-receipt-only tree changes
Classify the complete tree diff before builds or browser setup. Only nonempty top-level browser receipt JSON changes are exempt; mixed source, graphs, controls, docs and unavailable diffs keep ordinary runtime checks. Keep per-push secret scanning, independent canonical receipt validation and a strict E2E verdict which never calls skipped tests passing. Exercise real Git ranges and both workflow admission/result paths.

Contract-Neutral: Only browser-evidence-only tree diffs omit redundant runtime CI; application, dependency, trust and required source-proof contracts are unchanged.
Change-source: pulse-maintainer
2026-10-14 04:13:00 +01:00

51 lines
1.7 KiB
Python

#!/usr/bin/env python3
"""Recognise receipt-only tree changes, never substitute receipts for source tests.
Canonical Governance still validates these files. Runtime CI can be omitted only
when the complete tree diff contains nothing but browser evidence JSON. Any
source, dependency, workflow, documentation or unreadable diff retains runtime CI.
"""
import argparse
import re
import subprocess
import sys
COMMIT = re.compile(r"[0-9a-f]{40}")
RECEIPT = re.compile(rb"frontend-modern/browser-verification/[A-Za-z0-9_-]+\.json")
def receipt_only_paths(paths):
return bool(paths) and all(RECEIPT.fullmatch(path) is not None for path in paths)
def receipt_only_diff(base, head):
if not COMMIT.fullmatch(base) or not COMMIT.fullmatch(head):
return False
try:
# Null delimiters and disabled rename detection prevent quoted or
# renamed source paths from disappearing into a receipt-only list.
result = subprocess.run(
["git", "diff", "--no-ext-diff", "--no-renames", "--name-only", "-z",
base, head, "--"],
capture_output=True, timeout=30, check=False,
)
except (OSError, subprocess.TimeoutExpired):
print("Tree diff unavailable; retaining runtime CI.", file=sys.stderr)
return False
if result.returncode != 0 or not result.stdout.endswith(b"\0"):
return False
return receipt_only_paths(result.stdout[:-1].split(b"\0"))
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--base", required=True)
parser.add_argument("--head", required=True)
args = parser.parse_args()
print("true" if receipt_only_diff(args.base, args.head) else "false")
if __name__ == "__main__":
main()