Skip to content

fix(ci): unblock antipattern + delete duplicated TS check - #47

Merged
hyperpolymath merged 1 commit into
mainfrom
fix/ci-antipattern-and-language-policy
May 11, 2026
Merged

fix(ci): unblock antipattern + delete duplicated TS check#47
hyperpolymath merged 1 commit into
mainfrom
fix/ci-antipattern-and-language-policy

Conversation

@hyperpolymath

@hyperpolymath hyperpolymath commented May 11, 2026

Copy link
Copy Markdown
Owner

Summary

Two related CI fixes — both unblocking workflows that have been red on main for weeks.

1. .github/workflows/rsr-antipattern.yml — heredoc syntax bug

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 saw BUILTIN_GLOBS = [...] as a command and exited 127. Every commit to main since the check was added has hit this. Same bug was in hyperpolymath/my-lang (see hyperpolymath/my-lang#13).

The first Python block already does the full TypeScript exemption check honouring the universal allowlist and the parsed .claude/CLAUDE.md table. The duplicated second block is removed.

2. .github/workflows/language-policy.yml — duplicate TS check with no allowlist

The "Check for TypeScript files" step did a blunt find . -name "*.ts" filter with no allowlist beyond node_modules and *.d.ts. False-positived on legitimate bridge files like lol/test/vitest.config.ts, which lives under the **/test/** universal-allowlist pattern that rsr-antipattern.yml honours.

Two checks for the same banned-language family is also a single-source-of-truth violation. This PR removes the duplicate from language-policy.yml; rsr-antipattern.yml remains the canonical TypeScript-detection check. All other language-policy.yml steps (ReScript, Go, Python, V-lang, ATS2, Java/Kotlin, Swift, Flutter/Dart, Makefiles, package.json runtime deps) stay — they remain the single source of truth for those languages.

What this PR fixes vs. what stays red

Fixed by this PR:

  • antipattern-check no longer exits 127 on the heredoc syntax bug. It now runs to completion.
  • Check for Banned Languages / Check for TypeScript files no longer false-positives on lol/test/vitest.config.ts.

Surfaces real pre-existing migration debt (out of scope for this PR):

  • antipattern-check / Check for ReScript flags ~30 real .res files under rhodium-standard-repositories/satellites/{consent-aware-http,cccp/.../7-tentacles}/. These were previously hidden behind the heredoc crash — the check never reached this step before. The fix here unblocks the workflow's ability to surface them; the actual migration is its own multi-PR effort.
  • Check for Banned Languages / Check for ReScript files (in language-policy.yml) also flags the same .res files. Same observation.
  • Hypatia Neurosymbolic Analysis (Dogfooding)hypatia-cli.sh scan . exits 1 with no diagnostic across multiple repos. Filed at hyperpolymath/hypatia#213.

So this PR doesn't turn the standards CI fully green — that would need the ReScript migration and the Hypatia scanner fix. But it does:

  1. Unblock the antipattern check's ability to run.
  2. Eliminate a false-positive that was masking real signal.
  3. Halve the spurious red-X load on every PR.

Why now

Both bugs surfaced while merging the affinescript#64 port work in #46. Pre-existing — unrelated to that port — but kept its merge state at BLOCKED until force-merged with --admin. Fixing now so future port PRs have less friction.

Test plan

  • CI on this PR shows antipattern-check running to completion (not exit 127).
  • Check for Banned Languages / Check for TypeScript files step passes (no spurious vitest.config.ts hit).
  • Verified by sight: the only remaining failures on this PR are pre-existing — ReScript migration debt and the Hypatia scanner bug — not introduced or worsened here.

🤖 Generated with Claude Code

…ource

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 <noreply@anthropic.com>
@hyperpolymath
hyperpolymath merged commit 29cb6b8 into main May 11, 2026
16 of 19 checks passed
@hyperpolymath
hyperpolymath deleted the fix/ci-antipattern-and-language-policy branch May 11, 2026 08:20
Repository owner deleted a comment from chatgpt-codex-connector Bot May 13, 2026
hyperpolymath added a commit that referenced this pull request Jul 28, 2026
… tolerated (#557)

**Owner ruling, 2026-07-28:** *"nix flakes are deprecated and to be
thrown from the estate, we are only doing guix now… you can get rid of
them and references to them now or opportunistically as you think is
best."*

The canon already said *"Guix primary; NO Nix mirror"* (2026-05-18), but
**three places in this repo still read as though a flake were merely
discouraged** — and one actively tells you to keep it. A maintainer
following the current text would retain the flake and allowlist it. This
fixes the words, not the logic.

## What changed

**`spec/LANGUAGE-POLICY.adoc` §Package Management** — adds the hardened
paragraph: Nix is *removed*, not deprecated-but-tolerated, and removal
is a **standing opportunistic instruction** — strip it whenever you're
in a repo for any reason, including the *references* (direnv `use
flake`, `nix-shell` recipes, Dependabot's `nix` ecosystem,
package-manager detection branches, `.gitignore`/`.gitattributes`,
docs), not just the file.

It also records the measured caveat: **~25% of the estate's `guix.scm`
files are scaffold stubs, wrong-project, or `{{PROJECT_NAME}}`
placeholders**, so the *presence* of `guix.scm` is not evidence of
packaging.

**`scripts/check-package-policy.sh`** — the failure guidance led with
*"Do NOT simply delete the flake"*, which now reads as permission to
keep it. Rewritten to lead with removal **while keeping the real
engineering point that motivated it**: don't leave the repo unpackaged —
make Guix real (or fill the `Containerfile`, which is Podman-verifiable
where Guix isn't installable) *in the same change*. Explicitly rules out
allowlisting the flake.

**`.github/workflows/governance-reusable.yml`** — job renamed `Guix
primary / Nix fallback policy` → **`Guix packaging policy (Nix
retired)`**. There is no Nix fallback tier any more and the name was
teaching the opposite of the rule.

## Rename safety — checked, not assumed

A job rename changes the check-run name. A ruleset requiring the *old*
context would become a **phantom required check that never reports**,
blocking every merge — the known `--admin` trap.

I queried the rulesets on `standards`, `trope-checker`, `hermeneia` and
`hypatia`: the only required governance context is `governance /
Validate Hypatia Baseline`. **Nothing requires the Guix job.** Safe.

## Verified by running it

| case | result |
|---|---|
| Nix-only repo, past retirement date | `exit 1`, new guidance printed |
| repo with `guix.scm` | `exit 0`, *"Guix … detected (primary)"* |

`bash -n` clean; `governance-reusable.yml` still parses as YAML.

**No behavioural change to the policy logic** — the decision procedure,
grace-window variables and sealed-container detection are untouched.
This changes what the estate is *told*, plus one job label.

## Companion PR

`trope-checker`
[#47](hyperpolymath/trope-checker#47) is the
worked example: flake removed, the fake `guix-nix-policy.yml` deleted,
and ten config/script/doc references de-Nixed. Its root-shape gate went
FAIL → PASS with 0 failing checks.

## Scope note

61 other repos still carry a root `flake.nix` and 34 still carry the
fake `guix-nix-policy.yml`. Per the ruling those are to be handled
opportunistically; this PR makes the policy say so.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
hyperpolymath added a commit that referenced this pull request Jul 29, 2026
§2.1 already rules Nix retired and rightly warns against mass-deletion.
The owner ruling of 2026-07-28 — *"nix flakes are deprecated and to be
thrown from the estate"* — is **reconciled with that warning rather than
overriding it**: removal stays a per-repo judgement made while you are
*already working in the repo*. Opportunistic, never a fan-out sweep.

## What was genuinely missing

**Deleting `flake.nix` does not retire Nix.** Measured on
`trope-checker`
([#47](hyperpolymath/trope-checker#47)), one
flake had **ten satellites**:

| file | what it kept alive |
|---|---|
| `.envrc` | a direnv `use flake` block |
| `Justfile` + `contractiles/Justfile` | a `nix-shell` recipe |
| `build/setup.sh` | `nix` in package-manager detection **and** the
install switch |
| `install-tools.sh` | a flake-detecting branch running **ahead of
Guix** |
| `.github/dependabot.yml` | a `nix` `package-ecosystem` entry |
| `.gitignore` / `.gitattributes` | `flake.lock` and `*.nix` rules |
| `compliance/reuse/dep5` | `flake.lock` in the lockfile glob |
| docs / `PLAYBOOK.a2ml` | prose |

Leave any behind and the toolchain still reaches for Nix. They're now
listed in §2.1.

## Two traps recorded, because both cost time

- **`dependabot.yml` rejects the whole file on one malformed entry** —
re-parse after removing the `nix` ecosystem.
- **A root `.githooks/` is usually load-bearing** (CI runs validators
straight from it) — allowlist it in `root-allow.txt`; don't "tidy" it
away in passing.

Plus the standing caveat, restated where it will be read: a repo whose
`guix.scm` is a scaffold stub has **no working packaging** once the
flake is gone. Make Guix real, or fill the sealed container, *in the
same change*.

## Flagged, not resolved — the canon disagrees with itself

This repo carries **two** `LANGUAGE-POLICY.adoc` files and they
contradict each other:

- **`./LANGUAGE-POLICY.adoc`** (this one) self-declares canonical, is
the more current — §2.2 records the squisher-corpus identity clobber
measured 2026-07-29 across 418 repos — and makes **Bun tier 1**.
- **`./rhodium-standard-repositories/spec/LANGUAGE-POLICY.adoc`** still
lists **Deno** as *"Replaces Node/npm/Bun"*.

PR #51 on trope-checker cites the first; the estate `CLAUDE.md` I was
working under states the second. **I have not resolved this** — it needs
an owner decision on which file is authoritative. Note the Nix hardening
was also added to the *other* file earlier (standards #557), so both now
carry it; the runtime-tier contradiction is untouched.

Renders clean under `asciidoctor`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant