diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..0512f8f --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,52 @@ +name: Lint + +on: + pull_request: + push: + branches: [main] + +concurrency: + group: lint-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + format: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + # No `toolchain:` input — the action reads `rust-toolchain.toml`, so the + # pinned version lives in exactly ONE place. + components: rustfmt, clippy + - run: cargo fmt --all --check + + clippy: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + # No `toolchain:` input — the action reads `rust-toolchain.toml`, so the + # pinned version lives in exactly ONE place. + components: rustfmt, clippy + - uses: Swatinem/rust-cache@v2 + - run: cargo clippy --all-targets -- -D warnings + + test: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + # No `toolchain:` input — the action reads `rust-toolchain.toml`, so the + # pinned version lives in exactly ONE place. + components: rustfmt, clippy + - uses: Swatinem/rust-cache@v2 + - run: cargo test --workspace diff --git a/CLAUDE.md b/CLAUDE.md index 5b6d1d4..c77cc8e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -162,11 +162,16 @@ scales out before P-REHOST is green. ## Build ```sh -cargo +1.97.1 test # workspace = edition 2024 / rust 1.97.1 (matches OGAR) -cargo +1.97.1 clippy --all-targets -- -D warnings -cargo +1.97.1 fmt --check +cargo test # workspace = edition 2024 / rust 1.98.1 (matches OGAR) +cargo clippy --all-targets -- -D warnings +cargo fmt --check ``` +The pin lives in `rust-toolchain.toml` — a bare `cargo` in this checkout +resolves to it, so these invocations deliberately carry no `+` +prefix: that prefix would be a second source of truth for the toolchain +version, exactly what `rust-toolchain.toml` exists to make unnecessary. + ## Git — token-safe push (hard-won lesson, do not relearn) Outbound is a policy proxy. The `local_proxy@127.0.0.1:` remote allows diff --git a/Dockerfile.railway b/Dockerfile.railway index b827a82..f0b0a27 100644 --- a/Dockerfile.railway +++ b/Dockerfile.railway @@ -21,10 +21,10 @@ # because as a workspace member any path dep breaks every cargo invocation # in their CI. No lance, no DataFusion, no arrow arrives here. # -# 2. "raises the toolchain floor [to 1.97.1]" — ALSO FALSE, and the more +# 2. "raises the toolchain floor [to 1.98.1]" — ALSO FALSE, and the more # interesting error. Measured: `cargo +1.95.0 build -p a2ui-paint-web` # compiles `lance-graph-contract` from scratch and passes all 8 tests. -# The 1.97.1 came from lance-graph's `rust-toolchain.toml`, which is THAT +# The 1.98.1 came from lance-graph's `rust-toolchain.toml`, which is THAT # REPO'S OWN build pin — cargo does not read a dependency's toolchain file, # so it never propagates to a consumer. An MSRV that binds you is # `rust-version` in the dependency's manifest, and that crate declares @@ -44,18 +44,18 @@ # renderer needs; wgpu only adds the surface draw, which belongs in the # browser, not in this container. Do NOT add `--features wgpu`. # -# TOOLCHAIN — 1.97.1 by ALIGNMENT, not by necessity. CLAUDE.md documents -# `cargo +1.97.1` as this workspace's toolchain, so the image uses it and one +# TOOLCHAIN — 1.98.1 by ALIGNMENT, not by necessity. CLAUDE.md documents +# `cargo +1.98.1` as this workspace's toolchain, so the image uses it and one # version holds everywhere. What this pin is NOT is a floor: the crate declares # `rust-version = "1.95"` and genuinely builds and tests green on 1.95.0 with # every dependency present (measured, see the CORRECTION above). A newer # toolchain always works, so alignment is free — but do not cite this line as -# evidence that something requires 1.97.1. If the floor ever really does rise, +# evidence that something requires 1.98.1. If the floor ever really does rise, # it will show up as a `rust-version` bump in a manifest, and THAT is the thing # to move in lockstep with this pin. # --------------------------------------------------------------------------- -ARG RUST_VERSION=1.97.1 +ARG RUST_VERSION=1.98.1 ARG BIN_NAME=a2ui-paint-web # ── builder ──────────────────────────────────────────────────────────────── diff --git a/Dockerfile.solid.railway b/Dockerfile.solid.railway index b98740f..753b7de 100644 --- a/Dockerfile.solid.railway +++ b/Dockerfile.solid.railway @@ -30,13 +30,13 @@ # polygons. Vector out, no raster, no canvas, no `wgpu`. Railway containers # have no GPU and this tier does not want one. # -# TOOLCHAIN — 1.97.1 by ALIGNMENT, not necessity, exactly as in the paint +# TOOLCHAIN — 1.98.1 by ALIGNMENT, not necessity, exactly as in the paint # image. The crates declare `rust-version = "1.95"` and build green there; the # pin matches the toolchain CLAUDE.md documents so one version holds across the -# workspace. Do not cite this line as evidence that something requires 1.97.1. +# workspace. Do not cite this line as evidence that something requires 1.98.1. # --------------------------------------------------------------------------- -ARG RUST_VERSION=1.97.1 +ARG RUST_VERSION=1.98.1 ARG BIN_NAME=a2ui-solid-web # ── builder ──────────────────────────────────────────────────────────────── diff --git a/crates/a2ui-graph/src/gpu.rs b/crates/a2ui-graph/src/gpu.rs index d0c1d09..ff03d85 100644 --- a/crates/a2ui-graph/src/gpu.rs +++ b/crates/a2ui-graph/src/gpu.rs @@ -665,7 +665,9 @@ mod tests { .expect("device poll"); let data = slice.get_mapped_range().expect("readback mapped"); let painted = data - .chunks_exact(4) + .as_chunks::<4>() + .0 + .iter() .filter(|p| p[0] | p[1] | p[2] != 0) .count(); diff --git a/crates/a2ui-graph/src/radial.rs b/crates/a2ui-graph/src/radial.rs index d117ee5..3cd454e 100644 --- a/crates/a2ui-graph/src/radial.rs +++ b/crates/a2ui-graph/src/radial.rs @@ -731,8 +731,10 @@ mod tests { assert_eq!(&p.mereology[..4], &mer, "the correct read"); let naive: Vec = raw[..12] - .chunks_exact(2) - .map(|c| u16::from_le_bytes([c[0], c[1]])) + .as_chunks::<2>() + .0 + .iter() + .map(|c| u16::from_le_bytes(*c)) .collect(); assert_eq!( naive[0], 258, diff --git a/docs/WASM-INTEGRATION.md b/docs/WASM-INTEGRATION.md index 5f2cf3a..9040ceb 100644 --- a/docs/WASM-INTEGRATION.md +++ b/docs/WASM-INTEGRATION.md @@ -55,7 +55,7 @@ checks the four preconditions that otherwise fail silently or confusingly: ```bash RUSTFLAGS='-C target-feature=+simd128' \ - cargo +1.97.1 build -p a2ui-graph \ + cargo +1.98.1 build -p a2ui-graph \ --target wasm32-unknown-unknown --release wasm-bindgen --target web --out-dir pkg \ @@ -91,7 +91,7 @@ regenerated from the crate, never a source of truth. | `wasm-bindgen` CLI version == `Cargo.lock` pin | glue for a different ABI; surfaces at runtime, in a browser | | `wasm32-unknown-unknown` installed **for that toolchain** | `can't find crate for core` — reads like a broken install, is a one-line fix | | `FieldHandle` symbol present in the module | the client was linked out; see §"The two silent failures" | -| toolchain pin (`1.97.1`, override with `RUST_TOOLCHAIN`) | a bare `cargo` names two different rust-version floors and no fix | +| toolchain pin (`1.98.1`, override with `RUST_TOOLCHAIN`) | a bare `cargo` names two different rust-version floors and no fix | Targets are **per-toolchain**, which is why the second one exists: switching toolchains loses the target, and the resulting error names neither. diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..a1a2759 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,50 @@ +[toolchain] +channel = "1.98.1" +# The pinned version is the `channel` line ABOVE — deliberately not restated +# in this comment, so a future bump touches one line rather than editing +# prose that then drifts. (lance-graph's rust-toolchain.toml explains the +# same reasoning; every sibling repo in this stack — lance-graph, OGAR, +# tesseract-rs, stockfish-rs, ruff — follows this shape.) +# +# This file did not exist before this pin. Before it, a2ui-rs carried the +# toolchain only as PROSE — CLAUDE.md's `cargo +1.97.1 test/clippy/fmt`, +# docs/WASM-INTEGRATION.md, scripts/build-graph-wasm.sh's `RUST_TOOLCHAIN` +# default, and the two Dockerfiles' `ARG RUST_VERSION` — with no +# `.github/workflows/` at all in this repo to enforce any of it. That is +# exactly the drift shape this file exists to close: a bare `cargo` in this +# checkout now resolves to the reviewed toolchain without a human copying a +# version string across five files by hand. +# +# `rust-version = "1.95"` in Cargo.toml remains the crate's own declared +# MSRV floor and is untouched by this file — this channel is an alignment +# choice with the sibling repos, same as the Dockerfiles already document +# ("by ALIGNMENT, not by necessity"). Note the ndarray fork's OWN manifest +# now declares `rust-version = "1.98"` (verified in the sibling checkout), +# so 1.95 no longer reliably builds this workspace's `ndarray` git +# dependency regardless of this file's channel — a separate, pre-existing +# gap this bump does not attempt to close (see CLAUDE.md / this session's +# report for detail). +# +# Bump log (append one line per bump): +# (no file) → 1.98.1 added the file + bumped from the prose-only 1.97.1 +# pin in one step, joining the workspace-wide 1.98 sweep +# already landed in lance-graph / OGAR / stockfish-rs / +# ruff. Delta measured in THIS repo via +# `cargo clippy --all-targets -- -D warnings`: 2 findings, +# both `clippy::chunks_exact_to_as_chunks` (new in 1.98, +# default-on STYLE group) — `crates/a2ui-graph/src/ +# radial.rs` and `crates/a2ui-graph/src/gpu.rs`, both +# test-only `chunks_exact(N)` calls, fixed to +# `.as_chunks::().0`. No `#![allow(...)]`/ +# `#![expect(...)]` list carried the removed +# `clippy::from_iter_instead_of_collect`. `cargo test` +# and `cargo fmt --check` were both clean before and +# after the fix. +# +# Never auto-track `stable` — bump explicitly when a future version is +# reviewed and the workspace's fmt/clippy/test gates pass clean. +# +# rustfmt + clippy ride the pin so a fresh `rustup show` in this workspace +# materializes the complete CI-equivalent toolchain in one step (same +# rationale lance-graph's file states in full). +components = ["rustfmt", "clippy"] diff --git a/scripts/build-graph-wasm.sh b/scripts/build-graph-wasm.sh index d096c57..e60d456 100755 --- a/scripts/build-graph-wasm.sh +++ b/scripts/build-graph-wasm.sh @@ -28,12 +28,12 @@ cd "$(dirname "$0")/.." OUT="${1:-crates/a2ui-graph/pkg}" WASM=target/wasm32-unknown-unknown/release/a2ui_graph.wasm -# The workspace toolchain. 1.97.1 by ALIGNMENT — Dockerfile.railway documents +# The workspace toolchain. 1.98.1 by ALIGNMENT — Dockerfile.railway documents # it as this workspace's toolchain, and the ndarray fork's own manifest now -# requires 1.97, so a bare `cargo` (whatever the default happens to be) fails +# requires 1.98, so a bare `cargo` (whatever the default happens to be) fails # with a rust-version error that names two different floors and no fix. -# Override for a one-off: `RUST_TOOLCHAIN=1.98 ./scripts/build-graph-wasm.sh`. -TOOLCHAIN="${RUST_TOOLCHAIN:-1.97.1}" +# Override for a one-off: `RUST_TOOLCHAIN=1.99 ./scripts/build-graph-wasm.sh`. +TOOLCHAIN="${RUST_TOOLCHAIN:-1.98.1}" # ── 1. The CLI must match the crate ──────────────────────────────────────── # wasm-bindgen's generated glue is tied to the exact version of the crate