Skip to main content

Module stability

Module stability 

Source
Expand description

§Stability, versioning & the path to 1.0

How far each crate has settled, what a version number promises, the MSRV contract, and the gate this workspace holds itself to before tagging a 1.0.

§Versioning

Every crate is versioned and published independently and adheres to SemVer; each has its own CHANGELOG.md (Keep a Changelog) and is tagged <crate>-v<version>. There is no workspace-wide version.

While a crate is pre-1.0 (0.x), a SemVer minor bump (0.x → 0.(x+1)) may carry breaking changes and a patch (0.x.y → 0.x.(y+1)) is non-breaking — the standard Cargo ^0.x interpretation. Breaking changes are allowed at 0.x and called out in the changelog’s ### Changed/### Removed. After a crate reaches 1.0, it switches to strict SemVer: breaking changes require a major bump.

Because the crates depend on each other (vcs-corevcs-git/vcs-jj; the wrappers → the foundational vcs-diff/vcs-cli-support), each intra-workspace dependency carries a ^MAJOR.MINOR requirement that must stay in range when a dependency crosses a boundary — see the release process in AGENTS.md and the publish ordering in release.yml.

§Stability tiers

All crates are pre-1.0 today — the API may still change. Relative maturity:

CrateVersionTier
vcs-diff0.3settling
vcs-cli-support0.3settling
vcs-testkit0.3stable-ish (dev-only)
vcs-git0.7maturing
vcs-jj0.7maturing
vcs-github0.7maturing
vcs-core0.5evolving
vcs-gitlab0.3evolving
vcs-gitea0.3evolving
vcs-forge0.3evolving
vcs-watch0.3evolving
vcs-mcp0.3evolving

What the tiers mean — and the per-crate caveats:

  • settling — close to its 1.0 shape; small and pure. vcs-diff (diff model + parser, Version) and vcs-cli-support (the argv guard, fetch policy, error classifiers) are narrow surfaces unlikely to change much.
  • stable-ish (dev-only)vcs-testkit is a dev-dependency only, so its churn never reaches a release build.
  • maturing — broad, consumer-validated surfaces that still grow additively: vcs-git, vcs-jj (tracks jj, whose CLI/template surface churns — see the CI version matrix), and vcs-github (the gh PR/issue/run/release surface).
  • evolving — the surfaces with the most movement among the released crates; still growing (often additively), with the empirically-validated CLI argv/JSON occasionally shifting. vcs-core’s common facade grows as cross-backend needs surface (e.g. snapshot). vcs-gitlab / vcs-gitea are lean MR/PR lifecycles, mostly fixture-pinned (vcs-gitea is the narrower of the two — see its capability notes); vcs-forge’s unified DTOs grow with the wrappers; vcs-watch is the workspace’s first runtime-tokio + streaming API (its event set may still shift); vcs-mcp is the MCP server (a lib + binary), whose tool catalogue, names, and JSON shapes will grow.

§MSRV policy

The minimum supported Rust version is 1.88 (edition 2024 needs 1.85, but the wrappers use let-chains, stabilised in 1.88). It is declared once in [workspace.package] as rust-version = "1.88" and inherited by every crate, so cargo build on an older toolchain fails early with a clear message — the contract is machine-checked, not just documented.

An MSRV bump is treated as a minor-version change (a 0.x minor today; a major after 1.0 if a consumer pins an older toolchain) and is called out in the changelog. We bump the MSRV only when a dependency or a genuinely useful language feature requires it — not casually.

§Public-API review checklist (the 1.0 gate)

Before any crate is tagged 1.0, its public surface is reviewed against the invariants this workspace already holds (most are enforced today; 1.0 makes them a promise):

  • Trait object-safety & mockability. Every public trait stays object-safe (no generic methods, no nested-reference lifetimes — owned &[String]/Option<String>, not &[&str]/Option<&str>), so &dyn Api and async-trait keep working. The wrapper traits (GitApi/JjApi/ GitHubApi/GitLabApi/GiteaApi) are additionally mockall-friendly: the mock feature generates a Mock*Api. The facade traits (VcsRepo, ForgeApi) deliberately carry no mock feature — they’re generated by a macro_rules! whose :ty signatures mockall::automock can’t parse — so the facades are tested over a fake runner (Repo::from_git / Forge::from_github), which is their documented test path anyway.
  • #[non_exhaustive] on returned types. Every struct/enum a consumer reads (DTOs, parsed results) is #[non_exhaustive] so a new field/variant isn’t a breaking change — except deliberate value types (Version) that callers legitimately construct.
  • Structured errors. Failures surface as processkit::Error variants (Exit/Timeout/Spawn/Parse), never a stringly-typed blob; the facade adds only repo-detection variants. Classifiers (is_merge_conflict, …) give intent without matching on internals.
  • Injection-safe by default. Caller strings in bare positional argv slots are guarded (reject_flag_like); flag-value slots are documented as exempt.
  • No leaked internals. Re-exports are explicit (no glob leaks); private parsers/helpers stay private; the cli_client! seam isn’t part of the surface.
  • Docs + tests. Every public method has a doc comment and at least a hermetic test pinning its argv/parse; the pure parsers are property-tested for panic-freedom; real-binary behaviour is covered by the #[ignore] integration suites (CI version-matrixes jj).

§See also

  • AGENTS.md — the release process, changelog curation, and dependency conventions.
  • Process model & errors — the error model the API review references.
  • ROADMAP.md6.12 and the remaining path-to-1.0 work.