From 9aa85e22cfaf1b40be8b363c04af0512b6afb465 Mon Sep 17 00:00:00 2001 From: hyperpolymath Date: Sat, 16 May 2026 16:17:06 +0100 Subject: [PATCH] fix: remove residual dead V-lang wiring (Justfile/CI/scripts/docs) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #66 removed only the V-lang CI jobs. This finishes the dead-leaf cleanup: no V source exists (adapter/v/ was deleted in the prior 2026-04-12 sweep) and the real REST/gRPC/GraphQL surface is the Elixir backend (elixir/, Plug/Cowboy) — no V port was ever needed. Justfile: - delete build-adapter recipe - run/serve/install now use only the existing Elixir path (dead V else branches dropped; install no longer copies a V binary) - heal: removed the git-clone vlang/v + make + symlink block - doctor: dropped check_optional "V (vlang)" and the adapter/v binary artefact check (now checks elixir/) - matrix/tour/help-me: cosmetic V status echoes repointed to Elixir CI: - .github/workflows/lsp-dap-bsp.yml: delete the V-lang adapter-check job (ran `v check`; missed by PR #66) and drop it from completeness needs: - .github/workflows/e2e.yml: delete the dead "Build V adapter" step scripts/tests/docs: - tests/e2e_full.sh, federation_multinode.sh: launch the Elixir backend instead of the non-existent adapter/v/boj-server binary - tests/aspect_tests.sh: removed the dead V-lang ABI-contract aspect and the V SPDX loop; cartridge-completeness now ABI+FFI; aspects renumbered - scripts/boj-selinux-contexts.sh: dropped the dead V binary fcontext - docs (RSR_OUTLINE, QUICKSTART, GETTING-STARTED, blog-post-draft, wiki Developer/User guides), .github/DISCUSSION_TEMPLATE/ cartridge-proposal.yml, .gitignore, 0-AI-MANIFEST.a2ml: dead adapter/v/ path references / stack wording corrected to the Elixir+Zig reality Left untouched (intentional): CHANGELOG/ADR/.machine_readable history records (document the retirement), Intentfile/Mustfile Unbreakable-Stack ban-enforcement assets, and per-cartridge *_adapter.zig provenance comments / cartridge README adapter tables (out of scope for this dead-leaf PR; partly protected estate-rule surface). Validation: 3 changed YAML files yaml.safe_load OK; `just --list` OK (107 lines, build-adapter absent, all recipes intact); bash -n clean on all 4 edited shell scripts; 0-AI-MANIFEST.a2ml parens balanced. Co-Authored-By: Claude Opus 4.7 --- .../cartridge-proposal.yml | 2 +- .github/workflows/e2e.yml | 4 - .github/workflows/lsp-dap-bsp.yml | 30 +----- .gitignore | 4 - 0-AI-MANIFEST.a2ml | 6 +- Justfile | 84 ++++------------- docs/GETTING-STARTED.md | 20 ++-- docs/QUICKSTART.md | 2 +- docs/RSR_OUTLINE.adoc | 2 +- docs/outreach/blog-post-draft.md | 7 +- docs/wiki/Developer-Guide.md | 37 ++++---- docs/wiki/User-Guide.md | 2 +- scripts/boj-selinux-contexts.sh | 19 +--- tests/aspect_tests.sh | 93 ++++--------------- tests/e2e_full.sh | 16 ++-- tests/federation_multinode.sh | 18 ++-- 16 files changed, 98 insertions(+), 248 deletions(-) diff --git a/.github/DISCUSSION_TEMPLATE/cartridge-proposal.yml b/.github/DISCUSSION_TEMPLATE/cartridge-proposal.yml index b8568456..8293eb85 100644 --- a/.github/DISCUSSION_TEMPLATE/cartridge-proposal.yml +++ b/.github/DISCUSSION_TEMPLATE/cartridge-proposal.yml @@ -5,7 +5,7 @@ body: attributes: value: | Proposing a new cartridge for the Ayo (community) menu? Tell us about it! - Cartridges follow the three-layer stack: Idris2 ABI + Zig FFI + V-lang Adapter. + Cartridges follow the stack: Idris2 ABI + Zig FFI, served by the Elixir adapter. See docs/DEVELOPERS.md for the full guide. - type: input attributes: diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index acf7d118..32e4afd2 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -66,10 +66,6 @@ jobs: [ -f "$cart/build.zig" ] && (cd "$cart" && zig build) || true done - - name: Build V adapter - run: | - cd adapter/v && v -o boj-server . || echo "V adapter build attempted" - - name: Run E2E full test suite run: bash tests/e2e_full.sh diff --git a/.github/workflows/lsp-dap-bsp.yml b/.github/workflows/lsp-dap-bsp.yml index 9288f230..9a39588f 100644 --- a/.github/workflows/lsp-dap-bsp.yml +++ b/.github/workflows/lsp-dap-bsp.yml @@ -91,34 +91,6 @@ jobs: cd "$GITHUB_WORKSPACE" done - adapter-check: - name: V-lang Adapter Check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Install V-lang - run: | - sudo apt-get update && sudo apt-get install -y libgc-dev - git clone --depth=1 https://github.com/vlang/v - cd v && make && sudo ./v symlink - - name: Check LSP/DAP/BSP adapters - run: | - for cart in lsp-mcp dap-mcp bsp-mcp; do - echo "=== Checking $cart adapter ===" - adapter_dir="cartridges/$cart/adapter" - if [ ! -d "$adapter_dir" ]; then - echo "ERROR: $adapter_dir missing" - exit 1 - fi - v_files=$(find "$adapter_dir" -name '*.v' | wc -l) - if [ "$v_files" -eq 0 ]; then - echo "ERROR: No .v files in $adapter_dir" - exit 1 - fi - v check "$adapter_dir"/*.v 2>&1 || { echo "ERROR: V check failed for $cart"; exit 1; } - echo " V-lang check passed ($v_files files)" - done - panel-validation: name: Panel Manifest Validation runs-on: ubuntu-latest @@ -153,7 +125,7 @@ jobs: completeness: name: Cartridge Completeness Check runs-on: ubuntu-latest - needs: [abi-check, ffi-build, adapter-check, panel-validation] + needs: [abi-check, ffi-build, panel-validation] steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Verify triadic structure diff --git a/.gitignore b/.gitignore index 1c4933b6..2e12ee43 100644 --- a/.gitignore +++ b/.gitignore @@ -112,10 +112,6 @@ src/abi/build/ # Cartridge Idris2 build artifacts cartridges/*/abi/build/ -# V-lang build artifacts -adapter/v/boj-server -v.mod.lock - # Hypatia scanner logs .hypatia/ diff --git a/0-AI-MANIFEST.a2ml b/0-AI-MANIFEST.a2ml index 595b591f..b3ed021d 100644 --- a/0-AI-MANIFEST.a2ml +++ b/0-AI-MANIFEST.a2ml @@ -20,7 +20,7 @@ Class 1 (Simple) — self-contained cartridges via GitHub Actions. Class 2 (Orchestrator) — unified gateways (WS/MQTT/Webhook). Class 3 (Multiplier) — Elixir/BEAM for mass concurrency. - Every cartridge has Idris2 ABI + Zig FFI + V-lang Adapter triple.") + Every cartridge has Idris2 ABI + Zig FFI; the Elixir backend serves the network adapter.") ;; =================================================================== ;; CONTEXT TIERS @@ -65,7 +65,7 @@ ├── src/abi/ # Idris2 ABI (Catalogue, Protocol, Domain, Menu, Federation) ├── ffi/zig/ # Zig FFI (catalogue mount/unmount, loader) ├── generated/abi/ # Auto-generated C headers - ├── adapter/v/ # V-lang triple adapter (REST+gRPC+GraphQL, port 9000) + ├── elixir/ # Elixir triple adapter (REST+gRPC+GraphQL, Plug/Cowboy) ├── cartridges/ # One dir per matrix cell (database-mcp, nesy-mcp, fleet-mcp, ...) ├── container/ # Stapeln container ecosystem ├── panll/src/ # PanLL panel (ReScript/TEA) @@ -77,7 +77,7 @@ ;; =================================================================== (critical-invariants - (rule "Three-Layer Stack: every cartridge = Idris2 ABI + Zig FFI + V-lang Adapter") + (rule "Stack: every cartridge = Idris2 ABI + Zig FFI; Elixir backend serves the network adapter") (rule "Zero believe_me anywhere in src/abi/ or cartridges/*/abi/") (rule "%default total on all Idris2 files") (rule "IsUnbreakable proof required for Ready cartridges") diff --git a/Justfile b/Justfile index 3f84ec48..2641935a 100644 --- a/Justfile +++ b/Justfile @@ -430,14 +430,14 @@ matrix: ABI="✗"; FFI="✗"; ADAPTER="✗"; TESTS="✗" [ -f "cartridges/$cart/abi"/*/*.idr ] 2>/dev/null && ABI="✓" [ -f "cartridges/$cart/ffi"/*_ffi.zig ] 2>/dev/null && FFI="✓" - [ -f "cartridges/$cart/adapter"/*_adapter.v ] 2>/dev/null && ADAPTER="✓" + [ -d "elixir" ] 2>/dev/null && ADAPTER="✓" [ -f "cartridges/$cart/ffi/build.zig" ] 2>/dev/null && TESTS="✓" printf " %-20s %s %s %s %s\n" "$cart" "$ABI" "$FFI" "$ADAPTER" "$TESTS" done echo "" echo " Core catalogue: ffi/zig/src/catalogue.zig" echo " Dynamic loader: ffi/zig/src/loader.zig" - echo " V-lang adapter: adapter/v/src/ (directory)" + echo " REST server: elixir/ (Plug/Cowboy)" echo " Menu: .machine_readable/servers/menu.a2ml" echo "" @@ -449,49 +449,24 @@ matrix: run *args: build #!/usr/bin/env bash set -euo pipefail - # Preference: Elixir (Class 3) > V-lang (deprecated/banned) + # The REST surface is the Elixir backend (Class 3 Multiplier). if [ -d "elixir" ] && command -v mix >/dev/null 2>&1; then echo "Starting BoJ Server (Elixir Class 3 Multiplier)..." cd elixir && exec mix run --no-halt {{args}} else - ADAPTER="adapter/v/boj-server" - if [ ! -f "$ADAPTER" ]; then - if command -v v >/dev/null 2>&1; then - just build-adapter - else - echo "ERROR: V-lang adapter not built and 'v' not found." - echo "V-lang was banned 2026-04-10. Please use the Elixir backend (cd elixir && mix run)." - exit 1 - fi - fi - echo "Starting BoJ Server (Legacy V-lang Adapter)..." - LLP="$(pwd)/ffi/zig/zig-out/lib" - for d in cartridges/*/ffi/zig-out/lib; do [ -d "$d" ] && LLP="${LLP}:$(pwd)/${d}"; done - LD_LIBRARY_PATH="${LLP}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" exec "$ADAPTER" {{args}} + echo "ERROR: Elixir backend not available (need 'elixir/' dir and 'mix')." + echo "Install Elixir/Mix, then: cd elixir && mix run --no-halt" + exit 1 fi # Run with verbose output run-verbose *args: build BOJ_VERBOSE=1 just run {{args}} -# Build V-lang adapter binary (compiles full directory: REST+gRPC+GraphQL+SSE) -build-adapter: build - #!/usr/bin/env bash - set -euo pipefail - echo "Building V-lang adapter (REST+gRPC+GraphQL+SSE)..." - LFLAGS="-L$(pwd)/ffi/zig/zig-out/lib" - for d in cartridges/*/ffi/zig-out/lib; do - [ -d "$d" ] && LFLAGS="${LFLAGS} -L$(pwd)/${d}" - done - v -cc gcc -cflags "${LFLAGS} -Wl,--allow-multiple-definition -no-pie" \ - -o adapter/v/boj-server adapter/v/src/ - echo "Built: adapter/v/boj-server ($(du -h adapter/v/boj-server | cut -f1))" - -# Install to user path -install: build-adapter - @echo "Installing boj-server..." - cp adapter/v/boj-server ~/.local/bin/boj-server - @echo "Installed to ~/.local/bin/boj-server" +# Install: the REST surface is served by the Elixir backend (cd elixir && mix run) +install: build + @echo "The BoJ REST surface is the Elixir backend; no binary is installed." + @echo "Run it with: cd elixir && mix run --no-halt (or: just run)" # Start Cloudflare quick tunnel (exposes BoJ at *.trycloudflare.com) tunnel: @@ -503,14 +478,14 @@ tunnel: serve: build #!/usr/bin/env bash set -euo pipefail - ADAPTER="adapter/v/boj-server" - if [ ! -f "$ADAPTER" ]; then - just build-adapter + if [ ! -d "elixir" ] || ! command -v mix >/dev/null 2>&1; then + echo "ERROR: Elixir backend not available (need 'elixir/' dir and 'mix')." + exit 1 fi echo "Starting BoJ Server..." echo " Local: http://localhost:7700/status" echo " SSE: http://localhost:7703/sse" - LD_LIBRARY_PATH="$(pwd)/ffi/zig/zig-out/lib" "$ADAPTER" & + (cd elixir && mix run --no-halt) & BOJ_PID=$! trap "kill $BOJ_PID 2>/dev/null; kill $TUNNEL_PID 2>/dev/null; exit" INT TERM sleep 2 @@ -1218,7 +1193,6 @@ doctor: check "git" git "2.0+" echo "" echo "Optional tools:" - check_optional "V (vlang)" v "deprecated/banned 2026-04-10" check_optional "Cargo" cargo "needed by launch-scaffolder (mint/provision/config)" check_optional "cloudflared" cloudflared "needed for tunnel" check_optional "panic-attack" panic-attack "pre-commit scanner" @@ -1254,10 +1228,10 @@ doctor: else echo " [INFO] ffi/zig/zig-out/ not found — run 'just build'" fi - if [ -f "adapter/v/boj-server" ]; then - echo " [OK] adapter/v/boj-server binary exists" + if [ -d "elixir" ]; then + echo " [OK] elixir/ exists (REST server backend)" else - echo " [INFO] V-lang adapter not built — run 'just build-adapter'" + echo " [INFO] elixir/ backend not found" fi if [ -d "src/abi/build" ]; then echo " [OK] src/abi/build/ exists (Idris2 ABI compiled)" @@ -1317,25 +1291,6 @@ heal: ZIG_VER=$(asdf list zig 2>/dev/null | tail -1 | tr -d ' ') [ -n "$ZIG_VER" ] && asdf global zig "$ZIG_VER" && echo " Zig global version set: $ZIG_VER" fi - # --- Install V (vlang) --- - if ! command -v v >/dev/null 2>&1; then - echo "Installing V (API adapter)..." - if [ ! -d "$HOME/vlang" ]; then - git clone https://github.com/vlang/v "$HOME/vlang" - fi - (cd "$HOME/vlang" && make) - # Symlink without sudo — use ~/.local/bin if writable - mkdir -p "$HOME/.local/bin" - ln -sf "$HOME/vlang/v" "$HOME/.local/bin/v" - export PATH="$HOME/.local/bin:$PATH" - if ! grep -q '\.local/bin' "$HOME/.bashrc" 2>/dev/null; then - echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$HOME/.bashrc" - fi - echo " V installed at ~/.local/bin/v" - echo " (If 'v' is still not found in a new shell, run: sudo ~/vlang/v symlink)" - HEALED=$((HEALED + 1)) - echo "" - fi # --- System library dependencies --- if command -v apt-get >/dev/null 2>&1; then MISSING_PKGS="" @@ -1390,7 +1345,7 @@ tour: echo "" echo " 1. Idris2 ABI — Dependent types prove correctness" echo " 2. Zig FFI — C-compatible native execution" - echo " 3. V-lang API — REST + gRPC + GraphQL adapter" + echo " 3. Elixir API — REST + gRPC + GraphQL surface" echo "" echo "Three-Class Architecture:" echo " Class 1: Simple Track — CLI/curl, self-contained" @@ -1406,7 +1361,7 @@ tour: echo "Key directories:" echo " cartridges/ 70+ cartridge directories" echo " ffi/zig/ Core catalogue FFI" - echo " adapter/v/ V-lang triple adapter" + echo " elixir/ REST server (Plug/Cowboy)" echo " container/ Stapeln container ecosystem" echo "" CART_COUNT=$(ls -d cartridges/*-mcp 2>/dev/null | wc -l) @@ -1442,7 +1397,6 @@ help-me: echo "BUILD & RUN:" echo " just build Build all Zig FFI layers (catalogue + cartridges)" echo " just build-release Build with optimizations" - echo " just build-adapter Build V-lang API triple adapter" echo " just run Build + start server (REST 7700, gRPC 7701, GraphQL 7702)" echo " just run-verbose Start with verbose output" echo " just serve Server + Cloudflare tunnel" diff --git a/docs/GETTING-STARTED.md b/docs/GETTING-STARTED.md index 9793b3a2..263bb92a 100644 --- a/docs/GETTING-STARTED.md +++ b/docs/GETTING-STARTED.md @@ -6,7 +6,7 @@ | Tool | Version | Purpose | |------|---------|---------| | [Zig](https://ziglang.org/download/) | 0.15+ | FFI compilation | -| [V-lang](https://vlang.io/) | 0.5.0+ | Adapter compilation | +| [Elixir](https://elixir-lang.org/) | 1.15+ | REST/gRPC/GraphQL adapter | | GCC | any recent | Linking | Optional: @@ -29,18 +29,18 @@ for cart in cartridges/*/ffi; do (cd "$cart" && zig build 2>/dev/null) done -# Build the V adapter -cd adapter/v -v -cc gcc src/main.v -o boj-server -cd ../.. +# Fetch + compile the Elixir backend (REST/gRPC/GraphQL adapter) +cd elixir +mix deps.get && mix compile +cd .. ``` ### 2. Run ```bash -cd adapter/v -export LD_LIBRARY_PATH=../../ffi/zig/zig-out/lib:../../cartridges/container-mcp/ffi/zig-out/lib:../../cartridges/feedback-mcp/ffi/zig-out/lib -./boj-server +cd elixir +export LD_LIBRARY_PATH=../ffi/zig/zig-out/lib:../cartridges/container-mcp/ffi/zig-out/lib:../cartridges/feedback-mcp/ffi/zig-out/lib +mix run --no-halt ``` The server starts on three ports: @@ -107,12 +107,12 @@ All ports are configurable via environment variables: ## Architecture ``` -Idris2 ABI (proofs) → Zig FFI (execution) → V-lang Adapter (network) +Idris2 ABI (proofs) → Zig FFI (execution) → Elixir Adapter (network) ``` - **Idris2** defines types with dependent-type proofs (IsUnbreakable safety gate) - **Zig** implements C-ABI exports (mount/unmount, federation, feedback, etc.) -- **V-lang** exposes everything as REST + gRPC + GraphQL +- **Elixir** exposes everything as REST + gRPC + GraphQL (Plug/Cowboy on the BEAM) The capability matrix is 2D (protocol × domain) with an optional third axis (backend/provider) for community extensions. See `docs/EXTENSIBILITY.md`. diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index eebe5269..fa67d21f 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -45,7 +45,7 @@ cartridges/ # Matrix cells — one dir per (Protocol x Domain) pair fleet-mcp/ # MCP x Fleet (abi/ + ffi/) nesy-mcp/ # MCP x NeSy (abi/ + ffi/) agent-mcp/ # MCP x Agent (abi/ + ffi/) -adapter/v/ # V-lang triple adapter (REST+gRPC+GraphQL) — Phase 3 +elixir/ # REST server backend (REST+gRPC+GraphQL, Plug/Cowboy) container/ # Stapeln container ecosystem docs/ # Architecture, federation, developer guides .machine_readable/ # State files, menu, policies, contractiles diff --git a/docs/RSR_OUTLINE.adoc b/docs/RSR_OUTLINE.adoc index a7b65f0a..e164caea 100644 --- a/docs/RSR_OUTLINE.adoc +++ b/docs/RSR_OUTLINE.adoc @@ -100,7 +100,7 @@ boj-server/ │ └── agent-mcp/ # MCP × Agent │ ├── abi/ # SafeOODA.idr │ └── ffi/ # agent_ffi.zig + build.zig -├── adapter/v/ # V-lang triple adapter (Phase 3) +├── elixir/ # REST server backend (Plug/Cowboy) ├── container/ # Stapeln container ecosystem │ ├── Containerfile # Multi-stage OCI build (Chainguard) │ ├── compose.toml # selur-compose orchestration diff --git a/docs/outreach/blog-post-draft.md b/docs/outreach/blog-post-draft.md index 301a37c3..b1362e61 100644 --- a/docs/outreach/blog-post-draft.md +++ b/docs/outreach/blog-post-draft.md @@ -62,7 +62,7 @@ The typical developer server is Python or TypeScript. BoJ uses none of those. In |-------|----------|-----| | ABI | Idris2 | Prove the interface is correct | | FFI | Zig | Execute it natively | -| Adapter | V-lang | Serve it over the network | +| Adapter | Elixir | Serve it over the network | **Why Idris2?** Because it has dependent types. Not "type-safe" in the TypeScript sense. Actually provably correct at compile time. The core safety gate is a type called `IsUnbreakable` -- it's a mathematical proof that only cartridges in the `Ready` state can be activated. The type checker enforces this, not a runtime check, not a unit test. If the proof doesn't hold, the code doesn't compile. @@ -78,7 +78,7 @@ You literally cannot call `mount` on a cartridge that isn't `Ready`. The type sy **Why Zig?** Because it produces C-ABI-compatible shared libraries with zero runtime dependencies. Each cartridge compiles to a `.so` file. The Zig layer bridges Idris2's proofs with actual system calls -- file I/O, networking, database connections. Cross-compilation is built in, which matters when community members run nodes on ARM, x86, or whatever they have. -**Why V-lang?** Because one V codebase exposes all three API styles (REST + gRPC + GraphQL) on dedicated ports. One language, three protocols, no code generation step. +**Why Elixir?** Because one Elixir codebase on the BEAM (Plug/Cowboy) exposes all three API styles (REST + gRPC + GraphQL) on dedicated ports, with the fault-tolerance and concurrency the BEAM is known for. One runtime, three protocols, no code generation step. The result: a compact binary. 219 Zig tests + 8 integration tests + 32 seam checks. Thread-safe (every FFI entry point serialises on a per-module mutex). No virtualenvs, no node_modules, no pip install. @@ -90,8 +90,7 @@ Start the server: git clone https://github.com/hyperpolymath/boj-server.git cd boj-server cd ffi/zig && zig build && cd ../.. -cd adapter/v && v -cc gcc src/main.v -o boj-server -./boj-server +cd elixir && mix deps.get && mix run --no-halt ``` Three ports open: diff --git a/docs/wiki/Developer-Guide.md b/docs/wiki/Developer-Guide.md index 163ce11a..91c6467e 100644 --- a/docs/wiki/Developer-Guide.md +++ b/docs/wiki/Developer-Guide.md @@ -10,14 +10,14 @@ This guide is for people **developing** BoJ itself -- contributing cartridges, f Every BoJ cartridge follows a three-layer stack: ``` -Idris2 ABI (formal proofs) --> Zig FFI (native execution) --> V-lang Adapter (network) +Idris2 ABI (formal proofs) --> Zig FFI (native execution) --> Elixir Adapter (network) ``` | Layer | Language | Purpose | Location | |-------|----------|---------|----------| | **ABI** | Idris2 | Dependent-type proofs, state machines, `%default total`, zero `believe_me` | `src/abi/` (core), `cartridges/*/abi/` | | **FFI** | Zig | C-compatible native execution, zero runtime dependencies | `ffi/zig/` (core), `cartridges/*/ffi/` | -| **Adapter** | V-lang | Triple API: REST (7700) + gRPC (7701) + GraphQL (7702) | `adapter/v/` | +| **Adapter** | Elixir | Triple API: REST (7700) + gRPC (7701) + GraphQL (7702) | `elixir/` | ### Why these languages? @@ -25,7 +25,7 @@ Idris2 ABI (formal proofs) --> Zig FFI (native execution) --> V-lang Adapter (ne **Zig** provides native C ABI compatibility without runtime overhead. It bridges Idris2's proofs and actual system calls. Cross-compilation is built-in for varied community node hardware. -**V-lang** exposes all three API styles (REST, gRPC, GraphQL) from a single codebase. One port per protocol, one codebase to maintain. +**Elixir** exposes all three API styles (REST, gRPC, GraphQL) from a single codebase on the BEAM (Plug/Cowboy). One port per protocol, one codebase to maintain. ### The Capability Matrix @@ -52,7 +52,7 @@ Cloud | ## | | | | | | | ## | ## | | Tool | Version | Required? | |------|---------|-----------| | [Zig](https://ziglang.org/) | 0.15.2+ | Yes | -| [V-lang](https://vlang.io/) | 0.5.0+ | Yes (for adapter) | +| [Elixir](https://elixir-lang.org/) | 1.15+ | Yes (for adapter) | | GCC | any recent | Yes (linking) | | [Idris2](https://www.idris-lang.org/) | 0.8.0 | Only to modify ABI | | [just](https://just.systems/) | 1.40+ | Optional (convenience) | @@ -78,10 +78,10 @@ for cart in cartridges/*/ffi; do (cd "$cart" && zig build 2>/dev/null) done -# Build V-lang adapter -cd adapter/v -v -cc gcc src/main.v -o boj-server -cd ../.. +# Fetch Elixir backend deps (the REST/gRPC/GraphQL surface) +cd elixir +mix deps.get && mix compile +cd .. ``` With `just`: @@ -108,9 +108,11 @@ Pick a capability domain and protocol(s): cartridges/your-cartridge-name/ abi/ # Idris2 source ffi/ # Zig source (with build.zig) - adapter/ # V-lang source ``` +The network surface (REST/gRPC/GraphQL) is served centrally by the +Elixir backend in `elixir/`; cartridges expose only the ABI + FFI layers. + ### 3. Write the Idris2 ABI Requirements: @@ -127,12 +129,14 @@ Requirements: - Zero runtime dependencies - Wrap all mutable globals with `std.Thread.Mutex` (see Thread-Safety below) -### 5. Write the V-lang adapter +### 5. Wire the cartridge into the Elixir adapter -Requirements: -- Expose the cartridge via the declared protocols -- Handle the order-ticket protocol -- Return proper status responses +The network surface (REST/gRPC/GraphQL) is served centrally by the +Elixir backend in `elixir/` — there is no per-cartridge adapter to write. +Ensure your cartridge: +- Is reachable via the declared protocols through the Elixir backend +- Handles the order-ticket protocol +- Returns proper status responses ### 6. Register in the menu @@ -281,12 +285,11 @@ ffi/zig/ # Zig FFI -- native execution src/e2e_order.zig # End-to-end order-ticket tests cartridges/ # 18 cartridge directories - database-mcp/ # Each has abi/ + ffi/ + adapter/ + database-mcp/ # Each has abi/ + ffi/ container-mcp/ ... -adapter/v/ # V-lang triple adapter - src/main.v # REST + gRPC + GraphQL server +elixir/ # REST + gRPC + GraphQL server (Plug/Cowboy) container/ # Deployment Containerfile # Chainguard base image diff --git a/docs/wiki/User-Guide.md b/docs/wiki/User-Guide.md index 1eed802c..d615b6c3 100644 --- a/docs/wiki/User-Guide.md +++ b/docs/wiki/User-Guide.md @@ -75,7 +75,7 @@ Any MCP-compatible client can consume BoJ. Start the server in MCP mode: ```bash LD_LIBRARY_PATH=ffi/zig/zig-out/lib \ - ./adapter/v/boj-server --mcp + bash -c 'cd elixir && mix run --no-halt -- --mcp' ``` The server reads JSON-RPC 2.0 from stdin and writes responses to stdout. diff --git a/scripts/boj-selinux-contexts.sh b/scripts/boj-selinux-contexts.sh index c929a182..b56b6621 100755 --- a/scripts/boj-selinux-contexts.sh +++ b/scripts/boj-selinux-contexts.sh @@ -18,22 +18,15 @@ readonly BOJ_ROOT_SEMANAGE="${BOJ_ROOT#/var}" echo "=== BoJ Server SELinux Context Setup ===" -# 1. Binary: bin_t (already correct, make persistent) -echo "[1/3] Setting fcontext rule: adapter binary -> bin_t" -semanage fcontext -a -t bin_t \ - "${BOJ_ROOT_SEMANAGE}/adapter/v/boj-server" 2>/dev/null \ - || semanage fcontext -m -t bin_t \ - "${BOJ_ROOT_SEMANAGE}/adapter/v/boj-server" - -# 2. Cartridge shared libraries: lib_t -echo "[2/3] Setting fcontext rule: cartridge .so files -> lib_t" +# 1. Cartridge shared libraries: lib_t +echo "[1/2] Setting fcontext rule: cartridge .so files -> lib_t" semanage fcontext -a -t lib_t \ "${BOJ_ROOT_SEMANAGE}/cartridges/.*/ffi/zig-out/lib/.*\\.so" 2>/dev/null \ || semanage fcontext -m -t lib_t \ "${BOJ_ROOT_SEMANAGE}/cartridges/.*/ffi/zig-out/lib/.*\\.so" -# 3. Core FFI shared libraries: lib_t -echo "[3/3] Setting fcontext rule: core FFI .so files -> lib_t" +# 2. Core FFI shared libraries: lib_t +echo "[2/2] Setting fcontext rule: core FFI .so files -> lib_t" semanage fcontext -a -t lib_t \ "${BOJ_ROOT_SEMANAGE}/ffi/zig/zig-out/lib/.*\\.so" 2>/dev/null \ || semanage fcontext -m -t lib_t \ @@ -41,9 +34,7 @@ semanage fcontext -a -t lib_t \ # Apply the contexts echo "Applying contexts with restorecon..." -restorecon -v "${BOJ_ROOT}/adapter/v/boj-server" 2>&1 || true restorecon -Rv "${BOJ_ROOT}/cartridges/" 2>&1 || true restorecon -Rv "${BOJ_ROOT}/ffi/" 2>&1 || true -echo "=== Done. Verify with: ls -Z ${BOJ_ROOT}/adapter/v/boj-server ===" -echo "=== And: ls -Z ${BOJ_ROOT}/cartridges/database-mcp/ffi/zig-out/lib/ ===" +echo "=== Done. Verify with: ls -Z ${BOJ_ROOT}/cartridges/database-mcp/ffi/zig-out/lib/ ===" diff --git a/tests/aspect_tests.sh b/tests/aspect_tests.sh index e8b287af..7e517537 100755 --- a/tests/aspect_tests.sh +++ b/tests/aspect_tests.sh @@ -6,11 +6,10 @@ # # Validates architectural invariants that span the entire codebase: # 1. Thread safety — all Zig FFI modules use Mutex protection -# 2. ABI/FFI contract — V-lang C declarations match Zig exports -# 3. Formal verification safety — no believe_me or assert_total in Idris2 -# 4. SPDX compliance — all source files have license headers -# 5. Cartridge completeness — all cartridges have ABI + FFI + Adapter layers -# 6. Error handling — no panic/unreachable in production Zig code paths +# 2. Formal verification safety — no believe_me or assert_total in Idris2 +# 3. SPDX compliance — all source files have license headers +# 4. Cartridge completeness — all cartridges have ABI + FFI layers +# 5. Error handling — no panic/unreachable in production Zig code paths # # Usage: # bash tests/aspect_tests.sh @@ -110,59 +109,9 @@ done echo "" # ═══════════════════════════════════════════════════════════════════════ -# Aspect 2: ABI/FFI Contract — V-lang C declarations match Zig exports +# Aspect 2: Formal Verification Safety — banned patterns in Idris2 # ═══════════════════════════════════════════════════════════════════════ -bold "Aspect 2: V-lang C FFI declarations match Zig exports" - -v_main="$PROJECT_DIR/adapter/v/src/main.v" - -if [[ ! -f "$v_main" ]]; then - fail "V-lang adapter main.v not found" -else - # Extract C function names declared in V - v_cffi=$(grep -oP '(?<=fn C\.)\w+' "$v_main" | sort -u) - - # Extract Zig export function names from core FFI - zig_exports="" - for zigfile in "$zig_ffi_dir"/*.zig; do - zig_exports+=$(grep -oP '(?:pub )?export fn \K\w+' "$zigfile" 2>/dev/null || true) - zig_exports+=$'\n' - done - - # Also check cartridge FFI files for exports - for cart_dir in "$PROJECT_DIR"/cartridges/*/ffi; do - [ -d "$cart_dir" ] || continue - for zigfile in $(find "$cart_dir" -name '*.zig' 2>/dev/null); do - zig_exports+=$(grep -oP '(?:pub )?export fn \K\w+' "$zigfile" 2>/dev/null || true) - zig_exports+=$'\n' - done - done - - zig_sorted=$(echo "$zig_exports" | grep -v '^$' | sort -u) - - # Check that every V C.xxx declaration has a matching Zig export - mismatch_count=0 - matched_count=0 - while IFS= read -r cfunc; do - [[ -z "$cfunc" ]] && continue - if echo "$zig_sorted" | grep -qx "$cfunc"; then - matched_count=$((matched_count + 1)) - else - fail "V declares C.$cfunc but no Zig export found" - mismatch_count=$((mismatch_count + 1)) - fi - done <<< "$v_cffi" - - if [[ $mismatch_count -eq 0 ]]; then - pass "All $matched_count V C-FFI declarations have matching Zig exports" - fi -fi -echo "" - -# ═══════════════════════════════════════════════════════════════════════ -# Aspect 3: Formal Verification Safety — banned patterns in Idris2 -# ═══════════════════════════════════════════════════════════════════════ -bold "Aspect 3: Formal verification safety (Idris2)" +bold "Aspect 2: Formal verification safety (Idris2)" # believe_me — unsafe cast, bypasses type checker believe_hits=$(grep -rn 'believe_me' "$PROJECT_DIR" --include='*.idr' \ @@ -236,9 +185,9 @@ fi echo "" # ═══════════════════════════════════════════════════════════════════════ -# Aspect 4: SPDX Compliance — license headers on all source files +# Aspect 3: SPDX Compliance — license headers on all source files # ═══════════════════════════════════════════════════════════════════════ -bold "Aspect 4: SPDX header compliance" +bold "Aspect 3: SPDX header compliance" spdx_missing=0 spdx_checked=0 @@ -261,15 +210,6 @@ for idrfile in $(find "$PROJECT_DIR" -name '*.idr' -not -path '*/build/*' 2>/dev fi done -# Check V files -for vfile in $(find "$PROJECT_DIR" -name '*.v' -not -path '*/v/*/.git/*' 2>/dev/null); do - spdx_checked=$((spdx_checked + 1)) - if ! head -5 "$vfile" | grep -q 'SPDX-License-Identifier'; then - fail "Missing SPDX header: $(basename "$vfile") ($(dirname "$vfile" | sed "s|$PROJECT_DIR/||"))" - spdx_missing=$((spdx_missing + 1)) - fi -done - # Check shell scripts for shfile in $(find "$PROJECT_DIR" -name '*.sh' -not -path '*/.machine_readable/scripts/*' 2>/dev/null); do spdx_checked=$((spdx_checked + 1)) @@ -296,40 +236,39 @@ fi echo "" # ═══════════════════════════════════════════════════════════════════════ -# Aspect 5: Cartridge Completeness — ABI + FFI + Adapter layers +# Aspect 4: Cartridge Completeness — ABI + FFI layers # ═══════════════════════════════════════════════════════════════════════ -bold "Aspect 5: Cartridge layer completeness (ABI + FFI + Adapter)" +bold "Aspect 4: Cartridge layer completeness (ABI + FFI)" incomplete=0 complete=0 for cart_dir in "$PROJECT_DIR"/cartridges/*/; do cart_name=$(basename "$cart_dir") - has_abi=false; has_ffi=false; has_adapter=false + has_abi=false; has_ffi=false [ -d "$cart_dir/abi" ] && has_abi=true [ -d "$cart_dir/ffi" ] && has_ffi=true - [ -d "$cart_dir/adapter" ] && has_adapter=true - if $has_abi && $has_ffi && $has_adapter; then + if $has_abi && $has_ffi; then complete=$((complete + 1)) else - fail "$cart_name: incomplete layers (ABI=$has_abi FFI=$has_ffi Adapter=$has_adapter)" + fail "$cart_name: incomplete layers (ABI=$has_abi FFI=$has_ffi)" incomplete=$((incomplete + 1)) fi done if [[ $incomplete -eq 0 ]]; then - pass "All $complete cartridges have ABI + FFI + Adapter layers" + pass "All $complete cartridges have ABI + FFI layers" else red " $incomplete cartridges are incomplete" fi echo "" # ═══════════════════════════════════════════════════════════════════════ -# Aspect 6: Error handling — no unreachable in production Zig exports +# Aspect 5: Error handling — no unreachable in production Zig exports # ═══════════════════════════════════════════════════════════════════════ -bold "Aspect 6: Error handling (no bare unreachable in Zig exports)" +bold "Aspect 5: Error handling (no bare unreachable in Zig exports)" # Check for bare `unreachable` in production code paths (not test files) unreachable_count=0 diff --git a/tests/e2e_full.sh b/tests/e2e_full.sh index 283ce97f..b96ca4ab 100755 --- a/tests/e2e_full.sh +++ b/tests/e2e_full.sh @@ -13,7 +13,7 @@ # bash tests/e2e_full.sh # # Prerequisites: -# - BoJ binary built (just build-adapter) +# - Elixir backend available (elixir/ dir + mix on PATH) # - Zig FFI libraries built (just build-ffi) # - curl, jq, node/deno on PATH @@ -21,7 +21,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -BOJ_BIN="$PROJECT_DIR/adapter/v/boj-server" +ELIXIR_DIR="$PROJECT_DIR/elixir" MCP_BRIDGE="$PROJECT_DIR/mcp-bridge/main.js" REST_PORT="${BOJ_REST_PORT:-7700}" BASE_URL="http://localhost:${REST_PORT}" @@ -92,12 +92,12 @@ echo "" # ─── Preflight checks ──────────────────────────────────────────────── bold "Preflight: Checking prerequisites..." -if [[ ! -x "$BOJ_BIN" ]]; then - red " ERROR: BoJ binary not found at $BOJ_BIN" - red " Run 'just build-adapter' first." +if [[ ! -d "$ELIXIR_DIR" ]] || ! command -v mix &>/dev/null; then + red " ERROR: Elixir backend not available (need $ELIXIR_DIR and 'mix')" + red " Install Elixir/Mix; the BoJ REST surface is the Elixir backend." exit 1 fi -green " BoJ binary found" +green " Elixir backend found" if ! command -v curl &>/dev/null; then red " ERROR: curl not found on PATH" @@ -125,10 +125,10 @@ fi echo "" # ═══════════════════════════════════════════════════════════════════════ -# Step 1: Start the V-lang server +# Step 1: Start the Elixir REST server # ═══════════════════════════════════════════════════════════════════════ bold "Step 1: Starting BoJ server on port $REST_PORT..." -BOJ_REST_PORT="$REST_PORT" "$BOJ_BIN" > "$TMPDIR_TEST/boj-e2e-full.log" 2>&1 & +( cd "$ELIXIR_DIR" && BOJ_REST_PORT="$REST_PORT" mix run --no-halt ) > "$TMPDIR_TEST/boj-e2e-full.log" 2>&1 & PIDS+=($!) # Wait for health check (up to 10 seconds) diff --git a/tests/federation_multinode.sh b/tests/federation_multinode.sh index 8a48d57d..ad5ad236 100755 --- a/tests/federation_multinode.sh +++ b/tests/federation_multinode.sh @@ -11,14 +11,14 @@ # bash tests/federation_multinode.sh # # Prerequisites: -# - BoJ binary built (just build-adapter) +# - Elixir backend available (elixir/ dir + mix on PATH) # - curl, jq on PATH set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -BOJ_BIN="$PROJECT_DIR/adapter/v/boj-server" +ELIXIR_DIR="$PROJECT_DIR/elixir" export LD_LIBRARY_PATH="$PROJECT_DIR/ffi/zig/zig-out/lib:$PROJECT_DIR/cartridges/container-mcp/ffi/zig-out/lib" green() { printf '\033[32m%s\033[0m\n' "$*"; } @@ -66,26 +66,26 @@ echo " BoJ Server — Multi-Node Federation Test" echo "=================================================================" echo "" -if [[ ! -x "$BOJ_BIN" ]]; then - red "ERROR: BoJ binary not found at $BOJ_BIN" - red "Run 'just build-adapter' first." +if [[ ! -d "$ELIXIR_DIR" ]] || ! command -v mix &>/dev/null; then + red "ERROR: Elixir backend not available (need $ELIXIR_DIR and 'mix')" + red "The BoJ REST surface is the Elixir backend." exit 1 fi # ─── Node A: REST 7710, gRPC 7711, GraphQL 7712, Federation 9910 ─── bold "Starting Node A (ports 7710/9910)..." -BOJ_REST_PORT=7710 BOJ_GRPC_PORT=7711 BOJ_GRAPHQL_PORT=7712 \ +( cd "$ELIXIR_DIR" && BOJ_REST_PORT=7710 BOJ_GRPC_PORT=7711 BOJ_GRAPHQL_PORT=7712 \ BOJ_FEDERATION_PORT=9910 BOJ_QUIC=1 \ BOJ_NODE_ID="node-alpha" BOJ_REGION="eu-west-1" \ - "$BOJ_BIN" > "$TMPDIR_TEST/boj-node-a.log" 2>&1 & + mix run --no-halt ) > "$TMPDIR_TEST/boj-node-a.log" 2>&1 & PIDS+=($!) # ─── Node B: REST 7720, gRPC 7721, GraphQL 7722, Federation 9920 ─── bold "Starting Node B (ports 7720/9920)..." -BOJ_REST_PORT=7720 BOJ_GRPC_PORT=7721 BOJ_GRAPHQL_PORT=7722 \ +( cd "$ELIXIR_DIR" && BOJ_REST_PORT=7720 BOJ_GRPC_PORT=7721 BOJ_GRAPHQL_PORT=7722 \ BOJ_FEDERATION_PORT=9920 BOJ_QUIC=1 \ BOJ_NODE_ID="node-bravo" BOJ_REGION="us-east-1" \ - "$BOJ_BIN" > "$TMPDIR_TEST/boj-node-b.log" 2>&1 & + mix run --no-halt ) > "$TMPDIR_TEST/boj-node-b.log" 2>&1 & PIDS+=($!) # Wait for both nodes to be ready