docs(plans): add verified evidence-architecture execution plan #265
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |