Skip to content

feat(kpm): remove C++ FFI as default — pure Rust FreakMatcher complete (#142)#175

Merged
kalwalt merged 1 commit into
feat/freak-visual-databasefrom
feat/m9-3-pure-rust-default
Jun 5, 2026
Merged

feat(kpm): remove C++ FFI as default — pure Rust FreakMatcher complete (#142)#175
kalwalt merged 1 commit into
feat/freak-visual-databasefrom
feat/m9-3-pure-rust-default

Conversation

@kalwalt

@kalwalt kalwalt commented Jun 4, 2026

Copy link
Copy Markdown
Member

Closes #142 (M9-3). Last piece of the M9 milestone.

TL;DR

The structural M9-3 work (Cargo.toml default features, build.rs gating, conditional cpp_backend module) was done incrementally during M9-1 / M9-2. This PR makes the pure-Rust default explicit, CI-gated, and documented.

After merging, a plain cargo add webarkitlib-rs && cargo build works on machines without a C++ compiler. The ffi-backend feature stays available as an opt-in for validation + legacy .fset3 marker generation.

Diff scope

5 files changed, +146 / -9 lines. No source/test changes — all infrastructure + docs.

File What changed
crates/core/Cargo.toml Add explicit default = []; nft_marker_gen example now requires ffi-backend (it uses CppFreakMatcher directly)
.github/workflows/ci.yml New pure-rust-build job (ubuntu-only, no libclang-dev install) — proves cargo build / test succeed without a C++ toolchain
ARCHITECTURE.md Feature-flag table lists (default) as first row; kpm::rust_backend / kpm::cpp_backend documented with default/opt-in roles; "Building and Testing" restructured
README.md New "Pure Rust tracking" + "Building without C++" sections; ffi-backend clarified as opt-in for validation + legacy .fset3 generation
crates/core/benches/BENCHMARKS.md New "KPM / NFT performance (M9-3 status)" section explaining why existing marker_bench can't satisfy the within-20% target on its own, with functional-parity evidence + deferred-perf-bench note

Verification (run locally)

  • cargo fmt --all -- --check clean
  • cargo check -p webarkitlib-rs (no features) clean
  • cargo clippy -p webarkitlib-rs -- -D warnings exit 0
  • cargo build -p webarkitlib-rs (no features) clean
  • cargo test -p webarkitlib-rs (no features) → 431 passed, 7 ignored
  • cargo build -p webarkitlib-rs --features ffi-backend clean
  • cargo test -p webarkitlib-rs --features ffi-backend --lib kpm241 passed (FFI path unchanged)

Acceptance criterion from #142

Criterion Status
Pure-Rust build without C++ compiler ✅ verified locally; new pure-rust-build CI job enforces it going forward
FFI build still works ✅ verified locally; kpm-build matrix continues to exercise it
cargo publish --dry-run succeeds ⏳ deferred to CI; local Schannel cert-revocation issue prevents verification on my Windows host. CI will surface any packaging problems.
Performance within 20% of C++ on pinball-demo explicitly deferred per #142's escape hatch ("If slower, open a follow-up performance issue rather than blocking this PR"). The existing marker_bench measures barcode marker detection, not KPM/FreakMatcher — see BENCHMARKS.md for the functional-parity evidence + follow-up plan

Follow-ups (filed)

  • chore(deps): upgrade criterion 0.5.1 → 0.8.x #174 — upgrade criterion 0.5.1 → 0.8.x. Surfaced during this PR (criterion is significantly out of date; three major version bumps available). Intentionally separated per CLAUDE.md "fresh branch per issue/sub-issue" — the 0.5 → 0.8 span has likely API breaks that need their own focused review.

What this closes for M9 as a whole

With #142 (this PR) merged, the M9 milestone is complete:

Plus the cross-cutting work that came out of M9 testing:

🤖 Generated with Claude Code

#142)

Closes M9-3. The structural M9-3 work (Cargo.toml default feature set,
build.rs gating of C++ compilation, conditional cpp_backend module) was
done incrementally during M9-1 and M9-2; this commit makes the
pure-Rust default explicit, CI-gated, and documented.

## What this commit lands

1. **Explicit `default = []`** in `crates/core/Cargo.toml`. The
   default feature set was already implicitly empty (no `default`
   line existed), but stating it explicitly makes the M9-3 intent
   self-documenting alongside the `ffi-backend = []` line that
   already existed.

2. **`required-features = ["log-helpers", "ffi-backend"]`** on the
   `nft_marker_gen` example. It uses `CppFreakMatcher` directly to
   build `.fset3` files, so it must explicitly opt in to the C++
   backend now that the default doesn't pull it in. (Other
   `CppFreakMatcher` consumers — `simple_nft_dual` — were already
   opt-in via `dual-mode`.)

3. **New `pure-rust-build` CI job** in `.github/workflows/ci.yml`.
   Ubuntu-only (the invariant is build-system gating, not
   platform-specific compilation). Crucially does NOT install
   `libclang-dev` — if any unconditional bindgen/cc dependency
   ever leaks into the no-features build path, this job fails.
   Runs `cargo fmt --check`, `cargo check`, `cargo clippy -D warnings`,
   `cargo build`, and `cargo test` on `webarkitlib-rs` with **no**
   `--features` flag. Catches the strongest possible regression
   class for this milestone.

4. **ARCHITECTURE.md updates**: feature-flag table now lists `(default)`
   as the first row (pure Rust); `kpm::rust_backend` and `kpm::cpp_backend`
   are documented with their default/opt-in roles; the "Building and
   Testing" section restructures around "Pure Rust tracking (default —
   no C++ compiler needed)" and "Opt-in: C++ FFI backend" subsections.

5. **README.md updates**: new "Pure Rust tracking" and "Building
   without C++" sections explicitly state that `cargo add
   webarkitlib-rs` works on hosts without a C++ toolchain; the
   `ffi-backend` feature table entry now describes it as opt-in for
   validation + legacy `.fset3` generation.

6. **BENCHMARKS.md update**: new "KPM / NFT performance (M9-3 status)"
   section documents that the existing `marker_bench` measures
   `ar_detect_marker` (barcode/template marker detection), not the
   FreakMatcher path — so it can't satisfy the "within 20% of C++ on
   pinball-demo" perf target on its own. The functional parity
   evidence (test_dual_mode_no_divergence_on_pinball, #169
   absolute_corner_error, #173 cross_stack_parity, #155
   kpm_regression test_full_pipeline_pose) all pass within their
   tolerances; the within-20% wall-clock measurement is explicitly
   deferred to a follow-up Criterion bench (`kpm_bench.rs`),
   permitted by #142's escape hatch: "If slower, open a follow-up
   performance issue rather than blocking this PR."

## Verification

- `cargo fmt --all -- --check` clean
- `cargo check -p webarkitlib-rs` clean (no features, no C++)
- `cargo clippy -p webarkitlib-rs -- -D warnings` exit 0
- `cargo build -p webarkitlib-rs` clean (no features)
- `cargo test -p webarkitlib-rs` — 431 passed, 7 ignored (no features)
- `cargo build -p webarkitlib-rs --features ffi-backend` clean
- `cargo test -p webarkitlib-rs --features ffi-backend --lib kpm` —
  241 passed (FFI path unchanged)

## Follow-ups

- **#174**: upgrade criterion 0.5.1 → 0.8.x (surfaced during this PR;
  intentionally separated per CLAUDE.md "one issue per branch").
- KPM-specific Criterion benchmark to satisfy the within-20% target
  with real wall-clock numbers (referenced in BENCHMARKS.md).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@kalwalt kalwalt self-assigned this Jun 5, 2026
@kalwalt kalwalt moved this from Backlog to In review in Plan to port KPM to rust Jun 5, 2026
@kalwalt kalwalt merged commit 980eda2 into feat/freak-visual-database Jun 5, 2026
18 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in Plan to port KPM to rust Jun 5, 2026
kalwalt added a commit that referenced this pull request Jun 5, 2026
Closes #139 (M9 milestone umbrella).

Makes the pure-Rust FreakMatcher / VisualDatabase the default backend.
A plain `cargo build` now produces a working NFT tracker with no C++
toolchain (clang / libclang / cc) required — the C++ FFI is opt-in
behind `--features ffi-backend`, used only for cross-validation,
regression baselines, and the `nft_marker_gen` example.

Sub-milestones folded in (16 sub-PRs):
  M9-1 / #140 — VisualDatabase port .............. #145, #149, #151, #153
  M9-2 / #141 — RustFreakMatcher + DualFreakMatcher #156, #159
  M9-3 / #142 — pure-Rust as default ............. #175

Cross-cutting work that came out of M9:
  - Cross-platform / cross-stack matcher determinism:
      Rust HashMap → BTreeMap (#170#171)
      C++ unordered_map → std::map (WebARKitLib#39, absorbed via #172)
  - Hand-annotated absolute corner-error gate (#166 Track A):
      #163 dump_pyramid, #165 fixtures, #167 annotator tool,
      #168 annotations, #169 the gate itself.
      Finding: Rust 5.27 px vs C++ 18.79 px max corner error on
      pinball-demo — pure-Rust backend is more accurate.
  - Cross-stack parity vs jsartoolkitNFT-Node 1.10.0 (#173,
      jsartoolkitNFT#584 Track 2): sidecar bridge package +
      Linux CI gate (rot ≤ 0.08, trans ≤ 10 mm).
  - Restored kpm_regression Linux baseline (#155#158).

CI surface added:
  - pure-rust-build job (ubuntu, non-recursive checkout, no
    libclang-dev) — guards the M9-3 invariant that the default
    build path never leaks a C++ dependency.
  - ffi-backend integration tests + absolute_corner_error +
    cross_stack_parity on Linux in kpm-build.

Stats: 31 commits, 45 files, +9,051 / −133.

Deferred (not blocking M9): #142's "within 20% of C++ on
pinball-demo" wall-clock target — `marker_bench` measures barcode
detection, not KPM. A dedicated `kpm_bench.rs` is filed as a
follow-up. Other follow-ups: #161 (WASM browser examples),
#174 (criterion 0.5 → 0.8), #177 (raise M9 patch coverage 84.76%
→ ≥90%).

Closes: #139, #140, #141, #142, #155, #157, #160, #166, #170
@kalwalt kalwalt deleted the feat/m9-3-pure-rust-default branch June 6, 2026 12:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant