feat(cli): publish clean, grouped help instead of developer docstrings (#389) - #501
Merged
Conversation
#389) Typer published each command's raw `__doc__` because no command set `help=`, so an end user read "Wires the pure `bundle.provenance.resolve_backfill_raises` sweep core (design D4/D5) into Typer's confirm-gate", plus `decision #717`, `MVP-3 gap #8 S2a`, `Slice 1` and `ADR-0003`. There was no need to choose between traceability and a clean surface: `help=` decouples them. All 26 commands now publish a user-facing line while their docstrings keep every reference maintainers rely on. This matters past `--help` too -- MCP tool descriptions are usually derived from the same source, and text that does not help a person will not help an agent. The 26 commands were also listed flat in declaration order, which put `purge` -- irreversible and rare -- fourth, while `query`, the value moment, sat near the bottom. They are now grouped into five panels by what the reader is trying to do: get started, explore, curate, maintain, remove. Grouping alone was not enough. Rich prints a panel when it first meets a command belonging to it, so declaration order still decided panel order and "Remove" landed SECOND -- making the irreversible verbs MORE prominent than the flat list did. `PANEL_ORDER` plus a stable sort of the registry makes the reading order explicit rather than a side effect of where a function happens to sit in this file. Four tests pin the result: no published command help carries traceability vocabulary, the five panels exist, they print in reading order, and every command declares a known panel. Refs #389; its remaining bullets (vocabulary mismatch, the `init` embedding warning's placement, and two `doctor` items) stay open. Reviewed under lineage `review-6e884bb4642ac6fb`, high risk, canonical 4R, approved with receipt, zero blockers.
… legible (#389) Folds in the five findings from this branch's own four-lens review. Two were accuracy defects in text this change itself published, which is the sweep's real hazard: a clean line that is WRONG is worse than the jargon it replaced. `adjudicate` published "Decide which candidate duplicates are really the same concept, with the model proposing and you confirming", which reads as though invoking it performs merges. Its own docstring says the plain invocation is read-only and never writes, merges or decides -- that needs a separate apply flag. It now says so. `suggest-volatility` omitted the advisory, writes-nothing reassurance its three sibling read-only verbs all state, which is the same inconsistency #389 complains about elsewhere. A published option help string on `forget --scope` still carried the internal token "S2a". The jargon test did not catch it because it matched only fixed substrings; it now also matches patterns for abbreviated slice tokens, paired design references and numbered gap references. Mutation-verified: restoring the token fails the test with `{'forget': ['S2a']}`, and the substring-only version passed that same mutation. The panel sort's bare tuple lookup raised at import with a message naming neither the command nor the bad value -- taking the whole CLI down, help included, for one typo. `_panel_rank` keeps the hard failure, which is right, and adds the command name, the offending value and the allowed set. Failing mutely was the part that was wrong. Also corrects a test docstring that claimed it prevented that import-time failure. It cannot: the sort runs when the module loads, long before pytest collects anything. Reviewed under lineage `review-f3a75ff7d21f93f8`, high risk, canonical 4R, approved with receipt, zero blockers.
…y uses (#389) The pattern added one commit ago required a word boundary immediately after its digit run, so it matched a bare "Slice 1" and missed "Slice 2a" and "Slice 2b-ii" -- there is no boundary between a digit and the letter after it, and the lettered forms are the ones the docstrings here mostly use. A guard for jargon that skips the dominant shape of that jargon is not a guard. Measured before and after rather than reasoned about: the three real slice forms now match, and "Sliced bread" and "sliced" still do not. Reviewed under lineage `review-5c4e2c90128c01d4`, medium risk, one focus lens, approved with receipt, zero findings.
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.
Refs #389 — this carries its help-surface bullets (1 and 2). The remaining four (the
reconcile/listvocabulary mismatch, theinitembedding-warning placement, and the twodoctoritems) stay open; #389 explicitly says to split any bullet that grows, and this one did.What a user actually read before
Typer publishes each command's raw
__doc__unless the command setshelp=. No command did. So--helpshowed things like:along with
decision #717,MVP-3 gap #8 S2a,Slice 1andADR-0003.There was never a choice to make between traceability and a clean surface —
help=decouples them. All 26 commands now publish a user-facing line while their docstrings keep every reference maintainers rely on. This matters past--help: MCP tool descriptions are usually derived from the same source, and text that does not help a person will not help an agent.Grouping, and the part grouping alone did not fix
The 26 commands were listed flat in declaration order, which put
purge— irreversible and rare — fourth, whilequery, the value moment, sat near the bottom. They are now grouped into five panels by what the reader is trying to do: get started, explore, curate, maintain, remove. The rule is written down next to the app so the next contributor applies it rather than matching the nearest-looking neighbour.Grouping by itself made things worse in one respect, which only showed up on rendering the real output: Rich prints a panel when it first meets a command belonging to it, so declaration order still decided panel order and Remove landed second — the irreversible verbs more prominent than the flat list had them.
PANEL_ORDERplus a stable sort of the registry makes reading order explicit instead of a side effect of where a function sits in the file.Three review rounds, each catching what the last missed
This branch went through three full review cycles. Recording what each found, because the pattern is the point:
Round 1 shipped clean help but left the panel ordering above.
Round 2 found two published lines that were clean but wrong — the real hazard of a sweep like this.
adjudicatepublished "Decide which candidate duplicates are really the same concept, with the model proposing and you confirming", which reads as though invoking it performs merges; its own docstring says the plain invocation is read-only and writing needs a separate flag.suggest-volatilityomitted the writes-nothing reassurance its three sibling read-only verbs all state. It also caught a published option help string onforget --scopestill carrying the internal tokenS2a, which the jargon test had passed over because it matched only fixed substrings.Round 3 fixed an anchor in one of the very patterns round 2 added:
\bSlice \d+\bmatched a bareSlice 1but missedSlice 2aandSlice 2b-ii, because there is no word boundary between a digit and the letter after it — and the lettered forms are the ones this codebase mostly uses.Separately, the sweep's first draft dropped a bounded-scope honesty statement from
set-sensitivity's published help that a pre-existing test requires to stay published. The suite caught it, which is exactly what that test is for.Verification
uv run pytest -q→ 4025 passed, 1 skipped.uv run mypy .→ Success, 179 files.ruff check/ruff formatclean and convergent.S2ato the published option help fails it with{'forget': ['S2a']}; the substring-only version passed that same mutation, which is why it was replaced.Native review
Three lineages, all approved with receipts, all zero blockers:
review-6e884bb4642ac6fb(high, 4R),review-f3a75ff7d21f93f8(high, 4R),review-5c4e2c90128c01d4(medium, one lens, zero findings).pre-prdenies this PR, same structural reason as #498, #499 and #500: it measures the whole branch againstorigin/mainwhile each receipt binds its own increment, so no single receipt covers the union.receipt-binding / candidate-or-paths-mismatch, actionexplicit-maintainer-action. Every changed line was reviewed and approved.