diff --git a/internal/scoring/scoring.go b/internal/scoring/scoring.go index c8666806..dfea8f2d 100644 --- a/internal/scoring/scoring.go +++ b/internal/scoring/scoring.go @@ -134,6 +134,8 @@ func (h HeuristicScorer) Score(sk *skill.Skill) *ScoreResult { desc := sk.Frontmatter.Description name := sk.Frontmatter.Name trimmedDesc := strings.TrimSpace(desc) + trimmedBody := strings.TrimSpace(sk.Body) + searchText := strings.TrimSpace(trimmedDesc + "\n" + trimmedBody) result.DescriptionLen = utf8.RuneCountInString(trimmedDesc) // Short-circuit: description >1024 chars is Invalid @@ -147,12 +149,15 @@ func (h HeuristicScorer) Score(sk *skill.Skill) *ScoreResult { return result } - result.HasTriggers = containsAny(trimmedDesc, triggerPatterns) + result.HasTriggers = containsAny(searchText, triggerPatterns) result.TriggerCount = countPhrasesAfterPattern(trimmedDesc, "USE FOR:") + - countPhrasesAfterPattern(trimmedDesc, "WHEN:") + countPhrasesAfterPattern(trimmedDesc, "WHEN:") + + countPhrasesAfterPattern(trimmedBody, "USE FOR:") + + countPhrasesAfterPattern(trimmedBody, "WHEN:") - result.HasAntiTriggers = containsAny(trimmedDesc, antiTriggerPatterns) - result.AntiTriggerCount = countPhrasesAfterPattern(trimmedDesc, "DO NOT USE FOR:") + result.HasAntiTriggers = containsAny(searchText, antiTriggerPatterns) + result.AntiTriggerCount = countPhrasesAfterPattern(trimmedDesc, "DO NOT USE FOR:") + + countPhrasesAfterPattern(trimmedBody, "DO NOT USE FOR:") // Context-dependent anti-trigger risk (Issue #78) // Severity scales with catalog size: High (≥15) → error, Moderate (6-14) → warning. @@ -178,7 +183,7 @@ func (h HeuristicScorer) Score(sk *skill.Skill) *ScoreResult { } } - result.HasRoutingClarity = containsAny(trimmedDesc, routingClarityPatterns) + result.HasRoutingClarity = containsAny(searchText, routingClarityPatterns) validateName(name, result) validateDescriptionLength(result.DescriptionLen, result) diff --git a/internal/scoring/scoring_test.go b/internal/scoring/scoring_test.go index d309a941..13f7728e 100644 --- a/internal/scoring/scoring_test.go +++ b/internal/scoring/scoring_test.go @@ -526,6 +526,29 @@ DO NOT USE FOR: deployments.` require.Equal(t, 4, result.TriggerCount) } +func TestHeuristicScorer_DetectsSectionsInBody(t *testing.T) { + desc := strings.Repeat("This skill documents compliance behavior for authoring checks. ", 4) + sk := mkSkill("test-skill", desc) + sk.Body = ` +**UTILITY SKILL** - Test skill for compliance scoring. + +USE FOR: testing waza compliance scoring, reproducing trigger detection bugs. + +DO NOT USE FOR: production use, unrelated tasks. + +INVOKES: internal validators. +` + + result := (&HeuristicScorer{}).Score(sk) + + require.Equal(t, AdherenceHigh, result.Level) + require.True(t, result.HasTriggers) + require.True(t, result.HasAntiTriggers) + require.True(t, result.HasRoutingClarity) + require.Equal(t, 2, result.TriggerCount) + require.Equal(t, 2, result.AntiTriggerCount) +} + // Test #74: Invalid adherence level for >1024 char descriptions func TestInvalidAdherenceLevel(t *testing.T) { // Test that Invalid level exists and ranks below Low