Skip to content

Spec multi-arg audit: git and the editor diff options - #342

Merged
acarl005 merged 2 commits into
mainfrom
factory/audit-multi-arg-git-editors
Aug 24, 2026
Merged

Spec multi-arg audit: git and the editor diff options#342
acarl005 merged 2 commits into
mainfrom
factory/audit-multi-arg-git-editors

Conversation

@warp-agent-staging

@warp-agent-staging warp-agent-staging Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Audit of the options in this group that declare two or more args, part of the corpus-wide pass following the ln fix in #341. Group: git and the editor diff options.

The completer resolves the last declared arg of a multi-arg option regardless of which value is being typed, so a mis-modelled option actively breaks completion. Every verdict below was checked against the tool's own ground truth before anything was edited.

Ground truth used

  • git 2.43.0, installed and run in this environment: git branch -h, git switch -h, git config -h. No git man pages were installed, so the synopses were cross-checked against https://git-scm.com/docs/git-branch and https://git-scm.com/docs/git-switch.
  • VS Code: code is not installable here, so the official parser definition was used — src/vs/platform/environment/node/argv.ts in microsoft/vscode.

Why git appears twice

The scan found the git options in two files because two specs describe git:

  • command-signatures/json/git.json — the maintained spec, using Rust generatorName references.
  • command-signatures/json/hub.json — a stale Fig-derived copy of the same spec (its internal "name" is literally "git", and it carries no hub-specific subcommands). Lookup in assets.rs is by filename, so this file is what ships for the hub command, which proxies git. Both are real and both are fixed here.

One difference matters: every arg in hub.json carries inline Fig JavaScript generators, a field the Rust Arg struct in completion-metadata/src/fig_types.rs does not deserialize. Those args therefore produce no suggestions at all today. No generatorName was introduced in hub.json, because hub has no registered generator set in generators/mod.rs — a name there would pass all_referenced_generators_exist (which pools names across all commands) but resolve to nothing at runtime.

Options changed

Option File Category Evidence
git branch -m / --move git.json, hub.json 1 — operands written into the option git branch -h: -m, --[no-]move move/rename a branch and its reflog, listed under "Specific git-branch actions" with no value placeholder. Usage line: git branch [<options>] (-m | -M) [<old-branch>] <new-branch> — the two names are operands of git branch.
git branch -M git.json, hub.json 1 git branch -h: -M move/rename a branch, even if target exists — no value placeholder; same usage line.
git branch --no-track git.json, hub.json 1 git branch -h: -t, --[no-]track[=(direct|inherit)] — the negated form takes no value. Its two local_branches args were the <branch-name> [<start-point>] operands from git branch [--track[=(direct|inherit)] | --no-track] [-f] [--recurse-submodules] <branch-name> [<start-point>].
git branch -t / --track git.json, hub.json 3 — value set enumerated as args git branch -h: -t, --[no-]track[=(direct|inherit)]. The declared [branch, start point] was wrong on both counts: the value set is direct|inherit, and those two names are the command's operands. The args are removed and the option left boolean — see "The --track value is unmodellable today" below for why it does not become a one-argument option.
git switch -c / --create git.json, hub.json 1 git switch -h: -c, --[no-]create <branch> — exactly one value. Synopsis: git switch [<options>] (-c|-C) <new-branch> [<start-point>] — the start-point is an operand of switch.
git switch -C / --force-create git.json, hub.json 1 git switch -h: -C, --[no-]force-create <branch> — exactly one value; same synopsis line.
git switch -t / --track git.json, hub.json 3 git switch -h: -t, --[no-]track[=(direct|inherit)]. Same treatment as the git branch copy: args removed, option left boolean.
git switch --no-track git.json, hub.json 1 git-switch(1) documents --no-track with no value: "Do not set up 'upstream' configuration…". Its args were duplicates of switch's own positionals.
code -d / --diff code.json 1 microsoft/vscode, src/vs/platform/environment/node/argv.ts:104: 'diff': { type: 'boolean', cat: 'o', alias: 'd', args: ['file', 'file'], … }. type is 'boolean', so diff goes into booleanOptions and is passed to minimist(args, { boolean: booleanOptions, … }) (argv.ts:328); the two paths land in argv._. The args field is read only by formatUsage (argv.ts:400-408) to render the help line. --merge in the same table is also type: 'boolean' with four "args", which confirms the field is help-text metadata rather than option values.
code-insiders -d / --diff code-insiders.json 1 Same file, same option definition; code-insiders is the Insiders build of the same CLI.

One structural addition

git branch had no top-level args in either spec, so removing the option args alone would have dropped branch-name completion outright — git branch -m ⇥ would have offered nothing. The documented operand was therefore added to the branch subcommand as an optional variadic branch-name, per the synopsis forms in git-branch(1). In git.json it carries generatorName: local_branches (the same generator the removed option args used, so today's suggestions are preserved); in hub.json it carries no generator, for the reason above.

The --track value is unmodellable today — please do not "fix" this back

--track does accept direct or inherit, so it is tempting to model it as a single optional argument carrying those two suggestions. That would be wrong, and the omission here is deliberate.

git's parse-options marks --track as OPTION_OPTARG, so the value is legal only when attached. Both forms were run to confirm:

  • git branch --track=direct attached start — succeeds.
  • git branch --track direct spaced start — prints usage and fails.

A normal optional argument in this schema models the space-separated form, so suggesting direct/inherit there would confidently complete a command git rejects. The schema cannot express the attached-only form either:

  • CommandOption.requires_equals exists in completion-metadata/src/fig_types.rs (deserialized from requiresEquals), but From<CommandOption> for Opt (fig_types.rs:485-499) copies only name, description, args, is_required and priorityrequires_equals is silently dropped.
  • Opt itself (completion-metadata/src/signature.rs:169-176) has no such field, so the information cannot reach the completer at all.

Until requiresEquals is plumbed through to Opt, suggesting nothing beats suggesting an invalid command. --track therefore stays boolean in all four places.

Options verified as correct and left alone

Option Category Evidence
git config --get-urlmatch [name, url] 4 — genuinely multi-valued git config -h: --[no-]get-urlmatch get value specific for the URL: section[.var] URL — two values.
git config --get-color [name, default] 4 git config -h: --[no-]get-color find the color configured: slot [default] — two values, the second optional. Matches the spec's [name, default (isOptional)] exactly.

Other residuals

Nothing in this group was left unresolved for lack of ground truth. Two further things a reviewer should know:

  1. git switch -c <name> ⇥ loses the commits generator. Before the fix, the second declared arg (start point, generatorName: commits) was what the completer resolved — meaning you got git log --oneline hashes while typing the new branch name, which is the bug. After the fix, the start-point operand falls through to switch's own first positional, which offers local_branches + refs_remote_branches rather than commits. Branches are valid start points, so this is a narrower suggestion set at that position, not a broken one. Widening switch's first positional to include commits would pollute plain git switch <branch>, where a bare commit is not accepted, so it was left alone.
  2. git branch -m was not user-visibly broken before, because both of its declared args were the identical local_branches generator, so the last-arg bug produced the right answer by coincidence. The modelling was still wrong, and the fix keeps the same suggestions via the new top-level positional.

Noticed outside this group, not touched

  • code / code-insiders -a/--add and -g/--goto are the same class of error but declare a single arg, so they fell below the scan's two-or-more threshold. argv.ts:106,108 declares both type: 'boolean' with help-only args; their operands belong to the command, which already has a variadic filepaths+folders positional.
  • git.json sets "requiresSeparator": true on git log --diff-filter, but requiresSeparator is not a field on CommandOption in completion-metadata/src/fig_types.rs, so it is silently dropped at deserialization. Renaming it to requiresEquals would not help, for the reason given above.

Validation

  • cargo test -p warp-command-signatures176 passed, 0 failed. This covers all_command_specs_succeed_deserialization and all_referenced_generators_exist.
  • npx prettier --check on all four edited files — clean.
Computer-use video recordings (1)

View video recording - GUI validation of this PR: typing git branch , git branch -m , git branch -m fea and git branch --track , showing branch names offered from the newly added positional in every form, with no duplicated pair.

Audit of options declaring two or more args, for the git and editor-diff
group. Each verdict was checked against the tool's own ground truth.

Operands written into the option (option is a boolean flag; the extra
args duplicate the command's positionals):
  git branch -m/--move, -M, --no-track   (git branch -h; git-branch(1)
    synopsis 'git branch (-m|-M) [<old-branch>] <new-branch>')
  git switch -c/--create, -C/--force-create
    ('-c, --[no-]create <branch>' takes exactly one value; the
    start-point is an operand of switch)
  git switch --no-track
  code -d/--diff, code-insiders -d/--diff
    (microsoft/vscode argv.ts: "diff" is type:'boolean'; its 'args'
    field is only read by formatUsage for help rendering, and the two
    paths are collected into argv._)

A value set enumerated as args:
  git branch -t/--track, git switch -t/--track
    ('-t, --[no-]track[=(direct|inherit)]') collapse to one optional
    argument carrying direct/inherit as suggestions, matching the
    sibling --color[=<when>] shape already used in this spec.

git branch had no top-level args of its own, so simply removing the
option args would have dropped branch-name completion entirely. Added
the documented operand as a variadic positional so it still resolves.

git config --get-urlmatch and --get-color are genuinely two-valued
('get value specific for the URL: section[.var] URL' and 'find the
color configured: slot [default]') and are left untouched.

hub.json is a stale Fig-derived copy of the git spec that ships for the
hub command, so it carries the same defects and gets the same fixes.
Its arg generators are inline Fig JavaScript, which Warp does not
deserialize, so no generatorName was introduced there.
@warp-agent-staging

Copy link
Copy Markdown
Contributor Author

This PR was generated with Warp.

Comment @warp-factory on this PR to send it follow-up work.

View run View conversation View on Slack

Review finding on the revision: --track's direct|inherit value is legal
only when attached. Verified both forms --
  git branch --track=direct attached start   succeeds
  git branch --track direct spaced start     prints usage
git's parse-options marks the option OPTION_OPTARG.

A plain optional argument models the space-separated form, so carrying
direct/inherit as suggestions would complete a command git rejects. The
schema cannot express attached-only today: CommandOption.requires_equals
is deserialized in fig_types.rs but dropped by From<CommandOption> for
Opt, and Opt has no such field, so the flag never reaches the completer.

Leave the option boolean in all four places (git branch and git switch,
in both git.json and hub.json). Suggesting nothing beats suggesting an
invalid command. Recorded in the PR body as unmodellable rather than
merely omitted, so it does not get 'fixed' back.
@acarl005
acarl005 marked this pull request as ready for review August 23, 2026 22:25
@warp-for-oss

warp-for-oss Bot commented Aug 23, 2026

Copy link
Copy Markdown

@acarl005

I'm starting a first review of this pull request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

@warp-agent-staging warp-agent-staging Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Per-hunk reasoning, inline below, so the evidence sits next to the change instead of only in the description.

Ground truth was git 2.43.0's own -h output, run in this environment — no git man pages were installed, so the synopses were cross-checked against git-scm.com. For VS Code, code could not be installed here, so the authority is the option table in src/vs/platform/environment/node/argv.ts in microsoft/vscode.

Two options in scope are deliberately absent from the diff. Both were checked and are genuinely two-valued, per git config -h:

  • --get-urlmatch [name, url]--[no-]get-urlmatch get value specific for the URL: section[.var] URL
  • --get-color [name, default]--[no-]get-color find the color configured: slot [default], the second value optional, matching the spec's isOptional exactly.

They sit roughly 6,000 lines from the nearest hunk in git.json, and GitHub only accepts inline comments on lines inside the diff, so that note is here rather than anchored.

Responding as wilson: Open session · View in factory

"template": "filepaths"
}
]
"description": "Compare two files with each other"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

VS Code's parser treats --diff as a mode flag, so the two paths are never consumed by the option. argv.ts:104: 'diff': { type: 'boolean', cat: 'o', alias: 'd', args: ['file', 'file'], … }type: 'boolean' puts diff into booleanOptions, which is handed to minimist(args, { boolean: booleanOptions, … }) at argv.ts:328, so both paths land in argv._.

The args field is read only by formatUsage (argv.ts:400-408) to render the help line; --merge on the next line is also type: 'boolean' with four "args", which settles that it is help metadata rather than option values. code's top-level variadic filepaths+folders positional already serves the operands, so nothing is lost.

"template": "filepaths"
}
]
"description": "Compare two files with each other"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Same option, same source: code-insiders is the Insiders build of the same CLI and shares argv.ts. Reasoning is on the code.json hunk.

