From 124dd9c3c2b3d18d4b4b21af6de108c3ff80f89a Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 05:53:06 +0000 Subject: [PATCH 01/12] build: production targets x86-64-v4; config-v4.toml Production always runs on v4 (Railway about 95%, Claude Code sessions about 70%), so everything shipped builds for x86-64-v4: Dockerfile, Dockerfile.hhtld, cognitive-stack, symbiont, both thinking-engine images, and the wheel (make publish). New .cargo/config-v4.toml mirrors ndarray's (without -Dwarnings) and applies to x86_64 only, so arm64 builds are untouched. On a host without AVX-512, ndarray's startup cpu_guard exits with the missing features instead of a mid-run SIGILL. Measured: --config .cargo/config-v4.toml joins with config.toml's native (-Ctarget-cpu=native -Ctarget-cpu=x86-64-v4); the later flag wins, the cfg equals v4 alone (23 features vs native's 32 on this host). The Dockerfiles copy the file over config.toml and never join. Comments in config.toml, config-v3.toml (no longer the shipping target) and Dockerfile.md updated to match. Board entry D-PROD-V4 records the decision and what stays open (CI tests the v3 arm only; probes don't refuse off-v4 timings; Dockerfile.avx512 now duplicates Dockerfile). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .cargo/config-v3.toml | 7 +-- .cargo/config-v4.toml | 12 +++++ .cargo/config.toml | 15 ++++--- .../2026-10-13-production-targets-v4.md | 42 +++++++++++++++++ .claude/board/entries/README.md | 3 +- Dockerfile | 12 ++--- Dockerfile.avx512 | 2 +- Dockerfile.hhtld | 8 ++-- Dockerfile.md | 45 ++++++++++--------- crates/cognitive-stack/Dockerfile | 8 ++-- crates/symbiont/Dockerfile | 8 ++-- crates/thinking-engine/Dockerfile | 8 ++-- crates/thinking-engine/Dockerfile.railway | 8 ++-- python/Makefile | 8 ++-- 14 files changed, 123 insertions(+), 63 deletions(-) create mode 100644 .cargo/config-v4.toml create mode 100644 .claude/board/entries/2026-10-13-production-targets-v4.md diff --git a/.cargo/config-v3.toml b/.cargo/config-v3.toml index a71aebe5a..e3e98453f 100644 --- a/.cargo/config-v3.toml +++ b/.cargo/config-v3.toml @@ -1,6 +1,7 @@ -# Portable distribution baseline: x86-64-v3 (AVX2), every x86_64 since -# Haswell. REQUIRED for anything shipped from this tree, now that the default -# `.cargo/config.toml` is `native`. Mirrors ndarray/.cargo/config-v3.toml. +# x86-64-v3 (AVX2), every x86_64 since Haswell. NOT the production target: +# production always runs on v4 and ships with config-v4.toml. Kept for +# building or testing the AVX2 arm on purpose. Never cite a timing from a v3 +# build: production does not run that arm. Mirrors ndarray/.cargo/config-v3.toml. # cargo build --config .cargo/config-v3.toml ... [target.'cfg(target_arch = "x86_64")'] rustflags = ["-Ctarget-cpu=x86-64-v3"] diff --git a/.cargo/config-v4.toml b/.cargo/config-v4.toml new file mode 100644 index 000000000..006840089 --- /dev/null +++ b/.cargo/config-v4.toml @@ -0,0 +1,12 @@ +# Production target: x86-64-v4 (AVX-512 F + BW + CD + DQ + VL), nothing above +# it. Production always runs on v4, so everything shipped from this tree +# builds with this file (Dockerfiles) or the same flag (wheel, images that +# copy no .cargo). Mirrors ndarray/.cargo/config-v4.toml without its +# `-Dwarnings`, which is a CI rule, not a build-image rule. +# cargo build --config .cargo/config-v4.toml ... +# On a host without AVX-512 the binary does not SIGILL mid-run: ndarray's +# startup `cpu_guard` names the missing features and exits before `main`. +# `config-avx512.toml` (Sapphire Rapids) is stricter and SIGILLs on earlier +# AVX-512 silicon such as Cascade Lake, so it is not the production default. +[target.'cfg(target_arch = "x86_64")'] +rustflags = ["-Ctarget-cpu=x86-64-v4"] diff --git a/.cargo/config.toml b/.cargo/config.toml index ba4523219..8f2e83535 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -30,10 +30,11 @@ # (`cfg!(target_feature = "avx512f")`), never by "it was the default". # # A default build is therefore tuned to the BUILD HOST and is NOT portable. -# Anything shipped pins its tier explicitly: +# Production always runs on x86-64-v4, so anything shipped builds for v4: # -# portable baseline (AVX2): cargo build --config .cargo/config-v3.toml ... -# AVX-512 (v4): cargo build --config .cargo/config-avx512.toml ... +# production (x86-64-v4): cargo build --config .cargo/config-v4.toml ... +# AVX2 arm on purpose: cargo build --config .cargo/config-v3.toml ... +# Sapphire Rapids only: cargo build --config .cargo/config-avx512.toml ... # # CI: build.yml, rust-test.yml and style.yml set `RUSTFLAGS` with an explicit # `-C target-cpu=x86-64-v3` (a RUSTFLAGS env REPLACES every cargo-config @@ -43,9 +44,11 @@ # (.github/scripts/resolve-native-rustflags.sh, used by dir-sim-persist.yml and # identity.yml) and keys the cache to those flags; without that, an artifact # built on a runner with AVX-512 is reused on one without and dies with SIGILL. -# The same script works locally: RUSTFLAGS="$(.github/scripts/resolve-native-rustflags.sh)". Everything else that ships pins x86_64 to v3 without -# touching other architectures: the Dockerfiles that copy this tree replace -# this file with config-v3.toml (x86_64-only), the thinking-engine images set +# The same script works locally: RUSTFLAGS="$(.github/scripts/resolve-native-rustflags.sh)". +# Everything that ships builds x86_64 for v4 without touching other +# architectures: the Dockerfiles that copy this tree replace this file with +# config-v4.toml (x86_64-only), `Dockerfile` and `Dockerfile.avx512` set +# RUSTFLAGS to x86-64-v4, the thinking-engine images set # CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS, and `make publish` in # python/ sets RUSTFLAGS only on an x86_64 host. Note that the per-target # variable is JOINED with this file's entry, with `native` last (measured), so diff --git a/.claude/board/entries/2026-10-13-production-targets-v4.md b/.claude/board/entries/2026-10-13-production-targets-v4.md new file mode 100644 index 000000000..c3f3e30bb --- /dev/null +++ b/.claude/board/entries/2026-10-13-production-targets-v4.md @@ -0,0 +1,42 @@ +# 2026-10-13 — Production builds target x86-64-v4 (D-PROD-V4) + +**Status:** DONE (build targets); the CI test tier and probe guards are OPEN. + +**DECISION:** everything shipped from this tree builds for x86-64-v4: the +Dockerfiles, the thinking-engine images and the wheel. There is no v3 +production variant. + +**BASIS:** production always runs on v4. Measured exposure: Railway hosts +about 95% v4, Claude Code sessions about 70% v4. A v3 build ships the arm +production never runs, and a timing measured on it is not evidence for +production. + +**SCOPE:** + +| site | before | after | +|---|---|---| +| `Dockerfile` | `RUSTFLAGS -C target-cpu=x86-64-v3` | `x86-64-v4` | +| `Dockerfile.hhtld`, `crates/cognitive-stack/Dockerfile`, `crates/symbiont/Dockerfile` | `cp config-v3.toml config.toml` | `cp config-v4.toml config.toml` (x86_64 only; arm64 untouched) | +| `crates/thinking-engine/Dockerfile`, `Dockerfile.railway` | `CARGO_TARGET_X86_64_…_RUSTFLAGS x86-64-v3` | `x86-64-v4` | +| `python/Makefile` (`make publish`) | `x86-64-v3` on x86_64 hosts | `x86-64-v4` | +| new `.cargo/config-v4.toml` | — | `-Ctarget-cpu=x86-64-v4`, mirrors ndarray's file without `-Dwarnings` | + +**Measured:** `cargo --config .cargo/config-v4.toml` JOINS with +`.cargo/config.toml`'s `native` (rustc receives `-Ctarget-cpu=native +-Ctarget-cpu=x86-64-v4`). The later flag wins: the cfg equals v4 alone +(23 target features), not native (32 on this Cascade Lake host). The +Dockerfiles copy the file over `config.toml`, so they never join. + +**Safety:** on a host without AVX-512, ndarray's startup `cpu_guard` names +the missing features and exits before `main`; the binary does not die with +SIGILL mid-run. That holds only for binaries that link ndarray. + +**OPEN:** +- `build.yml`, `rust-test.yml` and `style.yml` still test the v3 arm only; + production's AVX-512 code paths have no coverage in lance-graph's main CI. +- Probes and examples do not yet refuse to report timings off v4. +- `Dockerfile.avx512` now builds the same tier as `Dockerfile`; it is kept + until nothing names it. +- Not verified with `docker build` here. + +**REVISIT WHEN:** a production host without AVX-512 appears. diff --git a/.claude/board/entries/README.md b/.claude/board/entries/README.md index 1718bc9c5..ebd9de8e5 100644 --- a/.claude/board/entries/README.md +++ b/.claude/board/entries/README.md @@ -25,10 +25,11 @@ index row, (3) no duplicate entry id. Checks 1 and 2 are deliberately opposite directions; the stranding this convention prevents shows up in exactly one of them, never both. -324 entries, 2026-08-06 .. 2026-10-12. +325 entries, 2026-08-06 .. 2026-10-13. | date | entry id | finding | file | |---|---|---|---| +| 2026-10-13 | `D-PROD-V4` | | [2026-10-13-production-targets-v4.md](2026-10-13-production-targets-v4.md) | | 2026-10-12 | `D-SAG-1` | | [2026-10-12-software-awareness-graph.md](2026-10-12-software-awareness-graph.md) | | 2026-10-12 | `D-CMR-RESET` | method layer was a second algebra beside the folds and slower than a row loop (430–480 µs vs 283 µs); moved to backup, rebuild as bindings over existing folds | [2026-10-12-session-reset-inventory.md](2026-10-12-session-reset-inventory.md) | | 2026-10-12 | `D-SAG-5-0` | Post-#1509 SAG self-querying, provenance and limited attention with NARS/Hyperon/PLN comparisons; research prompt and high-signal falsifiers | [2026-10-12-sag-reflexive-cognition-research.md](2026-10-12-sag-reflexive-cognition-research.md) | diff --git a/Dockerfile b/Dockerfile index f8ba785ab..4b5e78f4f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ -# lance-graph — Railway compile-test image (AVX2 default) +# lance-graph — Railway compile-test image (x86-64-v4, the production target) # Verifies the workspace builds cleanly (core + bgz17 + planner + contract) # Requires Rust 1.99.0 (LazyLock, modern std APIs) # # CPU detection & SIMD dispatch documentation: see Dockerfile.md -# AVX-512 pinned variant: see Dockerfile.avx512 +# Dockerfile.avx512 now builds the same tier; it is kept until nothing names it. # # Build: docker build -t lance-graph-test . # Run: docker run --rm lance-graph-test @@ -41,10 +41,10 @@ COPY crates/bgz17/Cargo.toml crates/bgz17/Cargo.toml # Copy source COPY crates/ crates/ -# Default target: x86-64-v3 (AVX2) — runs on GitHub CI and most servers. -# Use Dockerfile.avx512 for x86-64-v4 (AVX-512) on Skylake-X / Ice Lake / Sapphire Rapids. -# The .cargo/config.toml pins x86-64-v4 for LOCAL builds; override here for portability. -ENV RUSTFLAGS="-C target-cpu=x86-64-v3" +# Production always runs on x86-64-v4, so the compile-test image builds and +# tests that arm. (The repo's .cargo/config.toml defaults to `native`; this +# RUSTFLAGS replaces it.) +ENV RUSTFLAGS="-C target-cpu=x86-64-v4" # Build bgz17 standalone (zero deps, fast check) RUN cargo build --release --manifest-path crates/bgz17/Cargo.toml 2>&1 \ diff --git a/Dockerfile.avx512 b/Dockerfile.avx512 index 154d4d9fb..5989ab48f 100644 --- a/Dockerfile.avx512 +++ b/Dockerfile.avx512 @@ -5,7 +5,7 @@ # ONLY deploy on AVX-512 hardware. # # CPU detection & SIMD dispatch documentation: see Dockerfile.md -# Portable (AVX2) variant: see Dockerfile +# Dockerfile builds the same tier (x86-64-v4) since production moved to v4. # # Build: docker build -f Dockerfile.avx512 -t lance-graph-avx512 . # Run: docker run --rm lance-graph-avx512 diff --git a/Dockerfile.hhtld b/Dockerfile.hhtld index 7927a30ea..753dd9598 100644 --- a/Dockerfile.hhtld +++ b/Dockerfile.hhtld @@ -48,12 +48,12 @@ RUN if [ ! -d /build/ndarray ]; then \ fi WORKDIR /build/lance-graph -# Portable baseline. The repo's .cargo/config.toml defaults to `native` -# (tuned to the build host); an image must run on any x86_64 since Haswell. -# The copied tree's config is replaced by config-v3.toml, which only applies +# Production target. The repo's .cargo/config.toml defaults to `native` +# (tuned to the build host); production always runs on x86-64-v4, so the +# copied tree's config is replaced by config-v4.toml. That file only applies # to x86_64 targets, so an arm64 build keeps its own aarch64 baseline (a # global RUSTFLAGS would hand the aarch64 compiler an x86 CPU name). -RUN cp .cargo/config-v3.toml .cargo/config.toml +RUN cp .cargo/config-v4.toml .cargo/config.toml # Build the decode example (the inference binary) RUN cargo build --release --example tts_17b_hhtld_decode \ diff --git a/Dockerfile.md b/Dockerfile.md index dd0ec3f30..5dcf2488a 100644 --- a/Dockerfile.md +++ b/Dockerfile.md @@ -1,13 +1,17 @@ # lance-graph Docker CPU Detection & SIMD Dispatch -## Three-Tier Build Strategy +## Build Targets -| Target | Dockerfile | RUSTFLAGS | Use case | +Production always runs on x86-64-v4 (AVX-512), so every image and the wheel +build for v4. + +| Target | File | Flags | Use case | |---|---|---|---| -| **Portable (AVX2)** | `Dockerfile` | `-C target-cpu=x86-64-v3` | GitHub CI, general servers | -| **AVX-512 pinned** | `Dockerfile.avx512` | `-C target-cpu=x86-64-v4` | Production (Skylake-X+) | -| **HHTL-D TTS** | `Dockerfile.hhtld` | (inherits) | TTS inference container | -| **Local dev** | `.cargo/config.toml` | `-C target-cpu=x86-64-v4` | Developer machines | +| **Compile test (v4)** | `Dockerfile` | `-C target-cpu=x86-64-v4` | Railway compile/test image | +| **Same tier** | `Dockerfile.avx512` | `-C target-cpu=x86-64-v4` | Kept until nothing names it | +| **HHTL-D TTS** | `Dockerfile.hhtld` | `.cargo/config-v4.toml` | TTS inference container | +| **Local dev** | `.cargo/config.toml` | `-C target-cpu=native` | Developer machines (host CPU) | +| **CI tests** | `build.yml`, `rust-test.yml`, `style.yml` | `-C target-cpu=x86-64-v3` | Not production; never cite a timing from it | ## How lance-graph Uses SIMD @@ -52,14 +56,16 @@ Polyfill (ndarray simd.rs): **Important:** `RUSTFLAGS` env var **replaces** (not appends to) the `rustflags` array in `.cargo/config.toml`. This is a Cargo design decision. -lance-graph's `.cargo/config.toml` sets `target-cpu=x86-64-v4` for local dev. -CI workflows set `RUSTFLAGS="-C debuginfo=1 -C target-cpu=x86-64-v3"` which -**overrides** config.toml entirely. The CI binary targets AVX2. +lance-graph's `.cargo/config.toml` sets `target-cpu=native` for local dev. +The test workflows set `RUSTFLAGS="-C debuginfo=0 -C target-cpu=x86-64-v3"`, +which **overrides** config.toml entirely, so those CI binaries target AVX2. -This is intentional: -- Local dev: maximum SIMD (AVX-512, everything inlined) -- CI: portable (AVX2, runtime detection for anything higher) -- Production Docker: choose `Dockerfile` (AVX2) or `Dockerfile.avx512` +- Local dev: the host CPU (`native`). +- CI tests: AVX2. Production does not run this arm, so a timing from it is + not evidence. +- Production: x86-64-v4, in every Dockerfile and the wheel. On a host without + AVX-512, ndarray's startup `cpu_guard` names the missing features and exits + before `main` instead of dying with SIGILL. ## AMX Detection @@ -77,11 +83,9 @@ lance-graph inherits this via ndarray; no ARM-specific configuration needed. ## Choosing the Right Dockerfile ``` -GitHub CI / PR checks → Dockerfile (AVX2, -C target-cpu=x86-64-v3) -Railway / production → Dockerfile.avx512 (-C target-cpu=x86-64-v4) -TTS inference → Dockerfile.hhtld (downloads codebooks + runs decoder) -Raspberry Pi / ARM → Dockerfile (NEON auto-detected at runtime) -Maximum compatibility → docker build --build-arg RUSTFLAGS="-C target-cpu=x86-64" +Railway / production → Dockerfile or Dockerfile.avx512 (-C target-cpu=x86-64-v4) +TTS inference → Dockerfile.hhtld (config-v4.toml; downloads codebooks) +Raspberry Pi / ARM → Dockerfile.hhtld (config-v4.toml applies to x86_64 only) ``` ## Verifying CPU Features @@ -98,12 +102,9 @@ println!("{:?}", simd_caps()); // CpuCaps { avx512: true, avx2: true, fma: true ## Build Examples ```bash -# Default (AVX2) — safe everywhere +# Production tier (x86-64-v4) docker build -t lance-graph-test . -# AVX-512 pinned — production servers -docker build -f Dockerfile.avx512 -t lance-graph-avx512 . - # TTS inference docker build -f Dockerfile.hhtld \ --build-arg RELEASE_TAG=v0.1.0 \ diff --git a/crates/cognitive-stack/Dockerfile b/crates/cognitive-stack/Dockerfile index acdbfffeb..d9bc11e69 100644 --- a/crates/cognitive-stack/Dockerfile +++ b/crates/cognitive-stack/Dockerfile @@ -35,12 +35,12 @@ WORKDIR /build # The lance-graph repo (this build context). cognitive-stack path-deps the # in-repo crates (lance-graph, the four template crates, lance-graph-ogar). COPY . /build/lance-graph -# Portable baseline. The repo's .cargo/config.toml defaults to `native` -# (tuned to the build host); an image must run on any x86_64 since Haswell. -# The copied tree's config is replaced by config-v3.toml, which only applies +# Production target. The repo's .cargo/config.toml defaults to `native` +# (tuned to the build host); production always runs on x86-64-v4, so the +# copied tree's config is replaced by config-v4.toml. That file only applies # to x86_64 targets, so an arm64 build keeps its own aarch64 baseline (a # global RUSTFLAGS would hand the aarch64 compiler an x86 CPU name). -RUN cp /build/lance-graph/.cargo/config-v3.toml /build/lance-graph/.cargo/config.toml +RUN cp /build/lance-graph/.cargo/config-v4.toml /build/lance-graph/.cargo/config.toml # lance-graph path-deps the ndarray fork as a SIBLING (`../../../ndarray`). # Clone it next to the repo so that path resolves. diff --git a/crates/symbiont/Dockerfile b/crates/symbiont/Dockerfile index c54144a36..3be3157c0 100644 --- a/crates/symbiont/Dockerfile +++ b/crates/symbiont/Dockerfile @@ -35,12 +35,12 @@ WORKDIR /build # The lance-graph repo (this build context). symbiont path-deps lance-graph + # perturbation-sim from inside it. COPY . /build/lance-graph -# Portable baseline. The repo's .cargo/config.toml defaults to `native` -# (tuned to the build host); an image must run on any x86_64 since Haswell. -# The copied tree's config is replaced by config-v3.toml, which only applies +# Production target. The repo's .cargo/config.toml defaults to `native` +# (tuned to the build host); production always runs on x86-64-v4, so the +# copied tree's config is replaced by config-v4.toml. That file only applies # to x86_64 targets, so an arm64 build keeps its own aarch64 baseline (a # global RUSTFLAGS would hand the aarch64 compiler an x86 CPU name). -RUN cp /build/lance-graph/.cargo/config-v3.toml /build/lance-graph/.cargo/config.toml +RUN cp /build/lance-graph/.cargo/config-v4.toml /build/lance-graph/.cargo/config.toml # lance-graph's own Cargo.toml path-deps the ndarray fork as a SIBLING # (`../../../ndarray`). Clone it next to the repo so that path resolves. diff --git a/crates/thinking-engine/Dockerfile b/crates/thinking-engine/Dockerfile index 125a69359..f58e3261e 100644 --- a/crates/thinking-engine/Dockerfile +++ b/crates/thinking-engine/Dockerfile @@ -1,8 +1,8 @@ FROM rust:1.98.1-bookworm AS builder -# Portable baseline for x86_64 only: this image does not copy .cargo, so the -# per-target variable is the only flag source, and it does not apply when -# building for another architecture. -ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C target-cpu=x86-64-v3" +# Production target (x86-64-v4) for x86_64 only: this image does not copy +# .cargo, so the per-target variable is the only flag source, and it does not +# apply when building for another architecture. +ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C target-cpu=x86-64-v4" WORKDIR /app # Dependencies first (cached layer) diff --git a/crates/thinking-engine/Dockerfile.railway b/crates/thinking-engine/Dockerfile.railway index d54e5489a..cd8adbfe2 100644 --- a/crates/thinking-engine/Dockerfile.railway +++ b/crates/thinking-engine/Dockerfile.railway @@ -7,10 +7,10 @@ # The codebooks run standalone for reasoning at 5,676 queries/sec FROM rust:1.98.1-bookworm AS builder -# Portable baseline for x86_64 only: this image does not copy .cargo, so the -# per-target variable is the only flag source, and it does not apply when -# building for another architecture. -ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C target-cpu=x86-64-v3" +# Production target (x86-64-v4) for x86_64 only: this image does not copy +# .cargo, so the per-target variable is the only flag source, and it does not +# apply when building for another architecture. +ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C target-cpu=x86-64-v4" WORKDIR /app # Copy workspace diff --git a/python/Makefile b/python/Makefile index eb8b886b0..a210c10cf 100644 --- a/python/Makefile +++ b/python/Makefile @@ -25,10 +25,10 @@ clean: rm -rf ../target # The repo's .cargo/config.toml defaults to `native`, which would tune the -# wheel to the build host; a published x86_64 wheel must run on any x86_64 -# since Haswell. RUSTFLAGS replaces the config's flags; it is set only on an -# x86_64 host so an arm64 build keeps its own baseline. -PORTABLE_RUSTFLAGS := $(if $(filter x86_64,$(shell uname -m)),RUSTFLAGS="-C target-cpu=x86-64-v3",) +# wheel to the build host; production runs on x86-64-v4, so the wheel is +# built for exactly that. RUSTFLAGS replaces the config's flags; it is set +# only on an x86_64 host so an arm64 build keeps its own baseline. +PORTABLE_RUSTFLAGS := $(if $(filter x86_64,$(shell uname -m)),RUSTFLAGS="-C target-cpu=x86-64-v4",) publish: $(PORTABLE_RUSTFLAGS) maturin build --release --out dist --sdist From f466ef62a01428ea42adba9514ece58115793056 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 05:56:15 +0000 Subject: [PATCH 02/12] docs: Dockerfile.avx512 is the canonical deploy file Dockerfile is the same-tier fallback for a deploy that does not name Dockerfile.avx512. Board entry records the open native-vs-v4 choice for that fallback. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .claude/board/entries/2026-10-13-production-targets-v4.md | 6 ++++-- Dockerfile | 3 ++- Dockerfile.avx512 | 3 ++- Dockerfile.md | 6 +++--- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.claude/board/entries/2026-10-13-production-targets-v4.md b/.claude/board/entries/2026-10-13-production-targets-v4.md index c3f3e30bb..8a307a7a7 100644 --- a/.claude/board/entries/2026-10-13-production-targets-v4.md +++ b/.claude/board/entries/2026-10-13-production-targets-v4.md @@ -35,8 +35,10 @@ SIGILL mid-run. That holds only for binaries that link ndarray. - `build.yml`, `rust-test.yml` and `style.yml` still test the v3 arm only; production's AVX-512 code paths have no coverage in lance-graph's main CI. - Probes and examples do not yet refuse to report timings off v4. -- `Dockerfile.avx512` now builds the same tier as `Dockerfile`; it is kept - until nothing names it. +- Open choice: `Dockerfile.avx512` is the canonical deploy file and plain + `Dockerfile` is the same-tier fallback for a deploy that forgets the file + name. Whether that fallback should be `native` instead of v4 is undecided; + `native` tunes to the Railway build host, not the run host. - Not verified with `docker build` here. **REVISIT WHEN:** a production host without AVX-512 appears. diff --git a/Dockerfile b/Dockerfile index 4b5e78f4f..7a9c265ff 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,8 @@ # Requires Rust 1.99.0 (LazyLock, modern std APIs) # # CPU detection & SIMD dispatch documentation: see Dockerfile.md -# Dockerfile.avx512 now builds the same tier; it is kept until nothing names it. +# Dockerfile.avx512 is the canonical deploy file. This image builds the same +# tier, so a deploy that names it by mistake still gets x86-64-v4. # # Build: docker build -t lance-graph-test . # Run: docker run --rm lance-graph-test diff --git a/Dockerfile.avx512 b/Dockerfile.avx512 index 5989ab48f..c642b2541 100644 --- a/Dockerfile.avx512 +++ b/Dockerfile.avx512 @@ -5,7 +5,8 @@ # ONLY deploy on AVX-512 hardware. # # CPU detection & SIMD dispatch documentation: see Dockerfile.md -# Dockerfile builds the same tier (x86-64-v4) since production moved to v4. +# This is the canonical deploy file. Dockerfile builds the same tier +# (x86-64-v4) as the fallback when a deploy does not name this one. # # Build: docker build -f Dockerfile.avx512 -t lance-graph-avx512 . # Run: docker run --rm lance-graph-avx512 diff --git a/Dockerfile.md b/Dockerfile.md index 5dcf2488a..feb3c2963 100644 --- a/Dockerfile.md +++ b/Dockerfile.md @@ -7,8 +7,8 @@ build for v4. | Target | File | Flags | Use case | |---|---|---|---| -| **Compile test (v4)** | `Dockerfile` | `-C target-cpu=x86-64-v4` | Railway compile/test image | -| **Same tier** | `Dockerfile.avx512` | `-C target-cpu=x86-64-v4` | Kept until nothing names it | +| **Deploy (canonical)** | `Dockerfile.avx512` | `-C target-cpu=x86-64-v4` | Railway / production deploys | +| **Same-tier fallback** | `Dockerfile` | `-C target-cpu=x86-64-v4` | Compile/test image; a deploy that forgets the file name still gets v4 | | **HHTL-D TTS** | `Dockerfile.hhtld` | `.cargo/config-v4.toml` | TTS inference container | | **Local dev** | `.cargo/config.toml` | `-C target-cpu=native` | Developer machines (host CPU) | | **CI tests** | `build.yml`, `rust-test.yml`, `style.yml` | `-C target-cpu=x86-64-v3` | Not production; never cite a timing from it | @@ -83,7 +83,7 @@ lance-graph inherits this via ndarray; no ARM-specific configuration needed. ## Choosing the Right Dockerfile ``` -Railway / production → Dockerfile or Dockerfile.avx512 (-C target-cpu=x86-64-v4) +Railway / production → Dockerfile.avx512 (canonical); Dockerfile is the same-tier fallback TTS inference → Dockerfile.hhtld (config-v4.toml; downloads codebooks) Raspberry Pi / ARM → Dockerfile.hhtld (config-v4.toml applies to x86_64 only) ``` From ba407ea02031a553577e455ddff510a27e488c19 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 05:57:59 +0000 Subject: [PATCH 03/12] ci: compile and link the x86-64-v4 arm without running it linux-build-v4 builds lance-graph's tests and benches for x86-64-v4 on a GitHub runner (mostly v3) and runs nothing. --target keeps RUSTFLAGS off build scripts and proc-macros, which do run on the host. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .../2026-10-13-production-targets-v4.md | 8 ++- .github/workflows/build.yml | 52 +++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/.claude/board/entries/2026-10-13-production-targets-v4.md b/.claude/board/entries/2026-10-13-production-targets-v4.md index 8a307a7a7..60e172044 100644 --- a/.claude/board/entries/2026-10-13-production-targets-v4.md +++ b/.claude/board/entries/2026-10-13-production-targets-v4.md @@ -32,8 +32,12 @@ the missing features and exits before `main`; the binary does not die with SIGILL mid-run. That holds only for binaries that link ndarray. **OPEN:** -- `build.yml`, `rust-test.yml` and `style.yml` still test the v3 arm only; - production's AVX-512 code paths have no coverage in lance-graph's main CI. +- `build.yml` gains `linux-build-v4`: it compiles and links lance-graph's + tests at x86-64-v4 with `--target`, so build scripts stay at the host + baseline, and runs nothing (most GitHub runners are v3). The v4 arm is now + compiled in CI but still never executed there. +- `build.yml`, `rust-test.yml` and `style.yml` still RUN tests on a v3 pin + instead of per-runner `native` (the #1526 resolver). - Probes and examples do not yet refuse to report timings off v4. - Open choice: `Dockerfile.avx512` is the canonical deploy file and plain `Dockerfile` is the same-tier fallback for a deploy that forgets the file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 90da7f3a0..1feac59c4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,3 +83,55 @@ jobs: run: cargo test --manifest-path crates/lance-graph/Cargo.toml - name: Check benchmarks run: cargo check --manifest-path crates/lance-graph/Cargo.toml --benches + + # Production runs x86-64-v4, but GitHub's runners are mostly v3, so the v4 + # arm cannot be executed here. This job compiles and links it without + # running anything. + # + # `--target` is load-bearing: without it RUSTFLAGS also reaches build + # scripts and proc-macros, which DO run on this host, so a v3 runner could + # die with SIGILL in the middle of the build. With an explicit target, + # RUSTFLAGS applies only to target artifacts (measured: the build script + # compiles with no target-cpu, the crate with x86-64-v4). + linux-build-v4: + runs-on: ubuntu-24.04 + timeout-minutes: 30 + env: + RUSTFLAGS: "-C debuginfo=0 -C target-cpu=x86-64-v4" + defaults: + run: + working-directory: lance-graph + steps: + - uses: actions/checkout@v4 + with: + path: lance-graph + - name: Checkout AdaWorldAPI/ndarray (sibling dependency) + uses: actions/checkout@v4 + with: + repository: AdaWorldAPI/ndarray + path: ndarray + - uses: actions/checkout@v4 + with: + repository: AdaWorldAPI/OGAR + path: OGAR + - name: Setup rust toolchain (pinned by rust-toolchain.toml) + run: rustup show + - name: Setup mold linker + uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 + - uses: Swatinem/rust-cache@v2 + with: + shared-key: "lance-graph-deps-v4" + workspaces: | + lance-graph/crates/lance-graph + - name: Install dependencies + run: | + sudo apt update + sudo apt install -y protobuf-compiler + - name: Check the target really is v4 + run: | + rustc --print cfg -C target-cpu=x86-64-v4 | grep -qx 'target_feature="avx512f"' + echo "Built for x86-64-v4 (not run). Runner CPU: $(grep -m1 'model name' /proc/cpuinfo | cut -d: -f2)" >> "$GITHUB_STEP_SUMMARY" + - name: Build tests for x86-64-v4 (no run) + run: cargo test --manifest-path crates/lance-graph/Cargo.toml --target x86_64-unknown-linux-gnu --no-run + - name: Check benchmarks for x86-64-v4 + run: cargo check --manifest-path crates/lance-graph/Cargo.toml --target x86_64-unknown-linux-gnu --benches From 467be2f1cf906d4bed78912dd40da3f78339cf88 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 06:00:07 +0000 Subject: [PATCH 04/12] ci: debug 0 for every artifact in the v4 compile job With --target, RUSTFLAGS no longer reaches build scripts and proc-macros, which then took the profile default (measured: -C debuginfo=2 on a build script). CARGO_PROFILE_{DEV,TEST}_DEBUG=0 pins them to 0; runner disk makes that mandatory. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .github/workflows/build.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1feac59c4..f242ac0d3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -98,6 +98,12 @@ jobs: timeout-minutes: 30 env: RUSTFLAGS: "-C debuginfo=0 -C target-cpu=x86-64-v4" + # Runner disk makes debug 0 mandatory. With `--target`, RUSTFLAGS no + # longer reaches build scripts and proc-macros, so their debug level + # comes from the profile; these pin it to 0 for every artifact. + CARGO_PROFILE_DEV_DEBUG: "0" + CARGO_PROFILE_TEST_DEBUG: "0" + CARGO_INCREMENTAL: "0" defaults: run: working-directory: lance-graph From b8db4b8853f7769315984f064f7d68243e57be4c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 06:01:32 +0000 Subject: [PATCH 05/12] board: record the debug-0 disk and time effect in D-PROD-V4 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .claude/board/entries/2026-10-13-production-targets-v4.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.claude/board/entries/2026-10-13-production-targets-v4.md b/.claude/board/entries/2026-10-13-production-targets-v4.md index 60e172044..bd19f7f89 100644 --- a/.claude/board/entries/2026-10-13-production-targets-v4.md +++ b/.claude/board/entries/2026-10-13-production-targets-v4.md @@ -27,6 +27,13 @@ production. (23 target features), not native (32 on this Cascade Lake host). The Dockerfiles copy the file over `config.toml`, so they never join. +**Debug 0 in CI (reported by the maintainer, not re-measured here):** a +build without debug info drops from 16-19 GB to 3.5 GB of disk and from +22-42 to 4-9 minutes. With `--target`, RUSTFLAGS no longer reaches build +scripts and proc-macros (measured: a build script compiled with +`-C debuginfo=2`), so the v4 job also sets `CARGO_PROFILE_DEV_DEBUG=0` and +`CARGO_PROFILE_TEST_DEBUG=0`. + **Safety:** on a host without AVX-512, ndarray's startup `cpu_guard` names the missing features and exits before `main`; the binary does not die with SIGILL mid-run. That holds only for binaries that link ndarray. From dcb8248d839826da6dcd0cc9db528631a5f577e5 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 06:03:45 +0000 Subject: [PATCH 06/12] =?UTF-8?q?board:=20#1525=20merged=20(D-NALP-1/2)=20?= =?UTF-8?q?=E2=80=94=20arc=20entry,=20LATEST=5FSTATE,=20STATUS=5FBOARD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .claude/board/LATEST_STATE.md | 7 ++++--- .claude/board/PR_ARC_INVENTORY.md | 7 +++++++ .claude/board/STATUS_BOARD.md | 4 ++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.claude/board/LATEST_STATE.md b/.claude/board/LATEST_STATE.md index 82210ed6e..a5847a842 100644 --- a/.claude/board/LATEST_STATE.md +++ b/.claude/board/LATEST_STATE.md @@ -1,11 +1,12 @@ -## 2026-10-13 — main after #1505, #1506, #1507–#1509, #1514, #1516, #1518, #1520, #1523, #1524, #1526 (merged); #1525 open +## 2026-10-13 — main after #1505, #1506, #1507–#1509, #1514, #1516, #1518, #1520, #1523, #1524, #1525, #1526 (merged); #1529 open - **On `main`, live:** `.cargo/config.toml` defaults to `-Ctarget-cpu=native` with `config-v3.toml` as the portable baseline and `debug = 0` everywhere (#1505); `compute_dag_kahn` checks all 256 field positions (#1506); R2IL `MIN`/`MAX` lowering onto mask-risc (#1518, the part outside glove-parity). - **Merged then withdrawn by #1524 (D-CMR-RESET):** the class-method layer of `lance-graph-glove-parity` (`method`, `call`, `decl`, `gremlin`, `awareness`; #1507, #1508, #1509, #1514, #1516, #1518, #1520). Prior state: `backup/session-011BMJ-2026-10-12`. Inventory: entry `2026-10-12-session-reset-inventory.md`. - **Docs only:** SAG capstone (#1523): `ProposedMethod`, four-state status; not built. -- **Open:** #1525 D-NALP W1/W2 (`lance-graph-nal`: NodeGuid-keyed beliefs, byte apertures, `Question`/`TruthAtLeast`/`Choice` over compiled mask-risc programs; mask-risc `CompiledProgram`). +- **On `main` (#1525, merged `08635ed`):** D-NALP W1/W2, `crates/lance-graph-nal` (NodeGuid-keyed beliefs, byte apertures, `Question`/`TruthAtLeast`/`Choice` over compiled mask-risc programs; mask-risc `CompiledProgram`). +- **Open:** #1529 D-PROD-V4 (shipped images and the wheel build at x86-64-v4; `linux-build-v4` compiles the v4 arm in CI without running it). - **CI (#1526, merged `abc0a1f`):** the native default plus `rust-cache` reused AVX-512 artifacts on runners without them (SIGILL in `dir-sim log in Lance`). `native` is now written out as each runner's exact feature list, and the cache is keyed to it. -- **Rules carried from this session (operator):** classid-dependent methods go through the existing `hotplug.rs` plug-and-play; NAL/NARS operations are global core methods (no classid check, no plug, no `BeliefClass`); internal pins are forbidden (the v3 pins in the Dockerfiles and wheel build are an open decision). +- **Rules carried from this session (operator):** classid-dependent methods go through the existing `hotplug.rs` plug-and-play; NAL/NARS operations are global core methods (no classid check, no plug, no `BeliefClass`); internal pins are forbidden (the v3 pins in the Dockerfiles and wheel build are replaced by v4 in #1529). ## 2026-10-12 — dir-sim membership path witness + role evidence on branch `ccr-0455e606-wmtsor` (unmerged) diff --git a/.claude/board/PR_ARC_INVENTORY.md b/.claude/board/PR_ARC_INVENTORY.md index b397adec8..bd0f58201 100644 --- a/.claude/board/PR_ARC_INVENTORY.md +++ b/.claude/board/PR_ARC_INVENTORY.md @@ -1,3 +1,10 @@ +## 2026-10-13 — lance-graph PR #1525 (merged `08635ed`, branch `ccr-9f3b8075-74u47l-nalp`, head `077bb0a`, 16 commits) — D-NALP-1/2: NAL queries as NodeGuid apertures over the fold path + +- **Added:** new crate `crates/lance-graph-nal` (excluded, own workspace root, like `lance-graph-r2il`). A belief's key is its NodeGuid in the reading `nal-statement-v1` (`[classid, S, copula, P, id]`); `f` and `c` are value lanes in the key's sealed order. A selection is `Aperture { key, bytes }` (4 = class, 6 = subject, 10 = statement), resolved to one range by `SealedFacetLane::bound_aperture`. `nal::{Question, TruthAtLeast, Choice}` lower their R2IL procedure over `FoldDialect` once at bind and keep the mask-risc `Program`; calls run `execute_compiled` with the aperture range as the extent. mask-risc gains `CompiledProgram`. +- **Locked:** no new opcode (`FN = None` for every operation); no foreign keys. Measured (release, AVX-512, n = 1,048,576, median of 101, answers checked before timing): Question 19–20 ns, TruthAtLeast 81–127 ns, Choice 248 ns, bind 274 ns, row loop 495–559 µs; the subject range passed as an ANDed mask instead of the extent took 195 µs. 7 oracle tests over unsorted input; 7 disable runs red. +- **Deferred / open:** R2IL `RANGE` takes its bounds from two `u8` immediates, so it cannot name a range past row 255 (procedures use `FoldDialect::emit_pred(Pred::Range)`; needs an `ogar-r2il` change). No argmax fold: `Choice` returns the maximum confidence, not the belief. D-NALP-1's ClassView `WideFieldMask` projection and binder mask, and W3 (revision) onward, are not built. +- **Confidence:** high for the three queries at the measured size; the `u8` range limit is real and unfixed. + ## 2026-10-13 — lance-graph PR #1526 (merged `abc0a1f`, branch `ccr-9f3b8075-74u47l-cpukey`, head `8342c9f`, 4 commits) — CI: spell target-cpu=native out per runner and key the cache to it - **Added:** `.github/scripts/resolve-native-rustflags.sh`: prints `-Ctarget-feature=` with the runner's exact native feature list and no CPU name, and fails unless `rustc --print cfg` under those flags equals native; `--cpu` prints the name for logs. `dir-sim-persist.yml` and `identity.yml` set `RUSTFLAGS` from it before each of their three rust-cache steps, key the cache on its hash, and write the CPU to the job summary. diff --git a/.claude/board/STATUS_BOARD.md b/.claude/board/STATUS_BOARD.md index 9c3ae2192..07e539797 100644 --- a/.claude/board/STATUS_BOARD.md +++ b/.claude/board/STATUS_BOARD.md @@ -53,8 +53,8 @@ Plan: `.claude/plans/nal-polyfill-v1.md`. Template: D-SQLP. No opcode, tenant or | D-id | scope | status | gate / falsifier | |---|---|---|---| | **D-NALP-0** | Plan, board rows | In PR | docs only | -| **D-NALP-1** | Statement layout + declared ClassView reading; additive `WideFieldMask` projection path on `ClassView`; binder's mask; term width decision | In PR #1525 (NodeGuid reading `nal-statement-v1`, term width u16, aperture selection; ClassView wide projection and binder mask still queued) | only the mask's lanes are read; undeclared reading and masked-out field refuse; Small = Wide answers | -| **D-NALP-2** | Query procedures: select, truth threshold, choice by confidence, support count | In PR #1525 (`crates/lance-graph-nal`: NodeGuid key, byte apertures; 7 oracle tests, 7 disable runs red; 19–248 ns at 1,048,576 rows) | equal to a row-at-a-time oracle; one-pattern threshold disable red; no new opcode | +| **D-NALP-1** | Statement layout + declared ClassView reading; additive `WideFieldMask` projection path on `ClassView`; binder's mask; term width decision | Partial: #1525 merged `08635ed` (NodeGuid reading `nal-statement-v1`, term width u16, aperture selection); ClassView wide projection and binder mask Queued | only the mask's lanes are read; undeclared reading and masked-out field refuse; Small = Wide answers | +| **D-NALP-2** | Query procedures: select, truth threshold, choice by confidence, support count | Shipped #1525 `08635ed` (`crates/lance-graph-nal`: NodeGuid key, byte apertures; 7 oracle tests, 7 disable runs red; 19–248 ns at 1,048,576 rows); support count and argmax not built | equal to a row-at-a-time oracle; one-pattern threshold disable red; no new opcode | | **D-NALP-3** | Revision as `GroupCrossPowerSumsI32` over stored `w`/`f` | Queued | equal to exact integer revision; OpenNARS revision points; duplicate evidence counts once | | **D-NALP-4** | Per-row truth law into a lane: `MapPairU8` vs fixed-point multiply-high | Queued | insufficiency proof; per-row parity with `isa::truth`, error in codes; one shape also serves SQL nullable arithmetic | | **D-NALP-5** | Deduction / induction / abduction / analogy over populations | Queued (after D-NALP-4) | equals pairwise scalar rule; abduction direction test red for the reversed statement | From 63d720e36ff198f783f9d31ecd9624768a0788fa Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 06:05:03 +0000 Subject: [PATCH 07/12] build: Dockerfile.avx512 targets sapphirerapids Railway hosts are Sapphire Rapids, Emerald Rapids or newer. The canonical deploy file now compiles VNNI, BF16 and FP16 in; plain Dockerfile stays at x86-64-v4 as the fallback. The build stage runs the tests, so a build on an older host fails there instead of in production. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .../2026-10-13-production-targets-v4.md | 14 +++++++---- Dockerfile | 5 ++-- Dockerfile.avx512 | 24 ++++++++++++------- Dockerfile.md | 11 +++++---- 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/.claude/board/entries/2026-10-13-production-targets-v4.md b/.claude/board/entries/2026-10-13-production-targets-v4.md index bd19f7f89..f1a656537 100644 --- a/.claude/board/entries/2026-10-13-production-targets-v4.md +++ b/.claude/board/entries/2026-10-13-production-targets-v4.md @@ -15,7 +15,8 @@ production. | site | before | after | |---|---|---| -| `Dockerfile` | `RUSTFLAGS -C target-cpu=x86-64-v3` | `x86-64-v4` | +| `Dockerfile` | `RUSTFLAGS -C target-cpu=x86-64-v3` | `x86-64-v4` (fallback) | +| `Dockerfile.avx512` (canonical deploy) | `x86-64-v4` | `sapphirerapids` (Railway hosts are Sapphire Rapids, Emerald Rapids or newer, per the maintainer) | | `Dockerfile.hhtld`, `crates/cognitive-stack/Dockerfile`, `crates/symbiont/Dockerfile` | `cp config-v3.toml config.toml` | `cp config-v4.toml config.toml` (x86_64 only; arm64 untouched) | | `crates/thinking-engine/Dockerfile`, `Dockerfile.railway` | `CARGO_TARGET_X86_64_…_RUSTFLAGS x86-64-v3` | `x86-64-v4` | | `python/Makefile` (`make publish`) | `x86-64-v3` on x86_64 hosts | `x86-64-v4` | @@ -46,10 +47,13 @@ SIGILL mid-run. That holds only for binaries that link ndarray. - `build.yml`, `rust-test.yml` and `style.yml` still RUN tests on a v3 pin instead of per-runner `native` (the #1526 resolver). - Probes and examples do not yet refuse to report timings off v4. -- Open choice: `Dockerfile.avx512` is the canonical deploy file and plain - `Dockerfile` is the same-tier fallback for a deploy that forgets the file - name. Whether that fallback should be `native` instead of v4 is undecided; - `native` tunes to the Railway build host, not the run host. +- `Dockerfile.avx512` builds `sapphirerapids`; its build stage runs the + tests, so that arm executes on the Railway build host and nowhere else. + CI compiles only the v4 arm; the Sapphire Rapids-only code (VNNI, BF16, + FP16) is not compiled in lance-graph CI. +- Plain `Dockerfile` stays at v4 as the fallback. `native` was rejected: it + tunes to the build host, and a newer build host would compile in features + a Sapphire Rapids run host lacks. - Not verified with `docker build` here. **REVISIT WHEN:** a production host without AVX-512 appears. diff --git a/Dockerfile b/Dockerfile index 7a9c265ff..434014e33 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,8 +3,9 @@ # Requires Rust 1.99.0 (LazyLock, modern std APIs) # # CPU detection & SIMD dispatch documentation: see Dockerfile.md -# Dockerfile.avx512 is the canonical deploy file. This image builds the same -# tier, so a deploy that names it by mistake still gets x86-64-v4. +# Dockerfile.avx512 is the canonical deploy file (sapphirerapids). This image +# builds the broader x86-64-v4 tier as the fallback for a deploy that does not +# name that file. # # Build: docker build -t lance-graph-test . # Run: docker run --rm lance-graph-test diff --git a/Dockerfile.avx512 b/Dockerfile.avx512 index c642b2541..00a2ec2cc 100644 --- a/Dockerfile.avx512 +++ b/Dockerfile.avx512 @@ -1,12 +1,18 @@ -# lance-graph — AVX-512 pinned build (server/Railway) -# target-cpu=x86-64-v4: native AVX-512, all SIMD inlined. -# Consumes ndarray with same AVX-512 pinning. +# lance-graph — Sapphire Rapids build (server/Railway) +# target-cpu=sapphirerapids: the x86-64-v4 AVX-512 baseline plus VNNI, BF16, +# FP16, VBMI2, BITALG and VPOPCNTDQ (AMX is runtime-detected by ndarray; +# stable rustc does not expose it as a cfg). Railway hosts are Sapphire Rapids, +# Emerald Rapids or newer; all of them carry these features. # -# ONLY deploy on AVX-512 hardware. +# ONLY deploy on Sapphire Rapids or newer. On an older host ndarray's startup +# cpu_guard names the missing features and exits before main. +# +# The build stage runs the tests, so they execute on the build host: a build +# that lands on an older host fails here instead of in production. # # CPU detection & SIMD dispatch documentation: see Dockerfile.md -# This is the canonical deploy file. Dockerfile builds the same tier -# (x86-64-v4) as the fallback when a deploy does not name this one. +# This is the canonical deploy file. Dockerfile builds the broader x86-64-v4 +# tier as the fallback when a deploy does not name this one. # # Build: docker build -f Dockerfile.avx512 -t lance-graph-avx512 . # Run: docker run --rm lance-graph-avx512 @@ -30,8 +36,8 @@ WORKDIR /app COPY Cargo.toml ./ COPY crates/ crates/ -# AVX-512 pinned: compile-time dispatch, everything inlined -ENV RUSTFLAGS="-C target-cpu=x86-64-v4" +# Compile-time dispatch for Sapphire Rapids, everything inlined +ENV RUSTFLAGS="-C target-cpu=sapphirerapids" # bgz17 standalone (zero deps, fast check) RUN cargo build --release --manifest-path crates/bgz17/Cargo.toml 2>&1 \ @@ -53,4 +59,4 @@ RUN cargo test --release \ FROM debian:bookworm-slim RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates && rm -rf /var/lib/apt/lists/* -CMD ["echo", "lance-graph AVX-512 build verified — Rust 1.99.0, target-cpu=x86-64-v4"] +CMD ["echo", "lance-graph build verified — Rust 1.99.0, target-cpu=sapphirerapids"] diff --git a/Dockerfile.md b/Dockerfile.md index feb3c2963..f3dc90b47 100644 --- a/Dockerfile.md +++ b/Dockerfile.md @@ -2,13 +2,14 @@ ## Build Targets -Production always runs on x86-64-v4 (AVX-512), so every image and the wheel -build for v4. +Production always runs on x86-64-v4 (AVX-512) or better. Railway hosts are +Sapphire Rapids, Emerald Rapids or newer, so the canonical deploy file builds +for `sapphirerapids`; every other image and the wheel build for v4. | Target | File | Flags | Use case | |---|---|---|---| -| **Deploy (canonical)** | `Dockerfile.avx512` | `-C target-cpu=x86-64-v4` | Railway / production deploys | -| **Same-tier fallback** | `Dockerfile` | `-C target-cpu=x86-64-v4` | Compile/test image; a deploy that forgets the file name still gets v4 | +| **Deploy (canonical)** | `Dockerfile.avx512` | `-C target-cpu=sapphirerapids` | Railway / production (Sapphire Rapids, Emerald Rapids or newer) | +| **Fallback** | `Dockerfile` | `-C target-cpu=x86-64-v4` | Compile/test image; a deploy that forgets the file name still gets AVX-512 | | **HHTL-D TTS** | `Dockerfile.hhtld` | `.cargo/config-v4.toml` | TTS inference container | | **Local dev** | `.cargo/config.toml` | `-C target-cpu=native` | Developer machines (host CPU) | | **CI tests** | `build.yml`, `rust-test.yml`, `style.yml` | `-C target-cpu=x86-64-v3` | Not production; never cite a timing from it | @@ -83,7 +84,7 @@ lance-graph inherits this via ndarray; no ARM-specific configuration needed. ## Choosing the Right Dockerfile ``` -Railway / production → Dockerfile.avx512 (canonical); Dockerfile is the same-tier fallback +Railway / production → Dockerfile.avx512 (sapphirerapids, canonical); Dockerfile (v4) is the fallback TTS inference → Dockerfile.hhtld (config-v4.toml; downloads codebooks) Raspberry Pi / ARM → Dockerfile.hhtld (config-v4.toml applies to x86_64 only) ``` From 9b282a110f892841d3478cadd44165691c1a7ab9 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 06:06:26 +0000 Subject: [PATCH 08/12] build: fallback Dockerfile targets native The canonical deploy file stays sapphirerapids; the fallback builds for the build host's CPU, guarded at startup by ndarray's cpu_guard. Board records that neither Dockerfile provides the ndarray sibling the build needs. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .../entries/2026-10-13-production-targets-v4.md | 12 ++++++++---- Dockerfile | 14 +++++++------- Dockerfile.avx512 | 4 ++-- Dockerfile.md | 7 ++++--- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/.claude/board/entries/2026-10-13-production-targets-v4.md b/.claude/board/entries/2026-10-13-production-targets-v4.md index f1a656537..d4d9ed27b 100644 --- a/.claude/board/entries/2026-10-13-production-targets-v4.md +++ b/.claude/board/entries/2026-10-13-production-targets-v4.md @@ -15,7 +15,7 @@ production. | site | before | after | |---|---|---| -| `Dockerfile` | `RUSTFLAGS -C target-cpu=x86-64-v3` | `x86-64-v4` (fallback) | +| `Dockerfile` | `RUSTFLAGS -C target-cpu=x86-64-v3` | `native` (fallback; the build host's CPU) | | `Dockerfile.avx512` (canonical deploy) | `x86-64-v4` | `sapphirerapids` (Railway hosts are Sapphire Rapids, Emerald Rapids or newer, per the maintainer) | | `Dockerfile.hhtld`, `crates/cognitive-stack/Dockerfile`, `crates/symbiont/Dockerfile` | `cp config-v3.toml config.toml` | `cp config-v4.toml config.toml` (x86_64 only; arm64 untouched) | | `crates/thinking-engine/Dockerfile`, `Dockerfile.railway` | `CARGO_TARGET_X86_64_…_RUSTFLAGS x86-64-v3` | `x86-64-v4` | @@ -51,9 +51,13 @@ SIGILL mid-run. That holds only for binaries that link ndarray. tests, so that arm executes on the Railway build host and nowhere else. CI compiles only the v4 arm; the Sapphire Rapids-only code (VNNI, BF16, FP16) is not compiled in lance-graph CI. -- Plain `Dockerfile` stays at v4 as the fallback. `native` was rejected: it - tunes to the build host, and a newer build host would compile in features - a Sapphire Rapids run host lacks. +- Plain `Dockerfile` builds `native` (maintainer's decision). It tunes to the + build host; if the run host lacks a compiled-in feature, ndarray's startup + `cpu_guard` stops the binary before `main`, and ndarray#360 warns at build + time about enabled features the guard has no row for. +- Neither Dockerfile provides the ndarray sibling (`/ndarray`) that the + default features and `lance-graph-planner` require, so as written they + cannot resolve dependencies; `crates/symbiont/Dockerfile` clones it. - Not verified with `docker build` here. **REVISIT WHEN:** a production host without AVX-512 appears. diff --git a/Dockerfile b/Dockerfile index 434014e33..8885e78e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,12 @@ -# lance-graph — Railway compile-test image (x86-64-v4, the production target) +# lance-graph — Railway compile-test image (target-cpu=native, the build host) # Verifies the workspace builds cleanly (core + bgz17 + planner + contract) # Requires Rust 1.99.0 (LazyLock, modern std APIs) # # CPU detection & SIMD dispatch documentation: see Dockerfile.md # Dockerfile.avx512 is the canonical deploy file (sapphirerapids). This image -# builds the broader x86-64-v4 tier as the fallback for a deploy that does not -# name that file. +# is the fallback for a deploy that does not name that file: it builds for the +# build host's own CPU, so it takes whatever that host has. ndarray's startup +# cpu_guard stops the binary on a run host that lacks a compiled-in feature. # # Build: docker build -t lance-graph-test . # Run: docker run --rm lance-graph-test @@ -43,10 +44,9 @@ COPY crates/bgz17/Cargo.toml crates/bgz17/Cargo.toml # Copy source COPY crates/ crates/ -# Production always runs on x86-64-v4, so the compile-test image builds and -# tests that arm. (The repo's .cargo/config.toml defaults to `native`; this -# RUSTFLAGS replaces it.) -ENV RUSTFLAGS="-C target-cpu=x86-64-v4" +# The build host's own CPU, the same default as the repo's .cargo/config.toml +# (which this image does not copy, so it is set here). +ENV RUSTFLAGS="-C target-cpu=native" # Build bgz17 standalone (zero deps, fast check) RUN cargo build --release --manifest-path crates/bgz17/Cargo.toml 2>&1 \ diff --git a/Dockerfile.avx512 b/Dockerfile.avx512 index 00a2ec2cc..1bb4e9c09 100644 --- a/Dockerfile.avx512 +++ b/Dockerfile.avx512 @@ -11,8 +11,8 @@ # that lands on an older host fails here instead of in production. # # CPU detection & SIMD dispatch documentation: see Dockerfile.md -# This is the canonical deploy file. Dockerfile builds the broader x86-64-v4 -# tier as the fallback when a deploy does not name this one. +# This is the canonical deploy file. Dockerfile builds for the build host's +# CPU (native) as the fallback when a deploy does not name this one. # # Build: docker build -f Dockerfile.avx512 -t lance-graph-avx512 . # Run: docker run --rm lance-graph-avx512 diff --git a/Dockerfile.md b/Dockerfile.md index f3dc90b47..3c5214d37 100644 --- a/Dockerfile.md +++ b/Dockerfile.md @@ -4,12 +4,13 @@ Production always runs on x86-64-v4 (AVX-512) or better. Railway hosts are Sapphire Rapids, Emerald Rapids or newer, so the canonical deploy file builds -for `sapphirerapids`; every other image and the wheel build for v4. +for `sapphirerapids`, the fallback `Dockerfile` builds `native` (the build +host), and every other image and the wheel build for v4. | Target | File | Flags | Use case | |---|---|---|---| | **Deploy (canonical)** | `Dockerfile.avx512` | `-C target-cpu=sapphirerapids` | Railway / production (Sapphire Rapids, Emerald Rapids or newer) | -| **Fallback** | `Dockerfile` | `-C target-cpu=x86-64-v4` | Compile/test image; a deploy that forgets the file name still gets AVX-512 | +| **Fallback** | `Dockerfile` | `-C target-cpu=native` | Compile/test image; a deploy that forgets the file name gets the build host's CPU | | **HHTL-D TTS** | `Dockerfile.hhtld` | `.cargo/config-v4.toml` | TTS inference container | | **Local dev** | `.cargo/config.toml` | `-C target-cpu=native` | Developer machines (host CPU) | | **CI tests** | `build.yml`, `rust-test.yml`, `style.yml` | `-C target-cpu=x86-64-v3` | Not production; never cite a timing from it | @@ -84,7 +85,7 @@ lance-graph inherits this via ndarray; no ARM-specific configuration needed. ## Choosing the Right Dockerfile ``` -Railway / production → Dockerfile.avx512 (sapphirerapids, canonical); Dockerfile (v4) is the fallback +Railway / production → Dockerfile.avx512 (sapphirerapids, canonical); Dockerfile (native) is the fallback TTS inference → Dockerfile.hhtld (config-v4.toml; downloads codebooks) Raspberry Pi / ARM → Dockerfile.hhtld (config-v4.toml applies to x86_64 only) ``` From ead937100c4c6b97fce39e1c7e8ffcd20447faf4 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 06:11:06 +0000 Subject: [PATCH 09/12] ci: compile both production tiers in linux-build-v4 linux-build-v4 becomes a matrix over x86-64-v4 and sapphirerapids, each compiled and linked with --target and run nowhere. Companion: AdaWorldAPI/ndarray#361. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .../2026-10-13-production-targets-v4.md | 11 ++++----- .github/workflows/build.yml | 23 +++++++++++++------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/.claude/board/entries/2026-10-13-production-targets-v4.md b/.claude/board/entries/2026-10-13-production-targets-v4.md index d4d9ed27b..d97abe4df 100644 --- a/.claude/board/entries/2026-10-13-production-targets-v4.md +++ b/.claude/board/entries/2026-10-13-production-targets-v4.md @@ -40,17 +40,16 @@ the missing features and exits before `main`; the binary does not die with SIGILL mid-run. That holds only for binaries that link ndarray. **OPEN:** -- `build.yml` gains `linux-build-v4`: it compiles and links lance-graph's - tests at x86-64-v4 with `--target`, so build scripts stay at the host - baseline, and runs nothing (most GitHub runners are v3). The v4 arm is now - compiled in CI but still never executed there. +- `build.yml` gains `linux-build-v4`, a two-entry matrix (`x86-64-v4`, + `sapphirerapids`): it compiles and links lance-graph's tests for each tier + with `--target`, so build scripts stay at the host baseline, and runs + nothing (most GitHub runners are v3). Both tiers are compiled in CI but + never executed there. ndarray gets the same pair in AdaWorldAPI/ndarray#361. - `build.yml`, `rust-test.yml` and `style.yml` still RUN tests on a v3 pin instead of per-runner `native` (the #1526 resolver). - Probes and examples do not yet refuse to report timings off v4. - `Dockerfile.avx512` builds `sapphirerapids`; its build stage runs the tests, so that arm executes on the Railway build host and nowhere else. - CI compiles only the v4 arm; the Sapphire Rapids-only code (VNNI, BF16, - FP16) is not compiled in lance-graph CI. - Plain `Dockerfile` builds `native` (maintainer's decision). It tunes to the build host; if the run host lacks a compiled-in feature, ndarray's startup `cpu_guard` stops the binary before `main`, and ndarray#360 warns at build diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f242ac0d3..5ed2cdbba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -93,11 +93,20 @@ jobs: # die with SIGILL in the middle of the build. With an explicit target, # RUSTFLAGS applies only to target artifacts (measured: the build script # compiles with no target-cpu, the crate with x86-64-v4). + # + # Two tiers: x86-64-v4 (the floor production runs on) and sapphirerapids + # (Dockerfile.avx512, the canonical deploy; Railway hosts are Sapphire + # Rapids, Emerald Rapids or newer). Both compile, neither runs. linux-build-v4: + name: linux-build-v4 (${{ matrix.cpu }}) runs-on: ubuntu-24.04 timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + cpu: [x86-64-v4, sapphirerapids] env: - RUSTFLAGS: "-C debuginfo=0 -C target-cpu=x86-64-v4" + RUSTFLAGS: "-C debuginfo=0 -C target-cpu=${{ matrix.cpu }}" # Runner disk makes debug 0 mandatory. With `--target`, RUSTFLAGS no # longer reaches build scripts and proc-macros, so their debug level # comes from the profile; these pin it to 0 for every artifact. @@ -126,18 +135,18 @@ jobs: uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 - uses: Swatinem/rust-cache@v2 with: - shared-key: "lance-graph-deps-v4" + shared-key: "lance-graph-deps-${{ matrix.cpu }}" workspaces: | lance-graph/crates/lance-graph - name: Install dependencies run: | sudo apt update sudo apt install -y protobuf-compiler - - name: Check the target really is v4 + - name: Check the target really is AVX-512 run: | - rustc --print cfg -C target-cpu=x86-64-v4 | grep -qx 'target_feature="avx512f"' - echo "Built for x86-64-v4 (not run). Runner CPU: $(grep -m1 'model name' /proc/cpuinfo | cut -d: -f2)" >> "$GITHUB_STEP_SUMMARY" - - name: Build tests for x86-64-v4 (no run) + rustc --print cfg -C target-cpu=${{ matrix.cpu }} | grep -qx 'target_feature="avx512f"' + echo "Built for ${{ matrix.cpu }} (not run). Runner CPU: $(grep -m1 'model name' /proc/cpuinfo | cut -d: -f2)" >> "$GITHUB_STEP_SUMMARY" + - name: Build tests for ${{ matrix.cpu }} (no run) run: cargo test --manifest-path crates/lance-graph/Cargo.toml --target x86_64-unknown-linux-gnu --no-run - - name: Check benchmarks for x86-64-v4 + - name: Check benchmarks for ${{ matrix.cpu }} run: cargo check --manifest-path crates/lance-graph/Cargo.toml --target x86_64-unknown-linux-gnu --benches From 0badfafc3d161e86bc6d11307814a6f2284eb7eb Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 06:13:32 +0000 Subject: [PATCH 10/12] build: keep v4 flags off build scripts in the config-v4 images Dockerfile.hhtld, crates/cognitive-stack/Dockerfile and crates/symbiont/Dockerfile build with --target , so the cfg-keyed v4 flags reach only the binary, not build scripts and proc-macros, which run on the build host. Outputs are copied back to the paths the runtime stages read. (codex P1) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .../2026-10-13-production-targets-v4.md | 6 +++++ Dockerfile.hhtld | 24 +++++++++++++++---- crates/cognitive-stack/Dockerfile | 11 ++++++++- crates/symbiont/Dockerfile | 11 ++++++++- 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/.claude/board/entries/2026-10-13-production-targets-v4.md b/.claude/board/entries/2026-10-13-production-targets-v4.md index d97abe4df..340812588 100644 --- a/.claude/board/entries/2026-10-13-production-targets-v4.md +++ b/.claude/board/entries/2026-10-13-production-targets-v4.md @@ -35,6 +35,12 @@ scripts and proc-macros (measured: a build script compiled with `-C debuginfo=2`), so the v4 job also sets `CARGO_PROFILE_DEV_DEBUG=0` and `CARGO_PROFILE_TEST_DEBUG=0`. +**Build scripts:** the three images that copy `config-v4.toml` build with +`--target ` (codex P1 on #1529). Without it the cfg-keyed v4 +flags also reach build scripts and proc-macros, which run on the build host +(measured on a scratch crate: the build script compiled with +`target-cpu=x86-64-v4`; with `--target`, with none). + **Safety:** on a host without AVX-512, ndarray's startup `cpu_guard` names the missing features and exits before `main`; the binary does not die with SIGILL mid-run. That holds only for binaries that link ndarray. diff --git a/Dockerfile.hhtld b/Dockerfile.hhtld index 753dd9598..ffa6076ae 100644 --- a/Dockerfile.hhtld +++ b/Dockerfile.hhtld @@ -55,14 +55,30 @@ WORKDIR /build/lance-graph # global RUSTFLAGS would hand the aarch64 compiler an x86 CPU name). RUN cp .cargo/config-v4.toml .cargo/config.toml +# `--target ` keeps the v4 flags on the binary only. Without it +# cargo also compiles build scripts and proc-macros for v4 and runs them +# here, so a build host without AVX-512 would die with SIGILL mid-build. +# With an explicit target they stay at the host baseline. The binaries then +# land under target// and are copied to the path the runtime stage +# reads. +# thinking-engine is excluded from the workspace, so CARGO_TARGET_DIR pins +# the output to the directory the runtime stage copies from. +ENV CARGO_TARGET_DIR=/build/lance-graph/target + # Build the decode example (the inference binary) -RUN cargo build --release --example tts_17b_hhtld_decode \ - --manifest-path crates/thinking-engine/Cargo.toml 2>&1 || \ +RUN T="$(rustc -vV | sed -n 's/^host: //p')" \ + && cargo build --release --target "$T" --example tts_17b_hhtld_decode \ + --manifest-path crates/thinking-engine/Cargo.toml 2>&1 \ + && mkdir -p target/release/examples \ + && cp "target/$T/release/examples/tts_17b_hhtld_decode" target/release/examples/ || \ echo "Build failed — ndarray dependency may be missing" # Also build the cascade runner if available -RUN cargo build --release --example tts_cascade_runner \ - --manifest-path crates/thinking-engine/Cargo.toml 2>&1 || true +RUN T="$(rustc -vV | sed -n 's/^host: //p')" \ + && cargo build --release --target "$T" --example tts_cascade_runner \ + --manifest-path crates/thinking-engine/Cargo.toml 2>&1 \ + && mkdir -p target/release/examples \ + && cp "target/$T/release/examples/tts_cascade_runner" target/release/examples/ || true # ═══════════════════════════════════════════════════════════════════ # Stage 2: Runtime diff --git a/crates/cognitive-stack/Dockerfile b/crates/cognitive-stack/Dockerfile index d9bc11e69..06a96a4c4 100644 --- a/crates/cognitive-stack/Dockerfile +++ b/crates/cognitive-stack/Dockerfile @@ -48,7 +48,16 @@ RUN git clone --depth 1 --branch "$ADA_BRANCH" \ https://github.com/AdaWorldAPI/ndarray.git /build/ndarray WORKDIR /build/lance-graph/crates/cognitive-stack -RUN cargo build --release +# `--target ` keeps the v4 flags on the binary only. Without it +# cargo also compiles build scripts and proc-macros for v4 and runs them +# here, so a build host without AVX-512 would die with SIGILL mid-build. +# With an explicit target they stay at the host baseline. The binaries then +# land under target// and are copied to the path the runtime stage +# reads. +RUN T="$(rustc -vV | sed -n 's/^host: //p')" \ + && cargo build --release --target "$T" \ + && mkdir -p target/release \ + && cp "target/$T/release/cognitive-stack" target/release/ # ── runtime ────────────────────────────────────────────────────────────────── FROM debian:bookworm-slim diff --git a/crates/symbiont/Dockerfile b/crates/symbiont/Dockerfile index 3be3157c0..be728ca1a 100644 --- a/crates/symbiont/Dockerfile +++ b/crates/symbiont/Dockerfile @@ -48,7 +48,16 @@ RUN git clone --depth 1 --branch "$ADA_BRANCH" \ https://github.com/AdaWorldAPI/ndarray.git /build/ndarray WORKDIR /build/lance-graph/crates/symbiont -RUN cargo build --release +# `--target ` keeps the v4 flags on the binary only. Without it +# cargo also compiles build scripts and proc-macros for v4 and runs them +# here, so a build host without AVX-512 would die with SIGILL mid-build. +# With an explicit target they stay at the host baseline. The binaries then +# land under target// and are copied to the path the runtime stage +# reads. +RUN T="$(rustc -vV | sed -n 's/^host: //p')" \ + && cargo build --release --target "$T" \ + && mkdir -p target/release \ + && cp "target/$T/release/symbiont" target/release/ # ── runtime ────────────────────────────────────────────────────────────────── FROM debian:bookworm-slim From 56eff6e0cbd82d2fde2427b637237551bc7224fe Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 06:23:21 +0000 Subject: [PATCH 11/12] build: make Dockerfile and Dockerfile.avx512 resolve the workspace Both clone the ndarray and OGAR siblings at their default branches to /ndarray and /OGAR and copy tools/ (the workspace member outside crates/). Dockerfile.hhtld's fallback fetched ndarray's nonexistent main branch; it now fetches master. Checked in a Docker-shaped layout: all members and path dependencies resolve. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- .../entries/2026-10-13-production-targets-v4.md | 11 ++++++++--- Dockerfile | 12 +++++++++++- Dockerfile.avx512 | 12 +++++++++++- Dockerfile.hhtld | 2 +- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/.claude/board/entries/2026-10-13-production-targets-v4.md b/.claude/board/entries/2026-10-13-production-targets-v4.md index 340812588..64d7daccf 100644 --- a/.claude/board/entries/2026-10-13-production-targets-v4.md +++ b/.claude/board/entries/2026-10-13-production-targets-v4.md @@ -60,9 +60,14 @@ SIGILL mid-run. That holds only for binaries that link ndarray. build host; if the run host lacks a compiled-in feature, ndarray's startup `cpu_guard` stops the binary before `main`, and ndarray#360 warns at build time about enabled features the guard has no row for. -- Neither Dockerfile provides the ndarray sibling (`/ndarray`) that the - default features and `lance-graph-planner` require, so as written they - cannot resolve dependencies; `crates/symbiont/Dockerfile` clones it. +- `Dockerfile` and `Dockerfile.avx512` could not resolve dependencies: they + provided neither sibling the workspace path-deps (ndarray, OGAR) and did not + copy the workspace member `tools/dto-class-check`. Both now clone ndarray and + OGAR at their default branches (`master`, `main`) to `/ndarray` and `/OGAR` + and copy `tools/`. Checked in a Docker-shaped layout: every member and path + dependency resolves (cargo reached locking 879 packages; only `--offline` + stopped the download). `Dockerfile.hhtld`'s fallback fetched ndarray's + `main` branch, which does not exist; it now fetches `master`. - Not verified with `docker build` here. **REVISIT WHEN:** a production host without AVX-512 appears. diff --git a/Dockerfile b/Dockerfile index 8885e78e1..6591218d9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ FROM debian:bookworm-slim AS builder # System deps for arrow/lance/protobuf RUN apt-get update && apt-get install -y --no-install-recommends \ - curl ca-certificates gcc libc6-dev pkg-config libssl-dev \ + curl ca-certificates gcc libc6-dev pkg-config libssl-dev git \ protobuf-compiler cmake \ && rm -rf /var/lib/apt/lists/* @@ -27,6 +27,14 @@ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ sh -s -- -y --default-toolchain 1.99.0 --profile minimal \ && rustc --version | grep -q "1.99.0" +# lance-graph path-deps two sibling repos: ndarray (`../ndarray` from the +# workspace root, `../../../ndarray` from a crate) and OGAR. With the +# workspace at /app both resolve to the filesystem root, so they are cloned +# to /ndarray and /OGAR. No branch is named: each repo's default branch +# (ndarray `master`, OGAR `main`) is the floating head the CI jobs also build. +RUN git clone --depth 1 https://github.com/AdaWorldAPI/ndarray.git /ndarray \ + && git clone --depth 1 https://github.com/AdaWorldAPI/OGAR.git /OGAR + WORKDIR /app # Copy workspace manifest (no lock — see ISS-STALE-AUTHORITY-LOCKS) @@ -43,6 +51,8 @@ COPY crates/bgz17/Cargo.toml crates/bgz17/Cargo.toml # Copy source COPY crates/ crates/ +# Workspace member outside crates/ (the root Cargo.toml lists it). +COPY tools/ tools/ # The build host's own CPU, the same default as the repo's .cargo/config.toml # (which this image does not copy, so it is set here). diff --git a/Dockerfile.avx512 b/Dockerfile.avx512 index 1bb4e9c09..b87787d81 100644 --- a/Dockerfile.avx512 +++ b/Dockerfile.avx512 @@ -20,7 +20,7 @@ FROM debian:bookworm-slim AS builder RUN apt-get update && apt-get install -y --no-install-recommends \ - curl ca-certificates gcc libc6-dev pkg-config libssl-dev \ + curl ca-certificates gcc libc6-dev pkg-config libssl-dev git \ protobuf-compiler cmake \ && rm -rf /var/lib/apt/lists/* @@ -31,10 +31,20 @@ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ sh -s -- -y --default-toolchain 1.99.0 --profile minimal \ && rustc --version | grep -q "1.99.0" +# lance-graph path-deps two sibling repos: ndarray (`../ndarray` from the +# workspace root, `../../../ndarray` from a crate) and OGAR. With the +# workspace at /app both resolve to the filesystem root, so they are cloned +# to /ndarray and /OGAR. No branch is named: each repo's default branch +# (ndarray `master`, OGAR `main`) is the floating head the CI jobs also build. +RUN git clone --depth 1 https://github.com/AdaWorldAPI/ndarray.git /ndarray \ + && git clone --depth 1 https://github.com/AdaWorldAPI/OGAR.git /OGAR + WORKDIR /app COPY Cargo.toml ./ COPY crates/ crates/ +# Workspace member outside crates/ (the root Cargo.toml lists it). +COPY tools/ tools/ # Compile-time dispatch for Sapphire Rapids, everything inlined ENV RUSTFLAGS="-C target-cpu=sapphirerapids" diff --git a/Dockerfile.hhtld b/Dockerfile.hhtld index ffa6076ae..d59bccdb6 100644 --- a/Dockerfile.hhtld +++ b/Dockerfile.hhtld @@ -43,7 +43,7 @@ COPY . /build/lance-graph # If building in CI, clone it here: RUN if [ ! -d /build/ndarray ]; then \ echo "WARNING: ndarray not found, attempting clone..." && \ - curl -sL "https://github.com/AdaWorldAPI/ndarray/archive/refs/heads/main.tar.gz" | \ + curl -sL "https://github.com/AdaWorldAPI/ndarray/archive/refs/heads/master.tar.gz" | \ tar xz && mv ndarray-* /build/ndarray || true; \ fi From 6197dac89a09d4b8fcf4534677dbdbfda13e5002 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 06:24:29 +0000 Subject: [PATCH 12/12] python: scope the wheel's v4 flags to the target (no SIGILL in proc-macros) make publish passes --target to maturin on x86_64, so the x86-64-v4 RUSTFLAGS reach only the wheel's code, not build scripts and proc-macros that run on the publishing host. (coderabbit) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011BMJnDBAfzcuQh5HeT39Rh --- python/Makefile | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/python/Makefile b/python/Makefile index a210c10cf..48bd880af 100644 --- a/python/Makefile +++ b/python/Makefile @@ -28,7 +28,15 @@ clean: # wheel to the build host; production runs on x86-64-v4, so the wheel is # built for exactly that. RUSTFLAGS replaces the config's flags; it is set # only on an x86_64 host so an arm64 build keeps its own baseline. -PORTABLE_RUSTFLAGS := $(if $(filter x86_64,$(shell uname -m)),RUSTFLAGS="-C target-cpu=x86-64-v4",) +# +# `--target ` is load-bearing: without it RUSTFLAGS also reaches +# build scripts and proc-macros (serde, pyo3, tokio), which run on this host, +# so a publishing machine without AVX-512 would die with SIGILL. With an +# explicit target the flags reach only the wheel's own code. +IS_X86_64 := $(filter x86_64,$(shell uname -m)) +HOST_TRIPLE := $(shell rustc -vV | sed -n 's/^host: //p') +PORTABLE_RUSTFLAGS := $(if $(IS_X86_64),RUSTFLAGS="-C target-cpu=x86-64-v4",) +PORTABLE_TARGET := $(if $(IS_X86_64),--target $(HOST_TRIPLE),) publish: - $(PORTABLE_RUSTFLAGS) maturin build --release --out dist --sdist + $(PORTABLE_RUSTFLAGS) maturin build --release --out dist --sdist $(PORTABLE_TARGET)