From 3c10b74076fd21e93be815a68909f02c649fe7c1 Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Tue, 26 May 2026 03:13:13 +0100 Subject: [PATCH] fix(governance): consult .hypatia-ignore for tsconfig/rescript.json check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brings the "Check for tsconfig / rescript config" step into line with the existing banned-language-files step (which already honours `.hypatia-ignore` + inline `# hypatia:ignore` pragma per the Explicit-Escape Principle, standards#72). Before this fix the step was an unconditional `[ -f rescript.json ] && exit 1` with no exemption mechanism, which blocked PRs in repos that legitimately retain ReScript while in mid-migration (per their `.claude/CLAUDE.md`). Concrete case: verisimdb#40 has `.hypatia-ignore` exempting all 34 `.res` source files correctly, but `rescript.json` at the repo root still hard-fails the governance gate. New behaviour: # .hypatia-ignore cicd_rules/banned_config_file:rescript.json cicd_rules/banned_config_file:tsconfig.json # if needed …or an inline `# hypatia:ignore cicd_rules/banned_config_file` pragma in the first 8 lines (works for JSONC; not strict JSON). Rule name: `cicd_rules/banned_config_file` — parallel to the existing `cicd_rules/banned_language_file` rule. Refs verisimdb#40 (the repro PR that surfaced this gap). Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/governance-reusable.yml | 52 +++++++++++++++++++---- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/.github/workflows/governance-reusable.yml b/.github/workflows/governance-reusable.yml index d0d99866..f848524f 100644 --- a/.github/workflows/governance-reusable.yml +++ b/.github/workflows/governance-reusable.yml @@ -347,16 +347,50 @@ jobs: echo "✅ No npm/bun violations" - name: Check for tsconfig / rescript config + # Honours the same `.hypatia-ignore` exemption mechanism as the + # banned-language-files step (standards#72, Explicit-Escape + # Principle). A config file is exempt if either + # * `.hypatia-ignore` contains the exact line + # `cicd_rules/banned_config_file:`, OR + # * the file carries an inline `# hypatia:ignore … banned_config_file` + # pragma in its first 8 lines (works for JSONC-style configs; + # not for strict JSON variants). + # Required so repos that legitimately retain ReScript while in + # mid-migration (per their `.claude/CLAUDE.md`, e.g. verisimdb) + # can declare the exemption explicitly instead of being globally + # blocked. Same pattern as the .res file step above. run: | - if [ -f "tsconfig.json" ]; then - echo "❌ tsconfig.json detected - use AffineScript instead" - exit 1 - fi - if [ -f "rescript.json" ] || [ -f "bsconfig.json" ]; then - echo "❌ rescript.json/bsconfig.json detected - use AffineScript config instead" - exit 1 - fi - echo "✅ No tsconfig.json / rescript config" + rule="cicd_rules/banned_config_file" + + is_exempt() { + f="$1" + if [ -f .hypatia-ignore ] && grep -qxF "${rule}:${f}" .hypatia-ignore; then + return 0 + fi + if head -n 8 "$f" 2>/dev/null | grep -q "hypatia:ignore.*${rule}"; then + return 0 + fi + return 1 + } + + check_config() { + cfg="$1"; hint="$2" + if [ -f "$cfg" ]; then + if is_exempt "$cfg"; then + echo "⏭️ exempt (${rule}): $cfg" + return 0 + fi + echo "❌ ${cfg} detected - ${hint}" + echo " (declare an exemption via .hypatia-ignore line" + echo " '${rule}:${cfg}' if intentional)" + exit 1 + fi + } + + check_config "tsconfig.json" "use AffineScript instead" + check_config "rescript.json" "use AffineScript config instead" + check_config "bsconfig.json" "use AffineScript config instead" + echo "✅ No non-exempt tsconfig.json / rescript config" - name: Summary run: |