From 04cfc2be3efebddb3e85bb79054909c44052f693 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 11 May 2026 09:58:23 +0200 Subject: [PATCH] fix(ci): unblock antipattern check and delegate TS detection to one source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two related fixes for CI checks that have been red on main for weeks (precursor to merging #46 — both unrelated to that port but blocking its clean merge). 1. .github/workflows/rsr-antipattern.yml — the "Check for TypeScript" step had two PYEOF tokens in succession but only one opening `python3 << 'PYEOF'`, leaving the second Python block dangling as bash commands. Bash interpreted `BUILTIN_GLOBS = [...]` as a command and exited 127. The first Python block already does the full TypeScript exemption check (universal allowlist + parsed .claude/CLAUDE.md table), so the duplicated second block is removed. No behaviour change beyond the workflow running to completion. 2. .github/workflows/language-policy.yml — the "Check for TypeScript files" step duplicated the rsr-antipattern check but with no allowlist beyond node_modules + *.d.ts, false-positiving on legitimate bridge files (e.g. lol/test/vitest.config.ts which lives under the *vscode*-or-tests/ universal allowlist that rsr-antipattern honours). The duplicate step is removed; the other language checks (ReScript, Go, Python, V-lang, ATS2, Java/Kotlin, Swift, Flutter/Dart, Makefiles, package.json runtime deps) all stay — they remain the single source of truth for those languages. Co-Authored-By: Claude Opus 4.7 --- .github/workflows/language-policy.yml | 13 ++--- .github/workflows/rsr-antipattern.yml | 77 --------------------------- 2 files changed, 5 insertions(+), 85 deletions(-) diff --git a/.github/workflows/language-policy.yml b/.github/workflows/language-policy.yml index df36175f..cf8356bf 100644 --- a/.github/workflows/language-policy.yml +++ b/.github/workflows/language-policy.yml @@ -18,14 +18,11 @@ jobs: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - - name: Check for TypeScript files - run: | - if find . -name "*.ts" -o -name "*.tsx" | grep -v node_modules | grep -v ".d.ts" | head -1 | grep -q .; then - echo "::error::TypeScript files found. Use AffineScript instead." - find . -name "*.ts" -o -name "*.tsx" | grep -v node_modules | grep -v ".d.ts" - exit 1 - fi - echo "✓ No TypeScript files found" + # TypeScript check delegated to rsr-antipattern.yml (which honours the + # universal allowlist and the .claude/CLAUDE.md exemptions table). The + # blunt `find -name "*.ts"` form previously here false-positived on + # legitimate bridge files (e.g. tests/*.vitest.config.ts under the + # *vscode*/tests/ allowlist). - name: Check for ReScript files run: | diff --git a/.github/workflows/rsr-antipattern.yml b/.github/workflows/rsr-antipattern.yml index a6436491..48a3ed2d 100644 --- a/.github/workflows/rsr-antipattern.yml +++ b/.github/workflows/rsr-antipattern.yml @@ -137,83 +137,6 @@ jobs: print(f"✅ No TypeScript files outside allowlist ({len(exemption_patterns)} per-repo exemption(s) parsed).") PYEOF - # Universal builtin allowlist — bridges that need no per-repo declaration. - # Files matching any of these patterns are always allowed. - BUILTIN_GLOBS = [ - '*.d.ts', - '**/bindings/**', - '**/tests/**', '**/test/**', - '**/scripts/**', - '**/mcp-adapter/**', - '**/*vscode*/**', - '**/cli/**', - '**/mod.ts', - '**/lsp-server.ts', '**/lsp_server.ts', '**/lsp.ts', '**/*-lsp.ts', - '**/deno-*/**', - '**/node_modules/**', - '**/vendor/**', - '**/examples/**', - '**/ffi/**', - ] - - # Per-repo exemptions parsed from .claude/CLAUDE.md "TypeScript Exemptions" table. - # Single source of truth — adding a row here unblocks CI for that path. - # Format expected: - # ### TypeScript Exemptions ... - # | Path | Files | Rationale | Unblock condition | - # |---|---|---|---| - # | `path/to/file.ts` | 1 | ... | ... | - # | `dir/*.ts` | 6 | ... | ... | - exemptions = [] - claude_md = pathlib.Path('.claude/CLAUDE.md') - if claude_md.exists(): - in_table = False - for line in claude_md.read_text(encoding='utf-8').splitlines(): - if re.search(r'TypeScript [Ee]xemptions', line): - in_table = True - continue - if in_table and line.startswith(('### ', '## ', '# ')): - break - if in_table and line.startswith('|'): - m = re.match(r'\|\s*`([^`]+)`', line) - if m: - exemptions.append(m.group(1)) - - # Find all .ts and .tsx files - found = [] - for ext in ('ts', 'tsx'): - found.extend(str(p) for p in pathlib.Path('.').rglob(f'*.{ext}')) - - def allowed(path): - p = path.lstrip('./') - for g in BUILTIN_GLOBS + exemptions: - if fnmatch.fnmatchcase(p, g): - return True - # also treat glob ending with / as a directory prefix - base = g.rstrip('/').rstrip('*').rstrip('/') - if base and (p == base or p.startswith(base + '/')): - return True - return False - - bad = sorted(f for f in found if not allowed(f)) - if bad: - print("❌ TypeScript files detected outside the allowlist.\n") - for f in bad: - print(f" {f}") - print() - print("To resolve, either:") - print(" (a) migrate the file to AffineScript") - print(" (see Human_Programming_Guide.adoc migration chapter), OR") - print(" (b) move it to an allowlisted bridge path") - print(" (bindings/, tests/, scripts/, mcp-adapter/, *vscode*/, cli/, deno-*/, etc.), OR") - print(" (c) add an entry to the 'TypeScript Exemptions' table in .claude/CLAUDE.md") - print(" with rationale + unblock condition.") - if exemptions: - print(f"\n(Currently {len(exemptions)} exemption(s) parsed from .claude/CLAUDE.md.)") - sys.exit(1) - print(f"✅ No TypeScript files outside allowlist ({len(exemptions)} per-repo exemption(s) parsed).") - PYEOF - - name: Check for ReScript run: | # Estate policy: RS/TS/JS -> AffineScript -> typed-wasm. ReScript (.res)