Repository navigation
fix(audit): detect an output flag from definitions and probe it as spelled - #178
Open
brettdavies wants to merge 2 commits into
Open
brettdavies wants to merge 2 commits into
brettdavies wants to merge 2 commits into
Conversation
…elled `p2-json-output` decided whether a tool has an output flag by looking for the characters `--output` or `--format` anywhere in its lowercased `--help`, at the top level and then in each subcommand. A longer flag (`--output-format`, `--output-dir`, `--format-version`), a usage line and a sentence all counted, and the probe that followed always passed `--output json` or `--format json`, whatever the help printed. A Go `flag` help that declares `-format` was not detected at all. Detection now asks the definition query, per help, and the safe probes pass each flag as the help spells it: `--help -format json` for a help that declares `-format` and no double-dash name. A longer flag that starts with `--output` or `--format` is a different name and triggers no probe. The evidence names what was found or searched: - skip: `` `--output` is declared in `export --help`, but no safe probe printed JSON (--help and --version override output flags in most CLIs) `` - opt_out: `no option definition in --help declares --output or --format; usage lines are not read. The tool is scored as shipping no structured output, ...`, with the count of subcommand helps read when there were any, and the dash-rule note when a help declares `-format` beside double-dash names. The unverified outcome is a variant of its own, so the declared `[p2] json_probe` takes over from it without comparing evidence strings. `--help` that times out or crashes still leaves the row a skip.
The opt-out evidence closed with `The tool is scored as shipping no structured output`. A tool whose help declares `--output-format` reads that sentence beside its own JSON mode, and the sentence is then false on its face. The evidence now says which flags the requirement accepts and stops there: `no option definition in --help declares --output or --format, the flags this requirement accepts; usage lines are not read.`
brettdavies
added this pull request to stack #166
October 8, 2026 22:34
This was referenced Oct 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
p2-json-outputdecided whether a tool has an output flag by looking for the characters--outputor--formatanywhere in its lowercased--help, at the top level and then in each subcommand. Then it probed with--output jsonor--format json, whatever the help printed.--output-format, make's--output-sync, cosign's--output-file, codex's--output-schema, biome's--formatter. The probe then passed--output jsonto a tool that has no--output.flaghelp that declares-formatwas not detected, and would have been probed with--formatif it had been.Detection now asks the definition query, per help, and each safe probe passes the flag as the help spells it:
--help -format jsonfor a help that declares-formatand no double-dash name. A longer flag that starts with--outputor--formatis a different name and triggers no probe.The evidence names what was found or searched:
`--output` is declared in `export --help`, but no safe probe printed JSON (--help and --version override output flags in most CLIs)no option definition in --help declares --output or --format, the flags this requirement accepts; usage lines are not read.It gives the number of subcommand helps read when there were any, and adds the dash-rule note when a help declares-formatbeside double-dash names. It no longer says the tooldoes not ship structured output: a tool whose help declares--output-formatwould read that beside its own JSON mode.The flag list is unchanged (
--output,--format), and so are the safe probes (--helpand--versiononly) and the[p2] json_probehand-off. A--helpthat times out or crashes still leaves the row a skip.For the reviewer: this PR moves scores. Nine tools were a skip only because a longer flag was mistaken for
--outputor--format. With no such flag declared they are an opt_out, which counts in the score at zero credit. Five of the nine (claude-code, dust, gemini-cli, ruff, yq) do select a format, through--output-format. Whether--output-formatshould satisfyp2-must-output-flagis a question about the requirement's flag list, which this series leaves as it is.Changelog
Fixed
p2-must-output-flagtreating a longer flag such as--output-format,--output-fileor--formatteras--outputor--format, and then probing with a flag the tool does not have. An output flag counts when an option definition declares--outputor--format.p2-must-output-flagmissing Goflaghelp that declares-formator-outputwith one dash. The safe probes now pass the flag as the help spells it.Changed
p2-must-output-flagskip evidence names the flag and the help that declares it, and opt_out evidence names what was searched.p2-must-schema-printquotes the same text when it follows that row.Documentation
json_probesection says the output flag is read from option definitions, is passed as the help spells it, and that a longer flag such as--output-formatis a different name.Type of Change
fix: Bug fix (non-breaking change which fixes an issue)Related Issues/Stories
docs/plans/2026-10-06-0034-fix-help-flag-names-across-frameworks-plan.md(unit U10, thejson_output.rsPR)p1-non-interactive), fix(audit): pass p1-flag-existence only when the help declares a gate flag #172, fix(audit): pass p7-quiet only when the help declares --quiet or -q #171, fix(audit): match a declared confirm flag against the definitions the help declares #170, fix(audit): find flag definitions at column 0, in box tables, and behind brackets #169, fix(audit): stop reading wrapped description lines as flag definitions #168, fix(audit): read names from a second column and descriptions after a marker #167, fix(audit): read every flag name a help declares whole #165, refactor(audit): look flags up through one model and one query #164, test(audit): pin what the flag parser reads from a capture of every help layout #163, feat(docker/score): compare two anc builds over the registry in one pinned image agentnative-site#455 (the corpus harness)Testing
Test Summary:
json_output.rs. A table of eight helps pairs each with the flags it declares as the probe must spell them. A stand-in that prints JSON only for--help -format jsonpasses. A stand-in that would print JSON for--output json, and declares only--output-format, is an opt_out and is not probed. The skip and opt_out evidence is asserted whole, at the top level and for a subcommand, with the dash-rule note.Usage: test [--output FORMAT]). They now declare it on a definition line, and two assert the new evidence text.cargo test --test dogfoodpasses, andancaudited with this build keeps its ownp2-must-output-flagpass. It now gets there throughaudit --help --output json: its top-level help mentions--outputonly in prose.Negatives observed failing. The new tests, run with
declared_output_flagsput back to the substring match and everything else at this PR's head:The third case is the one to read twice: with the substring match, a tool that declares only
--output-formatpasses, because the probe sends it--output json.The two evidence tests assert text this PR introduces. Before the rewording they failed against the old strings,
--output/--format flag detected but could not validate JSON via safe probes (--help/--version override output flags in most CLIs)andno --output/--format flag detected in any subcommand — tool does not ship structured output.Expected moves. Written before the corpus run. 184 rows: every
p2-must-output-flagrow that is not a pass, and thep2-must-schema-printrow that follows each one.p2-must-output-flagp2-json-outputp2-must-output-flagp2-json-outputp2-must-output-flagp2-json-outputp2-must-output-flagp2-json-outputp2-must-schema-printp2-schema-printp2-must-schema-printp2-schema-printp2-must-schema-printp2-schema-printp2-must-schema-printp2-schema-printWhy each status moves:
--output-format--outputor--format, at the top level or in any subcommand--output-format--output-format--output-format,--output-json--output-formatand--output-fileoncheck--output-schemaand--output-last-messageonexec--output-file--output-sync--formatteronrage-format stringhas one dash-format, in a help with no double-dash name; probed as-format json, which prints no JSON-format=FORMATongraph; probed asgraph --help -format json, which prints no JSONThe three passes hold: anc, bird and trivy are probed with a flag their help declares, and their rows and the rows that follow them do not move.
Derived, computed from the base scorecards. An opt_out joins the score's denominator at zero credit, and a skip leaves it:
badge.score_pctbadge.eligibleFor the nine,
summary.skipfalls by two, andsummary.opt_outandsummary.n_arise by one each. For actionlint and terraform it is the reverse. Noaudiencemoves: the label counts warns among its four signal rows, and nop2-json-outputrow is a warn before or after.How the prediction was made:
choosetolog, where--formatis declared), uv (versiontoexport), xh (--outputalone, without--format-options) and anc.Corpus before/after. Run after the tables above were written. Base
58497bf5f381, head4697a3c24879. Imagesha256:05db16cf226cd14a93a2682aea41b72d3e6b4d240cadba006f2881d3ffa996b3, networkbridge. 98 tools selected, 95 scored under both builds, 92 rerun three times.Moved rows (184), by row and status
p2-must-output-flagp2-json-outputp2-must-output-flagp2-json-outputp2-must-output-flagp2-json-outputp2-must-output-flagp2-json-outputp2-must-schema-printp2-schema-printp2-must-schema-printp2-schema-printp2-must-schema-printp2-schema-printp2-must-schema-printp2-schema-printDerived fields moved (53), the 33
summary.*counts left out of the tablebadge.score_pctbandbadge.score_pctbadge.eligiblebandbadge.score_pctbadge.eligiblebandbadge.score_pctbandbadge.score_pctbadge.score_pctbadge.score_pctbadge.score_pctbandbadge.score_pctbandbadge.score_pctbadge.score_pctbandThe 184 moved rows are the 184 expected. Compared row for row against the replay, each has the same status and the same evidence text before and after, subcommand counts included. The derived moves equal the predictions: the 20 fields above, and three
summarycounts for each of the eleven tools. Noaudiencemoved. Every moved row returned the same result in all four runs of each build. No row is unstable, no harness bug is flagged, and no tool failed to score under one build only.modsp3-should-about-long-about, the one row on the A/A noise list, did not move (base runs pass, warn, pass, pass; head runs pass, pass, pass, pass).cursor,nvidia-smiandxai-grok-buildare absent from the image and ran under neither build.Files Modified
Modified:
src/audits/behavioral/json_output.rs:declared_output_flagsasks the definition query and returns the declared spellings; the probes take them; the unverified outcome is its own variant; evidence reworded.README.md: thejson_probeparagraph.Created:
Renamed:
Deleted:
Breaking Changes
Eleven registry tools change status on
p2-must-output-flag, and two of them (biome, claude-code) drop below the badge floor. Every other non-pass row carries new evidence text. The scorecard schema and JSON shape are unchanged.Deployment Notes
Checklist