aidp 0.1.0

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.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +210 -0
  4. data/bin/aidp +5 -0
  5. data/lib/aidp/analyze/agent_personas.rb +71 -0
  6. data/lib/aidp/analyze/agent_tool_executor.rb +445 -0
  7. data/lib/aidp/analyze/data_retention_manager.rb +426 -0
  8. data/lib/aidp/analyze/database.rb +243 -0
  9. data/lib/aidp/analyze/dependencies.rb +335 -0
  10. data/lib/aidp/analyze/error_handler.rb +486 -0
  11. data/lib/aidp/analyze/export_manager.rb +425 -0
  12. data/lib/aidp/analyze/feature_analyzer.rb +397 -0
  13. data/lib/aidp/analyze/focus_guidance.rb +517 -0
  14. data/lib/aidp/analyze/incremental_analyzer.rb +543 -0
  15. data/lib/aidp/analyze/language_analysis_strategies.rb +897 -0
  16. data/lib/aidp/analyze/large_analysis_progress.rb +504 -0
  17. data/lib/aidp/analyze/memory_manager.rb +365 -0
  18. data/lib/aidp/analyze/parallel_processor.rb +460 -0
  19. data/lib/aidp/analyze/performance_optimizer.rb +694 -0
  20. data/lib/aidp/analyze/prioritizer.rb +402 -0
  21. data/lib/aidp/analyze/progress.rb +75 -0
  22. data/lib/aidp/analyze/progress_visualizer.rb +320 -0
  23. data/lib/aidp/analyze/report_generator.rb +582 -0
  24. data/lib/aidp/analyze/repository_chunker.rb +702 -0
  25. data/lib/aidp/analyze/ruby_maat_integration.rb +572 -0
  26. data/lib/aidp/analyze/runner.rb +245 -0
  27. data/lib/aidp/analyze/static_analysis_detector.rb +577 -0
  28. data/lib/aidp/analyze/steps.rb +53 -0
  29. data/lib/aidp/analyze/storage.rb +600 -0
  30. data/lib/aidp/analyze/tool_configuration.rb +456 -0
  31. data/lib/aidp/analyze/tool_modernization.rb +750 -0
  32. data/lib/aidp/execute/progress.rb +76 -0
  33. data/lib/aidp/execute/runner.rb +135 -0
  34. data/lib/aidp/execute/steps.rb +113 -0
  35. data/lib/aidp/shared/cli.rb +117 -0
  36. data/lib/aidp/shared/config.rb +35 -0
  37. data/lib/aidp/shared/project_detector.rb +119 -0
  38. data/lib/aidp/shared/providers/anthropic.rb +26 -0
  39. data/lib/aidp/shared/providers/base.rb +17 -0
  40. data/lib/aidp/shared/providers/cursor.rb +102 -0
  41. data/lib/aidp/shared/providers/gemini.rb +26 -0
  42. data/lib/aidp/shared/providers/macos_ui.rb +26 -0
  43. data/lib/aidp/shared/sync.rb +15 -0
  44. data/lib/aidp/shared/util.rb +41 -0
  45. data/lib/aidp/shared/version.rb +7 -0
  46. data/lib/aidp/shared/workspace.rb +21 -0
  47. data/lib/aidp.rb +53 -0
  48. data/templates/ANALYZE/01_REPOSITORY_ANALYSIS.md +100 -0
  49. data/templates/ANALYZE/02_ARCHITECTURE_ANALYSIS.md +151 -0
  50. data/templates/ANALYZE/03_TEST_ANALYSIS.md +182 -0
  51. data/templates/ANALYZE/04_FUNCTIONALITY_ANALYSIS.md +200 -0
  52. data/templates/ANALYZE/05_DOCUMENTATION_ANALYSIS.md +202 -0
  53. data/templates/ANALYZE/06_STATIC_ANALYSIS.md +233 -0
  54. data/templates/ANALYZE/07_REFACTORING_RECOMMENDATIONS.md +316 -0
  55. data/templates/COMMON/AGENT_BASE.md +129 -0
  56. data/templates/COMMON/CONVENTIONS.md +19 -0
  57. data/templates/COMMON/TEMPLATES/ADR_TEMPLATE.md +21 -0
  58. data/templates/COMMON/TEMPLATES/DOMAIN_CHARTER.md +27 -0
  59. data/templates/COMMON/TEMPLATES/EVENT_EXAMPLE.yaml +16 -0
  60. data/templates/COMMON/TEMPLATES/MERMAID_C4.md +46 -0
  61. data/templates/COMMON/TEMPLATES/OPENAPI_STUB.yaml +11 -0
  62. data/templates/EXECUTE/00_PRD.md +36 -0
  63. data/templates/EXECUTE/01_NFRS.md +27 -0
  64. data/templates/EXECUTE/02A_ARCH_GATE_QUESTIONS.md +13 -0
  65. data/templates/EXECUTE/02_ARCHITECTURE.md +42 -0
  66. data/templates/EXECUTE/03_ADR_FACTORY.md +22 -0
  67. data/templates/EXECUTE/04_DOMAIN_DECOMPOSITION.md +24 -0
  68. data/templates/EXECUTE/05_CONTRACTS.md +27 -0
  69. data/templates/EXECUTE/06_THREAT_MODEL.md +23 -0
  70. data/templates/EXECUTE/07_TEST_PLAN.md +24 -0
  71. data/templates/EXECUTE/08_TASKS.md +29 -0
  72. data/templates/EXECUTE/09_SCAFFOLDING_DEVEX.md +25 -0
  73. data/templates/EXECUTE/10_IMPLEMENTATION_AGENT.md +30 -0
  74. data/templates/EXECUTE/11_STATIC_ANALYSIS.md +22 -0
  75. data/templates/EXECUTE/12_OBSERVABILITY_SLOS.md +21 -0
  76. data/templates/EXECUTE/13_DELIVERY_ROLLOUT.md +21 -0
  77. data/templates/EXECUTE/14_DOCS_PORTAL.md +23 -0
  78. data/templates/EXECUTE/15_POST_RELEASE.md +25 -0
  79. metadata +301 -0
