Skip to content

fix(audit): read typer's and rich-click's required options - #183

Open
brettdavies wants to merge 2 commits into
fix/help-flags-quiet-probe-and-dashless-configfrom
fix/help-flags-typer-required-rows
Open

brettdavies wants to merge 2 commits into
fix/help-flags-quiet-probe-and-dashless-configfrom
fix/help-flags-typer-required-rows

Conversation

@brettdavies

@brettdavies brettdavies commented Oct 9, 2026 •

Copy link
Copy Markdown
Owner

Summary

From the code review of the stack. typer and rich-click mark a required option with * in the first cell of its box-table row:

╭─ Options ────────────────────────────────────────────────────────────────────╮
│    --output            -o       <str>  write output here                     │
│ *  --target            -t       <str>  where to deploy [required]            │
│    --help                              Show this message and exit.           │
╰──────────────────────────────────────────────────────────────────────────────╯

A row has to lead with a flag name to be a definition, so the --target row declared nothing while the rows around it were read. A tool's required flags were the ones anc could not see. Neither probe declared a required option, so no fixture held such a row and the gap did not show.

Two commits:

  1. The captures. Both probes gain a required -t, --target, and the snapshots record what the parser read from the new captures before the fix: every row but that one.
  2. The fix. The text cleanup that turns box edges into gaps also blanks a * that leads a box-table row and stands in a cell of its own. The row then leads with its name. A * outside a box table, or one that is part of a word (*.md), is left alone.

The probe image was rebuilt for the new probe sources. Its Dockerfile now installs the Thor gem from a file fetched by checksum, as it already does for the picocli jar: Thor was the one dependency of the image installed without an integrity check. The other 15 probe captures come out of the rebuilt image byte for byte, and index.json records the new image ID.

Changelog

Fixed

  • Fix required options going unread in typer and rich-click help, where the row is marked * in its first cell.

Documentation

  • The README's section on how behavioral audits read --help notes that typer's * marker is not part of a name.

Type of Change

  • fix: Bug fix (non-breaking change which fixes an issue)

Related Issues/Stories

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing completed
  • All tests passing

Test Summary:

  • Unit tests: the typer row above joins the layout table in classify.rs, the typer and rich-click fixtures are asserted to declare --target, -t, and normalize.rs tests the marker in a box row, a * bullet outside a box, and *.md inside one.
  • 1326 passing across the suite. Self-audit: cargo test --test dogfood passes.
  • Snapshots: the two probe snapshots. In the first commit they change only because the captures did (the table is wider, so line numbers shift and one description wraps differently), with no --target row. In the second they gain --target, -t | where to deploy [required].
  • Captures: capture.sh probes against the rebuilt image. Of 17 captures, the typer and rich-click ones differ from the committed fixtures and 15 are identical.

Negatives observed failing. The new tests against the captures commit, before the fix:

---- runner::help_probe::flags::classify::tests::a_definition_is_found_wherever_a_layout_prints_one stdout ----
[
    "typer 0.27.2: a required option, marked `*` in the first cell of its row: read [[\"--output\", \"-o\"], [\"--help\"]], declares [[\"--output\", \"-o\"], [\"--target\", \"-t\"], [\"--help\"]]",
]
---- runner::help_probe::flags::normalize::tests::a_required_marker_in_a_box_table_becomes_a_space stdout ----
assertion `left == right` failed
  left: "   *  --target  -t  <str>  where to deploy [required]   "
 right: "      --target  -t  <str>  where to deploy [required]   "
---- runner::help_probe::flags::classify::tests::column_0_and_box_table_fixtures_yield_their_definitions stdout ----
assertion failed: typer.contains(&vec!["--target".to_string(), "-t".to_string()])

Expected moves. Written before the corpus run.

None. No help text in the full registry capture set (910 files) has a box-table row that leads with a * cell, and rendering the set through the base and head parsers gives identical definitions. Replaying it through the base and head builds moves no row.

Corpus before/after. Run after the table above was written. Base 7e3ca56dfddd, head bfebab609d17. Image sha256:05db16cf226cd14a93a2682aea41b72d3e6b4d240cadba006f2881d3ffa996b3, network bridge. 98 tools selected, 95 scored under both builds, 1 rerun three times (mods).

Moved rows (0)

None.

Derived fields moved (0)

None.

No row and no derived field moved, as expected. mods p3-should-about-long-about, the one row on the A/A noise list, is reported as not moved: both builds returned the same result for it in at least one run. No row is unstable, no harness bug is flagged, and no tool failed to score under one build only. cursor, nvidia-smi and xai-grok-build are absent from the image and ran under neither build.

Files Modified

Modified:

  • src/runner/help_probe/flags/normalize.rs: the marker rule.
  • src/runner/help_probe/flags/classify.rs: tests.
  • tests/fixtures/help/probes/python/py_typer.py, py_richclick.py: a required option.
  • tests/fixtures/help/probes/Dockerfile: the Thor gem by checksum.
  • tests/fixtures/help/probe-typer__--help.txt, probe-rich-click__--help.txt, index.json
  • src/runner/help_probe/snapshots/probe-typer__--help.snap, probe-rich-click__--help.snap
  • README.md

Created:

  • None.

Renamed:

  • None.

Deleted:

  • None.

Breaking Changes

  • No breaking changes

Deployment Notes

  • No special deployment steps required

Checklist

  • Code follows project conventions and style guidelines
  • Commit messages follow Conventional Commits
  • Self-review of code completed
  • Tests added/updated and passing
  • No new warnings or errors introduced
  • Changes are backward compatible (or breaking changes documented)

typer and rich-click mark a required option with `*` in the first cell of its row. Neither probe declared one, so no fixture held that row.

Both probes gain a required `-t, --target`. The snapshots record what the parser reads from the new captures today: every row but that one.

The probe image is rebuilt for the new sources, and its Dockerfile now installs the Thor gem from a file fetched by checksum, as it already does for the picocli jar. Thor was the one dependency of the image installed without an integrity check. The other 15 probe captures come out of the rebuilt image byte for byte.
typer and rich-click mark a required option with `*` in the first cell of its box-table row:

    │ *  --target            -t       <str>  where to deploy [required]            │

A row has to lead with a flag name to be a definition, so that row declared nothing while the rows around it were read. A tool's required flags were the ones `anc` could not see.

The text cleanup that turns box edges into gaps now blanks a `*` that leads a box-table row and stands in a cell of its own. The row then leads with its name. A `*` outside a box table, or one that is part of a word (`*.md`), is left alone.
@brettdavies
brettdavies force-pushed the fix/help-flags-typer-required-rows branch from bb82405 to bfebab6 Compare October 9, 2026 17:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant