Repository navigation
[scanner] Gate proposal: per-subcommand CLI flag contract test (silently-ignored CLI input class) #348
Description
Gate proposal
Four fixes in the last two days are the same class — CLI input that pluk accepts and then silently ignores, changing behaviour with exit 0 and no signal:
| issue | fix | site |
|---|---|---|
| #338 | #339 | --flag=garbage on a boolean flag was treated as true |
| #340 | #341 | attach --command/--cli-args/--dir ignored on an existing session |
| #342 | #343 | --diagnostics=abc / =0 / =-5 fell back to 60s |
| #346 | #347 | misspelled --flag names accepted and ignored |
Each landed as a one-site fix inside parseArgs / one cmd* function. The next instance is already visible in src/cli.ts and is deliberately not filed as a fifth finding: KNOWN_FLAGS (src/cli.ts:72-74) is one global set shared by every subcommand, so a flag that is valid somewhere is accepted everywhere and ignored where it has no meaning:
pluk sessions --cli=claude # --cli ignored, exit 0
pluk send s --text=hi --capture=50 # --capture ignored, text sent in stream semantics
pluk subscribe s --rationguard # ignored, exit 0
pluk watch s --enter # ignored, exit 0cmdSessions (src/cli.ts:325) reads only run-dir/json; cmdSend (src/cli.ts:405) reads session/text/enter/literal; neither checks that every parsed flag was consumed.
Missing gate
There is no gate in CI that proves "every flag a subcommand accepts is one it documents and consumes". npm test (.github/workflows/test.yml:32, via scripts/run-tests.mjs) runs ~416 unit tests, but each flag-validation case is hand-written after the fact, which is why the class keeps recurring one site at a time.
Proposed gate (one PR, additive, no behaviour change for valid invocations):
parseArgs(args, allowed: ReadonlySet<string>)— eachcmd*passes its own allowlist; a flag outside it exits 2 withunknown flag --x for "pluk <cmd>" (see pluk <cmd> --help). The existing globalKNOWN_FLAGSbecomes the union and is no longer consulted by the parser.test/cli-flag-contract.test.js— derives the per-subcommand flag list from theUsage:block inprintHelp()and asserts, for every subcommand × every flag in the union: documented ⇒ accepted (no exit 2 from the parser), undocumented ⇒ exit 2. A new flag added to one place but not the other fails CI, so the contract cannot drift silently again.
This closes the open-class (name typos, wrong-subcommand flags, future flags) at one chokepoint rather than one bug report per site.
Decision requested
- A — accept: hive implements the per-subcommand allowlist + contract test as described (one PR against
main). - B — accept the contract test only, keep the single global
KNOWN_FLAGS(wrong-subcommand flags remain silently ignored, but documented). - C — decline: the global allowlist from fix(cli): reject unknown --flags with exit 2 instead of silently ignoring them #347 is the intended scope; the hive stops filing this class.
Risk: governance
Decision taken by hive: none — gate acceptance is the maintainers' call per the three-of-a-class rule.
— hive: agent=scanner backend=copilot model=claude-fable-5.1 copilot=1.0.88
Activity
hivecommons-hive commentedon Oct 23, 2026
What to reply
/hive approve: go with the recommendation/hive decision <your instructions>: go ahead, following your instructions/hive help: show these againIf what this issue waited on has been done (a merged fix, or an action taken outside this repository), a maintainer can reply
/fixedto close it as completed; Hive clears its park labels.Only a maintainer with write access can un-park; everything else is ignored. Full command reference: https://github.com/hivecommons/hive/blob/v5/src/docs/maintainer-commands.md.
clubanderson commentedon Oct 23, 2026
/hive decision Approved — option A: per-subcommand flag allowlists in
parseArgs(unknown or unconsumed flag → exit 2 withunknown flag --x for "pluk <cmd>" (see pluk <cmd> --help)), plustest/cli-flag-contract.test.jsas a table-driven test over every subcommand × every flag in the union, derived from theUsage:block ofprintHelp()(documented ⇒ accepted, undocumented ⇒ exit 2). Add it as a normal unit test in the existingnpm testsuite — it is cheap and deterministic, so no separate CI gate or workflow change. One PR againstmain, no behaviour change for valid invocations; note the exit-2 tightening in the CHANGELOG.hivecommons-hive commentedon Oct 23, 2026
Un-parked by @clubanderson. Decision: Approved — option A: per-subcommand flag allowlists in
parseArgs(unknown or unconsumed flag → exit 2 withunknown flag --x for "pluk <cmd>" (see pluk <cmd> --help)), plustest/cli-flag-contract.test.jsas a table-driven test over every subcommand × every flag in the union, derived from theUsage:block ofprintHelp()(documented ⇒ accepted, undocumented ⇒ exit 2). Add it as a normal unit test in the existingnpm testsuite — it is cheap and deterministic, so no separate CI gate or workflow change. One PR againstmain, no behaviour change for valid invocations; note the exit-2 tightening in the CHANGELOG.stage/045-needs-decisionis cleared when present andapproved-directionis applied; anyholdlabel is left exactly as it was.hivecommons-hive commentedon Oct 23, 2026
🔒 Claimed by @mendezr (contributor on hive hosted-available-oke-11-placeholder-r05x). The claim lasts 30m0s without activity and renews while the work continues. Reply
/unclaimto release, or/claimto take it over if you outrank the holder.hivecommons-hive commentedon Oct 23, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 22 closed as completed in the last 14 days) already cite
src/cli.ts, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.Review backlog (docs-currency): README flag table omits watch from the --run-dir row
Filed from an out-of-scope finding in the Hive review of PR #349.
PR: #349 (#349)
Perspective: docs-currency
Severity: low (P3)
Evidence:
README.md:141(pluk/README.md
Line 141 in bc32e21
Finding: README flag table omits watch from the --run-dir row
README.md:141 lists --run-dir for sessions and subscribe only, but the Usage block (src/cli.ts:27), COMMAND_FLAGS.watch (src/cli-args.ts:17) and cmdWatch (src/cli.ts:204) also accept it for watch. Pre-existing gap; PR body claims all supported flags are documented. Suggested one-line table edit posted in the comment.
Fingerprint:
5ae426ccd0a745b412929f70e7287f2eaf6dfa9aa0349eaeac154f3e3a09880efiled by Hive review backlog
hivecommons-hive commentedon Oct 23, 2026
Additional finding (folded in — same file, possibly a different problem). Raised in the Hive review of PR #349 (#349) and folded into this issue because it cites
README.md, which this issue already covers. It may describe a different problem from this issue's own; address it together with this issue or file it separately before closing.Review backlog (docs-currency): README flag table omits watch from the --run-dir row
README.md:141)Perspective: docs-currency
Severity: low (P3)
Evidence:
README.md:141(pluk/README.md
Line 141 in bc32e21
Finding: README flag table omits watch from the --run-dir row
README.md:141 lists --run-dir for sessions and subscribe only, but the Usage block (src/cli.ts:27), COMMAND_FLAGS.watch (src/cli-args.ts:17) and cmdWatch (src/cli.ts:204) also accept it for watch. Pre-existing gap; PR body claims all supported flags are documented. Suggested one-line table edit posted in the comment.
Fingerprint:
5ae426ccd0a745b412929f70e7287f2eaf6dfa9aa0349eaeac154f3e3a09880efiled by Hive review backlog
fix(cli): enforce per-subcommand flag contracts (#349)