mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-05 13:29:44 +02:00
A skill_file row whose path is the skill's own SKILL.md (persisted by older builds or direct create/update API calls) collides with the primary content the daemon writes itself, failing task prep with errPathPreExists on every non-codex local runtime (#3489). #3526 guarded this with strings.EqualFold(path, "SKILL.md") at the daemon write site and the three API ingress points, but the stored path is not canonicalized: "./SKILL.md" or "sub/../SKILL.md" slip past the exact-match guard while filepath.Join still resolves them onto the same SKILL.md, so prep can still break. Extract one canonical helper, skill.IsReservedContentPath, that cleans the path before the case-insensitive compare, and use it at all four sites (execenv writeSkillFiles, skill create, update, single-file upsert). Add a daemon-side regression test for writeSkillFiles ignoring a bundled SKILL.md (exact + "./" spellings) — the load-bearing fix previously had only API-layer coverage — plus a unit test for the helper. Existing poisoned rows are intentionally left in place (skipped at prep) per the decision on MUL-2928. MUL-2928 Follow-up to #3526; supersedes #3560. Co-authored-by: J <j@multica.ai> Co-authored-by: multica-agent <github@multica.ai>
32 lines
779 B
Go
32 lines
779 B
Go
package skill
|
|
|
|
import "testing"
|
|
|
|
func TestIsReservedContentPath(t *testing.T) {
|
|
reserved := []string{
|
|
"SKILL.md", // canonical
|
|
"skill.md", // case-insensitive
|
|
"SKILL.MD", // case-insensitive
|
|
"./SKILL.md", // non-canonical, resolves to SKILL.md
|
|
"foo/../SKILL.md", // non-canonical, resolves to SKILL.md
|
|
}
|
|
for _, p := range reserved {
|
|
if !IsReservedContentPath(p) {
|
|
t.Errorf("IsReservedContentPath(%q) = false, want true", p)
|
|
}
|
|
}
|
|
|
|
notReserved := []string{
|
|
"README.md",
|
|
"docs/SKILL.md", // genuine nested file, will not collide with the primary
|
|
"skills/SKILL.md",
|
|
"SKILL.md.bak",
|
|
"",
|
|
}
|
|
for _, p := range notReserved {
|
|
if IsReservedContentPath(p) {
|
|
t.Errorf("IsReservedContentPath(%q) = true, want false", p)
|
|
}
|
|
}
|
|
}
|