# Benchmark Next Increments Audit > Date: 2026-06-03 > Scope: what it takes to add hybrid goldens, Rust/Swift goldens, > performance/RSS budget gates, and portable binary fixtures to Fold's maturity > benchmark harness. ## Implementation status This audit has been implemented in the current working tree: - portable binary fixtures and `build_source` binary specs; - merge-only hybrid golden runner; - Rust/Swift frontend golden runner with structured skips; - wall/CPU/RSS measurement and optional loose budget gates; - umbrella summary wiring for all implemented suites. ## Current baseline Implemented benchmark pieces: - `scripts/benchmarks/compare_findings.py` - validates report shape; - checks physical locations; - checks backend provenance; - supports `must_report`, `must_not_report`, `min_total`, `max_total`, and `max_by_rule`. - `scripts/benchmarks/run_binary_goldens.py` - runs `fold scan --mode binary --binary ...`; - supports optional host-specific smokes via `skip_if_missing`; - supports generated fixtures via `build_source`. - `scripts/benchmarks/run_source_goldens.py` - generates temporary `compile_commands.json`; - runs `fold scan --mode source`. - `scripts/benchmarks/run_hybrid_goldens.py` - generates source compile DBs, resolves/builds binary fixtures, and runs merge-only hybrid scans. - `scripts/benchmarks/run_rust_swift_goldens.py` - runs Rust/Swift frontend scans with structured missing-tool skips. - `scripts/benchmarks/runner_common.py` - records wall/CPU/RSS metrics and enforces optional budget gates. - `scripts/benchmarks/summarize_maturity.py` - one-command JSON umbrella over all implemented suites. - Existing shipped specs include binary, source, hybrid, Rust, and Swift goldens. The comparator is intentionally dependency-free and has a SARIF/JSON report view only; runners handle scan invocation. ## 1. Hybrid golden runner ### What it needs A new runner should mirror `run_source_goldens.py` plus `run_binary_goldens.py`: - spec directory: `tests/benchmarks/hybrid/`; - runner: `scripts/benchmarks/run_hybrid_goldens.py`; - build or resolve a source compile DB; - resolve a binary path; - invoke: ```sh fold scan --mode hybrid \ --compile-db \ --binary \ --source-detectors <...> \ --binary-detectors <...> \ --hybrid-strategy merge-only \ --format json --output ``` Initial target should be merge-only. Hint-exchange strategies remain future work. ### Fixture strategy Use a tiny source fixture and matching tiny compiled binary fixture. The first hybrid golden should not require exact source/binary correlation yet; it should prove that both backends can contribute findings and provenance survives merge. Candidate first fixture: - source side: `tests/fixtures/security/div_const_zero.cpp` / `div_guarded.cpp`; - binary side: existing `tests/fixtures/binary/bof_*` or a new compiled small binary with a hardcoded string / simple null-deref heuristic; - expected: - at least one `backend=source` finding; - at least one `backend=binary` or `backend=binary-*` finding; - guarded source lookalike must not report; - no locationless findings. ### Comparator gap `compare_findings.py` can already match backend and rule IDs, but it cannot yet assert aggregate backend presence such as `require_backends: ["source", "binary"]`. Options: 1. encode with `must_report` entries that match known source and binary rules; 2. extend comparator with `expect.require_backends`. Recommendation: add `require_backends` because hybrid provenance is the point of this suite. ### Risks - Exact binary findings may vary by architecture/compiler. - Existing `bof_arm64`/`bof_x64` are committed binaries, but a generated fixture would be more portable if built during the runner. - Hybrid returns 1 if either backend emits actionable findings; runner already accepts 0/1 patterns from source/binary runners. ### Acceptance criteria - `scripts/benchmarks/run_hybrid_goldens.py --build build/release` runs at least one spec. - `summarize_maturity.py --all` includes `hybrid_goldens`. - First spec proves source + binary backend provenance in one report. - Spec fails closed on missing required inputs unless explicitly marked skippable. ## 2. Rust/Swift golden runner ### What it needs A new language-frontend runner should cover `fold scan --mode rust` and `fold scan --mode swift` without assuming both toolchains exist everywhere. Proposed runner: ```text scripts/benchmarks/run_frontend_goldens.py ``` or split runners: ```text scripts/benchmarks/run_rust_swift_goldens.py ``` Spec directories: ```text tests/benchmarks/rust/ tests/benchmarks/swift/ ``` Spec fields: - `mode`: `rust` or `swift`; - `paths`: source file or crate/package directory; - `detectors`; - `env`: optional environment overrides such as `FOLD_RUST_BIN`; - `skip_if_missing_tools`: true by default for Rust/Swift until CI images are pinned. ### Existing fixture surface Rust: - `tests/fixtures/rust/security_crate/` exists; - integration tests already locate `fold-rust` via `FOLD_RUST_BIN` or `tools/fold-rust/target/release/fold-rust`; - detectors include `rust-unsafe-api`, `rust-unchecked-index`, `rust-path-traversal`, `rust-command-injection`, and `rust-crypto-misuse`. Swift: - `tests/fixtures/swift/Package.swift` and `Sources/fuzz_me.swift` exist; - `fold-swift` is optional through Meson `-Dswift-frontend=true/false`; - Swift mode is already routed in `scan_router` and forces serial execution. ### Comparator gaps `compare_findings.py` is enough for initial Rust/Swift findings if specs use `ruleId`, `backend`, and message regexes. Possible extension later: - `require_confidence`; - `require_correlationKind`; - per-frontend degradation counters if profile/report properties expose them. ### Risks - Rust frontend depends on nightly/toolchain and `fold-rust` build output. - Swift frontend depends on `swiftc` and platform availability. - These suites should skip when tools are missing, but a skipped suite should be visible in the maturity summary. ### Acceptance criteria - Runner handles missing frontend binaries/toolchains as structured skips, not false passes or hard crashes. - At least one Rust spec checks a must-report unsafe API and a safe/missing rule shape. - At least one Swift spec checks a stable finding if current Swift detectors emit one; otherwise the first Swift spec should be a report-shape/no-crash golden with explicit `max_total` and provenance/location requirements for any emitted findings. - `summarize_maturity.py --all` includes Rust/Swift suite status. ## 3. Performance/RSS budget gates ### What it needs Current runners record wall-clock seconds only. A maturity budget gate needs structured resource measurement: - wall time; - CPU time when available; - max RSS; - optional Fold `--profile` JSON fields. On macOS, `/usr/bin/time -l` gives maximum resident set size. On Linux, `/usr/bin/time -v` gives maximum resident set size. Python `resource.getrusage` can capture child maxrss but units differ by platform and it may aggregate over children. Recommendation: implement a small cross-platform Python measurement wrapper using `resource.getrusage(RUSAGE_CHILDREN)` plus optional platform-specific `/usr/bin/time` fallback only if needed. ### Spec model Add optional budget fields under `expect`: ```json "budgets": { "max_wall_seconds": 10.0, "max_cpu_seconds": 20.0, "max_rss_mb": 512, "profile_max_total_wall_ms": 10000 } ``` Budget gates should start loose and informational for local work. CI can tighten specific small fixtures once stable. ### Integration options 1. Embed measurement in each runner. 2. Create shared helper module used by all benchmark runners. Recommendation: shared helper to avoid drift: ```text scripts/benchmarks/runner_common.py ``` Potential contents: - `run_fold_measured(cmd, cwd)`; - `load_json`, `resolve_path`, `find_fold_binary`; - resource result schema. ### Risks - RSS is noisy across Apple Silicon/Linux and linked-r2 vs CLI-r2 modes. - Cold caches make first run slower. - Profile mode forces serial execution for source/Rust/Swift paths, so profile timing should not be compared directly against non-profile timing unless the spec opts in. ### Acceptance criteria - Benchmark summaries include `wall_seconds`, `cpu_seconds`, and `rss_mb` when available. - Specs can set loose budgets and fail closed when exceeded. - Initial budgets are applied only to small, deterministic source/binary fixtures; host `/usr/bin/curl` smoke remains informational or skip-budgeted. - Docs explain platform noise and how to update budgets. ## 4. More portable binary fixtures ### What it needs The current real-binary curl smoke is useful but host-specific. Portable binary fixtures should be compiled from checked-in C/C++ source during setup or runner execution, or committed in controlled small forms for multiple architectures. Recommended layout: ```text tests/benchmarks/binary/fixtures/ guarded_division.c fortified_wrappers.c scanner_vs_writer.c hardcoded_secret.c build_binary_fixtures.py ``` Generated outputs should live under the benchmark output directory, not be checked in unless there is a strong cross-toolchain reason. ### First fixture set 1. `guarded_division.c` - contains actual machine division but guarded denominator; - expected: no `fold.div-by-zero`. 2. `scanner_vs_writer.c` - contains read-only scanners: `memchr`, `strstr`, `strchr`; - contains controlled writer: `memcpy` or `strncpy` in safe shape; - expected: no P-Code OOB false positives from scanner/import-stub adjacency. 3. `fortified_wrappers.c` - compiled with `_FORTIFY_SOURCE=2` where supported; - includes `__*_chk`-lowered patterns; - expected: fortified wrappers are not normalized to unchecked sinks. 4. `hardcoded_secret.c` - stable positive control for binary string/credential finding; - expected: at least one `fold.hardcoded-credential` backend binary finding. ### Runner support Extend `run_binary_goldens.py` or add helper support for specs with `build_source`: ```json { "name": "binary_guarded_division", "build_source": "fixtures/guarded_division.c", "compiler": "cc", "cflags": ["-O1"], "detectors": "security", "expect": { ... } } ``` If compiler is missing, fail closed for portable fixtures; unlike curl, these are core benchmark assets. ### Risks - `_FORTIFY_SOURCE` behavior varies by libc/platform; on macOS it may not lower exactly like glibc. - Division instruction selection varies under optimization. - r2/lifter behavior can vary by architecture. Mitigations: - Use separate specs for portable generic fixtures and platform-specific fortified behavior. - Include relaxed exact-count expectations; prefer `must_not_report` for known FP signatures and stable positive controls for one finding. - Use `--binary-max-functions` small caps only when function ordering is stable; otherwise scan all tiny fixture functions. ### Acceptance criteria - At least two generated binary fixtures are built and scanned in the binary golden suite. - One fixture is a stable positive control. - One fixture locks a P-Code false-positive shape independent of `/usr/bin/curl`. - Curl smoke remains optional and complementary. ## Recommended sequencing 1. Portable binary fixtures first: they also feed hybrid and perf suites. 2. Hybrid runner using one portable binary fixture plus existing source fixtures. 3. Performance/RSS budget infrastructure around existing source/binary runners. 4. Rust/Swift runner after deciding skip policy and stable Swift expectations. This sequencing gives hybrid/perf deterministic inputs before adding toolchain- optional frontend complexity.