Build: The Unified panoptes Command
Maps to: Task 13 (new — extends the plan). Kind: Build.
Objective
Create a top-level panoptes binary crate whose CLI is a clap subcommand enum wrapping the three stages: generate, run, and code. Make main return a type that produces the right OS exit code, and write an integration test (with assert_cmd) that runs the whole pipeline — generate, then run against a mock, then validate — and asserts the exit codes.
The spec (givens)
- This task extends the plan (the Answer Key stops at Task 12), so there is no worked solution to compare against — by this point that is the point.
- The subcommand enum has exactly three variants —
Generate,Run,Code— each carrying the same args as the standalone binary it wraps (--family/--out;--scenarios/--log/--epochs;--coded). mainreturnsstd::process::ExitCode(oranyhow::Result) so invalid data exits non-zero — the property the integration test asserts.
Concepts exercised
clapderive with a#[command(subcommand)]enum.mainreturningResult/ExitCodefor honest exit status.- Integration tests in
tests/that invoke the built binary withassert_cmd. - Composability: proving a failed stage produces a non-zero exit.
File structure
crates/panoptes-cli/
├── Cargo.toml # depends on gen, harness, coding
└── src/
└── main.rs # the subcommand enum + dispatch
tests/
└── pipeline.rs # end-to-end integration test
The three existing binaries can stay (they are handy for focused runs), or become thin shims. The new panoptes command is the front door.
Manifest: add "crates/panoptes-cli" to the workspace members. Its [dependencies]: panoptes-gen, panoptes-harness, panoptes-coding (path deps), plus clap, tokio, anyhow ({ workspace = true }); [dev-dependencies]: assert_cmd and tempfile for the integration test.
The build loop (you drive)
- Write the failing integration test first, in
tests/pipeline.rs:panoptes generate --family ...exits 0 and produces a manifest.panoptes code --coded <a-known-bad-file>exits non-zero (the composability guarantee).- Optionally, the full happy-path chain runs green.
- Predict:
assert_cmdruns the compiled binary as a subprocess. Before running, what does the test assert about the bad case — a specific exit code, or merely "failure"? Decide what "failure" should mean forpanoptes code. - Run, check — it fails because the
panoptesbinary does not exist yet. - Implement the subcommand enum and dispatch, wiring each variant to the stage function you already built. Return
ExitCodeso an invalid-data error becomes a non-zero exit. - Run green, commit.
Generate, Run, Code. When you match on it, the compiler checks you handled every variant. Before you write the match: what happens if you later add a Report subcommand and forget to handle it? (This is exhaustiveness — the same safety net enums gave you for codebook values, now guarding your CLI dispatch.)
Done when
cargo test runs the integration test green, panoptes --help lists the three subcommands, and panoptes code --coded bad.csv exits non-zero — provably composable in a && chain or a CI step.
panoptes tool whose validation failures stop a pipeline. Every correctness property built across the course is now reachable from one front door.