Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions plugins/governance/complexity/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ func TestAnalyze_CustomTierBoundaries(t *testing.T) {
}
customAnalyzer := NewComplexityAnalyzerWithConfig(&cfg)

if got := defaultAnalyzer.classifyTier(0.18); got != TierMedium {
t.Fatalf("default boundary classified 0.18 as %s, want %s", got, TierMedium)
if got := defaultAnalyzer.classifyTier(0.25); got != TierMedium {
t.Fatalf("default boundary classified 0.25 as %s, want %s", got, TierMedium)
}
if got := customAnalyzer.classifyTier(0.18); got != TierComplex {
t.Fatalf("custom boundary classified 0.18 as %s, want %s", got, TierComplex)
if got := customAnalyzer.classifyTier(0.25); got != TierComplex {
t.Fatalf("custom boundary classified 0.25 as %s, want %s", got, TierComplex)
}
}

Expand Down Expand Up @@ -359,25 +359,37 @@ func TestAnalyze_ReasoningOverrideNotTooEager(t *testing.T) {
func TestAnalyze_SimpleKeywordDoesNotSuppressTechnicalSignals(t *testing.T) {
a := NewComplexityAnalyzer()

// Scores ~0.18, which lands in SIMPLE under the default 0.20 boundary.
// The guard here is that the "what is" simple keyword only nudges the
// score down — it must not zero out the technical signal or block
// classification entirely.
result := a.Analyze(ComplexityInput{
LastUserText: "What is eventual consistency in distributed systems with sharding?",
})

if result.Tier == "SIMPLE" {
t.Errorf("expected non-SIMPLE tier for technical 'what is' question, got %s (score=%.3f)",
if result == nil {
t.Fatal("expected technical 'what is' question to classify, got nil")
}
if result.Score <= 0 {
t.Errorf("expected positive score for technical 'what is' question, got %s (score=%.3f)",
result.Tier, result.Score)
}
}

func TestAnalyze_AccessVsRefreshTokens(t *testing.T) {
a := NewComplexityAnalyzer()

// Scores ~0.19 — SIMPLE under the default 0.20 boundary, but the
// technical signal must still register as a positive score.
result := a.Analyze(ComplexityInput{
LastUserText: "Explain the difference between an access token and a refresh token. When would you use short-lived vs long-lived tokens?",
})

if result.Tier == "SIMPLE" {
t.Errorf("expected MEDIUM or higher tier for token lifecycle question, got %s (score=%.3f)",
if result == nil {
t.Fatal("expected token lifecycle question to classify, got nil")
}
if result.Score <= 0 {
t.Errorf("expected positive score for token lifecycle question, got %s (score=%.3f)",
result.Tier, result.Score)
}
}
Expand Down
4 changes: 2 additions & 2 deletions plugins/governance/complexity/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ const (
// Default boundaries are tuned to the 1.00 positive-weight scale in
// keywords.go; retune them together with the dimension weights.
const (
simpleMediumBoundary = 0.17
mediumComplexBoundary = 0.39
simpleMediumBoundary = 0.20
mediumComplexBoundary = 0.40
)

// TierBoundaries defines the score thresholds for tier classification.
Expand Down
4 changes: 2 additions & 2 deletions ui/lib/types/complexityRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,6 @@ export const KEYWORD_LIST_DEFINITIONS: Array<{
];

export const DEFAULT_TIER_BOUNDARIES: TierBoundaries = {
simple_medium: 0.17,
medium_complex: 0.39,
simple_medium: 0.2,
medium_complex: 0.4,
};
Loading