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.
Eight functions in
internal/api/handler_purchases.gosit at cyclomatic complexity exactly 10 onorigin/main, which is the pre-commit gate's ceiling (gocyclo -over 10). Measured againstgit show origin/main:internal/api/handler_purchases.go: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
caseto 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 onretryPurchaseso 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:
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.internal/apisuite before and after and diffing the results, not just checking it is green.Verify with
gocyclo -over 9 internal/api/handler_purchases.goso 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.