change record: accept multiple paths after --files #129

Merged
vnprc merged 3 commits from agent/files-usage-repeatable into master 2026-07-28 21:14:18 +01:00
Member

Closes allod/tools#128

allod change record's usage lines spell the staging flag [--files <file>...], which reads as "one or more values after the flag". The parser took exactly one and shifted past it, so a bare second path fell through to the catch-all and aborted with unexpected argument for change record: <path>.

A flag named --files that accepts exactly one file is the defect. The usage string was describing the interface a human would expect, so the parser moves to match it rather than the other way round.

  • -f|--files now consumes every following argument up to the next --prefixed token. change record takes no positional arguments, so nothing else can be swallowed.
  • The repeated form still accumulates, and the two combine: --files a b, --files a --files b, and -f a b --files c all name the same set.
  • Flag order is free, because a following option ends the list — --files a b -m msg and -m msg --files a b are equivalent.
  • A list that consumes nothing, whether --files at the end of the line or --files -m msg, still dies with the existing requires a value wording instead of falling through to the git add -u sweep that naming no files selects.
  • -- ends option parsing, so a path beginning with - stays reachable; a bare -- with nothing after it is an error for the same reason.
  • The usage synopsis returns to [--files <file>...], and the prose now describes the variadic flag instead of telling the reader to give each file its own flag.

The first commit on this branch took the opposite direction and edited the documentation to match the single-value parser. It stays in history; the commit after it supersedes that direction.

Risk

R1. Argument parsing for one subcommand, all of it before any git mutation. Every invocation that works on master keeps working — a lone --files a and the repeated --files a --files b parse exactly as before — and every form this adds aborts on master, so nothing can go from working to broken. The hazard worth naming is the empty file list, which would hand record back to git add -u and sweep another agent's tracked edits; that path is refused explicitly and covered by its own sabotage check. -- is the only token whose meaning changes: it previously reached the catch-all and died as an unknown option.

Validation

  • bash tests/allod-change.sh passes: 183 assertions, up from 159 on master. The 24 new ones cover several paths after one flag, the mixed -f a b --files c form, both flag orders with the resulting commit message asserted, the empty-list errors for --files, -f, and --, and a path literally named -dash.txt passed after --.
  • Sabotage checks, each applied to a green tree and confirmed as a non-empty diff before the run:
    • parser reverted to the single-value files+=("$2"); shift 2 — fails at record accepts several paths after one --files.
    • guard against a --prefixed token immediately after the flag removed — fails at record rejects --files followed by another option, which then commits a git add -u sweep instead of erroring.
    • -- case removed — fails at record stages a '-'-prefixed path after --.
  • This branch's own commit was recorded with the new form, ./allod change record -M <file> --files allod tests/allod-change.sh, staging both paths from one flag.
  • allod change --help renders the corrected usage block.

Found and left alone

  • allod/memory's git-workflow.md and allod.md spell the flag [-f <file>...]. This makes that spelling true rather than misleading, so neither needs an edit.
  • No other subcommand documents a <file>...-style variadic backed by a single-value parser. flake-update-cascade <input-name>... is genuinely variadic, and change submit's -F <file|-> is single-valued and spelled that way.
Closes allod/tools#128 `allod change record`'s usage lines spell the staging flag `[--files <file>...]`, which reads as "one or more values after the flag". The parser took exactly one and shifted past it, so a bare second path fell through to the catch-all and aborted with `unexpected argument for change record: <path>`. A flag named `--files` that accepts exactly one file is the defect. The usage string was describing the interface a human would expect, so the parser moves to match it rather than the other way round. - `-f|--files` now consumes every following argument up to the next `-`-prefixed token. `change record` takes no positional arguments, so nothing else can be swallowed. - The repeated form still accumulates, and the two combine: `--files a b`, `--files a --files b`, and `-f a b --files c` all name the same set. - Flag order is free, because a following option ends the list — `--files a b -m msg` and `-m msg --files a b` are equivalent. - A list that consumes nothing, whether `--files` at the end of the line or `--files -m msg`, still dies with the existing `requires a value` wording instead of falling through to the `git add -u` sweep that naming no files selects. - `--` ends option parsing, so a path beginning with `-` stays reachable; a bare `--` with nothing after it is an error for the same reason. - The usage synopsis returns to `[--files <file>...]`, and the prose now describes the variadic flag instead of telling the reader to give each file its own flag. The first commit on this branch took the opposite direction and edited the documentation to match the single-value parser. It stays in history; the commit after it supersedes that direction. ## Risk R1. Argument parsing for one subcommand, all of it before any git mutation. Every invocation that works on master keeps working — a lone `--files a` and the repeated `--files a --files b` parse exactly as before — and every form this adds aborts on master, so nothing can go from working to broken. The hazard worth naming is the empty file list, which would hand `record` back to `git add -u` and sweep another agent's tracked edits; that path is refused explicitly and covered by its own sabotage check. `--` is the only token whose meaning changes: it previously reached the catch-all and died as an unknown option. ## Validation - `bash tests/allod-change.sh` passes: 183 assertions, up from 159 on master. The 24 new ones cover several paths after one flag, the mixed `-f a b --files c` form, both flag orders with the resulting commit message asserted, the empty-list errors for `--files`, `-f`, and `--`, and a path literally named `-dash.txt` passed after `--`. - Sabotage checks, each applied to a green tree and confirmed as a non-empty diff before the run: - parser reverted to the single-value `files+=("$2"); shift 2` — fails at `record accepts several paths after one --files`. - guard against a `-`-prefixed token immediately after the flag removed — fails at `record rejects --files followed by another option`, which then commits a `git add -u` sweep instead of erroring. - `--` case removed — fails at `record stages a '-'-prefixed path after --`. - This branch's own commit was recorded with the new form, `./allod change record -M <file> --files allod tests/allod-change.sh`, staging both paths from one flag. - `allod change --help` renders the corrected usage block. ## Found and left alone - `allod/memory`'s `git-workflow.md` and `allod.md` spell the flag `[-f <file>...]`. This makes that spelling true rather than misleading, so neither needs an edit. - No other subcommand documents a `<file>...`-style variadic backed by a single-value parser. `flake-update-cascade <input-name>...` is genuinely variadic, and `change submit`'s `-F <file|->` is single-valued and spelled that way.
The record usage strings spelled the flag '[--files <file>...]', which reads
as a variadic list, while the parser consumes exactly one value per occurrence
and aborts on a bare second path. Spell it '[--files <file>]...', state the
rule in the usage prose, and cover both the repeated form and the refusal in
the change record tests.

Refs allod/tools#128
Owner

nobody writes a cli like this! it's just lazy. unacceptable.

make files (notice it has an s at the end) accept multiple filenames. then reevaluate whatever information you ingested to make this awful decision on feature direction. think about updating your memory or documentation or whatever to prevent this kind of decision in the future. no human would ever want to use the cli you just designed. treat cli interfaces as human facing interfaces and apply some common sense ux rules before you go off and build the wrong thing again.

smdh

nobody writes a cli like this! it's just lazy. unacceptable. make `files` (notice it has an s at the end) accept multiple filenames. then reevaluate whatever information you ingested to make this awful decision on feature direction. think about updating your memory or documentation or whatever to prevent this kind of decision in the future. no human would ever want to use the cli you just designed. treat cli interfaces as human facing interfaces and apply some common sense ux rules before you go off and build the wrong thing again. smdh
'--files' is plural, so it now consumes every following argument up to the next
option. The repeated form still accumulates and the two combine, so '--files a
b', '--files a --files b', and '-f a b --files c' all mean the same thing.

'change record' takes no positional arguments, so nothing becomes ambiguous. A
path that begins with '-' goes after '--', which ends option parsing, and a
path list that consumed nothing is an error rather than a silent fall back to
the 'git add -u' sweep.

The usage synopsis returns to '[--files <file>...]', which was an accurate
description of the flag all along.
allod-agent changed title from change record: document --files as a repeatable single-value flag to change record: accept multiple paths after --files 2026-07-28 20:57:48 +01:00
Author
Member

You are right. --files is plural and now takes as many paths as follow it.

What changed on the branch:

  • -f|--files consumes every following argument up to the next --prefixed token. Repeating the flag still accumulates, and the forms combine: --files a b, --files a --files b, and -f a b --files c all name the same set.
  • A following option ends the list, so flag order is free — --files a b -m msg and -m msg --files a b are equivalent.
  • --files with nothing usable after it is still an error, so an empty list never falls back to the git add -u sweep, and -- ends option parsing for a path that begins with -.
  • The usage synopsis goes back to [--files <file>...], which was accurate all along, and the prose that told you to give each file its own flag is gone.

Tests are at 183 assertions, up from 159 on master, and three sabotage runs confirm the new ones fail when the parser is reverted, when the empty-list guard is dropped, and when -- is removed.

Issue allod/tools#128 is corrected too: it had named the usage-string edit as the default and the variadic parser as the alternative, which was backwards.

The rule is going into allod/memory as a cli-design.md topic file, separate PR: a CLI is a human-facing interface, a plural flag takes multiple values, and when usage text and behavior disagree the default is to fix the behavior. Editing docs to match a defective implementation documents the bug, and a smaller diff is not a reason to ship a worse interface.

You are right. `--files` is plural and now takes as many paths as follow it. What changed on the branch: - `-f|--files` consumes every following argument up to the next `-`-prefixed token. Repeating the flag still accumulates, and the forms combine: `--files a b`, `--files a --files b`, and `-f a b --files c` all name the same set. - A following option ends the list, so flag order is free — `--files a b -m msg` and `-m msg --files a b` are equivalent. - `--files` with nothing usable after it is still an error, so an empty list never falls back to the `git add -u` sweep, and `--` ends option parsing for a path that begins with `-`. - The usage synopsis goes back to `[--files <file>...]`, which was accurate all along, and the prose that told you to give each file its own flag is gone. Tests are at 183 assertions, up from 159 on master, and three sabotage runs confirm the new ones fail when the parser is reverted, when the empty-list guard is dropped, and when `--` is removed. Issue allod/tools#128 is corrected too: it had named the usage-string edit as the default and the variadic parser as the alternative, which was backwards. The rule is going into `allod/memory` as a `cli-design.md` topic file, separate PR: a CLI is a human-facing interface, a plural flag takes multiple values, and when usage text and behavior disagree the default is to fix the behavior. Editing docs to match a defective implementation documents the bug, and a smaller diff is not a reason to ship a worse interface.
Author
Member

A bare -- is now a no-op rather than an error, matching the convention that -- ends option parsing rather than requiring an operand.

The earlier justification for erroring — that record -m "$m" -- "${files[@]}" with an empty array falls back to git add -u and can sweep another agent's edits — was answering the wrong question. record -m "$m" with no file flags at all already does exactly that, and it is the documented default. A bare -- naming nothing is the same situation, so refusing it added an inconsistency without closing the hazard.

The two cases are distinct and both now behave conventionally: an option missing its value is an error, so --files and -f with nothing following still fail with requires a value; a terminator with nothing after it names no files and leaves the git add -u default in force.

Tests are 185, up from 183. The empty-value assertions keep their "commits nothing" check, and a new case asserts a bare -- succeeds and stages both tracked files through the fallback. Sabotage-checked by restoring the error: the suite fails at not ok 135 - record accepts a bare -- with no path.

A bare `--` is now a no-op rather than an error, matching the convention that `--` ends option parsing rather than requiring an operand. The earlier justification for erroring — that `record -m "$m" -- "${files[@]}"` with an empty array falls back to `git add -u` and can sweep another agent's edits — was answering the wrong question. `record -m "$m"` with no file flags at all already does exactly that, and it is the documented default. A bare `--` naming nothing is the same situation, so refusing it added an inconsistency without closing the hazard. The two cases are distinct and both now behave conventionally: an option missing its value is an error, so `--files` and `-f` with nothing following still fail with `requires a value`; a terminator with nothing after it names no files and leaves the `git add -u` default in force. Tests are 185, up from 183. The empty-value assertions keep their "commits nothing" check, and a new case asserts a bare `--` succeeds and stages both tracked files through the fallback. Sabotage-checked by restoring the error: the suite fails at `not ok 135 - record accepts a bare -- with no path`.
vnprc approved these changes 2026-07-28 21:14:10 +01:00
vnprc merged commit cd40bb1dc2 into master 2026-07-28 21:14:18 +01:00
vnprc deleted branch agent/files-usage-repeatable 2026-07-28 21:14:18 +01:00
Sign in to join this conversation.
No description provided.