Skip to content
Merged
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
6 changes: 0 additions & 6 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
[unstable]
codegen-backend = true

[profile.dev]
codegen-backend = "cranelift"

[target.x86_64-unknown-linux-gnu]
Comment thread
coderabbitai[bot] marked this conversation as resolved.
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
11 changes: 9 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,15 @@ jobs:
else
cargo binstall --no-confirm --locked "whitaker-installer@${WHITAKER_INSTALLER_VERSION}"
fi
# --cranelift provisions rustc-codegen-cranelift on Whitaker's pinned
# toolchain; this project builds with the Cranelift debug backend.
# --cranelift provisions rustc-codegen-cranelift on Whitaker's own
# pinned toolchain, kept separate from this project's toolchain
# pin. This project's debug builds use Cranelift only via the
# opt-in tools/dev-fast/config.toml fragment, which the
# build/test/lint/typecheck Makefile targets pass explicitly with
# --config; .cargo/config.toml no longer sets a codegen backend
# (it configures the mold linker only). The Lint step's Whitaker
# invocation does not pass --config, so it lints under the
# default LLVM backend regardless of this provisioning.

whitaker-installer --cranelift
- name: Audit dependencies
Expand Down
16 changes: 10 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@ jobs:
key: cross-${{ env.CROSS_REVISION }}
- name: Install cross
env:
# Clear repository build flags from .cargo/config.toml (mold linker
# and Cranelift codegen-backend) before installing cross from CROSS_REVISION.
# .cargo/config.toml contains the Linux mold linker configuration
# only (no codegen backend); clear its RUSTFLAGS before installing
# cross from CROSS_REVISION.
RUSTFLAGS: ""
run: |
if [ -x "$HOME/.cargo/bin/cross" ]; then
Expand All @@ -74,11 +75,14 @@ jobs:
restore-keys: |
${{ runner.os }}-cargo-${{ matrix.target }}-
- name: Build release binary
# Use +stable to override rust-toolchain.toml (which specifies nightly
# with Cranelift for development) and ensure release builds use stable.
# Use +stable to override rust-toolchain.toml's nightly pin and
# ensure release builds use stable, regardless of local dev tooling.
env:
# Build release artifacts without repository-local linker flags,
# including mold rustflags from .cargo/config.toml.
# Build release artifacts without repository-local linker flags:
# .cargo/config.toml's mold rustflags are Linux-only and never
# apply here. Cranelift lives solely in the opt-in
# tools/dev-fast/config.toml fragment, which this build never
# reads, so there is nothing to isolate it from.
RUSTFLAGS: ""
run: cross +stable build --release --target ${{ matrix.target }}
- name: Prepare artifact
Expand Down
7 changes: 7 additions & 0 deletions .rustfmt.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Canonical rustfmt configuration for the estate. In a consuming
# repository this file lives at the root as `.rustfmt.toml`; keep it
# there, aligned with canon (the rust-rustfmt-baseline rule FMT-001
# compares the parsed keys).
#
# `unstable_features = true` means rustfmt must run on the nightly channel;
# the rust-rustfmt-baseline rule (FMT-002) checks for that evidence.
unstable_features = true
comment_width = 100
format_code_in_doc_comments = true
Expand Down
24 changes: 24 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,3 +378,27 @@ The following tooling is available in this environment:

These practices help maintain a high-quality codebase and facilitate
collaboration.

## Fast development builds

`make dev-build` and `make dev-test` compile with the opt-in Cranelift
backend and the mold linker configured in `tools/dev-fast/config.toml`.
They require a nightly toolchain and, on Linux, a `mold` binary on the
`PATH`. The fragment is passed explicitly with `--config`, so release,
coverage, and verification builds are unaffected; never copy its contents
into `.cargo/config.toml`, which Cargo applies to every build.

## dev-fast is the standard development path

The standard `make build`, `make test`, `make lint`, and `make typecheck`
targets already pass `--config tools/dev-fast/config.toml` to every cargo
invocation they make; this is not limited to the opt-in `dev-build`/
`dev-test` targets above. An agent or human who calls `cargo build`,
`cargo test`, `cargo clippy`, `cargo check`, or `cargo doc` directly for a
development build, test, lint, or typecheck run must pass
`--config tools/dev-fast/config.toml` too, or use the Makefile targets
instead of raw `cargo`. The fragment must never be applied to coverage,
release, or verification builds. Mixing direct-cargo and `make`
invocations without the flag thrashes the incremental build cache, since
Cargo fingerprints a build differently depending on which codegen backend
and linker configuration produced it.
16 changes: 16 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ allow_attributes = "deny"
allow_attributes_without_reason = "deny"
blanket_clippy_restriction_lints = "deny"
cognitive_complexity = "deny"
disallowed_methods = "deny"
needless_pass_by_value = "deny"
implicit_hasher = "deny"
missing_assert_message = "deny"

# 2. debugging leftovers
dbg_macro = "deny"
Expand Down Expand Up @@ -83,7 +85,21 @@ error_impl_error = "deny"
result_large_err = "deny"

[lints.rust]
unknown_lints = "deny"
renamed_and_removed_lints = "deny"
unsafe_code = "forbid"
missing_docs = "deny"

[lints.rustdoc]
missing_crate_level_docs = "deny"
broken_intra_doc_links = "deny"
private_intra_doc_links = "deny"
bare_urls = "deny"
invalid_html_tags = "deny"
invalid_codeblock_attributes = "deny"
unescaped_backticks = "deny"

[dev-dependencies]
camino = "1.2.5"
cap-std = { version = "4.0.2", features = ["fs_utf8"] }
rstest = "0.26.1"
29 changes: 23 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ UV_ENV = UV_CACHE_DIR=.uv-cache UV_TOOL_DIR=.uv-tools
TYPOS_VERSION ?= 1.48.0
TYPOS = $(UV) tool run typos@$(TYPOS_VERSION)

# The standard build, test, lint, and typecheck targets below use the
# opt-in dev-fast profile (Cranelift plus mold) defined in the Wave 1
# block near the end of this file. Declared here too so the standard
# targets can see it regardless of where in the file they sit.
DEV_FAST_CONFIG ?= tools/dev-fast/config.toml

build: target/debug/$(TARGET) ## Build debug binary
release: target/release/$(TARGET) ## Build release binary

Expand All @@ -36,14 +42,14 @@ clean: ## Remove build artifacts
$(CARGO) clean

test: ## Run tests with warnings treated as errors
RUSTFLAGS="$(RUST_FLAGS)" $(CARGO) $(TEST_CMD) $(TEST_FLAGS) $(BUILD_JOBS)
RUSTFLAGS="$(RUST_FLAGS)" $(CARGO) test --doc --workspace --all-features
RUSTFLAGS="$(RUST_FLAGS)" $(CARGO) --config "$(DEV_FAST_CONFIG)" $(TEST_CMD) $(TEST_FLAGS) $(BUILD_JOBS)
RUSTFLAGS="$(RUST_FLAGS)" $(CARGO) --config "$(DEV_FAST_CONFIG)" test --doc --workspace --all-features

test-workflow-contracts: ## Validate the mutation-testing caller contract
uv run --with 'pytest>=8' --with 'pyyaml>=6' pytest tests/workflow_contracts -q

target/%/$(TARGET): ## Build binary in debug or release mode
$(CARGO) build $(BUILD_JOBS) $(if $(findstring release,$(@)),--release) --bin $(TARGET)
$(CARGO) $(if $(findstring release,$(@)),,--config "$(DEV_FAST_CONFIG)") build $(BUILD_JOBS) $(if $(findstring release,$(@)),--release) --bin $(TARGET)

coverage: ## Generate lcov coverage with lld for llvm-tools compatibility
@echo "coverage linker flags: $(COVERAGE_LINKER_FLAGS)"
Expand All @@ -54,12 +60,12 @@ coverage: ## Generate lcov coverage with lld for llvm-tools compatibility
$(CARGO) llvm-cov --lcov --output-path lcov.info $(TEST_FLAGS)

lint: ## Run rustdoc, Clippy, and the Whitaker Dylint suite with warnings denied
RUSTDOCFLAGS="$(RUSTDOC_FLAGS)" $(CARGO) doc --no-deps
$(CARGO) clippy $(CLIPPY_FLAGS)
RUSTDOCFLAGS="$(RUSTDOC_FLAGS)" $(CARGO) --config "$(DEV_FAST_CONFIG)" doc --no-deps
$(CARGO) --config "$(DEV_FAST_CONFIG)" clippy $(CLIPPY_FLAGS)
RUSTFLAGS="$(RUST_FLAGS)" $(WHITAKER) --all -- $(CARGO_FLAGS)

typecheck: ## Type-check without building
RUSTFLAGS="$(RUST_FLAGS)" $(CARGO) check $(CARGO_FLAGS)
RUSTFLAGS="$(RUST_FLAGS)" $(CARGO) --config "$(DEV_FAST_CONFIG)" check $(CARGO_FLAGS)

fmt: ## Format Rust and Markdown sources
$(CARGO) +nightly fmt --all
Expand Down Expand Up @@ -111,3 +117,14 @@ rust-audit: ## Audit the Rust workspace for known vulnerabilities
help: ## Show available targets
@grep -E '^[a-zA-Z_-]+:.*?##' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS=":"; printf "Available targets:\n"} {printf " %-20s %s\n", $$1, $$2}'

# Opt-in accelerated debug builds (Cranelift + mold); requires a nightly
# toolchain. See AGENTS.md and tools/dev-fast/config.toml.
DEV_FAST_CONFIG ?= tools/dev-fast/config.toml

.PHONY: dev-build dev-test
dev-build: ## Build debug binaries with Cranelift and mold
$(CARGO) --config "$(DEV_FAST_CONFIG)" build

dev-test: ## Run tests with Cranelift and mold
$(CARGO) --config "$(DEV_FAST_CONFIG)" test
18 changes: 17 additions & 1 deletion clippy.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
# Align with CodeScene’s ceiling
# Canonical clippy configuration for the estate.
#
# The thresholds align with CodeScene's code-health ceilings.
cognitive-complexity-threshold = 9 # default is 25
too-many-arguments-threshold = 4 # default is 7
too-many-lines-threshold = 70 # default is 100
excessive-nesting-threshold = 4 # default is off

allow-expect-in-tests = true

# Enforce the environment-injection mandate. The reason strings surface in
# the diagnostic, so a contributor who trips one is told what to do instead.
#
# Sanctioned sites carry `#[expect(clippy::disallowed_methods, reason = "..")]`
# rather than `allow`, so the expectation goes unfulfilled — and warns — once
# the site is migrated. The backlog removes itself instead of rotting.
disallowed-methods = [
{ path = "std::env::var", reason = "inject an environment reader" },
{ path = "std::env::var_os", reason = "inject an environment reader" },
{ path = "std::env::vars", reason = "inject an environment reader" },
{ path = "std::env::vars_os", reason = "inject an environment reader" },
{ path = "std::env::set_var", reason = "use a stub environment in tests" },
{ path = "std::env::remove_var", reason = "use a stub environment in tests" },
]
53 changes: 49 additions & 4 deletions docs/developers-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,41 @@ The main `.github/workflows/ci.yml` workflow deliberately does not run
`make test WITH_ACT=1`; the separate Act workflow runs those slower
container-backed checks in parallel.

## Lint baseline

`Cargo.toml`'s `[lints.clippy]`, `[lints.rust]`, and `[lints.rustdoc]`
tables hold this repository's lint baseline. `evert` is a single crate
with no `[workspace]` table, so the tables live directly on the crate
manifest rather than under `[workspace.lints]` with per-member
inheritance. `Cargo.toml` is authoritative for the exact entries; this
section summarizes intent rather than duplicating the list.

The baseline follows the estate's phase 2 Rust conventions: hygiene
and panic-prone operations are denied outright (`unwrap_used`,
`indexing_slicing`, `unreachable`, and similar), `pedantic` is enabled
as a warning tier, and `missing_docs` and `missing_crate_level_docs`
require real documentation rather than suppression.

Where a lint violation is a genuine, tracked deferral rather than a
bug, annotate the site with
`#[expect(clippy::<lint>, reason = "...")]`, never `allow`. An
`#[expect]` only suppresses the warning while the violation remains;
once the site is fixed, the unfulfilled expectation itself warns, so
the deferral surfaces for removal instead of rotting silently in the
codebase.

`clippy.toml` carries the numeric thresholds behind the baseline
(cognitive complexity, argument count, function length, nesting
depth) and the `disallowed-methods` list that blocks direct
`std::env::var`/`var_os`/`vars`/`vars_os`/`set_var`/`remove_var`
calls. Each disallowed method's `reason` tells the contributor what to
do instead: inject an environment reader in production code, or use a
stub environment in tests.

The pinned nightly toolchain in `rust-toolchain.toml` supplies the
`rustfmt`, `clippy`, and `rust-analyzer` components the baseline and
this workflow depend on.

## Spelling policy

`make all` and `make markdownlint` enforce en-GB-oxendict spelling with the
Expand Down Expand Up @@ -77,10 +112,20 @@ as a test assertion on the SHA string.

## Tooling

Development builds use Cranelift for debug code generation. On Linux targets,
`.cargo/config.toml` configures clang to link with `mold` so debug builds link
quickly. Coverage generation uses `lld` because LLVM coverage tooling expects
LLVM-compatible linker behaviour.
Development builds use the standard LLVM backend by default. On Linux
targets, `.cargo/config.toml` configures clang to link with `mold` so debug
builds link quickly. Coverage generation uses `lld` because LLVM coverage
tooling expects LLVM-compatible linker behaviour.

The pinned nightly toolchain retains the `llvm-tools-preview` and
`rustc-codegen-cranelift-preview` components, so the Cranelift backend and
LLVM coverage tooling are always installed; `tools/dev-fast/config.toml` is
what actually controls the repository-local opt-in activation. The opt-in
accelerated path, `make dev-build` and `make dev-test`, applies the
Cranelift codegen backend alongside `mold` via that fragment. It requires a
nightly toolchain and is never applied to release, coverage, or
verification builds; see [Fast development
builds](../AGENTS.md#fast-development-builds) in `AGENTS.md`.

Install `clang`, `lld`, `mold`, `python3`, and `cargo-audit` before running the
full generated workflow locally on Linux.
Expand Down
8 changes: 7 additions & 1 deletion docs/repository-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ compact and omits build output such as `target/`.

├── tests/
│ └── stub.rs
├── tools/
│ └── dev-fast/
│ └── config.toml
├── AGENTS.md
├── Cargo.toml
├── LICENSE
Expand All @@ -47,7 +50,7 @@ compact and omits build output such as `target/`.
## Path responsibilities

- `.cargo/config.toml`: Configures Cargo defaults for local development,
including Linux linker and code-generation settings.
including Linux linker settings.
- `.github/dependabot.yml`: Configures automated dependency update checks.
- `.github/workflows/act-validation.yml`: Runs the generated workflow
validation through `act` separately from main CI.
Expand Down Expand Up @@ -77,6 +80,9 @@ compact and omits build output such as `target/`.
behaviour.
- `tests/stub.rs`: Keeps the generated test directory valid until real tests
replace it.
- `tools/dev-fast/config.toml`: Configures the opt-in accelerated debug build
(Cranelift plus `mold`), applied explicitly via `make dev-build` and
`make dev-test`; never merged into `.cargo/config.toml`.
- `AGENTS.md`: Provides repository-specific working instructions for agents and
contributors.
- `Cargo.toml`: Defines package metadata, dependencies, lint policy, and Cargo
Expand Down
16 changes: 10 additions & 6 deletions docs/users-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ settings, and documented starter code. Library projects render `src/lib.rs`.
Application projects render `src/main.rs`, `src/lib.rs`, release automation, and
`[package.metadata.binstall]` metadata for binary installation.

Development builds use Cranelift for debug code generation. On Linux targets,
`.cargo/config.toml` configures clang to link with `mold` so local debug builds
link quickly. Coverage generation uses `lld` instead because LLVM coverage
tools expect LLVM-compatible linker behaviour.
See the [developers' guide](developers-guide.md) for local build tooling,
including the linker configuration and the opt-in accelerated build path.

## Makefile Targets

Expand All @@ -25,12 +23,18 @@ The generated `Makefile` exposes these public targets:
- `make test` runs `cargo nextest run` when cargo-nextest is installed and
falls back to `cargo test` otherwise. All projects also run doctests.
- `make build` builds the debug target.
- `make dev-build` builds the debug target using the opt-in accelerated
build configuration described in the
[developers' guide](developers-guide.md).
- `make dev-test` runs tests using the same configuration.
- `make release` builds the release target.
- `make coverage` writes `lcov.info` using `cargo llvm-cov` and `lld`.
- `make audit` derives the Rust workspace root with `cargo metadata` and runs
`cargo audit` once from that root.
- `make markdownlint` checks Markdown files.
- `make nixie` validates Mermaid diagrams.

Install `clang`, `lld`, `mold`, `python3`, and `cargo-audit` before running the
full generated workflow locally on Linux.
Install `clang`, `lld`, `python3`, and `cargo-audit` before running the full
generated workflow locally on Linux. See the
[developers' guide](developers-guide.md) for the additional tooling the
opt-in accelerated build path requires.
1 change: 1 addition & 0 deletions rust-toolchain.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ channel = "nightly-2026-05-28"
components = [
"clippy",
"llvm-tools-preview",
"rust-analyzer",
"rustc-codegen-cranelift-preview",
"rustfmt",
]
Loading
Loading