Skip to content

build: pin toolchain versions via tracked .tool-versions#41

Merged
hyperpolymath merged 1 commit intomainfrom
pin-toolchain-versions
Apr 30, 2026
Merged

build: pin toolchain versions via tracked .tool-versions#41
hyperpolymath merged 1 commit intomainfrom
pin-toolchain-versions

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Summary

Pins the four runtime versions a fresh-clone install needs to boot boj-rest with all 115 cartridges discoverable on :7700. asdf reads .tool-versions automatically when you cd into the repo, so the pins are transparent for any user already on asdf.

Discovered during the 2026-04-30 install — without these pins the next person hits exactly the same traps:

Pin Why
zig 0.15.1 ffi/zig/build.zig was written against Zig 0.15. Zig 0.16's std.Thread API broke 14 compile sites in catalogue/loader/guardian/federation/coprocessor/sla/community/sdp. asdf-zig latest currently resolves to 0.16, so without a pin every fresh clone fails just build.
elixir 1.18.4-otp-25 Ubuntu 24.04 LTS apt ships Elixir 1.14, but elixir/mix.exs declares ~> 1.15. The -otp-25 suffix matches the apt erlang-base on 24.04 (Erlang/OTP 25 / erts-13.2.2.5), avoiding a from-source Erlang build via asdf-erlang.
idris2 0.8.0 Required for just verify and just typecheck. asdf-idris2 is a source build needing libgmp-dev + chezscheme from apt — pinning at least removes the moving target.
deno 2.7.14 Required by BojRest.JsWorkerPool. Without it, JS cartridges fall back to fork-per-call (~200ms cold start per invoke).

Also removes .tool-versions from .gitignore and replaces the line with a comment explaining why the file is now tracked. asdf convention is to commit this file — it's the polyglot equivalent of package.json for runtime versions.

Test plan

  • On a fresh Ubuntu 24.04 with asdf installed and apt's erlang-base (OTP 25) present:
    • git clone … && cd boj-server → asdf reads .tool-versions automatically.
    • asdf install resolves all four versions (zig, elixir, idris2, deno).
    • just doctor reports all required tools green.
    • just build produces 111 .so cartridges (or the current count).
    • just install-service brings up boj-rest.service on :7700 cleanly.
    • curl localhost:7700/health returns cartridges_loaded:115.

Out of scope

  • asdf-erlang version is left to apt's OTP 25 — switching to asdf-erlang would let us bump Elixir to 1.18+otp-26/27 and gain newer features but adds a 10+ min source build to every cold install. Separate decision.
  • SPARK / gnatprove and Cranelift's clif-util are install-time decisions, not runtime version pins, so they're not in here.
  • The elixir/boj-rest.service template still hardcodes /usr/bin/mix, which fails when Elixir is asdf-managed. Fixing that is in the cleanup PR alongside the AffineScript port and Hypatia env fix.

🤖 Generated with Claude Code

Adds an asdf-readable .tool-versions at repo root pinning the four
runtimes that QUICKSTART-USER.adoc requires, and removes the .gitignore
line that kept it untracked. asdf convention is to commit this file —
it's the equivalent of package.json for the polyglot runtime side.

Each pin matches the version that successfully boots boj-rest with all
115 cartridges discoverable on :7700. Without these pins, the next
fresh-clone setup hits the version traps surfaced during the 2026-04-30
install:

  zig 0.15.1            ffi/zig/build.zig was written against 0.15;
                        Zig 0.16's std.Thread API broke 14 compile
                        sites in catalogue/loader/guardian/federation/
                        coprocessor/sla/community/sdp. asdf-zig latest
                        currently resolves to 0.16, so without a pin
                        every fresh clone fails `just build`.

  elixir 1.18.4-otp-25  Ubuntu 24.04 LTS apt ships Elixir 1.14, but
                        elixir/mix.exs declares ~> 1.15. The OTP-25
                        suffix matches the apt erlang-base on 24.04
                        (Erlang/OTP 25 / erts-13.2.2.5), avoiding a
                        from-source Erlang build via asdf-erlang.

  idris2 0.8.0          Required for `just verify` and `just typecheck`
                        on the Idris2 ABI. asdf-idris2 builds from
                        source and needs `libgmp-dev` + `chezscheme`
                        from apt — pinning at least removes the moving
                        target.

  deno 2.7.14           Required by the JS cartridge worker pool.
                        Without it, BojRest.JsWorkerPool falls back to
                        fork-per-call (~200 ms cold start per invoke).

