Skip to content

Commit 8c9ddcb

Browse files
hyperpolymathclaude
andcommitted
harden(foundation P1): reproducible CI-via-flake exact pin (additive verifier)
flake.nix evolved to pin the toolchain reproducibly: * Agda via nixpkgs nixos-24.11 (2.7.0.1) * standard-library tag v2.3 as a flake input (was nixpkgs-bundled, a DIFFERENT version than CI/local verify against) * absolute-zero @3ff5cee as a flake input (was a local ~/dev checkout — not reproducible / not CI-usable) plus a hermetic checks.suite (guardrail + 4 roots + N5 xfail) under that pinned toolchain. CI: additive job runs . ADDITIVE and continue-on-error: the apt + jobs remain the gate, so the 2.7.0.1-vs-verified-2.8.0 delta (if any) is SURFACED, not a regression. First green run is the P1 verification. Honest constraints, flagged not hidden (triage, not a blind cutover): * no in the dev env → flake authored designed-correct, verified BY CI, NOT locally claimed green; libraries file built via writeText+cp (no heredoc/indentation hazard) to de-risk the one fragile part by construction. * cross-stack: a devShell-only flake.nix also lives on the reframe stack (#47, commit 185eb74); THIS strictly supersedes it (adds pins+checks, no behavioural conflict) — take this at integration. * Agda 2.7.0.1 vs verified 2.8.0 is an explicit surfaced decision, not an assumption; reconcile via the logged CI delta. docs/foundation.adoc P1 item moved tracked-followup -> implemented, pending first-green CI verification; revision history appended. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7cfa771 commit 8c9ddcb

3 files changed

Lines changed: 170 additions & 6 deletions

File tree

.github/workflows/agda.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,28 @@ jobs:
179179
agda --ignore-interfaces -i proofs/agda proofs/agda/Smoke.agda
180180
agda --ignore-interfaces -i proofs/agda proofs/agda/characteristic/All.agda
181181
agda --ignore-interfaces -i proofs/agda proofs/agda/examples/All.agda
182+
183+
flake-check:
184+
# Foundation P1: the reproducible, exactly-pinned toolchain.
185+
# `nix flake check` runs flake.nix's hermetic `checks.suite`
186+
# (flake-pinned Agda + PINNED stdlib v2.3 + PINNED absolute-zero
187+
# @3ff5cee, guardrail + 4 roots + N5 xfail). ADDITIVE: the apt
188+
# `check` and `cold-check` jobs remain the gate, so a version
189+
# delta surfaced here (e.g. 2.7.0.1 vs verified 2.8.0) is
190+
# informative, not a regression. Its first green run IS the P1
191+
# verification (the dev env has no nix; CI is the verifier).
192+
# Flip continue-on-error to false once it is first green.
193+
runs-on: ubuntu-latest
194+
continue-on-error: true
195+
steps:
196+
- name: Checkout
197+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
198+
199+
- name: Install Nix (pinned action)
200+
uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30
201+
with:
202+
extra_nix_config: |
203+
experimental-features = nix-command flakes
204+
205+
- name: nix flake check (hermetic, reproducible)
206+
run: nix flake check --print-build-logs

docs/foundation.adoc

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,25 @@ hack: left explicit and failing, never forced green.
8989

9090
== Known limitations (tracked, not silent)
9191

92-
. *CI Agda version not exactly pinned.* CI installs Ubuntu's `agda`
93-
(apt); local dev and the Nix flake differ (2.8.0 / flake-pinned).
94-
The CI step *records and minimally asserts* the version (fails on a
95-
wildly wrong major) so it is visible, not silently floating. Exact
96-
parity via *CI-through-the-flake* is the tracked P1 follow-up — the
97-
only honest way to pin Agda reproducibly.
92+
. *CI Agda exact pin* — *reproducible pin IMPLEMENTED 2026-05-18;
93+
first-green verification delegated to CI.* `flake.nix` now pins, as
94+
flake inputs: Agda via `nixpkgs nixos-24.11` (2.7.0.1), standard
95+
library at tag `v2.3`, and `absolute-zero` at commit `3ff5cee…`
96+
(previously nixpkgs-bundled stdlib + a local `absolute-zero`
97+
checkout — neither reproducible). A hermetic `checks.suite`
98+
(guardrail + four roots + N5 xfail) runs under that pinned
99+
toolchain; an *additive* `flake-check` CI job (`nix flake check`)
100+
exercises it. This is honest about its boundary: the dev
101+
environment has no `nix`, so the flake was authored designed-correct
102+
but its build is *first verified by CI*, not claimed green here. It
103+
is `continue-on-error` until first green so a version delta
104+
(2.7.0.1 vs the verified-green 2.8.0 / apt) is *surfaced*, not a
105+
regression; the apt `check` + `cold-check` jobs remain the gate.
106+
Open sub-item: on first green, flip `continue-on-error` to `false`
107+
and retire the apt job; if red, the logged delta says which
108+
nixpkgs/Agda to bump. (Cross-stack: a devShell-only `flake.nix`
109+
also exists on the reframe stack PR #47; this one strictly
110+
supersedes it.)
98111
. *External-fibre triangulation* — *DONE 2026-05-18*,
99112
`proofs/agda/EchoFiberTriangulation.agda` (wired into `All.agda`,
100113
pinned in `Smoke.agda`, `--safe --without-K`, zero postulates).
@@ -157,3 +170,12 @@ Pinned inputs: `standard-library` `v2.3`; `absolute-zero`
157170
follow-up entry is intentionally deferred to stack reconciliation
158171
(the append-only log evolves on the reframe/earn-back stack; adding
159172
a divergent entry on this `main`-based branch would fork it).
173+
* *2026-05-18 — CI-via-flake reproducible pin implemented.*
174+
`flake.nix` evolved to pin Agda (nixpkgs nixos-24.11) + stdlib v2.3
175+
+ absolute-zero @3ff5cee as flake inputs, with a hermetic
176+
`checks.suite`; additive `flake-check` CI job
177+
(`continue-on-error`) added as the verifier. Authored without local
178+
`nix` (none in dev env) — designed-correct, CI-verified, not
179+
locally claimed green; flagged as such, gate unchanged. P1 item
180+
status moved from "tracked follow-up" to "implemented, pending
181+
first-green CI verification".

flake.nix

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
{
2+
# SPDX-License-Identifier: PMPL-1.0-or-later
3+
#
4+
# Reproducible toolchain for echo-types — foundation P1 (CI-via-flake
5+
# exact pin; docs/foundation.adoc §"Known limitations").
6+
#
7+
# CROSS-STACK NOTE. A simpler devShell-only flake.nix also exists on
8+
# the reframe stack (commit 185eb74, PR #47). THIS file is a strict
9+
# evolution of it (same devShell tools + PINNED Agda-library inputs +
10+
# a hermetic `checks` output). At integration, this harden-stack
11+
# version supersedes the reframe-stack one — no behavioural conflict,
12+
# it only adds pins and checks.
13+
#
14+
# PINNING DECISION (explicit, surfaced — not assumed):
15+
# * Agda: nixpkgs `nixos-24.11` -> agda 2.7.0.1 (also ghc 9.6.6,
16+
# cabal 3.12.1.0, rustc 1.82.0, just 1.38.0 — .tool-versions
17+
# match). The verified-green local toolchain is agda 2.8.0; CI's
18+
# apt job runs yet another. The suite has so far proven robust
19+
# across apt-agda and 2.8.0; whether it also typechecks under
20+
# 2.7.0.1 + stdlib v2.3 is VERIFIED BY the additive
21+
# `nix flake check` CI job, not assumed here. If that job is red
22+
# it surfaces the exact version delta to reconcile (bump the
23+
# nixpkgs input); the apt + cold-check jobs remain the gate
24+
# meanwhile, so nothing regresses.
25+
# * standard-library: PINNED to tag v2.3 as a flake input (was
26+
# nixpkgs-bundled — a different version than CI/local verify).
27+
# * absolute-zero: PINNED to commit 3ff5cee… as a flake input
28+
# (was a local ~/dev checkout — not reproducible / not CI-usable).
29+
#
30+
# NOTE: authored without a local `nix` (none in the dev env);
31+
# flake.lock is generated and the build first verified BY CI.
32+
# Designed-correct, CI-verified — not locally claimed green.
33+
description = "echo-types reproducible toolchain (Agda + libs pinned)";
34+
35+
inputs = {
36+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
37+
agda-stdlib = {
38+
url = "github:agda/agda-stdlib/v2.3";
39+
flake = false;
40+
};
41+
absolute-zero = {
42+
url = "github:hyperpolymath/absolute-zero/3ff5cee7f3fd002378089cd02f0c90a3747b45f0";
43+
flake = false;
44+
};
45+
};
46+
47+
outputs = { self, nixpkgs, agda-stdlib, absolute-zero }:
48+
let
49+
systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
50+
forAllSystems = nixpkgs.lib.genAttrs systems;
51+
52+
# The Agda libraries file as an exact store file — no heredoc,
53+
# no Nix-string indentation hazard. Agda resolves each
54+
# `.agda-lib`'s `include:` relative to that file's own directory,
55+
# so pointing at the pinned inputs' own `.agda-lib` paths is
56+
# sufficient. (Nix `"..."` interprets `\n` as a real newline.)
57+
mkLibs = pkgs: pkgs.writeText "agda-libraries"
58+
"${agda-stdlib}/standard-library.agda-lib\n${absolute-zero}/absolute-zero.agda-lib\n";
59+
in {
60+
devShells = forAllSystems (system:
61+
let
62+
pkgs = import nixpkgs { inherit system; };
63+
libs = mkLibs pkgs;
64+
in {
65+
default = pkgs.mkShell {
66+
name = "echo-types";
67+
packages = [
68+
pkgs.agda pkgs.just pkgs.ghc pkgs.cabal-install
69+
pkgs.rustc pkgs.cargo pkgs.rustfmt pkgs.clippy
70+
];
71+
shellHook = ''
72+
export AGDA_DIR="$PWD/.agda"
73+
mkdir -p "$AGDA_DIR"
74+
cp -f ${libs} "$AGDA_DIR/libraries"
75+
chmod u+w "$AGDA_DIR/libraries"
76+
echo "echo-types devShell (PINNED):"
77+
command -v agda >/dev/null && echo " agda : $(agda --version 2>/dev/null | head -n1)"
78+
echo " stdlib: v2.3 (flake input, pinned)"
79+
echo " absz : 3ff5cee (flake input, pinned)"
80+
'';
81+
};
82+
});
83+
84+
# Hermetic, reproducible verification: the flake-pinned Agda over
85+
# the pinned stdlib v2.3 + absolute-zero, running the same
86+
# guardrail + four roots + N5 expected-failure gate that CI's
87+
# apt job runs. `nix flake check` exercises this.
88+
checks = forAllSystems (system:
89+
let
90+
pkgs = import nixpkgs { inherit system; };
91+
libs = mkLibs pkgs;
92+
in {
93+
suite = pkgs.runCommand "echo-types-suite"
94+
{ nativeBuildInputs = [ pkgs.agda pkgs.bash ]; }
95+
''
96+
export HOME="$TMPDIR"
97+
mkdir -p "$HOME/.agda"
98+
cp -f ${libs} "$HOME/.agda/libraries"
99+
# Agda needs a writable source tree (.agdai outputs).
100+
cp -r ${self} src
101+
chmod -R u+w src
102+
cd src
103+
bash tools/check-guardrails.sh proofs/agda
104+
agda -i proofs/agda proofs/agda/All.agda
105+
agda -i proofs/agda proofs/agda/Smoke.agda
106+
agda -i proofs/agda proofs/agda/characteristic/All.agda
107+
agda -i proofs/agda proofs/agda/examples/All.agda
108+
if agda -i proofs/agda proofs/agda/characteristic/N5Falsifier.agda \
109+
> /dev/null 2>&1; then
110+
echo "N5Falsifier unexpectedly typechecks — see foundation.adoc"
111+
exit 1
112+
fi
113+
touch "$out"
114+
'';
115+
});
116+
};
117+
}

0 commit comments

Comments
 (0)