Skip to content

toolchain(rust): define deterministic build toolchain, explicit MSRV policy and Core/Tauri compatibility lanes #572

Description

@qnbs

Context

WorldScript Studio's Rust surface is growing in strategic importance because renderer-neutral Core work is a prerequisite/foundation for the Tauri→Qt path.

Current repository state is not yet a fully explicit Rust toolchain contract:

# src-tauri/Cargo.toml
edition = "2021"
rust-version = "1.77.2"

but the repository currently has no root rust-toolchain.toml, while CI/release workflows install Rust through dtolnay/rust-toolchain and can therefore follow a broader/current toolchain policy than the manifest's declared minimum.

Current upstream stable Rust as of 2026-09-01 is Rust 1.98.0:
https://blog.rust-lang.org/releases/latest/

The large gap between a declared rust-version = 1.77.2 and a current floating/stable build environment is not automatically wrong: rust-version is an MSRV claim, not necessarily the version maintainers should build with. But those two concepts must be separated and tested deliberately.

This issue owns Rust toolchain determinism and support policy, not migration of additional application logic into Rust.

Related architecture owners include #445, #551–#553, #332 and the native roadmap.

Goal

Define three explicit Rust lanes:

DECLARED_MSRV
  = oldest Rust version WorldScript intentionally claims to support

PINNED_BUILD_TOOLCHAIN
  = deterministic Rust version/components used by normal CI/development/release builds

CURRENT_STABLE_QUALIFICATION
  = forward-compatibility signal against upstream stable Rust

Then ensure Tauri and renderer-neutral Core crates use one coherent policy rather than incidental toolchain drift.


Phase 0 — inventory all Rust authorities

Before mutation, inventory:

  • src-tauri/Cargo.toml;
  • every manifest under crates/;
  • both Cargo.lock files;
  • workspace resolver/edition settings;
  • .github/workflows/ci.yml Rust gates;
  • .github/workflows/tauri-build.yml;
  • .github/workflows/tauri-intel-qualification.yml;
  • any release/container/native workflows using Rust;
  • dtolnay/rust-toolchain channel/components arguments;
  • local setup/docs;
  • rustfmt/clippy invocation;
  • target triples installed by CI;
  • Tauri CLI/build tooling that may impose its own Rust minimum;
  • Candle/ML optional feature dependencies;
  • workspace crates' actual MSRV requirements.

Produce a table:

Rust surface Edition Declared rust-version CI toolchain Clippy/rustfmt Targets Notes
src-tauri 2021 1.77.2
crates/*

No Rust crate should have an accidental different support policy.


Decide the MSRV policy first

Do NOT simply change:

1.77.2 → current stable

because that converts a minimum-compatibility statement into a build-version pin and needlessly raises the compiler floor.

First determine whether 1.77.2 is still a truthful supported MSRV.

Run a real MSRV proof using the exact committed dependency graph and the required feature sets.

At minimum:

cargo +1.77.2 check --locked
cargo +1.77.2 test --locked where dependency/tool support permits

for:

  • renderer-neutral Core workspace;
  • Tauri crate/default features;
  • security/storage-related crates;
  • relevant feature combinations;
  • optional rust-compute separately if its dependency MSRV differs.

If dependencies no longer support 1.77.2, classify the first actual blocker:

DIRECT_WORLD_SCRIPT_CODE
TAURI_RUNTIME
TAURI_PLUGIN
TRANSITIVE_DEPENDENCY
CORE_CRATE_DEPENDENCY
OPTIONAL_COMPUTE_FEATURE

Raise MSRV only to the minimum evidence-backed version required by the supported graph, not automatically to the latest stable release.


Introduce a deterministic build toolchain

After compatibility evidence, add a repository-owned Rust toolchain authority such as:

# rust-toolchain.toml
[toolchain]
channel = "<vetted exact stable release>"
profile = "minimal"
components = ["rustfmt", "clippy"]

The exact selected version must be re-derived at implementation time.

Current Rust 1.98.0 is a candidate for qualification, not a pre-decided pin merely because it is newest.

Required properties:

  • exact/reproducible version for developer + CI builds;
  • rustfmt and clippy from the same toolchain;
  • target components installed explicitly where required;
  • workflows do not independently float to unrelated stable versions;
  • release builds report toolchain identity in evidence/logs.

If the repository deliberately chooses a rolling stable build toolchain instead, document why that nondeterminism is worth the tradeoff and provide a canary strategy. The preferred default is a pinned stable version plus forward qualification.


Current-stable qualification lane

Separately run the Rust workspace against current upstream stable on an evidence-appropriate cadence.

Semantics:

PINNED_BUILD_TOOLCHAIN
= required merge/release authority

CURRENT_STABLE_QUALIFICATION
= advisory/scheduled forward-compatibility oracle

If upstream stable breaks WorldScript:

  • required builds remain deterministic on the pin;
  • open/classify the incompatibility;
  • do not silently update the pin in every workflow;
  • upgrade intentionally once fixed.

This reduces surprise when the pinned compiler is eventually advanced.


Pin-advance policy

Define when the pinned build toolchain should move forward.

Suggested gate for each pin advance:

cargo check --locked
cargo test --locked
cargo fmt --check
cargo clippy with repository warning policy
Tauri Rust gate
Core Rust gate
packaged native build smoke where relevant
security/OSV Cargo lock scan

Also record:

old pin
new pin
MSRV unchanged/raised
reason
new warnings/lints
binary/build-size change where material

Do not combine a compiler pin jump with unrelated Core authority changes unless one genuinely depends on the other.


Clippy policy

Compiler upgrades often surface new Clippy lints.

Treat them as:

NEW_REAL_DEFECT
STYLE/IDIOM IMPROVEMENT
FALSE_POSITIVE / INTENTIONAL PATTERN
TOOLCHAIN_TRANSITION_ONLY

Do not globally add broad allow(...) attributes merely to make a new compiler pass.

Any new suppression must have a narrow rationale and respect existing suppression-debt policy.


Cargo.lock and resolver behavior

A Rust toolchain change must not opportunistically update the entire Cargo dependency graph unless required.

Use --locked for compatibility and CI evidence.

If the new compiler requires dependency movement:

  1. prove why;
  2. split dependency modernization if substantial;
  3. run OSV/SCA against both src-tauri/Cargo.lock and crates/Cargo.lock;
  4. preserve causal reviewability.

Coordinate dependency-provenance/security work with #529/#448 rather than duplicating it.


Tauri/Core distinction

The renderer-neutral Core workspace and transitional Tauri shell should consume the same toolchain policy, but their supported dependency graphs may impose different MSRVs.

If so, explicitly choose one of:

UNIFIED_MSRV = max(required Core, required Tauri)

or

SEPARATE_PUBLISHED_MSRV
= only if there is a real distribution/reuse reason

Do not let this become accidental divergence.

Because Qt will later consume Rust Core, prefer a Core toolchain contract that is not defined by incidental WebKit/Tauri implementation details.


Edition policy

Do not migrate Rust edition simply because a newer edition exists.

Audit whether edition 2021 remains appropriate or whether an edition migration has concrete value/requirements. If a future edition migration produces broad source churn, track it separately from toolchain pinning/MSRV establishment.

No edition bump is required to close this issue unless evidence says otherwise.


Release/build evidence

For packaged native builds record at minimum:

rustc --version --verbose
cargo --version
target triple
Tauri crate/CLI versions
Cargo.lock digest or commit SHA

This helps correlate future platform regressions with actual toolchain movement.

Coordinate packaging/platform evidence with #332 and #507.


CI efficiency relationship

#550 owns cost/latency.

This issue may introduce an MSRV/current-stable qualification lane, but #550 may later choose a scheduled cadence or path-awareness once support evidence exists.

Do not drop MSRV/current-stable evidence solely to save runner minutes.


Rollback

A build-toolchain pin advance must be reversible by reverting the toolchain file/config while leaving user data/application formats untouched.

If a newer compiler exposes a real undefined/incorrect application behavior, fix the defect rather than indefinitely pinning old Rust without an owner.


Acceptance criteria

  • Every Rust manifest/workflow/toolchain authority is inventoried.
  • DECLARED_MSRV, PINNED_BUILD_TOOLCHAIN, and CURRENT_STABLE_QUALIFICATION are explicitly distinguished.
  • The current rust-version = 1.77.2 claim is actually tested or deliberately raised to the minimum evidence-backed supported version.
  • No MSRV is raised merely to equal current stable.
  • A repository-owned deterministic build toolchain is established, preferably via rust-toolchain.toml or an equivalently singular authority.
  • rustfmt/clippy use the same pinned toolchain.
  • Normal CI/release workflows do not independently float Rust versions.
  • Current upstream stable receives a forward-compatibility qualification lane/cadence.
  • Core and Tauri MSRV/toolchain relationships are explicit.
  • Pin advancement has a documented check/test/clippy/packaging/security gate.
  • Cargo dependency graph changes remain separately reviewable where material.
  • Packaged native evidence reports exact Rust toolchain identity.
  • No Qt implementation or Core feature migration is bundled merely to establish toolchain policy.

Non-goals

  • raising MSRV to Rust 1.98 just because it is current;
  • moving more application logic into Rust;
  • starting Qt implementation;
  • performing a broad Rust edition/source-style migration;
  • updating all Cargo dependencies without cause;
  • weakening Clippy/security checks to accept a newer compiler;
  • defining Core architecture inside a toolchain issue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions