The current bench harness has inconsistent prompts across arms, broken Docker builds for multiple benchmark categories, model name mapping failures, and requires manual babysitting. Results are not scientifically comparable.
Every arm (native, kernel, kernel-cpu) receives exactly the same prompt. No arm gets extra system prompt, silent context injection, or additional instructions.
SYSTEM: "This is a needle-bench benchmark. There is a bug hidden in this codebase. Find it and fix it. Run test.sh to verify your fix."
USER: "find the needle. run test.sh to verify your fix."
- Native arm: CLI receives this prompt via its
-p/--promptflag - Kernel arm:
run_bench_agent_loopreceives this assystem_prompt+ user message - Kernel-cpu arm: Same as kernel, different driver
- No
silent_contextinjection on any arm - The only difference between arms is the execution harness, not the prompt
Every benchmark Dockerfile must build successfully on the needle-bench-native base image.
Docker rewrite rules (docker_build_with_native_base):
- Only replace the LAST
FROMline (runtime stage) - Builder stages keep their original toolchain images
- Alpine→Debian package mapping for runtime stage only
ENV JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF-8"injected after runtime FROM/var/cache/apk/*lines neutralized- No
apktranslation in builder stages
Base image (docker/Dockerfile.bench-native):
- Must include: Go, Python, Node, Java (JDK 17), Rust (via rustup), build-essential
- Must include: all vendor CLIs (claude, gemini, codex, vibe, kimi, opencode, aider)
- Single image, all runtimes, no conditional installs
Model name mapping must be correct for:
- Native CLIs: claude, gemini, codex, vibe (Mistral), kimi, opencode (fallback)
- OpenRouter: provider/model format (e.g.
anthropic/claude-haiku-4-5) - OpenCode: provider/model format (e.g.
openai/gpt-4.1)
Known broken mappings to fix:
codestral-2508via vibe: TOML config has trailing whitespace mangling model namedeepseek-r1→ OpenCode:deepseek/deepseek-reasonernot recognizeddeepseek-r1-0528→ OpenCode:deepseek/deepseek-r1-0528not recognized- Models without OpenCode support should be kernel-only (no native arm)
local_linux_binary()must find~/projects/haystack/target/x86_64-unknown-linux-musl/release/ostkmake installbuilds both macOS + musl binaries- Kernel and kernel-cpu arms always use
--localwhen available, fall back to download
Every score file must include:
resolved: boolturns_to_fix: u32input_tokens: u64output_tokens: u64estimated_cost_usd: f64 (computed from rate card if not reported by CLI)tool_uses: u32wall_clock: f64 (seconds)summary: String (model's description of what it did)stop_reason: Stringarm: Stringbenchmark: Stringmodel: String (normalized)timestamp: ISO 8601
After every run (pass or fail):
docker logs <container>captured toruns/<model>-<arm>/<bench>.log- Container kept if
--keepflag set, otherwise cleaned up - Score file written regardless of pass/fail
ARM_PATTERNmatchesnative,kernel,kernel-cpu(already fixed)- Rate card covers all models
--dry-runshows what would be generated- Output:
public/scores.json+public/experiment-scores.json
Running ostk bench --all --model <model> --arm both --local --docker must:
- Build all 40 benchmark images (skip cached)
- Run each benchmark on each arm
- Skip benchmarks that already have score files
- Capture container logs
- Write score files with full metrics
- Print summary at end
- Exit 0 if all benchmarks ran (even if models failed to solve)
- No manual intervention required
- Unify prompt: single
BENCH_SYSTEM_PROMPTandBENCH_USER_PROMPTconstants used by ALL arms - Remove
silent_contextinjection from kernel arm - Fix vibe TOML heredoc (no leading whitespace)
- Fix
local_linux_binary()path resolution - Add container log capture (
docker logs→.logfile) - Verify all 40 Dockerfiles build on native base
- Verify model name mappings for all 35 models
- Add
--dry-runtoostk benchthat lists what would run without running - Run full matrix: 40 benchmarks × 35 models × 3 arms = 4,200 runs
- Regenerate leaderboard with
consolidate_scores.py