"generatorName": "local_branches"
}
]
"description": "Move/rename a branch and its reflog"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Both are listed by git branch -h with no value placeholder — -m, --[no-]move move/rename a branch and its reflog and -M move/rename a branch, even if target exists — so neither consumes a value. The two branch names are operands of the command, per the usage line git branch [<options>] (-m | -M) [<old-branch>] <new-branch>; they keep their local_branches completions through the subcommand positional added further down this file.

"generatorName": "commits"
}
]
"description": "When creating a new branch, set up 'upstream' configuration"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

git branch -h: -t, --[no-]track[=(direct|inherit)]. The value set is direct|inherit — never a branch and a start point, which is what the removed args claimed.

It stays a bare flag rather than becoming a one-value option because git accepts the value only when attached: git branch --track=direct attached start succeeds, git branch --track direct spaced start prints usage (parse-options marks it OPTION_OPTARG). We cannot express attachment today — requires_equals is dropped by From<CommandOption> for Opt (fig_types.rs:485-499) and Opt (signature.rs:169-176) has no such field — so offering direct/inherit at a space-separated position would confidently complete a command git rejects.

"generatorName": "local_branches"
}
]
"description": "Do not set up 'upstream' configuration, even if the branch.autoSetupMerge configuration variable is true"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The negated half of -t, --[no-]track[=(direct|inherit)] takes no value at all. The two local_branches args it carried were the command's own operands, from git branch [--track[=(direct|inherit)] | --no-track] [-f] [--recurse-submodules] <branch-name> [<start-point>].

]
}
]
],

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Mirrors the git branch positional added in git.json, with one deliberate difference: no generatorName. hub has no registered generator set in generators/mod.rs, so a name here would satisfy all_referenced_generators_exist — that test pools generator names across all commands — while resolving to nothing at runtime.

}
}
]
"args": {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Mirrors git switch -c in git.json.

}
}
]
"args": {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Mirrors git switch -C in git.json.

}
}
]
"description": "When creating a new branch, set up 'upstream' configuration"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Mirrors git switch --track in git.json.

}
}
]
"description": "Do not set up 'upstream' configuration, even if the branch.autoSetupMerge configuration variable is true"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Mirrors git switch --no-track in git.json.

