Skip to content

fix(generator): keep clap option groups and option-attached operands out of required positionals - #4722

Open
thomhurst wants to merge 1 commit into
mainfrom
issue-4692-cargo-regen
Open

fix(generator): keep clap option groups and option-attached operands out of required positionals#4722
thomhurst wants to merge 1 commit into
mainfrom
issue-4692-cargo-regen

Conversation

@thomhurst

Copy link
Copy Markdown
Owner

Summary

The scheduled cargo regeneration (#4680, run 34006412119) failed because CargoOptionsTests no longer compiled against the regenerated CargoAddOptions. Regenerating locally from cargo 1.98.0 (Docker rust:1-slim, the same command tree as the baseline) showed the test break was a symptom: the generator had lost every option under cargo add's Source: and Section: headings (--path, --git, --branch, --rev, --registry, --dev, --build, --target) and turned Dep into a required constructor parameter. Both regressions came from #4470 (2026-09-02), one day after the last successful cargo regeneration (#4487).

Changes

  • CargoCliScraper: the heading gate accepted only headings containing "option" or ending in "selection". clap groups options under arbitrary headings, so every heading is now an option section except the positional, command and prose ones (Arguments, Commands, Examples, Usage, Environment, Notes, See also). The existing Examples: fixture still stays out.
  • UsageSynopsisParser.RelaxArgumentsMissingFromAlternatives: an operand attached to an option (--path <PATH>) counted as a positional slot at the same index, so with [OPTIONS] in front of each form (same phase) <DEP> was never relaxed even though --path/--git are its alternatives. The old fixture only passed because its forms had different phases. Option-attached operands are no longer positional slots. This is the same mechanism behind the PipUninstallOptions(Package) finding on [Automated] Update pip CLI Options #4554 (-r <requirements file> is option-attached).
  • Regenerated cargo with the fixed generator and recorded Cargo.Generation.json provenance the way the workflow does. The only generated change is the explicit IValidatableObject.Validate the generator now emits (same as [Automated] Update gcloud CLI Options #4665's gcloud output); CargoOptionsTests compiles and passes unchanged.

Validation

  • CargoCliScraperTests, UsageSynopsisParserTests, CliScraperTraversalTests (157) and the full Scrapers namespace (664) pass.
  • ModularPipelines.Rust.UnitTests (7) passes against the regenerated options.
  • PublicAPI baselines are untouched: main records no CargoAddOptions.Validate entry, so the explicit implementation removes nothing that was declared. Sync-PublicApiBaselines.ps1 threw "Compiler error log contains no RS0016 public API entries" locally and was not used.

Closes #4692

https://claude.ai/code/session_01PkLNTUfwGXjqXZrYrHaDGC

…out of required positionals

Two regressions from #4470 broke the cargo regeneration (#4692):

- CargoCliScraper only read option rows under headings containing "option"
  or ending in "selection", so clap's `Source:` and `Section:` groups on
  `cargo add`/`cargo remove` (--path, --git, --branch, --dev, ...) vanished
  from the generated options. Every heading is now an option section except
  the positional, command and prose ones (Arguments, Commands, Examples, ...).

- UsageSynopsisParser treated an operand attached to an option
  (`--path <PATH>`) as a positional slot when deciding whether an operand
  missing from an alternate usage form is still required. With `[OPTIONS]`
  ahead of every form the phases matched, so `<DEP>` stayed a required
  constructor parameter even though `--path`/`--git` are alternatives to it.
  Option-attached operands no longer count as positional slots.

Regenerated cargo from cargo 1.98.0 (the same tree as the baseline) and
recorded provenance; the only generated change is the explicit
IValidatableObject.Validate implementation the generator now emits, and
CargoOptionsTests compiles and passes unchanged.

Closes #4692

Claude-Session: https://claude.ai/code/session_01PkLNTUfwGXjqXZrYrHaDGC
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 6, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-06T08:25:54.684465Z 03fa1cf PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Sep 6, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 3 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: c8300acd-1023-4ff2-86b6-b502aba88304

📥 Commits

Reviewing files that changed from the base of the PR and between 2708f78 and 03fa1cf.

⛔ Files ignored due to path filters (2)
  • src/ModularPipelines.Rust/Generated/Cargo.Generation.json is excluded by !**/generated/**
  • src/ModularPipelines.Rust/Options/CargoAddOptions.Generated.cs is excluded by !**/*.generated.*
📒 Files selected for processing (4)
  • tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator.Tests/Scrapers/CargoCliScraperTests.cs
  • tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator.Tests/Scrapers/UsageSynopsisParserTests.cs
  • tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Scrapers/Cli/CargoCliScraper.cs
  • tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Scrapers/Cli/UsageSynopsisParser.cs

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

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 03fa1cf31a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +712 to 716
var positionalCandidates = alternativeArguments.Where(IsPositionalSlot).ToArray();
return positionalCandidates.Length == selectedArgumentCount
&& positionalCandidates.Any(candidate =>
candidate.IsRequired
&& candidate.PositionIndex == selectedArgument.PositionIndex

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude selected option operands from positional matching

When the highest-ranked synopsis contains an option-owned operand, such as tool run --file <FILE> <TARGET>, and another form contains one renamed positional such as tool run <OBJECT>, the filtered counts are both one, but <FILE> still participates in the index fallback and matches <OBJECT> at index 0. Consequently <FILE> remains required even though the alternate form omits --file; require selectedArgument to be a positional slot before applying this fallback.

Useful? React with 👍 / 👎.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Review

This is a well-targeted fix for the cargo regeneration regression, and the root-cause analysis in the description is solid — both bugs are demonstrated with new, focused tests rather than just patched around the symptom.

CargoCliScraper.IsOptionSectionHeading — inverting the heuristic (deny-list of prose/positional/command headings instead of an allow-list of "option"/"selection" headings) correctly handles clap's arbitrary heading names (Source:, Section:, Manifest Options:, Package Selection:). The new Options_Under_Custom_Clap_Headings_Are_Parsed test pins this down well, including the known -p, --package [<SPEC>] optional-value gap (tracked separately as #4712) rather than silently mishandling it.

UsageSynopsisParser.IsPositionalSlot/IsRequiredInAlternative — correctly reuses the existing AssociatedOptionSwitch field (already used in CliPositionalArgument.MergeDuplicates) rather than introducing a new concept, which keeps "is this operand actually positional" consistent across the parser. Filtering both sides of the count comparison (selectedPositionalCount vs positionalCandidates.Length) to positional-only slots is the right fix — comparing apples to apples instead of raw argument counts that included option-owned operands.

Both changes are made in the shared scraper/generator logic rather than cargo-specific special-casing, in line with the project's stated preference for generic fixes that benefit every tool. Regenerated output is minimal (just the IValidatableObject.Validate explicit-interface change, consistent with the #4665 precedent), and the description's PublicAPI-baseline check confirms this isn't a tracked API removal.

One non-blocking observation: IsOptionSectionHeading's !heading.Contains("command", ...) catch-all is a bit broad — it would also exclude a hypothetical heading like "Command Options:" if some future clap-based tool used one, even though such a heading would legitimately contain options. Not worth blocking on since it's speculative and the current behavior is fully covered by tests, but worth keeping in mind if a future regeneration surfaces that heading shape.

No prior review comments on this PR raised anything actionable (Codex found nothing, CodeRabbit was rate-limited), so there's nothing outstanding to verify against.

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.

Regenerated CargoAddOptions breaks CargoOptionsTests so the cargo update cannot be opened

1 participant