Skip to content

Commit 8720d1d

Browse files
authored
Merge pull request #77 from AdaWorldAPI/claude/ci-lint-gate
Add first CI lint gate (fmt + clippy + test), pin Rust 1.98.1
2 parents a061e11 + aacad00 commit 8720d1d

5 files changed

Lines changed: 364 additions & 1 deletion

File tree

.claude/board/EPIPHANIES.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,45 @@
1+
## E-THE-PIN-THAT-CLAIMED-ONE-PLACE-CREATED-A-SECOND-1 (2026-09-05)
2+
3+
**Finding.** The first CI gate this repo ever had went red on its first
4+
run, and the two causes were both "the same thing is declared twice, and
5+
cargo silently picks the nearer one."
6+
7+
`rust-toolchain.toml` was added at the repository root carrying the
8+
sentence *"the pin lives in exactly ONE place"* — while
9+
`native/lgj-abi/rust-toolchain.toml` already existed, pinning `1.97.1`.
10+
Cargo reads whichever file is nearest the working directory, so the root
11+
file governed a command run from the root and the crate file governed a
12+
command run from the crate. Two files, one toolchain, disagreeing by where
13+
you happened to stand. The root file is removed; the crate file is the
14+
authority, bumped to `1.98.1`, and it sits beside `.cargo/config.toml`,
15+
which cargo resolves the same way.
16+
17+
That bump is forced, not cosmetic: `ndarray` 0.17.2 now declares
18+
`rust-version = "1.98"`, so a 1.97.1 resolve of this crate fails outright.
19+
The same upstream move turned every MSRV job in `AdaWorldAPI/tract` red on
20+
the same afternoon.
21+
22+
**The second cause is the more interesting one, because a test caught it.**
23+
`native/lgj-abi/.cargo/config.toml` pins `-Ctarget-cpu=x86-64-v4`, and
24+
`abi::tests::the_x86_64_build_has_a_vector_baseline` exists to turn a lost
25+
baseline into a test failure instead of a SIGILL inside a JVM downcall.
26+
The workflow ran cargo from the repository root with `--manifest-path`
27+
pointing into the crate — and **cargo reads `.cargo/config.toml` from the
28+
working directory's ancestry, never from the manifest's directory.** The
29+
baseline was therefore never applied, the manifest reported the scalar
30+
backend, and the test fired exactly as designed. `--manifest-path` is not
31+
equivalent to running in the crate directory, and this is the failure that
32+
proves it.
33+
34+
**Consequence.** The jobs now run with `working-directory` set to the
35+
crate, and CI additionally exports `CARGO_BUILD_RUSTFLAGS=-Ctarget-cpu=
36+
x86-64-v3`, because GitHub-hosted runners do not guarantee AVX-512 and a
37+
v4 build would die on them with the very SIGILL that config comment
38+
describes. v3 still satisfies the test's `AVX2 | AVX512` assertion, so the
39+
gate is retargeted rather than weakened. Verified locally on both sides:
40+
the old invocation reproduces the failure, the new one passes 138 tests
41+
plus the G11 fence, with fmt and clippy clean.
42+
143
## E-THE-GUARD-YOU-WIRE-IS-NOT-THE-GUARD-YOU-NAMED-1 (2026-08-28)
244

345
**Finding.** A wave chartered as "wire the epoch re-check" cannot deliver

.claude/board/LATEST_STATE.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,63 @@
1+
## 2026-09-05 — storno: the gate's own first run corrected two claims above
2+
3+
Corrects the entry immediately below, which is left in place per the
4+
storno rule. Two of its statements were wrong when written:
5+
6+
- *"adds `rust-toolchain.toml` (this repo had none)"* — one already
7+
existed at `native/lgj-abi/rust-toolchain.toml`, pinning `1.97.1`.
8+
- *"the pin has exactly one spelling"* — adding the root file made two,
9+
and cargo reads whichever is nearest the working directory.
10+
11+
The root file is removed and the crate-level file is bumped to `1.98.1`
12+
(forced: `ndarray` 0.17.2 declares `rust-version = "1.98"`). The three
13+
jobs now run with `working-directory` set to the crate rather than
14+
`--manifest-path` from the root, because `.cargo/config.toml` is read
15+
from the working directory's ancestry and the v4 target-cpu baseline was
16+
being dropped — which is what `the_x86_64_build_has_a_vector_baseline`
17+
caught on the gate's first run. CI exports the v3 baseline explicitly,
18+
since GitHub-hosted runners do not guarantee AVX-512. Full account:
19+
`EPIPHANIES.md` `E-THE-PIN-THAT-CLAIMED-ONE-PLACE-CREATED-A-SECOND-1`.
20+
21+
## 2026-09-05 — first CI lint gate: fmt + clippy + rust-test, Rust pinned to 1.98.1
22+
23+
**Branch `claude/ci-lint-gate`, PR #77.** This repo has never had a
24+
`.github/workflows/` directory — every gate documented in `CLAUDE.md` (the
25+
G11 contract-import fence, the epoch-recheck falsifiers, `ApiSurfaceTest`,
26+
the L1/L2 semantic-leak pins) has only ever run when a session happened to
27+
invoke `cargo test` by hand. Adds `.github/workflows/lint.yml`, three jobs
28+
scoped to `native/lgj-abi` (the repo's only Cargo crate): `format`
29+
(`cargo fmt --check`), `clippy` (`--all-targets -- -D warnings`), and
30+
`rust-test` (`--all-targets`, which is what finally makes
31+
`tests/g11_contract_import_fence.rs` run anywhere but a session's own shell —
32+
the same gap `CLAUDE.md` names for G11 itself: "prose until 2026-09-03"
33+
because nothing ran the test that enforces it).
34+
35+
`lgj-abi` path-deps `ndarray`, `lance-graph`'s `lance-graph-contract`, and
36+
(optional, off by default) `OGAR`'s `ogar-class-view`. Cargo resolves the
37+
full graph including inactive optional path deps, so `clippy`/`rust-test`
38+
check out all three siblings — the identical shape `lance-graph`'s own
39+
`style.yml` already uses (self + each sibling into its own named
40+
subdirectory under one runner workspace root).
41+
42+
Also adds `rust-toolchain.toml` (this repo had none) pinning
43+
`channel = "1.98.1"`, joining the sweep `ndarray`/`lance-graph`/`OGAR`
44+
already carry. `setup-rust-toolchain@v1` is invoked with no `toolchain:`
45+
input, so the pin has exactly one spelling.
46+
47+
**Java is deliberately out of scope.** `java/` holds only `README.md` +
48+
`.gitignore` — no Maven, no Gradle, no source. The README says so directly
49+
("no Maven, no Gradle... `javac` and `java` are the entire Java toolchain").
50+
Nothing to wire a CI job against yet; filed as a named follow-up rather than
51+
guessed at.
52+
53+
**Not measured in this PR:** whether `clippy --all-targets -- -D warnings`
54+
is actually clean on `lgj-abi` today. Disk constraints (a large dependency
55+
tree through the contract crate) ruled out a local `cargo build`/`clippy`
56+
run, so this PR's own CI run is the first real measurement — if it comes
57+
back red on pre-existing debt, the follow-up is this workspace's own tiered
58+
posture (`continue-on-error: true` + a named `TECH_DEBT.md` line), not a
59+
bundled auto-fix.
60+
161
## 2026-09-04 — lgj_hop: the conjunction is one truth-table pass, and the lane is read as a lane (5×)
262

363
**Branch `claude/pr-294-ragged-path-validation-170zcy`**, lgj-abi only — no

.claude/board/PR_ARC_INVENTORY.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,66 @@
88
> anti-pattern the imported board rules name. Backfilled below in one
99
> pass rather than left stale; PR #4 onward gets its entry at merge time.
1010
11+
## PR #77 — first CI lint gate: fmt + clippy + rust-test, Rust pinned to 1.98.1 (opened 2026-09-05, head `6d4b1a2`)
12+
13+
**Added.** `.github/workflows/lint.yml` (three jobs: `format`, `clippy`,
14+
`rust-test`, all scoped to `native/lgj-abi` via `--manifest-path`);
15+
`rust-toolchain.toml` pinning `channel = "1.98.1"` + `rustfmt`/`clippy`
16+
components (this repo had neither a workflow directory nor a toolchain pin
17+
before this PR).
18+
19+
**Locked.** The G11 contract-import fence (`tests/g11_contract_import_fence.rs`)
20+
now runs on every push/PR via `rust-test`, closing the exact gap
21+
`CLAUDE.md` names for G11 itself ("prose until 2026-09-03" — a rule
22+
enforced by a test nothing ever ran). `clippy`/`rust-test` check out all
23+
three path-dep siblings (`ndarray`, `lance-graph`, `OGAR`) because Cargo
24+
resolves the full dependency graph including the inactive optional
25+
`ogar-classview` feature's path dep — mirroring `lance-graph`'s own
26+
`style.yml` checkout shape exactly.
27+
28+
**Deferred.** A Java CI job — `java/` has no build system at all (no
29+
Maven, no Gradle, no source), per its own README; wiring a job against a
30+
build system that doesn't exist would guess at a command with nothing to
31+
verify it against. Whether `-D warnings` is clean on `lgj-abi` today is
32+
also unmeasured locally (disk constraints); this PR's own CI run is the
33+
first real measurement, with the tiered `continue-on-error` +
34+
`TECH_DEBT.md` fallback named in the PR body if it comes back red on
35+
pre-existing debt.
36+
37+
**Correction (2026-09-05, head `1ea5c85`).** Appended per the append-only
38+
rule rather than edited above; the original lines stay as written.
39+
40+
- *"this repo had neither a workflow directory nor a toolchain pin before
41+
this PR"* — the workflow half is right, the toolchain half is not.
42+
`native/lgj-abi/rust-toolchain.toml` already pinned `1.97.1`. Adding a
43+
second file at the repository root made two pins for one toolchain, and
44+
cargo reads whichever is nearest the working directory. The root file is
45+
removed; the crate-level file is the authority, now `1.98.1` — forced,
46+
since `ndarray` 0.17.2 declares `rust-version = "1.98"`.
47+
- *"runs on every push/PR"* — the `push` trigger is limited to `main`, so
48+
the accurate statement is every pull request and every push to `main`.
49+
- *"all scoped to `native/lgj-abi` via `--manifest-path`"* — that scoping
50+
is what broke the first run. Cargo reads `.cargo/config.toml` from the
51+
working directory's ancestry, never from the manifest's directory, so
52+
the crate's `-Ctarget-cpu` baseline was dropped and
53+
`the_x86_64_build_has_a_vector_baseline` failed exactly as designed. The
54+
jobs now set `working-directory` to the crate, and CI exports the v3
55+
baseline explicitly because GitHub-hosted runners do not guarantee
56+
AVX-512. Each `setup-rust-toolchain` step also gained `rust-src-dir`:
57+
`defaults.run.working-directory` governs `run:` steps only, so without it
58+
the action reads no toolchain file and falls back to `stable`.
59+
- *"whether `-D warnings` is clean on `lgj-abi` today is unmeasured"* — now
60+
measured locally: clippy and fmt clean, 138 unit tests plus the G11 fence
61+
passing, under the same commands CI runs.
62+
63+
**Docs.** `LATEST_STATE.md` entry; this entry.
64+
65+
**Confidence.** High that the workflow shape is correct (it is a direct
66+
transplant of `lance-graph`'s own proven `style.yml` checkout pattern,
67+
adapted to this repo's single-crate layout). Unmeasured whether the
68+
`clippy`/`rust-test` jobs pass clean on first run — that is what the CI
69+
run itself is for.
70+
1171
## PR #68 — mask-risc-lowering v1 → v4: SPEC completion, the 5+3 council, voxelmasking (merged 2026-09-03 as `dfb4ab1`, head `4ad9377`)
1272

1373
**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`.

.github/workflows/lint.yml

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
name: Lint
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
11+
cancel-in-progress: true
12+
13+
# Least-privilege: these jobs only read the repo (checkout + build + lint).
14+
permissions:
15+
contents: read
16+
17+
env:
18+
CARGO_TERM_COLOR: always
19+
20+
jobs:
21+
# lgj-abi path-deps ndarray and lance-graph-contract (crates/lance-graph-contract
22+
# in the AdaWorldAPI/lance-graph sibling), and optionally (feature `ogar-classview`,
23+
# off by default) ogar-class-view in the AdaWorldAPI/OGAR sibling. Cargo resolves
24+
# the full dependency graph — including inactive optional path deps — so all three
25+
# siblings must exist on disk even though only two are compiled into the default
26+
# build. Checked out under the runner's top-level workspace, sibling to this repo's
27+
# own checkout, exactly as `../../../<repo>` from native/lgj-abi/Cargo.toml expects
28+
# (matches AdaWorldAPI/lance-graph's own .github/workflows/style.yml pattern).
29+
format:
30+
runs-on: ubuntu-latest
31+
timeout-minutes: 15
32+
defaults:
33+
run:
34+
working-directory: lance-graph-java/native/lgj-abi
35+
steps:
36+
- uses: actions/checkout@v4
37+
with:
38+
path: lance-graph-java
39+
- uses: actions-rust-lang/setup-rust-toolchain@v1
40+
with:
41+
# `defaults.run.working-directory` applies to `run:` steps only, NOT
42+
# to action steps: this action executes from GITHUB_WORKSPACE, where
43+
# the checkout is a subdirectory and no toolchain file is visible. It
44+
# would silently fall back to `stable` instead of the pin. `rust-src-dir`
45+
# is the input that points it at the crate — which is also where
46+
# `rust-toolchain.toml` lives, beside `.cargo/config.toml`.
47+
rust-src-dir: lance-graph-java/native/lgj-abi
48+
# The baseline goes HERE, not in a `CARGO_BUILD_RUSTFLAGS` env var.
49+
# This action exports `RUSTFLAGS` from its own `rustflags` input
50+
# (default `-D warnings`), and `RUSTFLAGS` overrides
51+
# `build.rustflags` — which is what `CARGO_BUILD_RUSTFLAGS` sets, so a
52+
# baseline put there is silently discarded. The first run proved it:
53+
# the crate's own SIGILL-guard test was reached with no target-cpu at
54+
# all. The action's default is kept alongside the baseline, not
55+
# replaced.
56+
#
57+
# v3 rather than the crate's own v4: `.cargo/config.toml` pins AVX-512
58+
# because the production artifact is built for one known host, and
59+
# GitHub-hosted runners do not guarantee it. That file names v3 as the
60+
# remedy for a machine without AVX-512, and AVX2 is what
61+
# `the_x86_64_build_has_a_vector_baseline` requires — so this
62+
# retargets the gate rather than weakening it.
63+
rustflags: -D warnings -Ctarget-cpu=x86-64-v3
64+
# No `toolchain:` input — the action reads `rust-toolchain.toml`, so the
65+
# pinned version lives in exactly ONE place.
66+
components: rustfmt, clippy
67+
- name: Check formatting (lgj-abi)
68+
run: cargo fmt -- --check
69+
70+
clippy:
71+
runs-on: ubuntu-latest
72+
timeout-minutes: 30
73+
defaults:
74+
run:
75+
working-directory: lance-graph-java/native/lgj-abi
76+
steps:
77+
- uses: actions/checkout@v4
78+
with:
79+
path: lance-graph-java
80+
- name: Checkout AdaWorldAPI/ndarray (sibling dependency)
81+
uses: actions/checkout@v4
82+
with:
83+
repository: AdaWorldAPI/ndarray
84+
path: ndarray
85+
- name: Checkout AdaWorldAPI/lance-graph (sibling dependency, lance-graph-contract)
86+
uses: actions/checkout@v4
87+
with:
88+
repository: AdaWorldAPI/lance-graph
89+
path: lance-graph
90+
- name: Checkout AdaWorldAPI/OGAR (sibling dependency, optional ogar-classview feature)
91+
uses: actions/checkout@v4
92+
with:
93+
repository: AdaWorldAPI/OGAR
94+
path: OGAR
95+
- uses: actions-rust-lang/setup-rust-toolchain@v1
96+
with:
97+
# `defaults.run.working-directory` applies to `run:` steps only, NOT
98+
# to action steps: this action executes from GITHUB_WORKSPACE, where
99+
# the checkout is a subdirectory and no toolchain file is visible. It
100+
# would silently fall back to `stable` instead of the pin. `rust-src-dir`
101+
# is the input that points it at the crate — which is also where
102+
# `rust-toolchain.toml` lives, beside `.cargo/config.toml`.
103+
rust-src-dir: lance-graph-java/native/lgj-abi
104+
# The baseline goes HERE, not in a `CARGO_BUILD_RUSTFLAGS` env var.
105+
# This action exports `RUSTFLAGS` from its own `rustflags` input
106+
# (default `-D warnings`), and `RUSTFLAGS` overrides
107+
# `build.rustflags` — which is what `CARGO_BUILD_RUSTFLAGS` sets, so a
108+
# baseline put there is silently discarded. The first run proved it:
109+
# the crate's own SIGILL-guard test was reached with no target-cpu at
110+
# all. The action's default is kept alongside the baseline, not
111+
# replaced.
112+
#
113+
# v3 rather than the crate's own v4: `.cargo/config.toml` pins AVX-512
114+
# because the production artifact is built for one known host, and
115+
# GitHub-hosted runners do not guarantee it. That file names v3 as the
116+
# remedy for a machine without AVX-512, and AVX2 is what
117+
# `the_x86_64_build_has_a_vector_baseline` requires — so this
118+
# retargets the gate rather than weakening it.
119+
rustflags: -D warnings -Ctarget-cpu=x86-64-v3
120+
components: rustfmt, clippy
121+
- uses: Swatinem/rust-cache@v2
122+
with:
123+
workspaces: lance-graph-java/native/lgj-abi
124+
- name: Clippy lgj-abi
125+
run: cargo clippy --all-targets -- -D warnings
126+
127+
rust-test:
128+
runs-on: ubuntu-latest
129+
timeout-minutes: 30
130+
defaults:
131+
run:
132+
working-directory: lance-graph-java/native/lgj-abi
133+
steps:
134+
- uses: actions/checkout@v4
135+
with:
136+
path: lance-graph-java
137+
- name: Checkout AdaWorldAPI/ndarray (sibling dependency)
138+
uses: actions/checkout@v4
139+
with:
140+
repository: AdaWorldAPI/ndarray
141+
path: ndarray
142+
- name: Checkout AdaWorldAPI/lance-graph (sibling dependency, lance-graph-contract)
143+
uses: actions/checkout@v4
144+
with:
145+
repository: AdaWorldAPI/lance-graph
146+
path: lance-graph
147+
- name: Checkout AdaWorldAPI/OGAR (sibling dependency, optional ogar-classview feature)
148+
uses: actions/checkout@v4
149+
with:
150+
repository: AdaWorldAPI/OGAR
151+
path: OGAR
152+
- uses: actions-rust-lang/setup-rust-toolchain@v1
153+
with:
154+
# `defaults.run.working-directory` applies to `run:` steps only, NOT
155+
# to action steps: this action executes from GITHUB_WORKSPACE, where
156+
# the checkout is a subdirectory and no toolchain file is visible. It
157+
# would silently fall back to `stable` instead of the pin. `rust-src-dir`
158+
# is the input that points it at the crate — which is also where
159+
# `rust-toolchain.toml` lives, beside `.cargo/config.toml`.
160+
rust-src-dir: lance-graph-java/native/lgj-abi
161+
# The baseline goes HERE, not in a `CARGO_BUILD_RUSTFLAGS` env var.
162+
# This action exports `RUSTFLAGS` from its own `rustflags` input
163+
# (default `-D warnings`), and `RUSTFLAGS` overrides
164+
# `build.rustflags` — which is what `CARGO_BUILD_RUSTFLAGS` sets, so a
165+
# baseline put there is silently discarded. The first run proved it:
166+
# the crate's own SIGILL-guard test was reached with no target-cpu at
167+
# all. The action's default is kept alongside the baseline, not
168+
# replaced.
169+
#
170+
# v3 rather than the crate's own v4: `.cargo/config.toml` pins AVX-512
171+
# because the production artifact is built for one known host, and
172+
# GitHub-hosted runners do not guarantee it. That file names v3 as the
173+
# remedy for a machine without AVX-512, and AVX2 is what
174+
# `the_x86_64_build_has_a_vector_baseline` requires — so this
175+
# retargets the gate rather than weakening it.
176+
rustflags: -D warnings -Ctarget-cpu=x86-64-v3
177+
components: rustfmt, clippy
178+
- uses: Swatinem/rust-cache@v2
179+
with:
180+
workspaces: lance-graph-java/native/lgj-abi
181+
# Runs every #[test] in lgj-abi, including tests/g11_contract_import_fence.rs
182+
# — the fence CLAUDE.md's "Enforcement" section names as structural: it walks
183+
# src/ and rejects any `lance_graph_contract::` module outside the four-name
184+
# allowlist. Per this repo's own history, "G11 was prose until 2026-09-03"
185+
# because nothing ran the test that enforces it; this job is what runs it.
186+
- name: Test lgj-abi
187+
run: cargo test --all-targets

0 commit comments

Comments
 (0)