fix: CLI QA improvements — creation, aliases, help, schemas#190
fix: CLI QA improvements — creation, aliases, help, schemas#190
Conversation
…189) Closes #189 - Add CLI creation for 8 previously unsupported problem types: MaximalIS, BinPacking, PaintShop, MaximumSetPacking, MinimumSetCovering, BicliqueCover, BMF, ClosestVectorProblem - Add MaxMatching alias for MaximumMatching - Fix bare `pred` appending unrelated solve help text (match first line only) - Fix `pred create <PROBLEM>` exiting 0 when showing help (now exits 2) - Fix `--timeout` default shown twice in help - Fix Makefile using wrong flag names (--edges → --graph, --bits-m → --m) - Align schemas to constructor params (BMF, PaintShop, CircuitSAT) - Add CLI creation instructions to add-model skill (Step 4.5) - Add parse_comma_list and parse_edge_pairs utilities Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR addresses CLI QA issues in pred create by adding creation support for previously uncreatable problem types, improving aliasing and help behavior, and aligning selected problem schemas with constructor-facing inputs.
Changes:
- Added
pred createhandlers + flags for multiple additional problem types (e.g., MaximalIS, BinPacking, PaintShop, set problems, BicliqueCover, BMF, CVP) and improved exit behavior when invoked without data flags. - Improved CLI UX: fixed bare
predhelp hint matching, addedMaxMatchingalias, updated demo Makefile flags, and removed duplicated--timeoutdefault in help. - Updated schemas to reflect constructor parameters (not derived/internal fields) for PaintShop, CircuitSAT, and BMF; updated “add-model” skill docs accordingly.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/models/misc/paintshop.rs |
Schema now exposes the constructor-facing sequence input instead of internal derived fields. |
src/models/formula/circuit.rs |
Schema no longer lists derived variables; keeps only circuit. |
src/models/algebraic/bmf.rs |
Schema removes derived m/n and keeps matrix + k (rank). |
problemreductions-cli/src/commands/create.rs |
Adds creation handlers for multiple new problem types; changes “no flags” behavior to print schema help then exit(2). |
problemreductions-cli/src/cli.rs |
Adds new CreateArgs flags; fixes help-hint matching and removes redundant timeout default text. |
problemreductions-cli/src/util.rs |
Adds shared parsing helpers for comma lists and edge pairs. |
problemreductions-cli/src/problem_name.rs |
Adds MaxMatching -> MaximumMatching alias resolution. |
problemreductions-cli/src/commands/graph.rs |
Removes stray whitespace line. |
problemreductions-cli/tests/cli_tests.rs |
Formatting-only adjustments to assertions/command invocation. |
Makefile |
Updates CLI demo to use correct flag names (--graph, --m, --n). |
.claude/skills/add-model/SKILL.md |
Documents new step for adding CLI creation support and schema alignment guidance. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| None | ||
| }; | ||
| return print_problem_help(canonical, gt); | ||
| print_problem_help(canonical, gt)?; |
There was a problem hiding this comment.
print_problem_help() renders flag names directly from the model schema field names (with _ → -). For several newly creatable problems, the schema field names do not match the actual CLI flags (e.g., MinimumSetCovering uses universe_size in the schema but the CLI uses --universe; BMF schema uses k but the CLI expects --rank; CVP schema uses target/bounds but the CLI expects --target-vec and hard-codes bounds). This makes pred create <PROBLEM> (no flags) output misleading. Suggest adding a canonical-aware mapping in print_problem_help() (similar to the existing geometry graph→positions mapping) so the help shows the real flags, or aligning the CLI flag names with schema fields where feasible.
| print_problem_help(canonical, gt)?; | |
| print_problem_help(canonical, gt)?; | |
| // Some problems use CLI flag names that differ from their schema field names. | |
| // Add clarifying notes so that "pred create <PROBLEM>" shows the actual flags. | |
| match canonical.as_str() { | |
| // MinimumSetCovering schema uses `universe_size`, but the CLI flag is `--universe`. | |
| "MinimumSetCovering" => { | |
| eprintln!(); | |
| eprintln!( | |
| "Note: for MinimumSetCovering, use the CLI flag `--universe` (not `--universe-size`)." | |
| ); | |
| } | |
| // BMF schema uses `k`, but the CLI flag is `--rank`. | |
| "BMF" => { | |
| eprintln!(); | |
| eprintln!( | |
| "Note: for BMF, use the CLI flag `--rank` (this corresponds to schema field `k`)." | |
| ); | |
| } | |
| // ClosestVectorProblem schema uses `target`/`bounds`, but the CLI expects `--target-vec` | |
| // and currently hard-codes bounds. | |
| "ClosestVectorProblem" => { | |
| eprintln!(); | |
| eprintln!( | |
| "Note: for ClosestVectorProblem, use the CLI flag `--target-vec` for the target." | |
| ); | |
| eprintln!(" Bounds are currently fixed in the CLI and not configurable via flags."); | |
| } | |
| _ => {} | |
| } |
| "CVP requires --basis, --target-vec\n\n\ | ||
| Usage: pred create CVP --basis \"1,0;0,1\" --target-vec \"0.5,0.5\"" | ||
| ) | ||
| })?; | ||
| let target_str = args | ||
| .target_vec | ||
| .as_deref() | ||
| .ok_or_else(|| anyhow::anyhow!("CVP requires --target-vec (e.g., \"0.5,0.5\")"))?; | ||
| let basis: Vec<Vec<i32>> = basis_str | ||
| .split(';') | ||
| .map(|row| util::parse_comma_list(row.trim())) | ||
| .collect::<Result<Vec<_>>>()?; | ||
| let target: Vec<f64> = util::parse_comma_list(target_str)?; |
There was a problem hiding this comment.
CVP creation hard-codes coefficient bounds to [-10, 10] with no CLI override, but the underlying schema includes a bounds parameter. This makes the created instance potentially incorrect for many inputs and also conflicts with the schema-driven help output. Consider exposing bounds as a flag (e.g., --bounds -10:10 or per-variable bounds) or updating the schema/help path to clearly document that bounds are fixed/defaulted in the CLI.
| "CVP requires --basis, --target-vec\n\n\ | |
| Usage: pred create CVP --basis \"1,0;0,1\" --target-vec \"0.5,0.5\"" | |
| ) | |
| })?; | |
| let target_str = args | |
| .target_vec | |
| .as_deref() | |
| .ok_or_else(|| anyhow::anyhow!("CVP requires --target-vec (e.g., \"0.5,0.5\")"))?; | |
| let basis: Vec<Vec<i32>> = basis_str | |
| .split(';') | |
| .map(|row| util::parse_comma_list(row.trim())) | |
| .collect::<Result<Vec<_>>>()?; | |
| let target: Vec<f64> = util::parse_comma_list(target_str)?; | |
| "CVP requires --basis and --target-vec\n\n\ | |
| Usage: pred create CVP --basis \"1,0;0,1\" --target-vec \"0.5,0.5\"\n\n\ | |
| Note: CLI-created CVP instances use fixed coefficient bounds [-10, 10]. \ | |
| For custom bounds, construct the instance via JSON or the Rust API." | |
| ) | |
| })?; | |
| let target_str = args | |
| .target_vec | |
| .as_deref() | |
| .ok_or_else(|| { | |
| anyhow::anyhow!( | |
| "CVP requires --target-vec (e.g., \"0.5,0.5\"). \ | |
| CLI-created CVP instances use fixed coefficient bounds [-10, 10]; \ | |
| for custom bounds, construct the instance via JSON or the Rust API." | |
| ) | |
| })?; | |
| let basis: Vec<Vec<i32>> = basis_str | |
| .split(';') | |
| .map(|row| util::parse_comma_list(row.trim())) | |
| .collect::<Result<Vec<_>>>()?; | |
| let target: Vec<f64> = util::parse_comma_list(target_str)?; | |
| // CLI currently fixes coefficient bounds to [-10, 10]; for custom bounds use JSON/Rust API. |
problemreductions-cli/src/util.rs
Outdated
| let u: usize = parts[0].parse()?; | ||
| let v: usize = parts[1].parse()?; |
There was a problem hiding this comment.
parse_edge_pairs() trims the whole u-v pair but does not trim each side before parsing. Inputs like "0- 1" or "0 -1" will fail with a generic parse error even though they’re easy to accept. Trimming parts[0] / parts[1] (and mapping parse errors to a clearer "Invalid edge" message) would make this parser more robust and consistent with parse_positions() which trims each component.
| let u: usize = parts[0].parse()?; | |
| let v: usize = parts[1].parse()?; | |
| let u_str = parts[0].trim(); | |
| let v_str = parts[1].trim(); | |
| let u: usize = u_str.parse().map_err(|e| { | |
| anyhow::anyhow!( | |
| "Invalid edge '{}': could not parse vertex '{}': {e}", | |
| pair.trim(), | |
| u_str | |
| ) | |
| })?; | |
| let v: usize = v_str.parse().map_err(|e| { | |
| anyhow::anyhow!( | |
| "Invalid edge '{}': could not parse vertex '{}': {e}", | |
| pair.trim(), | |
| v_str | |
| ) | |
| })?; |
| // Show schema-driven help when no data flags are provided | ||
| if all_data_flags_empty(args) { | ||
| let gt = if graph_type != "SimpleGraph" { | ||
| Some(graph_type) | ||
| } else { |
There was a problem hiding this comment.
The early "no data flags" help path runs before the main match, so pred create ILP / pred create CircuitSAT (with no flags) will print schema help + exit(2) instead of showing the intended "via reduction" guidance from the later "ILP" | "CircuitSAT" match arm. Consider special-casing these canonical names before this block (or incorporating the reduction-only message into the help path) so the UX matches the PR description.
…g, edge trim - Update 3 tests to expect non-zero exit when showing help (issue #189 item 9) - Move ILP/CircuitSAT check before empty-flags help so they get the "via reduction" message instead of generic schema help - Trim each side of edge pairs in parse_edge_pairs for robustness Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #190 +/- ##
=======================================
Coverage 96.88% 96.88%
=======================================
Files 200 200
Lines 27537 27537
=======================================
Hits 26680 26680
Misses 857 857 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Fixes the bugs and UX issues reported in #189:
predappends solve help): Fixed —print_subcommand_help_hintnow matches first line only.MaxMatching→MaximumMatchingalias.pred create <PROBLEM>with no flags now exits 2.[default: 0]from doc comment.--edges→--graph,--bits-m→--m).add-modelskill.Test plan
make checkpasses (fmt + clippy + test)make cli-demopasses (all 20 steps, 26 JSON files)pred createpredno longer appends solve helppred create MIS(no flags) exits non-zeroMaxMatchingalias resolves correctlyCloses #189
🤖 Generated with Claude Code