feat(bench): clap CLI + JSON results-file writer (PR-J1) - #53
Conversation
Wires the bench binary to drive `run()` and lands the §3.6 JSON results-file writer. `main.rs` is no longer the red-gate scaffold — `cargo run -p ourios-bench --` / `just thesis-bench` now parse the §3.7 flag surface, run the enabled gates, write the results JSON, print a summary, and exit non-zero on a C1 correctness failure. Lands: - `Cargo.toml` — adds `clap` (derive). The CNCF-Rust- observability standard (Vector / Quickwit / OpenObserve / GreptimeDB all use it; the Rust analogue to Go's cobra); `ourios-server` will reuse it. - `src/main.rs` — clap `Cli` for the §3.7 flags (`--corpus`, `--results-dir`, `--bucket-dir`, `--keep-parquet`, `--hardware-kind` / `--allow-unknown-hardware`, `--update-benchmarks-md`, `--gates a1,c1,c2`). `--hardware-kind` is `required_unless_present` `--allow-unknown-hardware`; `--keep-parquet` `requires` `--bucket-dir`; `--gates` collapses to a `GateSet` (empty ⇒ all). Drives `run`, writes the JSON, prints a per-gate summary, exits non-zero only on a C1 reconstruction mismatch (§3.4.2) — A1/C2 gate outcomes are reported, not exit-gating. - `src/report.rs` — `write_results_json` serialises a `ResultsFile` to `<results-dir>/<timestamp>-<sha>.json` (colon-free name for cross-platform validity; bounded collision-retry suffix per §3.6). Re-exported from the crate root. Verified end-to-end on the seed corpus (`--gates a1,c1 --hardware-kind dev-laptop`): writes a valid results JSON, C1 = 1.000000 PASS, audit stream produces 5 KB (so the A1 audit-writer path is exercised), exit 0. A1 reports FAIL on the seed corpus as expected — 77 lines → ~1 MB Parquet (footer / dictionary overhead dwarfs the data), which is exactly why real §9 numbers need a millions-of-lines corpus and why A1-fail doesn't gate the exit. Un-`#[ignore]`'d / added tests: - RFC0006.5 (`main.rs`): `--hardware-kind` required unless `--allow-unknown-hardware`; parse-time rejection. - RFC0006.6 (`main.rs`): `--gates` scopes the measurement; default is all. - `--keep-parquet` requires `--bucket-dir` (parse-time). - RFC0006.4 JSON half (`report.rs`): results round-trip through disk with every §3.6 key; colon-free filename; collision suffix. Not in this PR: - The `--update-benchmarks-md` §9 markdown appender — parsed but warns "not implemented"; the JSON lands regardless. The §9 in-place rewrite (RFC0006.4 second sub-test, RFC0006.6 §9-untouched assertion) lands in PR-J2. - C2 — still `NotImplemented`; a default `--gates` (all) run errors on C2 until it lands. RFC0006.3 stays ignored. Verification (CLAUDE.md §6.6): - cargo fmt --all --check — clean. - cargo clippy --all-targets --all-features -- -D warnings — clean. - cargo test --all-features — 258 passed / 22-ish ignored (was 252; +3 CLI tests, +3 results-writer tests). Maturity gate: RFC 0006 stays `red` until C2 + the §9 appender land (RFC0006.3 / RFC0006.4-§9 / RFC0006.7 still ignored). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a clap-based CLI for ourios-bench, maps CLI args into BenchConfig (including gate selection), runs benchmarks via run(), writes ResultsFile as pretty JSON with collision-safe filenames and retries, updates RFC 0006 filename contract, and re-exports write_results_json. ChangesCLI and Results Reporting Implementation
Sequence DiagramsequenceDiagram
participant CLI
participant Clap as ClapParse
participant IntoCfg as Cli::into_config
participant BenchConfig
participant Runner as ourios_bench::run
participant ResultsFile
participant Writer as write_results_json
participant Printer as print_summary
participant Exit as ExitCode
CLI->>Clap: parse args (clap derive)
Clap->>IntoCfg: validate & convert
IntoCfg->>BenchConfig: produce BenchConfig
BenchConfig->>Runner: execute selected gates
Runner->>ResultsFile: return ResultsFile
ResultsFile->>Writer: serialize & attempt atomic write (create_new)
Writer-->>CLI: return PathBuf
ResultsFile->>Printer: produce human summary
Printer-->>CLI: print summary and warnings
CLI->>Exit: exit (1 on C1 failure, 2 on run error, 0 otherwise)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/ourios-bench/src/report.rs`:
- Around line 39-51: The current check-then-write in write_results_json is
TOCTOU-unsafe and can clobber an existing file; instead, attempt to atomically
create the file with
std::fs::OpenOptions::new().write(true).create_new(true).open(&path) inside the
same counter loop (retrying on Err(e) if e.kind() ==
io::ErrorKind::AlreadyExists by incrementing counter and recomputing path),
write the serialized serde_json::to_string_pretty(results) into the opened file,
map any non-AlreadyExists IO error to BenchError::Report (include path.display()
and the error), and if the loop exhausts all candidates return a
BenchError::Report indicating exhaustion; reference symbols: write_results_json,
results_dir, stem, counter, BenchError::Report, serde_json::to_string_pretty,
and std::fs::OpenOptions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 5de0c191-d195-4932-be70-0e62f1951e60
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (4)
crates/ourios-bench/Cargo.tomlcrates/ourios-bench/src/lib.rscrates/ourios-bench/src/main.rscrates/ourios-bench/src/report.rs
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Wires the bench binary to drive
run()and lands the §3.6 JSON results-file writer.main.rsis no longer the red-gate scaffold —cargo run -p ourios-bench --/just thesis-benchnow parse the §3.7 flag surface, run the enabled gates, write the results JSON, print a summary, and exit non-zero on a C1 correctness failure.Lands
Cargo.toml— addsclap(derive). The CNCF-Rust-observability standard (Vector / Quickwit / OpenObserve / GreptimeDB all use it; the Rust analogue to Go's cobra).ourios-serverwill reuse it.src/main.rs— clapClifor the §3.7 flags.--hardware-kindisrequired_unless_present--allow-unknown-hardware;--keep-parquetrequires--bucket-dir;--gatescollapses to aGateSet(empty ⇒ all). Drivesrun, writes the JSON, prints a per-gate summary, exits non-zero only on a C1 reconstruction mismatch (§3.4.2) — A1/C2 outcomes are reported, not exit-gating.src/report.rs—write_results_jsonserialises aResultsFileto<results-dir>/<timestamp>-<sha>.json(colon-free name for cross-platform validity; bounded collision-retry suffix per §3.6). Re-exported from the crate root.Verified end-to-end
cargo run -p ourios-bench -- --gates a1,c1 --hardware-kind dev-laptopon the seed corpus: writes a valid results JSON, C1 = 1.000000 PASS, audit stream produces ~5 KB (A1 audit-writer path exercised), exit 0. A1 reports FAIL on the seed corpus as expected — 77 lines → ~1 MB Parquet (footer/dictionary overhead dwarfs the data), which is exactly why real §9 numbers need a millions-of-lines corpus and why A1-fail doesn't gate the exit.Tests
main.rs):--hardware-kindrequired unless--allow-unknown-hardware; parse-time rejection.main.rs):--gatesscopes the measurement; default all.--keep-parquetrequires--bucket-dir(parse-time).report.rs): results round-trip through disk with every §3.6 key; colon-free filename; collision suffix.Not in this PR
--update-benchmarks-md§9 markdown appender — parsed but warns "not implemented"; the JSON lands regardless. The §9 in-place rewrite (RFC0006.4 second sub-test, RFC0006.6 §9-untouched assertion) lands in PR-J2.NotImplemented; a default--gates(all) run errors on C2 until it lands. RFC0006.3 stays ignored.Test plan
cargo fmt --all --check— clean.cargo clippy --all-targets --all-features -- -D warnings— clean.cargo test --all-features— 258 passed (+3 CLI, +3 results-writer).Maturity stage
RFC 0006 stays
reduntil C2 + the §9 appender land.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes / Reliability
Tests
Documentation