-
-
Notifications
You must be signed in to change notification settings - Fork 0
policy: add a language-policy drift gate (self-tested) #661
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
f6accdf
c5912a1
0966e4e
a4d9ea1
42a3a8a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| #!/usr/bin/env bash | ||
| # Language-policy drift gate. | ||
| # | ||
| # WHY THIS EXISTS. The estate's language policy is duplicated into ~372 per-repo | ||
| # `.claude/CLAUDE.md` files across 131 repos. On 2026-08-26 a census found 868 of them | ||
| # still listed **Bun as BANNED** with Deno as its replacement - the exact inverse of the | ||
| # standing ruling - and nothing had ever detected it. Correcting `standards` fixes one copy; | ||
| # agents read the local one. | ||
| # | ||
| # WHY ASSERTIONS, NOT A DIFF. The copies are legitimately not identical: repos carry their | ||
| # own exemption tables, architecture notes and carve-outs. A byte-for-byte generator would | ||
| # be permanently red. So this gate asserts the INVARIANTS the policy must satisfy, whatever | ||
| # the surrounding wording. | ||
| # | ||
| # Exit 0 = compliant. Exit 1 = drift. Every failure prints file:line. | ||
| set -uo pipefail | ||
| status=0 | ||
| files=$(git ls-files '*CLAUDE.md' 2>/dev/null | grep -v node_modules) | ||
| [ -z "$files" ] && { echo "no CLAUDE.md tracked - nothing to check"; exit 0; } | ||
|
Check failure on line 19 in tools/policy/check-language-policy.sh
|
||
|
|
||
| fail(){ printf ' \033[31mFAIL\033[0m %s\n %s\n' "$1" "$2"; status=1; } | ||
|
Check warning on line 21 in tools/policy/check-language-policy.sh
|
||
|
|
||
| for f in $files; do | ||
| echo "checking $f" | ||
|
|
||
| # --- must NOT appear ------------------------------------------------------- | ||
| # 1. Bun banned. This is the inversion that went undetected across 868 files. | ||
| if grep -nF -- '| Bun | Deno |' "$f" >/dev/null; then | ||
| fail "$f:$(grep -nF -- '| Bun | Deno |' "$f" | head -1 | cut -d: -f1)" \ | ||
| 'Bun is listed as BANNED with Deno as replacement - inverted. Bun is tier 1.' | ||
| fi | ||
| # 2. The rule that told repos not to declare dependencies at all. hyperpolymath/ubicity | ||
| # a phrase inside a blockquote or quotation marks is HISTORY, not policy | ||
| live(){ grep -vE '^[[:space:]]*>' "$1" | grep -vE '"[^"]*'"$2"'[^"]*"|\u201c[^\u201d]*'"$2"'[^\u201d]*\u201d'; } | ||
|
Check warning on line 34 in tools/policy/check-language-policy.sh
|
||
| # imported zod and glob, shipped no manifest, and could not build under ANY toolchain. | ||
| if live "$f" 'No package.json for runtime deps' | grep -qF 'No package.json for runtime deps'; then | ||
| fail "$f:$(grep -nF 'No package.json for runtime deps' "$f" | head -1 | cut -d: -f1)" \ | ||
| 'Forbids declaring dependencies. Bun is npm-compatible; a manifest is REQUIRED.' | ||
| fi | ||
| if live "$f" 'deno.json imports' | grep -qF 'deno.json imports'; then | ||
| fail "$f:$(grep -nF 'deno.json imports' "$f" | head -1 | cut -d: -f1)" \ | ||
| 'Directs dependency declaration into deno.json. Use package.json + bun.lock.' | ||
| fi | ||
| # 3. No tool description may advertise TypeScript. Owner ruling 2026-08-27: | ||
| # "no typescript ... that should not exist at all." | ||
| if grep -nE 'Executes .\.ts. directly|JS/TS runtime' "$f" >/dev/null; then | ||
| fail "$f:$(grep -nE 'Executes .\.ts. directly|JS/TS runtime' "$f" | head -1 | cut -d: -f1)" \ | ||
| 'Advertises TypeScript execution. TypeScript is banned; do not describe tools as TS runtimes.' | ||
| fi | ||
| # 4. Blanking scars. A bulk purge substituted a token with an EMPTY STRING, which also | ||
| # produced `rm -rf /lib` in wordpress-tools (the lethal shape is <token>/path -> /path). | ||
| if awk -F'|' 'NF==4 && $2 ~ /^[[:space:]]*$/{exit 0} END{exit 1}' "$f"; then | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 MEDIUM RISK The |
||
| fail "$f" 'Policy table row with an EMPTY first cell - blanking scar from a bulk substitution.' | ||
| fi | ||
| if grep -nF '| **** |' "$f" >/dev/null; then | ||
| fail "$f:$(grep -nF '| **** |' "$f" | head -1 | cut -d: -f1)" \ | ||
| 'Empty bold cell (****) - the language name was blanked out.' | ||
| fi | ||
| if grep -nE '\*\*No new +files\*\*|Only where +cannot' "$f" >/dev/null; then | ||
| fail "$f" 'Enforcement rule with a blanked language name.' | ||
| fi | ||
| # 5. A rule may not ban the language it mandates. | ||
| if grep -nE '^\| AffineScript \| AffineScript \|' "$f" >/dev/null; then | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 MEDIUM RISK This regex is too rigid and fails to account for the double-pipe ( |
||
| fail "$f" 'BANNED table maps AffineScript to itself - it bans the mandated language.' | ||
| fi | ||
|
|
||
| # --- must appear, if the file carries a language-policy table --------------- | ||
| if grep -qE '^### (ALLOWED|BANNED)' "$f"; then | ||
| { grep -qE '^\|[[:space:]]*\*\*Bun\*\*[[:space:]]*\|' "$f" || grep -qiE '^[-*][[:space:]]+\*{0,2}Bun\*{0,2}\b' "$f"; } || \ | ||
| fail "$f" 'No Bun row in ALLOWED. Bun is the tier-1 JS runtime and package manager.' | ||
| { grep -qE '^\|[[:space:]]*\*{0,2}Deno\*{0,2}[[:space:]]*\|[[:space:]]*\*{0,2}Bun\*{0,2}[[:space:]]*\|' "$f" || grep -qiE '^[-*][[:space:]]+Deno[[:space:]]*\(use Bun\)' "$f"; } || \ | ||
| fail "$f" 'Deno is not listed in BANNED with Bun as its replacement (ruling 2026-08-26).' | ||
| fi | ||
| done | ||
|
|
||
| if [ $status -eq 0 ]; then echo "language policy OK"; else | ||
|
Check failure on line 76 in tools/policy/check-language-policy.sh
|
||
| echo | ||
| echo "Language-policy drift detected. Canonical source: hyperpolymath/standards .claude/CLAUDE.md" | ||
| echo "Fix the local copy; do not weaken this gate." | ||
| fi | ||
| exit $status | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 MEDIUM RISK
Iterating over file paths with a word-splitting
forloop is unsafe if any file path contains a space. Use awhile readloop orxargs -0to handle filenames correctly.