@warp-for-oss warp-for-oss 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.

Overview

This PR updates static command signature metadata for VS Code diff flags and git branch/switch options by removing option-level args that represent command operands or help-only metadata, and by adding a branch positional operand so branch-name completion is not dropped.

Concerns

  • No blocking correctness concerns found in the annotated diff.
  • Security pass found no issues: the changes are static JSON metadata only, with no new executable code, dependencies, auth paths, input handling, or secrets.
  • Spec alignment was not applicable because spec_context.md contains no approved or repository spec context.
  • Comment/test audit: no code comments or tests were added or changed in the diff.

Verdict

Found: 0 critical, 0 important, 0 suggestions

Approve

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

@acarl005
acarl005 merged commit 89e4def into main Aug 24, 2026
8 checks passed
@acarl005
acarl005 deleted the factory/audit-multi-arg-git-editors branch August 24, 2026 02:11
@acarl005 acarl005 self-assigned this Aug 24, 2026
acarl005 pushed a commit to warpdotdev/warp that referenced this pull request Aug 24, 2026
<!-- warp:pr-description-artifacts start -->
<!-- warp:pr-description-artifacts end -->

## Description
Bumps the `warp-command-signatures` git dependency from `564724f` to
`d3725aa`, bringing the four merged spec-audit PRs into the app on top
of the already-merged `ln` fix (#341, which landed via #15480).

**What moved:** `Cargo.toml` rev `564724f` → `d3725aa`, plus the two
matching `Cargo.lock` entries (`warp-command-signatures`,
`warp-completion-metadata`). No other lockfile entries change.

**Commits in range (`564724f..d3725aa`):** exactly four —
- Spec multi-arg audit: git and the editor diff options
(warpdotdev/command-signatures#342)
- Fix mis-modelled multi-arg options: text, data and file utility specs
(#343)
- Fix multi-arg option modelling: build systems and language tooling
(#344)
- Fix mis-modelled multi-arg options: ecosystem CLIs and macOS tools
(#345)

(The full `ac69f9b..d3725aa` range is the five-PR audit; #341 is already
in the app via #15480, so this bump carries the remaining four.)

### What changes for users
- `date -f`, `hugo new -k`, and the `git branch` / `git switch` options
stop carrying the command's own operands as their arguments (the same
modelling error the `ln` fix corrected, now fixed across these too).
- `rsync --info` and `--debug` collapse to a single comma-separated
argument, and `--debug` gains the 27 flags it never had.
- `rustc -L` now inserts `dependency=` instead of a bare, invalid
`dependency`.
- `dart format`'s `--show` and `--summary` are modelled as real options
again.
- `lpass`'s boolean options offer `true` and `false`.
- `unzip -0` and `rustc --l` disappear — they are flags that don't
actually exist.
- **Deliberate loss:** `pmset`'s setting/value pair is no longer
modelled. This is the one visible regression in the batch and is
intentional — the previous modelling was wrong, and no correct arity was
available to replace it.

All four audit PRs were validated in the real GUI before merge. The
`make` variadic fix (`make.json`) came out of that validation, which is
why a `make` change rides along in a batch that is otherwise about
option arity.

## Linked Issue
- [x] The linked issue is labeled `ready-to-spec` or
`ready-to-implement`.
- [x] Where appropriate, screenshots or a short video of the
implementation are included below (especially for user-visible or UI
changes).

## Testing
- `cargo metadata --locked` passes — the minimal lockfile (only the two
command-signatures entries bumped) is in sync with the new rev.
- `cargo nextest run -p warp_completer --locked` corpus-backed tests
pass against the new specs, including
`test_all_known_signature_names_are_within_the_length_cap` (iterates the
whole embedded corpus) and the `bundle`/`kubectl`/`sudo` registry tests.
No corpus-backed test shifts.
- [x] I have manually tested my changes locally with `./script/run`

## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode

CHANGELOG-BUG-FIX: Fixed completions for many commands' multi-argument
options that were mis-modelled (e.g. `git branch`/`git switch`, `rsync
--info`/`--debug`, `rustc -L`, `dart format`, `hugo new`, `date`), so
they no longer offer the wrong arguments.

Co-authored-by: warp-agent-staging[bot] <240773466+warp-agent-staging[bot]@users.noreply.github.com>
iamwavecut pushed a commit to iamwavecut/warp that referenced this pull request Aug 25, 2026
<!-- warp:pr-description-artifacts start -->
<!-- warp:pr-description-artifacts end -->

## Description
Bumps the `warp-command-signatures` git dependency from `564724f` to
`d3725aa`, bringing the four merged spec-audit PRs into the app on top
of the already-merged `ln` fix (warpdotdev#341, which landed via warpdotdev#15480).

**What moved:** `Cargo.toml` rev `564724f` → `d3725aa`, plus the two
matching `Cargo.lock` entries (`warp-command-signatures`,
`warp-completion-metadata`). No other lockfile entries change.

**Commits in range (`564724f..d3725aa`):** exactly four —
- Spec multi-arg audit: git and the editor diff options
(warpdotdev/command-signatures#342)
- Fix mis-modelled multi-arg options: text, data and file utility specs
(warpdotdev#343)
- Fix multi-arg option modelling: build systems and language tooling
(warpdotdev#344)
- Fix mis-modelled multi-arg options: ecosystem CLIs and macOS tools
(warpdotdev#345)

(The full `ac69f9b..d3725aa` range is the five-PR audit; warpdotdev#341 is already
in the app via warpdotdev#15480, so this bump carries the remaining four.)

### What changes for users
- `date -f`, `hugo new -k`, and the `git branch` / `git switch` options
stop carrying the command's own operands as their arguments (the same
modelling error the `ln` fix corrected, now fixed across these too).
- `rsync --info` and `--debug` collapse to a single comma-separated
argument, and `--debug` gains the 27 flags it never had.
- `rustc -L` now inserts `dependency=` instead of a bare, invalid
`dependency`.
- `dart format`'s `--show` and `--summary` are modelled as real options
again.
- `lpass`'s boolean options offer `true` and `false`.
- `unzip -0` and `rustc --l` disappear — they are flags that don't
actually exist.
- **Deliberate loss:** `pmset`'s setting/value pair is no longer
modelled. This is the one visible regression in the batch and is
intentional — the previous modelling was wrong, and no correct arity was
available to replace it.

All four audit PRs were validated in the real GUI before merge. The
`make` variadic fix (`make.json`) came out of that validation, which is
why a `make` change rides along in a batch that is otherwise about
option arity.

## Linked Issue
- [x] The linked issue is labeled `ready-to-spec` or
`ready-to-implement`.
- [x] Where appropriate, screenshots or a short video of the
implementation are included below (especially for user-visible or UI
changes).

## Testing
- `cargo metadata --locked` passes — the minimal lockfile (only the two
command-signatures entries bumped) is in sync with the new rev.
- `cargo nextest run -p warp_completer --locked` corpus-backed tests
pass against the new specs, including
`test_all_known_signature_names_are_within_the_length_cap` (iterates the
whole embedded corpus) and the `bundle`/`kubectl`/`sudo` registry tests.
No corpus-backed test shifts.
- [x] I have manually tested my changes locally with `./script/run`

## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode

CHANGELOG-BUG-FIX: Fixed completions for many commands' multi-argument
options that were mis-modelled (e.g. `git branch`/`git switch`, `rsync
--info`/`--debug`, `rustc -L`, `dart format`, `hugo new`, `date`), so
they no longer offer the wrong arguments.

Co-authored-by: warp-agent-staging[bot] <240773466+warp-agent-staging[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant