Skip to content

Commit 989eabe

Browse files
Merge branch 'main' into fix/toolchain-version-asserts
2 parents 9d3170f + 98c1b32 commit 989eabe

7 files changed

Lines changed: 168 additions & 161 deletions

File tree

.github/workflows/ci.yml

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,24 @@ jobs:
2727
- name: Checkout
2828
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
2929

30-
# The pinned idris2-pack image ships no xz binary, so setup-zig's
31-
# .tar.xz download fails with "tar (child): xz: Cannot exec".
32-
- name: Install xz (needed to unpack the Zig tarball)
30+
# The pinned idris2-pack image is minimal. Two things are missing:
31+
# xz — setup-zig's .tar.xz download dies with "tar: xz: Cannot exec"
32+
# jq — tests/check-examples.sh exits 2 with "jq is required", so the
33+
# Trope IR conformance test never actually ran in CI
34+
- name: Install container prerequisites (xz, jq)
3335
shell: bash
3436
run: |
3537
set -euo pipefail
36-
if ! command -v xz >/dev/null 2>&1; then
38+
missing=()
39+
command -v xz >/dev/null 2>&1 || missing+=(xz-utils)
40+
command -v jq >/dev/null 2>&1 || missing+=(jq)
41+
if [ "${#missing[@]}" -gt 0 ]; then
42+
echo "installing: ${missing[*]}"
3743
apt-get update -qq
38-
apt-get install -y -qq --no-install-recommends xz-utils
44+
apt-get install -y -qq --no-install-recommends "${missing[@]}"
3945
fi
4046
xz --version | head -1
47+
jq --version
4148
4249
- name: Set up Zig
4350
uses: goto-bus-stop/setup-zig@abea47f85e598557f500fa1fd2ab7464fcb39406 # v2.2.1

.github/workflows/npm-bun-blocker.yml

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Runtime and package-manager policy check.
3+
#
4+
# Authority: hyperpolymath/standards LANGUAGE-POLICY.adoc §1.
5+
# Ordering: Bun (1st) > Deno (2nd) > pnpm (3rd) > npm (last resort).
6+
#
7+
# REPLACES npm-bun-blocker.yml, which failed any build carrying `bun.lockb` with
8+
# the message "npm/bun artifacts detected. Use Deno instead." That gate blocked
9+
# what is now the FIRST-choice runtime and mandated the second. It was present in
10+
# 55 repositories.
11+
#
12+
# What this fails on, deliberately:
13+
# MIXED TOOLCHAINS -- two different package managers' lockfiles in one repo.
14+
# That is real, actionable drift: two dependency graphs that can disagree.
15+
# What it does NOT fail on:
16+
# Using bun, deno, pnpm or npm. npm is LAST but PERMITTED; the check reports
17+
# the tier in use so drift is visible without blocking legitimate work.
18+
name: Runtime Policy
19+
on:
20+
push:
21+
branches: [main, master]
22+
pull_request:
23+
24+
concurrency:
25+
group: ${{ github.workflow }}-${{ github.ref }}
26+
cancel-in-progress: true
27+
28+
permissions:
29+
contents: read
30+
31+
jobs:
32+
runtime-policy:
33+
name: Runtime Policy
34+
runs-on: ubuntu-latest
35+
timeout-minutes: 10
36+
permissions:
37+
contents: read
38+
steps:
39+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
40+
41+
- name: Report runtime tier and reject mixed toolchains
42+
run: |
43+
set -euo pipefail
44+
45+
bun=0; deno=0; pnpm=0; npm=0
46+
[ -f bun.lockb ] || [ -f bun.lock ] && bun=1 || true
47+
[ -f deno.lock ] || [ -f deno.json ] || [ -f deno.jsonc ] && deno=1 || true
48+
[ -f pnpm-lock.yaml ] && pnpm=1 || true
49+
[ -f package-lock.json ] && npm=1 || true
50+
51+
total=$((bun + deno + pnpm + npm))
52+
53+
if [ "$total" -eq 0 ]; then
54+
echo "::notice::No JS/TS package manager in use — nothing to check."
55+
exit 0
56+
fi
57+
58+
# Report the tier actually in use (LANGUAGE-POLICY.adoc §1).
59+
[ "$bun" -eq 1 ] && echo "Bun — tier 1 (preferred)"
60+
[ "$deno" -eq 1 ] && echo "Deno — tier 2 (accepted; existing projects are grandfathered)"
61+
[ "$pnpm" -eq 1 ] && echo "pnpm — tier 3"
62+
[ "$npm" -eq 1 ] && echo "::warning::npm lockfile present. npm is tier 4, the last resort — permitted, never preferred. See LANGUAGE-POLICY.adoc §1."
63+
64+
if [ "$total" -gt 1 ]; then
65+
echo "::error::Mixed toolchains: $total package managers have lockfiles in this repository."
66+
echo "Two dependency graphs that can disagree is real drift. Pick one — preferring the"
67+
echo "highest tier present — and delete the others' lockfiles."
68+
exit 1
69+
fi
70+
71+
echo "✅ Single package manager in use."

.github/workflows/trope-check.yml

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
# SPDX-License-Identifier: MPL-2.0
22
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
33
#
4-
# Haec: every example lowers to a well-formed Trope IR document (bash + jq, no Python).
4+
# Haec: every example lowers to a well-formed Trope IR document AND round-trips
5+
# through the reference tropechecker to its expected verdict and witness.
6+
#
7+
# The round-trip is the one seam joining the three repos — Haec emits IR, the
8+
# checker returns a verdict — so it is built and asserted here rather than
9+
# skipped. TROPECHECK_REQUIRED=1 makes a missing binary a hard failure.
510
name: "🔴 Gate: Trope conformance"
611
on:
712
push:
@@ -16,7 +21,56 @@ concurrency:
1621
jobs:
1722
examples-lower-to-valid-ir:
1823
runs-on: ubuntu-latest
24+
timeout-minutes: 20
25+
# The reference checker is an Idris2 program whose verified core requires
26+
# Idris 2 *0.8.0*: under 0.7.0, Trope/Fidelity.idr fails to parse at the
27+
# lambda-impossible clause `No (\Refl impossible)`. Pinned by image digest.
28+
container:
29+
image: ghcr.io/stefan-hoeck/idris2-pack@sha256:de9781906050dc44704ec6de0108c86f899ef17b2642932b79e00245d613b8ad
1930
steps:
20-
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
21-
- name: Examples lower to valid Trope IR
31+
- name: Checkout Haec
32+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
33+
with:
34+
path: haec
35+
36+
# Checked out as a SIBLING of haec/ so tests/check-examples.sh finds it at
37+
# $ROOT/../trope-checker — which also activates the schema drift guard.
38+
- name: Checkout trope-checker (reference checker + canonical IR schema)
39+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
40+
with:
41+
repository: hyperpolymath/trope-checker
42+
ref: 69221ad6bec0c9286cb5c917edfad281e7e0089e # main @ 2026-07-28
43+
path: trope-checker
44+
45+
# The pinned idris2-pack image is minimal and ships no jq, which both the
46+
# test script and the conformance runner require.
47+
- name: Install container prerequisites (jq)
48+
shell: bash
49+
run: |
50+
set -euo pipefail
51+
if ! command -v jq >/dev/null 2>&1; then
52+
apt-get update -qq
53+
apt-get install -y -qq --no-install-recommends jq
54+
fi
55+
jq --version
56+
idris2 --version
57+
58+
# ADR 0002/0003: the Idris2 executable is the reference checker and reuses
59+
# the *proved* verified core, so the thing that runs is the thing that is
60+
# proved. Installing that core is therefore part of building the oracle.
61+
- name: Build the Idris2 reference checker
62+
shell: bash
63+
working-directory: trope-checker
64+
run: |
65+
set -euo pipefail
66+
idris2 --install verification/proofs/idris2/trope.ipkg
67+
( cd src/idris2 && idris2 --build tropecheck.ipkg )
68+
test -x src/idris2/build/exec/tropecheck
69+
echo "reference checker built"
70+
71+
- name: Examples lower to valid Trope IR, and round-trip to their verdicts
72+
shell: bash
73+
working-directory: haec
74+
env:
75+
TROPECHECK_REQUIRED: '1'
2276
run: bash tests/check-examples.sh

.github/workflows/ts-blocker.yml

Lines changed: 0 additions & 35 deletions
This file was deleted.

scripts/check-no-vlang.sh

Lines changed: 0 additions & 81 deletions
This file was deleted.

tests/check-examples.sh

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,38 @@ else
4040
echo -e "${Y}note${O} sibling trope-checker not checked out; skipping schema-drift guard"
4141
fi
4242

43-
# 4. full round-trip: verdicts via the sibling Idris2 checker, if built.
44-
BIN="$SIB/src/idris2/build/exec/tropecheck"
45-
if [ -x "$BIN" ]; then
43+
# 4. full round-trip: verdicts via the reference checker.
44+
#
45+
# TROPECHECK_BIN names the binary (same variable trope-checker's own conformance
46+
# runner honours); it defaults to the sibling Idris2 reference build. Set
47+
# TROPECHECK_REQUIRED=1 — as CI does — to make a missing binary a hard failure
48+
# rather than a skip: a round-trip that silently does not run is a fake gate.
49+
BIN="${TROPECHECK_BIN:-$SIB/src/idris2/build/exec/tropecheck}"
50+
if [ ! -x "$BIN" ] && [ "${TROPECHECK_REQUIRED:-0}" = "1" ]; then
51+
echo -e "${R}FAIL${O} TROPECHECK_REQUIRED=1 but no checker binary at $BIN"
52+
echo " build it with: idris2 --install verification/proofs/idris2/trope.ipkg"
53+
echo " idris2 --build src/idris2/tropecheck.ipkg (Idris2 0.8.0)"
54+
fail=1
55+
elif [ -x "$BIN" ]; then
4656
while read -r e; do
4757
ir=$(jq -r '.ir' <<<"$e"); exp=$(jq -r '.expect' <<<"$e")
48-
got=$("$BIN" "$EX/$ir" | awk '{print $1}')
49-
if [ "$got" = "$exp" ]; then echo -e "${G}ok${O} round-trip $ir$got"
50-
else echo -e "${R}FAIL${O} round-trip $ir: got $got, expected $exp"; fail=1; fi
58+
# the checker exits non-zero on p-insufficient — that is a verdict, not an
59+
# error, so do not let it abort the loop.
60+
out=$("$BIN" "$EX/$ir" || true)
61+
got=$(awk '{print $1}' <<<"$out")
62+
wexp=$(jq -r '.witness // [] | join("/")' <<<"$e")
63+
ok=1
64+
[ "$got" = "$exp" ] || ok=0
65+
if [ -n "$wexp" ]; then
66+
gw=$(grep -o 'witness=[^[:space:]]*' <<<"$out" | cut -d= -f2)
67+
gc=$(grep -o 'coord=[^[:space:]]*' <<<"$out" | cut -d= -f2)
68+
[ "$gw/$gc" = "$wexp" ] || ok=0
69+
fi
70+
if [ "$ok" = 1 ]; then echo -e "${G}ok${O} round-trip $ir$got${wexp:+ (witness $wexp)}"
71+
else echo -e "${R}FAIL${O} round-trip $ir: got '$out', expected $exp${wexp:+ witness $wexp}"; fail=1; fi
5172
done < <(jq -c '.examples[]' "$EX/EXAMPLES.json")
5273
else
53-
echo -e "${Y}note${O} sibling tropecheck binary not built; skipping verdict round-trip (run 'just trope-build' in ../trope-checker)"
74+
echo -e "${Y}note${O} no checker binary; skipping verdict round-trip (set TROPECHECK_BIN, or TROPECHECK_REQUIRED=1 to make this fatal)"
5475
fi
5576

5677
if [ "$fail" = 0 ]; then echo -e "\n${G}examples: all lower to valid Trope IR${O}"; else echo -e "\n${R}examples: failures${O}"; fi

0 commit comments

Comments
 (0)