refactor(cfcli): replace the bare exit-code ints with a named type - #17
Merged
Conversation
cfcli carried 2 comment lines across 3764 lines of Go, so every fact not expressed by a type had to be re-derived from the code on each reading. This adds doc comments to the declarations whose contract is not evident from the signature, and inline comments where a line is surprising. The facts recovered here are the ones that cost the most to re-derive: nil-tolerance of appDependencies.getenv and .now, the same-filesystem constraint replaceFile inherits from os.Rename, the four exit codes behind runWithDependencies' bare int return, and the format coupling between encryptDictionaryForTest and decryptDictionary. Comments only: the packages parse to identical ASTs with comments dropped, and gofmt, go vet, and go test are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
runWithDependencies returned an untyped int, so each of the 21 return sites spelled its exit code as a literal and the only description of what those literals meant was a four-row table in a doc comment. A table in a comment drifts; a constant does not. exitStatus and its four values move that vocabulary into the code, where each value carries the condition it reports and the compiler keeps the name next to the number. run, runWithDependencies, and runExcludeCommand return the type instead of int, main converts once at os.Exit, and the tests compare against the names rather than 0 through 3. Behavior is unchanged: the same four numbers reach the process exit in the same conditions. README.md's exit-0 line gains the exclude command, which it had always omitted. 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.
Why
runWithDependenciesreturned an untypedint. All 21 return sites spelled their exit code as a bare literal, and the only place that said what those literals meant was a four-row table in a doc comment:That table is exactly the kind of comment #16 argues against writing when there is an alternative: it restates values the code already holds, nothing checks it, and it goes stale the moment a fifth code appears or a fourth changes meaning. The honest answer to comment drift is to encode what the type system can hold and comment only the remainder — so this removes the table rather than maintaining it.
The tests made the same point from the other side.
if exitCode != 3says nothing about what 3 is, and a reader debugging a red build had to go find the table to learn it.What
exitStatusand its four values, in a newcfcli/exit_status.go. Each constant carries the condition it reports, so the description now sits next to the number and the compiler keeps them together.run,runWithDependencies, andrunExcludeCommandreturnexitStatusinstead ofint. The signature now says what the value is, which was the complaintintinvited.mainconverts once, atos.Exit.want 1/want 0now format the constant instead, so a renumbering cannot leave a lying message behind.README.md's exit-0line gains theexcludecommand, which it had always omitted — the constant's comment and the README now describe the same condition.How to verify
Behavior is unchanged: the same four numbers reach the process exit under the same conditions, and no test expectation was relaxed to make this pass.
The exit codes are a published interface — scripts branch on them — so the check that matters is that the numeric values did not move. They are pinned twice: by the explicit
= 0…= 3in the const block rather thaniota, and by the tests, which still assert the same outcomes through the new names.What this deliberately does not do
A distinct type does not make the set closed —
return 7still compiles, because an untyped constant converts. Go offers no way to prevent that, and pretending otherwise in a comment would be the same mistake this PR removes. The win here is naming and locality, not enforcement.🤖 Generated with Claude Code