{"record":{"id":"57e6ddbe908bc13e","repo":"gastownhall/beads","slug":"kind-is-required","errorCode":null,"errorMessage":"kind is required","messagePattern":"kind is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/audit/audit.go","lineNumber":115,"sourceCode":"\t\tif closeErr := f.Close(); closeErr != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to close interactions log: %w\", closeErr)\n\t\t}\n\t\treturn p, nil\n\t}\n\tif !errors.Is(err, os.ErrExist) {\n\t\treturn \"\", fmt.Errorf(\"failed to create interactions log: %w\", err)\n\t}\n\treturn p, nil\n}\n\n// Append appends an event to .beads/interactions.jsonl as a single JSON line.\n// This is intentionally append-only: callers must not mutate existing lines.\nfunc Append(e *Entry) (string, error) {\n\tif e == nil {\n\t\treturn \"\", fmt.Errorf(\"nil entry\")\n\t}\n\tif e.Kind == \"\" {\n\t\treturn \"\", fmt.Errorf(\"kind is required\")\n\t}\n\n\tp, err := EnsureFile()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif e.ID == \"\" {\n\t\te.ID, err = newID()\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\tif e.CreatedAt.IsZero() {\n\t\te.CreatedAt = time.Now().UTC()\n\t} else {\n\t\te.CreatedAt = e.CreatedAt.UTC()\n\t}","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/audit/audit.go#L97-L133","documentation":"Append requires every audit Entry to carry a non-empty Kind discriminator and returns this error when Entry.Kind is \"\". Kind labels the event type (e.g. LLM call, tool call, field change) and the JSONL sidecar relies on it to be meaningful. Like the nil check, this is an input-validation error raised before any file I/O.","triggerScenarios":"Calling audit.Append(&audit.Entry{}) or AppendIfEnabled with an entry literal that omits Kind, or building an Entry dynamically where the Kind field is set from an empty string variable.","commonSituations":"Adding a new audit event type and forgetting to assign its Kind constant; zero-value struct literals; deserializing an entry from JSON that lacked \"kind\" and re-appending it.","solutions":["Set a descriptive Kind on the Entry before appending (e.g. \"field_change\", \"llm_call\").","Define Kind values as package-level constants and use them at every construction site.","Validate required fields with a small helper before calling Append.","Check upstream data sources for empty kind strings."],"exampleFix":"// before\nentry := &audit.Entry{IssueID: issue.ID}\naudit.AppendIfEnabled(entry) // \"kind is required\"\n// after\nentry := &audit.Entry{Kind: \"field_change\", IssueID: issue.ID}\naudit.AppendIfEnabled(entry)","handlingStrategy":"validation","validationCode":"if entry != nil && strings.TrimSpace(entry.Kind) == \"\" {\n    return fmt.Errorf(\"audit entry requires a non-empty kind\")\n}","typeGuard":"func hasKind(e *audit.Entry) bool { return e != nil && e.Kind != \"\" }","tryCatchPattern":"if _, err := audit.Append(e); err != nil && strings.Contains(err.Error(), \"kind is required\") {\n    return fmt.Errorf(\"entry %p built without Kind\", e)\n}","preventionTips":["Define Kind values as constants and use them in every Entry literal.","Add a unit test asserting every audit-event constructor sets Kind.","Reject empty kinds at the boundary where entries are built."],"tags":["go","validation","audit","required-field"],"backgroundTag":"missing-required-field","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}