Skip to content

chore(api): ten functions in handler_purchases.go sit at the gocyclo ceiling, so any one-line change breaks pre-commit #163

Description

@cristim

Eight functions in internal/api/handler_purchases.go sit at cyclomatic complexity exactly 10 on origin/main, which is the pre-commit gate's ceiling (gocyclo -over 10). Measured against git show origin/main:internal/api/handler_purchases.go:

10  (*Handler).validateExecutePurchaseRequest
10  (*Handler).sendPurchaseApprovalEmail
10  (*Handler).revokeViaEmailToken
10  (*Handler).loadAndValidateRetryRequest
10  (*Handler).cancelPurchaseViaSession
10  (*Handler).cancelPurchase
10  (*Handler).authorizeSessionExecuteDirect
10  (*Handler).authorizePlannedPurchaseCancel

Each passes today. Each breaks the pre-commit hook the moment anyone adds a single if, case, && or || to it — including a change that is otherwise a one-line bug fix. Whoever touches one of these next inherits a refactor they did not sign up for, in a file that carries approve, cancel, execute and retry authorization.

Note the class: adding a case to a dispatch switch adds 1, so a benign-looking addition breaches the gate.

Why this is filed rather than fixed opportunistically

Raised as a nit during LeanerCloud/cloud-commitments-cli#1713 and correctly declined there. That PR only renamed a callee and added no complexity, and loadAndValidateRetryRequest's own comment records that its gates stay "in the order documented on retryPurchase so the security boundary is the same" — order is the security boundary, so extracting a subset of gates is a change that wants its own review rather than being buried in a money-path diff.

Fixing one function in isolation also leaves the class untouched, which is the actual problem.

Suggested approach

Treat it as one deliberate hygiene pass over the file, not eight drive-bys:

  • For the authorization functions (authorizeSessionExecuteDirect, authorizePlannedPurchaseCancel, cancelPurchaseViaSession, revokeViaEmailToken, loadAndValidateRetryRequest), preserve gate ordering exactly and say so in each extracted helper's doc. Any reordering is a security change and must be called out explicitly, not absorbed into a refactor.
  • Extract only where the boundary is natural — a self-contained validation block, a lookup-and-check pair — never by splitting a function at an arbitrary line to get under the threshold.
  • No behaviour change. Confirm by running the full internal/api suite before and after and diffing the results, not just checking it is green.

Verify with gocyclo -over 9 internal/api/handler_purchases.go so the remaining margin is visible rather than only the pass/fail at 10.

Found while verifying a declined nit on LeanerCloud/cloud-commitments-cli#1713.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions