Skip to content

fix(spec): let a flag inside a clause set its setting - #1611

Merged
jdx merged 1 commit into
claude/github-issue-1608-d0989cfrom
claude/clause-settings
Nov 3, 2026
Merged

jdx merged 1 commit into
claude/github-issue-1608-d0989cfrom
claude/clause-settings

Conversation

@jdx

@jdx jdx commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

A flag with setting = "key" inside a #[usage(clause)] element now sets its setting, the same as one in a flattened group. Before, the root never collected clause elements. Their bindings were missing from SETTINGS_BINDINGS, SETTING_DECLS and the settings registry. The value the user typed never reached the settings layer. A root whose only bound flags were in a clause could not use #[usage(settings)] at all: the derive said there was "no elsewhere".

#[derive(Args)]
struct Tool {
    #[usage(long, setting = "postinstall")]
    postinstall: Option<String>,
    #[usage(long, setting = "exclude")]
    exclude: Vec<String>,
    tool: String,
}

#[derive(Cli)]
#[usage(bin = "ex", settings)]
struct Ex {
    #[usage(clause)]
    tools: Vec<Tool>,
}

ex --postinstall first --exclude a node --exclude b python --postinstall last ruby now resolves postinstall = "last" and exclude = ["a", "b"]. Several clause items that give one setting contribute what a single command repeating the flag would: every entry of a list setting, in order, and the last value of any other. If a list item is not valid text, the whole list is dropped, as it already is within one item. The fold lives in a new usage_argv::spec::fold_settings_given.

Stacked on #1610.

Validation: a new conformance test, conformance/tests/derive_settings_clause.rs, covers bindings, registry types, drift, one item, several items and an item with no flags. A unit test covers the fold, and cargo test --all --all-features passes. Clippy is clean for the changed code. The one remaining -D warnings failure, in derive_settings_declared.rs, was already on the base branch.

AI-assisted — Tool: Claude Code; model: anthropic/claude-opus-5-5; version: 2.1.316.

🤖 Generated with Claude Code


Note

Medium Risk
Changes derive-generated settings aggregation for a new field kind, which affects CLI config resolution wherever clauses bind settings; logic is tested but adoption paths are easy to miss.

Overview
Flags with setting = "…" on fields inside a #[usage(clause)] item are now wired into the root’s settings tables and resolved layer, matching flattened groups. The derive treats each clause field as a settings child: bindings and declarations come from the item Args type, and values are built by folding every parsed item (plus the in-progress item) through new fold_settings_given.

Multi-item clauses behave like repeating the same flags on one line: list settings accumulate entries in order; scalar settings keep the last value; mixing NotText with a list collapses the whole list to NotText. Roots that only bind settings via clause items can use #[usage(settings)] without the previous “no elsewhere” error.

Coverage adds conformance/tests/derive_settings_clause.rs for bindings, registry drift, and resolution, plus unit tests for the fold helper.

Reviewed by Cursor Bugbot for commit 2b494b4. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Caution

Review failed

The pull request is closed.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

Share

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

@greptile-apps

greptile-apps Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge.

Summary

This PR lets flags inside clauses contribute settings to the root command.

  • Flags inside clause items now feed the root CLI's settings.

No actionable issues were found.

Reviews (2) · Last reviewed commit: "fix(spec): collect settings bound by a f..." · Reviewed by Greptile

A #[usage(clause)] element whose flag has setting = "key" never reached
the root's SETTINGS_BINDINGS, SETTING_DECLS or settings layer, and a root
whose only bound flags were in a clause could not say #[usage(settings)].
Clauses are now collected like flattened groups. Several items giving
one setting contribute every item of a list setting, and the last value
of any other.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
AI-Assisted: Tool: Claude Code; model: unavailable; version: 2.1.309
Entire-Checkpoint: 01M6FP1HM2SBTGXXQ25T45PPCN
@jdx
jdx force-pushed the claude/clause-settings branch from d136126 to 2b494b4 Compare November 3, 2026 03:19
@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Instruction counts

benchmark trend instructions Δ wall (min) Δ
markdown ▃▃▁▂▂▄▂▂▂▁█▇▆▄▅▇ 266,930,202 → 266,996,926 +0.02% 46.93 → 47.32ms +0.83%
startup ▇▇▇▇▆▇▆▇▇▆▇▇▇▇▁█ 1,010,474 → 1,017,341 +0.68% 1.42 → 1.41ms -0.81%

No instruction-count regression above 1%.

Only instruction counts gate. Wall clock is shown for context — on identical hardware it moves 4-20% run to run.

Measured by tak — instruction-counted CLI benchmarks, stored in this repository's git notes.

Shadow comparison

Parsing mise use -g node@20 against a shadow of mise's committed spec.
Reported, not gated: the shadow grows as the derive learns to express more, so
what to watch is the ratio rather than either column.

framework stripped binary, bytes
usage 1250024
bpaf 2494640
clap 3100904
framework instructions, cold parse vs usage
usage 8295 —
clap 6313736 761x
bpaf 21909300 2641x
                                              min       p01       p10    median
usage-rs: argv -> struct                      749       750       754       776  ns
clap: build tree + parse -> struct        1240587   1244342   1253826   1270013  ns
bpaf: build parser + parse -> struct      3436630   3436630   3484832   3509174  ns

usage: argv -> struct                             762 ns      0.76 µs
clap: build tree + parse -> struct            1261273 ns   1261.27 µs
clap: parse -> struct, tree reused              49949 ns     49.95 µs
clap: build tree only                          749337 ns    749.34 µs

2b494b46dfa0 vs c9e2b646a282 · measured on the runner, not pushed to the history.

@jdx
jdx added this pull request to stack #1614 November 3, 2026 12:13
@jdx
jdx merged commit 12d11fe into main Nov 3, 2026
14 of 15 checks passed
@jdx
jdx deleted the claude/clause-settings branch November 3, 2026 12:14
mise-en-dev added a commit that referenced this pull request Nov 3, 2026
### 🚀 Features

- **(go)** refuse undeclared environment variables in generated parsers
by [@jdx](https://github.com/jdx) in
[#1612](#1612)
- **(spec)** let a flag with setting declare its setting by
[@jdx](https://github.com/jdx) in
[#1610](#1610)
- **(spec)** refuse unknown environment variables under an application
prefix by [@jdx](https://github.com/jdx) in
[#1609](#1609)

### 🐛 Bug Fixes

- **(complete)** offer --help and --version when completing flags by
[@jdx](https://github.com/jdx) in
[#1605](#1605)
- **(spec)** let a flag inside a clause set its setting by
[@jdx](https://github.com/jdx) in
[#1611](#1611)

### 📚 Documentation

- **(contributing)** remove the AI reply restriction by
[@jdx](https://github.com/jdx) in
[#1602](#1602)

### 🔍 Other Changes

- set up jouet for agents by [@jdx](https://github.com/jdx) in
[#1603](#1603)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant