Skip to content

fleet(dispatch): duplicate and contradictory flags silently resolved — repeated values overwrite, --no-* always beats --* #5713

Open

Description

@dezren39

fleet(dispatch): duplicate and contradictory flags are silently resolved — last value wins, --no-* always beats --*

Summary

fleet dispatch launch / fleet dispatch enqueue parse their flags with a hand-rolled parser (pkgs/fleet/crates/fleet-dispatch/src/lib.rs) that silently discards user input in three ways:

  1. Duplicate value flags overwrite silently. parse_args stores each --flag value with values.insert(...) (lib.rs:555), so --repo developing-today/code --repo dezren39/darwin-nix launches against the second repo with no error or warning — the first value is silently dropped.
  2. Contradictory boolean pairs resolve by check order, not argument order. verb_launch tests no-issue before issue and no-wait before wait (lib.rs:638-649), so --issue --no-issue and --no-issue --issue both send issue: false. One of the two flags the user typed is silently ignored, whichever order they wrote them in.
  3. --prompt + --prompt-file together silently drop the prompt. prompt_of (lib.rs:580-587) prefers --prompt-file whenever it is present; an explicitly typed --prompt <text> is discarded without a word.

This is the fleet CLI family's established silent-discard class (see #5568, #5572, #5592, #5603, #5607, #5652 — trailing/extra arguments silently ignored, each fixed to a usage error naming the argument). Duplicate and contradictory flags are the same failure one step earlier in parsing, with sharper consequences: launch creates real sessions, tracking issues, and queue tasks, so a silently-wrong --repo, a silently-dropped tracking issue (--issue overridden by a stray --no-issue), or a silently-substituted prompt acts on the wrong work instead of merely misreporting success.

Evidence (main @ af0847d, read via gh api raw; laptop unavailable this run — broker tunnel down, #5708)

  • pkgs/fleet/crates/fleet-dispatch/src/lib.rs:527-570 — parse_args: value flags go into a Map via values.insert(name, ...) at :555 with no duplicate check; bool flags via flags.insert(...) at :544. Unknown flags and missing values are usage errors — duplicates are the one malformed shape that is not.
  • pkgs/fleet/crates/fleet-dispatch/src/lib.rs:638-649 — verb_launch: if parsed.flag("no-issue") { issue=false } else if parsed.flag("issue") { issue=true }, and the same shape for no-wait/wait. Both members of a pair can be present simultaneously; the negative always wins regardless of order.
  • pkgs/fleet/crates/fleet-dispatch/src/lib.rs:580-587 — prompt_of: if let Some(path) = args.get("prompt-file") { read it } else require --prompt. Both supplied → the --prompt text never reaches the request body.
  • pkgs/fleet/crates/fleet-dispatch/src/lib.rs:660-735 — verb_enqueue shares the same parser and the same prompt_of, so duplicates of --repo / --title / --issue-number / --dedupe-key overwrite silently there too.
  • The fleet-queue client parser has the same overwrite shape (pkgs/fleet/crates/fleet-queue/src/client.rs:471-504, opts.insert at :487/:490) — noted as the sibling surface; this issue's fix is scoped to fleet-dispatch, and the queue parser can be aligned in the same change if the worker judges it in-scope, or filed separately.

Why it matters

fleet dispatch launch is the fleet's own session launcher: it POSTs to pm-dispatch, which creates a tracking issue and a queue task and starts an OpenCode session on the laptop. Silent flag resolution means a mistyped or scripted command can launch work against the wrong repository, skip the tracking issue the operator asked for, wait (or not wait) contrary to the flag they wrote last, or run a prompt read from a file instead of the text they typed — with exit 0 and no indication anything was overridden. Every sibling surface in this CLI family now errors on silently-discarded input; dispatch's parser is the remaining one that resolves it quietly.

Acceptance criteria

  • parse_args in fleet-dispatch rejects a repeated value flag (--repo a --repo b, including the --repo=a inline form) with a usage error naming the flag, before any network call.
  • verb_launch rejects --issue together with --no-issue, and --wait together with --no-wait, with a usage error naming the contradictory pair, before any network call. (Rejecting a repeated identical bool flag is optional; the contradictory pair must error.)
  • Supplying both --prompt and --prompt-file to launch or enqueue is a usage error naming both, instead of silently preferring the file.
  • Single, non-contradictory invocations behave exactly as today (including --help in any position, per fleet dispatch status silently ignores all arguments — --help performs a live GET /health and typos are swallowed #5560's verb help handling).
  • New pinning tests in the fleet-dispatch test module cover: duplicate value flag rejected, both contradictory pairs rejected in both orders, prompt+prompt-file rejected, and the ordinary single-flag controls still parse.
  • cargo test -p fleet-dispatch passes on the laptop / in CI.

Related: #5560 (dispatch status args, fixed), #5555 (dispatch status endpoint gap), #5413 (absorb dispatch into repo-queue — if that lands first, the same rule should hold in the absorbing parser).

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    source/creatorFiled by the new-issue-creator job
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/fleetpkgs/fleet multicall binary + platform crates
    on Nov 5, 2026
  2. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

  3. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  4. 134 remaining items

  5. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  6. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    queue/claimedQueue worker lifecycle state
    and removed
    queue/claimedQueue worker lifecycle state
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 6, 2026
  7. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  8. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Nov 6, 2026
  9. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    Agent note — task 9818 handed off (lane code-g)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/fleetpkgs/fleet multicall binary + platform crateskind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)queue/parkedQueue task is parked (waiting on CI, time, or an event)source/creatorFiled by the new-issue-creator jobstatus/parkedDeliberately paused with a recorded resume conditiontask/small-fixQueue packet kind: bounded fix with reproduction and targeted testswork/assignedQueue worker lifecycle state

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions