-
Notifications
You must be signed in to change notification settings - Fork 1
390 lines (328 loc) · 18.6 KB
/
Copy pathci.yml
File metadata and controls
390 lines (328 loc) · 18.6 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
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
verify:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: clippy, rustfmt
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Format check
run: cargo fmt --all -- --check
- name: Clippy
run: cargo clippy --workspace --all-targets -- -D warnings
- name: Test
run: cargo test --workspace
- name: Audit
run: cargo install cargo-audit --locked && cargo audit
# Dogfoods action.yml against this repo's own PRs -- proves the
# published-npm-package + composite-action path actually works end to
# end, not just that `cargo test` passes against the Rust source directly.
# continue-on-error: shadow mode while this is new (matches this repo's
# own rollout convention for new gates -- elicit_hub_confirm, verification,
# etc. all default off/observe-only at first).
#
# Audit 11.4 (2026-08-06): reviewed this job's run history before
# considering promotion. Found two real infra failure modes, not false
# positives from the guard's own risk analysis -- neither is "the gate
# doing its job":
# 1. `error: unrecognized subcommand 'guard'` -- ran against a commit
# from before this job's build-from-source+alias steps existed
# (older npm-install-only version of this job). Self-resolved by
# the current job definition; not expected to recur.
# 2. `fatal: origin/main...HEAD: no merge base` -- action.yml's
# shallow-fetch fix only fetched the base ref at depth=1, sharing no
# history with this checkout's own depth=1 HEAD. Fixed in the same
# commit as this comment (action.yml's "Resolve review scope" step
# now fetches depth=100 + falls back to `--unshallow`).
# Promotion criteria (remove `continue-on-error` once ALL of these hold):
# - 10 consecutive PRs where this job actually ran (not skipped) with
# zero infra-category failures (subcommand/merge-base/install/
# timeout) -- a real "aggregate_risk >= fail-on" block is NOT an
# infra failure and doesn't reset this count.
# - At least one of those 10 was a PR this job correctly blocked or
# would have blocked (fail-on triggered), confirmed by manual review
# to be a genuine high-risk change, not a false positive.
# - No open false-positive report against calm guard's risk model
# older than 7 days.
calm-guard-dogfood:
runs-on: ubuntu-latest
timeout-minutes: 15
continue-on-error: true
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
# Full history, not action.yml's own best-effort shallow-fetch
# fallback -- this job is specifically what proves the merge-base
# calculation is correct, so it shouldn't lean on the same
# fallback it's meant to be testing.
fetch-depth: 0
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
# Dogfooding must exercise THIS commit's own calm-cli, not whatever
# was last published to npm -- action.yml's default `version: latest`
# install can lag a real subcommand by days (found for real: `guard`
# landed in 9773d41, after the v0.5.0 npm tag, so the plain npm-install
# path 404'd on `error: unrecognized subcommand 'guard'` here until
# this fix). Building from source and aliasing it as `calm-mcp` on
# PATH, then passing skip-install: true, tests the actual wiring this
# PR/push is changing instead of a stale release.
- name: Build calm-cli from source (this commit, not the last npm release)
run: cargo build -p calm-cli
- name: Alias the freshly built binary as calm-mcp on PATH
run: |
mkdir -p "$HOME/.local/bin"
ln -sf "$GITHUB_WORKSPACE/target/debug/calm" "$HOME/.local/bin/calm-mcp"
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- uses: ./
with:
skip-install: true
# No `base`/`commits` input -- exercises action.yml's own
# pull_request/push auto-detection, not an explicit override.
stack-graphs-corpus:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Run Stack Graphs Regression Corpus
run: cargo test --test parity_test test_formal_edges -- --nocapture
# WS-1 task 4.8 crash-injection suite (docs/plans/2026-08-02-phase1-p0-
# execution-plan.md §6 milestone gate item 1: "kill -9 tại mọi giá trị
# TxState, ≥100 lần mỗi transition, 0 trường hợp disk thay đổi mà không
# có tx_events row tương ứng"). `#[ignore]`d in the normal test binary
# (300 real subprocess spawns is too slow for routine `cargo test
# --workspace`) -- this job is the dedicated place it actually runs on
# every push/PR to main, Linux, matching the milestone's own platform.
txn-crash-injection:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Crash-inject every reachable TxState transition (100x each, real SIGKILL)
run: cargo test -p calm-cli --test txn_crash_injection -- --ignored
embeddings:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: clippy
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
# The `embeddings` feature (model2vec-rs). The default model's weights
# are fetched from HuggingFace Hub and checksum-verified by
# crates/calm-core/build.rs::ensure_embedding_weights at compile time
# (2026-07-12 — used to be vendored via Git LFS, which exhausted the
# GitHub account's LFS bandwidth budget; see
# docs/superskills/specs/2026-07-12-edge-release-binary-distribution.md).
# No special checkout step needed here any more — build.rs handles it,
# and degrades to a placeholder (never fails the build) if the fetch
# doesn't succeed, same as before.
- name: Clippy (embeddings)
run: cargo clippy -p calm-core --all-targets --features embeddings -- -D warnings
- name: Test (embeddings)
run: cargo test -p calm-core --features embeddings
no-stack-graphs-formal:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: clippy
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
# D1 (2026-07-30 stack-graphs-demotion-lever): the ONLY dependency
# chain in the whole workspace that pins core `tree-sitter` to "^0.24"
# (verified via `cargo tree -i -p tree-sitter@0.24.7` -- real precedent
# for why this matters: Perl was dropped from the 25-language list
# (2026-07-10) for exactly this reason, see
# docs/superskills/plans/2026-07-10-25-language-expansion.md §1.4).
# `resolver::formal` compiles to a same-API stub without this feature
# (crates/calm-core/src/resolver/mod.rs) -- this job is the only CI
# coverage of that stub actually compiling and behaving correctly
# (`cargo check` alone can silently bit-rot a cfg branch nothing else
# ever builds). Keeps every OTHER default feature on
# (embeddings/tier0-5/scip-overlay) so this isolates JUST the
# stack-graphs-formal absence, not a combination of several features
# being off at once.
- name: Clippy (no stack-graphs-formal)
run: cargo clippy -p calm-core --all-targets --no-default-features --features embeddings,tier0-5,scip-overlay -- -D warnings
- name: Test (no stack-graphs-formal)
run: cargo test -p calm-core --no-default-features --features embeddings,tier0-5,scip-overlay
- name: Verify tree-sitter core is actually unpinned (not just a feature flag on paper)
run: |
set -e
LEAKED=$(cargo tree -p calm-core --no-default-features --features embeddings,tier0-5,scip-overlay 2>&1 | grep -ic "stack-graph" || true)
if [ "$LEAKED" -ne 0 ]; then
echo "::error::stack-graphs family still present in the dependency tree without stack-graphs-formal -- the feature gate is not actually cutting the dependency"
exit 1
fi
all-languages:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: clippy
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
# The 11 Phase B/C languages (kotlin/swift/scala/dart/lua/elixir/
# haskell/ocaml/zig/powershell/groovy) are deliberately NOT in the
# `tier0-5` default bundle (opt-in only until proven stable — see
# calm-core/Cargo.toml's own comment on `lang-kotlin`), which means
# `verify`'s plain `cargo test --workspace` above NEVER compiles or
# tests a single line of their code — `lang_feature_flags_match_*`
# (crates/calm-core/tests/lang_feature_parity.rs) only checks that the
# Cargo.toml *declarations* line up across the 3 crates, not that the
# actual grammar-gated code builds/passes. This job is the real
# coverage: same "all 11 new lang-* features enabled together"
# combination first run by hand at the end of the 2026-07-10/11
# 25-language-expansion session (786 passed then) — promoted to a
# permanent CI job instead of staying a one-off manual check. Bundled
# with `lsp-overlay` too: the D.0-D.4 LspProvider generalization
# (2026-07-11) is also gated behind a non-default feature with no
# other CI coverage.
- name: Clippy (all languages + lsp-overlay)
run: cargo clippy --workspace --all-targets --features tier0-5,lang-kotlin,lang-swift,lang-scala,lang-dart,lang-lua,lang-elixir,lang-haskell,lang-ocaml,lang-zig,lang-powershell,lang-groovy,scip-overlay,lsp-overlay -- -D warnings
- name: Test (all languages + lsp-overlay)
run: cargo test --workspace --features tier0-5,lang-kotlin,lang-swift,lang-scala,lang-dart,lang-lua,lang-elixir,lang-haskell,lang-ocaml,lang-zig,lang-powershell,lang-groovy,scip-overlay,lsp-overlay
# Real cross-SDK MCP interop check (2026-07-14 upgrade item, ported from
# modelcontextprotocol/rust-sdk's own crates/rmcp/tests/test_with_js.rs —
# verified against that real source before porting). Every OTHER test in
# this repo (the `verify`/`all-languages` jobs above, the bash hook
# suite) drives `calm serve` with rmcp's own client code — same SDK,
# same author, on both sides of the wire, so a protocol-shape bug rmcp's
# own client happens to tolerate would never surface. This job is the
# other half: the official TypeScript MCP SDK (@modelcontextprotocol/sdk,
# a genuinely independent implementation) drives a real `calm serve`
# child process over real stdio and validates `tools/list` +
# `tools/call` end-to-end, including strict structuredContent-vs-
# outputSchema validation the TS SDK enforces that rmcp's own test
# client does not — this is exactly what caught a real schema/impl
# mismatch bug (`weak_cross_reference_languages` and 13 sibling fields
# missing `#[serde(default)]`) the very first time this check ran.
js-client-interop:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Build calm binary
run: cargo build --bin calm
# ubuntu-latest already ships a recent Node.js + npm (same assumption
# release.yml's npm-publish job already makes) — no actions/setup-node
# needed.
- name: Install JS interop test dependencies
working-directory: tests/js_client_interop
run: npm ci
- name: Run cross-SDK MCP interop check
working-directory: tests/js_client_interop
run: node client.mjs "$GITHUB_WORKSPACE/target/debug/calm" "$GITHUB_WORKSPACE/crates/calm-core/tests/fixtures/rust_workspace"
# Feature-matrix coverage for the 2026-07-28 OTel/HTTP upgrade
# (docs/superskills/plans/2026-07-28-otel-http-dynamic-toolsets.md) --
# `verify`'s plain `cargo build/test --workspace` above never compiles a
# single line of otel.rs/http.rs, same gap `all-languages` closes for the
# opt-in language features.
#
# The single-otel-version guard below locks in the audit's A2 finding
# (opentelemetry Rust crates version-skew: a bare `cargo add` to latest
# resolves opentelemetry to two coexisting core versions, silently
# broken) so a future dependency bump can't reintroduce it unnoticed.
# Uses `cargo metadata | jq` on the exact package name, NOT a `cargo
# tree | grep` substring match: a bare `grep -c 'opentelemetry v0.3[^1]'`
# (no tree-connector anchor) false-positive-matches the *substring*
# inside `tracing-opentelemetry v0.32.1` -- verified live 2026-07-28,
# that naive pattern reports count=1 even in the correctly-pinned,
# healthy state, which would make this job permanently red. `jq`
# filtering on `.name == "opentelemetry"` operates on cargo's own
# structured package list, so it can't confuse a real second core with
# an unrelated crate whose name happens to contain the same substring.
otel-http-features:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: clippy
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Clippy (otel)
run: cargo clippy -p calm-cli --features otel -- -D warnings
- name: Test (otel)
run: cargo test -p calm-cli --features otel
- name: Guard against opentelemetry core version skew (locks in audit A2 finding)
run: |
VERSIONS=$(cargo metadata --format-version 1 --features otel \
| jq -r '.packages[] | select(.name == "opentelemetry") | .version' | sort -u)
COUNT=$(printf '%s\n' "$VERSIONS" | grep -c .)
echo "Resolved opentelemetry core version(s): $VERSIONS"
if [ "$COUNT" -ne 1 ]; then
echo "::error::Expected exactly ONE resolved 'opentelemetry' core version, found $COUNT: $VERSIONS"
exit 1
fi
if ! printf '%s\n' "$VERSIONS" | grep -q '^0\.32\.'; then
echo "::error::Resolved opentelemetry core is $VERSIONS, expected the pinned 0.32.x line -- update crates/calm-cli/src/otel.rs's version-note comment and Cargo.toml's pin comment together if this is an intentional bump"
exit 1
fi
- name: Clippy (http)
run: cargo clippy -p calm-server -p calm-cli --features http -- -D warnings
- name: Test (http)
run: cargo test -p calm-server -p calm-cli --features http
# Wires `calm fitness-check` (README: "CI gate, exits 1 on failure") into
# actual CI — previously documented as a CI gate but never invoked by any
# workflow, so a declared `[[boundaries]]`/threshold violation could sit
# "over gate" indefinitely without ever failing a build. Runs `calm index`
# first since fitness-check reads `import_edges`/`symbols` from this repo's
# own `.calm/index.db`, which a fresh checkout doesn't have yet.
fitness-check:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Build calm binary
run: cargo build --bin calm
- name: Index this repo
run: ./target/debug/calm index --project-root .
- name: Fitness check
# --config is NOT optional despite the CLI's "uses defaults if not
# provided" framing: the numeric thresholds do have real defaults,
# but [[boundaries]]/[config_drift] have no conceptual default
# (an empty rule set) — omitting --config silently skips checking
# this repo's own declared boundary rules entirely rather than
# erroring, verified locally (`no [[boundaries]] rules declared`).
run: ./target/debug/calm fitness-check --project-root . --config thresholds.toml
# WS-13 (docs/plans/2026-08-01-calm-adopt-from-vheatm-plan.md P3-2): fails
# the build if docs/status.generated.md (scripts/gen-status.sh) has drifted
# from the tool schemas / Cargo features it's generated from — the same
# class of doc drift ("pilot" README vs "complete" registry) VHEATM's own
# repo is currently carrying. No Rust build needed here, just jq + bash.
status-drift:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Check docs/status.generated.md is not stale
run: ./scripts/gen-status.sh --check
# 2026-08-03 (docs/plans/2026-08-03-product-truth-closure-plan.md):
# gen-status.sh --check above only protects status.generated.md
# itself -- README/AGENTS.md/llms.txt/marketplace.json/plugin.json/
# workflow.rs are hand-authored and drifted from it even after it
# was regenerated correctly for the same tool-count bump.
- name: Check hand-authored docs match the generated tool count
run: ./scripts/check-doc-truth.sh
- name: Check benchmark claims registry is structurally consistent
run: ./scripts/check-claims-registry.sh