Name commands by what you type, in examples as well as usage lines - #179
Merged
Conversation
The usage line is generated from ShortName and so cannot be wrong; an @example is prose copied verbatim out of a shell comment, and prose goes stale at every rename. Nothing asserted that the thing an example tells you to type resolves at all. The test extracts the token after "wp-ops" — skipping leading VAR=value environment prefixes, which screenshot-patterns' example carries — and requires it to equal the entry's ShortName. Working post-Load reads the real ShortName without persisting it, which catalog.go:78-81 rules out. Red at this commit: 47 lines across 42 entries. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sweeps the 47 example lines the new test flagged, across 42 scripts, plus the regenerated catalog. Each rewrites only the command token; arguments, flags and the environment-variable prefix on screenshot-patterns' example are untouched. Most were merely long — the path form still resolves, so they worked while teaching the wrong name three rows under a usage line that taught the right one. wp-cli-pattern-validate's was genuinely broken: it still named bedrock/wp-cli-config/, a category 5.0.0 retired, so the line it told you to type errored out. One change applied 47 times, kept as one commit despite the atomic-commit rule. Turns TestExamplesNameTheCommand green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The example sweep only reached @example annotations. These four Go sites format e.Key straight into user-facing text, so they kept naming the internal key after 5.1.0 taught the usage line not to. serverside.go:171 access-log hint (macOS path) ansible.go:231 missing-argument error ansible.go:287 unannotated-playbook fallback All three now read through CommandName(). Left alone: dispatch.go's ambiguity message and search.go's listing, where the full key is the point. serverside.go's backup hint and the two shell scripts that echo the same advice were stale twice over — path form *and* `-e site=` , which the playbooks stopped accepting when they moved to positional arguments. They now print `wp-ops database-pull example.com production`, which is what the playbook's own @example says. serverside_test.go pinned the old strings, so its expectations move with them. check-deny-ips.sh:67 is not a hint but a real invocation piping into check-ips; it was the one place a rename would have broken a code path rather than a comment. Also past-tenses trellis-cli-comparison.md §5 rough edge #1, which asserted in the present tense something its own status header says 5.1.0 fixed, and the two trellis/security/README.md invocations. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Also lands the analysis this release implements, with its status header updated: the document was written against 3a53555 and its prose is kept as written, so it reads as a record of the pre-fix state. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
wp-ops scanner-targeted --helpprinted a correct usage line and then, threerows below it,
wp-ops wp-cli/security/scanner-targeted.5.1.0 fixed the usage line for every command and every executor — but it fixed
it by changing the code that generates it. Example lines are not generated;
they are prose copied verbatim out of each script's
@exampleannotation, sothey were never touched. 42 of the 71 commands that carry examples printed
at least one path-style invocation, 47 lines in total, in both render paths
(
exec.DetailBodyandexec.writeManifestHelpBodyeach print the stringunchanged).
The path forms still resolved, so nothing was broken for anyone who pasted one.
They were wrong in that they taught the long form as the command's name.
One was genuinely broken:
wp-cli-pattern-validate's example still namedbedrock/wp-cli-config/, a category 5.0.0 retired, so the line it told you totype answered
Unknown command or category. Same class of bug 5.1.1 fixed inREADME.md, missed then because nobody thought to grep the scripts for theretired category name.
Root cause
The catalog validates its own structure but not its prose.
ShortNameisguaranteed to resolve,
TestLoad_ShortNameUniqueBasenamespins that, and CIregenerates the catalog and diffs it. Every one of those checks is about the
key. The
Examplesfield travelled from a shell comment onto the user'sscreen without a single assertion that the thing it told them to type exists.
Approach
A sweep alone would fix today's output and guard nothing — the next rename
reintroduces it exactly as 5.1.1's would have, had its two
@examplelines nothappened to be the subject of that PR. Normalizing in the generator was
rejected: it would bake
ShortNameintocatalog.json, whichcatalog.go:78-81deliberately refuses to do, and it would leave the sourcefiles lying, which matters because a script header is read directly at least as
often as through
--help.So: validate in the
catalogpackage, then sweep once. The test workspost-
Load, reading the realShortNamewithout persisting it.Commits
The test, red. Extracts the token after
wp-ops— skippingVAR=valueenvironment prefixes, which
screenshot-patterns' example carries — andrequires it to equal the entry's
ShortName. It reproduced the 42/47 countindependently, so it is both the audit and the guard, with no window where
the guard exists but the sweep has not landed.
The 47-line sweep, across 42 scripts, plus the regenerated catalog.
Command token only; arguments, flags and environment prefixes untouched.
One change applied 47 times, kept as one commit despite the atomic-commit
rule.
The four Go sites no sweep of the scripts could reach — the macOS
access-log hint, the missing-argument error, the unannotated-playbook
fallback — now read through
CommandName(). The ambiguity message andsearchlisting keep printing full keys, where the path is the point.The backup hints in
serverside.go,db-backup.shandsite-backup.shwere stale twice over: path form and the
-e site=syntax the playbooksstopped accepting when they moved to positional arguments. They now print
wp-ops database-pull example.com production.serverside_test.gopinnedthe old strings, so its expectations move with them.
check-deny-ips.sh:67was not a hint but a real invocation piping intocheck-ips— the one place a rename would have broken a code path ratherthan a comment.
Plus
docs/trellis-cli-comparison.md§5, which asserted in the present tensesomething its own status header says 5.1.0 fixed, and two
trellis/security/README.mdinvocations. Documents that quote the path formas the problem being analysed were left alone.
Verification
go test ./...passes. Both symptoms confirmed against the built binary:go/internal/manifest/testdata/keeps its path-style examples — the parser mustgo on accepting the form — and was kept out of the sweep.
Not in scope
searchprints full keys andlistprints bare basenames, so the same commandappears under two names depending on how you found it. Neither is wrong on its
own terms; it is a UX call rather than a correctness one, and it stays open in
docs/example-line-drift.md§7.