diff --git a/.claude/board/ISSUES.md b/.claude/board/ISSUES.md index 05e7e51..5c42178 100644 --- a/.claude/board/ISSUES.md +++ b/.claude/board/ISSUES.md @@ -1,4 +1,4 @@ -## ISS-LGJ-CONSUMERS-HAVE-NO-CI-LINE (2026-09-22) — OPEN +## ISS-LGJ-CONSUMERS-HAVE-NO-CI-LINE (2026-09-22) — RESOLVED 2026-09-22 (job landed; dispatch proven by its own first run) `main` was RED and nothing said so. `GraphHopTest` reported 1 FAILED / 65 passed at `bb81d80`, established by running it from a clean worktree, not @@ -38,6 +38,83 @@ confirm the job goes red. A job that builds the consumers but never runs their mains would pass, and would be the no-gate-with-extra-steps outcome this entry exists to name. +--- + +**RESOLUTION (2026-09-22).** `java-suites` in `.github/workflows/lint.yml`: +twelve steps, same three-sibling checkout as `rust-test`, `cargo build +--release` for the artifact, then the four `javac`/`java` command strings +`java/README.md` documents, verbatim. No build tool was introduced — there +still is none, by design. + +**The first task — acquisition — is ANSWERED, and by a different mechanism +than the local one, which is why this entry was right to refuse to generalise +from the container's ladder.** Chain, each link read from a primary source +rather than inferred: + +1. `actions/setup-java`'s `normalizeVersion`: `if (version.endsWith('-ea')) { + ... stable = false }` — so `java-version: '28-ea'` is not-stable. +2. its temurin installer: `const releaseType = this.stable ? 'ga' : 'ea'`. +3. Adoptium's API, queried live: `release_type=ea` + `version=[28,29)` + + linux/x64/jdk serves `jdk-28+16-ea-beta` — the same build this container + runs. And `/v3/info/available_releases` omits 28 while naming it + `most_recent_feature_version`, which is *why* the `-ea` suffix is load-bearing. + +The container's blocker (gateway-blocked distribution hosts, hence the +GitHub-release download path) is a **this-container** constraint and never +applied to a runner. The version is deliberately NOT pinned to `+16`: internal +head pins are forbidden, and an upstream EA build is an external dependency +whose purpose is to move — what the suite needs is JEP 401 under preview, which +every 28 EA build carries. + +**Two counts in the entry above were wrong, measured on `origin/main` +(`aef2382`) before the job was written:** it is **four** consumer mains, not +three (`trades` carries both `TradesAllocationTest` and `TradesParityTest`, and +running one of two would have been precisely the no-gate-with-extra-steps +outcome this entry names). The core suite is **612 checks / 17 suites**, which +this entry had right while root `CLAUDE.md` still briefed every session with +`409 / 16 suites / abi 0.11`. That drift is fixed in the same commit, and fixed +STRUCTURALLY: the live count now exists in exactly one dated place and every +other site had its number removed rather than re-pinned. One measurement +restated in eight places goes stale in eight places. + +Measured, all four command strings run verbatim: core **612** (0 failures, abi +0.12, avx512, release), bricks **70**, graph **68**, trades **3** and **12** — +**765 checks across 5 entry points**, every one exit 0. + +**FALSIFIER: RUN, red-then-green, in the shape this entry demanded.** The stale +`0` pin was re-introduced in `GraphHopTest` and the consumer step's `run:` body +— extracted VERBATIM from the committed workflow via a YAML parse, not retyped — +was executed under `bash -e`: + +| run | mains reached | step exit | +|---|---|---| +| stale `0` pin | all four; `::error::consumer suites FAILED: …GraphHopTest` | **1** | +| restored | bricks 70, graph 68, trades 3 + 12, "all four consumer suites passed" | **0** | + +Two properties, one run. It catches the exact defect that survived a merge +(`1 FAILED, 67 passed` — the `bb81d80` shape), AND it reaches every main +regardless: a bare `java` under `bash -e` aborts the step at the first red one, +so one broken consumer would have masked the other three and each CI round would +have revealed exactly one of them. `AllTests` does not behave that way either, +and now neither does this loop. + +What a local run CANNOT prove is +dispatch: whether a runner starts the job and reaches JDK 28. **That is now +SETTLED by the first run (#86, `af58fbd`): `java-suites completed success`, all +13 steps.** The runner's own log closes the acquisition chain end to end — +`Downloading Java 28.0.0+16.0.ea (Temurin-Hotspot) from +.../adoptium/temurin28-binaries/releases/download/jdk-28%2B16-ea-beta/...`, the +exact release the Adoptium API named, resolved into +`/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/28.0.0-ea.16.0.ea/x64`. + +It also MEASURED something that had only been reasoned about. The runner reports +`abi 0.12, simd ndarray::simd avx2 (x86-64-v3)` against this host's `avx512`, +and every count comes back byte-identical — core **612**, bricks **70**, graph +**68**, trades **3** and **12**. The `simdBackend()` "diagnostic only" rule was +asserted here from reading the tests (`AbiContractTest` asserts only that a +backend was reported, `FusionParityTest` notes it, `DoctrineFenceTest` counts +source lines); it is now observed across two different backends. + ## ISS-LGJ-TOOLCHAIN-MUST-BE-JDK28-VALHALLA-PANAMA — UNBLOCKED; JDK 28 installed and the flip proven (2026-09-19) ⊘ The entry below says the migration is blocked because no JDK 28 can be diff --git a/.claude/board/LATEST_STATE.md b/.claude/board/LATEST_STATE.md index 1ad05d2..079ad59 100644 --- a/.claude/board/LATEST_STATE.md +++ b/.claude/board/LATEST_STATE.md @@ -1,3 +1,85 @@ +## 2026-09-22 — the Java gate is DISPATCHED, and one measurement stops being restated in eight places + +`ISS-LGJ-CONSUMERS-HAVE-NO-CI-LINE` is RESOLVED. `java-suites` in +`.github/workflows/lint.yml` builds `liblgj_abi.so`, then runs the four +`javac`/`java` command strings `java/README.md` documents, verbatim — no build +tool was introduced, there still is none by design. + +- **The issue's first task was acquisition, not the job**, and it resolves by a + mechanism this container does not use — which is why the entry was right to + refuse to generalise from the local ladder. Read from primary sources: + setup-java's `normalizeVersion` sets `stable = false` on an `-ea` suffix, its + temurin installer then asks `release_type=ea`, and Adoptium's API (queried + live) serves `jdk-28+16-ea-beta` — the same build this container runs. The + container's blocker was gateway-blocked distribution hosts; a runner never had + that constraint. NOT pinned to `+16`: internal head pins are forbidden, and + what the suite needs is JEP 401 under preview, which every 28 EA build carries. +- **Measured on `origin/main` (`aef2382`), every command verbatim:** core **612 + checks / 17 suites / 0 failures** (abi 0.12, avx512, release), bricks **70**, + graph **68**, trades **3** and **12** — **765 checks across 5 entry points**, + all exit 0. All of it was gating nothing. +- **Two counts were wrong on the way in.** FOUR consumer mains, not three + (`trades` carries two; running one of two would have been the + no-gate-with-extra-steps outcome the issue names). And root `CLAUDE.md` + briefed every session with `409 / 16 suites / abi 0.11`. Fixed + **structurally**, not re-pinned: the live count now exists in exactly ONE + dated place and every other site had its number REMOVED. One measurement + restated in eight places goes stale in eight places — which is what had + happened. The three surviving 409s are dated historical measurements kept as + evidence; the Valhalla-flip comparison is only meaningful against its own + baseline and must not be restated forward. +- **Falsifier run, red-then-green, on the step body extracted from the + committed YAML rather than retyped.** Stale `0` pin: all four mains reached, + `::error::` named the culprit, exit 1. Restored: exit 0. Not fail-fast + deliberately — a bare `java` under `bash -e` aborts at the first red main, so + one broken consumer would mask three others and each round would reveal one. + +**The one OPEN item CLOSED on the first run** (#86, `af58fbd`): +`java-suites completed success`, 13/13 steps. The runner downloaded +`Java 28.0.0+16.0.ea (Temurin-Hotspot)` from +`adoptium/temurin28-binaries/.../jdk-28+16-ea-beta` — the exact release the +Adoptium API had named, so the chain is closed by execution and not only by +reading. Bonus measurement: the runner reports `avx2 (x86-64-v3)` where this +host reports `avx512`, and all 765 counts are byte-identical, which turns the +backend-agnostic claim from something read out of the tests into something +observed across two backends. + +**Review follow-up (`2a30039`), both findings CodeRabbit-confirmed.** Two real +defects, both mine: + +- **Persisted checkout credentials** (zizmor `artipacked`). Fixed on ALL + THIRTEEN checkout steps, not the four named — `persist-credentials` appeared + nowhere in the file, every job runs `cargo`, so the `build.rs` read path was + identical in `format`/`clippy`/`rust-test`. Verified free first: nothing + pushes, `contents: read`, no secret read. **Verified at RUNTIME, not just in + YAML** — each of the four checkouts logs `persist-credentials: false`, then + `Setting up auth`, then `Removing auth` INSIDE the checkout step, so the + credential no longer spans the later `cargo build`. Without the flag there is + no in-step `Removing auth` and the config survives to post-job cleanup. +- **The documented suite command could not run.** My own pointer sentence aimed + at a JDK 25/26 command without the preview flags; measured `error: value + classes are a preview feature and are disabled by default`, exit 1. Fixing it + surfaced three more in the same block (`/usr/lib/jvm` now holds only Java 21 + so `temurin-26-jdk-amd64` does not exist here; the block mixed working + directories and died on `find: 'java/src/main'`; `-Dlgj.library=$PWD/target/...` + named an incidental leftover `target/` that is a separate inode from what + step 1 builds) — and one I INTRODUCED, caught only by executing it: + `--manifest-path` instead of `cd` broke the toolchain, because rustup reads + `rust-toolchain.toml` from the CWD (`rustc 1.94.1 is not supported`, exit + 101). The `cd` is load-bearing and is back in a subshell. Verified by + extracting the fenced block by PARSE and running it under `bash -e`: exit 0, + `ALL PASSED (612 checks)`. + I also nearly filed a FALSE finding — the two `.so` paths have different + mtimes, which read as a stale artifact; they are md5-identical. Checking + content instead of timestamps stopped it. + +**OPEN:** nothing on this. The remaining gap is elsewhere and unchanged — +`lint.yml` fires `on: {pull_request, push}` for THIS repository only, so an +upstream-only merge in `lance-graph` or `ndarray` cannot start the workflow and +a sibling break stays invisible until someone pushes here. That is the trigger +gap `E-THE-CI-GAP-WAS-THE-TRIGGER-NOT-THE-COVERAGE-1` already names; this job +inherits it rather than fixing it, and now inherits it for the Java half too. + ## 2026-09-22 — D-LGJ-FOLD-5: the consumer stops asking sixteen times, and a red pin on `main` gets root-caused The consumer half of minor 12. `BricksQuery.sumBy()` was sixteen queries — diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 3731c78..8d1d088 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -33,8 +33,22 @@ jobs: run: working-directory: lance-graph-java/native/lgj-abi steps: + # `persist-credentials: false` on EVERY checkout in this file (13 of them). + # Without it, a `pull_request` checkout leaves the workflow token in the + # clone's local git config, and every job here then runs `cargo`, which + # executes any `build.rs` the PR added — a read path to that token before + # the post-job cleanup. Flagged by zizmor as `artipacked`; raised by + # CodeRabbit against the `java-suites` checkouts on #86, and the other + # nine were already exposed identically, so this is the root-cause fix + # rather than four of thirteen. + # + # Provably free: no step in this file pushes, the workflow declares + # `contents: read`, and nothing reads a secret — so nothing here needs a + # persisted credential, and the sibling checkouts of ndarray / + # lance-graph / OGAR are public reads that never used one. - uses: actions/checkout@v4 with: + persist-credentials: false path: lance-graph-java - uses: actions-rust-lang/setup-rust-toolchain@v1 with: @@ -76,20 +90,24 @@ jobs: steps: - uses: actions/checkout@v4 with: + persist-credentials: false path: lance-graph-java - name: Checkout AdaWorldAPI/ndarray (sibling dependency) uses: actions/checkout@v4 with: + persist-credentials: false repository: AdaWorldAPI/ndarray path: ndarray - name: Checkout AdaWorldAPI/lance-graph (sibling dependency, lance-graph-contract) uses: actions/checkout@v4 with: + persist-credentials: false repository: AdaWorldAPI/lance-graph path: lance-graph - name: Checkout AdaWorldAPI/OGAR (sibling dependency, optional ogar-classview feature) uses: actions/checkout@v4 with: + persist-credentials: false repository: AdaWorldAPI/OGAR path: OGAR - uses: actions-rust-lang/setup-rust-toolchain@v1 @@ -133,20 +151,24 @@ jobs: steps: - uses: actions/checkout@v4 with: + persist-credentials: false path: lance-graph-java - name: Checkout AdaWorldAPI/ndarray (sibling dependency) uses: actions/checkout@v4 with: + persist-credentials: false repository: AdaWorldAPI/ndarray path: ndarray - name: Checkout AdaWorldAPI/lance-graph (sibling dependency, lance-graph-contract) uses: actions/checkout@v4 with: + persist-credentials: false repository: AdaWorldAPI/lance-graph path: lance-graph - name: Checkout AdaWorldAPI/OGAR (sibling dependency, optional ogar-classview feature) uses: actions/checkout@v4 with: + persist-credentials: false repository: AdaWorldAPI/OGAR path: OGAR - uses: actions-rust-lang/setup-rust-toolchain@v1 @@ -185,3 +207,139 @@ jobs: # because nothing ran the test that enforces it; this job is what runs it. - name: Test lgj-abi run: cargo test --all-targets + + # THE JAVA GATE. Until this job existed, `main` could be RED and nothing said + # so: `GraphHopTest` reported 1 FAILED / 65 passed at bb81d80 and survived a + # merge, because the three jobs above compile Rust only and nothing in + # `.github/` compiled a single line of Java. The 612-check core suite and the + # four consumer mains were LOCAL gates — run by whoever remembered. A gate that + # exists and is never dispatched is indistinguishable from no gate. + # Tracked as ISS-LGJ-CONSUMERS-HAVE-NO-CI-LINE. + # + # There is no build tool in this repo — no Maven, no Gradle, no wrapper — by + # design (`java/README.md`: "`javac` and `java` are the entire Java + # toolchain"). So this job shells out to raw javac/java with exactly the + # commands that README documents, which is what keeps the two from drifting: + # a contributor's local command and CI's command are the same string. + java-suites: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + path: lance-graph-java + # Same three siblings as `rust-test`, for the same reason: cargo resolves + # the whole graph including the inactive optional path dep, so all three + # must exist on disk before the artifact this job needs can be built. + - name: Checkout AdaWorldAPI/ndarray (sibling dependency) + uses: actions/checkout@v4 + with: + persist-credentials: false + repository: AdaWorldAPI/ndarray + path: ndarray + - name: Checkout AdaWorldAPI/lance-graph (sibling dependency, lance-graph-contract) + uses: actions/checkout@v4 + with: + persist-credentials: false + repository: AdaWorldAPI/lance-graph + path: lance-graph + - name: Checkout AdaWorldAPI/OGAR (sibling dependency, optional ogar-classview feature) + uses: actions/checkout@v4 + with: + persist-credentials: false + repository: AdaWorldAPI/OGAR + path: OGAR + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + rust-src-dir: lance-graph-java/native/lgj-abi + # x86-64-v3, matching the jobs above: `.cargo/config.toml` pins AVX-512 + # for the one known production host and GitHub-hosted runners do not + # guarantee it. No Java test pins a backend name — `AbiContractTest` + # asserts only that one was reported, `FusionParityTest` merely notes + # it, and `DoctrineFenceTest` counts source lines — so the suite is + # backend-agnostic by construction and an AVX2 artifact gates the same + # behaviour. That is the `simdBackend()` "diagnostic only" rule holding. + rustflags: -D warnings -Ctarget-cpu=x86-64-v3 + components: rustfmt, clippy + - uses: Swatinem/rust-cache@v2 + with: + workspaces: lance-graph-java/native/lgj-abi + # The suite needs the real artifact. `AllTests` exits 2 when it is absent + # rather than reporting a failure — deliberately, so a missing library does + # not read as a broken test. In CI that distinction is moot: any non-zero + # exit fails the step, and here an absent artifact IS a defect. + - name: Build liblgj_abi.so (release) + working-directory: lance-graph-java/native/lgj-abi + run: cargo build --release + # `28-ea`, not `28`. JDK 28 is not GA: Adoptium's own + # /v3/info/available_releases lists it as most_recent_feature_version and + # NOT in available_releases. The `-ea` suffix is what makes setup-java ask + # for it — `normalizeVersion` sets `stable = false` on that suffix, and the + # temurin installer then queries `release_type=ea`, which serves + # jdk-28+16-ea-beta: the same build the development container runs. + # + # The version is deliberately NOT pinned to +16. This repo forbids internal + # head pins, and an upstream EA build is an external dependency whose whole + # purpose is to move; pinning it would mean a checksum bump per EA drop with + # nothing verified in exchange. What the suite actually requires is JEP 401 + # value classes under preview, and every 28 EA build carries those. + - name: Set up JDK 28 (early access) + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '28-ea' + # --enable-preview is for JEP 401 (value classes), NOT for Panama, which is + # final since 22. The flag is repo-wide and deliberate: mixing previewed and + # non-previewed classfiles is what poisons a build. + - name: Compile the core suite (main + test) + working-directory: lance-graph-java/java + run: | + javac --release 28 --enable-preview -d out \ + $(find src/main/java src/test/java -name '*.java') + # -Dlgj.library is an EXPLICIT request, and `Abi.locateLibrary` refuses to + # fall back to a search path when it cannot be honoured. That is what stops + # this job from silently measuring some other artifact than the one the step + # above just built. + - name: Run the core suite (AllTests) + working-directory: lance-graph-java/java + run: | + java --enable-preview --enable-native-access=ALL-UNNAMED \ + -Dlgj.library="$GITHUB_WORKSPACE/lance-graph-java/native/lgj-abi/target/release/liblgj_abi.so" \ + -cp out com.adaworldapi.lancegraph.AllTests + - name: Compile the consumer suites + working-directory: lance-graph-java + run: | + javac --release 28 --enable-preview -cp java/out -d consumers/out \ + $(find consumers -name '*.java') + # FOUR mains, not three. `trades` carries two — an allocation floor and a + # parity suite — and running only one of them would be the + # no-gate-with-extra-steps outcome: compiling a consumer proves it builds, + # never that its assertions hold. + # + # NOT fail-fast, deliberately. A `run:` step is `bash -e`, and a bare + # `java` in this loop would abort the whole step at the first red main — + # verified, the loop does not reach its remaining members — so one broken + # consumer would mask the other three and each CI round would reveal + # exactly one of them. `|| failed=...` collects instead, and the step still + # exits non-zero. This mirrors `AllTests`, which runs every suite before + # exiting 1 rather than stopping at the first failure. + - name: Run the consumer suites + working-directory: lance-graph-java + run: | + failed="" + for main in com.adaworldapi.bricks.BricksAuthTest \ + com.adaworldapi.graph.GraphHopTest \ + com.adaworldapi.trades.TradesAllocationTest \ + com.adaworldapi.trades.TradesParityTest ; do + echo "::group::$main" + java --enable-preview --enable-native-access=ALL-UNNAMED \ + -Dlgj.library="$GITHUB_WORKSPACE/lance-graph-java/native/lgj-abi/target/release/liblgj_abi.so" \ + -cp "java/out:consumers/out" "$main" || failed="$failed $main" + echo "::endgroup::" + done + if [ -n "$failed" ]; then + echo "::error::consumer suites FAILED:$failed" + exit 1 + fi + echo "all four consumer suites passed" diff --git a/.gitignore b/.gitignore index d822913..317c5ea 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ Cargo.lock.bak *.class /java/out/ /java/target/ +# The java-suites CI job's consumer class tree (it compiles consumers/**/src +# against java/out). Pure build residue, same footing as /java/out/. +/consumers/out/ /bench/out/ # gate-run.sh's two API builds (before/after) + its bench build. Its results/gate-*.csv are # NOT ignored: a real gate run is banked deliberately, by the results commit §5 requires. diff --git a/CLAUDE.md b/CLAUDE.md index 484446e..2540b83 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -68,7 +68,21 @@ all report `isValue() == true` at runtime, and the full suite is **409 checks, 0 failures** under `--release 28 --enable-preview` against a freshly built `liblgj_abi.so` (abi 0.11, `ndarray::simd avx512`) — byte-for-byte the same 409 as the unflipped baseline on the same JDK. `bench/run.sh` carries the pin -and the flag. Measured facts and the obtain route (most JDK hosts are +and the flag. + +**THE CURRENT FIGURE LIVES HERE, AND ONLY HERE.** Measured 2026-09-22 on +`origin/main` (`aef2382`): the core suite is **612 checks across 17 suites, +0 failures**, against `abi 0.12, ndarray::simd avx512, profile release`; the +four consumer mains add **153** (bricks 70, graph 68, trades 3 + 12). The 409 / +16-suite / abi-0.11 figures above and below are the 2026-09-19 and 2026-09-16 +measurements, true on their dates and kept as the dated evidence they are — the +Valhalla-flip comparison in particular is only meaningful against the baseline +it was taken against, so it must NOT be restated forward. ⊘ Every OTHER site in +this file that carried a live count has had the number REMOVED rather than +re-pinned: one measurement restated in eight places goes stale in eight places, +which is exactly what happened here (the count had drifted 409 -> 612 and the +file still briefed every session with 409). A session that needs the current +number runs the suite; the command is four minutes and is written out below. Measured facts and the obtain route (most JDK hosts are egress-blocked here; GitHub release *download* paths are not) live in `.claude/knowledge/jdk-toolchain-facts.md`. @@ -597,7 +611,7 @@ to PR on that basis. > ⊘ **The first version of this section, written earlier the same day, led with > the apt route and was itself misleading.** Re-checked: **`/opt/jdks/jdk-26.0.2` -> was present the whole time** (26.0.2.1), the suite runs `ALL PASSED (409 +> was present the whole time** (26.0.2.1), the suite ran `ALL PASSED (409 > checks)` on it, and `.claude/knowledge/jdk-toolchain-facts.md` had already > named that exact path. Nothing needed installing. The session looked at > `java -version` and `/usr/lib/jvm` — **neither of which sees `/opt/jdks`** — @@ -661,22 +675,58 @@ nothing ran** — a missing library reported as a failure would send the reader hunting a bug that is not there). So: build the `.so`, `javac`, `java`. ```sh -# 1. the native artifact -cd native/lgj-abi && cargo build --release # -> target/release/liblgj_abi.so - -# 2. compile main + test together (56 files) -J=/usr/lib/jvm/temurin-26-jdk-amd64/bin # or java-25-openjdk-amd64 +# Every path below is relative to the REPO ROOT; stay there for all three steps. +# (The block used to `cd native/lgj-abi` in step 1 and then use root-relative +# paths in step 2, so running it top-to-bottom failed on +# `find: 'java/src/main': No such file or directory`.) +SO=$PWD/native/lgj-abi/target/release/liblgj_abi.so + +# 1. the native artifact. The `cd` is LOAD-BEARING and must stay: rustup reads +# `rust-toolchain.toml` from the CWD, and that file lives in native/lgj-abi, +# so `--manifest-path` alone builds with whatever rustc is ambient -- measured +# 2026-09-22, `error: rustc 1.94.1 is not supported ... requires rustc 1.97`, +# exit 101. Same trap as `setup-rust-toolchain`'s `rust-src-dir` input in +# .github/workflows/lint.yml, one layer down. The subshell keeps the CWD from +# leaking into step 2, which is root-relative. +( cd native/lgj-abi && cargo build --release ) + +# 2. compile main + test together (58 files). BOTH flags are required, not +# stylistic: six types in java/src/main are `public value record`, so a +# javac without --enable-preview fails with "value classes are a preview +# feature and are disabled by default" (measured 2026-09-22, exit 1). And +# the JDK must be 28 -- see the inventory note below before reaching for a +# /usr/lib/jvm path. +J=/opt/jdks/jdk-28+16/bin find java/src/main java/src/test -name '*.java' > /tmp/srcs.txt -$J/javac -d /tmp/jout @/tmp/srcs.txt +$J/javac --release 28 --enable-preview -d /tmp/jout @/tmp/srcs.txt # 3. run. `-Dlgj.library` is an EXPLICIT request and `Abi.locateLibrary` # refuses to fall back to a search path if it cannot be honoured — by # design, so a run can never silently measure a different artifact. -$J/java --enable-native-access=ALL-UNNAMED \ - -Dlgj.library=$PWD/target/release/liblgj_abi.so \ +# $PWD/target/release/... was the OLD spelling and was ambiguous: from +# native/lgj-abi it is right, but from the repo root it names an incidental +# leftover `target/` (there is no root Cargo.toml) that is a SEPARATE inode +# from the artifact step 1 builds — byte-identical today, free to diverge, +# and absent entirely in a fresh clone. An ambiguous path is exactly what +# the no-fallback rule exists to rule out, so $SO is absolute. +$J/java --enable-preview --enable-native-access=ALL-UNNAMED \ + -Dlgj.library="$SO" \ -cp /tmp/jout com.adaworldapi.lancegraph.AllTests ``` +> **⊘ CONTAINER JDK INVENTORY, measured 2026-09-22 — the 25/26 routes below are +> RECOVERY instructions, not a description of this container.** `/opt/jdks` +> holds exactly `jdk-28+16` (`jdk-26.0.2` and the `jdk-27` Valhalla EA build +> are both GONE), and `/usr/lib/jvm` holds **only Java 21**, which cannot +> compile this repo at all — value records need 28. So the `temurin-26-jdk-amd64` +> path the command above used to name did not exist, and the reachability table +> further down reads "verified on 25 AND 26" as DATED EVIDENCE from 2026-09-16, +> never as a statement about what is installed now. The rung-1 check +> (`ls -d /opt/jdks/*/`) remains the answer; rungs 3-4 (apt) are what you run +> when rung 1 comes back empty. Same failure shape as the 409-vs-612 drift this +> file already carries: a present-tense claim about a measured environment goes +> stale silently, and the fix is to date it rather than to re-pin it forward. + **Measured 2026-09-16 on BOTH `Temurin 26.0.2.1` and `openjdk 25.0.4`: `ALL PASSED (409 checks)`** across all 16 suites, against `abi 0.11, simd ndarray::simd avx512, profile release` — identical on the two JDKs. The @@ -689,7 +739,7 @@ the artifact you meant. | need | reachable here? | source | |---|---|---| | **Panama FFM** (`java.lang.foreign`, the whole `internal/ffm` membrane) | **YES** — final since 22 | Ubuntu `openjdk-25-jdk-headless`, or Adoptium `temurin-26-jdk` | -| the 16-suite `AllTests` run (409 checks) | **YES**, verified on 25 AND 26 | either of the above | +| the full `AllTests` run | **YES**, verified on 25 AND 26 | either of the above | | `valhalla-lab/src/stable` (records, JDK 26) | **YES** | Adoptium `temurin-26-jdk` | | `valhalla-lab/src/valhalla` (**value** records, JDK 27 EA) | not via apt | `https://jdk.java.net/valhalla/` — reachable, `HTTP 200` | @@ -700,12 +750,15 @@ is a Valhalla EA feature, not a mainline one. `https://jdk.java.net/valhalla/` **is reachable through this environment's proxy** (verified `HTTP 200`), so that build is a download away rather than a blocker. `bench/` and `valhalla-lab/` are measurement arms, NOT gates; the merge gate is the Rust -suite plus the 409-check Java run, and both are reachable here. +suite, the full `AllTests` run, and the four consumer mains — all three +dispatched by the `java-suites` job in `.github/workflows/lint.yml`, and all +three reachable here. (Before that job existed they were LOCAL gates and `main` +could be red unnoticed, which it was; see `ISS-LGJ-CONSUMERS-HAVE-NO-CI-LINE`.) **Consequence for every future session:** "the Java side could not be verified" is no longer an acceptable status line for this repo. The Rust half -(`cargo test` in `native/lgj-abi`) and the Java half (409 checks) are BOTH -runnable in this container, and a PR that claims the Java surface is unverified +(`cargo test` in `native/lgj-abi`) and the Java half (`AllTests`, plus the four +consumer mains) are BOTH runnable in this container, and a PR that claims the Java surface is unverified is claiming something that takes about four minutes to falsify. ## Missing-capability STOP rule