{"record":{"id":"ec4128a52fe19756","repo":"sipeed/picoclaw","slug":"unsupported-change-kind-q","errorCode":null,"errorMessage":"unsupported change_kind %q","messagePattern":"unsupported change_kind %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/evolution/apply.go","lineNumber":213,"sourceCode":"\t\t}\n\t\treturn strings.TrimRight(existingBody, \"\\n\") + \"\\n\\n\" + strings.TrimLeft(patch, \"\\n\"), nil\n\tcase ChangeKindMerge:\n\t\tpatch, err := renderDeployablePatchBody(draft.BodyOrPatch, draft.TargetSkillName)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif !hadOriginal || strings.TrimSpace(existingBody) == \"\" {\n\t\t\treturn renderDeployableSkillBody(draft.BodyOrPatch), nil\n\t\t}\n\t\tmergedSection := strings.Join([]string{\n\t\t\t\"\",\n\t\t\t\"## Merged Knowledge\",\n\t\t\tstrings.TrimSpace(patch),\n\t\t\t\"\",\n\t\t}, \"\\n\")\n\t\treturn strings.TrimRight(existingBody, \"\\n\") + mergedSection, nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unsupported change_kind %q\", draft.ChangeKind)\n\t}\n}\n\nfunc renderDeployablePatchBody(body, targetSkillName string) (string, error) {\n\tbody = renderDeployableSkillBody(body)\n\tfrontmatter, markdownBody := splitSkillFrontmatter(body)\n\tif frontmatter == \"\" {\n\t\tmarkdownBody = body\n\t} else {\n\t\tfields, err := parseSkillFrontmatterFields(frontmatter, true)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif name := strings.TrimSpace(fields[\"name\"]); name != \"\" && name != targetSkillName {\n\t\t\treturn \"\", fmt.Errorf(\n\t\t\t\t\"skill patch frontmatter name %q does not match target skill %q\",\n\t\t\t\tname,\n\t\t\t\ttargetSkillName,","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/evolution/apply.go#L195-L231","documentation":"renderAppliedBody's switch default (pkg/evolution/apply.go:213): draft.ChangeKind is not one of the four supported constants (\"create\", \"append\", \"replace\", \"merge\" from types.go). The Go zero value \"\" also lands here, so an unset ChangeKind is rejected rather than defaulted.","triggerScenarios":"A SkillDraft constructed without setting ChangeKind (zero value \"\"); ChangeKind loaded from the persisted drafts store (skill_drafts.json) with a typo'd or new value such as \"update\" or \"Create\"; drafts written by a newer package version using a kind this binary does not know.","commonSituations":"Hand-built drafts in tests or tools forgetting the field; version skew between the writer and reader of the drafts store; serialized enum renamed across releases.","solutions":["Set ChangeKind to evolution.ChangeKindCreate / Append / Replace / Merge exactly","Validate ChangeKind against the four constants before calling ApplyDraft","Purge or re-save stale drafts in skill_drafts.json after upgrading or downgrading","Reject unknown change_kind values at draft load time"],"exampleFix":"// before\ndraft := evolution.SkillDraft{TargetSkillName: \"x\", BodyOrPatch: body} // ChangeKind == \"\"\n\n// after\ndraft := evolution.SkillDraft{TargetSkillName: \"x\", BodyOrPatch: body, ChangeKind: evolution.ChangeKindCreate}","handlingStrategy":"validation","validationCode":"func supportedChangeKind(k evolution.ChangeKind) bool {\n\tswitch k {\n\tcase evolution.ChangeKindCreate, evolution.ChangeKindAppend,\n\t\tevolution.ChangeKindReplace, evolution.ChangeKindMerge:\n\t\treturn true\n\t}\n\treturn false\n}\n\nif !supportedChangeKind(draft.ChangeKind) {\n\t// reject or default before calling ApplyDraft","typeGuard":"func isValidChangeKind(k evolution.ChangeKind) bool {\n\tswitch k {\n\tcase evolution.ChangeKindCreate, evolution.ChangeKindAppend,\n\t\tevolution.ChangeKindReplace, evolution.ChangeKindMerge:\n\t\treturn true\n\t}\n\treturn false\n}","tryCatchPattern":"if err := applier.ApplyDraft(ctx, ws, draft); err != nil {\n\tif strings.Contains(err.Error(), \"unsupported change_kind\") {\n\t\t// draft came from a newer/older store — re-save or drop it\n\t}\n}","preventionTips":["Always set ChangeKind from the exported constants; never construct the string by hand","Validate change_kind when loading drafts from JSON and reject unknown values at load time","After version upgrades, purge drafts whose kinds the current binary does not recognize"],"tags":["go","enum","validation","serialization","version-skew"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}