mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
4a641e7ef1
Fifth post-audit sweep. 24 files, +66/-60.
CRITICAL (user-facing):
* .github/workflows/skill-validation.yml:422: CI eval runner
--model claude-sonnet-4 → claude-sonnet-4-6. Previously CI would
target a retiring model.
* src/coordination/consensus/providers/claude-provider.ts: Claude 3.x
consensus provider modernized — type union extended with
claude-sonnet-4-6 / claude-opus-4-7 / claude-haiku-4-5 as first
entries, default model updated from claude-3-5-sonnet-20241022
to claude-sonnet-4-6, availableModels list prepends new models.
Legacy 3.x entries retained for backward compat.
* src/mcp/security/sampling-server.ts: default model
claude-3-sonnet-20240229 (retired 2026-02-19) → claude-sonnet-4-6.
Skill evals (12 files, 6 + 6 mirrors):
* .claude/skills/ and assets/skills/ mirrors for:
performance-testing, chaos-engineering-resilience, quality-metrics,
localization-testing, accessibility-testing,
n8n-trigger-testing-strategies. models_to_test list updated to
claude-sonnet-4-6 / claude-haiku-4-5.
Test files (9):
* tests/unit/coordination/consensus/providers/claude-provider.test.ts:
default model, test descriptions, and references updated to 4.6/4.7.
* tests/unit/routing/economic-routing.test.ts: claude-3-opus-20240229
usage → claude-opus-4-7.
* tests/unit/learning/skill-validation-learner.test.ts: claude-3-haiku
/ claude-3.5-sonnet / claude-3-opus → new canonicals.
* tests/unit/mcp/handlers/handler-test-utils.ts: claude-3-haiku →
claude-haiku-4-5.
* tests/integration/llm/{real-provider-integration,multi-provider}.test.ts:
bare 'claude-sonnet-4' canonical → 'claude-sonnet-4-6'.
* tests/integration/validation/parallel-eval-runner.test.ts:
claude-3.5-sonnet / claude-3-haiku → new canonicals.
* tests/routing/advisor/multi-model-executor.test.ts:
CRITICAL BUG — 'claude-opus-4-6' (non-existent model ID, typo) ×2
→ 'claude-opus-4-7'. Stale test name 'anthropic/claude-opus-4
when no provider' → '-4.7'.
* tests/unit/opencode/degradation.test.ts: CRITICAL BUG —
modelId 'claude-opus-4-6' (typo) → 'claude-opus-4-7'.
Left intentionally untouched:
* tests/unit/coordination/consensus/providers/openrouter-provider.test.ts:
tests that OpenRouter provider lists claude-3-haiku / claude-3.5-sonnet
/ claude-3-opus as supported. These assertions reflect actual
OpenRouter provider data, which hasn't changed. Adding new-model
assertions would be an enhancement, not a fix.
Verification:
* 0 tsc errors
* 174/174 tests across touched paths pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
197 lines
6.2 KiB
TypeScript
197 lines
6.2 KiB
TypeScript
/**
|
|
* Provider Graceful Degradation Tests
|
|
*
|
|
* Validates that AQE skill/agent invocations degrade gracefully based on
|
|
* the model provider's capability tier:
|
|
* - tier1-any: Works on all providers (simple transforms)
|
|
* - tier2-good: Works on capable models (code gen, analysis)
|
|
* - tier3-best: Needs best models (architecture, security audit)
|
|
*
|
|
* When a provider cannot meet the required tier, the system should:
|
|
* - Warn the user
|
|
* - Suggest alternative actions or lower-tier skills
|
|
* - Never silently produce low-quality output
|
|
*/
|
|
|
|
import { describe, it, expect } from 'vitest';
|
|
import { ModelTier } from '../../../packages/aqe-opencode-types/src/index';
|
|
|
|
// =============================================================================
|
|
// Provider Capability Definitions
|
|
// =============================================================================
|
|
|
|
interface ProviderProfile {
|
|
providerId: string;
|
|
modelId: string;
|
|
tier: ModelTier;
|
|
}
|
|
|
|
const PROVIDERS: Record<string, ProviderProfile> = {
|
|
'claude-opus': {
|
|
providerId: 'anthropic',
|
|
modelId: 'claude-opus-4-7',
|
|
tier: ModelTier.Tier3Best,
|
|
},
|
|
'claude-sonnet': {
|
|
providerId: 'anthropic',
|
|
modelId: 'claude-sonnet-4-6',
|
|
tier: ModelTier.Tier3Best,
|
|
},
|
|
'gpt-4o': {
|
|
providerId: 'openai',
|
|
modelId: 'gpt-4o',
|
|
tier: ModelTier.Tier2Good,
|
|
},
|
|
'gpt-4o-mini': {
|
|
providerId: 'openai',
|
|
modelId: 'gpt-4o-mini',
|
|
tier: ModelTier.Tier1Any,
|
|
},
|
|
'ollama-llama': {
|
|
providerId: 'ollama',
|
|
modelId: 'llama3.2',
|
|
tier: ModelTier.Tier1Any,
|
|
},
|
|
};
|
|
|
|
// =============================================================================
|
|
// Tier Comparison Logic
|
|
// =============================================================================
|
|
|
|
const TIER_ORDER: Record<ModelTier, number> = {
|
|
[ModelTier.Tier1Any]: 1,
|
|
[ModelTier.Tier2Good]: 2,
|
|
[ModelTier.Tier3Best]: 3,
|
|
};
|
|
|
|
interface DegradationResult {
|
|
allowed: boolean;
|
|
warning?: string;
|
|
alternatives?: string[];
|
|
}
|
|
|
|
/**
|
|
* Check whether a provider meets the requirements of a skill's tier.
|
|
*/
|
|
function checkProviderDegradation(
|
|
providerTier: ModelTier,
|
|
requiredTier: ModelTier
|
|
): DegradationResult {
|
|
const providerLevel = TIER_ORDER[providerTier];
|
|
const requiredLevel = TIER_ORDER[requiredTier];
|
|
|
|
if (providerLevel >= requiredLevel) {
|
|
return { allowed: true };
|
|
}
|
|
|
|
// Provider is below the required tier
|
|
const alternatives: string[] = [];
|
|
if (requiredLevel === 3 && providerLevel === 2) {
|
|
alternatives.push('Use a tier3 model (Claude Sonnet/Opus) for best results');
|
|
alternatives.push('Proceed with reduced quality and review output manually');
|
|
} else if (requiredLevel >= 2 && providerLevel === 1) {
|
|
alternatives.push('Use a tier2+ model for code generation and analysis');
|
|
alternatives.push('Break the task into simpler sub-tasks');
|
|
}
|
|
|
|
return {
|
|
allowed: false,
|
|
warning: `Provider tier ${providerTier} is below required tier ${requiredTier}. ` +
|
|
'Output quality may be degraded.',
|
|
alternatives,
|
|
};
|
|
}
|
|
|
|
// =============================================================================
|
|
// Tests
|
|
// =============================================================================
|
|
|
|
describe('Provider Graceful Degradation', () => {
|
|
it('should allow tier1 skills on any provider', () => {
|
|
const requiredTier = ModelTier.Tier1Any;
|
|
|
|
for (const [name, provider] of Object.entries(PROVIDERS)) {
|
|
const result = checkProviderDegradation(provider.tier, requiredTier);
|
|
expect(result.allowed, `${name} should allow tier1 skills`).toBe(true);
|
|
expect(result.warning).toBeUndefined();
|
|
}
|
|
});
|
|
|
|
it('should allow tier2 skills on tier2 and tier3 providers', () => {
|
|
const requiredTier = ModelTier.Tier2Good;
|
|
|
|
// Tier2 and tier3 providers should be fine
|
|
const tier2PlusProviders = ['claude-opus', 'claude-sonnet', 'gpt-4o'];
|
|
for (const name of tier2PlusProviders) {
|
|
const result = checkProviderDegradation(PROVIDERS[name].tier, requiredTier);
|
|
expect(result.allowed, `${name} should allow tier2 skills`).toBe(true);
|
|
}
|
|
});
|
|
|
|
it('should warn for tier3 skills on GPT-4o-mini', () => {
|
|
const result = checkProviderDegradation(
|
|
PROVIDERS['gpt-4o-mini'].tier,
|
|
ModelTier.Tier3Best
|
|
);
|
|
|
|
expect(result.allowed).toBe(false);
|
|
expect(result.warning).toBeDefined();
|
|
expect(result.warning).toContain('below required tier');
|
|
});
|
|
|
|
it('should warn for tier2 skills on tier1-only providers', () => {
|
|
const result = checkProviderDegradation(
|
|
PROVIDERS['ollama-llama'].tier,
|
|
ModelTier.Tier2Good
|
|
);
|
|
|
|
expect(result.allowed).toBe(false);
|
|
expect(result.warning).toBeDefined();
|
|
});
|
|
|
|
it('should suggest alternatives for blocked skills', () => {
|
|
const result = checkProviderDegradation(
|
|
PROVIDERS['gpt-4o-mini'].tier,
|
|
ModelTier.Tier3Best
|
|
);
|
|
|
|
expect(result.alternatives).toBeDefined();
|
|
expect(result.alternatives!.length).toBeGreaterThan(0);
|
|
expect(result.alternatives!.some((a) => a.includes('tier3') || a.includes('tier2'))).toBe(true);
|
|
});
|
|
|
|
it('should proceed without warning for matching tier', () => {
|
|
// Claude Opus is tier3, running a tier3 skill
|
|
const result = checkProviderDegradation(
|
|
PROVIDERS['claude-opus'].tier,
|
|
ModelTier.Tier3Best
|
|
);
|
|
|
|
expect(result.allowed).toBe(true);
|
|
expect(result.warning).toBeUndefined();
|
|
expect(result.alternatives).toBeUndefined();
|
|
});
|
|
|
|
it('should allow higher-tier providers for lower-tier skills', () => {
|
|
// Claude Opus (tier3) running a tier1 skill
|
|
const result = checkProviderDegradation(
|
|
PROVIDERS['claude-opus'].tier,
|
|
ModelTier.Tier1Any
|
|
);
|
|
|
|
expect(result.allowed).toBe(true);
|
|
});
|
|
|
|
it('should warn for tier3 skills on tier2-only providers', () => {
|
|
const result = checkProviderDegradation(
|
|
PROVIDERS['gpt-4o'].tier,
|
|
ModelTier.Tier3Best
|
|
);
|
|
|
|
expect(result.allowed).toBe(false);
|
|
expect(result.warning).toContain('below required tier');
|
|
expect(result.alternatives).toBeDefined();
|
|
expect(result.alternatives!.some((a) => a.includes('tier3'))).toBe(true);
|
|
});
|
|
});
|