From 6d4b1a2e5b889240957e41fd0d00b99b84f55767 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 5 Sep 2026 20:02:24 +0000 Subject: [PATCH 1/5] Add first CI lint gate (fmt + clippy + test), pin Rust 1.98.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This repo has never had a .github/workflows/ directory. Adds .github/workflows/lint.yml with three jobs scoped to native/lgj-abi (the only Cargo crate in the repo; the Java side has no build system at all — see java/README.md, "no Maven, no Gradle"): - format: cargo fmt --check - clippy: cargo clippy --all-targets -- -D warnings - rust-test: cargo test --all-targets, which runs tests/g11_contract_import_fence.rs — the structural enforcement of the G11 contract-import allowlist that CLAUDE.md's own history notes was "prose until 2026-09-03" because nothing ran the test that proves it. lgj-abi path-deps ndarray, lance-graph's lance-graph-contract, and (optionally, off by default) OGAR's ogar-class-view. Cargo resolves the full dependency graph including inactive optional path deps, so all three siblings are checked out for clippy/rust-test, mirroring AdaWorldAPI/lance-graph's own .github/workflows/style.yml pattern exactly (self into a named subdir, each sibling into its own subdir under the same workspace root). Also adds rust-toolchain.toml pinning channel = 1.98.1 with rustfmt + clippy components, joining the workspace-wide 1.98.1 sweep already carried by the ndarray / lance-graph / OGAR sibling repos. The workflow's setup-rust-toolchain step takes no toolchain: input, so this file is the single source of truth for the pinned version. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01AGVLyRZNEKKBSfBDJfbY3V --- .github/workflows/lint.yml | 118 +++++++++++++++++++++++++++++++++++++ rust-toolchain.toml | 17 ++++++ 2 files changed, 135 insertions(+) create mode 100644 .github/workflows/lint.yml create mode 100644 rust-toolchain.toml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..859ce84 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,118 @@ +name: Lint + +on: + pull_request: + push: + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +# Least-privilege: these jobs only read the repo (checkout + build + lint). +permissions: + contents: read + +env: + CARGO_TERM_COLOR: always + +jobs: + # lgj-abi path-deps ndarray and lance-graph-contract (crates/lance-graph-contract + # in the AdaWorldAPI/lance-graph sibling), and optionally (feature `ogar-classview`, + # off by default) ogar-class-view in the AdaWorldAPI/OGAR sibling. Cargo resolves + # the full dependency graph — including inactive optional path deps — so all three + # siblings must exist on disk even though only two are compiled into the default + # build. Checked out under the runner's top-level workspace, sibling to this repo's + # own checkout, exactly as `../../../` from native/lgj-abi/Cargo.toml expects + # (matches AdaWorldAPI/lance-graph's own .github/workflows/style.yml pattern). + format: + runs-on: ubuntu-latest + timeout-minutes: 15 + defaults: + run: + working-directory: lance-graph-java + steps: + - uses: actions/checkout@v4 + with: + path: lance-graph-java + - 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 + - name: Check formatting (lgj-abi) + run: cargo fmt --manifest-path native/lgj-abi/Cargo.toml -- --check + + clippy: + runs-on: ubuntu-latest + timeout-minutes: 30 + defaults: + run: + working-directory: lance-graph-java + steps: + - uses: actions/checkout@v4 + with: + path: lance-graph-java + - name: Checkout AdaWorldAPI/ndarray (sibling dependency) + uses: actions/checkout@v4 + with: + repository: AdaWorldAPI/ndarray + path: ndarray + - name: Checkout AdaWorldAPI/lance-graph (sibling dependency, lance-graph-contract) + uses: actions/checkout@v4 + with: + repository: AdaWorldAPI/lance-graph + path: lance-graph + - name: Checkout AdaWorldAPI/OGAR (sibling dependency, optional ogar-classview feature) + uses: actions/checkout@v4 + with: + repository: AdaWorldAPI/OGAR + path: OGAR + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + components: rustfmt, clippy + - uses: Swatinem/rust-cache@v2 + with: + workspaces: lance-graph-java/native/lgj-abi + - name: Clippy lgj-abi + run: cargo clippy --manifest-path native/lgj-abi/Cargo.toml --all-targets -- -D warnings + + rust-test: + runs-on: ubuntu-latest + timeout-minutes: 30 + defaults: + run: + working-directory: lance-graph-java + steps: + - uses: actions/checkout@v4 + with: + path: lance-graph-java + - name: Checkout AdaWorldAPI/ndarray (sibling dependency) + uses: actions/checkout@v4 + with: + repository: AdaWorldAPI/ndarray + path: ndarray + - name: Checkout AdaWorldAPI/lance-graph (sibling dependency, lance-graph-contract) + uses: actions/checkout@v4 + with: + repository: AdaWorldAPI/lance-graph + path: lance-graph + - name: Checkout AdaWorldAPI/OGAR (sibling dependency, optional ogar-classview feature) + uses: actions/checkout@v4 + with: + repository: AdaWorldAPI/OGAR + path: OGAR + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + components: rustfmt, clippy + - uses: Swatinem/rust-cache@v2 + with: + workspaces: lance-graph-java/native/lgj-abi + # Runs every #[test] in lgj-abi, including tests/g11_contract_import_fence.rs + # — the fence CLAUDE.md's "Enforcement" section names as structural: it walks + # src/ and rejects any `lance_graph_contract::` module outside the four-name + # allowlist. Per this repo's own history, "G11 was prose until 2026-09-03" + # because nothing ran the test that enforces it; this job is what runs it. + - name: Test lgj-abi + run: cargo test --manifest-path native/lgj-abi/Cargo.toml --all-targets diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..3bed53b --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,17 @@ +[toolchain] +channel = "1.98.1" +# The pinned version is the `channel` line ABOVE — not restated in this +# comment, so a future bump edits one line and leaves the log below intact +# (the ndarray/lance-graph/OGAR sibling repos already learned this the hard +# way: restating the version in prose is what makes the prose wrong). +# +# Bump log (append one line per bump): +# (none) → 1.98.1 2026-09-05: this repo's first pin, joining the +# workspace-wide 1.98.1 sweep already carried by +# ndarray / lance-graph / OGAR. +# +# rustfmt + clippy are mandatory CI components and must ship with the +# pinned channel — `actions-rust-lang/setup-rust-toolchain@v1` reads this +# file for the toolchain (no `toolchain:` input in the workflow), so the +# pin lives in exactly ONE place. +components = ["rustfmt", "clippy"] From 893cc92854c880b46024532921b5e7ebe7c4b3cd Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 5 Sep 2026 20:03:37 +0000 Subject: [PATCH 2/5] Board hygiene: PR #77 entry (CI lint gate + Rust 1.98.1 pin) Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01AGVLyRZNEKKBSfBDJfbY3V --- .claude/board/LATEST_STATE.md | 40 +++++++++++++++++++++++++++++++ .claude/board/PR_ARC_INVENTORY.md | 34 ++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/.claude/board/LATEST_STATE.md b/.claude/board/LATEST_STATE.md index b832cf3..8d7bbb2 100644 --- a/.claude/board/LATEST_STATE.md +++ b/.claude/board/LATEST_STATE.md @@ -1,3 +1,43 @@ +## 2026-09-05 — first CI lint gate: fmt + clippy + rust-test, Rust pinned to 1.98.1 + +**Branch `claude/ci-lint-gate`, PR #77.** This repo has never had a +`.github/workflows/` directory — every gate documented in `CLAUDE.md` (the +G11 contract-import fence, the epoch-recheck falsifiers, `ApiSurfaceTest`, +the L1/L2 semantic-leak pins) has only ever run when a session happened to +invoke `cargo test` by hand. Adds `.github/workflows/lint.yml`, three jobs +scoped to `native/lgj-abi` (the repo's only Cargo crate): `format` +(`cargo fmt --check`), `clippy` (`--all-targets -- -D warnings`), and +`rust-test` (`--all-targets`, which is what finally makes +`tests/g11_contract_import_fence.rs` run anywhere but a session's own shell — +the same gap `CLAUDE.md` names for G11 itself: "prose until 2026-09-03" +because nothing ran the test that enforces it). + +`lgj-abi` path-deps `ndarray`, `lance-graph`'s `lance-graph-contract`, and +(optional, off by default) `OGAR`'s `ogar-class-view`. Cargo resolves the +full graph including inactive optional path deps, so `clippy`/`rust-test` +check out all three siblings — the identical shape `lance-graph`'s own +`style.yml` already uses (self + each sibling into its own named +subdirectory under one runner workspace root). + +Also adds `rust-toolchain.toml` (this repo had none) pinning +`channel = "1.98.1"`, joining the sweep `ndarray`/`lance-graph`/`OGAR` +already carry. `setup-rust-toolchain@v1` is invoked with no `toolchain:` +input, so the pin has exactly one spelling. + +**Java is deliberately out of scope.** `java/` holds only `README.md` + +`.gitignore` — no Maven, no Gradle, no source. The README says so directly +("no Maven, no Gradle... `javac` and `java` are the entire Java toolchain"). +Nothing to wire a CI job against yet; filed as a named follow-up rather than +guessed at. + +**Not measured in this PR:** whether `clippy --all-targets -- -D warnings` +is actually clean on `lgj-abi` today. Disk constraints (a large dependency +tree through the contract crate) ruled out a local `cargo build`/`clippy` +run, so this PR's own CI run is the first real measurement — if it comes +back red on pre-existing debt, the follow-up is this workspace's own tiered +posture (`continue-on-error: true` + a named `TECH_DEBT.md` line), not a +bundled auto-fix. + ## 2026-09-04 — lgj_hop: the conjunction is one truth-table pass, and the lane is read as a lane (5×) **Branch `claude/pr-294-ragged-path-validation-170zcy`**, lgj-abi only — no diff --git a/.claude/board/PR_ARC_INVENTORY.md b/.claude/board/PR_ARC_INVENTORY.md index 1f5f12f..cf80cdb 100644 --- a/.claude/board/PR_ARC_INVENTORY.md +++ b/.claude/board/PR_ARC_INVENTORY.md @@ -8,6 +8,40 @@ > anti-pattern the imported board rules name. Backfilled below in one > pass rather than left stale; PR #4 onward gets its entry at merge time. +## PR #77 — first CI lint gate: fmt + clippy + rust-test, Rust pinned to 1.98.1 (opened 2026-09-05, head `6d4b1a2`) + +**Added.** `.github/workflows/lint.yml` (three jobs: `format`, `clippy`, +`rust-test`, all scoped to `native/lgj-abi` via `--manifest-path`); +`rust-toolchain.toml` pinning `channel = "1.98.1"` + `rustfmt`/`clippy` +components (this repo had neither a workflow directory nor a toolchain pin +before this PR). + +**Locked.** The G11 contract-import fence (`tests/g11_contract_import_fence.rs`) +now runs on every push/PR via `rust-test`, closing the exact gap +`CLAUDE.md` names for G11 itself ("prose until 2026-09-03" — a rule +enforced by a test nothing ever ran). `clippy`/`rust-test` check out all +three path-dep siblings (`ndarray`, `lance-graph`, `OGAR`) because Cargo +resolves the full dependency graph including the inactive optional +`ogar-classview` feature's path dep — mirroring `lance-graph`'s own +`style.yml` checkout shape exactly. + +**Deferred.** A Java CI job — `java/` has no build system at all (no +Maven, no Gradle, no source), per its own README; wiring a job against a +build system that doesn't exist would guess at a command with nothing to +verify it against. Whether `-D warnings` is clean on `lgj-abi` today is +also unmeasured locally (disk constraints); this PR's own CI run is the +first real measurement, with the tiered `continue-on-error` + +`TECH_DEBT.md` fallback named in the PR body if it comes back red on +pre-existing debt. + +**Docs.** `LATEST_STATE.md` entry; this entry. + +**Confidence.** High that the workflow shape is correct (it is a direct +transplant of `lance-graph`'s own proven `style.yml` checkout pattern, +adapted to this repo's single-crate layout). Unmeasured whether the +`clippy`/`rust-test` jobs pass clean on first run — that is what the CI +run itself is for. + ## PR #68 — mask-risc-lowering v1 → v4: SPEC completion, the 5+3 council, voxelmasking (merged 2026-09-03 as `dfb4ab1`, head `4ad9377`) **Added.** Four commits on `.claude/plans/mask-risc-lowering-v1.md`, plan-only — no kernel, no ABI symbol, no mint, no production code. `51dcffc` completed SPEC v1 to the council bar (non-goals, pre-registered gates G1–G8, per-savant question sets); `00570a0` draft v2 (5 savants, 40 findings, 24 amendments); `0212d21` ratified v3 (3 reviewers, 2 BLOCK + 14 FIX, 2 external Codex P1s); `4ad9377` the v4 amendment — §14 voxelmasking, §3c reuse map, §15 two probes. `STATUS_BOARD` rows `D-MRL-0f` and `D-MRL-0g`. From 1ea5c85e35e0b008438bde5a1ed854f7c533285f Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 5 Sep 2026 20:21:00 +0000 Subject: [PATCH 3/5] Make the gate actually run the crate, and pin the toolchain once The first CI run of this gate went red, and both causes are the same shape: something is declared twice and cargo silently picks whichever copy is nearest the working directory. A `rust-toolchain.toml` was added at the repository root carrying the sentence "the pin lives in exactly ONE place", while `native/lgj-abi/rust-toolchain.toml` already existed pinning 1.97.1. The root file is removed and the crate-level file is the authority, bumped to 1.98.1. That bump is forced rather than cosmetic: ndarray 0.17.2 now declares `rust-version = "1.98"`, so a 1.97.1 resolve of this crate fails outright. The failing test is the more interesting half. `native/lgj-abi/.cargo/config.toml` pins `-Ctarget-cpu=x86-64-v4`, and `the_x86_64_build_has_a_vector_baseline` exists to turn a lost baseline into a legible test failure instead of a SIGILL inside a JVM downcall. The jobs ran cargo from the repository root with `--manifest-path` pointing into the crate, and cargo reads `.cargo/config.toml` from the working directory's ancestry, never from the manifest's directory. The baseline was never applied, the manifest reported the scalar backend, and the test fired exactly as designed. `--manifest-path` is not equivalent to running in the crate directory. So the jobs now set `working-directory` to the crate, and CI exports `CARGO_BUILD_RUSTFLAGS=-Ctarget-cpu=x86-64-v3` on top: GitHub-hosted runners do not guarantee AVX-512, and a v4 build would die on them with the very fault that config comment describes. v3 still satisfies the test's `AVX2 | AVX512` assertion, so the gate is retargeted, not weakened. Verified on both sides locally: the old invocation reproduces the failure, the new one passes 138 unit tests plus the G11 contract-import fence, with `cargo fmt -- --check` and `cargo clippy --all-targets -- -D warnings` clean. Board: EPIPHANIES gains the finding; LATEST_STATE gains a storno correcting two claims in the entry this PR wrote an hour ago. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01AGVLyRZNEKKBSfBDJfbY3V --- .claude/board/EPIPHANIES.md | 42 ++++++++++++++++++++++++++++++ .claude/board/LATEST_STATE.md | 20 ++++++++++++++ .github/workflows/lint.yml | 21 ++++++++++----- native/lgj-abi/rust-toolchain.toml | 16 +++++++++++- rust-toolchain.toml | 17 ------------ 5 files changed, 92 insertions(+), 24 deletions(-) delete mode 100644 rust-toolchain.toml diff --git a/.claude/board/EPIPHANIES.md b/.claude/board/EPIPHANIES.md index 131162f..d502f38 100644 --- a/.claude/board/EPIPHANIES.md +++ b/.claude/board/EPIPHANIES.md @@ -1,3 +1,45 @@ +## E-THE-PIN-THAT-CLAIMED-ONE-PLACE-CREATED-A-SECOND-1 (2026-09-05) + +**Finding.** The first CI gate this repo ever had went red on its first +run, and the two causes were both "the same thing is declared twice, and +cargo silently picks the nearer one." + +`rust-toolchain.toml` was added at the repository root carrying the +sentence *"the pin lives in exactly ONE place"* — while +`native/lgj-abi/rust-toolchain.toml` already existed, pinning `1.97.1`. +Cargo reads whichever file is nearest the working directory, so the root +file governed a command run from the root and the crate file governed a +command run from the crate. Two files, one toolchain, disagreeing by where +you happened to stand. The root file is removed; the crate file is the +authority, bumped to `1.98.1`, and it sits beside `.cargo/config.toml`, +which cargo resolves the same way. + +That bump is forced, not cosmetic: `ndarray` 0.17.2 now declares +`rust-version = "1.98"`, so a 1.97.1 resolve of this crate fails outright. +The same upstream move turned every MSRV job in `AdaWorldAPI/tract` red on +the same afternoon. + +**The second cause is the more interesting one, because a test caught it.** +`native/lgj-abi/.cargo/config.toml` pins `-Ctarget-cpu=x86-64-v4`, and +`abi::tests::the_x86_64_build_has_a_vector_baseline` exists to turn a lost +baseline into a test failure instead of a SIGILL inside a JVM downcall. +The workflow ran cargo from the repository root with `--manifest-path` +pointing into the crate — and **cargo reads `.cargo/config.toml` from the +working directory's ancestry, never from the manifest's directory.** The +baseline was therefore never applied, the manifest reported the scalar +backend, and the test fired exactly as designed. `--manifest-path` is not +equivalent to running in the crate directory, and this is the failure that +proves it. + +**Consequence.** The jobs now run with `working-directory` set to the +crate, and CI additionally exports `CARGO_BUILD_RUSTFLAGS=-Ctarget-cpu= +x86-64-v3`, because GitHub-hosted runners do not guarantee AVX-512 and a +v4 build would die on them with the very SIGILL that config comment +describes. v3 still satisfies the test's `AVX2 | AVX512` assertion, so the +gate is retargeted rather than weakened. Verified locally on both sides: +the old invocation reproduces the failure, the new one passes 138 tests +plus the G11 fence, with fmt and clippy clean. + ## E-THE-GUARD-YOU-WIRE-IS-NOT-THE-GUARD-YOU-NAMED-1 (2026-08-28) **Finding.** A wave chartered as "wire the epoch re-check" cannot deliver diff --git a/.claude/board/LATEST_STATE.md b/.claude/board/LATEST_STATE.md index 8d7bbb2..0f33359 100644 --- a/.claude/board/LATEST_STATE.md +++ b/.claude/board/LATEST_STATE.md @@ -1,3 +1,23 @@ +## 2026-09-05 — storno: the gate's own first run corrected two claims above + +Corrects the entry immediately below, which is left in place per the +storno rule. Two of its statements were wrong when written: + +- *"adds `rust-toolchain.toml` (this repo had none)"* — one already + existed at `native/lgj-abi/rust-toolchain.toml`, pinning `1.97.1`. +- *"the pin has exactly one spelling"* — adding the root file made two, + and cargo reads whichever is nearest the working directory. + +The root file is removed and the crate-level file is bumped to `1.98.1` +(forced: `ndarray` 0.17.2 declares `rust-version = "1.98"`). The three +jobs now run with `working-directory` set to the crate rather than +`--manifest-path` from the root, because `.cargo/config.toml` is read +from the working directory's ancestry and the v4 target-cpu baseline was +being dropped — which is what `the_x86_64_build_has_a_vector_baseline` +caught on the gate's first run. CI exports the v3 baseline explicitly, +since GitHub-hosted runners do not guarantee AVX-512. Full account: +`EPIPHANIES.md` `E-THE-PIN-THAT-CLAIMED-ONE-PLACE-CREATED-A-SECOND-1`. + ## 2026-09-05 — first CI lint gate: fmt + clippy + rust-test, Rust pinned to 1.98.1 **Branch `claude/ci-lint-gate`, PR #77.** This repo has never had a diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 859ce84..20cba24 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,6 +16,15 @@ permissions: env: CARGO_TERM_COLOR: always + # `native/lgj-abi/.cargo/config.toml` pins `-Ctarget-cpu=x86-64-v4` + # (AVX-512) because the production artifact is built for one known host. + # GitHub-hosted runners do not guarantee AVX-512, so a v4 build would emit + # instructions the runner cannot execute and die with SIGILL — the exact + # fault that config's own comment describes. It names the remedy for a + # machine without AVX-512: override the baseline at build time with v3. + # AVX2 is what `the_x86_64_build_has_a_vector_baseline` requires, so the + # test still proves a vector baseline exists rather than being weakened. + CARGO_BUILD_RUSTFLAGS: -Ctarget-cpu=x86-64-v3 jobs: # lgj-abi path-deps ndarray and lance-graph-contract (crates/lance-graph-contract @@ -31,7 +40,7 @@ jobs: timeout-minutes: 15 defaults: run: - working-directory: lance-graph-java + working-directory: lance-graph-java/native/lgj-abi steps: - uses: actions/checkout@v4 with: @@ -42,14 +51,14 @@ jobs: # pinned version lives in exactly ONE place. components: rustfmt, clippy - name: Check formatting (lgj-abi) - run: cargo fmt --manifest-path native/lgj-abi/Cargo.toml -- --check + run: cargo fmt -- --check clippy: runs-on: ubuntu-latest timeout-minutes: 30 defaults: run: - working-directory: lance-graph-java + working-directory: lance-graph-java/native/lgj-abi steps: - uses: actions/checkout@v4 with: @@ -76,14 +85,14 @@ jobs: with: workspaces: lance-graph-java/native/lgj-abi - name: Clippy lgj-abi - run: cargo clippy --manifest-path native/lgj-abi/Cargo.toml --all-targets -- -D warnings + run: cargo clippy --all-targets -- -D warnings rust-test: runs-on: ubuntu-latest timeout-minutes: 30 defaults: run: - working-directory: lance-graph-java + working-directory: lance-graph-java/native/lgj-abi steps: - uses: actions/checkout@v4 with: @@ -115,4 +124,4 @@ jobs: # allowlist. Per this repo's own history, "G11 was prose until 2026-09-03" # because nothing ran the test that enforces it; this job is what runs it. - name: Test lgj-abi - run: cargo test --manifest-path native/lgj-abi/Cargo.toml --all-targets + run: cargo test --all-targets diff --git a/native/lgj-abi/rust-toolchain.toml b/native/lgj-abi/rust-toolchain.toml index 652fcca..f19a0b1 100644 --- a/native/lgj-abi/rust-toolchain.toml +++ b/native/lgj-abi/rust-toolchain.toml @@ -2,5 +2,19 @@ # Stable only. Matches ndarray / lance-graph / the rest of the AdaWorldAPI # stack. No nightly features anywhere in this crate — in particular no # `core::simd` / portable-simd (abi.md §8). -channel = "1.97.1" +channel = "1.98.1" components = ["clippy", "rustfmt"] + +# Bump log (append one line per bump; the version itself is the `channel` +# line above and is deliberately not restated here): +# 1.97.1 → 1.98.1 2026-09-05: joins the workspace-wide sweep already +# carried by ndarray / lance-graph / OGAR. Forced, not +# optional: ndarray 0.17.2 now declares rustc 1.98, so +# a 1.97.1 build of this crate fails to resolve at all. +# +# This is THE toolchain file for this repo. A second one briefly existed at +# the repository root; it was removed rather than kept in sync, because two +# files pinning one toolchain is the defect this sweep exists to remove, and +# cargo reads whichever is nearest the working directory — so the two would +# disagree silently depending on where a command was run from. This file sits +# beside `.cargo/config.toml`, which cargo resolves the same way. diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index 3bed53b..0000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,17 +0,0 @@ -[toolchain] -channel = "1.98.1" -# The pinned version is the `channel` line ABOVE — not restated in this -# comment, so a future bump edits one line and leaves the log below intact -# (the ndarray/lance-graph/OGAR sibling repos already learned this the hard -# way: restating the version in prose is what makes the prose wrong). -# -# Bump log (append one line per bump): -# (none) → 1.98.1 2026-09-05: this repo's first pin, joining the -# workspace-wide 1.98.1 sweep already carried by -# ndarray / lance-graph / OGAR. -# -# rustfmt + clippy are mandatory CI components and must ship with the -# pinned channel — `actions-rust-lang/setup-rust-toolchain@v1` reads this -# file for the toolchain (no `toolchain:` input in the workflow), so the -# pin lives in exactly ONE place. -components = ["rustfmt", "clippy"] From 4fc4c392c1979723ff8d60afcd231111b1e8ae0c Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 5 Sep 2026 20:26:15 +0000 Subject: [PATCH 4/5] Point setup-rust-toolchain at the crate, and record the corrections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A review finding on this PR, verified against the action's own documentation: `defaults.run.working-directory` governs `run:` steps only. Each `actions-rust-lang/setup-rust-toolchain` step executes from GITHUB_WORKSPACE, where this repository is a subdirectory and no toolchain file is visible, so it would silently install `stable` instead of the pin. `rust-src-dir` is the input that points it at the crate — the same directory that now holds the single `rust-toolchain.toml`, beside `.cargo/config.toml`. The reviewer's suggested value was the repository root, which was correct against the commit it read. It is the crate directory here, because the root toolchain file was removed in the previous commit rather than kept in sync. The board's PR entry gains an appended correction rather than an edit, per its own append-only rule, covering the four claims that first entry got wrong: the repo did have a toolchain pin, the push trigger is limited to `main`, `--manifest-path` is not equivalent to running in the crate directory, and `-D warnings` is no longer unmeasured. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01AGVLyRZNEKKBSfBDJfbY3V --- .claude/board/PR_ARC_INVENTORY.md | 26 ++++++++++++++++++++++++++ .github/workflows/lint.yml | 21 +++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/.claude/board/PR_ARC_INVENTORY.md b/.claude/board/PR_ARC_INVENTORY.md index cf80cdb..e300d3e 100644 --- a/.claude/board/PR_ARC_INVENTORY.md +++ b/.claude/board/PR_ARC_INVENTORY.md @@ -34,6 +34,32 @@ first real measurement, with the tiered `continue-on-error` + `TECH_DEBT.md` fallback named in the PR body if it comes back red on pre-existing debt. +**Correction (2026-09-05, head `1ea5c85`).** Appended per the append-only +rule rather than edited above; the original lines stay as written. + +- *"this repo had neither a workflow directory nor a toolchain pin before + this PR"* — the workflow half is right, the toolchain half is not. + `native/lgj-abi/rust-toolchain.toml` already pinned `1.97.1`. Adding a + second file at the repository root made two pins for one toolchain, and + cargo reads whichever is nearest the working directory. The root file is + removed; the crate-level file is the authority, now `1.98.1` — forced, + since `ndarray` 0.17.2 declares `rust-version = "1.98"`. +- *"runs on every push/PR"* — the `push` trigger is limited to `main`, so + the accurate statement is every pull request and every push to `main`. +- *"all scoped to `native/lgj-abi` via `--manifest-path`"* — that scoping + is what broke the first run. Cargo reads `.cargo/config.toml` from the + working directory's ancestry, never from the manifest's directory, so + the crate's `-Ctarget-cpu` baseline was dropped and + `the_x86_64_build_has_a_vector_baseline` failed exactly as designed. The + jobs now set `working-directory` to the crate, and CI exports the v3 + baseline explicitly because GitHub-hosted runners do not guarantee + AVX-512. Each `setup-rust-toolchain` step also gained `rust-src-dir`: + `defaults.run.working-directory` governs `run:` steps only, so without it + the action reads no toolchain file and falls back to `stable`. +- *"whether `-D warnings` is clean on `lgj-abi` today is unmeasured"* — now + measured locally: clippy and fmt clean, 138 unit tests plus the G11 fence + passing, under the same commands CI runs. + **Docs.** `LATEST_STATE.md` entry; this entry. **Confidence.** High that the workflow shape is correct (it is a direct diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 20cba24..f3a9a21 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -47,6 +47,13 @@ jobs: path: lance-graph-java - uses: actions-rust-lang/setup-rust-toolchain@v1 with: + # `defaults.run.working-directory` applies to `run:` steps only, NOT + # to action steps: this action executes from GITHUB_WORKSPACE, where + # the checkout is a subdirectory and no toolchain file is visible. It + # would silently fall back to `stable` instead of the pin. `rust-src-dir` + # is the input that points it at the crate — which is also where + # `rust-toolchain.toml` lives, beside `.cargo/config.toml`. + rust-src-dir: lance-graph-java/native/lgj-abi # No `toolchain:` input — the action reads `rust-toolchain.toml`, so the # pinned version lives in exactly ONE place. components: rustfmt, clippy @@ -80,6 +87,13 @@ jobs: path: OGAR - uses: actions-rust-lang/setup-rust-toolchain@v1 with: + # `defaults.run.working-directory` applies to `run:` steps only, NOT + # to action steps: this action executes from GITHUB_WORKSPACE, where + # the checkout is a subdirectory and no toolchain file is visible. It + # would silently fall back to `stable` instead of the pin. `rust-src-dir` + # is the input that points it at the crate — which is also where + # `rust-toolchain.toml` lives, beside `.cargo/config.toml`. + rust-src-dir: lance-graph-java/native/lgj-abi components: rustfmt, clippy - uses: Swatinem/rust-cache@v2 with: @@ -114,6 +128,13 @@ jobs: path: OGAR - uses: actions-rust-lang/setup-rust-toolchain@v1 with: + # `defaults.run.working-directory` applies to `run:` steps only, NOT + # to action steps: this action executes from GITHUB_WORKSPACE, where + # the checkout is a subdirectory and no toolchain file is visible. It + # would silently fall back to `stable` instead of the pin. `rust-src-dir` + # is the input that points it at the crate — which is also where + # `rust-toolchain.toml` lives, beside `.cargo/config.toml`. + rust-src-dir: lance-graph-java/native/lgj-abi components: rustfmt, clippy - uses: Swatinem/rust-cache@v2 with: From aacad006c132c9b4c345c5bb8f74f4bc165244d8 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 5 Sep 2026 20:29:32 +0000 Subject: [PATCH 5/5] Put the target-cpu baseline where cargo will actually read it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit set the CI baseline as `CARGO_BUILD_RUSTFLAGS`, and the run showed it having no effect: the toolchain resolved to 1.98.1 as intended, and the crate's SIGILL-guard test still failed with no baseline at all. `CARGO_BUILD_RUSTFLAGS` is the environment spelling of `build.rustflags`, and `RUSTFLAGS` overrides it. The toolchain action exports `RUSTFLAGS` from its own `rustflags` input, which defaults to `-D warnings` — visible in the run log as `_srt_NEW_RUSTFLAGS: -D warnings` written into `GITHUB_ENV`. So the baseline was set, then discarded, in every job. Moved onto the action's `rustflags` input, keeping its default alongside rather than replacing it. Reproduced and verified both ways locally against the same commands CI runs: with `-D warnings` alone the guard test fails exactly as it did on the runner; with the baseline added it passes and the crate is 138 tests green plus the G11 fence. Worth stating plainly, because this is the third instance in one PR of the same shape: a setting can be present, correct, and inert because something nearer the point of use wins. Two toolchain files where cargo takes the nearest. A config file cargo reads from the working directory rather than the manifest. And now an env var an action overwrites. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01AGVLyRZNEKKBSfBDJfbY3V --- .github/workflows/lint.yml | 57 ++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f3a9a21..3731c78 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,15 +16,6 @@ permissions: env: CARGO_TERM_COLOR: always - # `native/lgj-abi/.cargo/config.toml` pins `-Ctarget-cpu=x86-64-v4` - # (AVX-512) because the production artifact is built for one known host. - # GitHub-hosted runners do not guarantee AVX-512, so a v4 build would emit - # instructions the runner cannot execute and die with SIGILL — the exact - # fault that config's own comment describes. It names the remedy for a - # machine without AVX-512: override the baseline at build time with v3. - # AVX2 is what `the_x86_64_build_has_a_vector_baseline` requires, so the - # test still proves a vector baseline exists rather than being weakened. - CARGO_BUILD_RUSTFLAGS: -Ctarget-cpu=x86-64-v3 jobs: # lgj-abi path-deps ndarray and lance-graph-contract (crates/lance-graph-contract @@ -54,6 +45,22 @@ jobs: # is the input that points it at the crate — which is also where # `rust-toolchain.toml` lives, beside `.cargo/config.toml`. rust-src-dir: lance-graph-java/native/lgj-abi + # The baseline goes HERE, not in a `CARGO_BUILD_RUSTFLAGS` env var. + # This action exports `RUSTFLAGS` from its own `rustflags` input + # (default `-D warnings`), and `RUSTFLAGS` overrides + # `build.rustflags` — which is what `CARGO_BUILD_RUSTFLAGS` sets, so a + # baseline put there is silently discarded. The first run proved it: + # the crate's own SIGILL-guard test was reached with no target-cpu at + # all. The action's default is kept alongside the baseline, not + # replaced. + # + # v3 rather than the crate's own v4: `.cargo/config.toml` pins AVX-512 + # because the production artifact is built for one known host, and + # GitHub-hosted runners do not guarantee it. That file names v3 as the + # remedy for a machine without AVX-512, and AVX2 is what + # `the_x86_64_build_has_a_vector_baseline` requires — so this + # retargets the gate rather than weakening it. + rustflags: -D warnings -Ctarget-cpu=x86-64-v3 # No `toolchain:` input — the action reads `rust-toolchain.toml`, so the # pinned version lives in exactly ONE place. components: rustfmt, clippy @@ -94,6 +101,22 @@ jobs: # is the input that points it at the crate — which is also where # `rust-toolchain.toml` lives, beside `.cargo/config.toml`. rust-src-dir: lance-graph-java/native/lgj-abi + # The baseline goes HERE, not in a `CARGO_BUILD_RUSTFLAGS` env var. + # This action exports `RUSTFLAGS` from its own `rustflags` input + # (default `-D warnings`), and `RUSTFLAGS` overrides + # `build.rustflags` — which is what `CARGO_BUILD_RUSTFLAGS` sets, so a + # baseline put there is silently discarded. The first run proved it: + # the crate's own SIGILL-guard test was reached with no target-cpu at + # all. The action's default is kept alongside the baseline, not + # replaced. + # + # v3 rather than the crate's own v4: `.cargo/config.toml` pins AVX-512 + # because the production artifact is built for one known host, and + # GitHub-hosted runners do not guarantee it. That file names v3 as the + # remedy for a machine without AVX-512, and AVX2 is what + # `the_x86_64_build_has_a_vector_baseline` requires — so this + # retargets the gate rather than weakening it. + rustflags: -D warnings -Ctarget-cpu=x86-64-v3 components: rustfmt, clippy - uses: Swatinem/rust-cache@v2 with: @@ -135,6 +158,22 @@ jobs: # is the input that points it at the crate — which is also where # `rust-toolchain.toml` lives, beside `.cargo/config.toml`. rust-src-dir: lance-graph-java/native/lgj-abi + # The baseline goes HERE, not in a `CARGO_BUILD_RUSTFLAGS` env var. + # This action exports `RUSTFLAGS` from its own `rustflags` input + # (default `-D warnings`), and `RUSTFLAGS` overrides + # `build.rustflags` — which is what `CARGO_BUILD_RUSTFLAGS` sets, so a + # baseline put there is silently discarded. The first run proved it: + # the crate's own SIGILL-guard test was reached with no target-cpu at + # all. The action's default is kept alongside the baseline, not + # replaced. + # + # v3 rather than the crate's own v4: `.cargo/config.toml` pins AVX-512 + # because the production artifact is built for one known host, and + # GitHub-hosted runners do not guarantee it. That file names v3 as the + # remedy for a machine without AVX-512, and AVX2 is what + # `the_x86_64_build_has_a_vector_baseline` requires — so this + # retargets the gate rather than weakening it. + rustflags: -D warnings -Ctarget-cpu=x86-64-v3 components: rustfmt, clippy - uses: Swatinem/rust-cache@v2 with: