From 1878c24d42a498ec93c5fe3f3a8f8025e4e49257 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Thu, 30 Apr 2026 16:44:53 +0100 Subject: [PATCH] chore: migrate language policy from ReScript to AffineScript estate-wide Per user directive 2026-04-30: '.res is out, all .ts to .affine now; affinescript-config-present replaces.' CI rule workflows (.github/workflows/ + a2ml-action duplicates): - ts-blocker.yml: extend to also block .res; messages -> AffineScript - rsr-antipattern.yml: new ReScript-block step + new rescript.json block step; allowed/blocked lists updated - language-policy.yml: new ReScript-block step; replace 'use ReScript' with 'use AffineScript'; switch .scm to .a2ml in required-files; add 'affine' to SPDX-header extensions Canonical rule (hypatia-rules/rsr-self-compliance.a2ml): - @forbidden_files: .ts reason -> AffineScript; new .res entry Contractile rules (.machine_readable/contractiles/must/Mustfile.a2ml): - rescript-json-present -> affinescript-config-present - no-typescript / no-python messages -> AffineScript - new no-rescript rule - no-unsafe-coerce now scans .affine (was .res) Agent-facing policy (.claude/CLAUDE.md + sonnet.md + consent-aware-http copy): ReScript replaced by AffineScript in allowed/banned tables; ReScript explicitly added to banned list (2026-04-30). RSR_OUTLINE.adoc (3 copies): Tier-1 'ReScript' -> 'AffineScript'; prohibited 'TypeScript/JavaScript (use ReScript)' -> 'TypeScript/ JavaScript/ReScript (use AffineScript)'. a2ml-templates/{META,AGENTIC}.a2ml.template: drop rescript, add affinescript; rescript added to banned list. agentic-a2ml/docs/ROADMAP.adoc: ReScript template -> AffineScript template. consent-aware-http/.migration/PYTHON_TO_RUST_RESCRIPT.md DELETED; replaced by .../PYTHON_TO_RUST_AFFINESCRIPT.adoc with rewritten content (no ReScript intermediate hop) and .md->.adoc per doc-format rule. Supersedes the narrower PR #34. Files deliberately not touched are listed in the PR body (bot exclusion registry, .gitignore artefacts, language-agnostic build hygiene rules, factual references). Co-Authored-By: Claude Opus 4.7 (1M context) --- .claude/CLAUDE.md | 16 ++++---- .github/workflows/language-policy.yml | 26 +++++++++---- .github/workflows/rsr-antipattern.yml | 35 +++++++++++++---- .github/workflows/ts-blocker.yml | 23 ++++++----- .../contractiles/must/Mustfile.a2ml | 19 ++++++---- 0-ai-gatekeeper-protocol/RSR_OUTLINE.adoc | 4 +- .../repo-guardian-fs/RSR_OUTLINE.adoc | 4 +- a2ml-templates/AGENTIC.a2ml.template | 4 +- a2ml-templates/META.a2ml.template | 2 +- .../.github/workflows/rsr-antipattern.yml | 34 +++++++++++++---- .../validate/.github/workflows/ts-blocker.yml | 21 +++++----- agentic-a2ml/docs/ROADMAP.adoc | 2 +- ai-instruction/sonnet.md | 4 +- consent-aware-http/.claude/CLAUDE.md | 17 +++++---- .../.github/workflows/ts-blocker.yml | 21 +++++----- .../PYTHON_TO_RUST_AFFINESCRIPT.adoc | 38 +++++++++++++++++++ .../.migration/PYTHON_TO_RUST_RESCRIPT.md | 24 ------------ consent-aware-http/RSR_OUTLINE.adoc | 4 +- hypatia-rules/rsr-self-compliance.a2ml | 4 +- 19 files changed, 193 insertions(+), 109 deletions(-) create mode 100644 consent-aware-http/.migration/PYTHON_TO_RUST_AFFINESCRIPT.adoc delete mode 100644 consent-aware-http/.migration/PYTHON_TO_RUST_RESCRIPT.md diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 529185ca..0d197895 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -32,7 +32,7 @@ for the canonical statement. | Language/Tool | Use Case | Notes | |---------------|----------|-------| -| **ReScript** | Primary application code | Compiles to JS, type-safe | +| **AffineScript** | Primary application code | Compiles to typed-wasm; affine/linear types. Replaces ReScript across the estate (RS/TS/JS → AffineScript → typed-wasm). | | **Deno** | Runtime & package management | Replaces Node/npm/bun | | **Rust/SPARK** | Performance-critical, systems, WASM, CLI tools, safety-critical | "Rust" always means "Rust/SPARK" per terminology note above. Preferred over Ada where reachable. | | **Zig** | FFI layer (hyperpolymath ABI/FFI standard), memory-safe systems where Rust/SPARK is overkill | Also the migration target for V-lang | @@ -43,7 +43,7 @@ for the canonical statement. | **Elixir** | Backend services, distributed systems | BEAM, Phoenix, OTP | | **Haskell** | Type-heavy tools, registry validation | Scaffoldia CLI | | **Bash/POSIX Shell** | Scripts, automation | Keep minimal | -| **JavaScript** | Only where ReScript cannot | MCP protocol glue, Deno APIs | +| **JavaScript** | Only where AffineScript cannot | MCP protocol glue, Deno APIs (transitional; prefer .affine where possible) | | **Nickel** | Configuration language | For complex configs | | **A2ML** | State/meta files | STATE.a2ml, META.a2ml, etc. (TOML-like format) | | **Julia** | Batch scripts, data processing | Per RSR | @@ -54,13 +54,14 @@ for the canonical statement. | Banned | Replacement | Notes | |--------|-------------|-------| -| TypeScript | ReScript | | +| TypeScript | AffineScript | RS/TS/JS → AffineScript → typed-wasm. | +| **ReScript** | AffineScript | Banned in new code as of 2026-04-30. Existing `.res` files migrate to `.affine` directly (do not pass through ReScript). | | Node.js | Deno | | | npm | Deno | | | Bun | Deno | | | pnpm/yarn | Deno | | | Go | Rust/SPARK | | -| **Python** | ReScript/Rust/SPARK/Julia | Fully banned, no exceptions (SaltStack exception removed 2026-01-03) | +| **Python** | AffineScript/Rust/SPARK/Julia | Fully banned, no exceptions (SaltStack exception removed 2026-01-03) | | Java/Kotlin | Rust/SPARK, Tauri, Dioxus | | | Swift | Tauri/Dioxus | | | React Native | Tauri/Dioxus | | @@ -70,7 +71,8 @@ for the canonical statement. | **Makefiles** | Mustfile/justfile | | **NOTE:** Python is fully banned. V-lang is fully banned (2026-04-10). ATS2 is -fully banned in favour of Idris2 + Rust/SPARK. All three bans are enforced by +fully banned in favour of Idris2 + Rust/SPARK. ReScript is fully banned in new +code as of 2026-04-30 (use AffineScript). All four bans are enforced by `.github/workflows/language-policy.yml`. ### Build System @@ -87,14 +89,14 @@ See: https://github.com/hyperpolymath/mustfile **No exceptions for Kotlin/Swift** - use Rust-first approach: -1. **Tauri 2.0+** - Web UI (ReScript) + Rust backend, MIT/Apache-2.0 +1. **Tauri 2.0+** - Web UI (AffineScript → typed-wasm) + Rust backend, MIT/Apache-2.0 2. **Dioxus** - Pure Rust native UI, MIT/Apache-2.0 Both are FOSS with independent governance (no Big Tech). ### Enforcement Rules -1. **No new TypeScript files** - Convert existing TS to ReScript +1. **No new TypeScript or ReScript files** - Convert existing TS/RS to AffineScript directly (`.affine`); ReScript is no longer the destination 2. **No package.json for runtime deps** - Use deno.json imports 3. **No node_modules in production** - Deno caches deps automatically 4. **No Go code** - Use Rust instead diff --git a/.github/workflows/language-policy.yml b/.github/workflows/language-policy.yml index 2331a54f..df36175f 100644 --- a/.github/workflows/language-policy.yml +++ b/.github/workflows/language-policy.yml @@ -21,12 +21,23 @@ jobs: - 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 ReScript instead." + 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" + - name: Check for ReScript files + run: | + # Estate policy: RS/TS/JS -> AffineScript -> typed-wasm. + # ReScript (.res) is no longer the TS replacement. + if find . -name "*.res" | grep -v node_modules | head -1 | grep -q .; then + echo "::error::ReScript files found. Use AffineScript instead." + find . -name "*.res" | grep -v node_modules + exit 1 + fi + echo "✓ No ReScript files found" + - name: Check for Go files run: | if find . -name "*.go" | head -1 | grep -q .; then @@ -41,7 +52,7 @@ jobs: # Allow Python only in ansible/ directories or for Ansible-specific files PYTHON_FILES=$(find . -name "*.py" | grep -v __pycache__ | grep -v ".venv" | grep -v "ansible" | grep -v "molecule" || true) if [ -n "$PYTHON_FILES" ]; then - echo "::error::Python files found outside Ansible context. Rewrite in Rust/ReScript." + echo "::error::Python files found outside Ansible context. Rewrite in Rust/AffineScript." echo "$PYTHON_FILES" exit 1 fi @@ -139,11 +150,12 @@ jobs: echo "::warning::.machine_readable/ directory not found" else echo "✓ .machine_readable/ directory exists" - for scm in STATE META ECOSYSTEM AGENTIC NEUROSYM PLAYBOOK; do - if [ ! -f ".machine_readable/${scm}.scm" ]; then - echo "::warning::Missing .machine_readable/${scm}.scm" + # Per estate policy: .a2ml is canonical; .scm is reserved for Guix. + for a2ml in STATE META ECOSYSTEM AGENTIC NEUROSYM PLAYBOOK; do + if [ ! -f ".machine_readable/6a2/${a2ml}.a2ml" ] && [ ! -f ".machine_readable/${a2ml}.a2ml" ]; then + echo "::warning::Missing .machine_readable/6a2/${a2ml}.a2ml (or top-level fallback)" else - echo "✓ .machine_readable/${scm}.scm exists" + echo "✓ ${a2ml}.a2ml present" fi done fi @@ -159,7 +171,7 @@ jobs: - name: Check SPDX headers run: | MISSING_SPDX=0 - for ext in rs res js jsx mjs ts tsx py go java kt swift sh bash; do + for ext in rs affine js jsx mjs ts tsx py go java kt swift sh bash; do while IFS= read -r file; do if [ -n "$file" ] && ! head -5 "$file" | grep -q "SPDX-License-Identifier"; then echo "::warning::Missing SPDX header: $file" diff --git a/.github/workflows/rsr-antipattern.yml b/.github/workflows/rsr-antipattern.yml index 7b2e6562..e95a8798 100644 --- a/.github/workflows/rsr-antipattern.yml +++ b/.github/workflows/rsr-antipattern.yml @@ -1,9 +1,8 @@ # SPDX-License-Identifier: PMPL-1.0 # RSR Anti-Pattern CI Check -# SPDX-License-Identifier: PMPL-1.0 # -# Enforces: No TypeScript, No Go, No Python (except SaltStack), No npm -# Allows: ReScript, Deno, WASM, Rust, OCaml, Haskell, Guile/Scheme +# Enforces: No TypeScript, No ReScript, No Go, No Python (except SaltStack), No npm +# Allows: AffineScript, Deno, WASM, Rust, OCaml, Haskell, Guile/Scheme name: RSR Anti-Pattern Check @@ -28,15 +27,27 @@ jobs: - name: Check for TypeScript run: | # Exclude bindings/deno/ - those are Deno FFI files using Deno.dlopen, not plain TypeScript - # Exclude .d.ts files - those are TypeScript type declarations for ReScript FFI + # Exclude .d.ts files - generated type declarations for FFI TS_FILES=$(find . \( -name "*.ts" -o -name "*.tsx" \) | grep -v node_modules | grep -v 'bindings/deno' | grep -v '\.d\.ts$' || true) if [ -n "$TS_FILES" ]; then - echo "❌ TypeScript files detected - use ReScript instead" + echo "❌ TypeScript files detected - use AffineScript instead" echo "$TS_FILES" exit 1 fi echo "✅ No TypeScript files (Deno FFI bindings excluded)" + - name: Check for ReScript + run: | + # Estate policy: RS/TS/JS -> AffineScript -> typed-wasm. ReScript (.res) + # is no longer used as the TS replacement; new code uses .affine instead. + RES_FILES=$(find . -name "*.res" | grep -v node_modules || true) + if [ -n "$RES_FILES" ]; then + echo "❌ ReScript files detected - use AffineScript instead" + echo "$RES_FILES" + exit 1 + fi + echo "✅ No ReScript files" + - name: Check for Go run: | if find . -name "*.go" | grep -q .; then @@ -67,11 +78,19 @@ jobs: - name: Check for tsconfig run: | if [ -f "tsconfig.json" ]; then - echo "❌ tsconfig.json detected - use ReScript instead" + echo "❌ tsconfig.json detected - use AffineScript instead" exit 1 fi echo "✅ No tsconfig.json" + - name: Check for rescript.json + run: | + if [ -f "rescript.json" ] || [ -f "bsconfig.json" ]; then + echo "❌ rescript.json/bsconfig.json detected - use AffineScript config instead" + exit 1 + fi + echo "✅ No rescript.json/bsconfig.json" + - name: Verify Deno presence (if package.json exists) run: | if [ -f "package.json" ]; then @@ -86,8 +105,8 @@ jobs: echo "╔════════════════════════════════════════════════════════════╗" echo "║ RSR Anti-Pattern Check Passed ✅ ║" echo "║ ║" - echo "║ Allowed: ReScript, Deno, WASM, Rust, OCaml, Haskell, ║" + echo "║ Allowed: AffineScript, Deno, WASM, Rust, OCaml, Haskell, ║" echo "║ Guile/Scheme, SaltStack (Python) ║" echo "║ ║" - echo "║ Blocked: TypeScript, Go, npm, Python (non-Salt) ║" + echo "║ Blocked: TypeScript, ReScript, Go, npm, Python (non-Salt)║" echo "╚════════════════════════════════════════════════════════════╝" diff --git a/.github/workflows/ts-blocker.yml b/.github/workflows/ts-blocker.yml index 6a09ba26..3a72b3fe 100644 --- a/.github/workflows/ts-blocker.yml +++ b/.github/workflows/ts-blocker.yml @@ -1,5 +1,5 @@ # SPDX-License-Identifier: PMPL-1.0-or-later -name: TypeScript/JavaScript Blocker +name: TypeScript / JavaScript / ReScript Blocker on: [push, pull_request] permissions: @@ -12,15 +12,20 @@ jobs: contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Block new TypeScript/JavaScript + - name: Block new TypeScript / JavaScript / ReScript run: | + # Estate language policy: RS/TS/JS -> AffineScript -> typed-wasm. + # ReScript (.res) is also banned now that AffineScript is the destination + # — no longer used as the TS replacement. NEW_TS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(ts|tsx)$' | grep -v '\.gen\.' || true) - NEW_JS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(js|jsx)$' | grep -v '\.res\.js$' | grep -v '\.gen\.' | grep -v 'node_modules' || true) - - if [ -n "$NEW_TS" ] || [ -n "$NEW_JS" ]; then - echo "❌ New TS/JS files detected. Use ReScript instead." - [ -n "$NEW_TS" ] && echo "$NEW_TS" - [ -n "$NEW_JS" ] && echo "$NEW_JS" + NEW_JS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(js|jsx)$' | grep -v '\.gen\.' | grep -v 'node_modules' || true) + NEW_RES=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.res$' || true) + + if [ -n "$NEW_TS" ] || [ -n "$NEW_JS" ] || [ -n "$NEW_RES" ]; then + echo "❌ New TS/JS/ReScript files detected. Use AffineScript instead." + [ -n "$NEW_TS" ] && echo "$NEW_TS" + [ -n "$NEW_JS" ] && echo "$NEW_JS" + [ -n "$NEW_RES" ] && echo "$NEW_RES" exit 1 fi - echo "✅ ReScript policy enforced" + echo "✅ AffineScript policy enforced" diff --git a/.machine_readable/contractiles/must/Mustfile.a2ml b/.machine_readable/contractiles/must/Mustfile.a2ml index 275ff336..d4da6835 100644 --- a/.machine_readable/contractiles/must/Mustfile.a2ml +++ b/.machine_readable/contractiles/must/Mustfile.a2ml @@ -68,9 +68,9 @@ These are hard requirements — CI and pre-commit hooks fail if any check fails. ## Web Client -### rescript-json-present -- description: ReScript config exists for web client -- run: test -f client/web/rescript.json +### affinescript-config-present +- description: AffineScript config exists for web client (replaces former rescript-json-present) +- run: test -f client/web/affinescript.toml || test -f client/web/dune-project - severity: warning ### web-entry-point @@ -98,8 +98,8 @@ These are hard requirements — CI and pre-commit hooks fail if any check fails. - severity: critical ### no-unsafe-coerce -- description: No unsafeCoerce in ReScript/Haskell code -- run: test -z "$(find . \( -name '*.res' -o -name '*.hs' \) -not -path '*/deps/*' -not -path '*/node_modules/*' -exec grep -l 'unsafeCoerce\|Obj.magic' {} \; 2>/dev/null)" +- description: No unsafeCoerce / Obj.magic in source (legacy ReScript/Haskell patterns; AffineScript has no equivalent escape hatch by design) +- run: test -z "$(find . \( -name '*.affine' -o -name '*.hs' \) -not -path '*/deps/*' -not -path '*/node_modules/*' -exec grep -l 'unsafeCoerce\|Obj.magic' {} \; 2>/dev/null)" - severity: critical ## Container Policy @@ -117,12 +117,17 @@ These are hard requirements — CI and pre-commit hooks fail if any check fails. ## Language Policy ### no-typescript -- description: No TypeScript files (use ReScript) +- description: No TypeScript files (use AffineScript) - run: test -z "$(find . -name '*.ts' -not -name '*.d.ts' -not -path '*/deps/*' -not -path '*/node_modules/*' 2>/dev/null)" - severity: warning +### no-rescript +- description: No ReScript files (use AffineScript) +- run: test -z "$(find . -name '*.res' -not -path '*/deps/*' -not -path '*/node_modules/*' 2>/dev/null)" +- severity: warning + ### no-python -- description: No Python files (use Julia/Rust/ReScript) +- description: No Python files (use Julia/Rust/AffineScript) - run: test -z "$(find . -name '*.py' -not -path '*/deps/*' -not -path '*/node_modules/*' 2>/dev/null)" - severity: warning diff --git a/0-ai-gatekeeper-protocol/RSR_OUTLINE.adoc b/0-ai-gatekeeper-protocol/RSR_OUTLINE.adoc index 6e9f5981..705d6dc1 100644 --- a/0-ai-gatekeeper-protocol/RSR_OUTLINE.adoc +++ b/0-ai-gatekeeper-protocol/RSR_OUTLINE.adoc @@ -146,7 +146,7 @@ project/ === Language Tiers -* **Tier 1** (Gold): Rust, Elixir, Zig, Ada, Haskell, ReScript +* **Tier 1** (Gold): Rust(+SPARK), Elixir, Zig, Ada, Haskell, AffineScript * **Tier 2** (Silver): Nickel, Racket, Guile Scheme, Nix * **Infrastructure**: Guix channels, derivations @@ -166,7 +166,7 @@ project/ === Prohibited * Python outside `salt/` directory -* TypeScript/JavaScript (use ReScript) +* TypeScript/JavaScript/ReScript (use AffineScript) * CUE (use Guile/Nickel) * `Dockerfile` (use `Containerfile`) diff --git a/0-ai-gatekeeper-protocol/repo-guardian-fs/RSR_OUTLINE.adoc b/0-ai-gatekeeper-protocol/repo-guardian-fs/RSR_OUTLINE.adoc index 6e9f5981..705d6dc1 100644 --- a/0-ai-gatekeeper-protocol/repo-guardian-fs/RSR_OUTLINE.adoc +++ b/0-ai-gatekeeper-protocol/repo-guardian-fs/RSR_OUTLINE.adoc @@ -146,7 +146,7 @@ project/ === Language Tiers -* **Tier 1** (Gold): Rust, Elixir, Zig, Ada, Haskell, ReScript +* **Tier 1** (Gold): Rust(+SPARK), Elixir, Zig, Ada, Haskell, AffineScript * **Tier 2** (Silver): Nickel, Racket, Guile Scheme, Nix * **Infrastructure**: Guix channels, derivations @@ -166,7 +166,7 @@ project/ === Prohibited * Python outside `salt/` directory -* TypeScript/JavaScript (use ReScript) +* TypeScript/JavaScript/ReScript (use AffineScript) * CUE (use Guile/Nickel) * `Dockerfile` (use `Containerfile`) diff --git a/a2ml-templates/AGENTIC.a2ml.template b/a2ml-templates/AGENTIC.a2ml.template index f8e62f2e..551b1827 100644 --- a/a2ml-templates/AGENTIC.a2ml.template +++ b/a2ml-templates/AGENTIC.a2ml.template @@ -57,10 +57,10 @@ documentation = "inline" # ── Language Constraints ────────────────────────────────────────────────── [agentic-config.constraints] # languages: Languages the agent is allowed to write in this project. -languages = ["rescript", "rust", "gleam", "{{PRIMARY_LANGUAGE}}"] +languages = ["affinescript", "rust", "gleam", "{{PRIMARY_LANGUAGE}}"] # banned: Languages the agent must NEVER use, even if asked. -banned = ["typescript", "go", "python", "makefile"] +banned = ["typescript", "rescript", "go", "python", "makefile"] # ── Project-Specific Overrides ──────────────────────────────────────────── [agentic-config.project-specific] diff --git a/a2ml-templates/META.a2ml.template b/a2ml-templates/META.a2ml.template index affd9d41..e5093c03 100644 --- a/a2ml-templates/META.a2ml.template +++ b/a2ml-templates/META.a2ml.template @@ -27,7 +27,7 @@ name = "{{PROJECT_NAME}}" # ── Development Practices ────────────────────────────────────────────────── [project-meta.development-practices] # code-style: Which language's conventions to follow. -# Common values: rescript, rust, gleam, elixir, idris2 +# Common values: affinescript, rust, gleam, elixir, idris2 code-style = "{{CODE_STYLE}}" # security: Which security framework is used. diff --git a/a2ml/actions/validate/.github/workflows/rsr-antipattern.yml b/a2ml/actions/validate/.github/workflows/rsr-antipattern.yml index a001dcd2..97653cc1 100644 --- a/a2ml/actions/validate/.github/workflows/rsr-antipattern.yml +++ b/a2ml/actions/validate/.github/workflows/rsr-antipattern.yml @@ -1,9 +1,8 @@ # SPDX-License-Identifier: PMPL-1.0-or-later # RSR Anti-Pattern CI Check -# SPDX-License-Identifier: PMPL-1.0-or-later # -# Enforces: No TypeScript, No Go, No Python (except SaltStack), No npm -# Allows: ReScript, Deno, WASM, Rust, OCaml, Haskell, Guile/Scheme +# Enforces: No TypeScript, No ReScript, No Go, No Python (except SaltStack), No npm +# Allows: AffineScript, Deno, WASM, Rust, OCaml, Haskell, Guile/Scheme name: RSR Anti-Pattern Check @@ -27,15 +26,26 @@ jobs: - name: Check for TypeScript run: | # Exclude bindings/deno/ - those are Deno FFI files using Deno.dlopen, not plain TypeScript - # Exclude .d.ts files - those are TypeScript type declarations for ReScript FFI + # Exclude .d.ts files - generated type declarations for FFI TS_FILES=$(find . \( -name "*.ts" -o -name "*.tsx" \) | grep -v node_modules | grep -v 'bindings/deno' | grep -v '\.d\.ts$' || true) if [ -n "$TS_FILES" ]; then - echo "❌ TypeScript files detected - use ReScript instead" + echo "❌ TypeScript files detected - use AffineScript instead" echo "$TS_FILES" exit 1 fi echo "✅ No TypeScript files (Deno FFI bindings excluded)" + - name: Check for ReScript + run: | + # Estate policy: RS/TS/JS -> AffineScript -> typed-wasm. + RES_FILES=$(find . -name "*.res" | grep -v node_modules || true) + if [ -n "$RES_FILES" ]; then + echo "❌ ReScript files detected - use AffineScript instead" + echo "$RES_FILES" + exit 1 + fi + echo "✅ No ReScript files" + - name: Check for Go run: | if find . -name "*.go" | grep -q .; then @@ -66,11 +76,19 @@ jobs: - name: Check for tsconfig run: | if [ -f "tsconfig.json" ]; then - echo "❌ tsconfig.json detected - use ReScript instead" + echo "❌ tsconfig.json detected - use AffineScript instead" exit 1 fi echo "✅ No tsconfig.json" + - name: Check for rescript.json + run: | + if [ -f "rescript.json" ] || [ -f "bsconfig.json" ]; then + echo "❌ rescript.json/bsconfig.json detected - use AffineScript config instead" + exit 1 + fi + echo "✅ No rescript.json/bsconfig.json" + - name: Verify Deno presence (if package.json exists) run: | if [ -f "package.json" ]; then @@ -85,8 +103,8 @@ jobs: echo "╔════════════════════════════════════════════════════════════╗" echo "║ RSR Anti-Pattern Check Passed ✅ ║" echo "║ ║" - echo "║ Allowed: ReScript, Deno, WASM, Rust, OCaml, Haskell, ║" + echo "║ Allowed: AffineScript, Deno, WASM, Rust, OCaml, Haskell, ║" echo "║ Guile/Scheme, SaltStack (Python) ║" echo "║ ║" - echo "║ Blocked: TypeScript, Go, npm, Python (non-Salt) ║" + echo "║ Blocked: TypeScript, ReScript, Go, npm, Python (non-Salt)║" echo "╚════════════════════════════════════════════════════════════╝" diff --git a/a2ml/actions/validate/.github/workflows/ts-blocker.yml b/a2ml/actions/validate/.github/workflows/ts-blocker.yml index 5c34a58c..3b1ce83c 100644 --- a/a2ml/actions/validate/.github/workflows/ts-blocker.yml +++ b/a2ml/actions/validate/.github/workflows/ts-blocker.yml @@ -1,5 +1,5 @@ # SPDX-License-Identifier: PMPL-1.0-or-later -name: TypeScript/JavaScript Blocker +name: TypeScript / JavaScript / ReScript Blocker on: [push, pull_request] permissions: read-all @@ -11,15 +11,18 @@ jobs: contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Block new TypeScript/JavaScript + - name: Block new TypeScript / JavaScript / ReScript run: | + # Estate policy: RS/TS/JS -> AffineScript -> typed-wasm. NEW_TS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(ts|tsx)$' | grep -v '\.gen\.' || true) - NEW_JS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(js|jsx)$' | grep -v '\.res\.js$' | grep -v '\.gen\.' | grep -v 'node_modules' || true) - - if [ -n "$NEW_TS" ] || [ -n "$NEW_JS" ]; then - echo "❌ New TS/JS files detected. Use ReScript instead." - [ -n "$NEW_TS" ] && echo "$NEW_TS" - [ -n "$NEW_JS" ] && echo "$NEW_JS" + NEW_JS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(js|jsx)$' | grep -v '\.gen\.' | grep -v 'node_modules' || true) + NEW_RES=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.res$' || true) + + if [ -n "$NEW_TS" ] || [ -n "$NEW_JS" ] || [ -n "$NEW_RES" ]; then + echo "❌ New TS/JS/ReScript files detected. Use AffineScript instead." + [ -n "$NEW_TS" ] && echo "$NEW_TS" + [ -n "$NEW_JS" ] && echo "$NEW_JS" + [ -n "$NEW_RES" ] && echo "$NEW_RES" exit 1 fi - echo "✅ ReScript policy enforced" + echo "✅ AffineScript policy enforced" diff --git a/agentic-a2ml/docs/ROADMAP.adoc b/agentic-a2ml/docs/ROADMAP.adoc index 87dc384f..a9537c0f 100644 --- a/agentic-a2ml/docs/ROADMAP.adoc +++ b/agentic-a2ml/docs/ROADMAP.adoc @@ -51,7 +51,7 @@ * [ ] Language-specific template branches: ** Rust template (Tier 1) -** ReScript template (Tier 1) +** AffineScript template (Tier 1) ** Elixir template (Tier 1) ** Ada/SPARK template (Tier 1) * [ ] Example CI/CD configurations per language diff --git a/ai-instruction/sonnet.md b/ai-instruction/sonnet.md index e13903bd..87077343 100644 --- a/ai-instruction/sonnet.md +++ b/ai-instruction/sonnet.md @@ -83,8 +83,8 @@ You are implementing in . - -- +- - - AffineScript -> typed-wasm. NEW_TS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(ts|tsx)$' | grep -v '\.gen\.' || true) - NEW_JS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(js|jsx)$' | grep -v '\.res\.js$' | grep -v '\.gen\.' | grep -v 'node_modules' || true) - - if [ -n "$NEW_TS" ] || [ -n "$NEW_JS" ]; then - echo "❌ New TS/JS files detected. Use ReScript instead." - [ -n "$NEW_TS" ] && echo "$NEW_TS" - [ -n "$NEW_JS" ] && echo "$NEW_JS" + NEW_JS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(js|jsx)$' | grep -v '\.gen\.' | grep -v 'node_modules' || true) + NEW_RES=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.res$' || true) + + if [ -n "$NEW_TS" ] || [ -n "$NEW_JS" ] || [ -n "$NEW_RES" ]; then + echo "❌ New TS/JS/ReScript files detected. Use AffineScript instead." + [ -n "$NEW_TS" ] && echo "$NEW_TS" + [ -n "$NEW_JS" ] && echo "$NEW_JS" + [ -n "$NEW_RES" ] && echo "$NEW_RES" exit 1 fi - echo "✅ ReScript policy enforced" + echo "✅ AffineScript policy enforced" diff --git a/consent-aware-http/.migration/PYTHON_TO_RUST_AFFINESCRIPT.adoc b/consent-aware-http/.migration/PYTHON_TO_RUST_AFFINESCRIPT.adoc new file mode 100644 index 00000000..f61e5dcb --- /dev/null +++ b/consent-aware-http/.migration/PYTHON_TO_RUST_AFFINESCRIPT.adoc @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: PMPL-1.0-or-later += Python → Rust / AffineScript Migration Guide + +== Policy + +This repo contains Python code that should be migrated to: + +* *Rust(+SPARK)* for systems / ML / backend code +* *AffineScript* (`.affine` → typed-wasm) for web / frontend / scripting + +Per estate language defaults (RS/TS/JS → AffineScript → typed-wasm; Python banned), `.res` and `.py` are no longer destinations — replace them with `.affine` directly. + +== Why + +* Python has dynamic typing and runtime errors. +* Rust(+SPARK) provides memory safety, performance, and (for boundary kernels) machine-checked correctness. +* AffineScript provides type safety, affine/linear types for resource-handling, and a deterministic compile target (typed-wasm). + +== Migration Steps + +. Identify Python files by purpose (systems vs web). +. Create equivalent Rust modules in `src/` or AffineScript in `src/*.affine`. +. Use `cargo` (Rust) or AffineScript build (`affinescript compile`) tooling. +. Remove Python files after migration. +. Update CI/CD (the `language-policy.yml` and `rsr-antipattern.yml` workflows already block new `.py` and `.res` files). + +== Exceptions + +* SaltStack configurations (legacy exemption — the SaltStack Python carve-out was removed 2026-01-03; verify whether this exemption still applies to your repo). +* One-time scripts (convert to shell or Rust). + +== Status + +PENDING MIGRATION + +== Notes on the prior `.res` step + +This guide previously named ReScript as the web/frontend destination. As of 2026-04-30, ReScript is also banned in new code — the canonical web/frontend destination is now AffineScript directly. Any in-flight Python → ReScript migration should be redirected to Python → AffineScript without an intermediate ReScript hop. diff --git a/consent-aware-http/.migration/PYTHON_TO_RUST_RESCRIPT.md b/consent-aware-http/.migration/PYTHON_TO_RUST_RESCRIPT.md deleted file mode 100644 index c5dade20..00000000 --- a/consent-aware-http/.migration/PYTHON_TO_RUST_RESCRIPT.md +++ /dev/null @@ -1,24 +0,0 @@ -# Python → Rust/ReScript Migration Guide - -## Policy -This repo contains Python code that should be migrated to: -- **Rust** for systems/ML/backend code -- **ReScript** for web/frontend/scripting - -## Why -- Python has dynamic typing and runtime errors -- Rust provides memory safety and performance -- ReScript provides type safety and JS interop - -## Migration Steps -1. Identify Python files by purpose (systems vs web) -2. Create equivalent Rust modules in `src/` or ReScript in `src/*.res` -3. Use `cargo` or `rescript` build systems -4. Remove Python files after migration -5. Update CI/CD - -## Exceptions -- SaltStack configurations (exempt) -- One-time scripts (convert to shell/Rust) - -## Status: PENDING MIGRATION diff --git a/consent-aware-http/RSR_OUTLINE.adoc b/consent-aware-http/RSR_OUTLINE.adoc index 6e9f5981..705d6dc1 100644 --- a/consent-aware-http/RSR_OUTLINE.adoc +++ b/consent-aware-http/RSR_OUTLINE.adoc @@ -146,7 +146,7 @@ project/ === Language Tiers -* **Tier 1** (Gold): Rust, Elixir, Zig, Ada, Haskell, ReScript +* **Tier 1** (Gold): Rust(+SPARK), Elixir, Zig, Ada, Haskell, AffineScript * **Tier 2** (Silver): Nickel, Racket, Guile Scheme, Nix * **Infrastructure**: Guix channels, derivations @@ -166,7 +166,7 @@ project/ === Prohibited * Python outside `salt/` directory -* TypeScript/JavaScript (use ReScript) +* TypeScript/JavaScript/ReScript (use AffineScript) * CUE (use Guile/Nickel) * `Dockerfile` (use `Containerfile`) diff --git a/hypatia-rules/rsr-self-compliance.a2ml b/hypatia-rules/rsr-self-compliance.a2ml index 577d1748..797acecb 100644 --- a/hypatia-rules/rsr-self-compliance.a2ml +++ b/hypatia-rules/rsr-self-compliance.a2ml @@ -55,7 +55,9 @@ reference: "rhodium-standard-repositories/RSR.adoc" @forbidden_files: - glob: "**/*.ts" - reason: "TypeScript banned — use ReScript" + reason: "TypeScript banned — use AffineScript (RS/TS/JS → AffineScript → typed-wasm per estate language defaults)" +- glob: "**/*.res" + reason: "ReScript banned — use AffineScript (RS/TS/JS → AffineScript → typed-wasm per estate language defaults)" - glob: "**/*.py" reason: "Python banned" - glob: "**/*.go"