@@ -0,0 +1,582 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "json"
5
+ require "yaml"
6
+
7
+ module Aidp
8
+ class ReportGenerator
9
+ # Default report templates
10
+ DEFAULT_TEMPLATES = {
11
+ "analysis_summary" => "templates/COMMON/ANALYSIS_SUMMARY.md.erb",
12
+ "repository_analysis" => "templates/ANALYZE/REPOSITORY_ANALYSIS.md.erb",
13
+ "architecture_analysis" => "templates/ANALYZE/ARCHITECTURE_ANALYSIS.md.erb",
14
+ "functionality_analysis" => "templates/ANALYZE/FUNCTIONALITY_ANALYSIS.md.erb",
15
+ "static_analysis" => "templates/ANALYZE/STATIC_ANALYSIS.md.erb",
16
+ "refactoring_recommendations" => "templates/ANALYZE/REFACTORING_RECOMMENDATIONS.md.erb"
17
+ }.freeze
18
+
19
+ def initialize(project_dir = Dir.pwd, config = {})
20
+ @project_dir = project_dir
21
+ @config = config
22
+ @output_dir = config[:output_dir] || File.join(project_dir, "docs")
23
+ @templates_dir = config[:templates_dir] || File.join(project_dir, "templates")
24
+ end
25
+
26
+ # Generate comprehensive analysis report
27
+ def generate_analysis_report(analysis_data, options = {})
28
+ report_data = prepare_report_data(analysis_data)
29
+ template_name = options[:template] || "analysis_summary"
30
+
31
+ template_path = find_template(template_name)
32
+ return nil unless template_path
33
+
34
+ report_content = render_template(template_path, report_data)
35
+ output_path = save_report(report_content, template_name, options)
36
+
37
+ {
38
+ content: report_content,
39
+ path: output_path,
40
+ template: template_name,
41
+ generated_at: Time.now
42
+ }
43
+ end
44
+
45
+ # Generate step-specific report
46
+ def generate_step_report(step_name, step_data, options = {})
47
+ report_data = prepare_step_data(step_name, step_data)
48
+ template_name = "#{step_name}_analysis"
49
+
50
+ template_path = find_template(template_name)
51
+ return nil unless template_path
52
+
53
+ report_content = render_template(template_path, report_data)
54
+ output_path = save_report(report_content, template_name, options)
55
+
56
+ {
57
+ content: report_content,
58
+ path: output_path,
59
+ step: step_name,
60
+ generated_at: Time.now
61
+ }
62
+ end
63
+
64
+ # Generate executive summary report
65
+ def generate_executive_summary(analysis_data, options = {})
66
+ summary_data = prepare_executive_summary_data(analysis_data)
67
+ template_path = find_template("executive_summary")
68
+
69
+ return nil unless template_path
70
+
71
+ summary_content = render_template(template_path, summary_data)
72
+ output_path = save_report(summary_content, "executive_summary", options)
73
+
74
+ {
75
+ content: summary_content,
76
+ path: output_path,
77
+ type: "executive_summary",
78
+ generated_at: Time.now
79
+ }
80
+ end
81
+
82
+ # Generate technical report
83
+ def generate_technical_report(analysis_data, options = {})
84
+ technical_data = prepare_technical_report_data(analysis_data)
85
+ template_path = find_template("technical_report")
86
+
87
+ return nil unless template_path
88
+
89
+ technical_content = render_template(template_path, technical_data)
90
+ output_path = save_report(technical_content, "technical_report", options)
91
+
92
+ {
93
+ content: technical_content,
94
+ path: output_path,
95
+ type: "technical_report",
96
+ generated_at: Time.now
97
+ }
98
+ end
99
+
100
+ # Generate comparison report
101
+ def generate_comparison_report(before_data, after_data, options = {})
102
+ comparison_data = prepare_comparison_data(before_data, after_data)
103
+ template_path = find_template("comparison_report")
104
+
105
+ return nil unless template_path
106
+
107
+ comparison_content = render_template(template_path, comparison_data)
108
+ output_path = save_report(comparison_content, "comparison_report", options)
109
+
110
+ {
111
+ content: comparison_content,
112
+ path: output_path,
113
+ type: "comparison_report",
114
+ generated_at: Time.now
115
+ }
116
+ end
117
+
118
+ # Generate custom report from template
119
+ def generate_custom_report(template_name, data, options = {})
120
+ template_path = find_template(template_name)
121
+ return nil unless template_path
122
+
123
+ report_content = render_template(template_path, data)
124
+ output_path = save_report(report_content, template_name, options)
125
+
126
+ {
127
+ content: report_content,
128
+ path: output_path,
129
+ template: template_name,
130
+ generated_at: Time.now
131
+ }
132
+ end
133
+
134
+ # Generate report index
135
+ def generate_report_index(reports, options = {})
136
+ index_data = {
137
+ reports: reports,
138
+ generated_at: Time.now,
139
+ project_name: File.basename(@project_dir)
140
+ }
141
+
142
+ template_path = find_template("report_index")
143
+ return nil unless template_path
144
+
145
+ index_content = render_template(template_path, index_data)
146
+ output_path = save_report(index_content, "report_index", options)
147
+
148
+ {
149
+ content: index_content,
150
+ path: output_path,
151
+ type: "report_index",
152
+ generated_at: Time.now
153
+ }
154
+ end
155
+
156
+ private
157
+
158
+ def prepare_report_data(analysis_data)
159
+ {
160
+ project_name: File.basename(@project_dir),
161
+ project_path: @project_dir,
162
+ analysis_data: analysis_data,
163
+ generated_at: Time.now,
164
+ config: @config,
165
+ metadata: generate_metadata(analysis_data)
166
+ }
167
+ end
168
+
169
+ def prepare_step_data(step_name, step_data)
170
+ {
171
+ step_name: step_name,
172
+ step_data: step_data,
173
+ project_name: File.basename(@project_dir),
174
+ project_path: @project_dir,
175
+ generated_at: Time.now,
176
+ config: @config
177
+ }
178
+ end
179
+
180
+ def prepare_executive_summary_data(analysis_data)
181
+ {
182
+ project_name: File.basename(@project_dir),
183
+ project_path: @project_dir,
184
+ generated_at: Time.now,
185
+ key_findings: extract_key_findings(analysis_data),
186
+ recommendations: extract_recommendations(analysis_data),
187
+ risk_assessment: assess_risks(analysis_data),
188
+ effort_estimation: estimate_effort(analysis_data)
189
+ }
190
+ end
191
+
192
+ def prepare_technical_report_data(analysis_data)
193
+ {
194
+ project_name: File.basename(@project_dir),
195
+ project_path: @project_dir,
196
+ generated_at: Time.now,
197
+ detailed_analysis: analysis_data,
198
+ technical_debt: calculate_technical_debt(analysis_data),
199
+ code_quality_metrics: extract_quality_metrics(analysis_data),
200
+ security_analysis: extract_security_analysis(analysis_data),
201
+ performance_analysis: extract_performance_analysis(analysis_data)
202
+ }
203
+ end
204
+
205
+ def prepare_comparison_data(before_data, after_data)
206
+ {
207
+ project_name: File.basename(@project_dir),
208
+ project_path: @project_dir,
209
+ generated_at: Time.now,
210
+ before_analysis: before_data,
211
+ after_analysis: after_data,
212
+ improvements: calculate_improvements(before_data, after_data),
213
+ regressions: identify_regressions(before_data, after_data),
214
+ metrics_comparison: compare_metrics(before_data, after_data)
215
+ }
216
+ end
217
+
218
+ def find_template(template_name)
219
+ # Check for custom template first
220
+ custom_template = File.join(@templates_dir, "#{template_name}.md.erb")
221
+ return custom_template if File.exist?(custom_template)
222
+
223
+ # Check default templates
224
+ default_template = DEFAULT_TEMPLATES[template_name]
225
+ return File.join(@project_dir, default_template) if default_template && File.exist?(File.join(@project_dir,
226
+ default_template))
227
+
228
+ # Check common templates
229
+ common_template = File.join(@project_dir, "templates", "COMMON", "#{template_name}.md.erb")
230
+ return common_template if File.exist?(common_template)
231
+
232
+ # Check analyze templates
233
+ analyze_template = File.join(@project_dir, "templates", "ANALYZE", "#{template_name}.md.erb")
234
+ return analyze_template if File.exist?(analyze_template)
235
+
236
+ nil
237
+ end
238
+
239
+ def render_template(template_path, data)
240
+ template_content = File.read(template_path)
241
+ erb = ERB.new(template_content, trim_mode: "-")
242
+ erb.result(binding)
243
+ end
244
+
245
+ def save_report(content, report_type, options)
246
+ timestamp = Time.now.strftime("%Y%m%d_%H%M%S")
247
+ filename = options[:filename] || "#{report_type}_#{timestamp}.md"
248
+ output_path = File.join(@output_dir, filename)
249
+
250
+ # Ensure output directory exists
251
+ FileUtils.mkdir_p(@output_dir)
252
+
253
+ # Write report content
254
+ File.write(output_path, content)
255
+
256
+ output_path
257
+ end
258
+
259
+ def generate_metadata(analysis_data)
260
+ {
261
+ total_files_analyzed: count_analyzed_files(analysis_data),
262
+ analysis_duration: calculate_analysis_duration(analysis_data),
263
+ tools_used: extract_tools_used(analysis_data),
264
+ languages_detected: extract_languages(analysis_data),
265
+ frameworks_detected: extract_frameworks(analysis_data)
266
+ }
267
+ end
268
+
269
+ def extract_key_findings(analysis_data)
270
+ findings = []
271
+
272
+ # Extract findings from different analysis types
273
+ if analysis_data[:repository_analysis]
274
+ findings.concat(extract_repository_findings(analysis_data[:repository_analysis]))
275
+ end
276
+
277
+ if analysis_data[:architecture_analysis]
278
+ findings.concat(extract_architecture_findings(analysis_data[:architecture_analysis]))
279
+ end
280
+
281
+ if analysis_data[:static_analysis]
282
+ findings.concat(extract_static_analysis_findings(analysis_data[:static_analysis]))
283
+ end
284
+
285
+ # Prioritize findings by severity
286
+ findings.sort_by { |finding| finding[:severity] || "medium" }
287
+ end
288
+
289
+ def extract_recommendations(analysis_data)
290
+ recommendations = []
291
+
292
+ # Extract recommendations from different analysis types
293
+ recommendations.concat(analysis_data[:refactoring_recommendations]) if analysis_data[:refactoring_recommendations]
294
+
295
+ if analysis_data[:modernization_recommendations]
296
+ recommendations.concat(analysis_data[:modernization_recommendations])
297
+ end
298
+
299
+ # Prioritize recommendations by impact
300
+ recommendations.sort_by { |rec| rec[:impact] || "medium" }
301
+ end
302
+
303
+ def assess_risks(analysis_data)
304
+ risks = []
305
+
306
+ # Assess security risks
307
+ risks.concat(assess_security_risks(analysis_data[:security_analysis])) if analysis_data[:security_analysis]
308
+
309
+ # Assess technical debt risks
310
+ if analysis_data[:technical_debt_analysis]
311
+ risks.concat(assess_technical_debt_risks(analysis_data[:technical_debt_analysis]))
312
+ end
313
+
314
+ # Assess maintenance risks
315
+ if analysis_data[:maintenance_analysis]
316
+ risks.concat(assess_maintenance_risks(analysis_data[:maintenance_analysis]))
317
+ end
318
+
319
+ risks
320
+ end
321
+
322
+ def estimate_effort(analysis_data)
323
+ effort = {
324
+ refactoring_effort: estimate_refactoring_effort(analysis_data),
325
+ modernization_effort: estimate_modernization_effort(analysis_data),
326
+ testing_effort: estimate_testing_effort(analysis_data),
327
+ documentation_effort: estimate_documentation_effort(analysis_data)
328
+ }
329
+
330
+ effort[:total_effort] = effort.values.sum
331
+ effort
332
+ end
333
+
334
+ def calculate_technical_debt(analysis_data)
335
+ debt = {
336
+ code_quality_debt: calculate_code_quality_debt(analysis_data),
337
+ architecture_debt: calculate_architecture_debt(analysis_data),
338
+ testing_debt: calculate_testing_debt(analysis_data),
339
+ documentation_debt: calculate_documentation_debt(analysis_data),
340
+ security_debt: calculate_security_debt(analysis_data)
341
+ }
342
+
343
+ debt[:total_debt] = debt.values.sum
344
+ debt
345
+ end
346
+
347
+ def extract_quality_metrics(analysis_data)
348
+ metrics = {}
349
+
350
+ if analysis_data[:static_analysis]
351
+ metrics[:code_quality] = extract_code_quality_metrics(analysis_data[:static_analysis])
352
+ end
353
+
354
+ if analysis_data[:test_coverage]
355
+ metrics[:test_coverage] = extract_test_coverage_metrics(analysis_data[:test_coverage])
356
+ end
357
+
358
+ if analysis_data[:complexity_analysis]
359
+ metrics[:complexity] = extract_complexity_metrics(analysis_data[:complexity_analysis])
360
+ end
361
+
362
+ metrics
363
+ end
364
+
365
+ def extract_security_analysis(analysis_data)
366
+ security = {}
367
+
368
+ if analysis_data[:security_scan]
369
+ security[:vulnerabilities] = analysis_data[:security_scan][:vulnerabilities] || []
370
+ security[:risk_level] = analysis_data[:security_scan][:risk_level] || "unknown"
371
+ end
372
+
373
+ if analysis_data[:dependency_analysis]
374
+ security[:dependency_vulnerabilities] = analysis_data[:dependency_analysis][:vulnerabilities] || []
375
+ end
376
+
377
+ security
378
+ end
379
+
380
+ def extract_performance_analysis(analysis_data)
381
+ performance = {}
382
+
383
+ if analysis_data[:performance_analysis]
384
+ performance[:bottlenecks] = analysis_data[:performance_analysis][:bottlenecks] || []
385
+ performance[:optimization_opportunities] = analysis_data[:performance_analysis][:optimizations] || []
386
+ end
387
+
388
+ performance
389
+ end
390
+
391
+ def calculate_improvements(before_data, after_data)
392
+ improvements = []
393
+
394
+ # Compare metrics
395
+ before_metrics = extract_metrics(before_data)
396
+ after_metrics = extract_metrics(after_data)
397
+
398
+ after_metrics.each do |metric, value|
399
+ before_value = before_metrics[metric]
400
+ next unless before_value && value > before_value
401
+
402
+ improvements << {
403
+ metric: metric,
404
+ improvement: value - before_value,
405
+ percentage: ((value - before_value) / before_value * 100).round(2)
406
+ }
407
+ end
408
+
409
+ improvements
410
+ end
411
+
412
+ def identify_regressions(before_data, after_data)
413
+ regressions = []
414
+
415
+ # Compare metrics
416
+ before_metrics = extract_metrics(before_data)
417
+ after_metrics = extract_metrics(after_data)
418
+
419
+ after_metrics.each do |metric, value|
420
+ before_value = before_metrics[metric]
421
+ next unless before_value && value < before_value
422
+
423
+ regressions << {
424
+ metric: metric,
425
+ regression: before_value - value,
426
+ percentage: ((before_value - value) / before_value * 100).round(2)
427
+ }
428
+ end
429
+
430
+ regressions
431
+ end
432
+
433
+ def compare_metrics(before_data, after_data)
434
+ comparison = {}
435
+
436
+ before_metrics = extract_metrics(before_data)
437
+ after_metrics = extract_metrics(after_data)
438
+
439
+ all_metrics = (before_metrics.keys + after_metrics.keys).uniq
440
+
441
+ all_metrics.each do |metric|
442
+ comparison[metric] = {
443
+ before: before_metrics[metric],
444
+ after: after_metrics[metric],
445
+ change: (after_metrics[metric] && before_metrics[metric]) ? after_metrics[metric] - before_metrics[metric] : nil
446
+ }
447
+ end
448
+
449
+ comparison
450
+ end
451
+
452
+ # Helper methods for data extraction
453
+ def count_analyzed_files(analysis_data)
454
+ count = 0
455
+ analysis_data.each_value do |data|
456
+ count += data[:files_analyzed] if data.is_a?(Hash) && data[:files_analyzed]
457
+ end
458
+ count
459
+ end
460
+
461
+ def calculate_analysis_duration(analysis_data)
462
+ duration = 0
463
+ analysis_data.each_value do |data|
464
+ duration += data[:duration] if data.is_a?(Hash) && data[:duration]
465
+ end
466
+ duration
467
+ end
468
+
469
+ def extract_tools_used(analysis_data)
470
+ tools = []
471
+ analysis_data.each_value do |data|
472
+ tools.concat(data[:tools_used]) if data.is_a?(Hash) && data[:tools_used]
473
+ end
474
+ tools.uniq
475
+ end
476
+
477
+ def extract_languages(analysis_data)
478
+ languages = []
479
+ analysis_data.each_value do |data|
480
+ languages << data[:language] if data.is_a?(Hash) && data[:language]
481
+ end
482
+ languages.uniq
483
+ end
484
+
485
+ def extract_frameworks(analysis_data)
486
+ frameworks = []
487
+ analysis_data.each_value do |data|
488
+ frameworks << data[:framework] if data.is_a?(Hash) && data[:framework]
489
+ end
490
+ frameworks.uniq
491
+ end
492
+
493
+ def extract_metrics(data)
494
+ metrics = {}
495
+
496
+ if data.is_a?(Hash)
497
+ data.each do |key, value|
498
+ if value.is_a?(Numeric)
499
+ metrics[key] = value
500
+ elsif value.is_a?(Hash)
501
+ metrics.merge!(extract_metrics(value))
502
+ end
503
+ end
504
+ end
505
+
506
+ metrics
507
+ end
508
+
509
+ # Placeholder methods for specific analysis extractions
510
+ def extract_repository_findings(data)
511
+ data[:findings] || []
512
+ end
513
+
514
+ def extract_architecture_findings(data)
515
+ data[:findings] || []
516
+ end
517
+
518
+ def extract_static_analysis_findings(data)
519
+ data[:findings] || []
520
+ end
521
+
522
+ def assess_security_risks(data)
523
+ data[:risks] || []
524
+ end
525
+
526
+ def assess_technical_debt_risks(data)
527
+ data[:risks] || []
528
+ end
529
+
530
+ def assess_maintenance_risks(data)
531
+ data[:risks] || []
532
+ end
533
+
534
+ def estimate_refactoring_effort(data)
535
+ data[:effort] || 0
536
+ end
537
+
538
+ def estimate_modernization_effort(data)
539
+ data[:effort] || 0
540
+ end
541
+
542
+ def estimate_testing_effort(data)
543
+ data[:effort] || 0
544
+ end
545
+
546
+ def estimate_documentation_effort(data)
547
+ data[:effort] || 0
548
+ end
549
+
550
+ def calculate_code_quality_debt(data)
551
+ data[:debt] || 0
552
+ end
553
+
554
+ def calculate_architecture_debt(data)
555
+ data[:debt] || 0
556
+ end
557
+
558
+ def calculate_testing_debt(data)
559
+ data[:debt] || 0
560
+ end
561
+
562
+ def calculate_documentation_debt(data)
563
+ data[:debt] || 0
564
+ end
565
+
566
+ def calculate_security_debt(data)
567
+ data[:debt] || 0
568
+ end
569
+
570
+ def extract_code_quality_metrics(data)
571
+ data[:metrics] || {}
572
+ end
573
+
574
+ def extract_test_coverage_metrics(data)
575
+ data[:metrics] || {}
576
+ end
577
+
578
+ def extract_complexity_metrics(data)
579
+ data[:metrics] || {}
580
+ end
581
+ end
582
+ end