feat(spec): say that one flag needs another, which nothing here could - #925
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Central YAML (base), Organization UI (inherited) Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThe PR adds the
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains; the previously reported default-ordering issue is addressed by requirement satisfaction logic that recognizes non-overridden declared defaults before those defaults are bound. Important Files Changed
Reviews (2): Last reviewed commit: "fix(spec): a defaulted flag is not a mis..." | Re-trigger Greptile |
The spec could say `conflicts`, `overrides`, `required_if` and `required_unless`, and had no way to say the positive form. `requires` is the last blocker in the derive's v1 list, and the only one of the four relationships mise's clap declarations cannot round-trip at all. Declared on the flag that imposes the rule, which is where clap puts it and where a reader looks for it. `required_if` states the same rule from the other end and both stay: `--out` needing `--format` is `requires="--format"` on `--out` or `required_if="--out"` on `--format`, and only the first keeps the rule beside the flag it is about. Wired the whole way through, since a constraint that only one parser enforces is worse than none: the KDL node in both spellings, usage-lib's check, the derive attribute with its selectors resolved at compile time, usage-argv's metadata, and the emitted KDL. An unmet requirement is reported as the *other* flag missing, which is what clap says and what a user can act on — the fix is to type `--key`, not to delete `--sign`. That also means no new `Error` variant, so the hot path's `Result` does not grow for a check that only fires on the cold one. A value from the environment or a default satisfies a requirement, matching what `conflicts` already does: the question is whether the other flag ended up with a value, not how it got one. The bridge does not carry it, and cannot. clap 4.6 has `Arg::requires` and its variants as setters with no getter and keeps the field `pub(crate)`, so a `Command` cannot be asked what it requires. `requires_cannot_come_across_from_clap` asserts that rather than leaving the empty vector looking like a bug, and will fail if a future clap exposes it. `gen-shadow` counts it against the clap dialect for the same reason: clap can be *written* with `requires`, and a spec regenerated from that command comes back without it, so emitting it there would make the clap side look more faithful than it is. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…its fields Two from review. A requirement whose target had a default was reported as unmet, which contradicted this PR's own documentation and, worse, contradicted the file it lives in: plain `required`, `required_if` and `required_unless` all read a default as filling a flag, so the same flag was missing in one check and present ten lines below. The rule, stated once so the next relationship inherits it: a *negative* rule — `conflicts` — counts only what was given, because a flag with a default would otherwise conflict with everything and nothing would parse. A *positive* rule asks whether the flag it names has a value, and a default is a value. usage-lib gets `selector_is_satisfied` beside `selector_is_explicit`; the derive skips emitting the check altogether when the target has a default, since it could never fail. And the conformance fixture declared `--key` and `--identity` without reading them, which `clippy --all-targets` fails on. They are asserted now, which is what they were for. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Pushed fixes for both findings. Defaults failing requirement checks (@greptile-apps P1) — correct, and worse than a doc mismatch: The rule, written down so the next relationship inherits it rather than picking again:
usage-lib gets The lint failure — the conformance fixture declared This comment was generated by Claude Code. |
|
Both fixes land correctly.
The derive side is the better call too: skipping the check entirely at compile time when the target has a default is cleaner than emitting The clap Everything looks good — no further concerns. |
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. ## What went away - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. ## What the conversion needed - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. ## What the emitted spec gains and loses Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. ## What went away - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. ## What the conversion needed - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. ## What the emitted spec gains and loses Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. ## What went away - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. ## What the conversion needed - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. ## What the emitted spec gains and loses Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ccepts Follow-up to the conversion, now stacked on the two gaps it found rather than describing them as open. `unknown_flags` reaches the whole tree. The root declares `error` once and every subcommand inherits it, so `usage lint --nope f.kdl` names the flag again instead of making `--nope` the file and calling the real file unexpected. The five commands that hand a command line to somebody else's script declare `value` for themselves, which is the half that needs a subcommand to be able to say something. ## From review `--version` says `usage 5.1.0`, not `usage-cli 5.1.0`. The crate is `usage-cli` and the binary is `usage`; everything else this CLI says about itself now comes from the spec, where the name is `usage`, so the version line was contradicting the help banner printed directly above it. Read from the spec by `version()`, which `-v` shares, so the two cannot drift. `--out-dir` without `--multi` is refused. clap said this as a `requires` in both directions; the spec can only state the direction that makes `--multi` need a destination, so without a check the other way `usage g markdown --out-dir docs` quietly wrote a single file somewhere else. Enforced in `run()` until #925's `requires` can carry it. `--completions` is a flag, which is how it is typed. The clap declaration made it a *positional*, so the spec, the docs, the manpage and the generated completions all described a `[COMPLETIONS]` argument that nothing accepts, while the flag that does work went undocumented. The conversion carried that over faithfully, wrong included. The point of emitting the spec from the declaration is that the two cannot disagree, so the declaration is what changes. Declined one: CodeRabbit read the `man` alias on `generate manpage` as removed. It is declared, in the emitted spec, and on the rendered page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. ## What went away - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. ## What the conversion needed - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. ## What the emitted spec gains and loses Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ccepts Follow-up to the conversion, now stacked on the two gaps it found rather than describing them as open. `unknown_flags` reaches the whole tree. The root declares `error` once and every subcommand inherits it, so `usage lint --nope f.kdl` names the flag again instead of making `--nope` the file and calling the real file unexpected. The five commands that hand a command line to somebody else's script declare `value` for themselves, which is the half that needs a subcommand to be able to say something. ## From review `--version` says `usage 5.1.0`, not `usage-cli 5.1.0`. The crate is `usage-cli` and the binary is `usage`; everything else this CLI says about itself now comes from the spec, where the name is `usage`, so the version line was contradicting the help banner printed directly above it. Read from the spec by `version()`, which `-v` shares, so the two cannot drift. `--out-dir` without `--multi` is refused. clap said this as a `requires` in both directions; the spec can only state the direction that makes `--multi` need a destination, so without a check the other way `usage g markdown --out-dir docs` quietly wrote a single file somewhere else. Enforced in `run()` until #925's `requires` can carry it. `--completions` is a flag, which is how it is typed. The clap declaration made it a *positional*, so the spec, the docs, the manpage and the generated completions all described a `[COMPLETIONS]` argument that nothing accepts, while the flag that does work went undocumented. The conversion carried that over faithfully, wrong included. The point of emitting the spec from the declaration is that the two cannot disagree, so the declaration is what changes. Declined one: CodeRabbit read the `man` alias on `generate manpage` as removed. It is declared, in the emitted spec, and on the rendered page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. ## What went away - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. ## What the conversion needed - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. ## What the emitted spec gains and loses Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ccepts Follow-up to the conversion, now stacked on the two gaps it found rather than describing them as open. `unknown_flags` reaches the whole tree. The root declares `error` once and every subcommand inherits it, so `usage lint --nope f.kdl` names the flag again instead of making `--nope` the file and calling the real file unexpected. The five commands that hand a command line to somebody else's script declare `value` for themselves, which is the half that needs a subcommand to be able to say something. ## From review `--version` says `usage 5.1.0`, not `usage-cli 5.1.0`. The crate is `usage-cli` and the binary is `usage`; everything else this CLI says about itself now comes from the spec, where the name is `usage`, so the version line was contradicting the help banner printed directly above it. Read from the spec by `version()`, which `-v` shares, so the two cannot drift. `--out-dir` without `--multi` is refused. clap said this as a `requires` in both directions; the spec can only state the direction that makes `--multi` need a destination, so without a check the other way `usage g markdown --out-dir docs` quietly wrote a single file somewhere else. Enforced in `run()` until #925's `requires` can carry it. `--completions` is a flag, which is how it is typed. The clap declaration made it a *positional*, so the spec, the docs, the manpage and the generated completions all described a `[COMPLETIONS]` argument that nothing accepts, while the flag that does work went undocumented. The conversion carried that over faithfully, wrong included. The point of emitting the spec from the declaration is that the two cannot disagree, so the declaration is what changes. Declined one: CodeRabbit read the `man` alias on `generate manpage` as removed. It is declared, in the emitted spec, and on the rendered page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. ## What went away - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. ## What the conversion needed - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. ## What the emitted spec gains and loses Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ccepts Follow-up to the conversion, now stacked on the two gaps it found rather than describing them as open. `unknown_flags` reaches the whole tree. The root declares `error` once and every subcommand inherits it, so `usage lint --nope f.kdl` names the flag again instead of making `--nope` the file and calling the real file unexpected. The five commands that hand a command line to somebody else's script declare `value` for themselves, which is the half that needs a subcommand to be able to say something. ## From review `--version` says `usage 5.1.0`, not `usage-cli 5.1.0`. The crate is `usage-cli` and the binary is `usage`; everything else this CLI says about itself now comes from the spec, where the name is `usage`, so the version line was contradicting the help banner printed directly above it. Read from the spec by `version()`, which `-v` shares, so the two cannot drift. `--out-dir` without `--multi` is refused. clap said this as a `requires` in both directions; the spec can only state the direction that makes `--multi` need a destination, so without a check the other way `usage g markdown --out-dir docs` quietly wrote a single file somewhere else. Enforced in `run()` until #925's `requires` can carry it. `--completions` is a flag, which is how it is typed. The clap declaration made it a *positional*, so the spec, the docs, the manpage and the generated completions all described a `[COMPLETIONS]` argument that nothing accepts, while the flag that does work went undocumented. The conversion carried that over faithfully, wrong included. The point of emitting the spec from the declaration is that the two cannot disagree, so the declaration is what changes. Declined one: CodeRabbit read the `man` alias on `generate manpage` as removed. It is declared, in the emitted spec, and on the rendered page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. ## What went away - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. ## What the conversion needed - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. ## What the emitted spec gains and loses Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ccepts Follow-up to the conversion, now stacked on the two gaps it found rather than describing them as open. `unknown_flags` reaches the whole tree. The root declares `error` once and every subcommand inherits it, so `usage lint --nope f.kdl` names the flag again instead of making `--nope` the file and calling the real file unexpected. The five commands that hand a command line to somebody else's script declare `value` for themselves, which is the half that needs a subcommand to be able to say something. ## From review `--version` says `usage 5.1.0`, not `usage-cli 5.1.0`. The crate is `usage-cli` and the binary is `usage`; everything else this CLI says about itself now comes from the spec, where the name is `usage`, so the version line was contradicting the help banner printed directly above it. Read from the spec by `version()`, which `-v` shares, so the two cannot drift. `--out-dir` without `--multi` is refused. clap said this as a `requires` in both directions; the spec can only state the direction that makes `--multi` need a destination, so without a check the other way `usage g markdown --out-dir docs` quietly wrote a single file somewhere else. Enforced in `run()` until #925's `requires` can carry it. `--completions` is a flag, which is how it is typed. The clap declaration made it a *positional*, so the spec, the docs, the manpage and the generated completions all described a `[COMPLETIONS]` argument that nothing accepts, while the flag that does work went undocumented. The conversion carried that over faithfully, wrong included. The point of emitting the spec from the declaration is that the two cannot disagree, so the declaration is what changes. Declined one: CodeRabbit read the `man` alias on `generate manpage` as removed. It is declared, in the emitted spec, and on the rendered page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. ## What went away - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. ## What the conversion needed - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. ## What the emitted spec gains and loses Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ccepts Follow-up to the conversion, now stacked on the two gaps it found rather than describing them as open. `unknown_flags` reaches the whole tree. The root declares `error` once and every subcommand inherits it, so `usage lint --nope f.kdl` names the flag again instead of making `--nope` the file and calling the real file unexpected. The five commands that hand a command line to somebody else's script declare `value` for themselves, which is the half that needs a subcommand to be able to say something. ## From review `--version` says `usage 5.1.0`, not `usage-cli 5.1.0`. The crate is `usage-cli` and the binary is `usage`; everything else this CLI says about itself now comes from the spec, where the name is `usage`, so the version line was contradicting the help banner printed directly above it. Read from the spec by `version()`, which `-v` shares, so the two cannot drift. `--out-dir` without `--multi` is refused. clap said this as a `requires` in both directions; the spec can only state the direction that makes `--multi` need a destination, so without a check the other way `usage g markdown --out-dir docs` quietly wrote a single file somewhere else. Enforced in `run()` until #925's `requires` can carry it. `--completions` is a flag, which is how it is typed. The clap declaration made it a *positional*, so the spec, the docs, the manpage and the generated completions all described a `[COMPLETIONS]` argument that nothing accepts, while the flag that does work went undocumented. The conversion carried that over faithfully, wrong included. The point of emitting the spec from the declaration is that the two cannot disagree, so the declaration is what changes. Declined one: CodeRabbit read the `man` alias on `generate manpage` as removed. It is declared, in the emitted spec, and on the rendered page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. ## What went away - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. ## What the conversion needed - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. ## What the emitted spec gains and loses Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ccepts Follow-up to the conversion, now stacked on the two gaps it found rather than describing them as open. `unknown_flags` reaches the whole tree. The root declares `error` once and every subcommand inherits it, so `usage lint --nope f.kdl` names the flag again instead of making `--nope` the file and calling the real file unexpected. The five commands that hand a command line to somebody else's script declare `value` for themselves, which is the half that needs a subcommand to be able to say something. ## From review `--version` says `usage 5.1.0`, not `usage-cli 5.1.0`. The crate is `usage-cli` and the binary is `usage`; everything else this CLI says about itself now comes from the spec, where the name is `usage`, so the version line was contradicting the help banner printed directly above it. Read from the spec by `version()`, which `-v` shares, so the two cannot drift. `--out-dir` without `--multi` is refused. clap said this as a `requires` in both directions; the spec can only state the direction that makes `--multi` need a destination, so without a check the other way `usage g markdown --out-dir docs` quietly wrote a single file somewhere else. Enforced in `run()` until #925's `requires` can carry it. `--completions` is a flag, which is how it is typed. The clap declaration made it a *positional*, so the spec, the docs, the manpage and the generated completions all described a `[COMPLETIONS]` argument that nothing accepts, while the flag that does work went undocumented. The conversion carried that over faithfully, wrong included. The point of emitting the spec from the declaration is that the two cannot disagree, so the declaration is what changes. Declined one: CodeRabbit read the `man` alias on `generate manpage` as removed. It is declared, in the emitted spec, and on the rendered page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. ## What went away - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. ## What the conversion needed - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. ## What the emitted spec gains and loses Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ccepts Follow-up to the conversion, now stacked on the two gaps it found rather than describing them as open. `unknown_flags` reaches the whole tree. The root declares `error` once and every subcommand inherits it, so `usage lint --nope f.kdl` names the flag again instead of making `--nope` the file and calling the real file unexpected. The five commands that hand a command line to somebody else's script declare `value` for themselves, which is the half that needs a subcommand to be able to say something. ## From review `--version` says `usage 5.1.0`, not `usage-cli 5.1.0`. The crate is `usage-cli` and the binary is `usage`; everything else this CLI says about itself now comes from the spec, where the name is `usage`, so the version line was contradicting the help banner printed directly above it. Read from the spec by `version()`, which `-v` shares, so the two cannot drift. `--out-dir` without `--multi` is refused. clap said this as a `requires` in both directions; the spec can only state the direction that makes `--multi` need a destination, so without a check the other way `usage g markdown --out-dir docs` quietly wrote a single file somewhere else. Enforced in `run()` until #925's `requires` can carry it. `--completions` is a flag, which is how it is typed. The clap declaration made it a *positional*, so the spec, the docs, the manpage and the generated completions all described a `[COMPLETIONS]` argument that nothing accepts, while the flag that does work went undocumented. The conversion carried that over faithfully, wrong included. The point of emitting the spec from the declaration is that the two cannot disagree, so the declaration is what changes. Declined one: CodeRabbit read the `man` alias on `generate manpage` as removed. It is declared, in the emitted spec, and on the rendered page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ccepts Follow-up to the conversion, now stacked on the two gaps it found rather than describing them as open. `unknown_flags` reaches the whole tree. The root declares `error` once and every subcommand inherits it, so `usage lint --nope f.kdl` names the flag again instead of making `--nope` the file and calling the real file unexpected. The five commands that hand a command line to somebody else's script declare `value` for themselves, which is the half that needs a subcommand to be able to say something. ## From review `--version` says `usage 5.1.0`, not `usage-cli 5.1.0`. The crate is `usage-cli` and the binary is `usage`; everything else this CLI says about itself now comes from the spec, where the name is `usage`, so the version line was contradicting the help banner printed directly above it. Read from the spec by `version()`, which `-v` shares, so the two cannot drift. `--out-dir` without `--multi` is refused. clap said this as a `requires` in both directions; the spec can only state the direction that makes `--multi` need a destination, so without a check the other way `usage g markdown --out-dir docs` quietly wrote a single file somewhere else. Enforced in `run()` until #925's `requires` can carry it. `--completions` is a flag, which is how it is typed. The clap declaration made it a *positional*, so the spec, the docs, the manpage and the generated completions all described a `[COMPLETIONS]` argument that nothing accepts, while the flag that does work went undocumented. The conversion carried that over faithfully, wrong included. The point of emitting the spec from the declaration is that the two cannot disagree, so the declaration is what changes. Declined one: CodeRabbit read the `man` alias on `generate manpage` as removed. It is declared, in the emitted spec, and on the rendered page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ccepts Follow-up to the conversion, now stacked on the two gaps it found rather than describing them as open. `unknown_flags` reaches the whole tree. The root declares `error` once and every subcommand inherits it, so `usage lint --nope f.kdl` names the flag again instead of making `--nope` the file and calling the real file unexpected. The five commands that hand a command line to somebody else's script declare `value` for themselves, which is the half that needs a subcommand to be able to say something. ## From review `--version` says `usage 5.1.0`, not `usage-cli 5.1.0`. The crate is `usage-cli` and the binary is `usage`; everything else this CLI says about itself now comes from the spec, where the name is `usage`, so the version line was contradicting the help banner printed directly above it. Read from the spec by `version()`, which `-v` shares, so the two cannot drift. `--out-dir` without `--multi` is refused. clap said this as a `requires` in both directions; the spec can only state the direction that makes `--multi` need a destination, so without a check the other way `usage g markdown --out-dir docs` quietly wrote a single file somewhere else. Enforced in `run()` until #925's `requires` can carry it. `--completions` is a flag, which is how it is typed. The clap declaration made it a *positional*, so the spec, the docs, the manpage and the generated completions all described a `[COMPLETIONS]` argument that nothing accepts, while the flag that does work went undocumented. The conversion carried that over faithfully, wrong included. The point of emitting the spec from the declaration is that the two cannot disagree, so the declaration is what changes. Declined one: CodeRabbit read the `man` alias on `generate manpage` as removed. It is declared, in the emitted spec, and on the rendered page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ccepts Follow-up to the conversion, now stacked on the two gaps it found rather than describing them as open. `unknown_flags` reaches the whole tree. The root declares `error` once and every subcommand inherits it, so `usage lint --nope f.kdl` names the flag again instead of making `--nope` the file and calling the real file unexpected. The five commands that hand a command line to somebody else's script declare `value` for themselves, which is the half that needs a subcommand to be able to say something. ## From review `--version` says `usage 5.1.0`, not `usage-cli 5.1.0`. The crate is `usage-cli` and the binary is `usage`; everything else this CLI says about itself now comes from the spec, where the name is `usage`, so the version line was contradicting the help banner printed directly above it. Read from the spec by `version()`, which `-v` shares, so the two cannot drift. `--out-dir` without `--multi` is refused. clap said this as a `requires` in both directions; the spec can only state the direction that makes `--multi` need a destination, so without a check the other way `usage g markdown --out-dir docs` quietly wrote a single file somewhere else. Enforced in `run()` until #925's `requires` can carry it. `--completions` is a flag, which is how it is typed. The clap declaration made it a *positional*, so the spec, the docs, the manpage and the generated completions all described a `[COMPLETIONS]` argument that nothing accepts, while the flag that does work went undocumented. The conversion carried that over faithfully, wrong included. The point of emitting the spec from the declaration is that the two cannot disagree, so the declaration is what changes. Declined one: CodeRabbit read the `man` alias on `generate manpage` as removed. It is declared, in the emitted spec, and on the rendered page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`usage` is now its own first adopter. The ten command structs, the root and the two command enums are declared with `usage-derive` instead of clap, and `--usage-spec` prints `Cli::to_kdl()` — the same tables that parsed the command line, rather than a transcription of a clap `Command` through `clap_usage`. Smaller than mise and far less forgiving of a lossy spec, because this CLI's spec is what generates its own docs, manpage and completions: anything the derive cannot say shows up in the checked-in output. - `clap`, `clap_usage` and the `clap-sort` dev-dependency, plus `tests/clap_sort.rs` — declaration order is held by the spec since #915. - `command_effects.rs`'s two tables, 60 lines that existed because "clap has no way to express this". Each command declares `#[usage(effect = "…")]` where it is defined; the file keeps `UNCLASSIFIED` and the coverage tests, which now read the derived metadata. A stale entry is no longer possible for the effects themselves — an effect moves with the command it is written on. - The four shell commands shared one `Shell` struct, which the derive refuses: a command collects into the struct that declares it. They are four structs flattening a shared group now, written by a macro so the paragraph of long help is not copied four times. Their docs improve as a side effect — all four used to say "Execute a shell script with the specified shell". - `sponsors` is a bare variant (#923), so its empty struct is gone. - `requires` has no positive form in the spec, so the two constraints that used it are stated as `required_if` on the other flag. `--out-dir requires --multi` is a positive requirement on a `bool` and has no spelling at all; #925 adds `requires`, and it belongs here when it lands. Gains `JDX_USAGE_BIN` on `--usage-bin` (the bridge dropped `env`), long help that keeps its line breaks, an `about` for `generate manpage`, and `name "usage"` rather than `name "usage-cli"`. Loses `subcommand_required`, which the spec can hold and the derive knows from a bare `T` subcommand field but does not emit, and strictness on subcommands: `unknown_flags` is accepted on an `Args` and ignored, and the root's is not inherited, so only the root is strict. Both are derive gaps worth their own fix rather than a workaround here. Workspace suite green, clippy clean, docs and assets re-rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ccepts Follow-up to the conversion, now stacked on the two gaps it found rather than describing them as open. `unknown_flags` reaches the whole tree. The root declares `error` once and every subcommand inherits it, so `usage lint --nope f.kdl` names the flag again instead of making `--nope` the file and calling the real file unexpected. The five commands that hand a command line to somebody else's script declare `value` for themselves, which is the half that needs a subcommand to be able to say something. ## From review `--version` says `usage 5.1.0`, not `usage-cli 5.1.0`. The crate is `usage-cli` and the binary is `usage`; everything else this CLI says about itself now comes from the spec, where the name is `usage`, so the version line was contradicting the help banner printed directly above it. Read from the spec by `version()`, which `-v` shares, so the two cannot drift. `--out-dir` without `--multi` is refused. clap said this as a `requires` in both directions; the spec can only state the direction that makes `--multi` need a destination, so without a check the other way `usage g markdown --out-dir docs` quietly wrote a single file somewhere else. Enforced in `run()` until #925's `requires` can carry it. `--completions` is a flag, which is how it is typed. The clap declaration made it a *positional*, so the spec, the docs, the manpage and the generated completions all described a `[COMPLETIONS]` argument that nothing accepts, while the flag that does work went undocumented. The conversion carried that over faithfully, wrong included. The point of emitting the spec from the declaration is that the two cannot disagree, so the declaration is what changes. Declined one: CodeRabbit read the `man` alias on `generate manpage` as removed. It is declared, in the emitted spec, and on the rendered page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Stacked on #919 — review that first; this PR's diff is the second commit.
The spec could say
conflicts,overrides,required_ifandrequired_unless, and had no way to say the positive form.requiresis the last blocker in PLAN.md's derive-v1 list.Why not just
required_ifIt states the same rule from the other end, and both stay.
--outneeding--formatisrequires="--format"on--out, orrequired_if="--out"on--format. Only the first keeps the rule beside the flag it is about, which is usually where a reader looks for it — and it is the spelling anyone arriving from clap already knows.Wired the whole way through
A constraint only one parser enforces is worse than none, so: the KDL node in both spellings (property for one selector, child node for several), usage-lib's check, the derive attribute with its selectors resolved at compile time, usage-argv's cold metadata, and the emitted KDL that docs, manpages and completions read.
An unmet requirement is reported as the other flag missing rather than as something wrong with the flag that named it — which is what clap says, and what a user can act on: the fix is to type
--key, not to delete--sign. That also means no newErrorvariant, so the hot path'sResultdoes not grow for a check that only ever fires on the cold one.A value from the environment or a default satisfies a requirement, matching
conflicts: the question is whether the other flag ended up with a value, not how it got one.The bridge does not carry it
clap_usagereads aclap::Commandback through public getters, and clap 4.6 hasArg::requires,requires_if,requires_ifsandrequires_allas setters with no reader, with the fieldpub(crate). So there is nothing to read, whatever theArgwas built with.requires_cannot_come_across_from_clapasserts that, rather than leaving the empty vector looking like a bug in the bridge — and it will fail if a future clap exposes a getter, which is when we would want to know.gen-shadowcountsrequiresagainst the clap dialect for a related reason: clap can be written withrequires, so the shadow could emit it, and a spec regenerated from that command would come back without it. Counting it keeps the clap side from looking more faithful than it is.docs/spec/integrations/clap.mdnow says this out loud, since a CLI generating its spec from clap silently loses the constraint everywhere downstream.Tests
requires_round_trips_in_both_spellings— property and child-node forms, throughto_string()and backrequires_cannot_come_across_from_clap— the bridge limit, asserteda_requirement_names_the_flag_that_is_missing/a_requirement_is_satisfied_by_a_short_form— usage-lib, including a selector spelled-kresolving to--keya_requirement_names_the_flag_that_was_not_given— the derive, plus the absent-flag case that makes this different from plain required-nessflag_relationships_reach_the_spec— the emitted KDL takes the child-node spelling for two selectors, and usage-lib parses it backcargo test --all --all-featuresandcargo clippy --all --all-features -- -D warningsare clean.🤖 Generated with Claude Code
Note
Medium Risk
Touches post-parse validation in usage-lib and derive-generated checks; behavior is well-tested but wrong satisfaction rules (defaults/env/overrides) would change CLI acceptance for derived binaries.
Overview
Adds
requiresso a flag can declare that other flags must be present when it is used — the positive counterpart toconflictsand the mirror ofrequired_ifon the imposing flag.Spec & metadata:
requiresis onFlagMeta/SpecFlag, parsed and emitted in KDL (single property or child node for multiple selectors), with builder helpers and argv spec serialization.Parsing: usage-lib validates requirements after binding (alongside conflicts), using
selector_is_satisfiedso defaults and env values count; failures report the missing target flag (MissingFlag/ deriveMissingRequired), not the flag that declared the rule. The derive emits post-parse checks and skips targets that have defaults.Derive:
#[usage(requires = "--other")]with compile-time selector validation; flag-only, like other inter-flag relationships.Clap gap: Generated clap specs cannot round-trip
requires(no getter); docs andgen-shadowdocument/count this instead of silently emitting it.Reviewed by Cursor Bugbot for commit 89866b8. Bugbot is set up for automated code reviews on this repo. Configure here.