go-cli-advertised-subcommand-unregistered
The bug: main.go's top-level dispatcher switch handled help, --help, --version, and ping, but the help text advertised a version subcommand that no case registered — so helios version fell into default: and printed Unknown command: version (exit 1). The version format line was also duplicated inline in --version, risking drift.
Fix 1 — extract the shared versionLine() formatter (main.go):
const version = "0.1.0"
// versionLine returns the canonical version string. Both the --version
// flag path and the version subcommand path print exactly this line, so
// the two paths can never drift apart. It is the testable seam: main()
// exits via os.Exit on failure, so this formatter is what unit tests pin.
func versionLine() string {
return fmt.Sprintf("helios version %s", version)
}
Fix 2 — register the version case and route both paths through the helper:
switch args[0] {
case "help", "-h", "--help":
fmt.Print(usage)
case "--version":
fmt.Println(versionLine())
case "version": // ← added case
fmt.Println(versionLine())
case "ping":
fmt.Println("pong")
default:
fmt.Printf("Unknown command: %s\n", args[0])
fmt.Print(usage)
os.Exit(1)
}
Fix 3 — table-test the seam (version_test.go), since the dispatcher exits via os.Exit on the failure path:
func TestVersionLine(t *testing.T) {
const want = "helios version 0.1.0"
tests := []struct {
name string
check func(got string) bool
}{
{"is non-empty", func(got string) bool { return got != "" }},
{"starts with the binary name", func(got string) bool { return strings.HasPrefix(got, "helios ") }},
{"embeds the version number", func(got string) bool { return strings.Contains(got, version) }},
{"matches the exact canonical line", func(got string) bool { return got == want }},
{"has no trailing newline (caller adds it)", func(got string) bool { return !strings.HasSuffix(got, "\n") }},
{"has no leading whitespace", func(got string) bool { return !strings.HasPrefix(got, " ") }},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := versionLine(); !tt.check(got) {
t.Errorf("versionLine() = %q (want %q)", got, want)
}
})
}
}
Reproduced the bug with a **fresh** build of the original source, then verified the fix on a fresh binary. Git history preserves both states: `a07b361` (bug) → `303fd18` (fix). **Before fix (fresh build):** ``` $ ./helios --help → advertises "version Print the helios version" $ ./helios version → Unknown command: version (exit=1) ``` **Stale-artifact trap confirmed:** after editing the source but *before* rebuilding, `./helios version` still printed `Unknown command` — the gitignored binary at the repo root was running old code. `git check-ignore helios` confirms `/helios` is ignored, so the binary must always be rebuilt (`go build -o helios .`) before verifying. **After fix (fresh `go build -o helios .`), full matrix:** | Command | Output | Exit | |---|---|---| | `--help` / `help` / `-h` | usage text | 0 | | `--version` | `helios version 0.1.0` | 0 | | `version` | `helios version 0.1.0` *(identical — shared helper)* | 0 | | `ping` | `pong` | 0 | | `bogus` | `Unknown command: bogus` + usage | 1 | | *(no args)* | usage text | 0 | Edge cases covered: no-args (help, exit 0), unknown command (usage + exit 1), and byte-exact agreement between `--version` and `version` output. `gofmt -l` clean, `go vet ./...` clean, `go test -v ./...` → `PASS` (6/6 table subtests, `ok helios 0.002s`).
{"model": "deepseek-v4-flash", "problem_class": "go-cli-advertised-subcommand-unregistered", "result": "passed", "tests": 6}