ethereum / ethereum/execution-specs
Refactor `static` into separate tox environments & dedicated `fast-checks` workflow
- Dominant language
- Python
- Stars
- 1.2k
- Forks
- 505
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 116
Description
Split the monolithic `static` tox environment into granular, single-purpose environments and move them to a dedicated `fast-checks` workflow. This makes CI failures immediately obvious (the failing job name tells you what broke) and ensures these checks always run as a prerequisite for other workflows.
## Motivation
The current `static` tox environment bundles multiple unrelated checks into a single job:
- `codespell` (spelling).
- `ruff check` / `ruff format` (linting/formatting).
- `mypy` (type checking).
- `ethereum-spec-lint` (custom linting).
- `uv lock --check` (dependency lock validation).
- `actionlint` (GitHub Actions linting).
Splitting the static checks will:
1. **Reduce debugging friction.** When `static` fails, developers must dig through logs to find which check failed and why. Separate environments provide immediate visibility - the job name itself tells you what broke.
2. **Enable always-on checks.** With `paths-ignore` being introduced (#2038), doc-only PRs may skip the `test.yaml` workflow entirely. A dedicated `fast-checks` workflow ensures checks like spellcheck are never skipped.
## Proposal
### 1. Split tox environments
Create separate tox environments for each check category:
| New Environment | Command(s) |
|-----------------|------------|
| `lint` | `ruff check`, `ruff format --check` |
| `typecheck` | `mypy` |
| `spellcheck` | `codespell` |
| `spec-lint` | `ethereum-spec-lint` |
| `lockcheck` | `uv lock --check` |
| `actionlint` | `actionlint` |
This is similar to the [execution-spec-tests](https://github.com/ethereum/execution-spec-tests/blob/main/tox.ini) pattern.
Additionally, create a `fast-checks` alias environment that runs all split checks without code duplication. See [lean-ethereum's tox.ini](https://github.com/leanEthereum/leanSpec/blob/fbbacbea4545be870e25e3c00a90fc69e019c5bb/tox.ini#L17-L23) for this pattern:
```ini
[testenv:fast-checks]
description = Run all fast checks (lint, typecheck, spellcheck, spec-lint, lockcheck, actionlint)
commands =
{[testenv:lint]commands}
{[testenv:typecheck]commands}
{[testenv:spellcheck]commands}
{[testenv:spec-lint]commands}
{[testenv:lockcheck]commands}
{[testenv:actionlint]commands}
```
This enables both the aggregate command (`tox -e fast-checks`) and granular runs (`tox -e spellcheck`).
Consider aliasing a `static` tox env, too for backwards compatibility.
### 2. Create dedicated workflow
Create `.github/workflows/fast-checks.yaml`:
- Triggers on **all** pushes and PRs (no `paths-ignore`).
- Runs fast (~2 min total).
- Executes `tox -e fast-checks` (the alias) or runs individual envs in parallel jobs.
### 3. Maintain fast-checks as a prerequisite
The current `test.yaml` already uses `static` as a prerequisite for all other jobs (`needs: static`). This proposal maintains that behavior while extracting it into a reusable workflow:
```yaml
jobs:
fast-checks:
uses: ./.github/workflows/fast-checks.yaml
py3:
needs: [fast-checks]
# ...
```
**Benefits of extraction:**
- **Decoupled triggers** - `fast-checks.yaml` has no `paths-ignore` and always runs. Other workflows (`test.yaml`, `benchmark.yaml`, `hive-consume.yaml`) keep their `paths-ignore` for expensive tests but call `fast-checks.yaml` as a prerequisite.
- **Single source of truth** - Fast checks are defined once, reused across all workflows via `uses:`.
- **Clearer CI view** - "fast-checks" appears as a separate workflow in GitHub Actions UI.
Alternatively, use `workflow_run` trigger or repository rulesets to enforce this.
## Related
- #2038: Optimizes CI by avoiding unnecessary checks, but introduces the side effect that doc-only PRs will not get spellchecked.
- Follow-up: GitHub Summary output with reproduce/fix commands (separate issue).
Contributor guide
Assessment
This issue has not been assessed yet.