specweave 0.6.8 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/README.md +1 -1
- package/CLAUDE.md +903 -99
- package/README.md +143 -207
- package/bin/specweave.js +67 -0
- package/dist/cli/commands/abandon.d.ts +13 -0
- package/dist/cli/commands/abandon.d.ts.map +1 -0
- package/dist/cli/commands/abandon.js +15 -0
- package/dist/cli/commands/abandon.js.map +1 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +94 -18
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/pause.d.ts +13 -0
- package/dist/cli/commands/pause.d.ts.map +1 -0
- package/dist/cli/commands/pause.js +15 -0
- package/dist/cli/commands/pause.js.map +1 -0
- package/dist/cli/commands/qa.d.ts +54 -0
- package/dist/cli/commands/qa.d.ts.map +1 -0
- package/dist/cli/commands/qa.js +98 -0
- package/dist/cli/commands/qa.js.map +1 -0
- package/dist/cli/commands/resume.d.ts +12 -0
- package/dist/cli/commands/resume.d.ts.map +1 -0
- package/dist/cli/commands/resume.js +14 -0
- package/dist/cli/commands/resume.js.map +1 -0
- package/dist/cli/commands/status.d.ts +12 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +23 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/ado.d.ts +57 -0
- package/dist/cli/helpers/issue-tracker/ado.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/ado.js +223 -0
- package/dist/cli/helpers/issue-tracker/ado.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/github.d.ts +65 -0
- package/dist/cli/helpers/issue-tracker/github.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/github.js +284 -0
- package/dist/cli/helpers/issue-tracker/github.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/index.d.ts +22 -0
- package/dist/cli/helpers/issue-tracker/index.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/index.js +270 -0
- package/dist/cli/helpers/issue-tracker/index.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/jira.d.ts +61 -0
- package/dist/cli/helpers/issue-tracker/jira.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/jira.js +265 -0
- package/dist/cli/helpers/issue-tracker/jira.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/types.d.ts +86 -0
- package/dist/cli/helpers/issue-tracker/types.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/types.js +16 -0
- package/dist/cli/helpers/issue-tracker/types.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/utils.d.ts +103 -0
- package/dist/cli/helpers/issue-tracker/utils.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/utils.js +240 -0
- package/dist/cli/helpers/issue-tracker/utils.js.map +1 -0
- package/dist/core/increment/limits.d.ts +68 -0
- package/dist/core/increment/limits.d.ts.map +1 -0
- package/dist/core/increment/limits.js +224 -0
- package/dist/core/increment/limits.js.map +1 -0
- package/dist/core/increment/metadata-manager.d.ts +114 -0
- package/dist/core/increment/metadata-manager.d.ts.map +1 -0
- package/dist/core/increment/metadata-manager.js +320 -0
- package/dist/core/increment/metadata-manager.js.map +1 -0
- package/dist/core/increment/status-commands.d.ts +43 -0
- package/dist/core/increment/status-commands.d.ts.map +1 -0
- package/dist/core/increment/status-commands.js +277 -0
- package/dist/core/increment/status-commands.js.map +1 -0
- package/dist/core/plugin-detector.d.ts +1 -0
- package/dist/core/plugin-detector.d.ts.map +1 -1
- package/dist/core/plugin-detector.js +25 -0
- package/dist/core/plugin-detector.js.map +1 -1
- package/dist/core/qa/qa-runner.d.ts +16 -0
- package/dist/core/qa/qa-runner.d.ts.map +1 -0
- package/dist/core/qa/qa-runner.js +404 -0
- package/dist/core/qa/qa-runner.js.map +1 -0
- package/dist/core/qa/quality-gate-decider.d.ts +53 -0
- package/dist/core/qa/quality-gate-decider.d.ts.map +1 -0
- package/dist/core/qa/quality-gate-decider.js +268 -0
- package/dist/core/qa/quality-gate-decider.js.map +1 -0
- package/dist/core/qa/risk-calculator.d.ts +126 -0
- package/dist/core/qa/risk-calculator.d.ts.map +1 -0
- package/dist/core/qa/risk-calculator.js +247 -0
- package/dist/core/qa/risk-calculator.js.map +1 -0
- package/dist/core/qa/types.d.ts +315 -0
- package/dist/core/qa/types.d.ts.map +1 -0
- package/dist/core/qa/types.js +8 -0
- package/dist/core/qa/types.js.map +1 -0
- package/dist/core/types/config.d.ts +35 -0
- package/dist/core/types/config.d.ts.map +1 -1
- package/dist/core/types/config.js +16 -0
- package/dist/core/types/config.js.map +1 -1
- package/dist/core/types/increment-metadata.d.ts +120 -0
- package/dist/core/types/increment-metadata.d.ts.map +1 -0
- package/dist/core/types/increment-metadata.js +138 -0
- package/dist/core/types/increment-metadata.js.map +1 -0
- package/dist/hooks/lib/invoke-translator-skill.d.ts +60 -0
- package/dist/hooks/lib/invoke-translator-skill.d.ts.map +1 -0
- package/dist/hooks/lib/invoke-translator-skill.js +201 -0
- package/dist/hooks/lib/invoke-translator-skill.js.map +1 -0
- package/dist/hooks/lib/translate-file.d.ts +59 -0
- package/dist/hooks/lib/translate-file.d.ts.map +1 -0
- package/dist/hooks/lib/translate-file.js +350 -0
- package/dist/hooks/lib/translate-file.js.map +1 -0
- package/dist/locales/en/cli.json +3 -1
- package/dist/metrics/calculators/change-failure-rate.d.ts +22 -0
- package/dist/metrics/calculators/change-failure-rate.d.ts.map +1 -0
- package/dist/metrics/calculators/change-failure-rate.js +70 -0
- package/dist/metrics/calculators/change-failure-rate.js.map +1 -0
- package/dist/metrics/calculators/deployment-frequency.d.ts +20 -0
- package/dist/metrics/calculators/deployment-frequency.d.ts.map +1 -0
- package/dist/metrics/calculators/deployment-frequency.js +61 -0
- package/dist/metrics/calculators/deployment-frequency.js.map +1 -0
- package/dist/metrics/calculators/lead-time.d.ts +22 -0
- package/dist/metrics/calculators/lead-time.d.ts.map +1 -0
- package/dist/metrics/calculators/lead-time.js +82 -0
- package/dist/metrics/calculators/lead-time.js.map +1 -0
- package/dist/metrics/calculators/mttr.d.ts +21 -0
- package/dist/metrics/calculators/mttr.d.ts.map +1 -0
- package/dist/metrics/calculators/mttr.js +60 -0
- package/dist/metrics/calculators/mttr.js.map +1 -0
- package/dist/metrics/dora-calculator.d.ts +24 -0
- package/dist/metrics/dora-calculator.d.ts.map +1 -0
- package/dist/metrics/dora-calculator.js +104 -0
- package/dist/metrics/dora-calculator.js.map +1 -0
- package/dist/metrics/github-client.d.ts +51 -0
- package/dist/metrics/github-client.d.ts.map +1 -0
- package/dist/metrics/github-client.js +133 -0
- package/dist/metrics/github-client.js.map +1 -0
- package/dist/metrics/types.d.ts +112 -0
- package/dist/metrics/types.d.ts.map +1 -0
- package/dist/metrics/types.js +10 -0
- package/dist/metrics/types.js.map +1 -0
- package/dist/metrics/utils/percentile.d.ts +25 -0
- package/dist/metrics/utils/percentile.d.ts.map +1 -0
- package/dist/metrics/utils/percentile.js +46 -0
- package/dist/metrics/utils/percentile.js.map +1 -0
- package/dist/metrics/utils/tier-classifier.d.ts +61 -0
- package/dist/metrics/utils/tier-classifier.d.ts.map +1 -0
- package/dist/metrics/utils/tier-classifier.js +100 -0
- package/dist/metrics/utils/tier-classifier.js.map +1 -0
- package/dist/utils/auth-helpers.d.ts +58 -0
- package/dist/utils/auth-helpers.d.ts.map +1 -0
- package/dist/utils/auth-helpers.js +108 -0
- package/dist/utils/auth-helpers.js.map +1 -0
- package/dist/utils/env-file.d.ts +88 -0
- package/dist/utils/env-file.d.ts.map +1 -0
- package/dist/utils/env-file.js +180 -0
- package/dist/utils/env-file.js.map +1 -0
- package/dist/utils/plugin-detection.d.ts +50 -0
- package/dist/utils/plugin-detection.d.ts.map +1 -0
- package/dist/utils/plugin-detection.js +229 -0
- package/dist/utils/plugin-detection.js.map +1 -0
- package/dist/utils/secrets-loader.d.ts +88 -0
- package/dist/utils/secrets-loader.d.ts.map +1 -0
- package/dist/utils/secrets-loader.js +271 -0
- package/dist/utils/secrets-loader.js.map +1 -0
- package/dist/utils/translation.d.ts +187 -0
- package/dist/utils/translation.d.ts.map +1 -0
- package/dist/utils/translation.js +414 -0
- package/dist/utils/translation.js.map +1 -0
- package/package.json +28 -44
- package/plugins/specweave/.claude-plugin/plugin.json +3 -3
- package/plugins/specweave/agents/pm/AGENT.md +330 -54
- package/plugins/specweave/agents/test-aware-planner/AGENT.md +1035 -0
- package/plugins/specweave/agents/test-aware-planner/templates/README.md +118 -0
- package/plugins/specweave/agents/test-aware-planner/templates/task-non-testable.md.template +24 -0
- package/plugins/specweave/agents/test-aware-planner/templates/task-testable.md.template +53 -0
- package/plugins/specweave/agents/test-aware-planner/templates/tasks-frontmatter.md.template +11 -0
- package/plugins/specweave/commands/README.md +88 -163
- package/plugins/specweave/commands/specweave-abandon.md +314 -0
- package/plugins/specweave/commands/specweave-check-tests.md +546 -0
- package/plugins/specweave/commands/{do.md → specweave-do.md} +5 -7
- package/plugins/specweave/commands/{increment.md → specweave-increment.md} +231 -4
- package/plugins/specweave/commands/specweave-pause.md +189 -0
- package/plugins/specweave/commands/specweave-qa.md +245 -0
- package/plugins/specweave/commands/specweave-resume.md +216 -0
- package/plugins/specweave/commands/specweave-status.md +397 -0
- package/plugins/specweave/commands/specweave-sync-tasks.md +256 -0
- package/plugins/specweave/commands/{translate.md → specweave-translate.md} +3 -3
- package/plugins/specweave/commands/specweave-update-scope.md +351 -0
- package/plugins/specweave/commands/specweave.md +21 -21
- package/plugins/specweave/hooks/post-increment-planning.sh +335 -0
- package/plugins/specweave/hooks/post-task-completion.sh +141 -0
- package/plugins/specweave/skills/SKILLS-INDEX.md +1 -1
- package/plugins/specweave/skills/brownfield-analyzer/SKILL.md +9 -9
- package/plugins/specweave/skills/increment-planner/SKILL.md +400 -212
- package/plugins/specweave/skills/increment-quality-judge-v2/SKILL.md +499 -0
- package/plugins/specweave/skills/plugin-detector/SKILL.md +114 -1
- package/plugins/specweave/skills/project-kickstarter/SKILL.md +74 -1
- package/plugins/specweave/skills/{rfc-generator → spec-generator}/SKILL.md +22 -29
- package/plugins/specweave/skills/specweave-detector/SKILL.md +3 -3
- package/plugins/specweave/skills/specweave-framework/SKILL.md +2 -2
- package/plugins/specweave-ado/.claude-plugin/plugin.json +18 -4
- package/plugins/specweave-ado/agents/ado-manager/AGENT.md +426 -0
- package/plugins/specweave-ado/commands/close-workitem.md +52 -0
- package/plugins/specweave-ado/commands/create-workitem.md +53 -0
- package/plugins/specweave-ado/commands/status.md +53 -0
- package/plugins/specweave-ado/commands/sync.md +55 -0
- package/plugins/specweave-ado/lib/ado-client.ts +361 -0
- package/plugins/specweave-ado/reference/ado-specweave-mapping.md +552 -0
- package/plugins/specweave-ado/skills/ado-sync/SKILL.md +344 -193
- package/plugins/specweave-docs/skills/docusaurus/SKILL.md +73 -0
- package/plugins/specweave-github/agents/github-manager/AGENT.md +49 -0
- package/plugins/specweave-github/commands/{github-close-issue.md → close-issue.md} +1 -1
- package/plugins/specweave-github/commands/{github-create-issue.md → create-issue.md} +1 -1
- package/plugins/specweave-github/commands/{github-status.md → status.md} +1 -1
- package/plugins/specweave-github/commands/{github-sync-tasks.md → sync-tasks.md} +1 -1
- package/plugins/specweave-github/commands/{github-sync.md → sync.md} +1 -1
- package/plugins/specweave-github/reference/github-specweave-mapping.md +377 -0
- package/plugins/specweave-github/skills/github-sync/SKILL.md +11 -3
- package/plugins/specweave-infrastructure/commands/{specweave.monitor-setup.md → monitor-setup.md} +5 -0
- package/plugins/specweave-infrastructure/commands/{specweave.slo-implement.md → slo-implement.md} +5 -0
- package/plugins/specweave-jira/agents/jira-manager/AGENT.md +380 -0
- package/plugins/specweave-jira/commands/{specweave.sync-jira.md → sync.md} +1 -1
- package/plugins/specweave-jira/reference/jira-specweave-mapping.md +508 -0
- package/plugins/specweave-ml/commands/ml-deploy.md +1 -1
- package/plugins/specweave-ml/commands/ml-evaluate.md +1 -1
- package/plugins/specweave-ml/commands/ml-explain.md +1 -1
- package/plugins/specweave-ml/commands/{specweave.ml-pipeline.md → ml-pipeline.md} +5 -0
- package/src/templates/AGENTS.md.template +331 -31
- package/src/templates/CLAUDE.md.template +36 -21
- package/src/templates/COMPLETION-REPORT.template.md +128 -0
- package/src/templates/README.md.template +17 -16
- package/src/templates/docs/README.md +11 -9
- package/src/templates/docs/spec-template.md +229 -0
- package/plugins/specweave/commands/inc.md +0 -85
- package/plugins/specweave/commands/list-increments.md +0 -180
- package/src/adapters/README.md +0 -275
- package/src/adapters/adapter-base.ts +0 -182
- package/src/adapters/adapter-interface.ts +0 -166
- package/src/adapters/adapter-loader.ts +0 -256
- package/src/adapters/agents-md-generator.ts +0 -228
- package/src/adapters/claude/README.md +0 -233
- package/src/adapters/claude/adapter.ts +0 -468
- package/src/adapters/claude-md-generator.ts +0 -377
- package/src/adapters/codex/README.md +0 -105
- package/src/adapters/codex/adapter.ts +0 -333
- package/src/adapters/cursor/.cursor/context/docs-context.md +0 -62
- package/src/adapters/cursor/.cursor/context/increments-context.md +0 -71
- package/src/adapters/cursor/.cursor/context/strategy-context.md +0 -73
- package/src/adapters/cursor/.cursor/context/tests-context.md +0 -89
- package/src/adapters/cursor/README.md +0 -283
- package/src/adapters/cursor/adapter.ts +0 -451
- package/src/adapters/doc-generator.ts +0 -331
- package/src/adapters/gemini/README.md +0 -97
- package/src/adapters/gemini/adapter.ts +0 -298
- package/src/adapters/generic/README.md +0 -277
- package/src/adapters/generic/adapter.ts +0 -378
- package/src/adapters/registry.yaml +0 -187
- /package/plugins/specweave/commands/{costs.md → specweave-costs.md} +0 -0
- /package/plugins/specweave/commands/{done.md → specweave-done.md} +0 -0
- /package/plugins/specweave/commands/{next.md → specweave-next.md} +0 -0
- /package/plugins/specweave/commands/{progress.md → specweave-progress.md} +0 -0
- /package/plugins/specweave/commands/{sync-docs.md → specweave-sync-docs.md} +0 -0
- /package/plugins/specweave/commands/{tdd-cycle.md → specweave-tdd-cycle.md} +0 -0
- /package/plugins/specweave/commands/{tdd-green.md → specweave-tdd-green.md} +0 -0
- /package/plugins/specweave/commands/{tdd-red.md → specweave-tdd-red.md} +0 -0
- /package/plugins/specweave/commands/{tdd-refactor.md → specweave-tdd-refactor.md} +0 -0
- /package/plugins/specweave/commands/{validate.md → specweave-validate.md} +0 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality Gate Decider - PASS/CONCERNS/FAIL decision logic
|
|
3
|
+
*
|
|
4
|
+
* @module qa/quality-gate-decider
|
|
5
|
+
* @since v0.8.0
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Default quality gate thresholds (BMAD pattern)
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_THRESHOLDS = {
|
|
11
|
+
fail: {
|
|
12
|
+
riskScore: 9.0, // Risk >= 9.0 → FAIL
|
|
13
|
+
testCoverage: 60, // Coverage < 60% → FAIL
|
|
14
|
+
specQuality: 50, // Spec score < 50 → FAIL
|
|
15
|
+
criticalVulnerabilities: 1, // Critical vulns >= 1 → FAIL
|
|
16
|
+
},
|
|
17
|
+
concerns: {
|
|
18
|
+
riskScore: 6.0, // Risk >= 6.0 → CONCERNS
|
|
19
|
+
testCoverage: 80, // Coverage < 80% → CONCERNS
|
|
20
|
+
specQuality: 70, // Spec score < 70 → CONCERNS
|
|
21
|
+
highVulnerabilities: 1, // High vulns >= 1 → CONCERNS
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
export class QualityGateDecider {
|
|
25
|
+
constructor(thresholds = DEFAULT_THRESHOLDS) {
|
|
26
|
+
this.thresholds = thresholds;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Main decision logic - determine PASS/CONCERNS/FAIL
|
|
30
|
+
*
|
|
31
|
+
* @param assessment - Quality assessment result from AI judge
|
|
32
|
+
* @param testCoverage - Optional test coverage result
|
|
33
|
+
* @param securityAudit - Optional security audit result
|
|
34
|
+
* @returns Quality gate result with decision and issues
|
|
35
|
+
*/
|
|
36
|
+
decide(assessment, testCoverage, securityAudit) {
|
|
37
|
+
const blockers = [];
|
|
38
|
+
const concerns = [];
|
|
39
|
+
const recommendations = [];
|
|
40
|
+
// Check 1: Risk Assessment (BMAD pattern)
|
|
41
|
+
if (assessment.risk_assessment) {
|
|
42
|
+
this.assessRisks(assessment.risk_assessment, blockers, concerns);
|
|
43
|
+
}
|
|
44
|
+
// Check 2: Test Coverage
|
|
45
|
+
if (testCoverage) {
|
|
46
|
+
this.assessTestCoverage(testCoverage, blockers, concerns);
|
|
47
|
+
}
|
|
48
|
+
// Check 3: Spec Quality
|
|
49
|
+
this.assessSpecQuality(assessment, blockers, concerns, recommendations);
|
|
50
|
+
// Check 4: Security Vulnerabilities
|
|
51
|
+
if (securityAudit) {
|
|
52
|
+
this.assessSecurity(securityAudit, blockers, concerns);
|
|
53
|
+
}
|
|
54
|
+
// Make final decision
|
|
55
|
+
const { decision, reasoning } = this.makeDecision(blockers, concerns);
|
|
56
|
+
return {
|
|
57
|
+
decision,
|
|
58
|
+
blockers,
|
|
59
|
+
concerns,
|
|
60
|
+
recommendations,
|
|
61
|
+
reasoning,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Assess risks and categorize into blockers/concerns
|
|
66
|
+
*/
|
|
67
|
+
assessRisks(riskAssessment, blockers, concerns) {
|
|
68
|
+
const overallRisk = riskAssessment.overall_risk_score;
|
|
69
|
+
// Check overall risk score first
|
|
70
|
+
if (overallRisk >= this.thresholds.fail.riskScore) {
|
|
71
|
+
// Find all critical risks (score >= 9.0)
|
|
72
|
+
const criticalRisks = riskAssessment.risks.filter((r) => r.score >= this.thresholds.fail.riskScore);
|
|
73
|
+
for (const risk of criticalRisks) {
|
|
74
|
+
blockers.push({
|
|
75
|
+
type: 'risk',
|
|
76
|
+
severity: 'critical',
|
|
77
|
+
title: `CRITICAL RISK: ${risk.title}`,
|
|
78
|
+
description: `${risk.description} (Score: ${risk.score.toFixed(1)}/10)`,
|
|
79
|
+
mitigation: risk.mitigation,
|
|
80
|
+
location: risk.location,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else if (overallRisk >= this.thresholds.concerns.riskScore) {
|
|
85
|
+
// Find all high risks (score 6.0-8.9)
|
|
86
|
+
const highRisks = riskAssessment.risks.filter((r) => r.score >= this.thresholds.concerns.riskScore &&
|
|
87
|
+
r.score < this.thresholds.fail.riskScore);
|
|
88
|
+
for (const risk of highRisks) {
|
|
89
|
+
concerns.push({
|
|
90
|
+
type: 'risk',
|
|
91
|
+
severity: 'high',
|
|
92
|
+
title: `HIGH RISK: ${risk.title}`,
|
|
93
|
+
description: `${risk.description} (Score: ${risk.score.toFixed(1)}/10)`,
|
|
94
|
+
mitigation: risk.mitigation,
|
|
95
|
+
location: risk.location,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Assess test coverage and identify gaps
|
|
102
|
+
*/
|
|
103
|
+
assessTestCoverage(testCoverage, blockers, concerns) {
|
|
104
|
+
const coverage = testCoverage.coverage_percentage;
|
|
105
|
+
if (coverage < this.thresholds.fail.testCoverage) {
|
|
106
|
+
blockers.push({
|
|
107
|
+
type: 'test_coverage',
|
|
108
|
+
severity: 'critical',
|
|
109
|
+
title: 'Insufficient test coverage',
|
|
110
|
+
description: `Coverage is ${coverage}% (minimum: ${this.thresholds.fail.testCoverage}%)`,
|
|
111
|
+
mitigation: `Add tests to reach ${this.thresholds.fail.testCoverage}% coverage`,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
else if (coverage < this.thresholds.concerns.testCoverage) {
|
|
115
|
+
concerns.push({
|
|
116
|
+
type: 'test_coverage',
|
|
117
|
+
severity: 'high',
|
|
118
|
+
title: 'Test coverage below target',
|
|
119
|
+
description: `Coverage is ${coverage}% (target: ${this.thresholds.concerns.testCoverage}%)`,
|
|
120
|
+
mitigation: `Add tests to reach ${this.thresholds.concerns.testCoverage}% coverage`,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
// Check for AC-ID coverage gaps
|
|
124
|
+
for (const gap of testCoverage.gaps) {
|
|
125
|
+
concerns.push({
|
|
126
|
+
type: 'test_gap',
|
|
127
|
+
severity: 'high',
|
|
128
|
+
title: `Missing test: ${gap.acceptance_criteria}`,
|
|
129
|
+
description: gap.description,
|
|
130
|
+
mitigation: gap.recommendation,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Assess specification quality
|
|
136
|
+
*/
|
|
137
|
+
assessSpecQuality(assessment, blockers, concerns, recommendations) {
|
|
138
|
+
const score = assessment.overall_score;
|
|
139
|
+
if (score < this.thresholds.fail.specQuality) {
|
|
140
|
+
blockers.push({
|
|
141
|
+
type: 'spec_quality',
|
|
142
|
+
severity: 'critical',
|
|
143
|
+
title: 'Specification quality unacceptable',
|
|
144
|
+
description: `Score is ${score}/100 (minimum: ${this.thresholds.fail.specQuality})`,
|
|
145
|
+
mitigation: 'Revise spec to address critical issues',
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
else if (score < this.thresholds.concerns.specQuality) {
|
|
149
|
+
concerns.push({
|
|
150
|
+
type: 'spec_quality',
|
|
151
|
+
severity: 'high',
|
|
152
|
+
title: 'Specification quality needs improvement',
|
|
153
|
+
description: `Score is ${score}/100 (target: ${this.thresholds.concerns.specQuality})`,
|
|
154
|
+
mitigation: 'Address HIGH priority suggestions',
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
// Add dimension-specific issues
|
|
158
|
+
for (const issue of assessment.issues) {
|
|
159
|
+
const gateIssue = {
|
|
160
|
+
type: `spec_${issue.dimension}`,
|
|
161
|
+
severity: issue.severity === 'critical' ? 'critical' : issue.severity === 'major' ? 'high' : 'medium',
|
|
162
|
+
title: `${issue.dimension.toUpperCase()}: ${issue.description}`,
|
|
163
|
+
description: issue.impact,
|
|
164
|
+
location: issue.location,
|
|
165
|
+
};
|
|
166
|
+
if (issue.severity === 'critical') {
|
|
167
|
+
blockers.push(gateIssue);
|
|
168
|
+
}
|
|
169
|
+
else if (issue.severity === 'major') {
|
|
170
|
+
concerns.push(gateIssue);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
recommendations.push(gateIssue);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Assess security vulnerabilities
|
|
179
|
+
*/
|
|
180
|
+
assessSecurity(securityAudit, blockers, concerns) {
|
|
181
|
+
const deps = securityAudit.dependency_vulnerabilities;
|
|
182
|
+
// Check critical vulnerabilities
|
|
183
|
+
if (deps.critical >= this.thresholds.fail.criticalVulnerabilities) {
|
|
184
|
+
const criticalVulns = deps.issues.filter((v) => v.severity === 'critical');
|
|
185
|
+
for (const vuln of criticalVulns) {
|
|
186
|
+
blockers.push({
|
|
187
|
+
type: 'security',
|
|
188
|
+
severity: 'critical',
|
|
189
|
+
title: `Critical vulnerability: ${vuln.vulnerability}`,
|
|
190
|
+
description: `Package: ${vuln.package}@${vuln.version}`,
|
|
191
|
+
mitigation: vuln.fix,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Check high vulnerabilities
|
|
196
|
+
if (deps.high >= this.thresholds.concerns.highVulnerabilities) {
|
|
197
|
+
const highVulns = deps.issues.filter((v) => v.severity === 'high');
|
|
198
|
+
for (const vuln of highVulns) {
|
|
199
|
+
concerns.push({
|
|
200
|
+
type: 'security',
|
|
201
|
+
severity: 'high',
|
|
202
|
+
title: `High vulnerability: ${vuln.vulnerability}`,
|
|
203
|
+
description: `Package: ${vuln.package}@${vuln.version}`,
|
|
204
|
+
mitigation: vuln.fix,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Check OWASP failures
|
|
209
|
+
const owaspFailures = securityAudit.owasp_checks.filter((c) => c.status === 'FAIL');
|
|
210
|
+
for (const check of owaspFailures) {
|
|
211
|
+
concerns.push({
|
|
212
|
+
type: 'security',
|
|
213
|
+
severity: 'high',
|
|
214
|
+
title: `OWASP ${check.category}`,
|
|
215
|
+
description: check.details,
|
|
216
|
+
mitigation: check.recommendation,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Make final decision based on blockers and concerns
|
|
222
|
+
*/
|
|
223
|
+
makeDecision(blockers, concerns) {
|
|
224
|
+
if (blockers.length > 0) {
|
|
225
|
+
return {
|
|
226
|
+
decision: 'FAIL',
|
|
227
|
+
reasoning: `Found ${blockers.length} blocker(s) that MUST be fixed before proceeding.`,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
if (concerns.length > 0) {
|
|
231
|
+
return {
|
|
232
|
+
decision: 'CONCERNS',
|
|
233
|
+
reasoning: `Found ${concerns.length} concern(s) that SHOULD be addressed before release.`,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
decision: 'PASS',
|
|
238
|
+
reasoning: 'All quality checks passed. Ready for production.',
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Get decision icon/emoji
|
|
243
|
+
*/
|
|
244
|
+
static getDecisionIcon(decision) {
|
|
245
|
+
switch (decision) {
|
|
246
|
+
case 'PASS':
|
|
247
|
+
return '🟢';
|
|
248
|
+
case 'CONCERNS':
|
|
249
|
+
return '🟡';
|
|
250
|
+
case 'FAIL':
|
|
251
|
+
return '🔴';
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Get decision color (for terminal output)
|
|
256
|
+
*/
|
|
257
|
+
static getDecisionColor(decision) {
|
|
258
|
+
switch (decision) {
|
|
259
|
+
case 'PASS':
|
|
260
|
+
return 'green';
|
|
261
|
+
case 'CONCERNS':
|
|
262
|
+
return 'yellow';
|
|
263
|
+
case 'FAIL':
|
|
264
|
+
return 'red';
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=quality-gate-decider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-gate-decider.js","sourceRoot":"","sources":["../../../src/core/qa/quality-gate-decider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Risk Calculator using BMAD pattern (Probability × Impact)
|
|
3
|
+
*
|
|
4
|
+
* @module qa/risk-calculator
|
|
5
|
+
* @since v0.8.0
|
|
6
|
+
*/
|
|
7
|
+
import { Risk, RiskAssessmentResult, RiskCategory, RiskSeverity } from './types';
|
|
8
|
+
export declare class RiskCalculator {
|
|
9
|
+
/**
|
|
10
|
+
* Calculate risk score using BMAD formula: P × I
|
|
11
|
+
*
|
|
12
|
+
* @param probability - Probability of risk occurring (0.0-1.0)
|
|
13
|
+
* @param impact - Impact severity if risk occurs (1-10)
|
|
14
|
+
* @returns Risk score (0.0-10.0)
|
|
15
|
+
* @throws Error if probability or impact out of range
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const score = RiskCalculator.calculateRiskScore(0.9, 10);
|
|
20
|
+
* // Returns: 9.0 (CRITICAL)
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
static calculateRiskScore(probability: number, impact: number): number;
|
|
24
|
+
/**
|
|
25
|
+
* Determine severity level based on risk score
|
|
26
|
+
*
|
|
27
|
+
* @param score - Risk score (0.0-10.0)
|
|
28
|
+
* @returns Severity level
|
|
29
|
+
*
|
|
30
|
+
* Thresholds:
|
|
31
|
+
* - 9.0-10.0: CRITICAL (must fix immediately)
|
|
32
|
+
* - 6.0-8.9: HIGH (should fix before release)
|
|
33
|
+
* - 3.0-5.9: MEDIUM (monitor, fix if time permits)
|
|
34
|
+
* - 0.0-2.9: LOW (acceptable risk)
|
|
35
|
+
*/
|
|
36
|
+
static determineSeverity(score: number): RiskSeverity;
|
|
37
|
+
/**
|
|
38
|
+
* Calculate overall risk score using weighted average
|
|
39
|
+
*
|
|
40
|
+
* Higher severity risks are weighted more heavily:
|
|
41
|
+
* - CRITICAL: 1.0
|
|
42
|
+
* - HIGH: 0.7
|
|
43
|
+
* - MEDIUM: 0.4
|
|
44
|
+
* - LOW: 0.1
|
|
45
|
+
*
|
|
46
|
+
* @param risks - Array of risk objects
|
|
47
|
+
* @returns Overall weighted risk score (0.0-10.0)
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const risks = [
|
|
52
|
+
* { score: 9.0, severity: 'CRITICAL', ... },
|
|
53
|
+
* { score: 6.0, severity: 'HIGH', ... },
|
|
54
|
+
* { score: 2.0, severity: 'LOW', ... }
|
|
55
|
+
* ];
|
|
56
|
+
* const overall = RiskCalculator.calculateOverallRisk(risks);
|
|
57
|
+
* // Returns: ~7.5 (weighted towards critical risks)
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
static calculateOverallRisk(risks: Risk[]): number;
|
|
61
|
+
/**
|
|
62
|
+
* Group risks by category and calculate category scores
|
|
63
|
+
*
|
|
64
|
+
* @param risks - Array of risk objects
|
|
65
|
+
* @returns Object with risk scores per category
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const grouped = RiskCalculator.groupRisksByCategory(risks);
|
|
70
|
+
* // Returns: { security: 7.5, technical: 4.2, implementation: 3.0, operational: 2.1 }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
static groupRisksByCategory(risks: Risk[]): Record<RiskCategory, number>;
|
|
74
|
+
/**
|
|
75
|
+
* Normalize probability from descriptive text to numeric value
|
|
76
|
+
*
|
|
77
|
+
* @param description - Text description (low/medium/high or percentage)
|
|
78
|
+
* @returns Numeric probability (0.0-1.0)
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* RiskCalculator.normalizeProbability('high'); // 0.8
|
|
83
|
+
* RiskCalculator.normalizeProbability('50%'); // 0.5
|
|
84
|
+
* RiskCalculator.normalizeProbability('0.9'); // 0.9
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
static normalizeProbability(description: string): number;
|
|
88
|
+
/**
|
|
89
|
+
* Normalize impact from descriptive text to numeric value
|
|
90
|
+
*
|
|
91
|
+
* @param description - Text description (minor/moderate/major/critical)
|
|
92
|
+
* @returns Numeric impact (1-10)
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* RiskCalculator.normalizeImpact('critical'); // 10
|
|
97
|
+
* RiskCalculator.normalizeImpact('moderate'); // 5
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
static normalizeImpact(description: string): number;
|
|
101
|
+
/**
|
|
102
|
+
* Create a risk object from raw data
|
|
103
|
+
*
|
|
104
|
+
* @param data - Partial risk data
|
|
105
|
+
* @returns Complete risk object with calculated fields
|
|
106
|
+
*/
|
|
107
|
+
static createRisk(data: {
|
|
108
|
+
id: string;
|
|
109
|
+
category: RiskCategory;
|
|
110
|
+
title: string;
|
|
111
|
+
description: string;
|
|
112
|
+
probability: number | string;
|
|
113
|
+
impact: number | string;
|
|
114
|
+
mitigation: string;
|
|
115
|
+
location: string;
|
|
116
|
+
acceptance_criteria?: string;
|
|
117
|
+
}): Risk;
|
|
118
|
+
/**
|
|
119
|
+
* Calculate full risk assessment result
|
|
120
|
+
*
|
|
121
|
+
* @param risks - Array of risk objects
|
|
122
|
+
* @returns Complete risk assessment result
|
|
123
|
+
*/
|
|
124
|
+
static calculateAssessment(risks: Risk[]): RiskAssessmentResult;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=risk-calculator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk-calculator.d.ts","sourceRoot":"","sources":["../../../src/core/qa/risk-calculator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEjF,qBAAa,cAAc;IACzB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAUtE;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY;IAOrD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM;IAsBlD;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC;IAYxE;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAqCxD;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAmCnD;;;;;OAKG;IACH,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE;QACtB,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,YAAY,CAAC;QACvB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;QAC7B,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;KAC9B,GAAG,IAAI;IA4BR;;;;;OAKG;IACH,MAAM,CAAC,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,oBAAoB;CAOhE"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Risk Calculator using BMAD pattern (Probability × Impact)
|
|
3
|
+
*
|
|
4
|
+
* @module qa/risk-calculator
|
|
5
|
+
* @since v0.8.0
|
|
6
|
+
*/
|
|
7
|
+
export class RiskCalculator {
|
|
8
|
+
/**
|
|
9
|
+
* Calculate risk score using BMAD formula: P × I
|
|
10
|
+
*
|
|
11
|
+
* @param probability - Probability of risk occurring (0.0-1.0)
|
|
12
|
+
* @param impact - Impact severity if risk occurs (1-10)
|
|
13
|
+
* @returns Risk score (0.0-10.0)
|
|
14
|
+
* @throws Error if probability or impact out of range
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const score = RiskCalculator.calculateRiskScore(0.9, 10);
|
|
19
|
+
* // Returns: 9.0 (CRITICAL)
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
static calculateRiskScore(probability, impact) {
|
|
23
|
+
if (probability < 0 || probability > 1) {
|
|
24
|
+
throw new Error(`Probability must be 0.0-1.0, got ${probability}`);
|
|
25
|
+
}
|
|
26
|
+
if (impact < 1 || impact > 10) {
|
|
27
|
+
throw new Error(`Impact must be 1-10, got ${impact}`);
|
|
28
|
+
}
|
|
29
|
+
return probability * impact;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Determine severity level based on risk score
|
|
33
|
+
*
|
|
34
|
+
* @param score - Risk score (0.0-10.0)
|
|
35
|
+
* @returns Severity level
|
|
36
|
+
*
|
|
37
|
+
* Thresholds:
|
|
38
|
+
* - 9.0-10.0: CRITICAL (must fix immediately)
|
|
39
|
+
* - 6.0-8.9: HIGH (should fix before release)
|
|
40
|
+
* - 3.0-5.9: MEDIUM (monitor, fix if time permits)
|
|
41
|
+
* - 0.0-2.9: LOW (acceptable risk)
|
|
42
|
+
*/
|
|
43
|
+
static determineSeverity(score) {
|
|
44
|
+
if (score >= 9.0)
|
|
45
|
+
return 'CRITICAL';
|
|
46
|
+
if (score >= 6.0)
|
|
47
|
+
return 'HIGH';
|
|
48
|
+
if (score >= 3.0)
|
|
49
|
+
return 'MEDIUM';
|
|
50
|
+
return 'LOW';
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Calculate overall risk score using weighted average
|
|
54
|
+
*
|
|
55
|
+
* Higher severity risks are weighted more heavily:
|
|
56
|
+
* - CRITICAL: 1.0
|
|
57
|
+
* - HIGH: 0.7
|
|
58
|
+
* - MEDIUM: 0.4
|
|
59
|
+
* - LOW: 0.1
|
|
60
|
+
*
|
|
61
|
+
* @param risks - Array of risk objects
|
|
62
|
+
* @returns Overall weighted risk score (0.0-10.0)
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const risks = [
|
|
67
|
+
* { score: 9.0, severity: 'CRITICAL', ... },
|
|
68
|
+
* { score: 6.0, severity: 'HIGH', ... },
|
|
69
|
+
* { score: 2.0, severity: 'LOW', ... }
|
|
70
|
+
* ];
|
|
71
|
+
* const overall = RiskCalculator.calculateOverallRisk(risks);
|
|
72
|
+
* // Returns: ~7.5 (weighted towards critical risks)
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
static calculateOverallRisk(risks) {
|
|
76
|
+
if (risks.length === 0)
|
|
77
|
+
return 0;
|
|
78
|
+
const weights = {
|
|
79
|
+
CRITICAL: 1.0,
|
|
80
|
+
HIGH: 0.7,
|
|
81
|
+
MEDIUM: 0.4,
|
|
82
|
+
LOW: 0.1,
|
|
83
|
+
};
|
|
84
|
+
let weightedSum = 0;
|
|
85
|
+
let totalWeight = 0;
|
|
86
|
+
for (const risk of risks) {
|
|
87
|
+
const weight = weights[risk.severity];
|
|
88
|
+
weightedSum += risk.score * weight;
|
|
89
|
+
totalWeight += weight;
|
|
90
|
+
}
|
|
91
|
+
return totalWeight > 0 ? weightedSum / totalWeight : 0;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Group risks by category and calculate category scores
|
|
95
|
+
*
|
|
96
|
+
* @param risks - Array of risk objects
|
|
97
|
+
* @returns Object with risk scores per category
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const grouped = RiskCalculator.groupRisksByCategory(risks);
|
|
102
|
+
* // Returns: { security: 7.5, technical: 4.2, implementation: 3.0, operational: 2.1 }
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
static groupRisksByCategory(risks) {
|
|
106
|
+
const categories = ['security', 'technical', 'implementation', 'operational'];
|
|
107
|
+
const result = {};
|
|
108
|
+
for (const category of categories) {
|
|
109
|
+
const categoryRisks = risks.filter((r) => r.category === category);
|
|
110
|
+
result[category] = this.calculateOverallRisk(categoryRisks);
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Normalize probability from descriptive text to numeric value
|
|
116
|
+
*
|
|
117
|
+
* @param description - Text description (low/medium/high or percentage)
|
|
118
|
+
* @returns Numeric probability (0.0-1.0)
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* RiskCalculator.normalizeProbability('high'); // 0.8
|
|
123
|
+
* RiskCalculator.normalizeProbability('50%'); // 0.5
|
|
124
|
+
* RiskCalculator.normalizeProbability('0.9'); // 0.9
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
static normalizeProbability(description) {
|
|
128
|
+
const normalized = description.toLowerCase().trim();
|
|
129
|
+
// Handle percentage
|
|
130
|
+
if (normalized.includes('%')) {
|
|
131
|
+
const percent = parseFloat(normalized.replace('%', ''));
|
|
132
|
+
return Math.min(Math.max(percent / 100, 0), 1);
|
|
133
|
+
}
|
|
134
|
+
// Handle decimal
|
|
135
|
+
if (/^[0-9.]+$/.test(normalized)) {
|
|
136
|
+
const value = parseFloat(normalized);
|
|
137
|
+
return Math.min(Math.max(value, 0), 1);
|
|
138
|
+
}
|
|
139
|
+
// Handle descriptive text
|
|
140
|
+
switch (normalized) {
|
|
141
|
+
case 'low':
|
|
142
|
+
case 'unlikely':
|
|
143
|
+
return 0.2;
|
|
144
|
+
case 'medium':
|
|
145
|
+
case 'possible':
|
|
146
|
+
case 'moderate':
|
|
147
|
+
return 0.5;
|
|
148
|
+
case 'high':
|
|
149
|
+
case 'likely':
|
|
150
|
+
case 'probable':
|
|
151
|
+
return 0.8;
|
|
152
|
+
case 'very high':
|
|
153
|
+
case 'certain':
|
|
154
|
+
case 'definite':
|
|
155
|
+
return 0.95;
|
|
156
|
+
default:
|
|
157
|
+
return 0.5; // Default to medium if unknown
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Normalize impact from descriptive text to numeric value
|
|
162
|
+
*
|
|
163
|
+
* @param description - Text description (minor/moderate/major/critical)
|
|
164
|
+
* @returns Numeric impact (1-10)
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* RiskCalculator.normalizeImpact('critical'); // 10
|
|
169
|
+
* RiskCalculator.normalizeImpact('moderate'); // 5
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
static normalizeImpact(description) {
|
|
173
|
+
const normalized = description.toLowerCase().trim();
|
|
174
|
+
// Handle numeric
|
|
175
|
+
if (/^[0-9]+$/.test(normalized)) {
|
|
176
|
+
const value = parseInt(normalized, 10);
|
|
177
|
+
return Math.min(Math.max(value, 1), 10);
|
|
178
|
+
}
|
|
179
|
+
// Handle descriptive text
|
|
180
|
+
switch (normalized) {
|
|
181
|
+
case 'minor':
|
|
182
|
+
case 'trivial':
|
|
183
|
+
case 'cosmetic':
|
|
184
|
+
return 2;
|
|
185
|
+
case 'moderate':
|
|
186
|
+
case 'medium':
|
|
187
|
+
case 'some impact':
|
|
188
|
+
return 5;
|
|
189
|
+
case 'major':
|
|
190
|
+
case 'significant':
|
|
191
|
+
case 'high':
|
|
192
|
+
return 8;
|
|
193
|
+
case 'critical':
|
|
194
|
+
case 'severe':
|
|
195
|
+
case 'catastrophic':
|
|
196
|
+
case 'system failure':
|
|
197
|
+
case 'data loss':
|
|
198
|
+
case 'security breach':
|
|
199
|
+
return 10;
|
|
200
|
+
default:
|
|
201
|
+
return 5; // Default to moderate if unknown
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Create a risk object from raw data
|
|
206
|
+
*
|
|
207
|
+
* @param data - Partial risk data
|
|
208
|
+
* @returns Complete risk object with calculated fields
|
|
209
|
+
*/
|
|
210
|
+
static createRisk(data) {
|
|
211
|
+
// Normalize probability and impact
|
|
212
|
+
const probability = typeof data.probability === 'string'
|
|
213
|
+
? this.normalizeProbability(data.probability)
|
|
214
|
+
: data.probability;
|
|
215
|
+
const impact = typeof data.impact === 'string' ? this.normalizeImpact(data.impact) : data.impact;
|
|
216
|
+
// Calculate score and severity
|
|
217
|
+
const score = this.calculateRiskScore(probability, impact);
|
|
218
|
+
const severity = this.determineSeverity(score);
|
|
219
|
+
return {
|
|
220
|
+
id: data.id,
|
|
221
|
+
category: data.category,
|
|
222
|
+
title: data.title,
|
|
223
|
+
description: data.description,
|
|
224
|
+
probability,
|
|
225
|
+
impact,
|
|
226
|
+
score,
|
|
227
|
+
severity,
|
|
228
|
+
mitigation: data.mitigation,
|
|
229
|
+
location: data.location,
|
|
230
|
+
acceptance_criteria: data.acceptance_criteria,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Calculate full risk assessment result
|
|
235
|
+
*
|
|
236
|
+
* @param risks - Array of risk objects
|
|
237
|
+
* @returns Complete risk assessment result
|
|
238
|
+
*/
|
|
239
|
+
static calculateAssessment(risks) {
|
|
240
|
+
return {
|
|
241
|
+
risks,
|
|
242
|
+
overall_risk_score: this.calculateOverallRisk(risks),
|
|
243
|
+
risk_by_category: this.groupRisksByCategory(risks),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=risk-calculator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk-calculator.js","sourceRoot":"","sources":["../../../src/core/qa/risk-calculator.ts"],"names":[],"mappings":"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"}
|