-
Notifications
You must be signed in to change notification settings - Fork 0
366 lines (331 loc) · 16.3 KB
/
Copy pathci.yml
File metadata and controls
366 lines (331 loc) · 16.3 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
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
# Cancel an in-flight CI run if a newer commit lands on the same ref.
# This dedupes user-push storms (rapid commits to a PR or main).
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
# `RUSTFLAGS: -D warnings` is applied per-step in the `rust` job below
# rather than globally — the napi-rs binding crate has macro-generated
# FFI items that trip pedantic-tier lints that don't apply to FFI
# surfaces.
# Skip CI on PR sync events from the release-plz bot. Rationale:
# - User pushes commit to main → CI runs on push (verifies the change).
# - release-plz auto-updates its release PR with version bumps + changelog
# entries on top of that commit → would re-trigger CI on pull_request
# synchronize, but the only diff vs the just-tested main is mechanical
# (Cargo.toml version, CHANGELOG.md additions) — testing it is redundant.
# - After PR merge, push of "chore: release vX.Y.Z" to main runs CI again
# (verifies the merged release state before release-plz publishes).
# Trade-off: if release-plz ever produces a broken Cargo.toml/CHANGELOG (e.g.
# malformed semver), we'd catch it post-merge instead of pre-merge. Acceptable
# since release-plz output is mechanical and the post-merge run still gates
# the publish step in release.yml.
#
# Applied as a per-job `if:` because GitHub Actions doesn't support workflow-
# level conditional triggering by author. The expression below excludes ONLY
# bot-authored PR-sync events; everything else (user push, user PR, etc.)
# runs normally.
jobs:
# ---------------------------------------------------------------------
# Rust: check + test + clippy + fmt + cargo-deny on the pinned 1.95
# toolchain (workspace `rust-toolchain.toml`). Excludes binding crates
# from `cargo test`/`cargo build` via workspace `default-members` —
# they need their own toolchains (napi-rs, maturin, wasm-pack) and
# land separately in the binding-specific jobs below.
# ---------------------------------------------------------------------
rust:
name: Rust ${{ matrix.toolchain }}
if: "${{ (github.event_name != 'pull_request' || github.actor != 'graphrefly-write-content[bot]') && (github.event_name != 'push' || !startsWith(github.event.head_commit.message, 'chore: release')) }}"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
toolchain: ["1.95"]
steps:
- uses: actions/checkout@v5
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ matrix.toolchain }}
components: rustfmt, clippy
- name: Cache cargo registry + target
uses: Swatinem/rust-cache@v2
with:
shared-key: rust-${{ matrix.toolchain }}
- name: Cargo fmt --check
run: cargo fmt --all -- --check
- name: Cargo check (default-members)
run: cargo check
env:
RUSTFLAGS: "-D warnings"
- name: Cargo clippy (default-members, all targets, pedantic-tier)
run: cargo clippy --all-targets -- -D warnings
- name: Cargo test (default-members)
run: cargo test --all-targets
env:
RUSTFLAGS: "-D warnings"
- name: Cargo doc (no deps; catches broken intra-doc links)
run: cargo doc --no-deps
env:
# `-D warnings` keeps real doc errors fatal (unparseable doc, missing
# docs on must-document items, etc.) but allows the three noisy
# doc-link lint families that pre-1.0 internal modules legitimately
# trigger:
# - private_intra_doc_links: links from public docs to private
# items (informative for maintainers, fine for pre-1.0).
# - broken_intra_doc_links: typos / unresolved paths in doc
# comments. Should be cleaned up but isn't blocking.
# - redundant_explicit_links: explicit target same as label.
# Tightening these to deny is a separate doc-quality slice (track
# in `docs/porting-deferred.md` if/when prioritized).
RUSTDOCFLAGS: "-D warnings -A rustdoc::private_intra_doc_links -A rustdoc::broken_intra_doc_links -A rustdoc::redundant_explicit_links"
# ---------------------------------------------------------------------
# Supply-chain audit via cargo-deny — license allowlist, advisory
# database, version-unification warnings. Pinned action version so
# `cargo install cargo-deny` doesn't recompile from source on every
# CI run.
# ---------------------------------------------------------------------
deny:
name: cargo deny (supply-chain audit)
if: "${{ (github.event_name != 'pull_request' || github.actor != 'graphrefly-write-content[bot]') && (github.event_name != 'push' || !startsWith(github.event.head_commit.message, 'chore: release')) }}"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: EmbarkStudios/cargo-deny-action@v2
with:
command: check
arguments: --all-features
# ---------------------------------------------------------------------
# napi-rs JavaScript binding — builds + lints. Doesn't run tests
# (the binding's tests are JS-side and live in graphrefly-ts's
# bench harness). The build verifies the cdylib link works.
# ---------------------------------------------------------------------
bindings-js:
name: napi-rs binding (cdylib build + clippy)
if: "${{ (github.event_name != 'pull_request' || github.actor != 'graphrefly-write-content[bot]') && (github.event_name != 'push' || !startsWith(github.event.head_commit.message, 'chore: release')) }}"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.95"
components: clippy
- uses: actions/setup-node@v5
with:
node-version: "24"
- name: Cache cargo
uses: Swatinem/rust-cache@v2
with:
shared-key: bindings-js
- name: Build napi-rs binding (lib + cdylib)
run: cargo build -p graphrefly-bindings-js --features tracing
# Clippy here is informational — napi-rs macro-generated code +
# FFI-exported `pub fn` items trip clippy::pedantic warnings that
# don't apply to FFI surfaces. Build success is the bar; clippy
# output is captured for review.
- name: Clippy on bindings-js (informational)
run: cargo clippy -p graphrefly-bindings-js --features tracing
continue-on-error: true
# ---------------------------------------------------------------------
# Cross-platform napi build matrix (Phase E rustImpl activation slice,
# D075). Builds the `.node` artifact for each target triple and uploads
# as a workflow artifact. NOT published to npm — that's a separate
# release-engineering slice. Downstream parity-tests in graphrefly-ts
# download the host artifact for activation testing.
#
# Matrix mirrors `crates/graphrefly-bindings-js/package.json`'s
# `napi.targets`. linux-arm64 + win-arm64 are emitted but not yet
# tested in parity (host runner constraint); when GitHub Actions
# offers ARM runners more broadly we'll wire those into parity too.
# ---------------------------------------------------------------------
napi-build-matrix:
name: napi build (${{ matrix.target }})
if: "${{ (github.event_name != 'pull_request' || github.actor != 'graphrefly-write-content[bot]') && (github.event_name != 'push' || !startsWith(github.event.head_commit.message, 'chore: release')) }}"
needs: bindings-js
strategy:
fail-fast: false
matrix:
include:
# x86_64-apple-darwin dropped 2026-05-09 — Apple stopped selling
# Intel Macs in 2023, install base shrinking, and macos-13 runner
# pool was queueing for minutes per build. Re-add later if user
# demand surfaces (could cross-compile from macos-14 to avoid the
# macos-13 deprecated-pool problem).
- target: aarch64-apple-darwin
runner: macos-14
artifact: graphrefly-native.darwin-arm64.node
- target: x86_64-unknown-linux-gnu
runner: ubuntu-latest
artifact: graphrefly-native.linux-x64-gnu.node
- target: aarch64-unknown-linux-gnu
runner: ubuntu-latest
artifact: graphrefly-native.linux-arm64-gnu.node
cross: true
- target: x86_64-pc-windows-msvc
runner: windows-latest
artifact: graphrefly-native.win32-x64-msvc.node
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v5
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.95"
targets: ${{ matrix.target }}
- uses: actions/setup-node@v5
with:
node-version: "24"
- name: Install pnpm
uses: pnpm/action-setup@v5
with:
version: "10"
- name: Cache cargo
uses: Swatinem/rust-cache@v2
with:
shared-key: napi-${{ matrix.target }}
- name: Install cross (linux-arm64 only)
if: matrix.cross == true
run: cargo install cross --git https://github.com/cross-rs/cross --locked
- name: Install @napi-rs/cli + workspace deps
working-directory: crates/graphrefly-bindings-js
run: |
pnpm install --no-frozen-lockfile
- name: Build napi binding (${{ matrix.target }})
working-directory: crates/graphrefly-bindings-js
run: |
if [ "${{ matrix.cross }}" = "true" ]; then
pnpm exec napi build --platform --release --target ${{ matrix.target }} --features standard --use-cross
else
pnpm exec napi build --platform --release --target ${{ matrix.target }} --features standard
fi
shell: bash
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: napi-${{ matrix.target }}
path: crates/graphrefly-bindings-js/${{ matrix.artifact }}
if-no-files-found: error
retention-days: 7
# ---------------------------------------------------------------------
# TLA+ model checks — runs the canonical handle-protocol scenarios
# from `~/src/graphrefly-ts/docs/research/`. The Rust port refines
# the same wave_protocol invariants; any drift between the Rust
# impl and the spec MUST surface here too.
#
# The MC harnesses live in graphrefly-ts. CI fetches them via raw
# GitHub URLs so this workflow doesn't need a sibling-repo checkout.
# When TS's MC files change, this CI picks them up on next run.
#
# Each TLC run uses ~10s of CPU on a small state space (the MCs are
# tuned for fast verification — diamond + rewire scenarios).
# ---------------------------------------------------------------------
tlc:
name: TLA+ model check (wave_protocol scenarios)
if: "${{ (github.event_name != 'pull_request' || github.actor != 'graphrefly-write-content[bot]') && (github.event_name != 'push' || !startsWith(github.event.head_commit.message, 'chore: release')) }}"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Set up Java (TLC requires JRE 11+)
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"
- name: Download TLA+ tools
run: |
curl -fL --retry 3 -o /tmp/tla2tools.jar \
https://github.com/tlaplus/tlaplus/releases/download/v1.8.0/tla2tools.jar
test -s /tmp/tla2tools.jar
- name: Fetch MC harnesses from graphrefly-ts (handle-protocol + wave-protocol-rewire)
# NOTE: pinned via the `TLA_REF` env var. `main` is the Rust port's
# default tracking branch — it picks up canonical-spec amendments
# immediately. Pin to a release SHA / tag once graphrefly-ts cuts
# versioned releases (post-v1.0). Tracked in
# `docs/porting-deferred.md` under "CI hardening".
env:
TLA_REF: main
shell: bash -euo pipefail {0}
run: |
mkdir -p /tmp/tla
# Two source repos:
# - graphrefly-ts/docs/research/ — handle_protocol + wave_protocol_rewire MC harnesses
# - graphrefly/formal/ — base wave_protocol.tla that handle_protocol EXTENDS
BASE_TS="https://raw.githubusercontent.com/graphrefly/graphrefly-ts/${TLA_REF}/docs/research"
BASE_SPEC="https://raw.githubusercontent.com/graphrefly/graphrefly/${TLA_REF}/formal"
# Note: handle_protocol.tla uses underscore — TLA+ requires the
# filename to match the MODULE name exactly (`MODULE handle_protocol`).
# An earlier hyphenated `handle-protocol.tla` filename was renamed
# in graphrefly-ts for this reason.
fetch() {
# `--retry-all-errors` retries on 404 too — covers the case where
# raw.githubusercontent.com's CDN edge hasn't propagated a fresh
# push yet. Without it, `--retry` skips 404. `--retry-delay 10`
# spaces retries to let CDN catch up.
local url="$1" out="$2"
curl -fL --retry 5 --retry-all-errors --retry-delay 10 \
-o "$out" "$url"
test -s "$out"
}
# From graphrefly-ts (handle-protocol refinement + rewire harness
# + Phase I partitioned-protocol harness).
for f in handle_protocol.tla handle_protocol_MC.tla handle_protocol_MC.cfg \
wave_protocol_rewire.tla wave_protocol_rewire_MC.tla \
wave_protocol_rewire_MC.cfg \
wave_protocol_partitioned.tla wave_protocol_partitioned_MC.tla \
wave_protocol_partitioned_MC.cfg; do
fetch "$BASE_TS/$f" "/tmp/tla/$f"
done
# From graphrefly (spec repo) — base modules that the above EXTEND.
for f in wave_protocol.tla; do
fetch "$BASE_SPEC/$f" "/tmp/tla/$f"
done
- name: TLC — handle_protocol_MC (diamond + handle-protocol refinement)
working-directory: /tmp/tla
# `set -euo pipefail` ensures a failed `java` invocation (OOM,
# classpath error, etc.) propagates through `tee` instead of being
# masked by `tee`'s exit code. The explicit `grep` checks cover
# TLC's logical failures (invariant violations, "Error:" lines).
shell: bash -euo pipefail {0}
run: |
java -XX:+UseParallelGC -jar /tmp/tla2tools.jar \
-tool -workers auto -config handle_protocol_MC.cfg handle_protocol_MC.tla \
| tee handle.log
# TLC reports "Model checking completed" on success; "Error:" or
# "Invariant ... is violated" on failure.
grep -q "Model checking completed" handle.log
! grep -q "is violated" handle.log
! grep -qi "^error:" handle.log
- name: TLC — wave_protocol_rewire_MC (set_deps substrate)
working-directory: /tmp/tla
shell: bash -euo pipefail {0}
run: |
java -XX:+UseParallelGC -jar /tmp/tla2tools.jar \
-tool -workers auto -config wave_protocol_rewire_MC.cfg wave_protocol_rewire_MC.tla \
| tee rewire.log
grep -q "Model checking completed" rewire.log
! grep -q "is violated" rewire.log
! grep -qi "^error:" rewire.log
- name: TLC — wave_protocol_partitioned_MC (Phase I — D3 closure)
# Per-partition wave_owner protocol verification (Slice Y1+Y2,
# 2026-05-09). Encodes Q6 invariants from
# `archive/docs/SESSION-rust-port-d3-per-subgraph-parallelism.md`:
# cross-partition deadlock-freedom, ascending-`SubgraphId`
# acquisition ordering, `Subscription::Drop` cleanup cascade,
# union/split discipline, mid-wave reentrancy rejection.
working-directory: /tmp/tla
shell: bash -euo pipefail {0}
run: |
java -XX:+UseParallelGC -jar /tmp/tla2tools.jar \
-tool -workers auto -config wave_protocol_partitioned_MC.cfg wave_protocol_partitioned_MC.tla \
| tee partitioned.log
grep -q "Model checking completed" partitioned.log
! grep -q "is violated" partitioned.log
! grep -qi "^error:" partitioned.log