Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 161 additions & 92 deletions .agents/skills/switchyard-docs/SKILL.md

Large diffs are not rendered by default.

26 changes: 12 additions & 14 deletions .agents/skills/switchyard-testing-ci/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,32 @@ use `cargo test --workspace` before calling a broad Rust MR ready.

| Situation | Command |
|---|---|
| Pick gates from the current diff | `python .agents/skills/switchyard-testing-ci/scripts/select_validation.py --changed` |
| Map the current diff | `git status -sb && git diff --stat && git diff --name-only` |
| Pre-PR hermetic gate (default) | `uv run ruff check . && uv run mypy switchyard && env -u OPENROUTER_API_KEY -u NVIDIA_API_KEY -u OPENAI_API_KEY -u ANTHROPIC_API_KEY uv run pytest tests/ -v -m "not integration"` |
| Mirror CI pytest with no live creds | `env -u OPENROUTER_API_KEY -u NVIDIA_API_KEY -u OPENAI_API_KEY -u ANTHROPIC_API_KEY uv run pytest tests/ -v -m "not integration"` |
| Rust component crate change | `cargo fmt --all --check && cargo clippy --workspace --all-targets -- -D warnings && cargo test -p switchyard-components` |
| Rust server crate change | `cargo fmt --all --check && cargo clippy --workspace --all-targets -- -D warnings && cargo test -p switchyard-server` |
| Broad Rust crate change | `cargo fmt --all --check && cargo clippy --workspace --all-targets -- -D warnings && cargo test --workspace` |
| Docs/Fern workflow change | `make -C docs check && uv run pytest tests/test_fern_docs.py -v -o addopts=` |
| Select focused validation from uncommitted paths | `python scripts/select_validation.py --changed` |
| Select validation for committed branch work | `python scripts/select_validation.py --base origin/main` |
| Any GitHub Actions workflow change | Run the selector, then `actionlint && zizmor --pedantic .github/workflows`; review `scripts/ci/README.md` |
| Slim-install regression guard | see [Slim-install smoke gate](#slim-install-smoke-gate) |
| Live e2e (only on explicit user request) | `NVIDIA_API_KEY=… uv run pytest tests/e2e/ -v -m integration -o addopts= --maxfail=10` |
| Skill/docs change only | YAML frontmatter check + `git diff --check` (see [Skill/docs-only gate](#skilldocs-only-gate)) |

## Dynamic Selection First
## Diff-Based Selection First

From the repo root, inspect the diff and let the selector propose focused gates:
From the repo root, inspect the diff and map each changed area to the focused gates below:

```bash
cd "$(git rev-parse --show-toplevel)"
git status -sb
git diff --stat
python .agents/skills/switchyard-testing-ci/scripts/select_validation.py --changed
```

For a not-yet-edited area, pass likely owners explicitly:

```bash
python .agents/skills/switchyard-testing-ci/scripts/select_validation.py \
--path switchyard/lib/translation/request_engine.py \
--path tests/test_request_translation_engine.py
```

Use the output as the starting plan, then add any tests revealed by code search or by the failure.
Use the current diff as the starting plan, then add any tests revealed by code search or by the
failure map in this skill.

## CI Gates and Local Equivalence

Expand All @@ -62,6 +58,8 @@ The hard GitHub Actions gates live in `.github/workflows/ci.yml`:
- `uv run ruff check .`
- SPDX header check for every Python file found by CI, including `.agents/skills/**/scripts/*.py`
- `uv run pytest tests/ -v -m "not integration"` on Python 3.12 through 3.14
- reusable Fern validation (`fern check`) called from `.github/workflows/ci.yml` and included in
the required `CI Success` aggregate
- Rust workspace gate: `cargo fmt --all --check`, `cargo clippy --workspace --all-targets -- -D warnings`,
and `cargo test --workspace`
- slim-install smoke: isolated `uv run --with` default install/import checks, heavy-package
Expand Down Expand Up @@ -302,7 +300,7 @@ uv run pytest tests/test_cli_stale_names.py tests/test_no_stale_module_paths.py
| Running `uv run pytest tests/ -v` with `OPENROUTER_API_KEY`/`NVIDIA_API_KEY`/`OPENAI_API_KEY`/`ANTHROPIC_API_KEY` set in your shell | Tests that mock providers can accidentally hit live endpoints. Default to `-m "not integration"`, or strip credentials with `env -u`. |
| Treating mypy as optional because CI marks it `continue-on-error` | Mypy still catches real bugs in `switchyard/` typed code. Run it for any change to profiles, route bundles, backends, request/response models, or translation. |
| Skipping the slim-install smoke gate after a dependency or top-level import change | This is the *actual* hard CI gate that catches `torch`/`transformers` accidentally landing in the default install. |
| Claiming validation from `scripts/select_validation.py` without rerunning it after committing changes | The script diffs against `HEAD` plus untracked files; if your changes are already committed, `--changed` returns "no diff". Pass `--path` explicitly, or diff against the branch base. |
| Claiming validation from `scripts/select_validation.py --changed` after committing changes | `--changed` covers staged, unstaged, and untracked paths. Use `--base origin/main` to include committed branch changes, or pass `--path` explicitly. |
| Adding `# noqa` or per-line ignores to make ruff green | Ruff is a hard CI gate. Fix the code or, if the rule is wrong here, lift the ignore to the file or project level with a one-line justification. |
| Editing a generated artifact (e.g., `docs/.venv-docs/...`) because ruff complained about it | Delete the artifact instead. CI does not have it; you should not either. |

Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ jobs:
- name: mypy
run: uv run mypy switchyard

# Keep Fern validation inside the required CI Success aggregate so a docs
# configuration failure cannot be merged as an optional check.
fern-docs:
name: Fern docs
uses: ./.github/workflows/fern-docs-ci.yml

# Unit tests on supported Python versions. Integration/e2e tests are
# intentionally deselected here because they may need Docker, live provider
# credentials, or network egress.
Expand Down Expand Up @@ -197,7 +203,7 @@ jobs:
ci-success:
name: CI Success
if: always()
needs: [lint, spdx-headers, rust, typecheck, test, slim-install-smoke]
needs: [lint, spdx-headers, rust, typecheck, fern-docs, test, slim-install-smoke]
runs-on: ubuntu-latest
steps:
- name: Verify all jobs succeeded
Expand Down
100 changes: 0 additions & 100 deletions .github/workflows/docs.yml

This file was deleted.

53 changes: 53 additions & 0 deletions .github/workflows/fern-docs-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Reusable Fern validation gate called by the repository CI workflow.

name: Fern docs (check)

on:
workflow_call:

permissions:
contents: read

jobs:
check:
name: Check Fern docs
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24"
package-manager-cache: false

- name: Install Fern CLI
run: | # zizmor: ignore[adhoc-packages] Fern is exact-version pinned in fern.config.json.
FERN_VERSION="$(jq -r '.version' docs/fern/fern.config.json)"
if ! [[ "$FERN_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.]+)?$ ]]; then
echo "::error::Refusing to install unexpected Fern CLI version: $FERN_VERSION"
exit 1
fi
npm install -g "fern-api@${FERN_VERSION}"

- name: Validate Fern configuration
working-directory: ./docs/fern
run: fern check
67 changes: 67 additions & 0 deletions .github/workflows/fern-docs-preview-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Workflow 1 of 2 for Fern doc previews.
#
# Collects docs sources and changed-file metadata from same-repository PR
# branches. No secrets are used here. Fork PRs receive the required Fern check
# but do not enter the hosted-preview path. The companion workflow builds the
# preview and posts the PR comment.

name: "Preview Fern Docs: Build"

on:
pull_request:
paths:
- "docs/**"
- ".github/workflows/fern-docs-preview-build.yml"

permissions:
contents: read

concurrency:
group: fern-docs-preview-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
collect:
name: Collect preview sources
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
runs-on: ubuntu-latest
steps:
- name: Checkout PR
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
Comment on lines +44 to +47

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Set persist-credentials: false on this untrusted-PR checkout.

This step checks out the possibly-malicious PR branch but never needs to push; leaving the default persist-credentials: true keeps a live token in the workspace for no benefit. Same pattern appears in publish-fern-docs.yml's checkout step (see consolidated comment).

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 37-40: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/fern-docs-preview-build.yml around lines 37 - 40, Update
the “Checkout PR” actions/checkout configuration in fern-docs-preview-build.yml
and the corresponding checkout step in publish-fern-docs.yml to set
persist-credentials to false, while preserving the existing fetch-depth setting.

Source: Linters/SAST tools

persist-credentials: false

- name: Save changed MDX paths
env:
BASE_REF: ${{ github.base_ref }}
run: |
mkdir -p .preview-metadata
git diff --name-only "origin/${BASE_REF}...HEAD" -- '*.mdx' > .preview-metadata/changed_mdx_files 2>/dev/null || true

# The nightly navigation reaches from docs/fern/ into docs/**/*.mdx,
# so the artifact must preserve the complete docs tree.
- name: Upload docs sources and metadata
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fern-preview
path: |
docs/
.preview-metadata/
include-hidden-files: true
retention-days: 1
Loading
Loading