项目文件夹

文件
wehub-resource-sync 26382a7ac6
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:30 +08:00

681 行
27 KiB
YAML

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
# Cancel a still-running CI for the same ref when a new push supersedes it —
# avoids burning runner-hours on stale commits during active PR iteration.
# Never cancel on main: a run there should always finish (e.g. for the
# scorecard/coverage artifacts it produces), even if another push lands.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: -Dwarnings
# CI must be hermetic: never let tests download the embedding model
# (~90 MB) in the background. Without this, the #551 auto-activation can
# load the engine mid-suite and slow tarpaulin past its timeout.
LEAN_CTX_EMBEDDINGS_AUTO_DOWNLOAD: "0"
jobs:
test:
name: Test
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
# --test-threads=1 (env-race legacy, v3.3.5) serializes ~70 binaries that
# now include heavy property/fuzz/benchmark suites (#291, #493, #551) —
# well beyond 90 min on hosted runners. Parallelization is tracked
# separately; until then the gate gets the time it actually needs.
#
# Tried switching to cargo-nextest (rust/.config/nextest.toml already
# exists and documents the same env-race for 3 known binaries via a
# `serial-state` test-group). Reverted: nextest's default parallelism
# (test-threads = -4) surfaced several more tests with hidden wall-clock
# timing assumptions (e.g. core::cache::tests::hebbian_eviction_bonus_is_wired
# depends on two calls landing in the same real-time 500ms window) that a
# `max-threads=1` test-group does NOT fix — that only serializes tests
# *within* the group against each other, it doesn't protect them from
# being scheduling-delayed by the many *other* tests still running in
# parallel elsewhere on the same runner. Revisit once those tests are
# made robust to scheduling jitter (or the burst window is made
# injectable for tests) rather than papering over it with test-groups.
timeout-minutes: 180
env:
# ~60 integration-test binaries each statically link the full lib
# (tree-sitter ×18, rten, aws-lc, resvg, …). With default full debug
# info that is 25-40 GB and the ubuntu runner dies with ENOSPC / the
# linker with SIGBUS. Line tables keep file:line in panic backtraces
# at a fraction of the size.
CARGO_PROFILE_DEV_DEBUG: line-tables-only
CARGO_PROFILE_TEST_DEBUG: line-tables-only
# property_compression alone took 8012s serialized on ubuntu (87% of
# the job) with proptest's default 256 cases — and pushed Windows past
# the 180-min timeout. 64 cases keep the properties exercised on every
# push at a quarter of the cost; local runs keep the full default.
PROPTEST_CASES: 64
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- name: Ensure toolchain is active
shell: bash
run: |
CARGO_HOME="${CARGO_HOME:-$HOME/.cargo}"
export PATH="$CARGO_HOME/bin:$PATH"
rustup default stable
cargo --version
echo "$CARGO_HOME/bin" >> $GITHUB_PATH
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
workspaces: rust -> target
# ---- Windows: MSYS2 + GNU target + jemalloc -------------------------
# The default MSVC toolchain can't build jemalloc (autotools mismatch).
# We switch to the GNU target with MSYS2/MinGW and pre-build jemalloc.
# See .github/actions/windows-jemalloc for the gory details.
- name: Setup MSYS2 and MinGW
if: runner.os == 'Windows'
uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # v2
with:
msystem: MINGW64
update: true
install: base-devel mingw-w64-x86_64-toolchain
path-type: inherit
- name: Install Rust GNU target
if: runner.os == 'Windows'
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
targets: x86_64-pc-windows-gnu
- name: Build jemalloc + dummy liballoc.a (Windows only)
if: runner.os == 'Windows'
id: jemalloc
uses: ./.github/actions/windows-jemalloc
- name: Free disk space
if: runner.os == 'Linux'
shell: bash
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/opt/hostedtoolcache/CodeQL /usr/local/.ghcup /usr/share/swift \
/usr/local/share/powershell /usr/local/share/chromium \
/usr/local/share/boost /usr/lib/jvm /usr/local/julia* || true
sudo docker system prune -af --volumes >/dev/null 2>&1 || true
df -h /
- name: Run tests
working-directory: rust
shell: bash
run: |
if [[ "${{ runner.os }}" == "macOS" ]]; then
CARGO="${CARGO_HOME}/bin/cargo"
else
CARGO="cargo"
fi
if [[ "${{ runner.os }}" == "Windows" ]]; then
JEMALLOC_OVERRIDE="${{ steps.jemalloc.outputs.jemalloc-override }}" \
CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUSTFLAGS="-L ${{ steps.jemalloc.outputs.dummy-dir }}" \
"$CARGO" test --target x86_64-pc-windows-gnu --all-features -- --test-threads=1
else
"$CARGO" test --all-features -- --test-threads=1
fi
# #581: lock in the parallel BM25 (incremental) rebuild win against silent
# regression. Timing is only meaningful on a quiet, single-threaded runner,
# so the gate is env-opt-in (no-op in the matrix above) and runs once here.
- name: BM25 build-time regression gate (#581)
if: runner.os == 'Linux'
working-directory: rust
shell: bash
env:
LEAN_CTX_PERF_GATE: "1"
run: cargo test --all-features --lib -- --test-threads=1 parallel_incremental_rebuild_perf_gate --nocapture
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: clippy
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
workspaces: rust -> target
- name: Run clippy
working-directory: rust
run: cargo clippy --all-features -- -D warnings
# Maintainability gate (#660): no Rust file grows past 1500 LOC
# (legacy files are frozen at 2000 via the script's allowlist).
- name: LOC gate (file size budget)
run: ./scripts/loc-gate.sh
# Guards the no-ORT build (#586). The `embeddings`/`neural` features pull the
# `ort` crate, whose `load-dynamic` dylib resolver has no fallback arm for
# non-tier-1 targets (FreeBSD, etc.), so community ports build with those
# features off. This job catches any code that references `ort`/embeddings
# without a feature gate. Dead code in the reduced build is expected, so
# warnings are not denied here (override the workflow-wide -Dwarnings).
build-minimal:
name: Build (no embeddings / no ORT)
runs-on: ubuntu-latest
env:
RUSTFLAGS: ""
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
workspaces: rust -> target
- name: Check build without ORT-backed features
working-directory: rust
run: cargo check --no-default-features --features "tree-sitter,http-server,team-server,secure-update,jemalloc"
# The no-tree-sitter combo is the slim-binary candidate (#663) and had
# rotted silently because only the no-ORT combo was checked.
- name: Check build without tree-sitter
working-directory: rust
run: cargo check --no-default-features --features "embeddings,http-server,team-server,secure-update,jemalloc"
fmt:
name: Format
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: rustfmt
- name: Check formatting
working-directory: rust
run: cargo fmt --check
cookbook:
name: Cookbook (Node)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: cookbook/package-lock.json
- name: Install
working-directory: cookbook
run: npm ci
- name: Lint
working-directory: cookbook
run: npm run lint
- name: Typecheck
working-directory: cookbook
run: npm run typecheck
- name: Test
working-directory: cookbook
run: npm test
- name: Build
working-directory: cookbook
run: npm run build
pi-extension:
name: Pi Extension (Node)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
# Fail fast if pi-lean-ctx / lean-ctx-bin drifted from the engine version,
# so the Pi extension can never quietly fall behind (npm skips the publish
# of a stale version). Runs on every push/PR — not just at release.
- name: Check npm package ↔ engine version coupling
run: python3 scripts/check-package-versions.py
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
cache-dependency-path: packages/pi-lean-ctx/package-lock.json
- name: Install
working-directory: packages/pi-lean-ctx
run: npm ci
- name: Typecheck
working-directory: packages/pi-lean-ctx
run: npm run typecheck
- name: Test
working-directory: packages/pi-lean-ctx
run: npm test
rust-sdk:
name: Rust SDK (lean-ctx-client)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: clippy, rustfmt
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
workspaces: clients/rust/lean-ctx-client -> target
- name: Format
working-directory: clients/rust/lean-ctx-client
run: cargo fmt --check
- name: Clippy
working-directory: clients/rust/lean-ctx-client
run: cargo clippy --all-targets -- -D warnings
- name: Test
working-directory: clients/rust/lean-ctx-client
run: cargo test
- name: Docs
working-directory: clients/rust/lean-ctx-client
env:
RUSTDOCFLAGS: -D warnings
run: cargo doc --no-deps
embed-sdk:
# Track A — the in-process embedding SDK (rust/crates/lean-ctx-sdk). It is a
# workspace member but excluded from `default-members`, so the engine's own
# test/clippy/doc jobs never see it; this job is its dedicated gate
# (pedantic clippy, doctests, the engine-integration tests, example build).
name: Embed SDK (lean-ctx-sdk)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: clippy, rustfmt
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
workspaces: rust -> target
- name: Format
working-directory: rust
run: cargo fmt -p lean-ctx-sdk --check
- name: Clippy (pedantic, 0 warnings)
working-directory: rust
run: cargo clippy -p lean-ctx-sdk --all-targets -- -D warnings
- name: Test (doctests + engine integration)
working-directory: rust
run: cargo test -p lean-ctx-sdk
- name: Example builds
working-directory: rust
run: cargo build -p lean-ctx-sdk --example embed
- name: Docs
working-directory: rust
env:
RUSTDOCFLAGS: -D warnings
run: cargo doc -p lean-ctx-sdk --no-deps
python-sdk:
name: Python SDK (leanctx)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: actions/setup-python@v5 # v5
with:
python-version: "3.11"
- name: Install
working-directory: clients/python
run: pip install -e ".[dev]"
- name: Test
working-directory: clients/python
run: python -m pytest -q
hermes-plugin:
# The Hermes context-engine plugin (integrations/hermes-lean-ctx) replaces
# Hermes' built-in ContextCompressor with lean-ctx. Gate: pytest (ABC
# conformance + tool_call/tool_result invariant + daemon-down graceful) and
# a benchmark smoke that proves the harness runs offline (local fallback).
name: Hermes Plugin (Python)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: actions/setup-python@v5 # v5
with:
python-version: "3.11"
- name: Install test deps
# Runtime dep (leanctx SDK) is wired onto sys.path by the plugin
# conftest from clients/python — no install needed. tiktoken makes the
# token count match the host model exactly; without it the plugin uses
# its char-based fallback (also tested).
run: pip install pytest tiktoken
- name: Run plugin tests
working-directory: integrations/hermes-lean-ctx
run: python -m pytest tests/ -q
- name: Benchmark smoke (offline, local fallback)
working-directory: integrations/hermes-lean-ctx
# Discard port → daemon unreachable → exercises deterministic local
# compaction end-to-end. Competitors are auto-skipped when absent.
run: python benchmarks/run.py --turns 40 --needles 6 --context-length 2000 --base-url http://127.0.0.1:9 --no-write
sdk-conformance:
# GL #395: every first-party SDK must prove the full /v1 contract against
# a real engine build. Red when an SDK misses a route, mistypes a shape,
# or the engine drifts from the frozen surface.
name: SDK Conformance Matrix
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
workspaces: |
rust -> target
clients/rust/lean-ctx-client -> target
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: cookbook/package-lock.json
- uses: actions/setup-python@v5 # v5
with:
python-version: "3.11"
- name: Install Python SDK
working-directory: clients/python
# langchain-core gives the adapter smoke a real framework round trip;
# LlamaIndex/CrewAI skip cleanly (heavy dep trees, covered by the
# framework-agnostic OpenAI adapter path).
run: pip install -e ".[dev]" langchain-core
- name: Run conformance kit (3 SDKs vs real server)
run: ./scripts/sdk-conformance.sh
- name: Upload conformance matrix
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: sdk-conformance-matrix
path: docs/reference/sdk-conformance-matrix.md
if-no-files-found: ignore
coverage:
name: Coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
# tarpaulin's LLVM engine (below) needs llvm-profdata/llvm-cov from
# the rustup component — without it the engine silently falls back.
components: llvm-tools-preview
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
workspaces: rust -> target
- name: Free disk space
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL || true
df -h /
- uses: taiki-e/install-action@74e87cbfa15a59692b158178d8905a61bf6fca95 # v2
with:
tool: cargo-tarpaulin
- name: Generate coverage
working-directory: rust
env:
CARGO_BUILD_JOBS: "2"
# --engine llvm uses LLVM source-based coverage (instrument-coverage +
# llvm-profdata) instead of tarpaulin's default ptrace engine. ptrace
# is non-deterministically fragile on hosted runners: it corrupts the
# tracee's registers under load, surfacing as a bogus
# "memory allocation of 1407…bytes failed" abort followed by
# "ECHILD: No child processes" — a flake unrelated to the code (the
# Test matrix on the same SHA stays green). The LLVM engine never
# ptraces, so the whole class of flake disappears.
run: |
cargo tarpaulin --engine llvm --out xml --skip-clean --all-features --lib --timeout 180 \
--exclude-files 'src/cli/*' --exclude-files 'src/main.rs' \
-- --test-threads=1
pkill -f 'target.*lean-ctx' 2>/dev/null || true
- name: Upload to Codecov
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
with:
fail_ci_if_error: false
deny:
name: cargo-deny
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: EmbarkStudios/cargo-deny-action@5bb39ff5d5a0e94dc9e2dc94eced0c6129743a57 # v2
with:
manifest-path: rust/Cargo.toml
adversarial:
name: Adversarial Safety
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
workspaces: rust -> target
- name: Run adversarial compression tests
working-directory: rust
run: cargo test --test adversarial_compression -- --nocapture
bench:
name: Benchmarks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
workspaces: rust -> target
- name: Compile benchmarks
working-directory: rust
run: cargo bench --no-run
- name: Generate reproducible scorecard
working-directory: rust
run: cargo run --quiet -- benchmark scorecard --json --output ../scorecard.json
- name: Upload scorecard artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: scorecard
path: scorecard.json
quality-gate:
name: Output-Quality Gate (eval A/B)
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
workspaces: rust -> target
- name: Build lean-ctx
working-directory: rust
run: cargo build --quiet
# Self-footprint gate (#578/#964): the fixed per-session cost lean-ctx
# itself injects (advertised tool schemas + MCP instructions + wakeup)
# must stay under budget. Runs in a scratch HOME + empty cwd so only OUR
# footprint is measured — no repo rules files, no developer state.
# Baseline after the diet: ~2147 tok (schemas 1685, instructions 462).
- name: Self-footprint gate (doctor overhead)
shell: bash
env:
LEAN_CTX_CONTEXT_BUDGET_TOKENS: "2600"
run: |
set -euo pipefail
BIN="$GITHUB_WORKSPACE/rust/target/debug/lean-ctx"
SCRATCH=$(mktemp -d)
mkdir -p "$SCRATCH/home" "$SCRATCH/data" "$SCRATCH/work"
cd "$SCRATCH/work"
HOME="$SCRATCH/home" LEAN_CTX_DATA_DIR="$SCRATCH/data" "$BIN" doctor overhead --gate
# Deterministic with/without output-quality proof. Three modes, in priority order:
# 1. A committed recording (rust/eval/recording.json) → byte-stable replay, no secrets,
# and the gate BLOCKS on a regression.
# 2. Otherwise, if LEAN_CTX_EVAL_* secrets are set → capture from the live model + gate.
# 3. Otherwise → skipped (the harness itself is still covered by the test job).
# Capture a recording once with: lean-ctx eval ab --suite … --record rust/eval/recording.json
- name: Run deterministic A/B output-quality gate
working-directory: rust
shell: bash
env:
LEAN_CTX_EVAL_MODEL_URL: ${{ secrets.LEAN_CTX_EVAL_MODEL_URL }}
LEAN_CTX_EVAL_MODEL: ${{ secrets.LEAN_CTX_EVAL_MODEL }}
LEAN_CTX_EVAL_MODEL_KEY: ${{ secrets.LEAN_CTX_EVAL_MODEL_KEY }}
run: |
set -euo pipefail
BIN=./target/debug/lean-ctx
REC=eval/recording.json
"$BIN" eval init eval-suite
if [ -f "$REC" ]; then
echo "Replaying committed recording (deterministic, no secrets)…"
"$BIN" eval ab --suite eval-suite/suite.ndjson --replay "$REC" --out ab-report.json --gate
elif [ -n "${LEAN_CTX_EVAL_MODEL_URL:-}" ]; then
echo "No committed recording; capturing from the configured live model…"
mkdir -p eval
"$BIN" eval ab --suite eval-suite/suite.ndjson --record "$REC" --out ab-report.json --gate
else
echo "::notice::Output-quality gate skipped — commit rust/eval/recording.json or set LEAN_CTX_EVAL_* secrets."
fi
- name: Verify artifact (signature + determinism digest)
working-directory: rust
shell: bash
run: |
if [ -f ab-report.json ]; then ./target/debug/lean-ctx eval verify ab-report.json; fi
- name: Upload signed A/B report
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: eval-ab-report
path: rust/ab-report.json
if-no-files-found: ignore
# Off-vs-on answer-quality testbench across pinned repos (#611). The committed
# local-fixture subset replays with a recorded model → byte-stable, no secrets,
# and BLOCKS on any per-repo regression. Refresh with:
# lean-ctx eval testbench --lock eval/testbench/testbench.lock.json --record eval/testbench/recording.json
- name: Run deterministic testbench gate (off vs on)
working-directory: rust
shell: bash
run: |
set -euo pipefail
BIN=./target/debug/lean-ctx
LOCK=eval/testbench/testbench.lock.json
REC=eval/testbench/recording.json
if [ -f "$REC" ]; then
echo "Replaying committed testbench subset (deterministic, no secrets)…"
"$BIN" eval testbench --lock "$LOCK" --replay "$REC" --out testbench-out --gate
else
echo "::notice::Testbench gate skipped — commit rust/eval/testbench/recording.json."
fi
- name: Upload testbench FINDINGS
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: testbench-findings
path: |
rust/testbench-out/FINDINGS.md
rust/testbench-out/regressions.json
if-no-files-found: ignore
doc:
name: Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
workspaces: rust -> target
- name: Check docs compile
working-directory: rust
env:
RUSTDOCFLAGS: -D warnings
run: cargo doc --no-deps --all-features
- name: Check generated reference docs are current
working-directory: rust
run: cargo run --example gen_docs --features dev-tools -- --check
- name: Check bundled registry snapshots are canonical
working-directory: rust
run: cargo run --example gen_registry --features dev-tools -- --check
- name: Check committed testbench recording is current
working-directory: rust
run: cargo run --example gen_testbench_recording --features dev-tools -- --check
# Single aggregating gate. Point branch protection at THIS one job ("CI Green")
# instead of every matrix leg — it stays correct when jobs are added/removed and
# cannot be bypassed by a silently-missing required check. Runs always() so it can
# inspect results even when a dependency failed; fails only on failure/cancelled
# (a legitimately skipped job — e.g. the optional quality-gate — does not block).
ci-green:
name: CI Green
if: always()
needs:
- test
- clippy
- build-minimal
- fmt
- cookbook
- pi-extension
- rust-sdk
- embed-sdk
- python-sdk
- hermes-plugin
- sdk-conformance
- coverage
- deny
- adversarial
- bench
- quality-gate
- doc
runs-on: ubuntu-latest
steps:
- name: Verify no required job failed
shell: bash
env:
NEEDS_JSON: ${{ toJSON(needs) }}
run: |
echo "$NEEDS_JSON"
python3 - <<'PY'
import json, os, sys
needs = json.loads(os.environ["NEEDS_JSON"])
blocked = {k: v["result"] for k, v in needs.items()
if v["result"] in ("failure", "cancelled")}
if blocked:
print("Required CI jobs did not pass:", blocked)
sys.exit(1)
print("All required CI jobs passed (success or skipped).")
PY
# Security audit runs in security-check.yml workflow