feat: Introduce cargo-anvil for unified Rust build/CI scaffolding - #33
Conversation
7be21da to
5243f05
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #33 +/- ##
=======================================
+ Coverage 93.2% 95.4% +2.1%
=======================================
Files 28 48 +20
Lines 1262 5029 +3767
=======================================
+ Hits 1177 4799 +3622
- Misses 85 230 +145
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
9e452bf to
bcf6d3b
Compare
|
36840e6 to
d87a60e
Compare
|
5e22123 to
d2529be
Compare
Addresses Sander's review feedback on PR #33: 'CI' is a working methodology, not a synonym for automation pipelines. Adopt 'cloud workflows' (neutral across GH Actions and ADO pipelines) throughout cargo-anvil docs, source comments, template comments, and Cargo.toml description/keywords. Scope: cargo-anvil only. No code identifiers changed. Pre-existing ox-tools repo docs (top-level README.md, DEVELOPMENT.md) and other crates' READMEs left alone since they predate cargo-anvil and were not part of Sander's review. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Top-level design document covering the why (unified, opinionated CI/build scaffolding for Rust repos), principles (recipe-first; cargo-as-fallback; owned-with-customization), and tier/group structure. Companion documents split out checks.md (catalog), local.md (justfile layout), updates.md (drift detection), github.md / ado.md (per-backend wiring), and verification.md (continuous-validation strategy). Includes the initial pipeline design, the --backend flag shape (repeatable not enum), the rename from cargo-ox-ci to cargo-ox-check, and implementation-plans/0000.md laying out the 22-step MVP path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
22 implementation steps from plan 0000: 1. CLI surface with no-op `update` subcommand 2. Backend autodetection from `origin` URL 3. Workspace discovery and member enumeration 4. `.ox-check.lock` manifest read/write 5. SHA-256 helpers + three-checksum (T/L/D) decision algorithm 6. Managed-region parser and writer 7. Plan, proposed-file emission, dry-run summary 8. tools.just emitter and owned-file driver 9. checks.just emitter (per-check recipes) 10. groups.just + tiers.just emitters 11. Justfile imports managed region 12. Cargo.toml workspace + member [lints] regions 13. deny.toml, rustfmt.toml, .delta.toml regions 14. End-to-end local-only update wiring 15-17. GitHub composite actions, reusable workflows, root workflows 18-20. ADO step templates, stages templates, root pipelines 21. Schema-validation tests (actionlint, taplo, just-parse) 22. regenerate-check workflow for dogfooding Plus initial README and crates.io polish. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Switch from anyhow to ohno::AppError throughout cargo-ox-check - Drop DecisionInputs::emptied and Decision::Skipped - Drop spurious ox-check-managed sentinels from owned .just templates - Move per-group GH action / ADO step YAML bodies into template files (single source for the per-group template body, substituted at emit) - Single-import Justfile pattern: only mod.just visible to users, all ox-check recipes reached transitively; alias in mod.just - Drop ADO YAML `pr:` trigger (Azure Repos uses branch policies) - Include master alongside main in scheduled-tier schedule - insta snapshot tests covering local, github, and ado emitted trees - Codecov upload (GH) and PublishCodeCoverageResults@2 (ADO) wired in Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
P0 docs sweep, then:
P1 (C2-C5): drop ox-check-tools-install-missing from the design;
Propose decision bumps manifest L to the new template;
purge stale manifest entries on update; categorized dry-run
summary (Will create / Will update / Will propose / etc.)
P2 (C6-C8): tool-version policy -- per-tool minimums + version-aware
require check + rustc/pwsh gate
P3 (C9-C11): three-tier impact scoping (modified / affected / required)
via cargo-delta, with per-tier env vars consumed by recipes
P4 (C12-C14): llvm-cov HTML report + missing lints; BASE_REF master
fallback; per-recipe _ox-check-require fan-out
P5 (C15-C16): GitHub actions/cache in setup composite; ADO Cache@2
in setup step
P6 (C17-C18): fixture scenarios under tests/fixtures/; rewrite
verification.md fixture/schema sections
Also: required-tier env var introduced and used by checks classified as
required (workspace-wide tools that consume the dep closure). Compile-
sensitive groups (pr-fast, pr-test, pr-runtime-analysis, advisories)
expanded to cross-OS. ARM64 legs added to GitHub default matrix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Pre-dogfood fixes: bash shell default, arch in cache key
- cargo-delta CLI / JSON shape adjustments after surveying real tool versions
- Per-recipe bash shebang annotation; drop intrusive `set shell`
- Initial dogfood pass on this repo + follow-up lint/rustfmt resolution
- Switch recipe interpreter from bash shebang to [script("pwsh")]
- Normalize line endings before hashing; lowercase justfile path migration
- Cohabit-outside-region pattern for ox-tools workspace lint extras
- Bump rustfmt max_width to 140
- File/region removal: handle catalog drops and disabled backends
- setup-action: install libclang on Linux; install rustfmt/clippy components
- InSync refreshes manifest L so stale-L from older binary versions self-heals
- Fix cargo-mutants --in-diff usage; tolerate per-tool install failures
- Matrix-input plumbing: hardcoded OS matrices, per-leg runner labels only
(rejected fromJSON(inputs.X) form -- silent empty-matrix failure mode)
- ADO backend: per-job wrapper template (steps/job.yml) for 1ESPT
extensibility -- adopters edit the wrapper to plug in templateContext
blocks; the dirty-file flow then preserves their edits
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Two Linux-only CI failures (PowerShell array-unwrap, cargo-delta name format mismatch for hyphenated packages) - setup-action: save cache even on job failure (deprecated save-always replacement) - Optional cargo-binstall installer with per-tool cargo-install fallback - License header exclusions for vendored files - Per-job cache keys + drop --workspace from more recipe tools - Skip re-install when tool already present at sufficient version - Justfile case fixes: lowercase justfile -> canonical "Justfile" with case-aware migration - Cache cargo's installed-tools registry (.crates.toml) too - doc2readme: add --workspace + regenerate READMEs - Spellcheck infrastructure: preprocess .spelling -> .dic, pass `--cfg spellcheck.toml`, skip llvm-cov on Windows ARM, mkdir target/coverage - Dictionary buildup: technical jargon, lowercase variants for case-sensitive merge, intra-doc link backticking Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Trigger CI with conventional-commits PR title check - ox-check-deny: dedupe [licenses] + bump unmaintained syntax - ox-check-udeps: drop unused deps surfaced by cargo-udeps - ox-check-semver-check: filter bin-only crates from --package; tolerate unpublished + bin->lib baselines - ox-check-external-types: per-manifest invocation (no --package); invoke via cargo +nightly; tolerate rustdoc JSON schema drift - ox-check-aprz: use 'deps' subcommand, not 'check' - setup: install nightly toolchain explicitly - Test fixes for ox-check mutation-testing coverage - Iterate group placement: try moving external-types and udeps to scheduled-advisories for speed, then revert udeps/semver-check to pr-fast (acceptable PR-tier cost) - GitHub: pass GITHUB_TOKEN to per-group composite action for cargo-aprz Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…zation - Pin nightly toolchains via versions.just; drop schema-mismatch tolerance (the pin makes drift impossible) - Ship default spellcheck.toml as a managed-region file - Switch ox-check-fmt to pinned nightly rustfmt with unstable opinions; bulk-format the codebase with that pin - Tighten ox-check lint catalog: Bucket A folding + contested-lint removals; drop empty_structs_with_brackets cohabit lint - Add rust.unexpected_cfgs to lint catalog (coverage cfgs) - Ship managed-region clippy.toml; attribute wildcard_imports bug workaround - Bump rust_nightly pin to nightly-2026-02-10 to match oxidizer Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Strip pre-existing spellcheck.toml content that collides with managed region - Fix stale snapshots + spellcheck typos from recent commits - ADO impact.yml needs setup.yml to bootstrap cargo - Cross-distro libclang install in setup.yml - Env-var form for impact baseline ref selection - Skip LFS smudge in impact baseline worktree - Validate impact package names; drop unknowns - Manifest mutation tests (double-newline guard, loop-bound progress) - Unify semver-check workspace path with per-package tolerance - Add ox-check-system-deps-check: probe for system-level libs (libclang) with per-OS install hints - Rename "nightly" tier to "scheduled" (PR #25 review feedback) - Per-OS impact stages to fix cfg-conditional dep gaps (impact-linux + impact-windows; each downstream leg consumes its OS's impact set) - Local-vs-CI parity for readme-check + impact validation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- cargo-heather: clarify ox-gen-readme opt-out reason; generate README via doc2readme so the README stays in sync with the crate-level rustdoc - Recipe-level cleanup: TODO on every OX_CHECK_INCLUDE recipe to factor out the preamble; inline `?? --workspace` splat; prune TODOs that turn out to be misplaced - Advisory PR comments for non-blocking findings (semver-check). Recipes exit 0 and write a markdown body to target/ox-check/comments/<NAME>.md when there are findings, remove the file when clean. GH wiring uses marocchino/sticky-pull-request-comment; ADO wiring uses a pwsh step against the ADO REST API. Skipped silently on builds without Contribute-to-PRs permissions - Extend spellcheck tokenization_splitchars to cover typographic punctuation (em-dash, en-dash, arrows) so prose with em-dashes tokenises correctly across cargo-spellcheck versions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Close two methodology gaps vs legacy CI (udeps --all-targets behaviour, external-types pinned-nightly enables PR-tier inclusion) - Rename pr-mutants -> pr-slow; add miri + careful to PR tier - Unified ox-check-setup recipe; install rustup components alongside cargo tools - Pin exact tool versions on install; accept newer if already present - Address real bugs surfaced by ox-check (walkdir unused, external-types API leaks: clap_builder::Error in cli, ohno::AppError in automation::run_cargo) - Bump cargo-heather pin (0.1.0 -> 0.2.1) since 0.1.0 fails to build from source on current Rust - miri exclusions for FS-heavy tests; pass `--no-tests=pass` to miri nextest only (not llvm-cov) - Add mermaid diagrams to checks.md / github.md / ado.md PR-slow CI structure: - Merge pr-test into pr-slow with three sub-recipes (slow1=tests+coverage, slow2=miri+careful, slow3=mutants) - Split pr-slow into three parallel CI jobs/stages (was: one sequential job per OS leg). Per-leg wall-clock drops from sum(slow1,slow2,slow3) to max(slow1,slow2,slow3). Umbrella `ox-check-pr-slow` just recipe preserved for local convenience CI diagram iteration: per-pipeline diagrams (PR + scheduled per backend), LR layout, single vertical column for jobs, multiple subgraph/column/ELK experiments converging on plain flowchart LR without invisible chains. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Diagram polish: - Spell out matrix legs (linux, windows, linux-arm, windows-arm) instead of "4-leg matrix"; drop tool lists from job labels (recipe column is source of truth) - Promote coverage upload to first-class node (codecov action / ADO PublishCodeCoverageResults@2) - Coverage upload: every leg except windows-arm (not linux-only). Single-leg coverage misses OS/arch-gated code; codecov coalesces multiple uploads against the same commit - Per-caller setup nodes so the ox-check-setup invocation is visible in every per-group composite/step template chain - Drop self-skip notes on pr-mutants node labels; drop verbose legends and prose paragraphs; simplify external-action labels - Add cargo delta as recipe node under impact; GH ox-check-impact now goes through ox-check-setup so cargo-delta picks up the catalog-pinned version (matches ADO behaviour) Naming reorg: - Rename pr-slow{1,2,3} to pr-{test,runtime-analysis,mutants}; rename ox-check-mutants check to ox-check-mutants-diff (parallels existing ox-check-mutants-full) - Rename cargo-ox-check -> cargo-ox-check-update; flatten the CLI (drop the redundant `update` subcommand since update is the only action) - Rename crate dir crates/cargo_ox_check_update -> crates/cargo-ox-check-update to match the hyphen convention used by cargo-coverage-gate and cargo-heather checks.md diagram: break out per-check nodes into a third layer, surface the ox-check alias, add ox-check- prefix to group labels, surface the pr-slow umbrella as a sibling of pr-fast. Other: - Drop misleading "oxidizer-github also uploads from a single canonical leg" comments (oxidizer-github actually uploads from three legs); the one-leg shape was an ox-check design simplification, then reverted - Drop orphan job.yml node from ADO PR diagram (its dotted "wraps via" edges were removed earlier and the node had no remaining edges) - Tighten diagram spacing via flowchart init config (nodeSpacing, rankSpacing, padding); bump font size on GH/ADO diagrams - Normalize crates/automation/Cargo.toml ox-check-lints managed region (drop trailing blanks that had caused a silent opt-out) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the monolithic ox-check-setup + tool-minimums.txt / rustup-components.txt data files with a per-tool, per-component, per-toolchain install + validate-prereqs recipe layer in tools.just, composed into per-check, per-group, per-tier, and global setup recipes. All version pins now live as plain just variables in versions.just (single source of truth, no sidecar data files). CI: GH composite ox-check-setup and ADO setup.yml take a 'group' input / parameter; per-group composites pass their own group name so a pr-fast leg never installs cargo-mutants. Special value 'none' skips tool install entirely (used by impact, which only needs cargo-delta). Naming: ox-check-tool-<bin>-install, ox-check-component-<tc>-<c>-install, ox-check-toolchain-<sym>-install at the atomic layer; ox-check-<check|group|tier>-setup at composition layers. Mirror ox-check-<x>-validate-prereqs recipes at every layer. Each check recipe depends on its matching -validate-prereqs (no more _ox-check-require). Failure policy: no tolerance -- a failed install fails the recipe (cargo-mutants ARM-Windows self-skip lives in the install body). Docs: local.md, github.md, ado.md, design.md updated to match. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
RUSTSEC-2026-0035 (pingora-cache) uses CVSS 4.0; cargo-audit 0.21.0 fails to parse the advisory database with 'unsupported CVSS version: 4.0'. 0.22.2 (released 2026-06-05) adds CVSS 4.0 support. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ox-check-system-deps-check only looked under /usr/lib/x86_64-linux-gnu for libclang. On ubuntu-24.04-arm runners the matching path is /usr/lib/aarch64-linux-gnu/, so the probe reported libclang missing even after apt-get install libclang-dev had put it there. Add aarch64-linux-gnu to the explicit-probe list and to the version-suffix glob fallback. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
cargo-spellcheck 0.15.1 no longer builds from source on Rust 1.93 (the locked ra_ap_stdx triggers E0804 'cannot add auto trait Send to dyn bound via pointer cast'), which broke the linux-arm pr-fast leg where binstall has no ARM prebuilt and falls back to source. Bump to 0.15.7; the em-dash word-boundary regression that motivated the original 0.15.1 pin is already mitigated by the typographic-punctuation entries we appended to tokenization_splitchars in spellcheck.toml's managed region (Phase 7.5). Separately, six tests in cargo-coverage-gate's workspace module stacked two #[cfg_attr(miri, ignore = ...)] attributes per test (one citing filesystem use, one citing cargo metadata subprocess). Newer rustc (nightly used by extended-analysis) treats the second ignore as redundant and emits 'unused attribute' under -D warnings, failing the legacy extended-analysis workflow. Collapsed each pair into a single attribute with a combined reason. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Same pattern as the workspace.rs fix: from_path_reads_from_disk had two stacked #[cfg_attr(miri, ignore = ...)] attributes (lines 166 and 168 straddling the #[test] attribute). Newer rustc emits 'unused attribute' on the second one. Collapsed into one with a combined reason. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Full rebrand of the unified-builds tool from cargo-ox-check-update / ox-check-* to cargo-anvil / anvil-*. Scope: - Crate / binary: crates/cargo-ox-check-update -> crates/cargo-anvil; Cargo name 'cargo-ox-check-update' -> 'cargo-anvil'; clap bin_name 'cargo ox-check-update' -> 'cargo anvil'. The subcommand token cargo injects is now 'anvil' and parse_from_cargo_args strips that. - Just recipe namespace: every ox-check-* recipe (groups, tiers, per-check, per-tool *-install / *-setup / *-validate-prereqs) renamed to anvil-*. 'just anvil' aliases anvil-pr. - Directories: justfiles/ox-check/ -> justfiles/anvil/ (both workspace and templates); .github/actions/ox-check-* -> .github/actions/anvil-*; .github/workflows/ox-check-pr*.yml + ox-check-scheduled*.yml renamed to anvil-pr*.yml + anvil-scheduled*.yml. - Lockfile: .ox-check.lock -> .anvil.lock. - Env vars: OX_CHECK_* -> ANVIL_*; ADO pipeline variable ox_check_rustc_version -> anvil_rustc_version. - Managed-region marker strings: '# managed by ox-check' -> '# managed by cargo anvil' (visible to every consuming repo on next regen). - Docs / README: design/, implementation-plans/, verification.md, all templates, snapshots regenerated. Verified locally: cargo check + 199 lib tests + 4 schema tests + 3 snapshot tests pass; 'cargo anvil' is idempotent on this workspace (31 items, 0 changes); 'just format' clean. The tests/update.rs integration binary triggers a Windows local-only UAC heuristic on the developer machine (filename starts with 'update'); CI runs it fine. Skipping pr-fast locally because cargo-aprz network appraisal runs >30min; CI is faster. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The rename to cargo-anvil is a deliberate brand choice (vs. the prior descriptive cargo-ox-check-update name). Add a one-paragraph note at the top of design.md explaining the forge metaphor, isolated so it doesn't leak into the user-facing surfaces. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Install a prebuilt cargo-binstall binary up front via the official action so the bootstrap branch in _install-tool (which runs 'cargo install --locked cargo-binstall' from source, ~4 min per cold-cache job) becomes a no-op on GH. Also opportunistically use binstall for 'just' itself with cargo-install fallback. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Addresses Sander's review feedback on PR #33: 'CI' is a working methodology, not a synonym for automation pipelines. Adopt 'cloud workflows' (neutral across GH Actions and ADO pipelines) throughout cargo-anvil docs, source comments, template comments, and Cargo.toml description/keywords. Scope: cargo-anvil only. No code identifiers changed. Pre-existing ox-tools repo docs (top-level README.md, DEVELOPMENT.md) and other crates' READMEs left alone since they predate cargo-anvil and were not part of Sander's review. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ee22477 to
71ad75c
Compare
Two follow-ups after rebasing on origin/main: 1. Regenerate crates/cargo-anvil/README.md — the prior CI -> cloud workflows rename in 71ad75c edited lib.rs doc-comments but didn't re-run doc2readme, so the README drifted. 2. Opt cargo-heather out of anvil-readme-check via [package.metadata.ox-gen-readme] disable = true. cargo-heather ships a hand-curated README with its own logo and layout and is already excluded from the legacy 'just readme'/'readme-check' recipes via hardcoded '--ignore cargo-heather'. anvil-readme-check supports the per-crate opt-out documented at checks.just:215. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reverts the [package.metadata.ox-gen-readme] disable opt-out added in 8639a43 (incorrect: 7a3dcd4 on main intentionally moved cargo-heather to the shared doc2readme pipeline). The real root cause was stale docs.rs URLs in README.md: PR #40 bumped the crate to v0.3.0 but didn't regenerate the README. main's legacy 'just readme-check' skips cargo-heather via hardcoded --ignore cargo-heather so the drift went undetected; anvil-readme-check (which has no per-crate skip-list) correctly flagged it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ralf Biedert (ralfbiedert)
left a comment
There was a problem hiding this comment.
Awww, I like the new name :)
Introduces
cargo-anvil: a cargo subcommand that ships and maintains an opinionated, unified build/CI scaffolding for Rust workspaces. Onecargo anvilinvocation emits a complete, reviewable tree of GitHub Actions workflows, Azure DevOps pipelines,justfiles/anvil/recipes, and managed regions inCargo.toml/deny.toml/rustfmt.toml/.delta.toml/clippy.toml/spellcheck.toml. Subsequent runs keep the tree in sync as the tool's catalog evolves, while preserving any local customizations the adopter has made.Why this exists
Every Rust repo in the
oxidizer/oxidizer-github/ox-toolsfamily hand-rolls its own CI on the same opinionated checks (fmt, clippy, deny, audit, miri, careful, mutants, llvm-cov, cargo-hack, semver-check, doc, aprz, …). The cost of keeping those copies in sync — toolchain bumps, lint updates, new advisory feeds, cross-OS matrix changes — is paid per-repo, by hand, every time.cargo-anvilcentralizes the catalog in one place and renders it into the per-repo CI surface.What an adopter gets
After one
cargo anvil, the repo contains:.github/workflows/anvil-pr.yml+anvil-pr-impl.ymland composite actions under.github/actions/anvil-*for the PR tier (anvil-pr-fast,anvil-pr-test,anvil-pr-mutants,anvil-pr-runtime-analysis)..github/workflows/anvil-scheduled.yml+anvil-scheduled-impl.ymland matching actions for the scheduled (nightly) tier..pipelines/(when--backend adois selected or autodetected).justfiles/anvil/recipe tree (mod.just,checks.just,groups.just,tiers.just,tools.just,versions.just). Localjust anvil-pr-fast,just anvil-clippy, etc. reproduce CI without anycargo-anvilbinary present.anvil-tool-<name>-install/-validate-prereqs, each checkanvil-<check>-setup/-validate-prereqs, each group/tier the same pattern, all composed up to a globalanvil-setup. CI jobs install only what they need.Cargo.toml(opinionated workspace + per-crate lints),rustfmt.toml,deny.toml,clippy.toml,spellcheck.toml,.delta.toml,.cargo-heather.toml. Each region is delimited by# managed by cargo anvil/# end managed by cargo anvil..anvil.lockmanifest tracking per-file and per-region checksums for the three-checksum update algorithm.Design highlights
modified,affected,required) backed bycargo-delta. Each check is tagged with the tier it scopes to; CI wiring emits one include-list env var per tier with a--skipsentinel for empty tiers. The required tier is included for tools whose correctness resolves through the dep graph (cargo doc,cargo hack,cargo udeps); the unscoped bucket is reserved forCargo.lock- and PR-context-only checks (deny,audit,aprz,pr-title).Write,LeaveAlone,Propose) keyed on a three-way comparison of (original-template, current-template, live-file) checksums, all tracked in the lock manifest. A user edit inside a managed region is preserved when the template hasn't moved; a template bump becomes a.anvil-proposedsidecar with a one-line summary, so customizations are never silently overwritten.origin's URL; explicit--backend github/--backend adooverride;--no-backendsfor local-only.actions/cache, ADOCache@2) keyed on OS + arch + rustc version + lockfile-family hashes +versions.justhash, so toolchain bumps and catalog updates invalidate cleanly..github/workflows/regenerate-check.yml— the one hand-written workflow that buildscargo-anvilfrom the PR's branch, runscargo anvil --dry-run, and fails the PR if the in-tree state drifts from what the templates would render.Verification
crates/cargo-anvil/src/(run/plan/decision/region/emit/workspace/manifest/checksum).tests/schemas.rs(every emitted TOML parseable; every emitted workflow valid againstactionlint; ADO YAML indentation consistent; every emitted recipejust-parseable).tests/snapshots.rscovering the three representative backend combinations (local-only, GitHub-backend, ADO-backend) — full byte-exact emitted tree.tests/update.rscovering single-crate (no[workspace]), opt-outs (emptied managed region preserved), customized (user edit inside a managed region preserved), migration (pre-existing hand-writtenJustfile/deny.toml/[profile.release]survive splicing).ox-toolsitself: this PR's workspace is the first adopter, so the full PR tier (anvil-pr-fast,anvil-pr-test,anvil-pr-mutants,anvil-pr-runtime-analysis) plus the scheduled tier runs against the verycargo-anvilbuild under review on every push.cargo-deltaCLI and JSON shape verified by running the actual binary against this workspace; the impact-step shell scripts encode the real two-snapshot--baseline/--currentflow.Total: 210 tests green locally + 4 PR-tier groups × 4 OS legs + impact + scheduled-runtime tier all green in CI.
Documentation
Lives under
crates/cargo-anvil/docs/:design/design.md— top-level design and CLI shape.design/local.md— thejustrecipe tree, impact env vars, daily-driver flow.design/github.md— owned reusable workflows, per-group composite actions, impact scoping.design/ado.md— owned stages templates, per-group step templates, 1ESPT composition guidance.design/checks.md— the opinionated catalog and per-group OS scope matrix.design/updates.md— the three-checksum state machine validated by fixture tests.verification.md— continuous-validation strategy (dogfooding + snapshot + fixtures + schema).implementation-plans/0000.md— initial implementation plan (history).implementation-plans/0001.md— design-vs-implementation reconciliation plan executed in this PR.Naming
The crate, binary, recipe namespace, lockfile, env vars, and managed-region markers all use
anvil(noox-prefix). This keeps the tool open-sourceable outside theox-brand. The forge metaphor (anvil = stable opinionated surface for forging per-repo build tooling) is mentioned indesign/design.mdonce and intentionally absent from user-facing surfaces.Follow-ups (not in this PR)
cargo-anvilto crates.io once a few in-tree adopters have shaken it out.cargo-anvilemits composable stages, not a 1ESPT extender; adopters compose the stages template into their compliance pipeline.