{"record":{"id":"45a321e0b815e950","repo":"gastownhall/beads","slug":"close-reason-is-terse-d-chars-aim-for-20-char","errorCode":null,"errorMessage":"close reason is terse (%d chars); aim for 20+ characters describing what was done","messagePattern":"close reason is terse \\((.+?) chars\\); aim for 20\\+ characters describing what was done","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/validation/template.go","lineNumber":211,"sourceCode":"\t\t}\n\t\tremaining = append(remaining, m)\n\t}\n\tif len(remaining) == 0 {\n\t\treturn nil\n\t}\n\ttemplateErr.Missing = remaining\n\treturn templateErr\n}\n\n// ValidateCloseReason checks if a close reason meets minimum quality standards.\n// Returns nil if the reason is acceptable. Used by validation.on-close config.\nfunc ValidateCloseReason(reason string) error {\n\treason = strings.TrimSpace(reason)\n\tif reason == \"\" || strings.EqualFold(reason, \"closed\") {\n\t\treturn fmt.Errorf(\"close reason is empty or default; provide a summary of what was done\")\n\t}\n\tif len(reason) < 20 {\n\t\treturn fmt.Errorf(\"close reason is terse (%d chars); aim for 20+ characters describing what was done\", len(reason))\n\t}\n\treturn nil\n}\n","sourceCodeStart":193,"sourceCodeEnd":215,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/validation/template.go#L193-L215","documentation":"ValidateCloseReason rejects close reasons shorter than 20 characters as too terse. The function trims whitespace, then enforces a minimum length so close summaries actually describe the work performed. This complements the empty/default check and is enforced by validation.on-close config.","triggerScenarios":"Closing an issue with a reason like \"done\", \"ok\", \"fixed\" — any trimmed string of fewer than 20 characters reaching ValidateCloseReason.","commonSituations":"One-word close messages typed interactively; scripts using placeholder reasons like \"wip done\"; agents summarizing too briefly.","solutions":["Write a reason of at least 20 characters describing what was done, e.g. \"Closed: implemented X, tested with Y\"","Expand terse script templates to include a short sentence about the change","Adjust validation.on-close thresholds only if 20 chars is genuinely too strict for your workflow"],"exampleFix":"// before\nbd close bd-42 --reason \"done\"\n// after\nbd close bd-42 --reason \"Done: rewrote collector to batch events; 3 tests added\"","handlingStrategy":"validation","validationCode":"if len(strings.TrimSpace(reason)) < 20 {\n    return fmt.Errorf(\"reason must be 20+ chars, got %d\", len(strings.TrimSpace(reason)))\n}","typeGuard":null,"tryCatchPattern":"if err := validation.ValidateCloseReason(reason); err != nil {\n    if strings.HasPrefix(err.Error(), \"close reason is terse\") { reason = expandReason(reason) }\n    return err\n}","preventionTips":["Template close reasons as full sentences, not words","Pre-commit hook or script assertion checking reason length","Use the close command's summary fields to compose reasons"],"tags":["validation","close-reason","length-limit"],"backgroundTag":"close-reason-quality","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}