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
name: CI
on:
push:
branches:
pull_request:
branches:
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
# Fail rustdoc on broken intra-doc links, private items linked from
# public APIs, etc. Surfaces breakage that `cargo check` doesn't catch.
RUSTDOCFLAGS: -D warnings
jobs:
check:
name: Check & Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
- name: cargo fmt
run: cargo fmt --all -- --check
- name: cargo clippy
run: cargo clippy --locked --all-targets -- -D warnings
- name: cargo check
run: cargo check --locked --all-targets
# Verify the binary builds without default features so the `semantic`
# feature gate (candle / usearch) cannot rot silently.
- name: cargo check --no-default-features
run: cargo check --locked --no-default-features --all-targets
# rustdoc with -D warnings (set via RUSTDOCFLAGS at the workflow level)
# catches broken intra-doc links and other doc-only regressions.
- name: cargo doc
run: cargo doc --locked --no-deps --all-features
# MSRV CI gate intentionally NOT enforced.
#
# ADR-008 documents MSRV at 1.82 as project intent. However, transitive
# deps in the Rust ecosystem (notably clap_lex 1.1.0+) ship Cargo.toml
# manifests using syntax newer than the 1.82 Cargo can parse, so a
# `runs-on: rust-toolchain@1.82.0` check fails on manifest parsing
# before reaching mati's own source. The MSRV declaration in Cargo.toml
# remains advisory documentation; enforcement would require either
# (a) pinning specific transitive versions (brittle) or (b) bumping
# MSRV and updating ADR-008.
test:
name: Test (${{ matrix.os }})
# Run the default-included test suite on both Linux and macOS.
# macOS coverage exists because mati ships as a Claude Code plugin and
# most users run it on macOS — APFS fsync semantics, BSD socket nuances,
# and the `logd` watchdog have caused real failures invisible to a
# Linux-only matrix.
#
# SKIPPED ON PULL REQUESTS: this job takes >15min on cold cache and
# blocks PR feedback. It still runs on every push to main so coverage
# is preserved after merge. To re-enable for PRs, remove the `if:` line.
if: github.event_name == 'push'
strategy:
fail-fast: false
matrix:
os:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
# Use cargo-nextest for the default test pass. Nextest runs each
# test in its own subprocess (vs cargo test's shared-binary model),
# which prevents tokio runtime / SurrealKV / OnceLock state from
# accumulating across hundreds of tests in one process. The matching
# local profile is the `default` profile in `.config/nextest.toml`.
- uses: taiki-e/install-action@nextest
- name: cargo nextest run
run: cargo nextest run --locked --all-targets --profile ci
# Nextest does not run doc tests (rustdoc API limitations). The
# `--doc` pass remains on vanilla `cargo test`. This stays
# single-binary but doc tests are short and CPU-light, so it's fine.
- name: cargo test --doc
run: cargo test --locked --doc
ignored-tests:
# The `#[ignore]`d integration tests cover subprocess lifecycle,
# crash recovery, concurrent socket dispatch, and the panic-hook
# pre-opened-fd path. They're slow and depend on a writable `~/`,
# so they don't run by default — but they do gate merges.
#
# SKIPPED ON PULL REQUESTS: subprocess tests are >15min on cold cache.
# Runs on push to main only. To re-enable for PRs, remove the `if:` line.
name: Ignored integration tests (${{ matrix.os }})
if: github.event_name == 'push'
strategy:
fail-fast: false
matrix:
os:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@nextest
- name: cargo nextest run -- --ignored
# Ignored subprocess tests race each other on `~/.mati/<slug>/`
# lifecycle logs and per-project sockets, so they need serial
# execution. `--test-threads=1` and nextest's per-subprocess
# isolation together give the strongest guarantee.
# `stress_700000_edges_linux_kernel_scale` runs here too and is
# fine at threads=1.
run: cargo nextest run --locked --all-targets --profile ci --run-ignored only --test-threads 1
benches:
# Benches are not run for wall-time (criterion regressions need a
# baseline + stable hardware that GH Actions does not provide). We
# only gate that they *compile*, so an SLO-relevant bench can't bit-rot
# silently between feature changes. Real bench runs happen locally
# against ADR-010 SLOs.
#
# SKIPPED ON PULL REQUESTS: criterion's release build is >10min on
# cold cache. Runs on push to main only. To re-enable for PRs, remove
# the `if:` line.
name: Benches compile
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: cargo bench --no-run
run: cargo bench --locked --no-run
feature-matrix:
name: Feature matrix (cargo hack)
runs-on: ubuntu-latest
# `cargo check --all-targets` exercises one feature combination at a time.
# `cargo hack --feature-powerset` exercises every combination, which
# catches refactors inside `#[cfg(feature = "semantic")]` blocks that
# compile fine under `--all-features` but break under default features.
# mati-cloud may enable different combinations than the OSS binary, so
# this catches integration breaks before the downstream consumer sees
# them.
#
# Currently mati has one optional feature (`semantic`), so the powerset
# is two combinations. Cheap and informative.
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install cargo-hack
uses: taiki-e/install-action@v2
with:
tool: cargo-hack
- name: cargo hack check --feature-powerset
# NOTE: `--no-dev-deps` was tried here but conflicts with `--locked`
# — cargo-hack rewrites Cargo.toml in-place, which causes cargo
# to demand a Cargo.lock regeneration that `--locked` forbids.
# The current powerset is just two combos (`[]` and `[semantic]`),
# so the overhead of including dev-deps is negligible.
run: cargo hack check --locked --feature-powerset
semver:
name: Public API semver check
runs-on: ubuntu-latest
# DISABLED pre-publish: cargo-semver-checks needs a meaningful baseline
# to compare against. Pre-1.0 the project is allowed to make breaking
# changes within 0.x.y; pre-publish there is no crates.io baseline and
# no git tag to compare to. Per-PR comparison against `origin/main`
# produces noise (PRs that legitimately break pre-1.0 API would fail)
# without a corresponding consumer that pins to versions.
#
# Re-enable when:
# - The crate is published to crates.io (set `version-tag-prefix: v`
# and remove `baseline-rev`), OR
# - A `v0.1.0` git tag exists (change `baseline-rev: origin/main` to
# `baseline-rev: v0.1.0`).
#
# Remove the `if: false` below to re-enable.
if: false
# `mati_core` is consumed by the enterprise binary (mati-cloud) as a
# Cargo crate. An accidental breaking change to the public API surface
# without a major-version bump forces downstream rework. This job
# compares the PR's `mati_core` API against the `main` branch and fails
# if it finds a violation.
steps:
- uses: actions/checkout@v4
with:
# cargo-semver-checks needs the baseline ref's history to compare
# against, not just the current commit.
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: cargo semver-checks (vs main)
uses: obi1kenobi/cargo-semver-checks-action@v2
with:
# Cargo *package* name (not the [lib] name). The lib `mati_core`
# lives inside the `mati` package; the action looks up packages
# by their `[package].name` field.
package: mati
# `origin/main` rather than `main`: on PR runs GitHub Actions
# checks out the PR head, so the bare name `main` is not a
# local ref. `fetch-depth: 0` populates `origin/main` but does
# not create a local `main` branch, so `git rev-parse main^{tree}`
# would fail. The remote-tracking ref resolves cleanly.
baseline-rev: origin/main
audit:
name: Security audit
runs-on: ubuntu-latest
# Fail fast on RUSTSEC vulnerabilities (default cargo-audit behavior:
# exit non-zero on Vulnerability entries, warnings allowed). Five
# accepted unmaintained/unsound advisories are documented in
# DECISIONS.md; new entries should be triaged before silencing here.
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Install cargo-audit
uses: taiki-e/install-action@v2
with:
tool: cargo-audit
- name: cargo audit
run: cargo audit
supply-chain:
name: Supply chain (cargo-deny)
runs-on: ubuntu-latest
# Broader supply-chain gate than `cargo audit` alone. Runs three of
# cargo-deny's four checks against `deny.toml`:
#
# bans — duplicate versions + wildcard version specifiers
# advisories — same RUSTSEC vulnerability stream as cargo-audit,
# plus optional yanked-crate detection (subsumes audit
# job; kept separate for ADR-007 traceability)
# sources — only crates.io, no git deps, no unknown registries
#
# The fourth check (licenses) is INTENTIONALLY SKIPPED. Customer
# license-key validation belongs in mati-cloud per CLAUDE.md "What
# this repo must NEVER include". Dependency license scanning for the
# commercial consumer is mati-cloud's responsibility on its final
# binary, not ours upstream.
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Install cargo-deny
uses: taiki-e/install-action@v2
with:
tool: cargo-deny
- name: cargo deny check (bans + advisories + sources)
run: cargo deny check bans advisories sources