The .gitignore line that kept .tool-versions untracked has been removed
and replaced with a comment explaining why the file is tracked.

Out of scope (deliberate):
* asdf-erlang version is left to apt's OTP 25 — switching to asdf-erlang
  would let us bump Elixir to 1.18+otp-26/27 and gain newer features
  but adds a 10+ min source build to every cold install.
* SPARK / gnatprove and Cranelift's clif-util are still install-time
  decisions, not runtime-version pins.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath hyperpolymath merged commit b078f60 into main Apr 30, 2026
9 of 13 checks passed
@hyperpolymath hyperpolymath deleted the pin-toolchain-versions branch April 30, 2026 15:43
hyperpolymath added a commit that referenced this pull request Apr 30, 2026
)

## Summary

Re-measures the date-stamped historical statements PR #40 deliberately
left out of scope (because they were measurements taken on 2026-04-25
and substituting blind would have been wrong). Now refreshed against the
actual repo state on 2026-04-30 after `just build` produced **111 of
115** cartridge `.so` libraries.

## Numbers refreshed

| Surface | Old | New |
|---|---|---|
| `TOPOLOGY.md` L4 | "Updated 2026-04-25. 112 cartridges across 6
tiers." | "Updated 2026-04-30. 115 cartridges across 6 tiers (111 with
`.so` built, 4 pending)." |
| `TEST-NEEDS.md` L124 | "112 cartridges loaded … as of 2026-04-25" |
"115 cartridges loaded … as of 2026-04-30" + the 4 not-yet-building
names |
| `ROADMAP.adoc` v1.0.1 (4 checkboxes) | mixed 112/checked + unchecked |
bumped to 115, re-dated 2026-04-30, two unchecked items now [x] (this PR
closes them) |
| `ROADMAP.adoc` v1.1.0 | "99 of 106 cartridges use `mod.js`" | "4 of
115 cartridges still use `mod.js`" — the gap closed substantially |
| `docs/ARCHITECTURE.md` L138 | "Once all 112 cartridges have verified
`.so` builds" | 115 + parenthetical 2026-04-30 measurement |
| `docs/ARCHITECTURE.md` L209–212 | "1 complete (boj-health), 111 in
progress" — INVERTED | "111 with `.so` built, 4 not yet building" —
actually inverts the breakdown |
| `docs/READINESS.md` L75 | "Cartridge fleet (106) … 103/106 shared libs
built" | "Cartridge fleet (115) … 111/115 shared libs built" |

The 4 cartridges still without `.so`: **`database-mcp`**,
**`echidna-llm-mcp`**, **`lang-mcp`**, **`orchestrator-lsp-mcp`**.
Flagged in three places so the next investigator has a starting list.

## What this PR deliberately does NOT do

- **Re-run mix test / zig test / FFI test counts.** The numbers in
`READINESS.md` (`113 FFI tests`, `178 core tests`, `4 believe_me`, etc.)
are last-documented values, not re-measured. The row text in
`READINESS.md` honestly notes this. Test re-run is a separate follow-up.
- **Re-count per-directory READMEs.** The "393 per-directory READMEs"
number is also a last-documented value. Same reasoning.
- **Investigate the 4 build-failing cartridges.** Their `just build`
errors are out of scope here; flagged for a follow-up.
- **Touch any other ARCHITECTURE / ROADMAP claims unrelated to count or
build status.**

## Test plan

- [ ] Visual review of the 5 changed files to make sure the numbers are
coherent (115 across the board for "total"; 111 for "built"; 4 for
"pending"; 2026-04-30 for "as of" dates).
- [ ] CI green on the branch (will hit the same 3 pre-existing failures
as #40 / #41 — TS/JS Blocker on the 6 `.ts` files, Hypatia missing
GITHUB_TOKEN; admin merge expected, same as those).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath added a commit that referenced this pull request Apr 30, 2026
… mix path in service unit (#43)

## Summary

Three of the four sub-parts of the deferred cleanup ledger from PR #40's
out-of-scope list. The fourth (port the 6 `.ts` cartridge adapters to
AffineScript→typed-wasm) is delegated to a scheduled remote agent that
fires 2026-05-07 and runs **one cartridge per pass**, so it stays
opportunistic and reviewable.

## Changes

| File | Fix |
|---|---|
| `.github/workflows/hypatia-scan.yml` | Adds job-level `GITHUB_TOKEN`
env (Hypatia CLI calls `gh api` for Dependabot lookups; without the
token it logs `Dependabot alerts unavailable: GITHUB_TOKEN not set` and
the job exits non-zero). Adds `security-events: read` permission. |
| `.github/workflows/rsr-antipattern.yml` | "use ReScript instead" →
"use AffineScript→typed-wasm instead". Header comment + Allows banner
updated to reflect estate-wide language policy 2026-04-30 (RS/TS/JS
default is AffineScript; ReScript transitional / adapter-shim only). |
| `.github/workflows/ts-blocker.yml` | "port to Zig or ReScript" / "use
Zig or ReScript instead" → "Zig (systems) or AffineScript→typed-wasm
(application)". Underlying detection unchanged. |
| `elixir/boj-rest.service` | Replace hardcoded `ExecStart=/usr/bin/mix`
(which is apt's 1.14, fails `mix.exs` `~> 1.15` check on Ubuntu 24.04
LTS) with `ExecStart=mix run --no-halt`. Adds `Environment=PATH` with
asdf shims, cargo bin, `~/.local/bin`. Adds `ASDF_DIR` + `ASDF_DATA_DIR`
so asdf shims work under systemd's clean env. Bumps cartridge-count
comment 112 → 115. |

## Why these specifically

PR #40 (spec drift) merged on 2026-04-30 surfaced four follow-up
cleanups; this PR closes three of them. The fourth (`.ts` → AffineScript
ports) was deliberately scheduled rather than rushed — verifying
AffineScript readiness for each cartridge is genuinely per-cartridge
work and the scheduled agent does it one at a time.

The `boj-rest.service` fix in particular was discovered the hard way
during the maintainer's install: the deployed unit needed a hand-patch
(`~/.config/systemd/user/boj-rest.service`) to point at
`~/.asdf/installs/elixir/1.18.4-otp-25/bin/mix`. Persisting the fix to
the source template (with `%h` systemd-substitution + asdf shim PATH)
means the next person installing on a fresh Ubuntu doesn't repeat the
dance.

The three pre-existing CI failures that were blocking PRs #40, #41, #42
are likely partially closed by this PR:

- **Hypatia** — should now pass with `GITHUB_TOKEN` wired up.
- **TS/JS Blocker** and **antipattern-check** — will *still* fail on the
6 `.ts` cartridge adapters (`academic-workflow-mcp`, `bofig-mcp`,
`ephapax-mcp`, `fireflag-mcp`, `hesiod-mcp`, `sanctify-mcp`). Those are
the scheduled agent's work. Admin-merge-without-CI is still expected for
this PR.

## Test plan

- [ ] CI shows Hypatia passing on this branch (GITHUB_TOKEN now
available).
- [ ] Diff visual review for the policy text — make sure no instance of
"use ReScript instead" remains in the workflow files.
- [ ] After merge, fresh install on a clean Ubuntu 24.04 LTS host with
asdf + the toolchain-pins from PR #41: `bash setup.sh && just doctor &&
just deps && just build && just install-service` — confirm
`boj-rest.service` starts cleanly without the `(Mix) You're trying to
run :boj_rest on Elixir v1.14.0` error that was previously hit.

## Out of scope

- The 6 `.ts` → AffineScript ports (scheduled, one per week from
2026-05-07, routine `trig_01X9BreihRW4AU5BdELY2QBY`).
- Re-running mix test / FFI tests for grade re-validation (READINESS.md
still lists the last-documented numbers per the re-measurement PR #42).
- The 4 cartridges still without `.so` (`database-mcp`,
`echidna-llm-mcp`, `lang-mcp`, `orchestrator-lsp-mcp`) — listed in #42
for follow-up.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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