From 9e49b6a4123c41ec0dbd4813d08166eaf5eb57ac Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Sun, 23 Aug 2026 07:28:52 +0800 Subject: [PATCH] test(cli): walk the nested verbs when checking the reference for flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `the_reference_documents_every_flag_of_the_verbs_it_covers` read one level: `cli.get_subcommands()`, then that verb's own arguments. Two things followed. It never descended, so every flag a level down was unchecked — `tab new --cwd`, `pane ls --all`, `pane split --ratio`, `pane close --orphans`, `server restart --hard`. And its gate for "is this verb documented" looked only for ``` `tty7 ```, which the page uses for leaf verbs; a group is headed ``` ## `pane` — panes ```. So `ws`, `tab`, `pane`, `machine` and `server` were skipped whole, taking their children with them. Fifteen flags were checked where there are twenty-two. Both fixed: the walk recurses, and the gate accepts either heading shape. The reference turns out to be complete — nothing was actually undocumented, which is worth knowing rather than assuming. The matching rule was too strict as well, and the extension is what showed it: requiring a backtick immediately before the dashes reported `server restart --hard` missing when it has its own table row, written as ``` `server restart --hard` ```. It now looks for the flag anywhere on the page. The floor is five named nested flags rather than a count, because a count drifts with the surface and what has to hold is that the walk went down. Verified both ways: dropping `--orphans` from the page is reported, and stopping the recursion is reported by name. --- crates/tty7-cli/src/cli.rs | 82 ++++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 13 deletions(-) diff --git a/crates/tty7-cli/src/cli.rs b/crates/tty7-cli/src/cli.rs index 0ef07caf..50c73ef7 100644 --- a/crates/tty7-cli/src/cli.rs +++ b/crates/tty7-cli/src/cli.rs @@ -688,29 +688,85 @@ mod tests { // Global flags have their own table, and `--help` is clap's. const EVERYWHERE: [&str; 4] = ["json", "quiet", "machine", "help"]; + // Recursive, because most of the flags are a level down: `ws rename`, + // `pane split`, `tab close`, `machine ls`, `server restart`. Walking + // only the top level pinned `run` and `wait` and left the rest of the + // surface free to drift — and the reference is what an agent reads + // before it ever runs `--help`. + fn walk( + cmd: &clap::Command, + path: &str, + doc: &str, + everywhere: &[&str], + missing: &mut Vec, + checked: &mut Vec, + ) { + for arg in cmd.get_arguments() { + let Some(long) = arg.get_long() else { continue }; + if everywhere.contains(&long) { + continue; + } + checked.push(format!("{path} --{long}")); + // The flag anywhere on the page, not only at the start of a + // code span. The page writes some of them inside a whole + // command — ``| `server restart --hard` | …`` — and requiring + // a backtick immediately before the dashes called that one + // undocumented when it has its own table row. + if !doc.contains(&format!("--{long}")) { + missing.push(format!("{path} --{long}")); + } + } + for sub in cmd.get_subcommands() { + if sub.get_name() == "help" { + continue; + } + walk( + sub, + &format!("{path} {}", sub.get_name()), + doc, + everywhere, + missing, + checked, + ); + } + } + let cli = Cli::command(); let mut missing: Vec = Vec::new(); - let (mut covered, mut checked) = (0usize, 0usize); + let mut covered = 0usize; + let mut checked: Vec = Vec::new(); for verb in cli.get_subcommands() { let name = verb.get_name(); - if !DOC.contains(&format!("`tty7 {name}")) { + // Two heading shapes, because the page uses both: a leaf verb gets + // ``### `tty7 capture …` `` and a group gets ``## `pane` — panes``. + // Matching only the first skipped `ws`, `tab`, `pane`, `machine` + // and `server` — every group, and with them every nested verb. + let documented = + DOC.contains(&format!("`tty7 {name}")) || DOC.contains(&format!("\n## `{name}`")); + if !documented { continue; } covered += 1; - for arg in verb.get_arguments() { - let Some(long) = arg.get_long() else { continue }; - if EVERYWHERE.contains(&long) { - continue; - } - checked += 1; - if !DOC.contains(&format!("`--{long}")) { - missing.push(format!("{name} --{long}")); - } - } + walk(verb, name, DOC, &EVERYWHERE, &mut missing, &mut checked); } // Or the loop could pass by matching nothing at all. assert!(covered >= 10, "only {covered} documented verbs were found"); - assert!(checked >= 5, "only {checked} verb flags were checked"); + // Named rather than counted: a count drifts with the surface, and what + // has to hold is that the walk went a level *down*. These five live + // under `tab`, `pane` and `server`, and a one-level walk reaches none + // of them — which is exactly the state this test was in. + for nested in [ + "tab new --cwd", + "pane ls --all", + "pane split --ratio", + "pane close --orphans", + "server restart --hard", + ] { + assert!( + checked.iter().any(|c| c == nested), + "`{nested}` was never reached, so the walk is not descending: {checked:?}" + ); + } assert!( missing.is_empty(), "the command reference does not mention these flags: {missing:?}"