#!/usr/bin/env bash # Repo-wide style gate: no em dashes, no tool-attribution phrases in any tracked # file. Mirrors the .githooks checks, run over the whole tree in CI so a bypassed # local hook is still caught at merge time. # # Portable: BSD-compatible grep, bash 3.2 (macOS) and bash 4+ (CI). set -u FAIL=0 # Em dash U+2014, built via printf so this script contains no em-dash byte. EMDASH=$(printf '\xe2\x80\x94') # Enforcement files legitimately contain the forbidden phrases in order to # detect them, so exclude them from the phrase scan. is_enforcement_file() { case "$1" in .githooks/*|scripts/check-style.sh|scripts/check-commit-attribution.sh|third_party/rules-swift/core/commits.md|third_party/rules-swift/core/git-discipline.md) return 0 ;; *) return 1 ;; esac } # Tool-attribution phrases. Assembled from fragments so this script does not # contain the full literal phrases (which would self-flag in other scanners). TOOL="Cla""ude" PHRASES=( "Co-Authored-By: $TOOL" "Co-authored-by: $TOOL" "Generated with $TOOL" "Generated by $TOOL" "Powered by $TOOL" "as an AI" ) # Vendor-neutral attribution: Rule 5.1 covers every AI assistant. Vendor names in # a list, matched against attribution prefixes, so the gate is tool-agnostic. AI_VENDORS="Codex Copilot Gemini ChatGPT OpenAI Anthropic Cursor" AI_PREFIXES='Co-Authored-By:|Co-authored-by:|Generated with|Generated by|with help from|Powered by' while IFS= read -r f; do [ -f "$f" ] || continue # The vendored rules-swift corpus is pinned upstream content, not authored here. case "$f" in third_party/*) continue ;; esac if LC_ALL=C grep -qF -- "$EMDASH" "$f" 2>/dev/null; then echo "style: em dash (U+2014) in $f" >&2 FAIL=1 fi if ! is_enforcement_file "$f"; then for p in "${PHRASES[@]}"; do if LC_ALL=C grep -qF -- "$p" "$f" 2>/dev/null; then echo "style: forbidden attribution phrase in $f" >&2 FAIL=1 fi done # Vendor-neutral attribution (Rule 5.1 covers every assistant, not just Claude). for vendor in $AI_VENDORS; do if LC_ALL=C grep -qiE -- "($AI_PREFIXES) $vendor" "$f" 2>/dev/null; then echo "style: forbidden attribution phrase ($vendor) in $f" >&2 FAIL=1 fi done fi done < <(git ls-files) if [ "$FAIL" -ne 0 ]; then echo "style: gate failed. Rules: third_party/rules-swift/core/git-discipline.md" >&2 fi # Roadmap gate (github-discipline: the roadmap check is wired into check-style). if ! bash scripts/check-roadmap.sh; then FAIL=1 fi exit "$FAIL"