> AI disclosure: this PR, the measurements behind it, and this description were produced with Claude Code at a maintainer's request. It should get human review before it leaves draft.
## Summary
This PR does three things:
- **`Cargo.toml`:** `[profile.coverage]` changes from `lto = "thin"` to `lto = false`.
- **`AGENTS.md`:** adds an opt-in note on incremental compilation for this profile, with its measured cost.
- **`AGENTS.md`:** the `cargo coverage -- <tool>` examples become `cargo coverage <tool>`; the old form runs every suite.
## Why
With `lto = "thin"`, the library crates are compiled to bitcode only (`-C linker-plugin-lto`). The final binary (`-C lto=thin`) then re-optimizes and re-codegens the whole program on every rebuild. After a one-line `oxc_minifier` edit, `cargo build --timings` showed where the time went:
| | `oxc_minifier` lib | `oxc_minsize` lib | `oxc_minsize` bin |
|---|---|---|---|
| `lto = "thin"` | 5.2s | 1.9s | **19.4s** (whole-program ThinLTO) |
| `lto = false` | 7.2s | 2.3s | **0.7s** (plain link) |
Every binary built with this profile pays that step separately. That covers the harnesses (`oxc_minsize`, `oxc_track_memory_allocations`, `oxc_coverage`) and the NAPI test builds (`pnpm build-test`). The profile's own comment says `lto = "thin"` was chosen for "faster compile time", and turning LTO off is faster still. The profile exists to run the harnesses with debug assertions, which doesn't need cross-crate LTO.
## Evidence: replaying 11 real `main` commits
Setup:
- **Commits:** the 11 picked from the rust 1.99.1 window. They cover minifier, ecmascript, codegen, parser, transformer and formatter, plus two `oxc_ast`/`oxc_str` refactors that rebuild 66 crates. Four of them change `allocs_*.yaml`, and one also changes `minsize.snap`.
- **Per commit and config:**
1. Build at the commit's parent (untimed).
2. Check out the commit.
3. Time `cargo minsize`, `cargo allocs` and `cargo coverage`, with build and run timed separately.
- **Machine:** 4-core Linux VM; each config used its own target dir.
| config | total edit→result | per commit | harness run (median) | target dir after 11 commits |
|---|---|---|---|---|
| `lto = "thin"` (before) | 1580s | 110–174s | 16.0s | 2.1 GB |
| **`lto = false` (this PR)** | **923s (1.7×)** | 36–140s (1.2× deep → 3.8× leaf) | **16.0s** | **1.8 GB** |
| `lto = false` + `CARGO_PROFILE_COVERAGE_INCREMENTAL=true` | 463s (3.4×) | 23–83s | 16.9s (+6%) | 12 GB (9.9 GB of it the incremental cache) |
**Correctness:** all 33 runs (3 configs × 11 commits) produced outputs byte-identical to the snapshots committed at each commit. That includes the commits whose snapshots changed.
## CI
PR CI on `c6014a89` passed. Several jobs that build with this profile are path-filtered or Windows-only on PRs. So I also triggered `ci.yml` manually on this branch ([run 39706156660](https://github.com/oxc-project/oxc/actions/runs/39706156660)), which runs them regardless of what changed. All 21 jobs that ran passed. The coverage-profile ones:
| job | how it uses the profile | result |
|---|---|---|
| Conformance, Minification Size, Allocations, Linter changes | `cargo coverage` / `minsize` / `allocs` / `lint-timings` | ✅ snapshots unchanged |
| Lexer (generic, AVX2, Neon) | lexer conformance via `oxc_coverage` | ✅ snapshots unchanged |
| Test NAPI Compiler, Test NAPI Oxlint, Test NAPI Oxfmt, Test Codegen | `pnpm build-test` | ✅ |
| Test NAPI Compiler (windows) | `cargo build --profile coverage` of the NAPI crates | ✅ |
**Not run before merge:** Test NAPI Oxlint (windows) and Test NAPI Oxfmt (windows). Their condition is `github.ref_name == 'main'`, with no manual trigger. The risk is low:
- Their Linux versions, which run the same `build-test` scripts, passed.
- Building NAPI libraries with this profile on Windows passed in Test NAPI Compiler (windows).
**Not affected:** the lexer benchmark uses the `bench` profile.
## Incremental: documented as opt-in only
Incremental roughly halves edit→result again, but its cache grew to ~10 GB over 11 commits and harness runs got ~6% slower. So `AGENTS.md` documents it as an opt-in env var with those costs, and it stays out of the profile.
## `cargo coverage -- <tool>` examples
The `coverage` alias already ends in `--`, so `cargo coverage -- parser` passes `-- parser` to the binary. `pico_args::subcommand()` then returns `None`, and the binary runs `run_all()`:
| command | suites run | time |
|---|---|---|
| `cargo coverage parser` | 4 | 5.0s |
| `cargo coverage -- parser` | 28 | 15.3s |
**Not included (possible follow-ups):**
- `just conformance <tool>` has the same problem.
- `oxc_coverage` could skip a leading `--`, so both forms work.
## Verification
- `typos` and the repo's pinned `oxfmt@0.74.0 --check` pass on `AGENTS.md` and `Cargo.toml`.
- `pnpm install` failed in the sandbox with a proxy 403 on a GitHub tarball, so I ran oxfmt directly.
- Before pushing, I also ran the harnesses, lexer conformance (generic and AVX2) and the NAPI crate build locally with LTO off. All matched HEAD.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01GZu5GvJLQYkfYHTAoH2yac
Running `just ready` after every commit repeats expensive workspace checks for small edits and successive PRs in a stack.
Keep the core rules in `AGENTS.md` and move the detailed workflow to `.agents/verification.md`, with an explicit instruction to read it before selecting checks. Scope verification to changed code and affected consumers, reuse results while inputs stay unchanged, and keep Cargo build settings consistent to avoid unnecessary rebuilds. For stacks, use each PR's diff against its parent and reserve broad integration checks for a stable tip.
This reduces repeated work during local and stacked development while retaining required subsystem checks and CI for each mergeable PR. It uses existing commands, with no additional verification scripts to maintain.
Exercised on local changes and a ten-PR stack; a fresh agent checked discovery and verification decisions after the split.
AI-assisted with Codex.
Bump the MSRV from Rust 1.96.0 to 1.97.0 under the N−2 policy after #27257 updated the toolchain to Rust 1.99.0. Update the prerequisite documentation and use the now-stable `isolate_lowest_one()` in the AST layout tool.
Iterate over the linter's underlying array with `&mut *self.by_type`, since boxed-array `IntoIterator` requires Rust 1.99 and fails on the new MSRV. This also satisfies Clippy's `explicit_iter_loop` lint.
## Summary
- bump the workspace MSRV from 1.95.0 to 1.96.0 under the N-2 policy after #25945
- retain an MSRV-compatible layout calculation while suppressing the Rust 1.98 Clippy suggestion
Remove the Prettier related stuff from the conformance, which is purely aimed at JS/TS.
Instead, `oxc_formatter_tests` manage Prettier's test fixtures along with Oxfmt.
`pnpm run build-test` is the correct command for building NAPI packages for running tests, not `pnpm build-dev`. Correct the docs accordingly. Also clarify the commands for running e2e tests.
## Summary
- document that `.github/workflows/pr.yml` requires scoped Conventional Commit PR titles
- add an example title to the contributor setup notes in `AGENTS.md`
## Testing
- not run; documentation-only change
## AI Usage
- Codex assisted with drafting the documentation change and PR description
## Summary
- Document that contributors who repeatedly submit low-quality ("slop")
AI PRs will be banned without prior warning
- Note that unbans can be requested via Discord
- Apply to both AGENTS.md and CONTRIBUTING.md
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
- The header on rules_enum.rs was being stripped by accident, which was confusing for users. So I fixed that.
- Mark the generated files as generated in `.gitattributes`, for GitHub to understand the diffs are mostly pointless and can be collapsed by default (the CI job enforces that these files be up to date anyway).
- Mark the generated rule files as `merge=ours`. See https://git-scm.com/book/ms/v2/Customizing-Git-Git-Attributes for more info on what that means, but it should make the merge conflicts less problematic.
- Updated `just ready` to include the lintgen command.
- Added `cargo lintgen` to the AGENTS.md file.
AI Disclosure: Used Claude to find the reason for the lack of header comment because I had no idea why it was happening.
## Summary
- Add a "Searching Test Suites" section documenting the pre-cloned test suite paths
- Helps AI assistants know where to search for test cases (test262, babel, typescript, prettier)
## Test plan
- Documentation only change
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add critical information on how we test in each crate. Additionally, add
CLAUDE.md to fix the issue that Claude code doesn't read AGENTS.md
automatically.
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>