diff --git a/CLAUDE.md b/CLAUDE.md index 981cd5db..dee2a21a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -136,14 +136,23 @@ The v1.5 trust hardening added: **Next (v2.2+)** (precise status): -- **Chapel → Rust C FFI bridge (L2, half-done)**. Zig shim - (`src/zig_ffi/`, 738 LoC, 4 files) and Chapel POC (`src/chapel/`, - 970 LoC) in place behind `--features chapel`; `cargo build --features - chapel` works standalone, 6/6 `proof_search` tests pass. The gap: - `dispatch.rs` still bypasses the feature-gated `ChapelParallelSearch` - strategy in `proof_search.rs`. Integration is split into 7 L2 sub-waves - tracked in `docs/handover/TODO.md`, gated on L1 Cap'n Proto completion. - Direct Rust↔Chapel today goes through Zig (no shortcut path). +- **Chapel → Rust C FFI bridge (L2.1 done; L2.2–L2.7 gated)**. Zig shim + (`src/zig_ffi/`) and Chapel POC (`src/chapel/`) are in place behind + `--features chapel`. L2.1 is wired: `ChapelParallelSearch` + (`proof_search.rs`) is invoked by `dispatch.rs::verify_proof_parallel` + and reachable on the live `/api/verify_parallel` route, with graceful + sequential fallback. `just build-chapel-ffi && cargo build --features + chapel` builds and links standalone; `cargo test --features chapel` + passes including the chapel-gated `test_verify_proof_parallel_chapel_path` + (7/7). Build reproducibility was fixed 2026-05-18: `build.rs` now + `rerun-if-changed` on the built Zig artifact (was order-dependent on + recipe vs prior `cargo` run), and `build.zig` bundles compiler-rt (was + failing the non-Zig link with `undefined symbol: __zig_probe_stack`). + Remaining L2.2–L2.7 (speculative search, corpus-parallel, mutation + parallelism, multi-locale, numeric hot paths, bench) are **not started + and hard-gated on L1 Cap'n Proto**, itself gated on the L3 7-day-green + hand-off — see `docs/handover/TODO.md`. Direct Rust↔Chapel goes + through Zig (no shortcut path). - **Train GNN/Transformer on larger corpus (Flux.jl, scaffold-only)**. Flux.jl is declared in `src/julia/Project.toml` and imported across diff --git a/Justfile b/Justfile index a1824d60..05077bf5 100644 --- a/Justfile +++ b/Justfile @@ -505,8 +505,10 @@ build-chapel: build-chapel-ffi cargo build --features chapel # Test Chapel integration +# Includes the chapel-gated dispatch test (verify_proof_parallel) — the bare +# `proof_search` filter alone silently skipped it. test-chapel: build-chapel-ffi - cargo test --features chapel -- proof_search + cargo test --features chapel --lib -- proof_search verify_proof_parallel # Test Zig FFI bridge independently test-chapel-ffi: diff --git a/build.rs b/build.rs index 172cdca4..d0dbc469 100644 --- a/build.rs +++ b/build.rs @@ -120,5 +120,12 @@ fn main() { // Re-run if FFI source changes println!("cargo:rerun-if-changed=src/zig_ffi/chapel_bridge.zig"); println!("cargo:rerun-if-changed=src/zig_ffi/build.zig"); + // Re-run when the *built artifact* appears or changes. Without this, + // a `cargo build` performed before `just build-chapel-ffi` caches the + // "library not found" decision (no link directives emitted) and a + // later Zig build is never picked up — link fails with undefined + // `echidna_chapel_*` symbols regardless of recipe order. + println!("cargo:rerun-if-changed=src/zig_ffi/zig-out/lib/libechidna_chapel_ffi.a"); + println!("cargo:rerun-if-changed=src/zig_ffi/zig-out/lib"); } } diff --git a/docs/handover/TODO.md b/docs/handover/TODO.md index 47b61e02..f458a0c1 100644 --- a/docs/handover/TODO.md +++ b/docs/handover/TODO.md @@ -111,11 +111,11 @@ Rationale: HTTP+JSON on Rust↔Julia hot path (`src/rust/gnn/client.rs:1-195` ## P3 — L2: Chapel maximum integration (~5–6 weeks, gated on L1) -Existing POC: `chapel_poc/parallel_proof_search.chpl` (420 LoC) + the self-linking FFI bridge (`53ab9b8`). **Not yet in dispatch path.** Sub-waves: +Existing POC: `chapel_poc/parallel_proof_search.chpl` (420 LoC) + the self-linking FFI bridge (`53ab9b8`). **L2.1 is wired into the dispatch path** (`dispatch.rs::verify_proof_parallel` → `ChapelParallelSearch`, live on `/api/verify_parallel`). Sub-waves: | Sub-wave | Scope | Est | |----------|-------|-----| -| L2.1 | Portfolio dispatch (promote POC) → `src/chapel/portfolio.chpl`; atomic first-wins; wire into `src/rust/dispatch.rs` behind `--chapel` feature flag | 1 week | +| L2.1 | ✅ **Done.** Portfolio dispatch POC promoted; `ChapelParallelSearch` wired into `src/rust/dispatch.rs` behind `--features chapel` with sequential fallback; reachable via `/api/verify_parallel`. Build reproducibility fixed 2026-05-18 (`build.rs` artifact `rerun-if-changed`; `build.zig` `bundle_compiler_rt`) — `cargo build/test --features chapel` green standalone, 7/7 incl. `test_verify_proof_parallel_chapel_path`. | — | | L2.2 | Speculative tactic search — parallel beam + MCTS; consumes `TacticSuggestion` stream from GNN | 1 week | | L2.3 | Corpus-parallel ops — `forall` over 66,674-proof corpus; replay, premise scoring, tactic mining, inverted index | 1 week | | L2.4 | Mutation-testing parallelism — fan out 1000s of mutants; integrate with `verification/mutation.rs` | 3 days | @@ -176,4 +176,4 @@ Existing POC: `chapel_poc/parallel_proof_search.chpl` (420 LoC) + the self-linki **P2 L1:** Not started. Gated on L3 hand-off (Tier-1 green for ≥ 7 days + all waves landed/deferred). -**P3 L2:** POC present + self-link fix landed; actual `src/chapel/` modules not started. Gated on L1. +**P3 L2:** L2.1 done — POC promoted, wired into dispatch (`/api/verify_parallel`), `--features chapel` builds/tests green standalone (build reproducibility fixed 2026-05-18). L2.2–L2.7 not started, hard-gated on L1 Cap'n Proto (itself gated on L3 7-day-green hand-off). diff --git a/src/zig_ffi/build.zig b/src/zig_ffi/build.zig index 3b2309cf..287b0738 100644 --- a/src/zig_ffi/build.zig +++ b/src/zig_ffi/build.zig @@ -30,6 +30,12 @@ pub fn build(b: *std.Build) void { }), .linkage = .dynamic, }); + // Bundle Zig's compiler-rt into the artifact. Zig std (panic/stack-trace + // DWARF machinery) references compiler-rt routines such as + // `__zig_probe_stack`; without bundling, linking this library into a + // non-Zig binary (Rust `cargo build --features chapel`) fails with + // `undefined symbol: __zig_probe_stack`. + lib.bundle_compiler_rt = true; // Chapel C headers are in the same directory lib.root_module.addIncludePath(b.path(".")); if (stubs) { @@ -53,6 +59,10 @@ pub fn build(b: *std.Build) void { }), .linkage = .static, }); + // See note on lib.bundle_compiler_rt above — the static archive is the + // one Rust actually links (`rustc-link-lib=static=echidna_chapel_ffi`), + // so it must carry compiler-rt itself. + lib_static.bundle_compiler_rt = true; lib_static.root_module.addIncludePath(b.path(".")); if (stubs) { lib_static.addCSourceFile(.{ .file = b.path("chapel_stubs.c"), .flags = &.{"-fno-sanitize=undefined"} });