-
Notifications
You must be signed in to change notification settings - Fork 0
268 lines (249 loc) · 11.5 KB
/
Copy pathbuild-oracle.yml
File metadata and controls
268 lines (249 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
name: Build and publish oracle_bin
# Build the standalone `oracle_bin` (the RocqRefRunner used by
# NetTopologySuite.Curve's differential-test harness) and publish it as a
# GHA artifact on every push to main. On release events the same binary
# is attached to the release as a downloadable asset, giving .Curve's CI
# a stable URL to consume.
#
# Toolchain pin: reuses the project's Dockerfile `toolchain` stage
# (rocq 9.2.0 + ocaml 4.14.2-flambda + coq-flocq.4.2.2 + ocamlfind),
# pulled from GHCR under its Dockerfile-hash tag (published by ci.yml on
# main pushes) with a buildx + GHA-layer-cache fallback on a miss, so
# the slow `opam install coq-flocq.4.2.2` step is not repeated.
#
# SPEED (June 2026): PULL REQUESTS reuse the incremental corpus cache
# that ci.yml maintains (.vo artefacts + sha256 manifest;
# scripts/ci_invalidate_stale_vo.py makes make's mtime logic sound
# against it by content). This job is a STRICTLY READ-ONLY cache
# consumer: it never saves the cache and never writes the manifest,
# because it does not run the axiom audit or refresh the .palog/
# chunks -- a cache saved here could pair a fresh manifest with stale
# Print Assumptions chunks and silently weaken ci.yml's guardrail 4.
# Main pushes and release events skip the restore entirely: the
# PUBLISHED oracle_bin always comes from a full from-clean build.
# `Validate_binary64_extract.v` (a leaf: nothing imports it) is touched
# after the invalidation pass so the extraction always re-runs and
# oracle/extracted.ml is always regenerated fresh.
on:
push:
branches: [main]
paths:
- 'oracle/**'
- 'theories-flocq/**'
- '_CoqProject.full'
- 'Dockerfile'
- '.github/workflows/build-oracle.yml'
# Gate `oracle/driver.ml` (the RocqRefRunner sources) on PRs into main.
# Without this trigger the oracle is only compiled AFTER merge to main:
# ci.yml never runs `make -C oracle/`, so a syntax/type error in a new
# driver mode (e.g. CLOTHOID_INTERSECT) would otherwise reach main
# unvalidated. Same `paths:` filter as the push trigger keeps the slow
# container build off PRs that don't touch the oracle/flocq corpus.
pull_request:
branches: [main]
paths:
- 'oracle/**'
- 'theories-flocq/**'
- '_CoqProject.full'
- 'Dockerfile'
- '.github/workflows/build-oracle.yml'
workflow_dispatch:
release:
types: [published]
# Opt into Node.js 24 for JavaScript actions (actions/checkout,
# actions/upload-artifact, docker/* actions etc.). GitHub Actions
# deprecated the Node.js 20 runtime on 2025-09-19 and forces Node.js 24
# as the default on 2026-06-02; setting this flag now silences the
# transitional deprecation warning and verifies the workflow runs
# cleanly on the new runtime before the cutover. See
# https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
build-oracle:
name: Build oracle_bin in pinned rocq 9.2.0 + flocq 4.2.2 container
# Skip standalone-package releases (robust-predicates-v* / spatial-algebra-v*):
# those are published by the package-*.yml workflows and have nothing to do
# with oracle_bin. Without this guard, every package release triggers this
# job and its release-attach step fails ("Resource not accessible by
# integration" -- this job only has contents: read), reding the release.
if: >-
github.event_name != 'release' ||
(!startsWith(github.event.release.tag_name, 'robust-predicates-v') &&
!startsWith(github.event.release.tag_name, 'spatial-algebra-v'))
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
env:
TOOLCHAIN_IMAGE: ghcr.io/${{ github.repository_owner }}/nts-proofs-toolchain
steps:
- uses: actions/checkout@v6
- name: Compute toolchain tag (content-addressed by Dockerfile)
id: toolchain
run: echo "tag=df-$(sha256sum Dockerfile | cut -c1-16)" >> "$GITHUB_OUTPUT"
- name: Log in to GHCR
continue-on-error: true
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Pull toolchain image from GHCR
# Publishing is ci.yml's job (it runs on EVERY main push); this
# workflow only consumes the tag, with a local build fallback.
id: pull
run: |
if docker pull "$TOOLCHAIN_IMAGE:${{ steps.toolchain.outputs.tag }}"; then
docker tag "$TOOLCHAIN_IMAGE:${{ steps.toolchain.outputs.tag }}" nts-proofs-oracle:ci
echo "hit=true" >> "$GITHUB_OUTPUT"
else
echo "hit=false" >> "$GITHUB_OUTPUT"
fi
- name: Set up Docker Buildx
if: steps.pull.outputs.hit != 'true'
uses: docker/setup-buildx-action@v3
- name: Build toolchain image (GHCR miss)
# Only when the Dockerfile changed (or the tag was never
# published). The GHA layer cache is shared with ci.yml's
# `rocq-flocq` job, so the slow `opam install coq-flocq.4.2.2`
# step (~5 min cold) is not repeated.
if: steps.pull.outputs.hit != 'true'
uses: docker/build-push-action@v6
with:
context: .
target: toolchain
load: true
tags: nts-proofs-oracle:ci
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Restore compiled-corpus cache (PRs only)
# READ-ONLY reuse of the cache ci.yml maintains. Main pushes
# and releases skip this: the published oracle_bin is always
# built from clean (artifact provenance). See the header
# comment for why this job must never SAVE the cache.
if: github.event_name == 'pull_request'
uses: actions/cache/restore@v4
with:
path: |
theories/*.vo*
theories/*.glob
theories/.*.aux
theories-flocq/*.vo*
theories-flocq/*.glob
theories-flocq/.*.aux
.palog
.vo-manifest
key: vo-cache-${{ hashFiles('Dockerfile') }}-${{ github.run_id }}
restore-keys: |
vo-cache-${{ hashFiles('Dockerfile') }}-
- name: Invalidate stale artefacts (content-addressed)
# Same script as ci.yml: ages unchanged .v files / touches
# changed ones by sha256 so make rebuilds exactly the changed
# files plus dependents. No-op on a cold cache.
run: python3 scripts/ci_invalidate_stale_vo.py
- name: Force extraction freshness
# Validate_binary64_extract.v is a leaf (nothing imports it);
# touching it AFTER the invalidation pass guarantees the
# extraction target always re-runs, so oracle/extracted.ml and
# .mli are regenerated from the (cached or rebuilt) dependency
# chain on every run. extracted.ml is gitignored -- it never
# exists before the build.
run: touch theories-flocq/Validate_binary64_extract.v
- name: Build corpus, extract, link oracle_bin
# Inside the pinned container, on the MOUNTED live checkout
# (cached .vo files are visible to make; oracle_bin lands
# directly in the runner workspace -- no docker cp dance):
# 1. Clean host-leaked makefile artefacts (NOT .vo -- those
# are the incremental cache).
# 2. rocq makefile -f _CoqProject.full -o Makefile.gen.
# 3. make -- rebuilds changed files + dependents + the touched
# extraction leaf, which writes oracle/extracted.ml + .mli.
# 4. make -C oracle/ -- links extracted.cmx + driver.cmx
# against -package str (ocamlfind is baked into the
# toolchain image).
# chmod lets the image's `rocq` user (uid 1000) write into
# runner-owned dirs; the chown hands the artefacts back.
run: |
chmod -R a+rwX .
docker run --rm -v "$PWD:/workspace" -w /workspace \
nts-proofs-oracle:ci \
bash -lc '
set -euxo pipefail
rm -f Makefile.gen Makefile.gen.conf .Makefile.d .Makefile.gen.d \
.nra.cache
rocq makefile -f _CoqProject.full -o Makefile.gen
make -f Makefile.gen -j"$(nproc)"
test -f oracle/extracted.ml
test -f oracle/extracted.mli
make -C oracle/
test -x oracle/oracle_bin
make -C oracle/ ffi
test -f oracle/libntsrocq.so
test -x oracle/ffi_probe
'
sudo chown -R "$(id -u):$(id -g)" .
- name: Sanity check artifact
run: |
test -x oracle/oracle_bin
file oracle/oracle_bin
ls -la oracle/oracle_bin
test -f oracle/libntsrocq.so
file oracle/libntsrocq.so
ls -la oracle/libntsrocq.so
- name: FFI parity gate (libntsrocq == oracle_bin, bit for bit)
# Phase 5: the in-process C ABI and the stdin/stdout oracle protocol
# call the SAME extracted code, so any divergence is a marshalling bug
# (argument order, enum encoding, truncated result list). Doubles are
# compared as raw IEEE 754 bit patterns. Nonzero exit on any '!!'.
run: |
docker run --rm -v "$PWD:/workspace" -w /workspace \
nts-proofs-oracle:ci \
bash -lc '
set -euxo pipefail
python3 oracle/gen_ffi_parity_tests.py
'
- name: Run oracle gated-invariant tests
# Runs each oracle test generator that gates proven invariants.
# oracle/oracle_bin was just built and is at the expected path.
# Nonzero exit on any '!!' invariant violation fails the build.
run: |
ORACLE_BIN=oracle/oracle_bin python3 oracle/gen_winding_number_tests.py \
> oracle/winding_number_tests.txt
ORACLE_BIN=oracle/oracle_bin python3 oracle/gen_disc_overlay_tests.py \
> oracle/disc_overlay_tests.txt
ORACLE_BIN=oracle/oracle_bin python3 oracle/gen_lec_circle_tests.py \
> oracle/lec_circle_tests.txt
ORACLE_BIN=oracle/oracle_bin python3 oracle/gen_obstacle_distance_tests.py \
> oracle/obstacle_distance_tests.txt
ORACLE_BIN=oracle/oracle_bin python3 oracle/gen_arc_distance_tests.py \
> oracle/arc_distance_tests.txt
ORACLE_BIN=oracle/oracle_bin python3 oracle/gen_i_circular_tests.py \
> oracle/i_circular_tests.txt
ORACLE_BIN=oracle/oracle_bin python3 oracle/gen_ieee_oracle_bridge_tests.py \
> oracle/ieee_oracle_bridge_run.txt
- name: Upload oracle_bin artifact (90-day retention)
uses: actions/upload-artifact@v4
with:
name: oracle-bin-linux
path: oracle/oracle_bin
retention-days: 90
- name: Upload libntsrocq artifact (90-day retention)
# Phase 5: the in-process native library + its ABI header, so the
# NetTopologySuite.Curve consumer can bind it without rebuilding the
# corpus. Linux x64 only for now (the runner's architecture).
uses: actions/upload-artifact@v4
with:
name: libntsrocq-linux-x64
path: |
oracle/libntsrocq.so
oracle/nts_ffi.h
retention-days: 90
- name: Attach oracle_bin to release (release events only)
if: github.event_name == 'release'
uses: softprops/action-gh-release@v2
with:
files: |
oracle/oracle_bin
oracle/libntsrocq.so
oracle/nts_ffi.h