docs(cli): server restart keeps sessions, and --hard is the one that does not

`Restart` became `Restart { hard: bool }` and the reference page did not
follow. It still read

    | `server restart` | Stop, then start — same consequence |

which had been true before the flag split the two apart. So the page told
a reader that restarting the server kills every pane on the machine — it
does not — and said nothing whatever about the option that does.

Both halves measured against a running server with a `sleep 600` in a
pane, not taken from the help text:

    server restart          "restarted in place; sessions kept running"
                            shell 74647 still alive, pane still LIVE
    server restart --hard   "stopped and started; sessions ended"
                            shell 74647 gone, pane LIVE=no

Wrong in the cautious direction, which is the quiet kind: someone who
wants their server on a new build reads that line, believes it will cost
them every shell, and does not run it — while the destructive spelling
they were never told about sits one flag away.

The guard walks clap's own command tree and holds every long flag to
being named somewhere on the page. Names only: whether the prose around a
flag is right is not something a test can hold, but a flag missing from
the page entirely is, and that is the state that shipped. Global flags
are exempt — they repeat on all forty-odd verbs and the page documents
them once, in a table of their own.

Checked against the page as it was: the guard reports `restart: --hard`.
This commit is contained in:
l0ng-ai
2026-08-23 00:58:36 +08:00
parent b6b3e782b4
commit 020769b3bb
2 changed files with 53 additions and 1 deletions
+51
View File
@@ -1072,6 +1072,57 @@ mod tests {
///
/// Every flag carried help and every positional did not — 22 of them, the
/// main argument of each verb, printed as a bare `[WORKSPACE]` with an
/// Every flag this CLI accepts is named on the page that documents it.
///
/// A flag nobody wrote down is a feature only its author knows about, and
/// the failure is worse when the flag is the destructive one:
/// `server restart --hard` shipped undocumented while the reference page
/// still described plain `restart` as "Stop, then start — same
/// consequence", which had been true before the flag split the two apart.
/// So the page told a reader that restarting kills every pane (it does
/// not), and said nothing at all about the option that does.
///
/// Names only. Whether the prose around a flag is *right* is not
/// something a test can hold — but a flag missing from the page entirely
/// is, and that is the state this catches.
///
/// The global flags are exempt: they repeat on all forty-odd verbs, and
/// the page documents them once in its own table rather than per verb.
#[test]
fn every_flag_is_named_on_the_reference_page() {
use clap::CommandFactory as _;
const PAGE: &str = include_str!("../../../docs/cli/reference.mdx");
const GLOBAL: &[&str] = &["json", "quiet", "help", "version", "machine", "config-dir"];
fn walk(cmd: &clap::Command, page: &str, missing: &mut Vec<String>, seen: &mut usize) {
for a in cmd.get_arguments() {
let Some(long) = a.get_long() else { continue };
if GLOBAL.contains(&long) {
continue;
}
*seen += 1;
if !page.contains(&format!("--{long}")) {
missing.push(format!("{}: --{long}", cmd.get_name()));
}
}
for sub in cmd.get_subcommands() {
walk(sub, page, missing, seen);
}
}
let (mut missing, mut seen) = (Vec::new(), 0usize);
walk(&Cli::command(), PAGE, &mut missing, &mut seen);
assert!(
seen > 15,
"only {seen} flags were inspected, so the walk has stopped finding them"
);
assert!(
missing.is_empty(),
"these flags exist but the reference page never names them: {missing:?}"
);
}
/// empty column beside it. The gap was invisible to anyone reading the
/// source, where a `value_name` looks like documentation.
#[test]
+2 -1
View File
@@ -450,7 +450,8 @@ list a retry needs.
| `server logs` | Tail the server log; prints the path, and says so when logging was never enabled (`TTY7_LOG=info` before the server starts) |
| `server start` | Bring up a server on this machine |
| `server stop` | Stop it — **every pane on the machine dies** |
| `server restart` | Stop, then start — same consequence |
| `server restart` | Hand the panes to a new server of this build; **sessions keep running** — the shells, and what they are running, carry across. A pane using tty7's own SSH client is the exception: that connection drops and has to be reopened |
| `server restart --hard` | Stop, then start — **every pane on the machine dies**, exactly as `stop` |
<Warning>
Do not run `start`, `stop`, or `restart` on someone else's behalf. They change